Extract MATLAB legend string from existing plot - matlab

I've been trying to get some of the data back out of a plot that's been previously created, but I've been struggling with the legend. I'm using MATLAB 2014b.
If I previously set my plot up using:
h.fig = figure();
h.ax = axes(); hold all;
h.line1 = plot(0:0.01:2*pi(), sin(0:0.01:2*pi()));
h.line2 = plot(0:0.01:2*pi(), cos(0:0.01:2*pi()));
h.xlab = xlabel('X');
h.ylab = ylabel('Y');
h.leg = legend('sin(x)', 'cos(x)');
Then without having h available I can still retrieve the x and y axis labels as strings:
xlab = get(get(gca, 'xlabel'), 'string');
ylab = get(get(gca, 'ylabel'), 'string');
However, I don't seem to be able to extract the text from a legend in a similar way. I notice that:
fig_children = get(gcf, 'children');
Shows me both the axes and legend as the children of the figure, but I don't seem to be able to access them in the same way I might with the axes:
ax = get(gca);
I'm probably mis-understanding something obvious about the way that it works, but I can't find a way to get the string out of a legend that's been previously made?

The legend text is associated to the line, rather than to a legend object, so:
ax_children = get(gca, 'children');
Outputs a line array of the lines I was plotting:
ax_children =
2x1 Line array:
Line (cos(x))
Line (sin(x))
And then:
leg_strings = get(ax_children, 'displayname');
Outputs a cell array:
leg_strings =
'cos(x)'
'sin(x)'
Which is what I was looking for.

To get the legend handle (assuming only one exists in the figure, otherwise you'll have to sort them out) you can use the following:
findobj(gcf,'type','Legend')
ans =
Legend (sin(x), cos(x)) with properties:
String: {'sin(x)' 'cos(x)'}
Location: 'northeast'
Orientation: 'vertical'
FontSize: 9
Position: [0.7226 0.8325 0.1589 0.0619]
Units: 'normalized'
Then the legend entries are available as cell array.
In short:
leg_strings = get(findobj(gcf,'type','Legend'),'String');

Related

Can we add legend for function "text" to matlab?

I want to add legend for my plot. Because I want to use the marker plot 'heartsuit', I use the 'text' function. If I add legend function in my code, it can't work. The command window say that 'Warning: Plot empty.' So, can we add legend to 'text' function? I have searched in many source, and I cannot find it.
clear all;
clc;
m = '\heartsuit';
x = 0:pi/5:2*pi;
y = sin(x);
text(x,y,m,'fontname','Arial','color','red','FontSize',18,'HorizontalAlignment','center','VerticalAlignment','middle');
grid on;
xlim([min(x) max(x)])
ylim([min(y) max(y)])
legend('Solusi Numerik');
Here's a hack. Plot a fake NaN point, create a legend for it, hide its legend line, and add the heart-suit in the string with appropriate space at an appropriate position. Adjust the color of heart-suit and/or string if needed.
hold on;
LgdStr = 'Solusi Numerik'; %Your legend string
hNaN = plot(NaN,NaN); %Plotting nothing
[~, icons] = legend(hNaN, LgdStr);%Creating a legend to get required space for string
icons(2).Visible = 'off'; %Hiding the fake legend line
icons(1).Position(1) = 0.125; %Adjusting the starting position of text
icons(1).String = ['\color{red}', m, ' \color{black}',LgdStr];
%Last line includes red-colored heart-suit at reasonable space from black-colored text
Result:

How to add an independent text in MATLAB plot legend

I need an additional text in the legend that is not related with graphical data together with the legend captions.
Something like this (it was made in OriginLab):
Following to this link Add custom legend without any relation to the graph
I can add some text using plot(NaN,NaN,'display','add info here2', 'linestyle', 'none'). But there is an indent in this text:
How to avoid this indent? And is there a more elegant method to add the text that is not associated with the legend together with the legend captions?
The legend function will return as its second output argument handles for all of the components that make up the symbols and text in the legend. You can therefore plot "dummy" lines as placeholders in the legend, reorder the handles when creating the legend to put the text where you want it, and modify the legend objects accordingly. Here's an example:
x = linspace(0, 2*pi, 100);
hl = plot(x, [sin(x); cos(x); tan(x); nan(size(x))].'); % Add a line of NaNs
axis([0 2*pi -4 4]);
[~, objH] = legend(hl([1 2 4 3]), 'sin', 'cos', 'junk', 'tan'); % Reorder handles
set(findobj(objH, 'Tag', 'junk'), 'Vis', 'off'); % Make "junk" lines invisible
pos = get(objH(3), 'Pos'); % Get text box position
set(objH(3), 'Pos', [0.1 pos(2:3)], 'String', 'also...'); % Stretch box and change text
You can use annotations. It's not perfect, but with few adjustments you'll get what you want. Here's an example:
% somthing to plot:
x = [0:0.1:5; 5:0.1:10].';
y = sin(x);
% plot the real data:
plot(x,y);
hold on
% make some space in the legend:
Spacing_lines = 3;
h = plot(nan(size(x,1),Spacing_lines));
hold off
set(h,{'Color'},{'w'}); % clear the dummy lines
% place the legend:
hl = legend([{'lable1','lable2'} repmat({''},1,Spacing_lines)]);
% add your text:
annotation('textbox',hl.Position,'String',{'Some info';'in 2 lines'},...
'VerticalAlignment','Bottom','Edgecolor','none');
And from this you get:
You can just add any text to any point of plot in this way:
txt1 = 'some information';
text(x1,y1,txt1)
where x1, y1 - coordinates.
By the way function text function has a lot of different properties (colors, font size, alignment etc.).
I think the easiest way is to just create some dummy function, plot it but set the color="none" - that way it will only show up in the legend (if that is where you wanted it).

Legend on scatter3 in Matlab

I was expecting that to work, but I am missing what is a "vector of handles", from MATLAB helpfile.
LEGEND(M), where M is a string matrix or cell array of strings, and
LEGEND(H,M) where H is a vector of handles to lines and patches also
works.
myone = ones(20,1);
mytwo = ones(20,1)+1;
rows = vertcat(myone,mytwo);
mylabels = {'Alpha', 'Beta'};
figure
grouplabels = mylabels(rows);
h = scatter3(rand(40,1),rand(40,1),rand(40,1),20,rows,'filled'), ...
view(-33,22)
legend(handle(h),grouplabels)
xlabel('X')
ylabel('Y')
zlabel('Z')
The problem with your code is that h, the output of scatter3, is a single handle. It's not an array of handles with the same size as your data (which is what you imply when trying to set 40x1 array of labels on it, ignoring irrelevant handle wrapper). And it's not even an array of two handles as one may have thought (one per color). So you cannot set legend like this. One way around would be to plot all the points of one color at a time:
hFig = figure();
axh = axes('Parent', hFig);
hold(axh, 'all');
h1 = scatter3(rand(20,1),rand(20,1),rand(20,1),20,'b','filled');
h2 = scatter3(rand(20,1),rand(20,1),rand(20,1),20,'r','filled');
view(axh, -33, 22);
grid(axh, 'on');
legend(axh, [h1,h2], {'Alpha', 'Beta'});

Matlab - how to make a custom legend

I have the following picture :
And I would like to make a legend for it. Basically, I want to make a legend for each type of rectangle. In the legend box, I want to mark each color line according to the type of body which it marks:
green line : head
yellow line : torso
purple line : right arm
cyan line : left arm
red line : left leg
blue line : right leg
This is basically custom, because I have more rectangles of each type. How can I do a custom legend and attach it to the figure which draws this picture?
There are 2 ways you could go about this. You could create your squares and then assign them to an hggroup. This way you dont have multiple items for each color. Something like this:
hold on
for ii = 1:4
hb(ii) = plot(rand(1,2), rand(1,2),'color','r');
end
hg = hggroup;
set(hb,'Parent',hg)
set(hg,'Displayname','Legs')
legend(hg)
Or you could create dummy objects, like this:
hold on
for ii = 1:4
hb(ii) = plot(rand(1,2), rand(1,2),'color','r');
end
p = plot([],[],'r');
legend(p,'Legs')
The former is a little more elegant.
I would like to add to dvreed77's answer on using hggroup that for clean legend use, I also needed to set the 'IconDisplayStyle' (Matlab R2014a), such that:
%4 kinds of lines:
n_areas = 4;
n_lines = 10;
%use built-in color map
cmap = hsv(n_areas);
%plot lines and generate handle vectors
h_fig = figure;
hold on
h_lines = zeros(1,n_lines);
for l = 1:n_areas
for k = 1:n_lines
h_lines(k) = plot(rand(1,2), rand(1,2),'Color',cmap(l,:));
end
%Create hggroup and set 'icondistplaystyle' to on for legend
curPlotSet = hggroup;
set(h_lines,'Parent',curPlotSet);
set(get(get(curPlotSet,'Annotation'),'LegendInformation'),...
'IconDisplayStyle','on');
end
%Now manually define legend label
legend('heads','legs','hands','feet')
The simplest way I can think of is to first plot one rectangle of each type and construct a legend for only unique rectangles. Like so:
figure;
hold on;
% unique rectangles
plot(rand(1, 10), 'b');
plot(rand(1, 10), 'g');
% the rest
plot(rand(1, 10), 'b');
plot(rand(1, 10), 'g');
% use normal legend with only as many entries as there are unique rectangles
legend('Blue', 'Green');
You will have many lines of the same color, but a legend only for unique colors.
Just draw legend dots outside the plot:
figure;
plot(-1,-1,'gs',-1,-1,'b^',-1,-1,'ro');
legend('x1','x2','x3','Location','NorthWest');
xlim([0,1]); ylim([0,1]);
To control the appearance of legend entries, plot points that have values which are NaN then pass the objects returned by plot and an array of labels to the legend function (NaN points are not visible in the plot, but appear in the legend).
colors = ["red", "blue"];
labels = ["this is red", "this is blue"];
% We 'plot' a invisible dummy point (NaN values are not visible in plots),
% which provides the line and marker appearance for the corresponding legend entry.
p1 = plot(nan, nan, colors(1));
hold on
p2 = plot(nan, nan, colors(2));
% Plot the actual plots. You can change the order of the next two function calls
% without affecting the legend.
plot([0, 1], [0, 1], colors(1));
plot([0, 1], [1, 0], colors(2));
legend([p1, p2], labels)
If the plots in [p1, p2] are not in the current figure when legend([p1, p2], labels) is called, then it will raise the following error:
Invalid argument. Type 'help legend' for more information.
You can filter plots that are not in the current figure using something like this:
plots_in_figure = findall(gcf,'Type','Line');
plots_for_legend_indices = ismember([p1, p2], plots_in_figure);
plots_for_this_legend = this.plots_for_legend(plots_for_legend_indices);
legend(plots_for_this_legend, labels)

Legend for multiple lines in Matlab plot

I have 13 lines on a plot, each line corresponding to a set of data from a text file. I'd like to label each line starting with the first set of data as 1.2, then subsequently 1.25, 1.30, to 1.80, etc., with each increment be 0.05. If I were to type it out manually, it would be
legend('1.20','1.25','1.30', ...., '1.80')
However, in the future, I might have more than 20 lines on the graph. So typing out each one is unrealistic. I tried creating a loop in the legend and it doesn't work.
How can I do this in a practical way?
N_FILES=13 ;
N_FRAMES=2999 ;
a=1.20 ;b=0.05 ;
phi_matrix = zeros(N_FILES,N_FRAMES) ;
for i=1:N_FILES
eta=a + (i-1)*b ;
fname=sprintf('phi_per_timestep_eta=%3.2f.txt', eta) ;
phi_matrix(i,:)=load(fname);
end
figure(1);
x=linspace(1,N_FRAMES,N_FRAMES) ;
plot(x,phi_matrix) ;
Need help here:
legend(a+0*b,a+1*b,a+2*b, ...., a+N_FILES*b)
As an alternative to constructing the legend, you can also set the DisplayName property of a line so that the legend is automatically correct.
Thus, you could do the following:
N_FILES = 13;
N_FRAMES = 2999;
a = 1.20; b = 0.05;
% # create colormap (look for distinguishable_colors on the File Exchange)
% # as an alternative to jet
cmap = jet(N_FILES);
x = linspace(1,N_FRAMES,N_FRAMES);
figure(1)
hold on % # make sure new plots aren't overwriting old ones
for i = 1:N_FILES
eta = a + (i-1)*b ;
fname = sprintf('phi_per_timestep_eta=%3.2f.txt', eta);
y = load(fname);
%# plot the line, choosing the right color and setting the displayName
plot(x,y,'Color',cmap(i,:),'DisplayName',sprintf('%3.2f',eta));
end
% # turn on the legend. It automatically has the right names for the curves
legend
Use 'DisplayName' as a plot() property, and call your legend as
legend('-DynamicLegend');
My code looks like this:
x = 0:h:xmax; % get an array of x-values
y = someFunction; % function
plot(x,y, 'DisplayName', 'Function plot 1'); % plot with 'DisplayName' property
legend('-DynamicLegend',2); % '-DynamicLegend' legend
source: http://undocumentedmatlab.com/blog/legend-semi-documented-feature/
legend can also take a cell list of strings as an argument. Try this:
legend_fcn = #(n)sprintf('%0.2f',a+b*n);
legend(cellfun(legend_fcn, num2cell(0:N_FILES) , 'UniformOutput', false));
The simplest approach would probably be to create a column vector of the numbers to use as your labels, convert them to a formatted character array with N_FILES rows using the function NUM2STR, then pass this as a single argument to LEGEND:
legend(num2str(a+b.*(0:N_FILES-1).','%.2f'));
I found this I found through Google:
legend(string_matrix) adds a legend containing the rows of the matrix string_matrix as labels. This is the same as legend(string_matrix(1,:),string_matrix(2,:),...).
So basically, it looks like you can construct a matrix somehow to do this.
An example:
strmatrix = ['a';'b';'c';'d'];
x = linspace(0,10,11);
ya = x;
yb = x+1;
yc = x+2;
yd = x+3;
figure()
plot(x,ya,x,yb,x,yc,x,yd)
legend(strmatrix)