# ColorFunction based on data

I have a list of numbers, and I would like to plot them using ArrayPlot (which is easy, usually :)). I would like to be able to color the elements of the plot based on the average of the list: one color if the number is above average, another if it is below. I have tried a couple of things, but so far, no joy.

First thing I tried is have a module around the colorFun defined by me and the ArrayPlot, to calculate the mean, since I don't want it to be kernel-wide (many other plots will come with the same technique), and then define, inside the module, the colorFun:

  Module[
{a, mean, colorFun},
a = RandomInteger[{0, 100}, 100];
mean = Mean[a];
colorFun[z_] := If[z <= mean, Red, Blue];
ArrayPlot[List@a, ImageSize -> Full, ColorFunction -> colorFun]
]


but this didn't work, since the plot would return all in the same color. It's actually not clear to me why.

I also tried to move colorFun in the form:

colorFun[z_]=RGBColor[{ , , }]


with 2 functions of z and mean for two elements and 0 for the third. The idea of using this approach instead of the if is that I could blend the colors (the further from the average, the more intense/bright the color I am plotting with).

Any ideas?

Thanks!

-
You need ColorFunctionScaling -> False... – PlatoManiac Apr 23 '13 at 10:33
...or rewrite colorFun[] so that it takes arguments in the interval $[0,1]$. – J. M. Apr 23 '13 at 10:42
Possible duplicate of Use ColorFunction in ListLinePlot with If – MarcoB May 23 at 15:03

For concreteness, here's how one might do Plato's suggestion:

Module[{a, mid, colorFun},
BlockRandom[SeedRandom[42]; (* for reproducibility *)
a = RandomInteger[{0, 100}, 100]];
mid = Mean[a];
colorFun[z_] := If[z <= mid, Red, Blue];
ArrayPlot[{a}, ColorFunction -> colorFun, ColorFunctionScaling -> False]]


To demonstrate the approach I proposed, I'll use it to implement your more fine-grained idea to have the color's intensity proportional to its distance from the mean, using Blend[]:

Module[{a, hi, lo, mid, colorFun},
BlockRandom[SeedRandom[42];
a = RandomInteger[{0, 100}, 100]];
{lo, mid, hi} = Through[{Min, Mean, Max}[a]];
colorFun[z_] := Blend[{{0, Red}, {Rescale[mid, {lo, hi}], White}, {1, Blue}}, z];
ArrayPlot[{a}, ColorFunction -> colorFun]]


-
Thanks! This providers a better scaling than my version. – mgm Apr 23 '13 at 11:12

I am now using this as a color function:

colorFun[z_] := Blend[{Red, Darker@Green}, (z - 1)/mean];


and it's working more or less fine. Please, never mind the noise, but maybe it will be useful for somebody else.

Also I am using, as suggested by PlatoManiac, ColorFunctionScaling -> False.

-