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

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'});

Related

Choosing specific line to legend in different matlab runs

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:

How to draw differently spaced grid lines in Matlab

On mathworks, I have found a code which is suppossed to draw grid lines in a plot:
g_x = -25:1.25:0;
g_y = -35:2.5:-5;
for i = 1:length(g_x)
plot([g_x(i) g_x(i)],[g_y(1) g_y(end)],'k:')% y grid lines
hold on
end
for i=1:length(g_y)
plot([g_x(1) g_x(end)],[g_y(i) g_y(i)],'k:') % x grid lines
hold on
end
here's a link
I don't understand the plot command: e.g. the y grid lines - one of the inputs is a vector containing all the spacing points of the x-axis, where I want to have a grid. These points are given in two columns and they are assigned to the second vector, which only contains the first and the last point shown on the y-axis. As I understand this command, it will for example take the first element g_x(1) and g_y(1) and plot a : , it will then take g_x(2) and g_y(1) and plot :, and so on. But How does it keep on plotting : from g_y(1) continuously until g-y(end) ?
To directly answer your question, it simply plots the two endpoints of each grid line and since the default LineStyle used by plot is a solid line, they will automatically be connected. What that code is doing is creating all permutations of endpoints and plotting those to form the grid.
Rather than creating custom plot objects (if you're using R2015b or later), you can simply use the minor grid lines and modify the locations of the minor tick marks of the axes.
g_x = -25:1.25:0;
g_y = -35:2.5:-5;
ax = axes('xlim', [-25 0], 'ylim', [-35 -5]);
% Turn on the minor grid lines
grid(ax, 'minor')
% Modify the location of the x and y minor tick marks
ax.XAxis.MinorTickValues = g_x;
ax.YAxis.MinorTickValues = g_y;
Basically the code does this:
g_x = -25:1.25:0;
generates a array with values -25.0000 -23.7500 -22.5000 -21.2500 ... 0
These are the positions where vertical lines are drawn
The same holds for g_y, but of course this determines where horizontal lines are drawn.
The option 'k' determined that it is a dashed line.
And the loops just loo through the arrays.
So in the first iteration the plot function draws a line from the position
[-25, -35]
to the position
[-25, -5]
So if you want to change the grid, just change the values stored in g_x
g_x = -25:3.0:0;
would for example draw vertical lines with the width 3.0
I hope this makes sense for you.

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.

Is there a way to put grid lines on top of a contour plot?

I am using the contourf function to create a contour plot:
I would like to get grid lines to appear on top of the plane that shows the contours.
I came across one solution, but it only works in 2D (that is when you view the contour plot in 2D) which involved the following two commands:
grid on
set(gca,'layer','top');
However, the grid lines do not appear when viewing the axes in 3D. Is there any way to do this simply?
You can accomplish that using line object manipulation that re-writes the grid lines, or a small FEX tool called gridxy .
For example, lets recreate a figure that has the same properties:
figure
set(gcf,'Renderer','OpenGL')
%# plot surface and contour
Z = peaks;
surf(Z), hold on
[~,h] = contourf(Z); %# get handle to contourgroup object
%# change the ZData property of the inner patches
hh = get(h,'Children'); %# get handles to patch objects
for i=1:numel(hh)
zdata = ones(size( get(hh(i),'XData') ));
set(hh(i), 'ZData',-10*zdata)
end
And add the extra grid lines:
v = get(gca);
hg=gridxy(get(gca,'XTick'),get(gca,'YTick'), 'Color',[1,1,1]*0.25,'Linestyle',':');
set(hg,'Zdata',repmat(v.ZLim(1)+eps,[1 numel(get(hg,'Ydata'))]));
However, is there a reason not to use surfc ? For example:
Z = peaks(20);
surfc(Z);
view(-45, 20);

Legend entry for color and marker

I have a plot which defines line properties based on test parameters. For example, in the plot below, blue lines have a value of A=1, and red is A=2. The solid lines with dots have B=10 and dashed with Xs B=20. When I create a legend, it makes an entry for each line plotted. I would like to have a legend something like this:
[blue] A=1
[red] A=2
-. B=10
--x B=20
I have many more entries than what you see below, so this would save a lot of space. Does anyone know if this is possible in Matlab?
UPDATE
Here's what I've tried towards Eitan's answer, to no luck.
figure(2);
plot(1:5,1:5,'b');
hold all;
plot(1:5,1:5,'r');
plot(1:5,1:5,'k.-');
plot(1:5,1:5,'kx--');
h = get(gca,'Children');
M = {'A=1','A=2','B=10','B=20'};
figure(1);
legend(h,M); % This makes the legend appear in Figure 2, but I want it in 1.
A possible way to do it would be first storing in an array h four handles corresponding to four sample lines in the following way:
h(1) is the handle of a blue solid line.
h(2) is the handle of a red solid line.
h(3) is the handle of a dot-dash line.
h(4) is the handle of a dot-cross line.
and then feeding them into legend alongside the desired strings like so:
legend(h, 'A = 1', 'A = 2', 'B = 10', 'B = 20')
EDIT: If you cannot obtain these four handles, it is also possible to plot separately "empty" lines (having NaN values for their coordinates) that have the same graphical properties (blue, red, dot-dash and cross-dash), and then get their handles. This way they exist as lineseries, but aren't actually plotted.