Accessing legend entries exceeds matrix dimensions - matlab

I am trying to plot some data with Matlab R2015a and as the data sets are changing for different plots I want to create the legend (semi-)automatically. I do this with a list of strings (called list) and then
leg = legend(list);
legtxt=findobj(leg,'type','text');
set(legtxt(1),'color','r');
set(legtxt(2),'color','b');
a.s.o. according to the entries.
However, no matter what index I give in the 'set(legtxt(i))' part, Matlab always tells me 'Index exceeds matrix dimensions.' Same, if I create the the legend manually by not using 'legend(list)' but explicitly typing the legend entries. Does anyone know why this happens or how to solve it? Thanks!

You need to use additional outputs from the call to legend. Specifically, check out the 2nd output called icons in the docs.
As for the error, the call to findobj(...) yields an empty vector, so matrix dimensions are indeed exceeded. Indeed (from the docs):
Starting in R2014b, the legend function returns a legend object. In
previous releases it returns an axes object.
So maybe that's why you can't use findobj to fetch legend text...
Anyhow here is how to solve your problem. In this example I create 3 plots and change the color of the text of the 1st and 2nd entry inside the legend:
x = 1:10;
y1 = sin(x);
y2 = cos(x);
y3 = x;
plot(x,y1,'y*',x,y2,'g--',x,y3,'k')
list = {'y1';'y2';'y3'};
%// You want to play with icons and possibly plots.
[leg,icons,plots,str] = legend(list)
set(icons(1),'color','r','FontSize',12)
set(icons(2),'color','b','FontSize',12)
Output:
Of course you can use the plots output to change any property you want of the plots to make them fit with their legend entry.

Related

How to add datatips in a fitted surface chart

I have created a fitted surface from x, y, z data points. How do I insert data tips for the min and max value in the chart?
defDM_fit = fit([def_X, def_Y],def_Z,'cubicinterp');
clf;
figure(2)
plot(defDM_fit,[def_X, def_Y],def_Z);
using the following test code is raising an error "Invalid argument. The object has been deleted or does not support data tips":
datatip(defDM_fit, def_X(1), def_Y(1), def_Z(1))
And I do not know how to manage that tips show up at min and max value in the chart by code.
Plotting a fitted surface created with fit outputs a 2x1 graphics array. The first element is the surface (Surface object), the second element is a Line object that holds the points on which your data was fitted. In order to add datatips, you will have to use one of these two objects, and more probably the Surface object, for example:
load franke
T = table(x,y,z);
f = fit([T.x, T.y],T.z,'linearinterp');
p = plot( f, [T.x, T.y], T.z );
datatip(p(1),T.x(1),T.y(1),T.z(1))
The first argument of datatip is a graphic object, not a surface/line fit object.
defDM_fit = fit([def_X, def_Y],def_Z,'cubicinterp');
figure(2)
p=plot(defDM_fit,[def_X, def_Y],def_Z);
datatip(p, def_X(1), def_Y(1), def_Z(1))
There are many other things that may be wrong with your approach, particularly because you are showing a surface plot (surf) in your example, yet your code uses a line plot (plot). I am not even sure what the arguments even are, the way you are putting them.
Consider reading the documentation of the functions you are using, as they come with examples on how to use them: https://uk.mathworks.com/help/curvefit/fit.html

GCA function doen't work to change axis-labels

I try to present 8 (name) labels on my x-axis. Instead, I get number 1 to 8.
Problem: In my previous asked question, I used gca function, that allows me to change axis labels. However, the same gca function doesn't work here.
This is my MatLab output:
Instead of 1,...8, I want to see Firm1...Firm8!
This is my code:
figure(2);
%four variables:
%pi --> 8x1 vector
%E_R_BL_Idzorek --> 8x1 vector
%pi_star1 --> 8x1 vector
%ER_100_TF1 --> 8x1 vector
ALL_DATA=[pi(1,1) E_R_BL_Idzorek(1,1) pi_star1(1,1) ER_100_TF1(1,1);pi(2,1) E_R_BL_Idzorek(2,1) pi_star1(2,1) ER_100_TF1(2,1);pi(3,1) E_R_BL_Idzorek(3,1) pi_star1(3,1) ER_100_TF1(3,1);pi(4,1) E_R_BL_Idzorek(4,1) pi_star1(4,1) ER_100_TF1(4,1);pi(5,1) E_R_BL_Idzorek(5,1) pi_star1(5,1) ER_100_TF1(5,1);pi(6,1) E_R_BL_Idzorek(6,1) pi_star1(6,1) ER_100_TF1(6,1);pi(7,1) E_R_BL_Idzorek(7,1) pi_star1(7,1) ER_100_TF1(7,1);pi(8,1) E_R_BL_Idzorek(8,1) pi_star1(8,1),ER_100_TF1(8,1)];
%plotting it with a bar function
bar(ALL_DATA);
%This is where I have problem with gca function
set(gca,'xticklabel',{'Firm1','Firm2','Firm3','Firm4','Firm5','Firm6','Firm7','Firm8'});
%this is the grid part:
grid on
ll = cell(1,4);
ll{1}='pi'; ll{2}='ERidz'; ll{3}='piTF'; ll{4}='ERTF';
legend(bar(ALL_DATA),ll);
You are using a newer version of MATLAB so you should use the newer graphics system. The newer system is based on objects. This makes setting properties of things like axes easier. For example:
fh = figure; % creates the figure window save the figure handle to set it's properties
ax = axes(fh); % creates the axes in the figure, again save the object
x = rand(8,100);
h = bar(ax, x); % create the bar graph in your axes object
% now use the saved object to access the exact feature you want. This way you always have the thing you want. No searching.
ax.XTickLabel = {'Firm1','Firm2','Firm3','Firm4','Firm5','Firm6','Firm7','Firm8'};
Saving the objects is also handy for tracking legends and other things. For example: legend(ax,... You know exactly which legend you're dealing with.
What appears to be happening is that you are correctly changing the XTicks as you want but then you overwrite your graph with legend(bar(.... That creates a new bar graph. Try changing that line to just legend(ll). I would still suggest using the object system.
It seems the problem is that you redraw the bar when you run
legend(bar(ALL_DATA),ll);
You should simply do
legend(ll);

include legend in matlab compass plot

I am using the compass command in matlab to plot wind speeds and direction. I would like to alter the default version to (1) remove the labels within the compass, and (2) draw a legend outside the compass plot to demonstrate the magnitude of each arrow.
Specifically, using the compass is it possible to include a legend which describes the magnitude of the arrows instead of having the values defined on the figure? For example:
rng(0,'twister') % initialize random number generator
M = randn(20,20);
Z = eig(M);
figure
compass(Z)
This is a normal compass plot where the magnitude of each entry is shown by labels on the figure, here they are 1:5. I can remove the labels with:
h = findall(gca,'type','text'); % Find all handles to text labels
legit = {'0','30','60','90','120','150','180','210','240','270','300','330','360',''}; % Define what to keep
idx = ~ismember(get(h,'string'),legit); % Take the others and set them to empty string
set(h(idx),'string','');
However, I would now like to include a legend which demonstrates the length of an arrow with a size of say 2 would be. Any ideas on how to do this?
Try some version of this -- after creating the data:
u=abs(Z)
figure(1)
compass(Z)
set(findobj(gcf,'type','text','-and','fontsize',10),'string','')
legend({['z_1 = ',num2str(u(1)),' units'],...
['z_2 = ',num2str(u(2)),' units']},...
'location','southoutside')
I used compass() a lot, but actually i'm not so sure that the font size of the labels are 10, in my (many) compass plots i have used this as a parameter and it worked fine. If it don't, just use the parameter text that findobj() will get all of the text in the figure as well.

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, ...).

Smooth Excel-like plot with correct legend in Matlab

I have some sparse data and want to plot them as markers connected by a smooth, interpolated line - like the default behaviour of Microsoft Excel.
There are solutions to this problem easily found on the internet, but I find them unsatisfactory. What they do is: plot the sparse data as one data set drawing it as markers without lines, interpolate it with a method of choice and plot the interpolation as the second data set, with lines without markers.
The problem with these tricks is that in the legend the two data sets will be listed separately. I would expect a single data set depicted in the legend as a line crossing through a marker.
Is it possible in Matlab?
If you want to plot an interpolated line there are lots of ways to do that. You can try generating an interpolated line using the matlab interp1() function.
Let's create x and y data with no NaN.
x = randn(1,10)
y = randn(1,10)
If you want 1000 data points where previously you only had a few, that's pretty easy:
x2 = min(x):(max(x)-min(x))/1000:max(x)
y2 = interp1(x,y,x2,'cubic')
and you can plot your data and spline using
plot(x,y,'r+')
hold on
plot(x2,y2,'r-')
A custom legend is straightforward when you use handle graphics. You can plot a dummy data set with a red line passing through a marker using
h(1) = plot(NaN,NaN,'r-+')
lstring{1} = 'Data';
You can then add a legend that points to this data set using
legend(h,lstring)
You'll end up with something that looks roughly like this:
The nice thing about using handle graphics (i.e. the h) is you can throw whatever data series you want into the legend as h(end+1) and lstring{end+1}.