# 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. Mar 12, 2015 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 Mar 12, 2015 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. Mar 12, 2015 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, 2015 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. >> Mar 13, 2015 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, 2015 at 1:11
• @Mr.Wizard Seems like Mathematica is trying to remove gray areas from its syntax for grey areas.
– Jens
Mar 13, 2015 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. Mar 13, 2015 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. Mar 13, 2015 at 8:16
• Nice solution. However, why as "raster"? It looses resolution. The alternative as Inset in Graphics seems to be good. Mar 17, 2015 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. Mar 18, 2015 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[3];
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). Mar 13, 2015 at 1:02
• Thank you @Mr.Wizard - how quickly i forget:)
– kglr
Mar 13, 2015 at 4:33