# ColorFunction or PlotStyle Based on List

I am plotting the values of a continuous, but complicated function Energy[x_] via ListLinePlot. Another function SpinVal[x_] also gives me values between -1 and +1.

I want the ListLinePlot curve of Energy[x_] to become blue when SpinVal[x_] returns -1, red when it returns +1 and respective colours between blue and red for any values between -1 and +1.

For ListPlot the following does the job (with example functions in the P.S.):

values = {#, Energy[#]} & /@xRange;
spins = SpinVal/@xRange;

ListPlot[{#} & /@values, PlotStyle -> Hue /@ (0.7 + 0.3/2*(1 + spins))]


(The (0.7 + 0.3/2*(1 + [...])-part is necessary for my choice of colours, since 0.7 is blue and 1 is red.)

This method, however, does not work for ListLinePlot, as it separates the points (see the ({#} & /@values)-part inside the plot function). I have made several attempts, e.g. something like what is recommended here, but since I want my function to be applicable to more plots than just this one, and since I have a terribly large amount of data points, I feel the need of an easier solution.

Ultimately, an elegant way to generate a legend would also be good. However, this legend can be generated easily by hand if no such elegant method exists.

P.S.

My code example above becomes quite illustrative if one just assumes a sine function for both Energy[x_] and SpinVal[x_]:

xRange = Range[-4, 4, 0.1];
values = {#, Sin[#]} & /@ xRange;
spins = Sin /@ xRange;

ListLinePlot[{#} & /@ values, PlotStyle -> Hue /@ (0.7 + 0.3/2*(1 + spins))]


It then looks like the following:

Of course, my actual problem does not have its colour grading matching the actual behaviour of the curve.

Thanks to MarcoB I was able to create a function that does the job:

xRange = Range[-4, 4, 0.1];
testvalues = {#, Sin[#]} & /@ xRange;
spins = Sin /@ xRange;

ListLinePlot[testvalues, ColorFunction -> (
Blend[{Green, Red}, Rescale[spins[[1 + Round[#1*(-1 + Length@xRange)]]], {-1, 1}]] &)]


I am not too familiar with the mechanisms behind the ListLinePlot function, so there could be some errors. However, this does give the desired result.

#1 runs from 0 to 1 in Length@xRange-many steps twice. If you write Echo[#1] in my function above, you see what I mean. There will be two sequences from 0 to 1. I do not know the purpose of the second sequence.

The trick here is to just map these steps on the indices of xRange or spins (since both have the same length) via a multiplication. Round is necessary to make the index an integer.

If one chooses ColorFunctionScaling -> False (natively, it is true), #1 takes all values of xRange. However, I found it easier to work with scaling on.

This could be a start, using the made up functions you suggested. I am using red and green as the two colors to mix to highlight the differences (red and blue was not very visible).

ClearAll[energy, spin]
energy[x_] := Cos[x]
spin[x_] := Sin[x]

Plot[
energy[x], {x, -2 Pi, 2 Pi},
ColorFunctionScaling -> False,
ColorFunction -> (Blend[{Red, Green}, Rescale[spin[#2], {-1, 1}]] &)
]


• Thank you! I have managed to make your function take its values from a list. Since I should probably say something about it, I will post it as a separate answer.
– Fred
Commented Jun 3, 2020 at 9:56
• @Fred Great! Glad it helped! Commented Jun 3, 2020 at 13:43