Matlab axis error using imagesc - matlab

I am plotting multiple heatmaps in matlab 3014b using imagesc with one common colorbar. Here is my code:
a(1)= subplot('Position',[0.1, 0.65, 0.3, 0.3]);
data1 = rand(5);
imagesc(data1)
ax = gca;
ax.XTick = [1 2 3 4 5 6];
ax.XTickLabel = {'0','0.1', '0.2', '0.3','0.4','0.5'};
ax.YTick = [1 2 3 4 5 6];
ax.YTickLabel = {'1','10', '100', '1000', '10000', '100000'};
a(2)= subplot('Position',[0.45, 0.65, 0.3, 0.3]);
data2 = rand(5);
imagesc(data2)
ax = gca;
ax.XTick = [1 2 3 4 5 6];
ax.XTickLabel = {'0','0.1', '0.2', '0.3','0.4','0.5'};
ax.YTick = [1 2 3 4 5 6];
ax.YTickLabel = {'1','10', '100', '1000', '10000', '100000'};
h=colorbar;
set(h, 'Position', [.8 .135 .0581 .8150])
for i=1:2
pos=get(a(i), 'Position');
set(a(i), 'Position', [pos(1) pos(2)]);
end
But I get the following error:
Error using matlab.graphics.axis.Axes/set
While setting the 'Position' property of Axes:
Value must be a 4 element vector
Not exactly sure how to resolve this? Thanks!

Error is right here:
for i=1:2
pos=get(a(i), 'Position');
set(a(i), 'Position', [pos(1) pos(2)]); %// <--- here
end
Is there a particular reason why you're truncating the last two elements? Position should be a 4 element vector where the first two elements define the distance from the lower-left corner of the container to the lower-left corner of the axes, and the third and fourth element are the width and height of the axes within the window. If it's your intention to perhaps keep all of the axes the same width/height, do something like this:
for i=1:2
pos=get(a(i), 'Position');
set(a(i), 'Position', [pos(1) pos(2) 1 1]); %// Change
end
Check out the documentation on MathWorks on axes properties... specifically Position here: http://www.mathworks.com/help/matlab/ref/axes-properties.html#zmw57dd0e52524

Related

Correctly aligning labels for subgroups within a tiledlayout

I want to put 5 plots in a figure using tiledlayout, 2x2 plots at the top then a plot at the bottom that spans two columns. There should be two sets of axis labels: one for the 2x2 plot and another for the bottom plot. My MWE is
x = linspace(-2,2,100);
y1 = sin(x);
y2 = cos(x);
y3 = sin(x).*cos(2*x);
y4 = sin(2*x).*cos(x);
y5 = y3 + y4;
figure('PaperUnits', 'inches', 'PaperSize', [4 6], 'PaperPosition', [0 0 4 6]);
t = tiledlayout(3,2,'TileSpacing','compact','Padding','compact');
nexttile; plot(x,y1); title('y_1');
nexttile; plot(x,y2); title('y_2');
nexttile; plot(x,y3); title('y_3');
nexttile; plot(x,y4); title('y_4');
xlabel(t,'time t_\alpha')
ylabel(t,'amplitude \alpha')
nexttile([1 2]); plot(x,y5); title('y_5');
xlabel('time t_\beta')
ylabel('amplitude \beta')
saveas(gcf,'myfig.jpg')
This gives me the following figure:
I want the amplitude \alpha ylabel and the time t_alpha xlabel to be aligned correctly for the 2x2 plots (as indicated by my red annotations). Is there a way to do this?
I'm using MATLAB R2020a. Note that the tiledlayout function was introduced in R2019b.
An approximation of what you wanted can be achieved by the approach I mentioned in my comment (using a "nested" tiledlayout). The steps necessary to make it work are:
Creating an external vertical layout.
Reserving the first two rows for the nested tiledlayout, by asking a 2-by-1 nexttile, making the resulting axes hidden, and creating a uipanel in its place. Calling uipanel is necessary because the parent of a tiledlayout cannot be another tiledlayout, but it can be a Panel.
Plotting everything in the appropriate panels, and applying the labels accordingly.
x = linspace(-2,2,100);
y1 = sin(x);
y2 = cos(x);
y3 = sin(x).*cos(2*x);
y4 = sin(2*x).*cos(x);
y5 = y3 + y4;
hF = figure('PaperUnits', 'inches', 'PaperSize', [4 6], 'PaperPosition', [0 0 4 6]);
tOut = tiledlayout(hF,3,1);
hAx = nexttile(tOut, [2,1]); hAx.Visible = 'off';
hP = uipanel(hF, 'Position', hAx.OuterPosition, 'BorderWidth', 0);
tIn = tiledlayout(hP,2,2,'TileSpacing','compact','Padding','compact');
nexttile(tIn); plot(x,y1); title('y_1');
nexttile(tIn); plot(x,y2); title('y_2');
nexttile(tIn); plot(x,y3); title('y_3');
nexttile(tIn); plot(x,y4); title('y_4');
xlabel(tIn,'time t_\alpha')
ylabel(tIn,'amplitude \alpha')
hAx = nexttile(tOut); plot(x,y5); title('y_5');
xlabel(hAx, 'time t_\beta')
ylabel(hAx, 'amplitude \beta')
Resulting in:
From here you can try tweaking the individual GUI elements (layouts, axes, panel) to get a result closer to what you wanted.
A completely different route I can suggest is starting with your code and adding the labels for the top 4 plots using the annotation function (instead of xlabel and ylabel).

How can I add vertical lines to my confusion matrix generated with matlab?

I have used the following code to generate my confusion matrix, which I have found it on internet :
confmat = C;
labels = {'0', '1', '2', '3', '11' };
numlabels = size(confmat, 1); % number of labels
confpercent = 100*confmat./repmat(sum(confmat, 1),numlabels,1);
imagesc(confpercent);
Mycolors=[0 0.7 0.4; 1 0.9 0.9 ]
colormap(flipud(Mycolors));
textStrings = num2str([confpercent(:)], '%.1f%%\n');
textStrings = strtrim(cellstr(textStrings));
[x,y] = meshgrid(1:numlabels);
hStrings = text(x(:),y(:),textStrings(:), ...
'HorizontalAlignment','center');
midValue = mean(get(gca,'CLim'));
textColors = repmat(confpercent(:) > midValue,1,3);
set(hStrings,{'Color'},num2cell(textColors,2));
set(gca,'XTick',1:numlabels,... 'XTickLabel',labels,... 'YTick',1:numlabels,... 'YTickLabel',labels,... 'TickLength',[0 0]);
I have gotten the next matrix
While I want to add vertical lines to my matrix to separate between values so I can get a similar one to the next :
I could get those vertical lines using pcolor(confusion_matrix) but the percentages are shiffted to the corner of each grid and I have got the next picture :
Use another axes object
The classic MATLAB trick when having to deal with different axes properties.
Basically we are going to create a new axes object, place it on top of the precious one, then make it transparent (no background color) so we can see what's behind, but we'll keep the grid lines well visible right where we want them.
So immediately after your sample code, add:
ax1 = gca ; % get handle of initial axes
ax2 = axes ; % create new axe and retrieve handle
lim = [0 numlabels] ; % Prepare X and Y properties
tks = 0:numlabels ;
% superpose the new axe on top, at the same position
set(ax2,'Position', get(ax1,'Position') );
% make it transparent (no color)
set(ax2,'Color','none') ;
% set the X and Y properties
set(ax2, ...
'XLim',lim,'XTick',tks,'XTickLabel','' ,...
'YLim',lim,'YTick',tks,'YTickLabel','' ) ;
% now set your grid properties
set(ax2,'GridColor','k','GridAlpha',1)
This will get you (data differ a bit because I randomly generated the confusion matrix):
Of course now you have full control over your grid lines, so you can also refine how they appear through the grid properties of the axes. A few interesting properties are:
GridLineStyle — Line style for grid lines
GridColor — Color of grid lines
GridAlpha — Grid-line transparency
LineWidth — Line width
For more details, look at the documentation for Axes Properties
Well !
I have found the requested thing to get the vertical and horizantal line, which is adding the lines simply using plot and hold on :
I have used the next code at the end of the mentioned one in my question :
hold on
plot ([2 2],get(gca, 'YLim'), 'Color', [0.15, 0.15, 0.15],'LineWidth',0.5)
plot ([1 1],get(gca, 'YLim'), 'Color', [0.15, 0.15, 0.15],'LineWidth',0.5)
plot ([3 3],get(gca, 'YLim'), 'Color', [0.15, 0.15, 0.15],'LineWidth',0.5)
plot ([4 4],get(gca, 'YLim'), 'Color', [0.15, 0.15, 0.15],'LineWidth',0.5)
plot (get(gca, 'XLim'), [1 1], 'Color', [0.15, 0.15, 0.15],'LineWidth',0.5)
plot (get(gca, 'XLim'), [2 2], 'Color', [0.15, 0.15, 0.15],'LineWidth',0.5)
plot (get(gca, 'XLim'), [3 3], 'Color', [0.15, 0.15, 0.15],'LineWidth',0.5)
plot (get(gca, 'XLim'), [4 4], 'Color', [0.15, 0.15, 0.15],'LineWidth',0.5)
I have used 1, 2, 3 and 4 because I have four classes and at the end of each class prediction results I need to plot the line.
Hope that will be useful

3 x-axis in matlab plot?

I need to plot a figure with 3 x-axes. Each axis is linked to the other by a mathematical formula. I want to do this because the x value can be seen as wavelength [nm], velocity [m/s] or energy [eV] and I want the reader to not have to convert it themselves on each graph.
I searched online and only found something for 2 x-axes, but no more.
Edit: I am using version R2011a.
So it should look like this, which I (obviously) didn't create in MATLAB:
Thanks in advance!
As shown in this answer, you can create a new axes object with near-zero height, so that it is essentially just the x-axis. Be aware that all actual plots must be done on the first axes as this is the area you can see!
Demo code:
% Create some plotting data and plot
x = 0:0.1:2*pi; y = sin(x);
% Plot, can specify line attributes (like LineWidth) either
% - inline: plot(x,y,'linewidth',2)
% - after: p1 = plot(x,y); p1.LineWidth = 2;
plot(x,y);
% Get current axes object (just plotted on) and its position
ax1 = gca;
axPos = ax1.Position;
% Change the position of ax1 to make room for extra axes
% format is [left bottom width height], so moving up and making shorter here...
ax1.Position = axPos + [0 0.3 0 -0.3];
% Exactly the same as for plots (above), axes LineWidth can be changed inline or after
ax1.LineWidth = 2;
% Add two more axes objects, with small multiplier for height, and offset for bottom
ax2 = axes('position', (axPos .* [1 1 1 1e-3]) + [0 0.15 0 0], 'color', 'none', 'linewidth', 2);
ax3 = axes('position', (axPos .* [1 1 1 1e-3]) + [0 0.00 0 0], 'color', 'none', 'linewidth', 2);
% You can change the limits of the new axes using XLim
ax2.XLim = [0 10];
ax3.XLim = [100 157];
% You can label the axes using XLabel.String
ax1.XLabel.String = 'Lambda [nm]';
ax2.XLabel.String = 'Velocity [m/s]';
ax3.XLabel.String = 'Energy [eV]';
Output:
Edit:
Before the 2014b graphics changes you will need to make a couple of tweaks for getting and setting axes properties. The equivalent code would more heavily use the set command, and look something like this:
x = 0:0.1:2*pi; y = sin(x);
plot(x,y);
ax1 = findobj(gca, 'type', 'axes')
axPos = get(ax1, 'Position');
set(ax1, 'Position', axPos + [0 0.3 0 -0.3]);
set(ax1, 'LineWidth', 2);
ax2 = axes('position', (axPos .* [1 1 1 1e-3]) + [0 0.15 0 0], 'color', 'none', 'linewidth', 2);
ax3 = axes('position', (axPos .* [1 1 1 1e-3]) + [0 0.00 0 0], 'color', 'none', 'linewidth', 2);
set(ax2, 'xlim', [0 10]);
set(ax3, 'xlim', [100 157]);
axes(ax1); xlabel('Lambda [nm]');
axes(ax2); xlabel('Velocity [m/s]');
axes(ax3); xlabel('Energy [eV]');
Here's an example of how you can do this:
msx = [1 50 60 90];
msy = [0 1 3 8];
lx = 90/4*[1 2 3 4]; % Scale the data with respect to the data that will use the "primary" X-axis
ly = [0 2 8 10];
evx = 90/19*[1 7 10 19]; % Scale the data with respect to the data that will use the "primary" X-axis
evy = [0 8 16 20];
figure
a=axes('units','normalized','position',[.1 .35 .7 .6],'xlim',[0 100],'xtick',0:10:100);
plot(lx, ly)
hold on
plot(msx, msy)
hold on
plot(evx, evy)
xlabel(a,'velocity m/s')
b=axes('units','normalized','position',[.1 .21 .7 0.000001],'xlim',[0 4],'color','none', 'xtick',0:1:10);
xlabel(b,'lambda nm');
c=axes('units','normalized','position',[.1 .10 .7 0.000001],'xlim',[0 19],'color','none', 'xtick',0:1:19);
xlabel(c,'energy eV');
For the position: specified as a four-element vector of the form [left bottom width height]. The default value of [0 0 1 1] includes the whole interior of the container. (see https://de.mathworks.com/help/matlab/ref/axes-properties.html)
Output figure:

Matlab colormap symmetric about 1

I have data that is constructed as a ratio, and therefore I'd like to use a red/white/blue colormap where white is assigned to 1 and red and blue surround it. Is there an easy way to do this?
You can easily construct a blue-white-read colormap using interp1. Here's a little anonymous function which takes an integer as input and constructs a colormap.
bwr = #(n)interp1([1 2 3], [0 0 1; 1 1 1; 1 0 0], linspace(1, 3, n), 'linear')
colormap(bwr(64));
To control where the white calls, you'll want to set the CLim of the axes. You will want to center your clims around the value that you want to be white.
set(gca, 'clim', [0 2])
And as a full example:
data = reshape(linspace(0, 100, 16), [4 4]) ./ 50;
figure
imagesc(data);
colormap(bwr(64));
colorbar;
set(gca, 'clim', [0 2])
Keep in mind though that since you have a ratio, all of the values between 0 and 1 will be compressed whereas the values > 1 can theoretically go all the way to infinity.
As an example:
data = reshape(linspace(1, 200, 16), [4 4]) ./ 50;
To correct for this you could log-transform your data prior to plotting and then change the colorbar tick marks to represent your initial ratio values.
LData = log(data);
imagesc(LData)
colormap(bwr(64));
cbar = colorbar();
set(gca, 'clim', [-1 1] * max(abs(LData(:))))
cticks = get(cbar, 'Ticks');
cticklabels = arrayfun(#(x)sprintf('%0.2f', x), exp(cticks), 'uniformoutput', false);
set(cbar, 'TickLabels', cticklabels);

Additional axis on 3D surface in MATLAB

Suppose I plot a 3d graph using
[X,Y,Z] = peaks(25);
figure
surf(X,Y,Z);
How can I add addtional x and y axis with labels to the z=0 plane like the red ones shown in this picture? I would like to keep the original axis as is.
I would just draw my own fake axis. I'm not sure there is a better solution, but this one works.
[X,Y,Z] = peaks(25);
figure
surf(X,Y,Z);
hold on;
%define the plot limits
xlim_arr = [-4 4];
ylim_arr = [-5 5];
zlim_arr = [-10 10];
%fix the limits of the real axes
xlim(xlim_arr);
ylim(ylim_arr);
zlim(zlim_arr);
%add grid and labels through all x-points
for i=xlim_arr(1):xlim_arr(2)
plot3([i i],[ylim_arr(1) ylim_arr(2)], [0 0], 'Color', [0.7 0.7 0.7], 'LineWidth',0.4);
text(i, ylim_arr(1)-0.4, 0, num2str(i));
text(i, ylim_arr(2)+0.4, 0, num2str(i));
end
%add grid and labels through all y-points
for i=ylim_arr(1):ylim_arr(2)
plot3([xlim_arr(1) xlim_arr(2)], [i i], [0 0], 'Color', [0.7 0.7 0.7], 'LineWidth',0.4);
text(xlim_arr(1)-0.4, i, 0, num2str(i));
text(xlim_arr(2)+0.4, i, 0, num2str(i));
end
%add the bold frame to highlight the fake axes
px = [xlim_arr(1) xlim_arr(1) xlim_arr(2) xlim_arr(2) xlim_arr(1)];
py = [ylim_arr(1) ylim_arr(2) ylim_arr(2) ylim_arr(1) ylim_arr(1)];
pz = [0 0 0 0 0];
plot3(px,py,pz, 'k', 'LineWidth', 0.5);