Add non-existent entry to legend - matlab

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:

Related

How to use togglebutton to turn labels in scatterplot on/off

I tried to create a scatter plot with labels for each point:
Now I would like to give the user of the code the possibility to turn the labels on and off.
So far my code looks like this:
x = rand(1,100); y = rand(1,100); pointsize = 30;
idx = repmat([1 : 10], 1, 10) % I used class memberships here
figure(1)
MDSnorm = scatter(x, y, pointsize, idx, 'filled');
dx = 0.015; dy = 0.015; % displacement so the text does not overlay the data points
T = text(x + dx, y +dy, labels);
colormap( jet ); % in my code I use a specific colormap
Button = uicontrol('Parent',figure(2),'Style','toggle','String',...
'labels','Units','normalized','Position',[0.8025 0.82 0.1 0.1],'Visible','on',...
'callback',{#pb_call, MDSnorm, ???});
At the end of my script I then tried to define the pb_call function. I tried out several different versions, they all failed.
I have a rough idea what I need to do. Something like:
function [] = pb_call( ??? )
if get(Button, 'Value')
T --> invisible % ???
else
T --> visible % ???
end
end
How can I modify the above to turn labels on or off as desired?
Here is a working example:
x = rand(1,9); y = rand(1,9); pointsize = 30;
idx = repmat(1 : 3, 1, 3); % I used class memberships here
labels = {'a', 'b', 'c', 'd', 'e', 'f', 'h', 'i', 'j'};
h_fig = figure(1); %Create a figure, an keep the handle to the figure.
MDSnorm = scatter(x, y, pointsize, idx, 'filled');
dx = 0.015; dy = 0.015; % displacement so the text does not overlay the data points
T = text(x + dx, y +dy, labels);
colormap( jet ); % in my code I use a specific colormap
%Add a button to the same figure (the figure with the labels).
Button = uicontrol('Parent',h_fig,'Style','toggle','String',...
'labels','Units','normalized','Position',[0.8025 0.82 0.1 0.1],'Visible','on',...
'callback',#pb_call);
function pb_call(src, event)
%Callback function (executed when button is pressed).
h_fig = src.Parent; %Get handle to the figure (the figure is the parent of the button).
h_axes = findobj(h_fig, 'Type', 'Axes'); %Handle to the axes (the axes is a children of the figure).
h_text = findobj(h_axes, 'Type', 'Text'); %Handle to all Text labels (the axes is the parent of the text labels).
%Decide to turn on or off, according to the visibility of the first text label.
if isequal(h_text(1).Visible, 'on')
set(h_text, 'Visible', 'off'); %Set all labels visibility to off
else
set(h_text, 'Visible', 'on'); %Set all labels visibility to on
end
end
Explanations are in the comments.

matlab plot with multiple colormaps

I want to create a plot with pcolor plot with an contour plot on top. Both with different colormaps - pcolor with "hot", the contour with "gray".
I newer Matlab version multiple colormaps are possible.
The code works, however both axis do not overlap, even if the axes positions are in sync.
%% prepare Data
Data2D = peaks(100);
Data2D = Data2D -min(Data2D(:));
Data2D = Data2D/max(Data2D(:)) * 100;
steps = 0:05:100;
xAxis = 1:size(Data2D,2);
yAxis = 1:size(Data2D,1);
figure(1); clf
ax1 = axes;
hold on;
% 3D flat plot
caxis([0 100]);
cmap = fliplr(jet(1000));
colormap(ax1, cmap(1:800,:));
hplot = pcolor(ax1, xAxis, yAxis, Data2D);
shading flat; % do not interpolate pixels
set(ax1,'XLim',[xAxis(1) xAxis(end)]);
set(ax1,'YLim',[yAxis(1) yAxis(end)]);
% colorbar
hcb = colorbar('location','EastOutside');
set(hcb, 'Ylim', [0 100]);
%% contour plot
ax2 = axes; linkaxes([ax1,ax2])
colormap(ax2, flipud(gray(1000)));
[C,hfigc] = contour(ax2, xAxis, yAxis, Data2D,steps);
% Hide the top axes
ax2.Visible = 'off';
ax2.XTick = [];
ax2.YTick = [];
set(hfigc, 'LineWidth',1.0);
hold off;
drawnow
If you didn't use ax2.Visible = 'off' you would probably see that the axes' positions are different, since the first axes are squashed to allow room for the colorbar which the second axes don't have.
TL;DR
You need to set the position properties to be equal
ax2.Position = ax1.Position
Demo
You can simulate this with a blank figure:
1.
% Create figure and first axes, which have a colorbar
figure(1)
ax1 = axes();
colorbar('location', 'eastoutside');
Output:
2.
% Add new axes
hold on;
ax2 = axes();
Output (notice the second axes fills the space of the first + colorbar):
3.
% Make the same, so that the second axes also allow for the colorbar
ax2.Position = ax1.Position;
Output (notice thicker numbers showing they are overlapping fully):

Zoom region within a plot in Matlab

I'm using Matlab to produce figures, and I'm wondering if there is a way to plot a zoomed region in a figure of the overall data?
I have scatter data plotted over one week, with the x-axis in hours, and I want to zoom into the first 3 hours, and display them within the main figure with the x-axis label of minutes.
The plotting code I have so far is as follows:
allvalsx = marabint(:,2)
allvalsy = marabint(:,5)
subvalsx = marabint(1:7,2);
subvalsy = marabint(1:7,2);
%% Plots the scatter chart.
sizemarker = 135
handle = scatter(allvalsx, allvalsy, sizemarker, '.')
figure(1)
axes('Position',[.2 .2 .2 .2])
handle2 = scatter(subvalsx, subvalsy, '.r')
title(plotTitle)
xlabel('Time since treatment (hours)')
ylabel('Contact angle (deg)')
% Axis scales x1, x2, y1, y2
axis([0, marabint(length(marabint),2) + 10, 0, 120]);
% This adds a red horizontal line indicating the untreated angle of the
% sample.
untreatedLine = line('XData', [0 marabint(length(marabint),2) + 10], 'YData', [untreatedAngle untreatedAngle], 'LineStyle', '-', ...
'LineWidth', 1, 'Color','r');
% Adding a legend to the graph
legendInfo = horzcat('Untreated angle of ', untreatedString)
hleg1 = legend(untreatedLine, legendInfo);
% This encases the plot in a box
a = gca;
% set box property to off and remove background color
set(a,'box','off','color','none')
% create new, empty axes with box but without ticks
b = axes('Position',get(a,'Position'),'box','on','xtick',[],'ytick',[]);
% set original axes as active
axes(a)
% link axes in case of zooming
linkaxes([a b])
set(gcf,'PaperUnits','inches');
set(gcf,'PaperSize', [8.267 5.25]);
set(gcf,'PaperPosition',[0 0.2625 8.267 4.75]);
set(gcf,'PaperPositionMode','Manual');
set(handle,'Marker','.');
print(gcf, '-dpdf', '-r150', horzcat('markertest4.pdf'));
This produces the following
Can anyone help me out with this?
yeah, I think I know what you need. Try this:
zoomStart = 0;
zoomStop = 3;
set(gca, 'XLim', [zoomStart zoomStop])
Let me know if that doesn't do what you need, and I'll give you a different way.

matlab bar colormap returns the same color for all bars

I have a problem with using bar and colormap.
I have a csv file like this which contains completion time for six tasks:
34,22,103,22,171,26
24,20,41,28,78,28
37,19,60,23,141,24
...
and I create a bar chart with of the means, and add the std variation errorbar.
res = csvread('sorting_results.csv');
figure();
y = mean(res)';
e = std(res);
hold on;
bar(y);
errorbar(y,e,'.r');
title('Sorting completion time');
ylabel('Completion time (seconds)');
xlabel('Task No.');
hold off;
colormap(summer(size(y,2)));
Why is the output like this? Why do the bars have the same color? And how do I put legends to the six bars?
A piece of code that does the magic. It doesn't use the canonical technique mentioned by #am304, as you will have a hard time setting up the legend with it. Here, for each one of the 6 input values, we plot a full 6 bars: one bar with the value and the remaining five set to zero.
x = rand(1,6); %create data
x_diag = diag(x); %zero matrix with diagonal filled with x
cmap = summer(6); %define colors to use (summer colomap)
figure('color','w','Render','Zbuffer'); %create figure
%bar plot for each x value
for ind_data = 1:length(x)
h_bar = bar( x_diag(ind_data, :)); %bar plot
set( get(h_bar,'children'), 'FaceVertexCData', cmap(ind_data,:) ) ; %color
hold on;
end
colormap('summer');
%legend-type info
hleg = legend( ('a':'f')' );
set(hleg, 'box', 'off');
%xticks info
set(gca, 'XTickLabel', ('a':'f')' );
%plot errors
e = ones(1,6) * 0.05;
errorbar(x, e,'.r');
set(gca, 'FontSize', 14, 'YLim', [ 0 (max(x) + max(e) + 0.1) ]);
See Coloring 2-D Bars According to Height in the MATLAB documentation. Only the first colour of the colormap is used to colour the faces, you need a bit of hack (as per code on that doc page) to do what you want.

Plot outside axis in Matlab

How to plot something outside the axis with MATLAB? I had like to plot something similar to this figure;
Thank you.
Here is one possible trick by using two axes:
%# plot data as usual
x = randn(1000,1);
[count bin] = hist(x,50);
figure, bar(bin,count,'hist')
hAx1 = gca;
%# create a second axis as copy of first (without its content),
%# reduce its size, and set limits accordingly
hAx2 = copyobj(hAx1,gcf);
set(hAx2, 'Position',get(hAx1,'Position').*[1 1 1 0.9], ...
'XLimMode','manual', 'YLimMode','manual', ...
'YLim',get(hAx1,'YLim').*[1 0.9])
delete(get(hAx2,'Children'))
%# hide first axis, and adjust Z-order
axis(hAx1,'off')
uistack(hAx1,'top')
%# add title and labels
title(hAx2,'Title')
xlabel(hAx2, 'Frequency'), ylabel(hAx2, 'Mag')
and here is the plot before and after:
You can display one axis with the scale you want, then plot your data on another axis which is invisible and large enough to hold the data you need:
f = figure;
% some fake data
x = 0:20;
y = 23-x;
a_max = 20;
b_max = 23;
a_height = .7;
%% axes you'll see
a = axes('Position', [.1 .1 .8 a_height]);
xlim([0 20]);
ylim([0 20]);
%% axes you'll use
scale = b_max/a_max;
a2 = axes('Position', [.1 .1 .8 scale*a_height]);
p = plot(x, y);
xlim([0 20]);
ylim([0 b_max]);
set(a2, 'Color', 'none', 'Visible', 'off');
I had similar problem and I've solved it thanks to this answer. In case of bar series the code is as follows:
[a,b] = hist(randn(1000,1)); % generate random data and histogram
h = bar(b,a); % plot bar series
ylim([0 70]) % set limits
set(get(h,'children'),'clipping','off')% turn off clippings