views:

382

answers:

2

I've encountered a problem while trying to use the answer from a NDSolve in two separate plot commands. To illustrate the problem, I'll use a simple differential equation and only one plot command. If I write something like this:

{Plot[x[t], {t, 0, 10}], x[4]} 
/. NDSolve[{x'[s] == - x[s], x[0] == 1}, x, {s, 0, 10}]

It solves the equation and calculates x[4] with no problem, but the plot turns empty, and I have no idea why.

In my actual problem, my equation is a quite complicated system for several functions, and instead of x[4] I draw a parametric plot of the solved functions. I ultimately intend to include all this in a Manipulate statement so I don't want the NDSolve statement to appear more than once (takes too long) and I can't just calculate it in advance (since it has a lot of parameters).


Edit: I would like to clarify and expand my question: What I actually want to do is to include my plotting statement in a Manipulate statement in the following way:

Manipulate[{Plot[x[t], {t, 0, 10}], x[4]} 
/. NDSolve[{x'[s] == - a*x[s], x[0] == 1}, x, {s, 0, 10}]
,{{a,1},0,5}]

Since only the Manipulate statement gives value to the parameter a, I can't calculate the answer to the NDSolve beforehand. Also, since my actual equation system is very complicated and non-linear, I can't use the symbolic function DSolve.

Sorry if it wasn't clear before.

+5  A: 

Your problem is that Plot[] does some funny things to make plotting more convenient, and one of the things it does is just not plot things it can't evaluate numerically. So in the expression you posted,

Plot[x[t], {t, 0, 10}]

just goes ahead and evaluates before doing the rule substitution with the solution from NDSolve, producing a graphics object of an empty plot. That graphics object contains no reference to x, so there's nothing to substitute for.

You want to make sure the substitution is done before the plotting. If you also want to make sure the substitution can be done in multiple places, you want to store the solution into a variable.

sol = NDSolve[{x'[s] == - x[s], x[0] == 1}, x, {s, 0, 10}];
{Plot[Evaluate[x[t] /. sol], {t, 0, 10}], x[4] /. sol}

The Evaluate[] in the Plot makes sure that Mathematica only does the substitution once, instead of once for each plot point. It's not important for a simple rule substitution like this, but it's a good habit to use it in case you ever want to plot something more complicated.


In order to make this work in a Manipulate, the simple way is to use With[], which is one of Mathematica's scoping constructs; it's the one to use where you just want to substitute something in without using it as variable you can mutate.

For example,

Manipulate[
  With[{sol = NDSolve[{x'[s] == - x[s], x[0] == 1}, x, {s, 0, 10}]},
    {Plot[x[t] /. sol // Evaluate, {t, 0, 10}, PlotRange -> {0, 1}], 
     x[4] /. sol}],
  {{a, 1}, {0, 5}}]

Use the PlotRange option to keep the y-axis fixed; otherwise things will jump around in an ugly way as the value of a changes. When you do more complex things with Manipulate, there are a number of options for controlling the speed of updates, which can be important if your ODE is complicated enough that it takes a while to solve.

Pillsy
+1  A: 

Meanwhile, I found another way to do this. It's less elegant, but it only uses one substitution so I've thought I'll post it here also.

The idea is to use Hold on the Plot so it wouldn't get evaluated, do the rule substitution and then ReleaseHold, just before the Manipulate.

Manipulate[ReleaseHold[
  Hold[ {Plot[x[t], {t, 0, 10}, PlotRange -> {0, 1}], x[4]} ]
 /.NDSolve[{x'[s] == -a x[s], x[0] == 1}, x, {s, 0, 10}]
], {{a, 1}, 0, 5}]
Yuval Elhanati