How do I modify the legend in a Matlab plot? - matlab

I would like to draw four circles of two colors. I'm using circle function to draw a circle. I'm facing problem with legend(). It colors the two data with the same color.
function main
clear all
clc
circle([ 10, 0], 3, 'b')
circle([-10, 0], 3, 'b')
circle([ 10, 10], 3, 'r')
circle([-10, 10], 3, 'r')
% Nested function to draw a circle
function circle(center,radius, color)
axis([-20, 20, -20 20])
hold on;
angle = 0:0.1:2*pi;
grid on
x = center(1) + radius*cos(angle);
y = center(2) + radius*sin(angle);
plot(x,y, color, 'LineWidth', 2);
xlabel('x-axis');
ylabel('y-axis');
title('Est vs Tr')
legend('true','estimated');
end
end
The following picture shows the problem. Both colored as blue instead one of them is red.
Any suggestions?

You can make your function circle() return the plot handles. Store the handles in a vector. In the end, you only call legend() once, after plotting all circles. The first argument in legend are then the function handles which you want to appear in the legend. Something like this:
function main
% clear all % functions have their own workspace, this should always be empty anyway
clc
handles = NaN(1,2);
handles(1,1) = circle([ 10, 0], 3, 'b'); % handle of a blue circle
circle([-10, 0], 3, 'b')
handles(1,2) = circle([ 10, 10], 3, 'r'); % handle of a red circle
circle([-10, 10], 3, 'r')
% Nested function to draw a circle
function h = circle(center,radius, color) % now returns plot handle
axis([-20, 20, -20 20])
hold on;
angle = 0:0.1:2*pi;
grid on
x = center(1) + radius*cos(angle);
y = center(2) + radius*sin(angle);
h = plot(x,y, color, 'LineWidth', 2);
xlabel('x-axis');
ylabel('y-axis');
title('Est vs Tr')
end
% legend outside of the function
legend(handles, 'true','estimated'); % legend for a blue and a red circle handle
end
The result looks like this:

The thing is that you draw 4 things and only have 2 entries in the legend.
As such it will pick the color of the first four things to color the legend.
Not in the opportunity to try it myself now, but I guess that the easiest 'solution' would be to draw your third circle first and then the second one.
circle([ 10, 0], 3, 'b')
circle([ 10, 10], 3, 'r')
circle([-10, 0], 3, 'b')
circle([-10, 10], 3, 'r')

Related

grouped bar chart with 2 y-axes is displayed as stacked bar

I would like to plot the grouped bar chart for the comparison of three methods. I tried the following code and it is displayed as stacked bar chart.can you please help
dice =[0, 3, 5];
no_of_region=[42, 12, 5];
figure;
bar(dice',.2,'grouped','FaceColor',[0 .5 .5],'EdgeColor',[0 .9 .9],'LineWidth',1.5)
ylabel('Dice Similarity index')
yyaxis right
bar(no_of_region, .2,'grouped','EdgeColor', 'r', 'LineWidth', 2);
legend('Dice Similarity Index','Number of regions')
legend('Location','northwest')
XTickLabel={'a' ; 'b';'c'};
XTick=[1 2 3]
set(gca, 'XTick',XTick);
set(gca, 'XTickLabel', XTickLabel);
set(gca, 'XTickLabelRotation', 45);
xlabel('Different Methods', 'Fontsize', 16)
ylabel('Number of Regions', 'Fontsize', 16)
title('Comparison of Algorithms', 'fontsize', 20);
set(gcf,'color','w');
OUTPUT I GOT AS:
One easy solution is to shift the bars left and right by half of their width (or more if you would like space between them). Here is the new code, which is also cleaned a bit stylistically:
% parameters
dice = [0, 3, 5];
no_of_region = [42, 12, 5];
X = [1, 2, 3]; % common x values for plot
bar_width = 0.2; % width of bars
% initialize figure
figure;
% left plot
bar(X.' - bar_width/2, dice', bar_width, 'grouped', ...
'FaceColor', [0 .5 .5], ...
'EdgeColor', [0 .9 .9], ...
'LineWidth', 1.5);
ylabel('Dice Similarity index');
% right plot
yyaxis right;
bar(X.' + bar_width/2, no_of_region, bar_width, 'grouped', ...
'EdgeColor', 'r', ...
'LineWidth', 2);
% plot formatting
legend({'Dice Similarity Index', 'Number of regions'}, ...
'Location', 'northwest');
XTickLabel = {'a' ; 'b'; 'c'};
XTick = X;
set(gca, ...
'XTick', XTick, ...
'XTickLabel', XTickLabel, ...
'XTickLabelRotation', 45);
xlabel('Different Methods', 'FontSize', 16);
ylabel('Number of Regions', 'FontSize', 16);
title('Comparison of Algorithms', 'FontSize', 20);
set(gcf, 'color', 'w');
Depending on desired behavior, you also might consider replacing figure; by clf;, which clears the existing figure or opens a new figure window if there is not already one open.

insert string within marker of matlab plot

I have a 2D line plot:
d3 = [1, 3, 5, 6, 8, 9];
plot(d3, '-ob');
I would like to know how to insert a value into the markers of the line plot, such as inserting the y values into the center of the markers. For example:
Would this be possible?
Use text and properly adjust the text properties to suit your purpose. You may have to play with the marker size and text alignment, but it's a fairly straightforward process.
For example:
% plot the data
figure
d3 = [1, 3, 5, 6, 8, 9];
n = 1:numel(d3);
plot(n,d3, '-ob','markersize',10,'markerfacecolor','w');
% step through the points in d3 and display a text label for each of them
for idx = 1:numel(d3)
text(n(idx),d3(idx), num2str(d3(idx)),...
'FontSize',8,...
'HorizontalAlignment','center');
end
There is a way of plotting digits in circle using some special fonts (for example, WingDings 2 has numbers in circle from digit 0 to 9). You may find some other free font with 2 digits in circle or square.
Here is the sample code.
font_numberCircle = 'WingDings 2';
x = 1:6;
y = rand(1,6);
m = {'j','l','n','o','q','r'}; %the markers to be plotted ('j' is 1 and 'r' is 9
figure('Color', 'w');
plot(x, y, 'r');
text(x, y, m, 'FontName', font_numberCircle, ...
'FontSize', 40, 'FontWeight', 'bold', ...
'HorizontalAlignment', 'center' )
set(gca, 'XLim', [0 7], 'YLim', [-0.1 1.1] );

How to get arrows on axes in MATLAB plot?

I want to plot something like this:
x = 0:0.01:10;
f = #(x) 50* 1.6.^(-x-5);
g = #(x) 50* 1.6.^(+x-10);
plot(x, f(x));
hold on
plot(x, g(x));
I can't manage to get axes similar to the ones in this figure:
I know I can remove the top and right lines like in this question, but I don't know how to get the arrows on the edges.
I don't need the additional annotations, but I would like to remove the ticks on the axes. I know how to do this when the axes are "normal", but I'm not sure if it must be done in another way when the axes are already manipulated.
Does anyone know how to do this?
Well, don't say I didn't warn you :)
% Some bogus functions
f = #(x) 50* 1.6.^(-x-5);
g = #(x) 50* 1.6.^(+x-10);
% Point where they meet
xE = 2.5;
yE = f(xE);
% Plot the bogus functions
figure(1), clf, hold on
x = 0:0.2:5;
plot(x,f(x),'r', x,g(x),'b', 'linewidth', 2)
% get rid of standard axes decorations
set(gca, 'Xtick', [], 'Ytick', [], 'box', 'off')
% Fix the axes sizes
axis([0 5 0 5])
% the equilibrium point
plot(xE, yE, 'k.', 'markersize', 20)
% the dashed lines
line([xE 0; xE xE], [0 yE; yE yE], 'linestyle', '--', 'color', 'k')
% the arrows
xO = 0.2;
yO = 0.1;
patch(...
[5-xO -yO; 5-xO +yO; 5.0 0.0], ...
[yO 5-xO; -yO 5-xO; 0 5], 'k', 'clipping', 'off')
% the squishy wiggly line pointing to the "equilibrium" text
h = #(x)0.5*(x+0.2) + 0.1*sin((x+0.2)*14);
x = 2.7:0.01:3.5;
plot(x, h(x), 'k', 'linewidth', 2)
% the static texts
text(xE-yO, -0.2, 'Q^*', 'fontweight', 'bold')
text(-2*yO, yE, 'P^*', 'fontweight', 'bold')
text(-2*yO, 4, 'Price', 'rotation', 90, 'fontsize', 14)
text( 4, -0.2, 'Quantity', 'fontsize', 14)
text( .5, 4.2, 'Demand', 'fontsize', 14, 'rotation', -55)
text( 4.0, 3.3, 'Supply', 'fontsize', 14, 'rotation', +55)
text( 3.6, 2.1, 'Equilibrium', 'fontsize', 14)
Result:
The symbolic math toolbox has provisions for making these arrows, but without that toolbox you are stuck with drawing the arrows yourself. The following code should be useful for this purpose:
% determine position of the axes
axp = get(gca,'Position');
% determine startpoint and endpoint for the arrows
xs=axp(1);
xe=axp(1)+axp(3)+0.04;
ys=axp(2);
ye=axp(2)+axp(4)+0.05;
% make the arrows
annotation('arrow', [xs xe],[ys ys]);
annotation('arrow', [xs xs],[ys ye]);
% remove old box and axes
box off
set(gca,'YTick',[])
set(gca,'XTick',[])
set(gca,'YColor',get(gca,'Color'))
set(gca,'XColor',get(gca,'Color'))
The only drawback is that for some figure window sizes you will have a 1-pixel white border below the arrows, and setting the LineWidth property of the axes to a ridiculous small value does not help.
But for printing, the small white border should not be relevant.

How to display two overlapping lines in matlab

I have to plot 5 lines that overlap in some regions, and I need to be able to see all the lines.
I can think of shifting the lines a bit to allow them to be displayed, but this doesn't seem a very elegante solution. Even so, how could I code such a thing?
Is there any other way to plot multiple overlapping lines while being able to distinguish them at every point?
For exemple, here is one exemple with 3 overlapping lines:
Thank you in advance!
Another way is to use transparency.
Unfortunatelly, line objects do not obey
transparency commands :(
A workaround is to:
1. download patchline (<-- link to Matlab Central)
2. use it to plot patchline with transparency
Once you have patchline, you can try something like:
% create some lines:
l1 = [1, 1, 1, 0, 0, 0.25, 1, 1, 0, 0, 0, 0, 1 1];
l2 = [0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1];
l3 = [1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0];
% plot with patchline (notice the use of 'EdgeAlpha'):
figure;
patchline(1:length(l1), l1, [], 'EdgeColor', [0.8, 0.2, 0.35],...
'LineWidth', 5, 'EdgeAlpha', 0.5 );
hold on;
patchline(1:length(l1), l2, 'EdgeColor', [0.2, 0.7, 0.55],...
'LineWidth', 5, 'EdgeAlpha', 0.5 );
patchline(1:length(l1), l3, 'EdgeColor', [0.1, 0.2, 0.95],...
'LineWidth', 5, 'EdgeAlpha', 0.5);
% change y limits to see line overlap clearly
set(gca, 'YLim', [-0.5, 1.5]);
Not an ideal way to do it - the rough 'cracks' will stay this way,
but you can experiment with different line widths or moving the
lines in y axis by a value that would correspond to an image with each
line covering only half of it closest neighbour...
You may play with EraseMode property of the plot line. The following code example shows how to shift the lines and EraseMode effect:
% First we generate some data
NLines = 2;
NPoints = 50;
LineWidth = 3;
ShiftStep = 1.1;
XData = linspace(0,1,NPoints);
YData = rand(NPoints,NLines);
for k=1:NLines
YData(:,k) = YData(:,k) > (k/(NLines+1));
end
% Then we create plot
figure('color','w');
subplot(3,1,1); plot(XData,YData, 'LineWidth',LineWidth);
ylim([-0.1 1.1]);
title('simple')
subplot(3,1,2); plot(XData,YData+repmat((0:NLines-1)*ShiftStep,NPoints,1), 'LineWidth',LineWidth, 'EraseMode','xor');
ylim([-0.1 1.1+ShiftStep*(NLines-1)]);
title('Shifted vertically')
subplot(3,1,3); plot(XData,YData, 'LineWidth',LineWidth, 'EraseMode','xor');
ylim([-0.1 1.1]);
title('EraseMode = xor')
In my opinion if you have more than three lines similar to your plot, shifting is visually more attractive. Also you may create several axes (Like I did) and plot each line in its own axes, so they will have y-labels set accordingly, but their X-labels will be essentially the same.
You can use plot3 and assign different Z values to different overlapping lines. However, it'll look more like you expect (Z being the "up" direction) if you swap the Y and Z axes:
Example:
Y1 = randn(1,100);
Y2 = randn(1,100);
X = 1:100;
Z1 = 1*ones(size(X));
Z2 = 2*ones(size(X));
plot3(X,Z1,Y1);
hold on;
plot3(X,Z2,Y2);

Plotting a line above/below existing lines created with plotyy

I'm running this code:
t = linspace(0, 10, 1000);
y1 = 2*t;
y2 = 3*t;
figure;
[ax, h1, h2] = plotyy(t, y1, t, y2);
set(h1, 'LineWidth', 4);
set(h2, 'LineWidth', 4);
hold on;
h3 = plot([5, 5], [0, 3000], 'LineWidth', 6, 'Color', [0.6, 0.6, 0.6]);
Which creates this plot:
Notice how the vertical grey line appears on top of the blue line (y1) but below the green line (y2).
How do I plot the grey line either on top of the other two lines, or below the other two lines?
I see two options:
A. Bring the gray line forward by moving it to the second axes created by the plotyy command
set(h3,'parent',ax(2));
B. Place the gray line on the bottom by rearranging the order of the blue and grey lines on
the axes.
chld = [h1 h3];
set(ax(1),'children',chld); %# reorders the two lines so that the gray line is in back.
To make the gray line bottom, you can also change the order of drawing.
t = linspace(0, 10, 1000);
y1 = 2*t;
y2 = 3*t;
figure;
h3 = plot([5, 5], [0, max(y1)], 'LineWidth', 6, 'Color', [0.6, 0.6, 0.6]);
hold on;
[ax, h1, h2] = plotyy(t, y1, t, y2);
set(h1, 'LineWidth', 4);
set(h2, 'LineWidth', 4);
There's a trick in h3 = plot(...) to make sure the left scale is correct, though.