Plots.jl: Assigning seriescolor using ColorGradient for line plot

I am having trouble using a ColorGradient to set the color levels of a dynamic number of series.

I can get the colorgradient to work if I use heatmap:

A = [i for i=1:100, j=1:100]
heatmap(A, c=ColorGradient(:inferno)) 

But for line plots it assigns the same color to all series:

N=40
n = 10; x = range(0,step=1,length=n); y=rand(n,N);
plot(x,y,c=ColorGradient(:inferno))

I am using Julia 1.0.1, Plots v0.21.0 and the GR v0.35.0 backend.

Any help would be appreciated.
Thanks!!

It is not quite clear to me what you want to do. Do you want to:

  1. Plot, say, 3 curves, with different color, e.g., one red, one blue, and one green?, or
  2. Do you want to plot one curve which changes color from, say, red to blue, along the curve?

Case 1.a: Julia v. 0.6.x allowed to make a vector of colors using the linspace() function, something along linspace(colorant"red",colorant"blue",5) would make a vector of 5 colors in the range from color colorant"red" and color colorant"blue".

Unfortunately, function linspace() has been removed, and the replacement, range() doesn’t support color argument. This is really unfortunate!

Anyway, the Plots syntax is that colors should be a row matrix, so colors in a vector need to be converted to colors in a row matrix.

You can, of course, still make the row matrix of colors manually:

plot([sin,cos,atanh], lc=[:red :blue])

Here, the list of functions will cycle through the row matrix of line colors.

Case 1.b: colors from color gradient.
Use a built-in color gradient, or design your own. Say you want to make your own, my_cgrad…

my_cgrad = cgrad([:red, :yellow, :blue])

makes a color gradient that starts in red, goes through yellow and ends up in blue. You need a minimum of two color elements in the argument vector.

To pick plot colors from the color gradient, do the following:

plot([sin, cos, atanh], palette = my_cgrad)

Case 2: Suppose you instead want to change the color along the line – perhaps mainly useful in parametric plots. This can be done as follows:

x = range(0,stop=2pi,length=50)
plot(sin.(x),cos.(x),lc=my_cgrad,line_z=x)
3 Likes

Thanks for the reply!

I am looking to do more along the lines of case 1. Basically I have a mxn Array which represents n different curves I would like to plot. I want to use a color gradient to choose the color for those n different curves but order it based on the column index of the Array. So if I am using the :blues ColorGradient, for example. I want the first curve (first column in the array) to be the darkest color available in the gradient, the last curve to be the lightest, and automatically select the appropriate colors in between in the gradient.

The palette method gets me close but when I do something like this:

N=40
n = 10; x = range(0,step=1,length=n); y=rand(n,N);
plot(x,y,palette=:blues)

It selects the colors from the gradient seemly randomly.

Does this mean that you really would like to use a row matrix of colors? In the “good old days” of linspace, one could do, say,

CLIST = reshape(linspace(colorant"blue",colorant"red",n),1,n)
plot(X,lc=CLIST)

Here, CLIST is a vector of n colors reshaped into a row matrix. Assumin that matrix X has n columns, the color of the first column equals the color of the first element in CLIST, the color of the second column of X equals the second element in row matrix CLIST, etc.

Another option: I think it is possible to specify that you want, say, n colors, and that you want these to be picked from some list of colors in such a way that they are the n that are easiest to distinguish. Don’t recall the syntax for doing this, though.

yes, i was assuming there was an internal method to Plots to select the colors when passing seriescolor=ColorGradient(:blues). But alternatively, it sounds like I am looking for a way to create a row vector of n colors that are along a gradient or between two defined colors. Any way to do this in 1.0 without linspace?

For context: I am trying to show how a m length variable changes over a number of iterations so would like a gradient to show this rather than distinct colors since there can be >100 difference curves.

Ah… range does work with colors! I tested it in a REPL where I had not used using Plots…

So – this works, I think…

using Plots;
n=20;
X=rand(100,n)
CList = reshape( range(colorant"red", stop=colorant"blue",length=n), 1, n );
plot(X,linecolor=CList)

See Introduction · Colors for some more.

2 Likes

Cool that works thanks!

Not sure if this is already available but it would be neat if there was a way to specify how the colors are picked from a palette. So I could do what I wanted with something like

plot(X,palette=my_cgrad, colorIndex=Col.index) 

Would probably be nice. I’m not a developer in any way, just a simple early user :-). Others may have to look into that.

Eh, plot(X, palette = :inferno) is already valid Plots syntax?

Note that Plots cannot know how many series you will add in the future, so when specifying a palette it will always try to select each color to be as widely spaced on the color gradient as possible.
If you know you have 5 series and want them spaced on the color gradient sequentially, you can use color and spread line_z over the 5 series:
plot(rand(20,5), color = :RdYlBu, line_z = (1:5)')


You can also just supply a vector with the color of each line to palette.

2 Likes

Thanks! That works well if I use the GR backend. However with pyplots I get an error:

Error showing value of type Plots.Plot{Plots.PyPlotBackend}:
ERROR: MethodError: no method matching py_color(::ColorGradient, ::Nothing)
Closest candidates are:
  py_color(::ColorGradient) at C:\Users\micah\.julia\packages\Plots\rmogG\src\backends\pyplot.jl:59
  py_color(::Colorant, ::Any) at C:\Users\micah\.julia\packages\Plots\rmogG\src\backends\pyplot.jl:60
  py_color(::Any) at C:\Users\micah\.julia\packages\Plots\rmogG\src\backends\pyplot.jl:56

Any ideas?

Bug :frowning:

I share the same desire as @Micah_BL (over and over, and never found a solution I could stick with).
While I would like plot(X, palette = :inferno) to work out of the box, it doesn’t lead to the desired result, as you explained above.

Note that Plots cannot know how many series you will add in the future

Wouldn’t just spreading the colors out evenly among the current given series be a sane default?

Also plot(rand(20,5), color = :RdYlBu, line_z = (1:5)') does not seem to work anymore. It gives me 5 lines of the same color :frowning:

Wow, what happened there?

The last issue will be fixed in https://github.com/JuliaPlots/Plots.jl/pull/2305

And disable the functionality of assigning a new color when adding a series? No, not in my opinion.