3
$\begingroup$

I wish to carry out a parameter sweep for a certain function in Manipulate, and create a plot for each parameter set.

Each plot of the function takes ~ 10 seconds, so I would like to precompute the plots for a table of parameter sets, then use manipulate to rapidly move between them. The Advanced Manipulate Functionality documentation has suggestions for slow computations, but does not say how to carry out this functionality.

Could you please help me figure out how to do this?

$\endgroup$
1
  • 6
    $\begingroup$ Compute the plots by mapping your function over a list of parameters. This will generate a list of plots ahead of time. Then use Manipulate[listOfPlots[[i]], {i, 1, Length@listOfPlots, 1}] to display the one you want. $\endgroup$
    – MarcoB
    Commented Aug 11, 2022 at 16:52

2 Answers 2

3
$\begingroup$

Working off the comment from @MarcoB, a working answer is as follows: If you wanted to plot $x^2+b$ and manipulate b while following the above, you could use this:

listOfPlots = Table[Plot[x^2 + b, {x, -1, 1}], {b, 1, 9}]
Manipulate[listOfPlots[[i]], {i, 1, Length@listOfPlots, 1}]
$\endgroup$
3
  • 4
    $\begingroup$ +1 If you have listOfPlots on a separate input line and want to re-open the notebook and not have to re-run listOfPlots, including SaveDefinitions -> True in the Manipulate command will save potentially lots of time. $\endgroup$
    – JimB
    Commented Aug 11, 2022 at 20:05
  • 2
    $\begingroup$ The first time I came across SaveDefinitions -> True, I thought, "Great!" and used it all the time. Then experience has taught me to avoid it. One can usually store data in better, transparent ways in which one controls what happens and when. $\endgroup$
    – Michael E2
    Commented Aug 12, 2022 at 13:44
  • $\begingroup$ @MichaelE2 Very good to know! +1 for your detailed answer. $\endgroup$
    – JimB
    Commented Aug 15, 2022 at 15:24
3
$\begingroup$

Some alternatives ideas. Plots, especially 3D plots, can be quite large. The list of plots below are around 165K. Some of the Manipulate cells that store the plots are around 670K. The one with plots in external file are 4-5K, but have to read the data in. These sizes are not large enough to cause problems with the responsiveness of the front end. So it's mainly a question of style. Other advantages of some solutions: automatic initialization of the plots; persistent initialization (no re-initialization needed when Mathematica restarts); localization of variables; shareability.

Save in an external, shareable file

To share, send both the notebook and the file listOfPlots.mx.

DumpSave[FileNameJoin[{NotebookDirectory[], "listOfPlots.mx"}], 
  listOfPlots];

Manipulate[
 If[! ListQ[listOfPlots],
  Get[FileNameJoin[{NotebookDirectory[], "listOfPlots.mx"}]]
  ];
 listOfPlots[[i]],
 {i, 1, Length@LocalSymbol["listOfPlots"], 1}
 ]

Save in an external, local file

Must initialize the local symbol (once!) before Manipulate will work. One could use CloudSymbol[], if one wants a cloud-based solution, which would make the list of plots accessible to other computers.

If[! ListQ[LocalSymbol["listOfPlots"]],
  LocalSymbol["listOfPlots"] = 
   Table[Plot[Cos[b x], {x, -1, 1}], {b, 1, 9}]
  ];

Manipulate[LocalSymbol["listOfPlots"][[i]],
 {i, 1, Length@LocalSymbol["listOfPlots"], 1}
 ]

Local file initialized in Manipulate

The initialization happens only once, after which the Manipulate operates smoothly. One can remove the local symbol first, to check initialization.

(*LocalSymbol["listOfPlots"]//Remove;*)

Manipulate[
 Dynamic[
  If[ListQ@LocalSymbol["listOfPlots"],
   LocalSymbol["listOfPlots"][[i]],
   "please wait"],
  SynchronousUpdating -> True],
 {i, 1, Length@LocalSymbol["listOfPlots"], 1},
 Initialization :> (
   If[! ListQ[LocalSymbol["listOfPlots"]],
     LocalSymbol["listOfPlots"] = 
      Table[Pause[1]; Plot[Cos[b x], {x, -1, 1}], {b, 1, 9}]
     ];),
 SynchronousInitialization -> False
 ]

Gussied up version, with a progress indicator.

Manipulate[
 Dynamic[
  If[ListQ@LocalSymbol["listOfPlots"],
   (*** MAIN BODY ***)
   LocalSymbol["listOfPlots"][[i]]
   (*** END  BODY ***)
   , If[! initializing,
    Button["Click to initialize plots",
     initializing = True;
     LocalSymbol["listOfPlots"] = 
       Table[
        Pause[1]; Plot[Cos[b x], {x, -1, 1}],
        {b, 1, 9}];
     initializing = False,
     Method -> "Queued"
     ],
    Dynamic@Column[{
       Row[{"Computing plot ", b}],
       ProgressIndicator[b/10.]
       }]
    ]],
  SynchronousUpdating -> True],
 (*** VAR DECLARATIONS ***)
 {i, 1, Length@LocalSymbol["listOfPlots"], 1},
 {{initializing, False}, None}, {b, None}
 ]

Plots stored in notebook in Manipulate

The variable listOfPlots is also localized in Manipulate and not a global variable (generally an advantage, unless you need the variable to be accessible both inside and outside Manipulate).

With[{listOfPlots0 = Table[Plot[Cos[b x], {x, -1, 1}], {b, 1, 9}]},
 Manipulate[listOfPlots[[i]],
  {i, 1, Length@listOfPlots, 1},
  {{listOfPlots, listOfPlots0}, None}]
 ]

One can use Iconize, if you "Evaluate in Place" (see Evaluation menu) to convert to an icon.

Manipulate[listOfPlots[[i]],
 {i, 1, Length@listOfPlots, 1},
 {{listOfPlots, Iconize@Table[Plot[Cos[b x], {x, -1, 1}], {b, 1, 9}]},
   None}]
$\endgroup$
1
  • $\begingroup$ One can also store data in a notebook with TaggingRules. For instance, CurrentValue[EvaluationNotebook[], {TaggingRules, "listOfPlots"}] = Table[Pause[1]; Plot[Cos[b x], {x, -1, 1}], {b, 1, 9}] to initialize and CurrentValue[EvaluationNotebook[], {TaggingRules, "listOfPlots"}] to access. $\endgroup$
    – Michael E2
    Commented Aug 17, 2022 at 13:04

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.