Not sure what is going wrong here. I created a minimal example below:
clear
steps = 1:6;
labels = cell(length(steps),1);
xvals = 1:10;
fig = figure(1);
ax = axes('parent',fig);
hold on
for ii=1:length(steps)
s=steps(ii);
yvals = zeros(length(xvals)) + ii;
labels{ii} = ['gain = ' num2str(s)];
plot(ax,xvals,yvals);
end
legend(ax, labels);
hold off
And the result on my system is:
With less lines it can even put colors in the legend that aren't even on the plot. What is happening?!
Explanation of what's happening
The problem is in the line
yvals = zeros(length(xvals)) + ii;
This creates a 10x10 square matrix, not a 1x10 vector. plot then plots each column of that matrix against xvals. That causes a mixing up of colors which is probably not what you want.
It's interesting to analyze specifically what happens. Matlab plots each column of that matrix with a different color, using the default cycle of colors, which in Matlab R2014b onwards is
But all columns of that matrix are the same, so each covers (overwrites) the preceding one, and you only see the last color.
Now, the color cycle has 7 colors and the matrix has 10 columns. So in the first iteration the last plotted column (the one you see) has color mod(10,7)==3 (yellow). In the second iteration you cycle through 10 more colors starting from 3, that is, you get color mod(3+10,7)==6 (light blue). And so on. Thus the color you see in the figure depends on the loop index ii, but not in the way you expected.
legend creates its entries by picking the color (and line spec) of each plotted line, in the order in which they were plotted. There are 10*6==60 plotted lines, each corresponding to a column of a matrix. But since you only supply six strings to legend, it just picks the first six of those lines, and uses their colors to create the legend entries. Those colors follow the default order, as explained above.
None of those first six lines that make it into the legend are actually seen in the figure, because they are covered by other lines. But legend doesn't care about that. So you get six legend entries with the default color order, which of course doesn't match the lines you actually see in the graph.
Solution
From the above, the solution is clear: replaced the referred line by
yvals = zeros(1, length(xvals)) + ii;
to create yvals as a vector (not a matrix). That way you'll get the figure you expected:
Related
I am trying to write a script to plot florescence intensity from some microscopy data as a scatter plot and threshold this data based on cells that respond greater than a certain amount in CFPMAX and plot these in green and cells that do not in red. When I try to plot this, I am unable to really assign proper colors to points and they end up being blue and red. I need each cell in the image to be assigned 4 values, (3 values for for each florescence channel and one value to determine whether or not it responded (green or red). Thus I was wondering if it was possible to assign the proper color to the 4th column of the matrix, or if I am going about this the wrong way all together. I have attached my code below.
MCHR=csvread('data1.csv');
MYFP=csvread('data2.csv');
MCFP=csvread('data3.csv');
CFPMAX=(max(MCFP))';
MCHMAX=(max(MCHR))';
YFPMAX=(max(MYFP))';
c=zeros(length(CFPMAX));
for i=1:length(c)
if CFPMAX(i)>40
c(i)='g'; %// green responders
else
c(i)='r'; %// red non-responders
end
end
MM=horzcat(MCHMAX,YFPMAX,CFPMAX,c);
scatter(MM(:,1),MM(:,2),100,MM(:,4),'filled','MarkerEdgeColor',[0 0 0])
title('Responders vs Non-Responders ')
xlabel('[TF1]') %// x-axis label
ylabel('[TF2]') %// y-axis label
As far as I can tell from the documentation, the input parameter c (assuming scatter(x,y,a,c,...)) can be one of:
A single character specifying a colour e.g. 'g' or 'r'. But just one single scalar colouring all of you points.
A single RGB triple colouring all of your points so [1,0,0] for red or [0,1,0] for green.
A three column matrix of RGB triples. This is likely what you want. I will demonstrate this to you.
A one column matrix of numbers which will colour the points according to a colormap. This one will also work for you but less explicitly. Incidentally, I would guess that this is option that MATLAB though your vector of characters was.
So in order to create the matrix of RGB triples you can modify your code to be
c=zeros(length(CFPMAX),3);
for i = 1:length(CFPMAX)
if CFPMAX(i)>40
c(i,:)=[0,1,0]; %// green responders
else
c(i,:)=[1,0,0]; %// red non-responders
end
end
However, you could actually do away with the for-loop completely in MATLAB and construct c in a vectorized approach using logical indexing:
c=zeros(length(CFPMAX),3);
c(CFPMAX > 40, 2) = 1; %// green responders
c(CFPMAX <= 40, 1) = 1; %// red responders
This is a more idiomatic way to do this in MATLAB.
I'm trying to reverse my legend entries order based on reverse ordering of legend colors in matlab bar plot, but it doesn't seem to work in my case.
Basicaly what I have is a GUIDE figure, that draws a lot of plots and is able to save them to a .png file. The effect looks like this:
I've managed to change the text order by flipping legend upside-down, but I can't change legend colors order.
Here's what I've got:
[a b] = legend(legenda);
map = colormap; % current colormap
n = size(b,1);
z = linspace(size(map,1),1,n/3); % there is 1 text and 2 line elements for every data series, so I divide by 3
z = round(z); %otherwise matlab gets angry that indices must be real integers or logicals
MAP = map(z(:),:); % gets elements specified by linspace from colormap
So far everything works ok.
The b vector for two series looks like this (starts with 2.0, because it's reversed):
Text (P+C 200 2.0.dpt)
Text (P+C 200 1.0.dpt)
Line (P+C 200 2.0.dpt)
Line (P+C 200 2.0.dpt)
Line (P+C 200 1.0.dpt)
Line (P+C 200 1.0.dpt)
So I figured out (based on the linked code), I have to change the color variable for every line entry.
for k = (n/3 + 1):n
a1 = get(b(k),'Children');
set(a1,'FaceColor',MAP(ceil((k - n/3)/2), :));
end
Ceil and dividing by 2 gives the same index twice.
This code, however, does nothing.
I've checked whether flipping the legend vector may be the source of my problems, but the color order stays the same. I've tried with MAP vector too - no luck.
When I remove the semicolon after the a1 = ... line in the for loop, I get:
a1 =
0x0 empty GraphicsPlaceholder array.
How can I get this to work?
Also, is there any good way to make the legend not cover the plots after it's saved (see picture linked above)?
The way I save it is by creating a temporary figure with 'visible' 'off' and doing a copyobj of axes and legend, then saving. Otherwise it saves the whole figure.
The reason for which the code provided in the answer to reverse ordering of legend colors in matlab bar plot does not work in your case is because in that case (plot of a bar chart) the object in the legend are patches while in your plot they are lines.
The FaceColor only applies to patches and not to lines.
The easiest way to solve you probles should be to reverse the order in which you plot the lines "since the beginning" and, doing that, directly using the set of colors you extract from the colormap.
Nevertheless, if you wnat to work with the legend after having plotted the graph, beside revrsing the items in the legend you have also to change the color of the lines in the plot, if you want to use the set of color extracted from the colormap (at present in your picture, some lines share the same color).
To can solve the problem in two steps:
revert the string in the legend and change the colors of the line sin the plot
update the color of the lines in the legend accordingly
The two steps are required since, when you change the color of the lines in the plot, the items in the legend are updated automatically.
With reference to the code youy've posted: you can access to the legend's string and line's color through the array b.
You can access to the handles of the lines plotted as follows:
p_h=get(gca,'children')
Since you have plotted 10 lines, the array b is build as follows:
b(1:10) contains the handles to the string
b(11:2:30) contains the handles to the lines
b(12:2:30) contains the handles to the markers
To chenge the positin of the legend you can set its location property: to put it outside the axes you can set it either to:
'NorthOutside' outside plot box near top
'SouthOutside' outside bottom
'EastOutside' outside right
'WestOutside' outside left
'NorthEastOutside' outside top right (default for 3-D plots)
'NorthWestOutside' outside top left
'SouthEastOutside' outside bottom right
'SouthWestOutside' outside bottom left
In the following you can find the code in which the above suggestions have been implemented.
figure
% Initial plot
h_p=plot(0:.1:2*pi,bsxfun(#plus,sin([0:.1:2*pi]),[3:3:30]'),'linewidth',3)
% Initial legend
[h_leg,b]=legend(cellstr(strcat(repmat('sin(x)+',10,1),num2str([3:3:30]'))))
%
% YOUR CODE TO GENERATE NTHE NEW COLORS
%
map = colormap; % current colormap
n = size(b,1);
z = linspace(size(map,1),1,n/3); % there is 1 text and 2 line elements for every data series, so I divide by 3
z = round(z); %otherwise matlab gets angry that indices must be real integers or logicals
MAP = map(z(:),:); % gets elements specified by linspace from colormap
%
% Reverse the legend strings
%
rev_str=flipud(get(b(1:10),'string'))
%
% Get the handles of the lines in the legend
%
b1=b(11:2:30)
%
% Revere the string in the legend
% and update the color of the lne in the plot using the colors defined in
% MAP
%
p_h=get(gca,'children')
for i=1:10
set(b(i),'string',rev_str{i})
set(p_h(i),'color',MAP(i,:),'linewidth',3)
end
%
% Reverse the color of the lines in the legend
for i=1:10
set(b1(i),'color',MAP(i,:),'linewidth',3)
end
%
% Move the legend outside the axes
%
set(h_leg,'location','NorthEastOutside')
Original Plot
Updated plot
Hope this helps.
If I open a previously (before R2014b) saved figure, the colors I used, for instance r, k , ... would appear according to the colormap they have been saved with. What is the fast way to convert the colors to their equivalent colors in the new colormap parula.
By equivalent colors I mean the standard sequence of colors that MATLAB utilizes when we usehold on command after each plot command, without setting the color property in the `plot'. something like this:
plot(x,y1);hold on;plot(x,y2);
It should be pretty much automatic If I change the default colormap of the plot, but it is not. Is there a command for that?
The plots I have, each includes more than 20 curves that makes it annoying to change the colors manually.
The following seems to work.
open example_figure.fig %// open old file in R2014b
ax = gca;
ch = ax.Children; %// the children are lines or other objects
co = ax.ColorOrder; %// this is the new set of colors
M = size(co,1);
p = 1; %// index of new color
for n = numel(ch):-1:1 %// start with lines plotted earlier. These have higher index
if strcmp(ch(n).Type,'line') %// we are only interested in lines
ch(n).Color = co(mod(p-1,M)+1,:); %// cycle through new colors
p = p + 1; %// increase color index
end
end
The key is that, as stated in Loren's blog,
The line colors used in plots are controlled by the ColorOrder property of the Axes object.
This is the property that stores the new hold on-colors used in R2014b. But this property applies to newly plotted lines, not to those already present from the file. So what my code above does is apply the colors defined by ColorOrder to the Children of the axes that are of type 'line'.
I've observed (at least in R2010b) that newer plots have lower indices within the children array. That is, when a new plot is added to the axes, it gets the first position in the Children array, pushing older plots to higher indices. That's why in the for loop above the children index (n) is descending while the new-color index (p) is ascending. This assures that the line that was plotted first (higher index) gets the first of the new colors, etc.
As an example, let's create a figure in R2010b:
plot(1:3, 'b')
hold on
plot(4:6, 'r')
plot(7:9, 'g')
The transformed figure is
I wish to format each line in a plot so that I can choose given colours for each line. However my x values are in matrix form so I cannot use the plot(x,y,'b',x,y,'r',...) style format. Many thanks.
I would recommend doing in a for loop, but maybe there is another way of doing it.
Define your colors in a matrix
cmap = hsv(10) %generate 10 random colors
hold on
for ii=1:10
plot(x(ii,:),y(ii,:),'color',cmap(ii,:))
end
Create cmap, as you wish. It needs to be a nlines X 3 size though.
If you don't need to choose colors as long as they are different, you can plot(transpose(data)) which will plot every line of data with a different color.
I'm trying to make a legend in a matlab figure that takes less space, in particular vertical size. Ideally, if I could change the inter-line spacing of the legend, this would have solved it, but I can't seem to find a way to do it.
I've searched around in Mathworks questions and Google. I've even tried to "write" from scratch the legend, but it doesn't work when I try to export to eps.
Is there a way to control the inter-line spacing in Matlab's legend? something undocumented maybe?
One way would be to adjust the aspect ratio of the legend:
set(h,'PlotBoxAspectRatioMode','manual');
set(h,'PlotBoxAspectRatio',[1 0.8 1]);
(Default is [1 1 1]).
You can also play with the exact positioning of the various legend elements. If h is the handle for your legend:
hc = get(h,'Children');
Now, hc will be of length 3 x the number of items in your legend.
hc(1) is the marker, hc(2) is the line, hc(3) is the text.
(and so on for subsequent items).
hc(1) will have a entry YData(vertical position, single value), hc(2) also has YData (vertical position - vector of two identical values), and hc(3) contains Position - [x y z] vector. The Y values for all these three should be the same.
Obtain the y-positions:
yd = zeros(length(hc)/3,1);
for n = 1:length(yd);
yd(n) = get(hc(1+(n-1)*3),'YData');
end
Assuming your legend doesn't have any text that goes over more than one line,yd should be evenly spaced steps. Define a new spacing of your choice, yd2.
Set new positions:
% markers
for n = 1:length(yd2)
set(hc(1+(n-1)*3),'YData',yd2(n));
end
% lines
for n = 1:3
set(hc(2+(n-1)*3),'YData',[yd2(n),yd2(n)]);
end
% text
for n = 1:3;
pos = get(hc(3+(n-1)*3),'Position');
pos(2) = yd(n);
set(hc(3+(n-1)*3),'Position',pos);
end
Problem - this shifts all the text and markers but doesn't change the border box. The easiest way if trying to make fine adjustments is to first define the final size/position of the legend, and then reposition/resize elements within to taste.
Also, you may find that when writing out images MATLAB helpfully redraws the image, resetting your adjustments. See this blog post on Undocumented MATLAB for info on that.