I want to represent the values of a matrix as an image, adding some text in its margins. To do so, I proceed as follows:
matrix = rand(10); %Suppose this matrix
figure('color','w')
imshow(matrix,[min(matrix(:)), max(matrix(:))])
colormap(gca,jet(256))
colorbar
truesize([400,400])
for i=1:size(matrix,1)
text(-2,i,['long text ' num2str(i)], 'Interpreter', 'none')
h = text(i,0,['column ' num2str(i)], 'Interpreter', 'none');
set(h,'Rotation',90);
end
The original figure is:
I can see the text on the left increasing the figure width (with the mouse for instance):
However, if I increase the figure height as well, the image increases, and I cannot see the full text on the left and on the top at the same time.
I have 2 questions:
Is there a neater way to represent a matrix including information outside like in this example?
How could I see the full text properly?
For the first part of your question, I would do something like this, so that you don't have to keep track of the position of the labels:
matrix = rand(10);
figure('color','w')
imagesc(matrix) % plot your matrix
axis equal % correct aspect-ratio
xlim([0.5, 10.5])
colormap(gca, jet(256))
colorbar
% Create your labels
x = cell(1, size(matrix, 1));
y = x;
for i = 1:size(matrix, 1)
x{i} = sprintf('Column %u', i);
y{i} = sprintf('Long text %u', i);
end
% Edit your x axis
set(gca, ...
'XTick', 1:size(matrix, 1), ... % select the ticks to be displayed
'XTickLabel', x, ... % select their labels
'XTickLabelRotation', 90, ... % rotate the labels vertically
'XAxisLocation', 'top'); % put the x axis on top
% Similar for the y axis
set(gca, ...
'YTick', 1:size(matrix, 1), ... % select the ticks to be displayed
'YTickLabel', y); % select their labels
For your second question, there is probably a way to automatically detect the optimal size of your axes, but you can simply do it by trial and error:
set(gca, 'OuterPosition', [0, 0.05, 1, 0.9]) % for example?
In particular, you might want to change the first and third element of the vector to modify the horizontal position and width (in fraction of the figure size), and the second and fourth element for the vertical position and height.
Related
I'd like to have the legend (of some contours) over the colorbar of a surf plot.
How can I have a layout similar to the image in a figure plot?
From the black
colorbar;
legend('label1','label2','Location','northeastoutside');
to the red one?
You can manually change the position of both the colorbar and the legend
% Make a demo plot
figure(); hold on
plot( rand(20,3) ); % lines for the legend
peaks(10); % surface for the colorbar
view(3); % 3D view
% Create a legend and colorbar, retain their handles
L = legend( 'show', 'location', 'eastoutside' );
C = colorbar();
% Get some key variables from the current position of the colorbar/legend
% -> avg mid point of colorbar and legend
x = ( L.Position(1) + (C.Position(1)+C.Position(3)) ) / 2;
% -> Max width of the two objects
w = max( L.Position(3), C.Position(3) );
% -> A nominal y value and padding to dictate the spacing
y = 0.1;
pad = 0.05;
% Move the legend and colorbar
% First move the x/y coords of the legend to be on top, centred around common x
L.Position(1:2) = [x - L.Position(3)/2, 1 - y - L.Position(4)];
% Then move the x/y coords of the colorbar to be on the bottom, centred around common x
C.Position(1:2) = [x - C.Position(3)/2, y];
% Then resize the colorbar to use the vertical space not utilised by the legend
C.Position(4) = L.Position(2) - pad - y;
% By moving the legend/colorbar the axes will have "popped" to use the full width
% Need to move it to span between the current left edge and the newly moved leg/colorbar
ax = gca();
ax.Units = 'Norm';
ax.Position(3) = (x-w/2) - pad - ax.Position(1) ;
Result:
You can do this interactively by clicking the "Cursor" icon in the top of the plot window and adjusting the legend/colorbar. Once you have finished editing choose "Generate Code" in the "File" menu of the plot window to have code generated so you can repeatedly create the plot.
I would like to plot a bar chart exactly like the on in the picture below.
What I am not able to do is to plot 2 sets of data, one on the left-hand side of the "0" and the one on the right-hand side respectively, using each one a different scale on the x-axis. Using the function barh there are instructions about how to move the baseline, but in this case there are 2 sets of different data with different scales.
As example, I am trying to plot the following arrays:
left = [.1; .5; .4; .6; .3]; % Scale 0-1, grows leftwards
right = [24; 17; 41; 25; 34]; % Scale 0-35, grows rightwards
Any hints please?
To handle the different scaling, you could manually multiply the values in left to be scaled, then modify the tick marks on that side.
% Automatically determine the scaling factor using the data itself
scale = max(right) / max(left);
% Create the left bar by scaling the magnitude
barh(1:numel(left), -left * scale, 'r');
hold on
barh(1:numel(right), right, 'b')
% Now alter the ticks.
xticks = get(gca, 'xtick')
% Get the current labels
labels = get(gca, 'xtickLabel');
if ischar(labels);
labels = cellstr(labels);
end
% Figure out which ones we need to change
toscale = xticks < 0;
% Replace the text for the ones < 0
labels(toscale) = arrayfun(#(x)sprintf('%0.2f', x), ...
abs(xticks(toscale) / scale), 'uniformoutput', false);
% Update the tick locations and the labels
set(gca, 'xtick', xticks, 'xticklabel', labels)
% Now add a different label for each side of the x axis
xmax = max(get(gca, 'xlim'));
label(1) = text(xmax / 2, 0, 'Right Label');
label(2) = text(-xmax/ 2, 0, 'Left Label');
set(label, 'HorizontalAlignment', 'center', 'FontWeight', 'bold', 'FontSize', 15)
Here's an example:
left = [.1; .5; .4; .6; .3]; % Scale 0-1, grows leftwards
right = [24; 17; 41; 25; 34]; % Scale 0-35, grows rightwards
ax_front = axes;
b_front = barh(right,0.35);
set(b_front,'facecolor',[0.2,0.4,1])
axis([-50,50,0,6])
axis off
ax_back = axes;
b_back = barh(-left,0.35)
axis([-1,1,0,6])
set(b_back,'facecolor',[1,0.4,0.2])
set(gca, 'xtick', [-1:0.2:1])
set(gca, 'xticklabel', [[1:-0.2:0],[10:10:50]])
grid on
axes(ax_front) % bring back to front
Result:
I want to add an entry manually to a MATLAB legend. This legend can be pre-existent and contain other graphed elements' entries, but not necessarily.
I make a scatter plot, but instead of using e.g. scatter(x,y), I plot it using
for n = 1:numel(x)
text(x(n),y(n),num2str(n), ...
'HorizontalAlignment','center','color',[1 0 0])
end
This results in a scatter plot of numbers one through the number of elements in x (and y, because they are of the same size). I want to add a legend entry for these numbers.
I tried to add or edit the legend with
[h,icons,plots,s] = legend(___)
as described on the legend documentation page. I can't figure out how I can add a legend entry, without having to plot something (such as an actual scatter plot or regular plot). I want the usual line or marker symbol in the legend to be a number or character such as 'n', indicating the numbers in the graph. Is this possible and how would one achieve this?
EDIT by Erik
My answer goes below zelanix's answer, because mine is based on it.
Original answer
A fairly workable solution may be as follows:
x = rand(10, 1);
y = rand(10, 1);
figure;
text(x,y,num2str(transpose(1:numel(x))),'HorizontalAlignment','center')
% Create dummy legend entries, with white symbols.
hold on;
plot(0, 0, 'o', 'color', [1 1 1], 'visible', 'off');
plot(0, 0, 'o', 'color', [1 1 1], 'visible', 'off');
hold off;
% Create legend with placeholder entries.
[h_leg, icons] = legend('foo', 'bar');
% Create new (invisible) axes on top of the legend so that we can draw
% text on top.
ax2 = axes('position', get(h_leg, 'position'));
set(ax2, 'Color', 'none', 'Box', 'off')
set(ax2, 'xtick', [], 'ytick', []);
% Draw the numbers on the legend, positioned as per the original markers.
text(get(icons(4), 'XData'), get(icons(4), 'YData'), '1', 'HorizontalAlignment', 'center')
text(get(icons(6), 'XData'), get(icons(6), 'YData'), '2', 'HorizontalAlignment', 'center')
axes(ax1);
Output:
The trick to this is that the new axes are created in exactly the same place as the legend, and the coordinates of the elements of the icons are in normalised coordinates which can now be used inside the new axes directly. Of course you are now free to use whatever font size / colour / whatever you need.
The disadvantage is that this should only be called after your legend has been populated and positioned. Moving the legend, or adding entries will not update the custom markers.
Erik's answer
Based on zelanix's answer above. It is a work-in-progress answer, I am trying to make a quite flexible function of this. Currently, it's just a script that you'd need to adapt to your situation.
% plot some lines and some text numbers
f = figure;
plot([0 1],[0 1],[0 1],[1 0])
x = rand(25,1);
y = rand(25,1);
for n = 1:numel(x)
text(x(n),y(n),num2str(n), ...
'HorizontalAlignment','center','color',[1 0 0])
end
hold on
% scatter(x,y) % used to test the number positions
scatter(x,y,'Visible','off') % moves the legend location to best position
% create the dummy legend using some dummy plots
plot(0,0,'o','Visible','off')
[l,i] = legend('some line','some other line','some numbers','location','best');
l.Visible = 'off';
% create empty axes to mimick legend
oa = gca; % the original current axes handle
a = axes;
axis manual
a.Box = 'on';
a.XTick = [];
a.YTick = [];
% copy the legend's properties and contents to the new axes
a.Units = l.Units; % just in case
a.Position = l.Position;
i = copyobj(i,a);
% replace the marker with a red 'n'
s = findobj(i,'string','some numbers');
% m = findobj(i(i~=s),'-property','YData','marker','o');
m = findobj(i(i~=s),'-property','YData');
sy = s.Position(2);
if numel(m)>1
dy = abs(m(1).YData - sy);
for k = 2:numel(m)
h = m(k);
dy2 = abs(h.YData - sy);
if dy2<dy
kbest = k;
dy = dy2;
end
end
m = m(kbest);
end
m.Visible = 'off';
mx = m.XData;
text(mx,sy,'n','HorizontalAlignment','center','color',[1 0 0])
% reset current axes to main axes
f.CurrentAxes = oa;
The result:
I would like to make individual label for each and every tick in matlab plot. I could do this by
xtick = [1, 10, 20];
xticklabels = {'January', 'February', 'December'};
set(gca, 'XTick', xtick);
set(gca, 'XTickLabel', xticklabels);
As the strings are very long, I would like to make them in a slanting way. So I would be very happy, if anyone could help me in displaying the label in a slanting way.
Thanks
I once had a somewhat similar problem and I found an example on Matlab answers by The Mathworks. Basically you create text objects with your labels and rotate them. Otherwise there is a submission on the File Exchange here that looks pretty nice. Hope that helps!
clear
clc
% Generate some test data. Assume that the X-axis represents months.
x = 1:12;
y = 10*rand(1,length(x));
% Plot the data.
h = plot(x,y,'+');
% Reduce the size of the axis so that all the labels fit in the figure.
pos = get(gca,'Position');
set(gca,'Position',[pos(1), .2, pos(3) .65])
% Add a title.
title('This is a title')
% Set the X-Tick locations so that every other month is labeled.
Xt = 1:2:11;
Xl = [1 12];
set(gca,'XTick',Xt,'XLim',Xl);
% Add the months as tick labels.
months = ['Jan';
'Feb';
'Mar';
'Apr';
'May';
'Jun';
'Jul';
'Aug';
'Sep';
'Oct';
'Nov';
'Dec'];
ax = axis; % Current axis limits
axis(axis); % Set the axis limit modes (e.g. XLimMode) to manual
Yl = ax(3:4); % Y-axis limits
% Place the text labels
t = text(Xt,Yl(1)*ones(1,length(Xt)),months(1:2:12,:));
set(t,'HorizontalAlignment','right','VerticalAlignment','top', ...
'Rotation',45);
% Remove the default labels
set(gca,'XTickLabel','')
% Get the Extent of each text object. This
% loop is unavoidable.
for i = 1:length(t)
ext(i,:) = get(t(i),'Extent');
end
% Determine the lowest point. The X-label will be
% placed so that the top is aligned with this point.
LowYPoint = min(ext(:,2));
% Place the axis label at this point
XMidPoint = Xl(1)+abs(diff(Xl))/2;
tl = text(XMidPoint,LowYPoint,'X-Axis Label', ...
'VerticalAlignment','top', ...
'HorizontalAlignment','center');
I have to plot some data and I need two x and y axes.
The main x and y give me displacement infos, the secondary (x on top and y on the right) give me infos on energy.
The issue I have is that if I make the plot window bigger the secondary axes don't resize properly and, but it is very minor, the plot title is written under the tool bar and I can see only the lower part of the letters.
Someone knows how to fix the main issue on secondary axes?
The code I used for secondary axis is:
figure(1)
%%%%voglio fare un plot tenendo fisse le dimensioni delle icone nella legenda
hplot = plot(yH(1,:),xH(1,:),'^', yC(:,1),xC(:,1),'*',yC(:,2),xC(:,2),'*',...
yC(:,3),xC(:,3),'*',yC(:,4),xC(:,4),'*',yC(:,5),xC(:,5),'*',...
yC(:,6),xC(:,6),'*','MarkerSize',s); % Markersize: specifys the size of the marker in points (s in questo caso)
hold on
plot(Ymcporigine,Xmcporigine,'k-','MarkerEdgeColor','k','MarkerSize',1); %Plot contorno MCP
hold on
plot(Yh, Xh, 'b-', 'MarkerSize', s); %Plot alone circolare
hold off
%Labe assi principali - It is necessary to give the label instructions after plot in order to avoid overlap
xlabel(gca, 'Deflessione magnetica [m]'); % label lower x axis
ylabel(gca,'Deflessione elettrica [m]'); %label left y axis
%particles outside MCP radius won't be appear in figure
xlim([0, Rmcp])
ylim([0, Rmcp])
%%%% legenda assi principali
l=legend(hplot, 'H^+','C^+','C^{+2}','C^{+3}','C^{+4}','C^{+5}','C^{+6}', 'Location','BestOutside');
a=get(l,'children');
set(a(1:3:end),'MarkerSize',10);
%%%% doppio Asse x
%xlabel(gca, 'Deflessione magnetica [m]'); % label asse x principale
%set secondary x limit as the momentum of a H+ at distance equal to the MCP radius
% Secondo Harres y=(q*B*LB*L)/sqrt(2mEkin) ==> mv=q*B*LB*L/y
mv_max = (q*B*LB*L)/Rmcp;
%mv_max = 1;
%Layout instruction
set(gca,'Box','off'); % Turn off the box surrounding the whole axes
axesUnits=get(gca,'Units');
axesPosition = get(gca,'Position'); %# Get the current axes position
hNewAxes = axes('Position',axesPosition,... %# Place a new axes on top...
'Units', axesUnits,...
'ActivePositionProperty', 'OuterPosition',...
'Color','none',... %# ... with no background color
'XAxisLocation','top',... %# ... located on the top
'Ytick', [],... %# ... with no y tick marks
'Xlim', [0, mv_max],... %# ... should define x axis scale (need to set xmax = mv_max)
'Box','off'); %# ... and no surrounding box
xlabel(hNewAxes,'Momentum (H^+)'); %# Add a label to the top axis
set(gca, 'XTickLabel', num2str(get(gca,'XTick')','%g'))
%%%%%Plot title - It is necessary to give the title instruction after secondary x axis in order to avoid overlap
title(['Calcolo approssimato interazione ioni campo magnetico B=', num2str(B), 'Tesla']);
%%%% doppio Asse y
%ylabel(gca,'Deflessione elettrica [m]'); %label asse y principale
%set secondary y limit as the energy of a H+ at distance equal to the MCP radius
% Secondo Harres x=(q*E*Le*L)/(2mEkin) ==> Ekin=q*E*Le*L/2mx
Le = 0.07; %Estensione del C.E. : 70 mm
E = 100000; %campo TP.m
Ekin_max = (q*E*Le*L)/(2*m_H*Rmcp);
%mv_max = 1;
set(gca,'Box','off'); % Turn off the box surrounding the whole axes
axesUnits = get(gca,'Units');
axesPosition = get(gca,'Position'); %# Get the current axes position
hNewAxes = axes('Position',axesPosition,... %# Place a new axes on top...
'Units', 'normalized',...
'ActivePositionProperty', 'OuterPosition',...
'Color','none',... %# ... with no background color
'YAxisLocation','right',... %# ... located on the right
'Ylim', [0, Ekin_max],... %# ... should define y axis scale (need to set ymax=Ekin_max)
'Xtick', [],... %# ... with no y tick marks
'Box','off'); %# ... and no surrounding box
ylabel(hNewAxes,'Energy (H^+)'); %# Add a label to the top axis
set(gca, 'YTickLabel', num2str(get(gca,'YTick')','%g'))
I remembered seeing this walkthrough on how to set up multiple axes in the Matlab documentation. I tried their sample code and everything resizes fine.
Where your code differs from the Matlab documentation, is that you need to define your x axis and y axis at the same time, not in two different new-axis statements. So take out your two hNewAxes statements and replace it with one that includes all the properties:
hNewAxes = axes('Position',axesPosition,... %# Place a new axes on top...
'Units', 'normalized',...
'ActivePositionProperty', 'OuterPosition',...
'Color','none',... %# ... with no background color
'YAxisLocation','right',... %# ... located on the right
'XAxisLocation','top',...
'Xlim', [0, mv_max],...
'Ylim', [0, Ekin_max],... %# ... should define y axis scale (need to set ymax=Ekin_max)
'Box','off'); %# ... and no surrounding box
If you want to plot some of your data lines with respect to one set of axes, and some with respect to the second, then for the second set you'll have to plot them in the style laid out at the end of the walkthrough:
hl2 = line(x2,y2,'Color','k','Parent',ax2);
where the 'Parent' property tells Matlab which axes to use.
From the Matlab docs it looks like you should set the ActivePositionProperty as OuterPosition instead of Position. I can't reproduce the scaling issue, but setting that does seem to adjust the title position.