Matlab - adapt xlim and ylim to remove white margin with surfc - matlab

I get an issue about the plot of 2d map of a surface with temperature (represented by color). The solution that I plot here is symmetric.
array x represents the array containing the temperature on (sizex,sizey) map size. In my code, sizex = 256 and sizey = 96.
I plot with the following code snippet :
surfc(x);
shading interp;
view([0,0,1]);
hc=colorbar;
set(hc,'position',[0.932 0.3 0.02 0.6]);
caxis([-10 10]);
xlabel('x domain');
ylabel('y domain');
zlabel('temperature');
xlim([0 sizex+2]);
ylim([0 sizey+2]);
and I get the following figure :
As you can see in the script, I added "2" to sizex and sizey to fill a white exterior margin.
If I don't add these values, i.e doing :
xlim([0 sizex]);
ylim([0 sizey]);
Then, I get the following figure :
And you can notice that parts of solution on right and upper sides are not displayed (rather hidden).
You can also see that even on the first figure above (like also for the second figure) (with adding "2" to xlim and ylim), it remains a slight white margin on bottom and I don't know how to remove it.
More precisely, I would like to fit exactly the dimensions of plot with dimensions of the grid data, i.e having temperature over 256x96 size without having margins.

First of all you defined sizex and sizey wrong. I copied your data from pastebin and size(x) yields [258,98] and not [256,96].
Now the other problem that you have is the following: You feed a 2D-Matrix x to surfc. Now what the command does, is putting the value x(1,1) at position (1,1) in the plot. If you don't want these "white borders" you need to put the value at position (0,0) instead. You can achieve that by feeding three matrices X,Y,Z to the surfc-command. You can genereate the matrices as follows:
[X,Y]=meshgrid(0:size(x,2)-1,0:size(x,1)-1);
Z=x;
surfc(X,Y,Z);
% From here on your regular code starts
shading interp;
view([0,0,1]);
hc=colorbar;
set(hc,'position',[0.932 0.3 0.02 0.6]);
caxis([-10 10]);
xlabel('x domain');
ylabel('y domain');
zlabel('temperature');
You should not need to define the limits of the plot now. In case you still need to, use this:
xlim([0,size(x,2)-1]);
ylim([0,size(x,1)-1]);

Related

Matlab: Plot a line over an image plot

I want to plot a line plot on top of an image plot in Matlab
First I plot the image data
figure(1); clf;
imagesc(t); colorbar
hold on;
axis tight
and then the line plot
line(ysum,y,'Color','red')
hold off;
The line plot however deletes the image and sets the background to white.
How can I plot on top of the image?
Your code isn't wrong, but it is not a minimal reproducible example, since you haven't defined t, y, ysum. When you call imagesc(t) the rows and columns will be the indices of t. In other words, it is the same as calling imagesc([1, size(t,2)], [1, size(t,1)], t). If t is small (say 10 x 10) but the elements of y,ysum are large (e.g. > 1000) then the 10 x 10 image will still be there, but it will be squished into the corner. Almost invisible.
So you need to make sure that the range of y, ysum, t line up. A quick work-around:
xidx = [min(ysum), max(ysum)];
yidx = [min(y), max(y)];
imagesc(xidx, yidx, t);

How to plot point and vectors in Matlab

A = [239920.240412166 1.31193313030682;
243577.444235102 1.38185205485119;
241899.250050298 1.51264147493485;
244659.326936560 1.50845243215867;
239862.361809342 1.50810833389632;
238395.616682194 1.37125000688350;
244558.389789124 1.27212093329482;
244290.890880318 1.35116080948488;
240303.711239396 1.36064181572699;
237464.430450140 1.48857869573721;
244415.381196104 1.51252425335623;
239855.328594799 1.29178640586301;
239304.806448742 1.31075813783171;
244827.243024016 1.32080934043223;
241465.885648910 1.53667019314427;
241139.254464482 1.40424079027764;
242300.037630214 1.27160249886092;
243330.396959248 1.61411410292679;
237530.389940994 1.21846939260826];
B = [0.6 0.18; 0.15 0.46]; % green circles
for i=1:2
plot(A(:,1),A(:,2),'r*');
hold on
plot(B(i,1),B(i,2), '-ko',...
'LineWidth',1,...
'MarkerFaceColor',[.49 1 .63],...
'MarkerSize',9);
end
When I ploted A and B, I got this:
B(1,1) = 0.6, but it appears in 0 (X-axis). Same with B(2,1) = 0.15
How to correct this?
A logarithmic scale on the xaxis will help with the view
set(gca, 'XScale', 'log')
However, it will lead to the fact, that now the values of A appear to populate one vertical line.
If you cannot live with this, you may want to try a broken x-axis. MATLAB doesn't support this with build-in functions, but there is a solution in the MATLAB file exchange
https://de.mathworks.com/matlabcentral/fileexchange/3683-breakxaxis
Btw: There is no need for the loop in your code. In fact you plot A twice on top of each other. Just
% Plot A and B without loop
plot(A(:,1), A(:,2),'r*')
hold on
plot(B(:,1), B(:,2), '-ko', 'LineWidth', 1, ...
'MarkerFaceColor', [.49 1 .63], 'MarkerSize',9)
% Set x axis to logarithmic scale
set(gca, 'XScale', 'log')
is sufficient to display your plot
Your x-axis goes from 0 to 250000. On that range, 0.6 and 0.15 are practically 0.
If you want you can use logarithmic scale in x-axis using semilogx

Matlab Image and Plot with Unexpected Flip

In the examples below, there are some obvious code differences in each case, but I don't understand how they would change the orientation of the image or the plot, as shown in each case.
The original image has a size of 407 x 813 x 3.
For the data in the contour, X ranges from -180 to +175, Y ranges from -85 to +85
For the image, I am trying to fit it so that X ranges from -180 to +180, Y ranges from -90 to +90. So the image covers a slightly wider geographic range than the image does.
I have a contour plot of some geographic data. It plots like this, and looks like I expect it to look:
The code to plot this looks is
figure (1);
contour(X, Y, dec0Mat,contoursAt, 'ShowText','on', 'LineWidth', 2);
colormap('Gray');
I can plot the image by itself, and it looks ok:
using this code:
figure (99)
imagesc([-180 180], [-90 90], worldMap);
But when I try to combine the two, I get this:
Using this code:
figure (1);
image([-180 180], [-90 90], worldMap);
hold on
title('Declination at elev = 0 km');
contour(X, Y, dec0Mat,contoursAt, 'ShowText','on', 'LineWidth', 2);
colormap('Gray');
In this case the map looks right, but the contour is flipped vertically.
In another case, I get this:
Using this code:
figure (3);
hold on
title('Declination at elev = 30 km');
imagesc([-180 180], [-90 90], worldMap);
contour(X, Y, dec30Mat,contoursAt, 'ShowText','on', 'LineWidth', 2);
colormap('Gray');
In this case the map is flipped vertically and the contour is plotted right.
Going by the Matlab documentation for imagesc, it says:
imagesc(x,y,C) displays C as an image and specifies the bounds of the
x- and y-axis with vectors x and y. If x(1) > x(2) or y(1) > y(2), the
image is flipped left-right or up-down, respectively. If x and y are
scalars, the image is translated to the specified location (x,y) such
that the upper left corner of the image starts at (x,y).
I highlighted what might be relevant for an image being flipped, but neither seems to be the case here and wouldn't explain the inconsistency where is is flipped in one case and not the other.
The explanation is that the imagesc command, like image, sets the 'Ydir' axis property to 'reverse'.
When called with C or X,Y,C, image sets the axes limits to tightly enclose the image, sets the axes YDir property to 'reverse', and sets the axes View property to [0 90].
This means that the vertical axis values increase from the top of the axis to the bottom.
Now you can compare the two cases:
If you run the contourf command by itself, you have the "normal" axis mode, with vertical axis values increasing from the bottom of the axis to the top. The vertical axis labelling in your first figure reflects that.
If you plot the image with imagesc and run contour on the same figure, the vertical axis is first flipped by imagesc. The subsequent contour command operates on a flipped vertical axis, and plots accordingly. That's why the contour lines are vertically flipped with respect to case 1.
Note that the combined figure obtained in case 2 is correct. If you "visually" combined the first two images of your question (which were obtained from calling imagesc and countour independently) it would be wrong, because they have different vertical axes.
This is not exactly a problem of rotation, but more a problem of vertical flip.
If you look carefully at your first two plots, you'll see that the vertical scales are flipped, so if you combine your two plots directly (whatever the way) you will end up with what you observe, i.e. one plot that is flipped with respect to the other.
I would suggest to flip the contour plot before superposition:
hold on
image([-180 180], [-90 90], worldMap);
title('Declination at elev = 0 km');
contour(X, Y, flipud(dec0Mat), contoursAt, 'ShowText','on', 'LineWidth', 2);
colormap('Gray');
or
hold on
image([-180 180], [-90 90], worldMap);
title('Declination at elev = 0 km');
contour(X, -Y, dec0Mat, contoursAt, 'ShowText','on', 'LineWidth', 2);
colormap('Gray');
Best,

Xtick marks and Xtick labels on heatmap in Matlab

Environment: Windows 7 64 bit, Matlab 2014a
Objective:
To draw a heatmap of errors for two parameters to be optimized.
To put proper tick marks and tick values
Draw the grid lines in the correct place
Problem: Arranging the X and Y tick positions and values. When the last ("end") value of the vectors in x and y axes are the same, the code I use puts the ticks and values properly. However, when the end values are different it does not, and produces something really weird.
Below I have included the code which I have modified so that you can run it without the need of adding anything. Of course in my case the error vector are the error values, not random numbers. To see the problem of "end value" use the second b vector.
fontsize = 20
k = [2^-5, 2^-3, 2^-1, 2^0, 2^1, 2^3, 2^5, 2^7, 2^9, 2^11, 2^13, 2^15]
b = [2^-5, 2^-3, 2^-1, 2^0, 2^1, 2^3, 2^5, 2^7, 2^8, 2^9, 2^10, 2^11, 2^13, 2^15]
% b = [2^-5, 2^-3, 2^-1, 2^0, 2^1, 2^3, 2^5, 2^7, 2^8, 2^9, 2^10, 2^11, 2^13, 2^19]
errorVector = randi(20, 1, length(b)*length(k))'
figure
% Create a matrix from error vector (size of error vector is [length(k)*length(b),1])
B = reshape(errorVector, [length(b), length(k)])
B = flipud(B)
% imagesc(x,y,C)
imagesc(b, k, B)
title('Heatmap Parameters Percent Error', 'FontSize', fontsize);
% Set colorbar limits
caxis([0 15])
colorbar;
ax1 = gca;
xTickLabel = (k)'
xTick = linspace(k(1), k(end), numel(xTickLabel))';
set(ax1, 'XTick', xTick, 'XTickLabel', xTickLabel)
xlabel('k parameter', 'FontSize', fontsize)
yTickLabel = (b)'
yTick = linspace(b(1), b(end), numel(yTickLabel))';
set(ax1, 'YTick', yTick, 'YTickLabel', flipud(yTickLabel(:)))
ylabel('b parameter', 'FontSize', fontsize)
set(ax1,'FontSize', fontsize)
Here, change any of the end values of b or k vectors, and the program will output a graph where the X and Y ticks are totally wrong.
Also, I would like to draw grid lines. When I use "grid on" it draws grid lines right on the tick marks which is not correct in the case of heatmap. Because tick marks will be in the center of the columns -or rows- but the grid lines should be at the boundaries between the columns -or rows.
By the way if you know a better way to plot a heatmap in Matlab, please do tell.
Please help me solve this problem. Any help is appreciated,
Ilyas
First of all - you don't need to flipud the B matrix - by default imagesc plots the y-data inversed, but you can fix this with the following statement:
set(gca,'ydir','normal');
This also means you don't have to mess around with flipping the tick-labels. You can get the labels right by doing the following:
% replace the imagesc call with:
imagesc(B);
set(gca,'ydir','normal');
% formatting stuff
...
% replace the set commands with:
set(ax1, 'XTick', 1:length(k), 'XTickLabel', k)
set(ax1, 'YTick', 1:length(b), 'YTickLabel', b)
By default, if you don't provide x and y data to the imagesc command, it will number them linearly (1,2,3...). Basically what we've done here is make sure that it has ticks for each of the elements of b and k, and then set the labels to the values of the respective vectors.
Unfortunately, I'm not sure if there is a way to get the grid spacing right with imagesc or not. You could try using pcolor instead, which has it's own set of issues, but allows you to get grid lines (of sorts) between the elements. It also allows you to use an interpolated shading mode, which will make your plot look more like a typical heat map.
To use pcolor instead, you just have to replace imagesc:
% imagesc(B);
% set(gca,'ydir','normal');
pcolor(B);
% this uses a smoother shading method, for a more 'heatmap' like output
% shading interp
Everything else should work as intended, I believe.

Plot vector (or arc) onto a rose plot. MATLAB

I have two datasets. One detailing a list of angles (which I am plotting onto a rose plot):
angles
-0.8481065519
0.0367932161
2.6273740453
...
n
The other, detailing directional statistics from this group of angles:
angle,error
-0.848106563,0.8452778824
Where angle essentially defines the directional mean, and error the circular variance, essentially an error bar either side of the angle
I have thus far plotted a rose histogram using the set of angles, as such:
h = rose(angles,36)
I would like to create a plot of the directional statistic angle (it does not need a length/magnitude - just to the edge of the circle plot) with the error around it.
As an example:
I added the lines by hand in Matlab. If possible it would be good to perhaps have shading within the arc too. Alternatively, (and possibly preferred) would be to have just a sliver above the rose plot bins (so it doesn't cover the data) with a centre line (showing the angle and shading surrounding for the error.
Thanks in advance.
How about this?
%// Data
angles = 2*pi*.8*randn(1,1e4);
angle = -0.848106563;
error = 0.8452778824;
%// Plot rose
rose(angles, 36);
axis image %// make axis square
hold on
%// Plot mean
a = axis;
a = a(2); %// size of axis
plot([0 cos(angle)*a], [0 sin(angle)*a], 'r')
%// Plot error as many shaded triangles that compose a circular wedge
t = linspace(-error/2+angle,error/2+angle,100); %// increase "100" if needed
for k = 1:numel(t)-1
h = patch([0 cos(t(k))*a cos(t(k+1))*a 0], ...
[0 sin(t(k))*a sin(t(k+1))*a 0], [.5 0 0], 'edgecolor', 'none');
%// change color [.5 0 0] to something else if desired. Note also alpha
set(h,'Facealpha',.3) %// make transparent
end
%// Place rose on top by rearranging order of axis children
ch = get(gca,'children');
set(gca,'children',[ch(2:end); ch(1)]);
For this to work, you need to use a figure renderer capable of transparency. So you may need to adjust the figure's renderer property.