How to change the color of lines as part of a plot based on a separate vector of values? - matlab

I have a collection of values stored in a 350x130 matrix, r, that I'm using to create a simple plot in Matlab:
figure;
plot(r)
Is there a way to color the resulting lines from r using another 350x1 vector, v? V contains a collection of integers, in this case, that vary from 1 to 4.
I'm imaging the call would look something like this, where, again, r is 350x130 and v is 350x1:
figure;
plot(r,v)

Let's define some example data:
r = rand(10,15);
v = randi(4,1,15);
Method 1 (more fun): using a comma-separated list
This creates a cell array and transforms it into a comma-separated list to call plot as plot(x1, y1, s1, x2, y2, s2, ...). The colors are limited to be defined as plot's linespec strings (such as 'g' or 'c+').
linespecs = {'r' 'g' 'b' 'm'};
c = repmat({1:size(r,1)}, 1, size(r,2));
c(2,:) = num2cell(r, 1);
c(3,:) = linespecs(v);
plot(c{:})
Method 2 (more readable and flexible): using a loop
linespecs = {'r' 'g' 'b' 'm'};
hold on
for k = 1:size(r,2)
plot(r(:,k), linespecs{v(k)})
end
This method allows using a colormap to specify arbitrary colors, not limited to linespec strings:
colors = winter(4); % arbitrary colormap
hold on
for k = 1:size(r,2)
plot(r(:,k), 'color', colors(v(k),:))
end

Related

Coloring Bars from a histogram/bargraph

I'm currently working on a project. For this project I've binned data according to where along a track something happens and now I would like to nicely present this data in a histogram. For this data however, multiple environments have been presented. I would like to color code each environment with its own color. The way I've done it now (very roughly) is:
x = 0:1:10;
y = bins;
color = ['b', 'g', 'g', 'g', 'y', 'y', 'g', 'g', 'g', 'b'];
b = hist(x, y, 'facecolor', 'flat');
b.CData = color
In this data bins contains all the bins a freeze has happened (1-10). These numbers are not in chronological order and not all numbers are present. However, when i use the code i get the following error:
Unable to perform assignment because dot indexing is not supported for variables of this type.
How can I color my various bars?
This is very nearly a duplicate of this question:
How to draw a colorful 1D histogram in matlab
However, you want to specify the colours according to the colorspec letter which changes things slightly.
The general concept is the same; you don't have that level of control with either hist (which is deprecated anyway) or histogram, so you have to plot it in two steps using histcounts and bar, because you do have that level of control on bar plots:
x = randn(100,1)*10; % random example data
% Specify the colours as RGB triplets
b = [0, 141, 201]/255;
g = [0, 179, 9]/255;
y = [247, 227, 40]/255;
% Build the numeric colours array
color = [b; g; g; g; y; y; g; g; g; b];
% Plot using histcounts and bar
[h,edges] = histcounts(x,10); % calculate the histogram data. 10 = size(color,1)
b = bar( (edges(1:end-1)+edges(2:end))/2, h ); % plot the bar chart
b.BarWidth = 1; % make the bars full width to look the same as 'histogram'
b.CData = color; % color is a 10x3 array (columns are RGB, one row per bar)
b.FaceColor = 'flat'; % Make 'bar' use the CData colours
Tip: you can find RGB colour values easily using any number of colour pickers online, but Googling "color picker" will give you one at the top of Search, from which you can copy the RGB values. Note that MATLAB expects values between 0 and 1, not 0 and 255.
In R2007b b = hist() indeed outputs a 1x11 double array, being the counts in each bin. This means that you cannot use the regular syntax to output a figure handle that way. Citing the documentation:
n = hist(Y) bins the elements in vector Y into 10 equally spaced containers and returns the number of elements in each container as a row vector. (...)
Solution 1:
Call hist(__); b = get(gcf);, i.e. force a figure handle. Check its properties on where the CData-equivalent property is. (On R2007b you need to do b = get(gcf);, followed by set(b, 'Color', color))
Solution 2:
Use the nowadays recommended histogram(). You can check its property list, you need to set
b.FaceColor = color;
b.EdgeColor = color;
However, as is already noted in this question hist(), and also histogram(), do not natively support the handling of multiple colours. That means that either of the above tricks need to be applied on a per-colour basis. In other words: first plot everything you want to have the colour blue with histogram( __, 'FaceColor', 'b', 'EdgeColor', 'b'), then the same for the green graph etc.

Generate multiple plot objects with vectors of equal length

MATLAB will generate multiple line objects when plot is used with a vector and a scalar:
a = 1:4;
ph = plot(a, 1, 'o');
numel(ph) % == 4
And usually, it is desired that plot generate a single line object for x and y arguments being vectors of the same length:
b = 1:2:8;
ph = plot(a, b, 'o');
numel(ph) % == 1
However, I'd like to generate a line object for each pair of values from a and b.
Note that the low-level line function also does not create one line per column if there is just one row.
So how can I force MATLAB to generate numel(a) line objects in an elegant way?
The best solution I could come up with uses arrayfun and requires an additional step to turn the cell array into an object array:
hold on;
ph = arrayfun(#(x, y) plot(x, y, 'o'), a, b, 'uni', 0)
ph = cat(2, ph{:});
(elegant means: no loop. Also, scatter won't work for me as it does not allow different marker types)
Edit:
Second best solution might be
ph = plot([a;nan(size(a))], [b;nan(size(a))], 'o')
This will produce four line objects but comes at the cost of having extra NaN data elements. Note the NaN have to be added to both arguments, otherwise there would be only two line series (the second one being invisible containing only NaNs for one coordinate).
If I understand you correctly, you want to plot both (or an arbitrary number) lines in one plot command. If so, you can use cellfun and input cell arrays, see example below:
x1 = 1:100;
x2 = 1:2:200;
y1 = rand(1,100);
y2 = rand(1,100);
X = {x1,x2};
Y = {y1,y2};
figure(1)
hold on
cellfun(#plot, X, Y)

Customizing multiple rootlocus plot colors (scale of grey) Matlab

I would like to customize the color of my rootlocus plot.
I use a for cycle to plot 10 rootlocus (with slightly different systems in the loop) and I would like every of them to be of a different shade of grey. I thought to use the gray command to obtain a matrix to store the RGB data and then use this matrix in the rlocus(sys,K,'style') command (choosing the i-th line at the i-th iteration of my cycle). Unfortunately the command requires the style to be a cell (for example 'g' or 'b') and not a vector of numbers.
This is a sample of my code:
figure()
hold on
L = [sys1, sys2, ..., sys10];
colors = gray(10);
for i = 0:9
rlocus (L(i+1), 'Color', colors(i+1, :));
end
The rlocus() function is not as powerful as the plot() function and only has limited support for setting colours with rlocus(sys, 'b') as you've noticed. However, we can combine it with the plot() function to make use of its power.
Here I use [R, K] = rlocus(sys) to return the values of the root locus, R. Each row of R represents a different trajectory. We can plot 1 trajectory of the root locus with plot(R(m, :)) and utilise the strength of plot() to change the colour however we wish.
L = [sys1, sys2, sys3, sys4, sys5, sys6, sys7, sys8, sys9, sys10];
C = gray(numel(L) + 1); % Extra 1 because the last value will be
% white and plotting white on white does
% not look well :P
figure;
hold on
for n = 1:numel(L)
[R, K] = rlocus(L(n));
for m = 1:numel(R)/length(R)
plot(R(m, :), 'Color', C(n, :));
end
end
hold off

matlab plotting a family of functions

Generate a plot showing the graphs of
y=(2*a+1)*exp(-x)-(a+1)*exp(2*x)
in the range x ∈ <-2, 4> for all integer values of a between -3 and 3
I know how to make typical plot for 2 values and set a range on the axes, but how to draw the graph dependent on the parameter a?
To elaborate on Ben Voigt's comment: A more advanced technique would be to replace the for-loop with a call to bsxfun to generate a matrix of evaluations of M(i,j) = f(x(i),a(j)) and call plot with this matrix. Matlab will then use the columns of the matrix and plot each column with individual colors.
%%// Create a function handle of your function
f = #(x,a) (2*a+1)*exp(-x)-(a+1)*exp(2*x);
%%// Plot the data
x = linspace(-2, 4);
as = -3:3;
plot(x, bsxfun(f,x(:),as));
%%// Add a legend
legendTexts = arrayfun(#(a) sprintf('a == %d', a), as, 'uni', 0);
legend(legendTexts, 'Location', 'best');
You could also create the evaluation matrix using ndgrid, which explicitly returns all combinations of the values of x and as. Here you have to pay closer attention on properly vectorizing the code. (We were lucky that the bsxfun approach worked without having to change the original f.)
f = #(x,a) (2*a+1).*exp(-x)-(a+1).*exp(2*x); %// Note the added dots.
[X,As] = ndgrid(x,as);
plot(x, f(X,As))
However for starters, you should get familiar with loops.
You can do it using a simple for loop as follows. You basically loop through each value of a and plot the corresponding y function.
clear
clc
close all
x = -2:4;
%// Define a
a = -3:3;
%// Counter for legend
p = 1;
LegendText = cell(1,numel(a));
figure;
hold on %// Important to keep all the lines on the same plot.
for k = a
CurrColor = rand(1,3);
y= (2*k+1).*exp(-x)-(k+1).*exp(2.*x);
plot(x,y,'Color',CurrColor);
%// Text for legend
LegendText{p} = sprintf('a equals %d',k);
p = p+1;
end
legend(LegendText,'Location','best')
Which gives something like this:
You can customize the graph as you like. Hope that helps get you started!

Setting colors for plot function in Matlab

I would like to be able to choose the colors for a multiline plot but I can not get it. This is my code
colors = {'b','r','g'};
T = [0 1 2]';
column = [2 3];
count = magic(3);
SelecY = count(:,column),
plot(T,SelecY,'Color',colors{column});
For some reason I couldn't get it to work without using a handle, but:
h = plot(T,SelecY);
set(h, {'Color'}, colors(column)');
Works for me.
You can only specify one color at a time that way, and it must be specified as a 3-element RGB vector. Your three routes are:
Loop through and specify the colors by string, like you have them:
hold on
for i=1:size(SelecY, 2)
plot(T, SelecY(:,i), colors{i});
end
Using the RGB color specification, you can pass the colors in via the 'Color' property, like you were trying to do above:
cols = jet(8);
hold on
for i=1:size(SelecY, 2)
plot(T, SelecY(:,i), 'Color', cols(i,:));
end
Also using the RGB way, you can specify the ColorOrder up front, and then let matlab cycle through:
set(gca, 'ColorOrder', jet(3))
hold all
for i=1:size(SelecY, 2)
plot(T, SelecY(:,i));
end
For setting colors after the fact, see the other answer.