2
$\begingroup$

Consider the following toy example:

sol = NDSolve[{
    x'[t] == {-1, -2} x[t],
    x[0] == {2, 2}
    },
   x, {t, 0, 4}
   ];
Plot[x[t] /. sol, {t, 0, 4}, PlotRange -> All]

enter image description here

As seen above, both plots are drawn in the same colour.

The usual trick of adding Evaluate does not work here, I guess because x[t] /. sol evaluates to a list with a single element:

enter image description here

and it's the InterpolatingFunction that later evaluates to a list.

Manually specifying the PlotStyle also doesn't seem to work.

How can I ensure that the different plots are assigned different colours/styles?

$\endgroup$

4 Answers 4

2
$\begingroup$

I would use Indexed:

sol = NDSolveValue[
    {x'[t] == {-1, -2} x[t], x[0] == {2, 2}},
    x,
    {t, 0, 4}
];

Plot[Evaluate @ Table[Indexed[sol[t], i], {i,2}], {t, 0, 4}]

enter image description here

$\endgroup$
3
$\begingroup$

I just found that this is covered in this answer, which I previously missed.

The trick is to use ListLinePlot, which seems handle InterpolatingFunctions better:

sol = NDSolve[{
    x'[t] == {-1, -2} x[t],
    x[0] == {2, 2}
    },
   x, {t, 0, 4}
   ];
ListLinePlot[x /. First@sol // Flatten]

gives

enter image description here

$\endgroup$
3
$\begingroup$

If Plot is necessary, the only solution in my mind is rebuilding the InterpolatingFunction. I've modified the definition of ODE a bit because x'[t] == {-1, -2} x[t] is not valid in v9.0.1.

Clear@times;
times[a_, b_?VectorQ] := a b
(* Alternatively: *)
(*
times = Compile[{{a, _Real, 1}, {b, _Real, 1}}, a b, 
  RuntimeOptions -> EvaluateSymbolically -> False]
 *)

sol = NDSolveValue[{x'[t] == {-1, -2}~times~x[t], x[0] == {2, 2}}, x, {t, 0, 4}]

sollst = ListInterpolation[#, sol[Coordinates][[1]]] & /@ Transpose@sol[ValuesOnGrid]

Plot[sollst[t] // Through // Evaluate, {t, 0, 4}, PlotRange -> All]

Mathematica graphics


OK, I happened to recall another solution. We can modify the Graphics instead:

i = 1;
Plot[sol[t], {t, 0, 4}, PlotRange -> All] /. 
 Line[a_] :> Sequence[ColorData[1][i++], Line@a]

But this solution is somewhat hard to control if you need deeper customization for the style.

$\endgroup$
3
$\begingroup$
Clear[sol]

sol[t_] = 
  x[t] /. NDSolve[{x'[t] == {-1, -2} x[t], x[0] == {2, 2}}, 
     x, {t, 0, 4}][[1]];

Plot[{sol[t][[1]], sol[t][[2]]}, {t, 0, 4}, PlotRange -> All,
 PlotLegends -> Placed[Automatic, {0.5, 0.5}]]

enter image description here

$\endgroup$
3
  • $\begingroup$ What if the number of elements of the solution array is not known a priori? Replacing the first argument of plot with something like sol[t][[#]]&/@Range@10 does not work, while Evaluate[sol[t][[#]]&/@Range@10] throws an error because tmp[t] is not a list when t is unevaluated $\endgroup$
    – glS
    Jul 30, 2018 at 17:30
  • $\begingroup$ ok I think I found the solution to that, leveraging the fact that Plot can handle held arguments: something like Evaluate[Hold[tmp[t][[#]]] & /@ Range@10] works $\endgroup$
    – glS
    Jul 30, 2018 at 17:36
  • 1
    $\begingroup$ @glS - If the number of elements is not unknown a priori then you would need to calculate the Range argument on the fly, i.e., Evaluate[Hold[sol[t][[#]]] & /@ Range@Length@sol[1]] $\endgroup$
    – Bob Hanlon
    Jul 30, 2018 at 17:43

Your Answer

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

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