Choosing specific line to legend in different matlab runs - matlab

I have made a simulation that calculates trajectories of objects and plot it.
The figure looks like this:
figure(1)
plot(ArrayRT1,ArrayRT2);
hold on
plot(ArrayRD1,ArrayRD2);
plot(ArrayRM1,ArrayRM2);
title('Interception Trajectory')
xlabel('Downrange (Kft)')
ylabel('Altitude (Kft) ')
grid on
Where:
plot(ArrayRT1,ArrayRT2) - 1st object trajectory
plot(ArrayRD1,ArrayRD2) - 2nd object trajectory
plot(ArrayRM1,ArrayRM2) - 3rd object trajectory
Now, I run the same simulation without closing the figure with different initial conditions to check how they affect the trajectories so basically after the 2nd run I will have 6 lines on my graph.
How can I choose when I make legend to show legend only for 4 lines:
1,2,3 from first run and the 6th (the 3rd from the 2nd run)
Thank you.

Option 1
Use the syntax legend(subset,___) to set a legend only to specific objects in you axes. This requires getting the handles to all these objects. You can do that by assigning then to an array of handles, as in the following example:
x = 1:10;
% plotting all the lines:
figure(1)
hold on
p(1) = plot(x,2*x);
p(2) = plot(x,3*x);
p(3) = plot(x,4*x);
p(4) = plot(x,2*x+1);
p(5) = plot(x,3*x+1);
p(6) = plot(x,4*x+1);
hold off
% set the legend to a subset of the lines
legend(p([1:3 6]),{'Line 1', 'Line 2','Line 3','Line 6'})
Alternatively, you can 'tag' the lines to whom you want to attach a legend and use findobj to locate their handles, as done in option 2 below.
Option 2
You can set the property DisplayName for your plots to something like "no legend" (or any other string) and then use a loop to turn it off for these specific plots. Here is an example:
x = 1:10;
% plotting all the lines:
figure(1)
hold on
plot(x,2*x,'DisplayName','Line 1');
plot(x,3*x,'DisplayName','Line 2');
plot(x,4*x,'DisplayName','Line 3');
plot(x,2*x+1,'DisplayName','no legend'); % tag for no legend
plot(x,3*x+1,'DisplayName','no legend');% tag for no legend
plot(x,4*x+1,'DisplayName','Line 6');
hold off
% set the legend off for all lines with 'no legend'
set_leg_off = findobj('DisplayName','no legend');
for k = 1:numel(set_leg_off)
set_leg_off(k).Annotation.LegendInformation.IconDisplayStyle = 'off';
end
% show the legend
legend show
Note that:
You don't need to set the DisplayName for all the lines, only for those you want to remove from the legend. However, if you just write legend show it will ignore them when counting the data lines, so if you omit the DisplayName only for line 6, it will give it the label "data1".
You can use other property like tag to mark the non-legend lines (or any other property that will distinguish between the line you want to plot and those you don't), and then if you decide later to show them they won't appear with the label "no legend". Just remember to correct the findobj call to the property you use.
Keep in mind that changing object's tag or DisplayName does not effect the appearance of them in the legend, this is only a way to mark them for the findobj function, so you can loop only on them and turn the legend off. If you want to turn the legend on later, you need to use this loop again.
In both cases, the result is:

Related

Creating a legend in MATLAB that includes scatter plots and normal plots

I want my legend to include the line from the plot and the marker from the scatterplot. For example,
rest = importdata('test.xlsx');
x = test.data(:,1);
y = test.data(:,2);
xx = min(x):0.001:max(x);
yy = interp1(x,y,xx,'cubic');
figure
s1 = scatter(x,y, 'filled', 'k');
hold on
p1 = plot(xx,yy, '--k');
legend(p1, 'x1');
This code creates the legend with only the dashes from the plot and not points from the scatterplot. I would like the legend to have the both the point and the dashed line at the same label. Something like "-.-"
Any help is much appreciated.
Thanks.
Option 1
Make a dummy plot with no data (nan) for the legend (also, as you can see here you can plot all the elements with one call to plot:
p = plot(nan,nan,'--ok', xx,yy,'--k', x,y,'ok');
set(p,{'MarkerFaceColor'},{'k'}); % fill the circles
legend('x1');
The result:
Option 2
Insted of legend(p1, 'x1');, write this:
[~,ico] = legend(p1,'x1'); % create the legend, and get handels to it's parts
ico(3).Marker = 'o'; % set the marker to circle
ico(3).MarkerFaceColor = 'k'; % set it's fill color to black
ico is:
3×1 graphics array:
Text (x1)
Line (x1)
Line (x1)
The first element is the text 'x1' in the figure. The second element is the dashed line, and the third is the (not-exist) marker of p1. This third element is reserved for cases like plot(xx,yy,'--ok'); where the legend include both marker and a line, but the line (in the legend) is represented with two points and the marker with only one, so we need different objects for them. Try to see what happens if you type ico(2).Marker = 'o'; in the example above.
Legend in MATLAB is additional axes that contains the same primitive object like lines and text.
If you want to draw custom legend the simple way will be using primitive commands line, text and patch for rectangles with filling. Also you can add one more axes object as a container.
By specifying p1 in the legend command you are telling MATLAB to only insert an item in the legend for the line corresponding to handle p1 - which is what you are seeing.
In your example case you just want
>>legend({'label_for_scatter','label_for_plot'});

Matlab legend for two plots only applies to second plot

I need to plot data of two vectors, and want the data points of each to be shown in a different colour that is explaned in a legend. However, the code below displays only the legend for the second one. What am I doing wrong?
for i_plot = 1 : plot_step : N
subplot(N, 1, i_plot)
h_A = plot(bookmarksA(i_plot, :),0,'b.','MarkerSize',24);
legend('a');
xlim ([0 pieceDuration])
set(gca, 'yTick', []);
title(subj_string(i_plot,:))
hold on
h_Z = plot(bookmarksZ(i_plot, :),0,'r.','MarkerSize',24);
legend(h_Z, 'z');
end
You're only passing one label / handle combination to the legend command at a time. For a given axes, each call to legend overrides previous calls to legend, deleting previous legends rather than adding to an existing legend. You'll want to call legend once with both plot handles and labels.
legend([h_A, h_Z], {'a', 'z'})
Update
Since in your case h_A and h_Z are arrays of plot handles with identical appearances, you can just pass the first item from h_A and h_Z to legend.
legend([h_A(1), h_Z(1)], {'a', 'z'})

how to decrease the legend width in matlab

I am using the matlab to plot some project figures, see the blow figure. Now I am trying to cut the legend width so that the line won't look so wide. I tried these command as suggest by Benoit_11:
[~,icons,~,~] = legend(leg,'location','northwest');
hline = icons(2);
linedata = get(hline,'xdata');
newdata = [linedata(1)+0.2 linedata(2)];
set(hline,'xdata',newdata,'linewidth',1)
I am using the for loop to plot these figures because I have multiple figures to analysis at the same time. Now I can change the length of the legend line right now. But I got another problem: if I have different length of legend text, even if I set the same starting point and end point, I will get different length for the line in the end (you can see that from the figures). I tried to modify icon(1) but always got the error. Any suggestions?
There are 2 things you are not doing right with your code (aside the fact that you use size as the handles to the legend...that's risky because size is a built-in function):
1) Calling legend with only 1 argument returns a handle to the legend object and getting its position actually gives you the position of the box enclosing the legend, i.e. the text + the line.
2) Using this line:
p(3) = p(3) - 0.06;
does modify the position, however you would need to set the new position of the legend with something like the following for the changes to be effective:
set(HandleToLegend,'Position',p)
To come back to your question, the trick is to assign many outputs during the call to legend; you can then modify specific elements of the legend object.
Actually we only need 1 of the 4 output arguments, called icons in the docs so I'll stick with the notation. Then, we can get the XData property of the line and modify it as we want. The XData is actually a 2-element vector:
[StartingPoint EndingPoint]
so changing one or the other (or both) will change the length of the line displayed in the legend box.
Here is the whole code with comments; I changed the length and linewidth of the line in the 2nd plot to highlight the changes.
clear
clc
close all
x = 1:10;
y = rand(1,10);
figure;
%// Default case
subplot(1,2,1)
plot(x,y);
legend('First plot','Location','NorthWest');
title('Before','FontSize',18);
%// With modifications
subplot(1,2,2)
plot(x,y);
title('After','FontSize',18);
%//========================
%// Change the legend here
%//========================
%// The "icons" output is what you want
[~,icons,~,~] = legend('First plot','Location','NorthWest');
%// icons(1) is the text of the current element in the legend Here its 'First plot'
i_1 = get(icons(1)); %// access the properties with this command.
%// icons(2) is the line associated with that text. Here the blue line.
i_2 = get(icons(2));
%// Mhh I don't know what icons(3) represents haha sorry about that.
i_3 = get(icons(3));
%// Get the actual line
hline = icons(2);
%// Fetch its XData property
LineData = get(hline,'XData')
%// Play with those 2 elements to see the output change.
NewData = [LineData(1)+.2 LineData(2)-.01];
%// Apply the changes
set(hline,'XData',NewData,'LineWidth',3)
Which gives the following:
You need to set the value of the Position property, you can just change the vector p. p does not affect the plot at all, it's just a vector of numbers. You have to modify it, then apply it back to the plot, using
set(size,'Position',p)
There does seem to be a minimum width of the legend however.

Dynamic Legend (Updates in every recursion)

I got a for i=1:15. Inside I generate a variable d=1:0.01:10, which is the x'x axis and based on this, I create a continuous function F(d) which has 2 unique variables pitch and yaw. I then plot this using different colors in every recursion using cmap = hsv(15);. So then it is:
d=1:0.01:10;
cmap = hsv(15);
for i=1:15
pitch = unidrnd(10);
yaw = unidrnd(10);
for j=1:length(d)
F(j) = d(j)*3*pitch*yaw; %// some long calculation here
end
p1 = plot(d,F,'Linewidth', 1.0);
title ('blah blah')
set(p1, 'Color', cmap(i,:));
hold on;
legend (['pitch,yaw:', num2str(pitch) num2str(yaw)])
end
hold off;
This code updates the unique pitch, yaw values in every recursion (without space between them so it is kind irritating) but fails to:
Apply the proper color, visible in the figure.
Hold the color from the previous iteration and the values of pitch,yaw.
Semidocumented Solution
Adding lines to a legend in a loop can be accomplished with "dynamic legends", as described on undocumentedmatlab.com.
The idea is to replace the legend command with:
legend('-DynamicLegend');
Then update the plot command with a DisplayName parameter:
plot(d,F,'Linewidth',1.0,'DisplayName',sprintf('pitch,yaw: %d,%d',pitch,yaw));
Then plots that are added to the axes get added to the legend:
If semi-documented features are not your cup of tea, use the DisplayName trick and simply toggle the legend off/on. That is, instead of -DynamicLegend:
legend('off'); legend('show');
A different variation that does not use either DisplayName or -DynamicLegend is to delete and recreate the legend with an array of stored strings.
Official Solution
The official solution recommended by MathWorks it so grab the existing legends` line handles and manually update the legend with those handles. This is pretty painful by comparison to the dynamic legend solution above:
% Get object handles
[LEGH,OBJH,OUTH,OUTM] = legend;
% Add object with new handle and new legend string to legend
legend([OUTH;p1],OUTM{:},sprintf('pitch,yaw: %d,%d',pitch,yaw))
As an HG2 (default in R2014+) alternative to #chappjc's official MW solution, one can take advantage of legend being re-implemented as its own class rather than a kludge of other graphics objects. This has cleaned up things a bit so they are simpler to interact with.
Though these new legend objects do not have an exposed property linking legend items to plotted objects, they do have such a property, 'PlotChildren', which is an array of object handles.
For example:
x = 1:10;
y1 = x;
y2 = x + 1;
figure
plot(x, y1, 'ro', x, y2, 'bs');
lh = legend({'Circle', 'Square'}, 'Location', 'NorthWest');
pc = lh.PlotChildren
Returns:
pc =
2x1 Line array:
Line (Circle)
Line (Square)
To update our legend object without calling legend again, we can modify the 'PlotChildren' and 'String' properties of our existing legend object. As long as there is a 'String' entry for each object in 'PlotChildren', it will be rendered in the legend.
For example:
y3 = x + 2;
hold on
plot(x, y3, 'gp');
% To make sure we target the right axes, pull the legend's PlotChildren
% and get the parent axes object
parentaxes = lh.PlotChildren(1).Parent;
% Get new plot object handles from parent axes
newplothandles = flipud(parentaxes.Children); % Flip so order matches
% Generate new legend string
newlegendstr = [lh.String 'Pentagram'];
% Update legend
lh.PlotChildren = newplothandles;
lh.String = newlegendstr;
Which returns:
This functionality can be wrapped into a generic helper function to support appending one or more legend entries. We've done so with legtools on GitHub
As of MATLAB 2017a, legends update automatically when adding or removing graphics objects.
Thus, nothing specific needs to be done now. One creates the legend, then in a loop one can add lines to the axes and they'll automatically appear in the legend.

How To Put String Labels on Contours for Contour Plots in MATLAB

I am wondering if it is possible to label the contours of a MATLAB contour plot with a set of user-defined strings?
I am currently using the following code snipper to produce a labelled contour plot:
%Create Data
X = 0.01:0.01:0.10
Y = 0.01:0.01:0.10
Z = repmat(X.^2,length(X),1) + repmat(Y.^2,length(Y),1)';
%Create Plot
hold on
[C,h] = contourf(X,Y,Z);
%Add + Format Labels to Plot
hcl = clabel(C,h,'FontSize',10,'Color','k','Rotation',0);
set(hcl,'BackgroundColor',[1 1 1],'EdgeColor',[0 0 0],'LineStyle','-',)
hold off
The issue with this code is that the labels are automatically generated by MATLAB. Even as I can easily change the contours that are labels, I cannot change the labels that they get.
Ideally, I would like to label them with a set of strings that I define myself. However if that is not possible, then I am wondering if it is possible to change the numeric format of the labels. The reason for this is that the code above actually produce a contour plot for an error rate, which I would like to display as a % value (i.e. use 1% in the contour label, instead of 0.01 etc.).
In this case, hcl is actually an array which stores handles to every contour label on your plot. When you set properties using the array (as in your code),
set(hcl, 'name', 'value')
You will set the property of every label to the same value.
You can change the properties of individual labels by iterating over the array. For example, this is how you would add a percentage sign:
for i = 1:length(hcl)
oldLabelText = get(hcl(i), 'String');
percentage = str2double(oldLabelText)*100;
newLabelText = [num2str(percentage) ' %'];
set(hcl(i), 'String', newLabelText);
end