# ColorFunctionScaling with ParametricPlot3D & InterpolatingFunctions

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, r, r, r} = {1, 0.72, 1.53, 1.27};
{k, k, k, k} = {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.1, {i, nsp}];
unks = Table[x[i], {i, nsp}];

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


It looks good with ColorFunctionScaling->False:

ParametricPlot3D[Evaluate[{x[t], x[t], x[t]} /. sol], {t, 100, tmax},
AxesLabel -> {"x1", "x2", "x3"}, PlotPoints -> 400,
ColorFunction -> (ColorData["SunsetColors", x[#4] /. sol] &),
ColorFunctionScaling -> False] but totally weird with ColorFunctionScaling->True:

ParametricPlot3D[Evaluate[{x[t], x[t], x[t]} /. sol], {t, 100, tmax},
AxesLabel -> {"x1", "x2", "x3"}, PlotPoints -> 400,
ColorFunction -> (ColorData["SunsetColors", x[#4] /. sol] &),
ColorFunctionScaling -> True] We can see what it should look like by manually applying our own scaling directly to the ColorFunction:

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

ParametricPlot3D[Evaluate[{x[t], x[t], x[t]} /. sol], {t, 100, tmax},
AxesLabel -> {"x1", "x2", "x3"}, PlotPoints -> 400,
ColorFunction -> (ColorData["SunsetColors", (x[#4] - min)/(max - min) /. sol] &),
ColorFunctionScaling -> False] Bug or user error? :) v11.1 on MacOS.

• "...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]$. – J. M. will be back soon Apr 19 '17 at 0:23
• @J.M. I expected the x[#4] /. sol would be scaled to $[0,1]$ not the #4, to match my last graph. ?? – Chris K Apr 19 '17 at 0:40
• 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] /. sol]) &) – J. M. will be back soon Apr 19 '17 at 1:03
• @J.M. So "user error" it is -- although I'd maintain that this is a weird design choice. Thanks for clearing this up. – Chris K Apr 19 '17 at 2:11

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 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.

• Thanks! My naive thought was that ColorFunctionScaling would scale according to whatever function #4 is wrapped in (in my case x[#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. – Chris K Apr 20 '17 at 16:01