# mixing color of individual parts of a function in DensityPlot

I have a function which is a sum of three terms and I want to plot it in a DensityPlot. However, I would like that the ColorFunction would be the RGBColor resulting of the mixed R color corresponding to first term, G color of the second term and B color of the third term. I think that my problem is similar to that of combine RGB channels of a RGB image, but applied to an addition of three functions in a DensityPlot.

Any idea will be welcome. I have tried several things. However, as expected, I always could change only the color of the whole function as a function of z.

Jose

• Use Blend in your ColorFunction. – David G. Stork Mar 12 '15 at 18:47
• @DavidG.Stork mathematica does not inject the coordinates into the ColorFunction. Only the function value, and that is not enough for what the OP wants to achieve – Dr. belisarius Mar 12 '15 at 19:01

Here is an example of how to do it:

f[x_, y_] := {Sin[x], Cos[y], Sin[2 x + y]}

Block[{x, y, h, xMin = -1, xMax = 3, yMin = -3, yMax = 3},
Graphics[{}, PlotRange -> {{xMin, xMax}, {yMin, yMax}},
Epilog -> Inset[Show[ColorCombine[Table[Image[
DensityPlot[f[x, y][[i]], {x, xMin, xMax}, {y, yMin, yMax},
Frame -> None, ImageMargins -> 0, PlotRangePadding -> None,
ColorFunction -> GrayLevel, ColorFunctionScaling -> None],
ColorSpace -> "Grayscale"], {i, 3}], "RGB"],
AspectRatio -> Full], {xMin, yMin}, {0, 0},
{xMax - xMin, yMax - yMin}], Frame -> True, PlotRangePadding -> .08]] The main ingredient is to do the three function components as separate DensityPlots, then apply ColorCombine to them, and insert the resulting Image into a Graphics frame with the same coordinate range as the original function.

For the last part, I use Inset with its three optional arguments to insure the correct positioning and stretching. The stretching to the correct aspect ratio only works if I first apply Show with the option AspectRatio -> Full to the image that is to be inserted.

I also added ColorFunctionScaling->None to DensityPlot so that you have control over the maximum and minimum ranges of your color channels. In the table of DensityPlots, the color channel is first populated by GrayScale only. The colors are created by ColorCombine, but this only works for images with the colorspace specification "Grayscale".

• I expected a gray scale from black to white for f[x_, y_] := {Sin[x], Sin@x, Sin@x}. It seems I have scaling issues. – Dr. belisarius Mar 12 '15 at 20:51
• @belisarius Oh, yes - I messed up the use of ColorCombine. Let me fix it. Next time, I should look at the documentation before answering... – Jens Mar 12 '15 at 21:57
• I just tried this code and got multiple errors of the type: Image::imgcsmsw: The specified color space GrayLevel and the number of channels 3 are not compatible; using Automatic instead. >> – Mr.Wizard Mar 13 '15 at 1:03
• @Mr.Wizard it must be something in version 10 - I have version 8 right now and it works. I'll look at it when I can test in version 10... later today, I hope. – Jens Mar 13 '15 at 1:11
• @Mr.Wizard Seems like Mathematica is trying to remove gray areas from its syntax for grey areas. – Jens Mar 13 '15 at 1:27

A possible alternative to DensityPlot is to render an Image:

(* kguler's example function *)
f[x_, y_] := {Sin[x] Sin[y], Sin[3 x] Cos[2 y], Cos[y/Pi] Sin[x + y]}

Array[f, {100, 100}, {{-2 Pi, 2 Pi}, {-2 Pi, 2 Pi}}] // Transpose // Reverse //
Rescale // Image // ImageResize[#, 300] & Here is a self-contained function that evaluates a function and plots it as a Raster, complete with axes:

plotAsRaster[
fn_,
points : {_, _} : {100, 100},
ranges : {{_, _}, {_, _}},
opts : OptionsPattern[Graphics]
] :=
Graphics[
Raster[Rescale@Array[fn, points, ranges]\[Transpose], ranges\[Transpose]],
opts, Frame -> True, AspectRatio -> 1
]


Test:

plotAsRaster[f, {{-2 Pi, 2 Pi}, {-2 Pi, 2 Pi}}] (This is not intended to be a well developed function but merely a proof of concept.)

A modification with interpolation:

plotAsRasterInterpolated[fn_, points : {_, _} : {100, 100}, ranges : {{_, _}, {_, _}},
opts : OptionsPattern[Graphics]] :=
Graphics[Raster[
ImageData@ImageResize[Image[Rescale@Array[fn, points, ranges]\[Transpose]], 3 points],
ranges\[Transpose]], opts, Frame -> True, AspectRatio -> 1, ImageSize -> 3 points]

• Basically, that is what I did. However, I am also interested in showing the axes for more information about the plot content. – José Antonio Díaz Navas Mar 13 '15 at 7:51
• @José Please see my update. I did not include interpolation in this example but if you find the idea otherwise pleasing I can include it. – Mr.Wizard Mar 13 '15 at 8:16
• Nice solution. However, why as "raster"? It looses resolution. The alternative as Inset in Graphics seems to be good. – José Antonio Díaz Navas Mar 17 '15 at 12:42
• @José It doesn't actually lose resolution, but it doesn't gain (apparent) resolution because I did not include interpolation. If that is included it will look smoother. I shall add an example to my answer. – Mr.Wizard Mar 18 '15 at 13:17
ClearAll[f]
f[x_, y_] := {Sin[x] Sin[y], Sin[3 x] Cos[2 y], Cos[y/Pi] Sin[ x + y]}

dp = DensityPlot[Plus @@ f[x, y], {x, -2 Pi, 2 Pi}, {y, -2 Pi, 2 Pi},
Frame -> False, ImageSize -> 300] dps = DensityPlot[f[x, y][[#]], {x, -2 Pi, 2 Pi}, {y, -2 Pi, 2 Pi},
Frame -> False, ImageSize -> 300,
ColorFunction -> (Function[{c}, RGBColor@RotateRight[{c, 0, 0}, # - 1]])] & /@ Range;
Row@dps Fold[ImageAdd, dps]  (* thanks: Mr. Wizard *)
(* Fold[ImageAdd, First@dps, Rest@dps] in case the two-args version doesn't work *) • Your last line of code may be replaced with Fold[ImageAdd, dps] according to (54784). – Mr.Wizard Mar 13 '15 at 1:02
• Thank you @Mr.Wizard - how quickly i forget:) – kglr Mar 13 '15 at 4:33