8
$\begingroup$

I want to implement start-stop dynamics within a Manipulate environment so that, when I click a "Start" button, the simulation starts, and when I click the "Stop" button, it stops. For a simple function f that only yields a pause, the following code does what I want

Manipulate[update;
 Which[
  run == 0, frame = "Ready to start",
  run == 1, frame = "Simulating..."; run = 2; update = 1 - update,
  run == 2, f[2]; run = 3; update = 1 - update,
  run == 3, frame = "Done"];
 frame,
 Dynamic@If[run == 0 || run == 3,
   Button["Start", run = 1; update = 1 - update],
   Button["Stop", FrontEndTokenExecute["EvaluatorAbort"]; run = 0; 
    update = 1 - update]],
 {{update, 0}, ControlType -> None},
 TrackedSymbols :> {update},
 Initialization :> (run = 0; f = Function[x, Pause[5]]), 
 ControlPlacement -> Left]

enter image description here

However, when f is more complex (for example solving a huge system of ODEs) this approach doesn't always work. That is, FrontEndTokenExecute["EvaluatorAbort"] is evaluated, but the content doesn't change back to the original idle frame. All computations are aborted and the buttons are no longer enabled. Any ideas on how to improve this?

I also suspect there must be an easier of doing this. I'd like to keep Manipulate as my main dynamic tool. Could DynamicModule facilitate this somehow? What I'm really looking for is full control of the evaluation within Manipulate, independently of how complex f is.

$\endgroup$
2
  • 1
    $\begingroup$ "It doesn't always work" because: Sometimes the variable "update" exceeds the recursion limit. Message: RecursionLimit::reclim2: Recursion depth of 1024 exceeded during evaluation of -update. $\endgroup$
    – hieron
    Aug 7 at 12:59
  • $\begingroup$ @hieron I couldn't post my example here as it is indeed a very long function, but thanks for the example! In my case I actually don't get any message, the cell simply stops being evaluated and the placeholder "Simulating..." text remains. Any ideas on how to solve this? $\endgroup$
    – sam wolfe
    Aug 10 at 19:03
3
$\begingroup$

Here is a second variant using CheckAbort (little bit shorter):

Manipulate[While[update, frame = "Simulating..."; frame = CheckAbort[
    simulate@3; update = False; "Done",
    update = False; "Ready for start"]
  ]; Dynamic@frame,
 
 Dynamic@Button[
   PaneSelector[{True -> "Stop", False -> "Start"}, Dynamic@update], 
   If[update, FrontEndTokenExecute@"EvaluatorAbort", update = True]],
 
 {{update, False}, {True, False}, ControlType -> None},
 Initialization :> {frame = "Ready for start", 
   simulate[s_] := Pause@s},
 ControlPlacement -> Left, ContentSize -> 150]
$\endgroup$
2
$\begingroup$

Tested under: "11 and 12.1.1 for Microsoft Windows (64-bit) (June 19, 2020)".
Seems ok now. For your old version: To find out, if you exceed the recursion limit, you just remove "ControlType->None" in update, then the message will appear, as soon as recursion limit exceeds.

Manipulate[
 While[update,
  Which[
   run == 0, frame = "Ready to start",
   run == 1, frame = "Simulating..."; simulate@3; run = 2,
   run == 2, update = False; frame = "Done"
   ]]; Dynamic@frame,
 
 Dynamic@If[run == 0 || run == 2, 
   Button["Start", run = 1; update = True],
   Button["Stop", run = 0; update = False; frame = "Ready to start";
    FrontEndTokenExecute@"EvaluatorAbort"]],
 
 {{update, False}, {True, False}, ControlType -> None},
 TrackedSymbols :> {update},
 Initialization :> {run = 0, frame = "Ready to start", 
   simulate[x_] := Pause[x]},
 ControlPlacement -> Left, ContentSize -> 150]
$\endgroup$

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.