4 views (last 30 days)

Show older comments

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!

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

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])

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!