3
$\begingroup$

If I write this:

sol = NDSolveValue[{f'[t] == (0.4 - 0.01 s[t]) f[t], 
    s'[t] == (-0.3 + 0.005 f[t]) s[t], f[0] == 40, s[0] == 20}, {f[t],
     s[t]}, {t, 0, 80}];
r[t_] = sol;

Then do this:

Manipulate[
 Show[ParametricPlot[sol, {t, 0, 80},
   PlotRange -> {{0, 140}, {0, 100}}],
  Graphics[{Red, Arrow[{{0, 0}, r[tau]}], 
    Arrow[{r[tau], r[tau] + r'[tau]}]}]
  ],
 {{tau, 0}, 0, 80}]

I get a nice Manipulate I can use for a classroom demonstration.

enter image description here

However, if I later use the sol variable to draw another image (a Plot, a ParametricPlot), the new sol value interferes with the Manipulate demonstration. For example, if the next cell in the notebook has:

sol = NDSolveValue[{x'[t] == y[t], y[t] == -x[t], x[0] == 1, 
   y[0] == -1}, {x[t], y[t]}, {t, 0, 5}]

Then this version of sol is now used in the Manipulate demonstration above. So, I tried the following:

Manipulate[Module[{sol, r},
  sol = NDSolveValue[{f'[t] == (0.4 - 0.01 s[t]) f[t], 
     s'[t] == (-0.3 + 0.005 f[t]) s[t], f[0] == 40, 
     s[0] == 20}, {f[t], s[t]}, {t, 0, 80}];
  r[t_] = sol;
  Show[ParametricPlot[sol, {t, 0, 80},
    PlotRange -> {{0, 140}, {0, 100}}],
   Graphics[{Red, Arrow[{{0, 0}, r[tau]}], 
     Arrow[{r[tau], r[tau] + r'[tau]}]}]
   ]],
 {{tau, 0}, 0, 80}]

But it doesn't work. I get an error that I just cannot understand.

Coordinate {InterpolatingFunction[{{0., 80.}}, {5, 7, 1, {353}, {4}, 0, 0, 0, 0, Automatic, {}, {}, False}, {{0., 0.0005236906903058783, 0.0010473813806117565, 0.002094762761223513, 0.0031421441418352696, 0.004189525522447026, 0.014663339328564591`, 0.02513715313 should be a pair of numbers, or a Scaled or Offset form.

Any thoughts?

Sjoerd C. de Vries suggestion in comments:

Module[{sol, r}, 
 Manipulate[
  sol = NDSolveValue[{f'[t] == (0.4 - 0.01 s[t]) f[t], 
     s'[t] == (-0.3 + 0.005 f[t]) s[t], f[0] == 40, 
     s[0] == 20}, {f[t], s[t]}, {t, 0, 80}];
  r[t_] = sol;
  Show[ParametricPlot[sol, {t, 0, 80}, 
    PlotRange -> {{0, 140}, {0, 100}}], 
   Graphics[{Red, Arrow[{{0, 0}, r[tau]}], 
     Arrow[{r[tau], r[tau] + r'[tau]}]}]], {{tau, 0}, 0, 80}]]

Still gives the error:

Coordinate {InterpolatingFunction[{{0., 80.}}, {5, 7, 1, {353}, {4}, 0, 0, 0, 0, Automatic, {}, {}, False}, {{0., 0.0005236906903058783, 0.0010473813806117565, 0.002094762761223513, 0.0031421441418352696, 0.004189525522447026, 0.014663339328564591`, 0.02513715313 should be a pair of numbers, or a Scaled or Offset form.

Michael E2: If I run Michael E2 suggestion it works.

Clear[r];
sol = First@
   NDSolve[{r'[
       t] == ({0.4, -0.3} + {{0, -0.01}, {0.005, 0}}.r[t]) r[t], 
     r[0] == {40, 20}}, r, {t, 0, 80}];
With[{sol = sol}, 
 Manipulate[
  Show[ParametricPlot[r[t] /. sol, {t, 0, 80}, 
    PlotRange -> {{0, 140}, {0, 100}}], 
   Graphics[{Red, Arrow[{{0, 0}, r[tau]}], 
      Arrow[{r[tau], r[tau] + r'[tau]}]} /. sol]], {{tau, 0}, 0, 80}]]

enter image description here

Then if sol gets changed in the global workspace, it doesn't affect Michaels first graph. Note there are very minor changes.

sol = First@
   NDSolve[{r'[
       t] == ({0.4, -0.3} + {{0, -0.01}, {0.002, 0}}.r[t]) r[t], 
     r[0] == {40, 20}}, r, {t, 0, 80}];
With[{sol = sol}, 
 Manipulate[
  Show[ParametricPlot[r[t] /. sol, {t, 0, 80}, 
    PlotRange -> {{0, 140}, {0, 100}}], 
   Graphics[{Red, Arrow[{{0, 0}, r[tau]}], 
      Arrow[{r[tau], r[tau] + r'[tau]}]} /. sol]], {{tau, 0}, 0, 80}]]

Which gives this graph, but doesn't change the first graph.

enter image description here

However, if I now run m_goldberg's script, with slight numerical changes.

Manipulate[
 Show[ParametricPlot[r[t], {t, 0, 80}, 
   PlotRange -> {{0, 140}, {0, 100}}], 
  Graphics[{Red, Arrow[{{0, 0}, r[tau]}], 
    Arrow[{r[tau], r[tau] + r'[tau]}]}]], {{tau, 0}, 0, 80}, 
 Initialization :> (r =.; 
   r[t_] = NDSolveValue[{f'[t] == (0.4 - 0.001 s[t]) f[t], 
      s'[t] == (-0.3 + 0.05 f[t]) s[t], f[0] == 40, 
      s[0] == 20}, {f[t], s[t]}, {t, 0, 80}])]

Then all three images look like this:

enter image description here

Moreover, if I go back to the first image and try to run the code again, I get this error:

ReplaceAll::reps: {False,True} is neither a list of replacement rules nor a valid dispatch table, and so cannot be used for replacing. >>

ReplaceAll::reps: {False,True} is neither a list of replacement rules nor a valid dispatch table, and so cannot be used for replacing. >>

ReplaceAll::reps: {False,True} is neither a list of replacement rules nor a valid dispatch table, and so cannot be used for replacing. >>

General::stop: Further output of ReplaceAll::reps will be suppressed during this calculation. >>

Which can be fixed if I Clear[r].

So, still having problems with more than one Manipulate in one notebook.

$\endgroup$
  • $\begingroup$ Put the Module outside of the manipulate (let it surround it). Better yet, use DynamicModule instead. $\endgroup$ – Sjoerd C. de Vries Mar 29 '15 at 20:51
  • $\begingroup$ I think I did try that (see my edit above), but I still could not get it to work. Replacing Module with Dynamic Module doesn't work either. Some strange other thing is going on? $\endgroup$ – David Mar 29 '15 at 22:44
  • $\begingroup$ Hint: for the understanding of the error message, the list of reals in the error message should be a pair of numbers refers to the result of r[tau] that used within the Graphics function. It looks like if r[tau] does not return a pair of numbers, when sol is defined as a local variable using the Module construct. Sorry I don't have solution but this for clarifying the meaning of the error. $\endgroup$ – penguin77 Mar 30 '15 at 1:01
4
$\begingroup$

You should not wrap a Manipulate expression with Module. Read the comments to this question to learn why. You can fix your problem by clearing r and making a definition of r[t] in the initialization section of your Manipulate expression. Like so:

r = 42;
Manipulate[
  Show[
    ParametricPlot[r[t], {t, 0, 80}, PlotRange -> {{0, 140}, {0, 100}}], 
    Graphics[{Red, Arrow[{{0, 0}, r[tau]}], 
                Arrow[{r[tau], r[tau] + r'[tau]}]}]],
  {{tau, 0}, 0, 80},
  {r, None},
  Initialization :> (
    r =.;
    r[t_] = 
      NDSolveValue[{
        f'[t] == (0.4 - 0.01 s[t]) f[t], s'[t] == (-0.3 + 0.005 f[t]) s[t], 
        f[0] == 40, s[0] == 20}, 
        {f[t], s[t]}, {t, 0, 80}])]

demo

| improve this answer | |
$\endgroup$
  • $\begingroup$ OK, this one does NOT work. To see what I am talking about, create a notebook file and enter your code and run it. Then add the following code after your first Manipulate demo, run it, and you will see it changes the plot in both demos. My comment is too long, so I will put the code in a second comment. $\endgroup$ – David Mar 30 '15 at 3:05
  • $\begingroup$ Manipulate[ Show[ParametricPlot[r[t], {t, 0, 80}, PlotRange -> {{0, 140}, {0, 100}}], Graphics[{Red, Arrow[{{0, 0}, r[tau]}], Arrow[{r[tau], r[tau] + r'[tau]}]}]], {{tau, 0}, 0, 80}, Initialization :> (r =.; r[t_] = NDSolveValue[{f'[t] == (0.4 - 0.001 s[t]) f[t], s'[t] == (-0.3 + 0.05 f[t]) s[t], f[0] == 40, s[0] == 20}, {f[t], s[t]}, {t, 0, 80}])] $\endgroup$ – David Mar 30 '15 at 3:05
  • $\begingroup$ @David. Sorry, I forgot to localize the variable r. I have edited my answer to fix the omission by adding the control definition {r, None} $\endgroup$ – m_goldberg Mar 30 '15 at 6:41
  • $\begingroup$ Thanks for that link and comments of John Fultz. $\endgroup$ – Kuba Mar 30 '15 at 6:59
  • $\begingroup$ @m_goldberg: Now it is working. I've still got a lot to learn. Thanks. $\endgroup$ – David Mar 31 '15 at 0:42
2
$\begingroup$

I might approach it like this. First I like to use the replacement Rule form of NDSolve. Since the solution is used as a vector, it makes sense to have NDSolve return the vector solution r. Using With to inject the solution removes the dependence of the Manipulate on an external symbol. Then sol can be reused without affecting this Manipulate. For increased security, replace all the r by \[FormalR].

sol = First@NDSolve[{
  r'[t] == ({0.4, -0.3} + {{0, -0.01}, {0.005, 0}}.r[t]) r[t], r[0] == {40, 20}},
  r, {t, 0, 80}];
With[{sol = sol}, 
 Manipulate[
  Show[
   ParametricPlot[r[t] /. sol, {t, 0, 80}, PlotRange -> {{0, 140}, {0, 100}}], 
   Graphics[{Red, Arrow[{{0, 0}, r[tau]}], Arrow[{r[tau], r[tau] + r'[tau]}]} /. sol]
  ],
  {{tau, 0}, 0, 80}]
 ]
| improve this answer | |
$\endgroup$
  • $\begingroup$ @Micheal E2: Ok, that worked. And so did this: sol = NDSolveValue[{r'[ t] == ({0.4, -0.3} + {{0, -0.01}, {0.005, 0}}.r[t]) r[t], r[0] == {40, 20}}, r, {t, 0, 80}]; With[{sol = sol}, Manipulate[ Show[ParametricPlot[sol[t], {t, 0, 80}, PlotRange -> {{0, 140}, {0, 100}}], Graphics[{Red, Arrow[{{0, 0}, sol[t]}], Arrow[{sol[t], sol[t] + sol'[t]}]}]], {{t, 0}, 0, 80}]] $\endgroup$ – David Mar 30 '15 at 2:57
  • $\begingroup$ @Micheal E2: I understood everything you did except the With[{sol=sol}, part. Why does that work? I am not understanding why that protect an outer sol from coming in and ruining the Manipulate demo. $\endgroup$ – David Mar 30 '15 at 2:58
  • $\begingroup$ Still having some problems. See my edits in the original post question. $\endgroup$ – David Mar 30 '15 at 5:34
  • $\begingroup$ @David With replaces the symbols defined with their values before the body is evaluated. It is as if the symbols are not really created inside the kernel; more precisely, the code that Manipulate sees does not have the symbol sol in it. For whatever reason, you can reuse symbol names (With[{x = x},...]). See 559 for more. -- I'm not sure what problem you're having. Is it the PlotRange when the parameters of the ODE are changed? If you don't need to save sol for use outside Manipulate, try With[{sol = First@NDSolve[... $\endgroup$ – Michael E2 Mar 30 '15 at 10:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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