How to set plot color for N curves to be a gradient of N color shades between light blue and dark blue (or any other color)?
287 views (last 30 days)
Show older comments
Travis Briles
on 24 Aug 2021
Answered: Simon Dengler
on 29 Nov 2022
Background
I have a variable number of datasets, N, which are generated in a loop. I would like to plot these datasets as a color gradient where each dataset is a different shade a given color, say from light blue to dark blue. Ideally, I would like the first and last colors to stay fixed, but would like the number of divisions between those colors (ie: light blue and dark blue) to vary as N varies. My solution runs into problems because parentheses are used to define a function defining a matrix of color triplets as well as the row index in the matrix.
Partial Solution
I use the 'uisetcolor' command to manually choose my desired shades for light blue and dark blue (this process not shown here, try it yourself):
lightBLUE = [0.356862745098039,0.811764705882353,0.956862745098039];
darkBLUE = [0.0196078431372549,0.0745098039215686,0.670588235294118];
With these chosen endpoints I create a blue color gradient with a fixed number of shades, 'kk' (this is based on the solution to a previous question by Matlab staff).
kk = 10;
blueGRADIENTfixed = [linspace(lightBLUE(1),darkBLUE(1),kk)', linspace(lightBLUE(2),darkBLUE(2),kk)', linspace(lightBLUE(3),darkBLUE(3),kk)'];
Create some fake data and plot it using 'blueGRADIENTfixed':
x = -10:0.5:10; %x-axis
N = 7; % # of curves to be plotted (imagine they are generated in a loop)
for i = 1:N
yi{i} = (2*i)*x.^2 %create fake y-axis data
end
fig = figure;
for i = 1:N
plot(x,yi{i},'color',blueGRADIENTfixed(i,:)) %loop over all curves in plot
hold on
end
That should give you a good idea of the intended result.
The problem
This works ok, but is not ideal because the number of gradations is fixed and I don't know it ahead of time. Suppose that I only had N=2 curves generated in the loop, if the number of gradients is hard coded at k=10, both curves will be plotted using very nearly the same shade of light blue (hard to distinguish). To fix this I tried defining a function that creates the necessary matrix for a variable number of gradations, 'Nvar':
blueGRADIENTflexible = @(Nvar) [linspace(lightBLUE(1),darkBLUE(1),Nvar)', linspace(lightBLUE(2),darkBLUE(2),Nvar)', linspace(lightBLUE(3),darkBLUE(3),Nvar)'];
test=blueGRADIENTflexible(N) %check that it works using previously defined N=7, OK
Try using it in plot loop:
fig2 = figure;
for i = 1:N
plot(x,yi{i},'color',blueGRADIENTflexible(N)(i,:))
hold on
end
This throws the following error: 'Indexing with parentheses '()' must appear as the last operation of a valid indexing expression.' (Note: if I evaluate the code using "Run" button on this page the error is "invalid array indexing"). This seems to be coming from the double use of parentheses for the function and row index. i.e. function(N) (i,:)
A dumb solution would be to just create a variable for the appropriately sized matrix for each plot to avoid the use of double parentheses. This would be something like:
fig3 = figure;
dumbdumb = blueGRADIENTflexible(N);
for i = 1:N
plot(x,yi{i},'color',dumbdumb(i,:))
hold on
end
This works, but I'd rather not do that because it still requires manually generating a new variable for each plot. I tried a few methods of converting the matrix to a cell array thinking that would fix the double parentheses problem but got a similar error.
Does anyone know of a way to get code simlar to that for 'fig2' to work?
Thanks!
0 Comments
Accepted Answer
Kelly Kearney
on 24 Aug 2021
I suggest reformatting the color-generating function so that instead of returning the entire gradient colormap, it returns only the single color you need at a given time:
lightBLUE = [0.356862745098039,0.811764705882353,0.956862745098039];
darkBLUE = [0.0196078431372549,0.0745098039215686,0.670588235294118];
blueGRADIENTflexible = @(i,N) lightBLUE + (darkBLUE-lightBLUE)*((i-1)/(N-1));
% Fake data
x = -10:0.5:10; %x-axis
N = 7; % # of curves to be plotted (imagine they are generated in a loop)
for i = 1:N
yi{i} = (2*i)*x.^2; %create fake y-axis data
end
% Plot
fig = figure;
for i = 1:N
plot(x,yi{i},'color',blueGRADIENTflexible(i,N)); %loop over all curves in plot
hold on
end
1 Comment
Travis Briles
on 13 Dec 2021
Edited: Travis Briles
on 13 Dec 2021
Note: Both @Kelly Kearney and @DGM's solution runs into an error if N=1, which is sometimes the case for me. Kelly's solution was easier to fix by just replacing 'N-1' with 'N'. ie:
blueGRADIENTflexible = @(i,N) lightBLUE + (darkBLUE-lightBLUE)*((i-1)/N);
You won't reach the final "darkBLUE" color shade but this fix works well enough for my purposes. Thanks to all.
More Answers (2)
DGM
on 24 Aug 2021
Edited: DGM
on 25 Aug 2021
Yeah. That's not valid indexing.
You could use interpolation tools to make the CT generator a function of the table size and the position within the table:
lightBLUE = [0.356862745098039,0.811764705882353,0.956862745098039];
darkBLUE = [0.0196078431372549,0.0745098039215686,0.670588235294118];
x = -10:0.5:10; %x-axis
N = 7; % # of curves to be plotted (imagine they are generated in a loop)
for i = 1:N
yi{i} = (2*i)*x.^2; %create fake y-axis data
end
blueGRADIENTflexible = @(n,nn) interp1([1/nn 1],[lightBLUE;darkBLUE],n/nn);
test=blueGRADIENTflexible((1:N),N)
for i = 1:N
plot(x,yi{i},'color',blueGRADIENTflexible(i,N))
hold on
end
I think that ideally, you could just turn that into a function that also accepted two color tuples as optional arguments. That way you can create whatever color sweeps you wanted. EDIT: see the attached file. Usage is as such:
createcolortable(lightBLUE,darkBLUE,7)
createcolortable(lightBLUE,darkBLUE,7,[2 2.5 3])
See Also
Categories
Find more on Data Distribution Plots in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!