Matlab equivalent of Maple densityplot - matlab

I would like to create a density plot of this function:
In Maple, one could use the densityplot function to achieve this (code at the end), which gives:
However, I am not sure what to use for plotting a similar figure in MATLAB.
Here is my current MATLAB code:
x = [0:10:100];
y = [-50:10:50];
s = [10, 0];
i = [50,25];
for ii = 1 : length(x)
sir(ii) = -10 * 9.8 * log10((power((x(ii) - s(1)),2) + power((y(ii) - s(2)),2)) / (power((x(ii) - i(1)),2) + power((y(ii) - i(2)),2)));
end
Could someone suggest an equivalent in MATLAB?
For the density plot in Maple, I used
densityplot(sir(x,y), x=0..100, y=-50..50, axes=boxed, style=patchnogrid, scaletorange=-5..50, colorscheme = [black, "green", "white"])

You can use surf (a 3D surface plot) to achieve this, but you will need a finer grid than steps of 10 for it to look good!
Also you will need meshgrid to get all combinations of the x and y coordinates.
Please see the comments for further details.
% Set up grid points
x = 0:0.1:100;
y = -50:0.1:50;
[x,y] = meshgrid(x,y);
% Set up parameters i, s and g
i = [50 25]; s = [10 0]; g = 9.8;
% Work out density
% - no need for loop if we use element-wise operations ./ and .^
% - power(z,2) replaced by z.^2 (same function, more concise)
% - You forgot the sqare roots in your question's code, included using .^(1/2)
% - line continuation with "...", could remove and have on one line
sir = -10*g*log10( ((x-s(1)).^2 + (y-s(2)).^2).^(1/2) ./ ...
((x-i(1)).^2 + (y-i(2)).^2).^(1/2) );
% Plot, and set to a view from above
surf(x,y,sir,'edgecolor','none','facecolor','interp');
view(2);
% Change the colour scheme
colormap('bone')
Result:
Matching your example
You used the Maple command scaletorange=-5..50. This limits the scale between -5 and 50 (docs), so since sir is our scale variable, we should limit it the same. In MATLAB:
% Restrict sir to the range [-5,50]
sir = min(max(sir,-5),50);
% Of course we now have to replot
surf(x,y,sir,'edgecolor','none','facecolor','interp');
view(2);
Now, if you wanted the black/green colours, you can use a custom colormap, this would also smooth out the banding caused by the 'bone' colormap only having 64 colours.
% Define the three colours to interpolate between, and n interpolation points
black = [0 0 0]; green = [0 1 0]; white = [1 1 1];
n = 1000;
% Do colour interpolation, equivalent to Maple's 'colorscheme = [black, "green", "white"]'
% We need an nx3 matrix of colours (columns R,G,B), which we get using interp1
colormap(interp1(1:3, [black; green; white], linspace(1,3,n)));
With g=3.5 (not sure what you used), we get an almost identical plot

Related

Fancy Correlation Plots in MATLAB

I'm trying to find a way to generate these pretty correlation plots in MATLAB. These are generated in R using 'corrplot' function, but couldn't find any similar code in MATLAB. Any help would be appreciated.
As a quick description, this function will create a color scale of the correlation values, and create circles in each cell of the correlation matrix/plot with the associated color. The size of the circles is also an indicator of the magnitude of the correlation, with larger circles representing a stronger relationship (positive or negative). More details could be found here.
you can use plot-corrmat (or modify it, depending how articulate you are in matlab), to obtain similar visualizations of correlation matrices (top pic). Or use Correlation circles , that looks somewhat similar as well (bottom pic)...
https://github.com/elayden/plot-corrmat
I could write the below code to generate a similar graph, based on the code provided here
% Produce the input lower triangular matrix data
C = -1 + 2.*rand(12,12);
C = tril(C,-1);
C(logical(eye(size(C)))) = 1;
% Set [min,max] value of C to scale colors
clrLim = [-1,1];
% load('CorrColormap.mat') % Uncomment for custom CorrColormap
% Set the [min,max] of diameter where 1 consumes entire grid square
diamLim = [0.1, 1];
myLabel = {'ICA','Elev','Pr','Rmax','Rmin','Srad','Wspd','Tmin','Tmax','VPD','ET_o','AW'};
% Compute center of each circle
% This assumes the x and y values were not entered in imagesc()
x = 1 : 1 : size(C,2); % x edges
y = 1 : 1 : size(C,1); % y edges
[xAll, yAll] = meshgrid(x,y);
xAll(C==0)=nan; % eliminate cordinates for zero correlations
% Set color of each rectangle
% Set color scale
cmap = jet(256);
% cmap = CorrColormap; % Uncomment for CorrColormap
Cscaled = (C - clrLim(1))/range(clrLim); % always [0:1]
colIdx = discretize(Cscaled,linspace(0,1,size(cmap,1)));
% Set size of each circle
% Scale the size between [0 1]
Cscaled = (abs(C) - 0)/1;
diamSize = Cscaled * range(diamLim) + diamLim(1);
% Create figure
fh = figure();
ax = axes(fh);
hold(ax,'on')
colormap(ax,'jet');
% colormap(CorrColormap) %Uncomment for CorrColormap
tickvalues = 1:length(C);
x = zeros(size(tickvalues));
text(x, tickvalues, myLabel, 'HorizontalAlignment', 'right');
x(:) = length(C)+1;
text(tickvalues, x, myLabel, 'HorizontalAlignment', 'right','Rotation',90);
% Create circles
theta = linspace(0,2*pi,50); % the smaller, the less memory req'd.
h = arrayfun(#(i)fill(diamSize(i)/2 * cos(theta) + xAll(i), ...
diamSize(i)/2 * sin(theta) + yAll(i), cmap(colIdx(i),:),'LineStyle','none'),1:numel(xAll));
axis(ax,'equal')
axis(ax,'tight')
set(ax,'YDir','Reverse')
colorbar()
caxis(clrLim);
axis off
The exact graph is available here:
Fancy Correlation Plots in MATLAB

matlab quiver3 plot color gradient in z direction? [duplicate]

I want the color of each arrow in a quiver3 plot from MATLAB to correspond to the magnitude of each arrow. Is there any way to do that?
I saw a few examples online that are able to do this for the 2D quiver, however none of them work for the 3D variant, quiver3.
I have the following plot and want to replace the blue arrows with a color corresponding to their magnitude.
In the old graphics system (R2014a and earlier) this is not possible using the built-in quiver object. You can easily get all of the plot objects that are used to compose the quiver plot
q = quiver(1:5, 1:5, 1:5, 1:5);
handles = findall(q, 'type', 'line');
But the tails are all represented by one plot object, and the arrow heads are represented by another. As such, you can't alter the color of each head/tail individually.
set(handles(1), 'Color', 'r')
set(handles(2), 'Color', 'g')
However, with the introduction of HG2 (R2014b and later), you can actually get access to two (undocumented) LineStrip objects (matlab.graphics.primitive.world.LineStrip) (one represents the heads and one represents the tails). These are accessible via the hidden properties Tail and Head.
q = quiver(1, 1, 1, 1);
headLineStrip = q.Head;
tailLineStrip = q.Tail;
You can then alter the color properties of these objects to make each arrow a different color.
The Basic Idea
To do this, I first compute the magnitude of all quiver arrows (this works for both quiver and quiver3)
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
Then I use the current colormap to map each magnitude to an RGB value. The shortest arrow is assigned the lowest color on the colormap and the longest arrow is assigned the highest color on the colormap. histcounts works great for assigning each magnitude an index which can be passed to ind2rgb along with the colormap itself. We have to multiply by 255 because we need the color to be RGB as an 8-bit integer.
% Get the current colormap
currentColormap = colormap(gca);
% Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
% Now map this to a colormap
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
The LineStrip ColorData property (when specified as truecolor) also needs to have an alpha channel (which we will set to 255 meaning opaque).
cmap(:,:,4) = 255;
At this point we can then set the ColorBinding property to interpolated rather than object (to decouple it from the quiver object) and set the ColorData property of both q.Head and q.Tail to the colors we created above giving each arrow it's own color.
Full Solution
NOTE: This solution works for both quiver and quiver3 and the code does not have to be adapted at all.
%// Create a quiver3 as we normally would (could also be 2D quiver)
x = 1:10;
y = 1:10;
[X,Y] = meshgrid(x, y);
Z = zeros(size(X));
U = zeros(size(X));
V = zeros(size(X));
W = sqrt(X.^2 + Y.^2);
q = quiver3(X, Y, Z, U, V, W);
%// Compute the magnitude of the vectors
mags = sqrt(sum(cat(2, q.UData(:), q.VData(:), ...
reshape(q.WData, numel(q.UData), [])).^2, 2));
%// Get the current colormap
currentColormap = colormap(gca);
%// Now determine the color to make each arrow using a colormap
[~, ~, ind] = histcounts(mags, size(currentColormap, 1));
%// Now map this to a colormap to get RGB
cmap = uint8(ind2rgb(ind(:), currentColormap) * 255);
cmap(:,:,4) = 255;
cmap = permute(repmat(cmap, [1 3 1]), [2 1 3]);
%// We repeat each color 3 times (using 1:3 below) because each arrow has 3 vertices
set(q.Head, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:3,:,:), [], 4).'); %'
%// We repeat each color 2 times (using 1:2 below) because each tail has 2 vertices
set(q.Tail, ...
'ColorBinding', 'interpolated', ...
'ColorData', reshape(cmap(1:2,:,:), [], 4).');
And applied to a 2D quiver object
If you don't necessarily want to scale the arrows to the entire range of the colormap you could use the following call to histcounts (instead of the line above) to map the magnitudes using the color limits of the axes.
clims = num2cell(get(gca, 'clim'));
[~, ~, ind] = histcounts(mags, linspace(clims{:}, size(currentColormap, 1)));
If your using a post r2014b version you can use undocumented features to change the colour of each line and head:
figure
[x,y] = meshgrid(-2:.5:2,-1:.5:1);
z = x .* exp(-x.^2 - y.^2);
[u,v,w] = surfnorm(x,y,z);
h=quiver3(x,y,z,u,v,w);
s = size(x);
nPoints = s(1)*s(2);
% create a colour map
cmap = parula(nPoints);
% x2 because each point has 2 points, a start and an end.
cd = uint8(repmat([255 0 0 255]', 1, nPoints*2));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the start and end of the
% line.
for jj=1:2
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the tail
set(h.Tail, 'ColorBinding','interpolated', 'ColorData',cd)
% create a color matrix for the heads
cd = uint8(repmat([255 0 0 255]', 1, nPoints*3));
count = 0;
% we need to assign a colour per point
for ii=1:nPoints
% and we need to assign a colour to the all the points
% at the head of the arrow
for jj=1:3
count = count + 1;
cd(1:3,count) = uint8(255*cmap(ii,:)');
end
end
% set the colour binding method and the colour data of the head
set(h.Head, 'ColorBinding','interpolated', 'ColorData',cd)
Note: I've not done anything clever with the magnitude and simply change the colour of each quiver based on the order in the original matrix - but you should be able to get the idea on how to use this "feature"
Note that if you are using Suevers solution and have NaNs in your data you should include this line before calling histcounts:
mags(isnan(mags)) = [];
Otherwise you will get an error about wrong input size because matlab does not create vertices for NaNs in your U/V/W data.

Specifying quiver vector color by density

I have some vectors with defined position and orientation. I could show them in space by using the below code:
theta = [pi/2,-pi/2,pi/2,pi/2,pi/2,pi/2,pi/2];
r = 0.25; % magnitude (length) of arrow to plot
x = [4,3.5,3.75,4.5,8,10,12]; y = [8.5,8.2,8.3,8,9,10,8];
u = r * cos(theta); % convert polar (theta,r) to cartesian
v = r * sin(theta);
h = quiver(x,y,u,v,'linewidth',2);
set(gca, 'XLim', [2 15], 'YLim', [4 15]);
As is clear from the image, in some regions the number of arrows is more than in other places. I want to show the arrows by color, where each color represents the density of the arrows.
Could anyone help me to do that? It would also be a good solution if there is a continuous background color which shows local densities.
Edit: Below are some options for colouring the background of the plot depending on the density of your points. I'm editing this into the top of my answer because it actually answers your question - individually colouring quiver arrows based on density!
x = rand(200,1)*10; y = rand(200,1)*10; % Set up random points
r = 1; u = r * cos(x); v = r * sin(y); % Quiver directions
colormap winter; c = colormap; % Set colourmap and assign to matrix
% Get density of points broken into a 10x10 grid
[n,~,~,binX,binY] = histcounts2(x,y,[10,10]);
% Get colour based on histogram density and chosen colormap colours
col = c(ceil(n(sub2ind(size(n), binX, binY))/max(n(:))*size(c,1)),:);
figure; hold on;
% Each quiver point must be plotted individually (slow!) because colours can
% only be applied to individual quivers. This could be sped up by plotting
% all of the same colour at once.
for ii = 1:size(x,1);
quiver(x(ii),y(ii),u(ii),v(ii),0,'color',col(ii,:));
end
Output:
Note: unlike the below example, you cannot use hist3 because you need it to return the bin index too. You could try this File Exchange function to achieve the same result (untested).
Here is an option using hist3 to get the density (in this example I use a 10x10 grid, as specified when calling hist3). Then using pcolor to display the density, and shading interp to smooth the colours.
Note: hist3 requires the Stats & ML toolbox, if you have Matlab 2015b or newer you can instead use the standard function histcounts2(x,y).
% Generate points and quiver directions
x = rand(200,1)*10; y = rand(200,1)*10;
u = r * cos(x); v = r * sin(y);
% Get density of points, format for input to pcolor
n = hist3([x,y],[10,10]); % Get density of points broken into a 10x10 grid
colx = linspace(min(x),max(x),size(n,1)+1);
coly = linspace(min(y),max(y),size(n,1)+1);
n = n'; n(size(n,2)+1,size(n,1)+1) = 0;
% Plot
figure
pcolor(colx,coly,n) % Density plot
hold on; colorbar; % Hold on for next plot and show colour bar key
quiver(x,y,u,v,'r') % Quiver plot
shading interp % Smooth plot colours
Output:
Edit: making the colours more muted
You can control the colours using colormap. This could be one of the defaults, or you can create a custom map of RGB triplets and have whatever colours you want! Here is an example, simply calling colormap bone; at the end of the above code:
In a custom colour map, you could make the colours even more muted / less contrasting.
Additionally, you can use caxis to scale the colour axis of a plot! Simply call
caxis([0,2*max(n(:))]);
at the end of the above code to double the maximum colour map value. You can tweak the 2 to get desired results:
this looks way less fancy but specifies the arrow color as function of the number of arrows in a certain number of bins of the x-axis
close all;
cm=colormap;
theta = [pi/2,-pi/2,pi/2,pi/2,pi/2,pi/2,pi/2];
r = 0.25; % magnitude (length) of arrow to plot
x = [4,3.5,3.75,4.5,8,10,12]; y = [8.5,8.2,8.3,8,9,10,8];
[n,c]=hist(x,5); %count arroes in bins
u = r * cos(theta); % convert polar (theta,r) to cartesian
v = r * sin(theta);
figure;hold on
for ii=1:numel(n) %quiver bin by bin
if n(ii)>0
if ii==1
wx=find(x<(c(ii)+(c(ii+1) - c(ii))/2)); %Which X to plot
elseif ii==numel(n)
wx=find(x>c(numel(n)-1));
else
wx=find((x>(c(ii)-(c(ii)-c(ii-1))/2)).*(x<(c(ii+1)-(c(ii+1)-c(ii))/2)));
end
indCol=ceil( (size(cm,1)*n(ii)-0) / max(n));%color propto density of arrows %in this bin
col = cm(indCol,:);%color for this bin
h = quiver(x(wx),y(wx),u(wx),v(wx),0,'linewidth',2,'color',col);
end
end
colorbar
caxis([0 max(n)])

2-D line gradient color in Matlab

Is it possible to add gradient color to 2-D line in Matlab, especially when you have small number of data points (less than 10?), so the result would be similar to one in image below?
This is not difficult if you have MATLAB R2014b or newer.
n = 100;
x = linspace(-10,10,n); y = x.^2;
p = plot(x,y,'r', 'LineWidth',5);
% modified jet-colormap
cd = [uint8(jet(n)*255) uint8(ones(n,1))].';
drawnow
set(p.Edge, 'ColorBinding','interpolated', 'ColorData',cd)
Which results in:
Excerpted from Undocumented Features - Color-coded 2D line plots with color data in third dimension. The original author was thewaywewalk. Attribution details can be found on the contributor page. The source is licenced under CC BY-SA 3.0 and may be found in the Documentation archive. Reference topic ID: 2383 and example ID: 7849.
Here's one possible approach: explicitly plot each segment of the line with a different color taken from the desired colormap.
x = 1:10; % x data. Assumed to be increasing
y = x.^2; % y data
N = 100; % number of colors. Assumed to be greater than size of x
cmap = parula(N); % colormap, with N colors
linewidth = 1.5; % desired linewidth
xi = x(1)+linspace(0,1,N+1)*x(end); % interpolated x values
yi = interp1(x,y,xi); % interpolated y values
hold on
for n = 1:N
plot(xi([n n+1]), yi([n n+1]), 'color', cmap(n,:), 'linewidth', linewidth);
end

Plotting the implicit function x+y - log(x) - log(y) -2 = 0 on MATLAB

I wanted to plot the above function on Matlab so I used the following code
ezplot('-log(x)-log(y)+x+y-2',[-10 10 -10 10]);
However I'm just getting a blank screen. But clearly there is at least the point (1,1) that satisfies the equation.
I don't think there is a problem with the plotter settings, as I'm getting graphs for functions like
ezplot('-log(y)+x+y-2',[-10 10 -10 10]);
I don't have enough rep to embed pictures :)
If we use solve on your function, we can see that there are two points where your function is equal to zero. These points are at (1, 1) and (0.3203 + 1.3354i, pi)
syms x y
result = solve(-log(x)-log(y)+x+y-2, x, y);
result.x
% -wrightOmega(log(1/pi) - 2 + pi*(1 - 1i))
% 1
result.y
% pi
% 1
If we look closely at your function, we can see that the values are actually complex
[x,y] = meshgrid(-10:0.01:10, -10:0.01:10);
values = -log(x)-log(y)+x+y-2;
whos values
% Name Size Bytes Class Attributes
% values 2001x2001 64064016 double complex
It seems as though in older versions of MATLAB, ezplot handled complex functions by only considering the real component of the data. As such, this would yield the following plot
However, newer versions consider the magnitude of the data and the zeros will only occur when both the real and imaginary components are zero. Of the two points where this is true, only one of these points is real and is able to be plotted; however, the relatively coarse sampling of ezplot isn't able to display that single point.
You could use contourc to determine the location of this point
imagesc(abs(values), 'XData', [-10 10], 'YData', [-10 10]);
axis equal
hold on
cmat = contourc(abs(values), [0 0]);
xvalues = xx(1, cmat(1,2:end));
yvalues = yy(cmat(2,2:end), 1);
plot(xvalues, yvalues, 'r*')
This is because x = y = 1 is the only solution to the given equation.
Note that the minimum value of x - log(x) is 1 and that happens when x = 1. Obviously, the same is true for y - log(y). So, -log(x)-log(y)+x+y is always greater than 2 except at x = y = 1, where it is exactly equal to 2.
As your equation has only one solution, there is no line on the plot.
To visualize this, let's plot the equation
ezplot('-log(x)-log(y)+x+y-C',[-10 10 -10 10]);
for various values of C.
% choose a set of values between 5 and 2
C = logspace(log10(5), log10(2), 20);
% plot the equation with various values of C
figure
for ic=1:length(C)
ezplot(sprintf('-log(x)-log(y)+x+y-%f', C(ic)),[0 10 0 10]);
hold on
end
title('-log(x)-log(y)+x+y-C = 0, for 5 < C < 2');
Note that the largest curve is obtained for C = 5. As the value of C is decreased, the curve also becomes smaller, until at C = 2 it completely vanishes.