0
$\begingroup$

Part of this recent question involves coloring a ParametricPlot3D of three variables from a set of ODEs according to a fourth variable. I just figured out how to do that using the slot #4, but ColorFunctionScaling->True doesn't seem to behave properly.

First, solve the ODEs:

nsp = 4;

{r[1], r[2], r[3], r[4]} = {1, 0.72, 1.53, 1.27};
{k[1], k[2], k[3], k[4]} = {1, 1, 1, 1};
amat = {{1, 1.09, 1.52, 0}, {0, 1, 0.44, 1.36}, {2.33, 0, 1, 0.47}, {1.21, 0.51, 0.35, 1}};
Do[a[i, j] = amat[[i, j]], {i, nsp}, {j, nsp}];

eqns = Table[x[i]'[t] ==
  r[i]*x[i][t]*(1 - Sum[a[i, j]*x[j][t]/k[i], {j, nsp}]), {i, nsp}];
ics = Table[x[i][0] == 0.1, {i, nsp}];
unks = Table[x[i], {i, nsp}];

tmax = 10000;
sol = NDSolve[{eqns, ics}, unks, {t, 0, tmax}][[1]];

It looks good with ColorFunctionScaling->False:

ParametricPlot3D[Evaluate[{x[1][t], x[2][t], x[3][t]} /. sol], {t, 100, tmax}, 
  AxesLabel -> {"x1", "x2", "x3"}, PlotPoints -> 400, 
  ColorFunction -> (ColorData["SunsetColors", x[4][#4] /. sol] &), 
  ColorFunctionScaling -> False]

Mathematica graphics

but totally weird with ColorFunctionScaling->True:

ParametricPlot3D[Evaluate[{x[1][t], x[2][t], x[3][t]} /. sol], {t, 100, tmax}, 
  AxesLabel -> {"x1", "x2", "x3"}, PlotPoints -> 400, 
  ColorFunction -> (ColorData["SunsetColors", x[4][#4] /. sol] &), 
  ColorFunctionScaling -> True]

Mathematica graphics

We can see what it should look like by manually applying our own scaling directly to the ColorFunction:

max = NMaximize[{x[4][t] /. sol, 0 < t < tmax}, t, Method -> "RandomSearch"][[1]];
min = NMinimize[{x[4][t] /. sol, 0 < t < tmax}, t, Method -> "RandomSearch"][[1]];

ParametricPlot3D[Evaluate[{x[1][t], x[2][t], x[3][t]} /. sol], {t, 100, tmax}, 
  AxesLabel -> {"x1", "x2", "x3"}, PlotPoints -> 400, 
  ColorFunction -> (ColorData["SunsetColors", (x[4][#4] - min)/(max - min) /. sol] &), 
  ColorFunctionScaling -> False]

Mathematica graphics

Bug or user error? :) v11.1 on MacOS.

$\endgroup$
4
  • 1
    $\begingroup$ "...but totally weird with ColorFunctionScaling -> True" - not really; per the docs, values rescaled to $[0, 1]$ are what get fed to the ColorFunction, instead of values in $[100,10000]$. $\endgroup$ Apr 19, 2017 at 0:23
  • $\begingroup$ @J.M. I expected the x[4][#4] /. sol would be scaled to $[0,1]$ not the #4, to match my last graph. ?? $\endgroup$
    – Chris K
    Apr 19, 2017 at 0:40
  • 1
    $\begingroup$ You'd think that, but indeed it is the t-values (#4) that get scaled. To convince yourself, try catching the values being used: ColorFunction -> ((Echo[#4]; ColorData["SunsetColors", x[4][#4] /. sol]) &) $\endgroup$ Apr 19, 2017 at 1:03
  • $\begingroup$ @J.M. So "user error" it is -- although I'd maintain that this is a weird design choice. Thanks for clearing this up. $\endgroup$
    – Chris K
    Apr 19, 2017 at 2:11

1 Answer 1

1
$\begingroup$

Here is a simpler, but hopefully equally illustrative example:

{ParametricPlot3D[{Cos[t], Sin[t], 0}, {t, 0, 2 π}, 
                  ColorFunction -> (Hue[#4] &), ColorFunctionScaling -> True, 
                  PlotLabel -> "w/ scaling"], 
 ParametricPlot3D[{Cos[t], Sin[t], 0}, {t, 0, 2 π}, 
                  ColorFunction -> (Hue[#4] &), ColorFunctionScaling -> False, 
                  PlotLabel -> "w/o scaling"]} // GraphicsRow

circles colored with and without scaling

Recalling that Hue[] is $1$-periodic, note that the circle on the left is colored by the color wheel exactly once, corresponding to an internal rescaling of the parameter to $[0,1]$, which is, coincidentally, Hue[]'s primary domain. The figure on the right, however, feeds the unscaled ($[0,2\pi]$) parameter values to Hue[], and this is manifested in the repeated bands of color.

$\endgroup$
1
  • $\begingroup$ Thanks! My naive thought was that ColorFunctionScaling would scale according to whatever function #4 is wrapped in (in my case x[4][#4]/.sol). Now I see that it would be ambiguous what exactly the proper function to scale by would be, so its better to just do it manually. $\endgroup$
    – Chris K
    Apr 20, 2017 at 16:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.