Plotting, marking and legend in a loop - matlab

I want to plot a graph, mark a point and write legend in a loop.
labels = {}
for i = 1: size(error,1)
r = plot(handles.axes1,temp(i).time,temp(i).signal);
hold (handles.axes1, 'on')
a = %find minimum index
xmin = temp(i).time(a);
ymin = temp(i).signal(a);
plot(handles.axes1,xmin,ymin,'ro')
labels{end+1} = sprintf('Type : %s, %f,%f',error{i,1}.main(1,1).type,xmin,ymin)
end
grid on
legend(r, labels);
Labeling does not work, as it takes only 1st elements ignoring extra element. and the whole method is a mess with color code all messed up, is there elegant way of doing this where my legend colour matches the plot ones

Another way to do this is to use the DisplayName keyword.
for i = 1:N_lines
%...
r(i) = plot(handles.axes1, temp(i).time, temp(i).signal, 'DisplayName', labels{i});
%...
end
legend('show')
The advantage of doing it like this is that it attaches the name directly to the plotted point. If you are debugging, and open the plot as its being written in the plot browser, as each point get plotted the name will appear next to the point in the right-hand pane. You also don't need to keep track of a separate labels variable in case you end up later reordering your points for some reason. This way the labels always travel with their associated points.
I should add that when you call the legend command with a cell of labels, among other things it backfills 'DisplayName' so that you can still change and query it after the plot has been built even if you don't explicitly set it like I've done above. However, I find this method to be self-documenting and more convenient because it's one less thing to keep track of.

You need to make r an array. As it is, you're only storing the last plot handle so when you call legend it's only going to use the last plot and the first label.
% Create a unique color for each plot
colors = hsv(size(error, 1));
for i = 1:size(error, 1)
r(i) = plot(handles.axes1,temp(i).time,temp(i).signal, 'Color', colors(i,:));
%...
labels{i} = sprintf('Type : %s, %f,%f',error{i,1}.main(1,1).type,xmin,ymin);
end
legend(r, labels)
As a side-note it's best to not use i or j as your looping variable and also, don't name your variable error as that's the name of a MATLAB built-in.

Related

Hide MATLAB legend entries for some graphical objects in plots

MATLAB legends list everything in a plot, including guidelines that you have put on a plot.
A fudge to get around that is to do
*Plot
*Add legend
*Add guidelines
However, MATLAB puts the most recent lines in the front, meaning the guidelines then sit over the displayed data; ugly and distracting.
Similar problems occur any time you build up a complicated plot, legend freaks out and grabs everything, and workarounds with plotting order can be ugly
Example code:
%**** Optional guidelines
figure(1)
plot([2 2],[0,1],'k--'); hold on
%**** DATA
N = 4;
y=rand(5,N);
x=1:1:5;
for plotLoop=1:N;
%* Plot
figure(1)
plot(x,y(plotLoop,:));
hold on
end
%*****LEGEND
hLegend = legend(LegTxt,...
'interpreter','latex',...
'location','eastoutside')
(move the code block order to replicate the situations mentioned above)
How to reasonably fix this?
If you want a certain graphics object to not produce a legend (and that will work even if you toggle the legend off and on again), you can modify the LegendInformation:
%# plot something that shouldn't show up as legend
handleWithoutLegend = plot(something);
%# modify the LegendInformation of the Annotation-Property of the graphical object
set(get(get(handleWithoutLegend,'Annotation'),'LegendInformation'),...
'IconDisplayStyle','off');
%# toggle legend on and off at will, and never see the something-object appear
If you try to turn off the legend on an array of handles, the best way is just to loop over them, with a try-wrapper for graphical objects that cannot produce a legend:
for h = listOfHandles(:)'
try
set(get(get(h,'Annotation'),'LegendInformation'),...
'IconDisplayStyle','off');
end
end
Craft a custom handle that you feed into the legend. Plot handles can be concatenated to form an object that legend is happy to accept as input.
The required code isn't pretty, but it does work.
%**** Optional guidelines for periodicity
figure(1)
plot([2 2],[0,1],'k--'); hold on
%**** DATA
N = 4;
y=rand(5,N);
x=1:1:5;
for plotLoop=1:N;
LegTxt{plotLoop} = num2str(plotLoop);
%* Plot
figure(1)
% if statement to construct a handle for the legend later
if plotLoop==1
htot=plot(x,y(plotLoop,:));
else
h=plot(x,y(plotLoop,:));
% Append this info to the figure handle
htot= [htot, h];
end
hold on
end
%*****LEGEND
hLegend = legend(htot,LegTxt,...
'interpreter','latex','FontSize',16,...
'location','eastoutside')
For the pedantic or curious, the loop for plotLoop=1:N; is here because I extracted the example from some rather complex code where the data is extracted from cell arrays. Obviously you could eliminate that loop for a lot of usage scenarios, I just decided to keep the code in its most flexible format!
You can also hide plot from legend in another way. Here's the sample:
figure(1)
hold on
x=1:10;
y1=x;
y2=x.^2/10;
y3=x.^3/100;
plot(x,y1);
plot(x,y2,'HandleVisibility','off');
plot(x,y3);
legend('x','x^3')
You just need to put 'HandleVisibility', 'off' to your plot that you don't want to show up in legend. That's how result looks like:
HandleVisibility is a line property so it might now work if you create plot in some other way. But for most use cases its enough and it is much simpler.

pzmap or pzplot color handle for multiple plots

I am plotting a closed loop poles of a systems using pzmap.m or pzplot.m whichever you prefer. I want to see the movement of poles and zeros as I change a variable depicted by L.
The function does not have a direct handle for color. In the example you can just choose the standard colors but cannot give your own color. Since I have to plot multiple times on the same figure, I create a handle for every iteration in a for loop and use findobj to set the color of the curve. To get the colors I want to have a colorbar. So I use jet to get the color distribution for my graph. But the market size stays the same and I have one ugly looking figure.
MWE:
cb=jet(10);
s=tf('s');
L_array=5:5:50;
figure; hold on;
for i=1:length(L_array)
L=L_array(i);
G=((58.2+11.7*L)*s^2*25^2+(3996.8 + 815.7*L)*s*25+815.7*25^2)/(s^2*(s^2*25^2+126.9*s*25+(3996.8+1.9*25^2)));
CL=feedback(G,1);
pzmap(CL);
h = findobj(gcf,'type','point'); set(h,'markers',12,'color',cb(i,:));
clear L G CL h
end
grid;
c=colorbar
c.Label.String = 'L'
If you run it you'll see that the size doesn't change and graph looks crazy with the y axis on either side labelled with ticks. I want a proper colorbar from blue to red and the colors distributed properly but can't get it after multiple tries. If I can get less cluttering that would be helpful too.
The are several problems in your code
h = findobj(gcf,'type','point'); The things drawn in the screen are actually of type 'line'!
Every iteration, you catch all the points, modify them an dimdediately after delete the properties with clear.
Additionally, h = findobj(gcf,'type','line'); will not return a single thing, but a set of them, so you need to index through it to set the properties. My modified code working looks like this:
clear;clc
cb=parula(10);
s=tf('s');
L_array=5:5:50;
figure; hold on;
for i=1:length(L_array)
L=L_array(i);
G=((58.2+11.7*L)*s^2*25^2+(3996.8 + 815.7*L)*s*25+815.7*25^2)/(s^2*(s^2*25^2+126.9*s*25+(3996.8+1.9*25^2)));
CL=feedback(G,1);
pzmap(CL);
end
% lets do this in the end!
% you will have length(L_array)*2 +1 items in h
h = findobj(gca,'type','line');
for jj=2:length(h)
set(h(jj),'MarkerSize',12,'Color',cb(floor(jj/2),:));
end
grid;
colormap(parula); % I am using parula, you can use jet, but I discourage it
c=colorbar;
PD: there are tons of reasons not to use jet!! Use perceptually uniform colormaps please!

Indicate name of filled areas inside area plot - Matlab?

It's difficult to identify in this area plot each one of the many filled areas by just looking at the legend (it's like 16!).
So, I was wondering if there's a way to place some sort of labels (with a pointer perhaps?) inside the plot that clearly identifies each filled areas?
Thanks!
Here is an alternative using annotation objects and the textarrow option, which displays text along with an arrow. This could be useful to you to point in narrow regions where text would hide data.
For example:
clear
clc
close all
x = 1:128;
%// Plot data
figure
hAxes1 = axes('Position',[.1 .1 .6 .8]);
image(x.');
axis off
colormap(jet(128))
%// Define labels
ColorLabels = {'Red';'Orange';'Green';'Blue';'More blue'};
%// Define starting and ending x and y positions
xstart = .8;
xend = .6;
ystart = linspace(.1,.8,numel(ColorLabels));
yend = linspace(.15,.8,numel(ColorLabels));
for k = 1:numel(ColorLabels)
annotation('textarrow', [xstart xend],[ystart(k) yend(k)],...
'String', ColorLabels{k});
end
gives the following output:
There may be a builtin way that I don't know about but I find the lower-level text function is usually the best answer for this kind of thing.
It'll require some housekeeping - you have to supply an x and y coordinate and the text to print, e.g.
text(20, 400, 'Region 4')
which will centre the label on (20,400) (see the 'VerticalAlignment' and 'HorizontalAlignment' name-value pairs in the docs for fine-tuning), so for me it's usually preferable to write a small wrapper that will work them out from the data. Of course this is usually specific to the particular type of data you're using and rarely generalises to other uses of area plots, but that's most likely why there isn't already a generic labelling function (that I'm aware of).

How to change font size of right axis of Pareto plot in Matlab

I am trying to bold the right side y axis for a Pareto plot in Matlab, but I can not get it to work. Does anyone have any suggestions? When I try to change the second dimension of ax, I get an error:
"Index exceeds matrix dimensions.
Error in pcaCluster (line 66)
set(ax(2),'Linewidth',2.0);"
figure()
ax=gca();
h1=pareto(ax,explained,X);
xlabel('Principal Component','fontweight','b','fontsize',20)
ylabel('Variance Explained (%)','fontweight','b','fontsize',20)
set(ax(1),'Linewidth',2.0);
set(ax(1),'fontsize',18,'fontweight','b');
%set(ax(2),'Linewidth',2.0);
%set(ax(2),'fontsize',18,'fontweight','b');
set(h1,'LineWidth',2)
Actually you need to add an output argument during the call to pareto and you will then get 2 handles (the line and the bar series) as well as 2 axes. You want to get the YTickLabel property of the 2nd axes obtained. So I suspect that in your call to pareto above you do not need to supply the ax argument.
Example:
[handlesPareto, axesPareto] = pareto(explained,X);
Now if you use this command:
RightYLabels = get(axesPareto(2),'YTickLabel')
you get the following (or something similar):
RightYLabels =
'0%'
'14%'
'29%'
'43%'
'58%'
'72%'
'87%'
'100%'
What you can do is actually to erase them altogether and replace them with text annotations, which you can customize as you like. See here for a nice demonstration.
Applied to your problem (with dummy values from the function docs), here is what you can do:
clear
clc
close all
y = [90,75,30,60,5,40,40,5];
figure
[hPareto, axesPareto] = pareto(y);
%// Get the poisition of YTicks and the YTickLabels of the right y-axis.
yticks = get(axesPareto(2),'YTick')
RightYLabels = cellstr(get(axesPareto(2),'YTickLabel'))
%// You need the xlim, i.e. the x limits of the axes. YTicklabels are displayed at the end of the axis.
xl = xlim;
%// Remove current YTickLabels to replace them.
set(axesPareto(2),'YTickLabel',[])
%// Add new labels, in bold font.
for k = 1:numel(RightYLabels)
BoldLabels(k) = text(xl(2)+.1,yticks(k),RightYLabels(k),'FontWeight','bold','FontSize',18);
end
xlabel('Principal Component','fontweight','b','fontsize',20)
ylabel('Variance Explained (%)','fontweight','b','fontsize',20)
which gives this:
You can of course customize everything you want like this.
That is because ax is a handle to the (first/left) axes object. It is a single value and with ax(1) you got lucky, its ax again, but ax(2) is simply not valid.
I suggest to read the docs about how to get the second axis. Another good idea always is to open the plot in the plot browser, click whatever object you want so it is selected and then get its handle by typing gco (get current object) in the command window. You can then use it with set(gco, ...).

How to change the axes labels on a boxplot

When using the boxplot command from Statistics toolbox, the axes properties change in a strange way. For example, one gets
XTick = []
XTickLabel =
XTickLabelMode = manual
XTickMode = manual
What is happening to the axes and how one can rename the labels, and/or drop some of the ticks?
Try calling boxplot using the optional labels parameter.
Edit - further information about what boxplot actually does.
boxplot does some complicated stuff - type edit boxplot to take a look through the code, and you'll see it's a very long and intricate function. Basically it makes a blank axis with no axis labels, which is why you're seeing empty values for XTick etc. Then it makes the boxplot elements out of individual lines, and it simulates fake axis labels by adding text elements. You can find them and modify them directly by plotting into a figure f, then getting the Children of f, then iterating through to get their Children. Eventually you'll find text elements with the label names.
Try this:
xtix = {'A','B','C'}; % Your labels
xtixloc = [1 2 3]; % Your label locations
set(gca,'XTickMode','auto','XTickLabel',xtix,'XTick',xtixloc);
For some reasons resetting XTickMode to auto seemed to be key.
Thank you, Sam Roberts, that was helpful.
I wrote the following to remove group labels based on this advice. However, it removes ALL the labels, including axis and data tips. There doesn't seem to be a way to remove a label on an axis but leave it on a data tip.
m = get(get(get(figH,'Children'),'Children'),'Children');
for ii = 1:numel(m)
if(strcmp(get(m(ii),'Type'),'text'))
set(m(ii),'String', '');
end
end
The variable figH is the handle to your figure. You can also try gcf if the boxplot is the active figure handle.