9
$\begingroup$

I would like to save current Manipulate parameter values to load them again later. Bookmarks (previously discussed here and here) work fine until the cell is reinitialized. Is it there a way to save a bookmark permanently and restore it at the next Mathematica session?

If not, how could I export a bookmark to a file and import it back? Since the code is huge (more than 80 controls of different types) and constantly evolving, I would like to have it automatized, preferably by a button within the same Manipulate.

Many thanks in advance for any useful hints!

Here is a small toy model to play with:

Manipulate[ 
    Plot[Fun[2 Pi freq x], {x, 0, 2}, 
        Axes -> showAxes,  
        PlotLabel -> If[showPlotLabel, plotLabel, ""]
      ],
    {Fun, {Sin, Cos}},
    {freq, 1, 3},
    Row[{
       Control[{showAxes, {True, False}}],
       Control[{showPlotLabel, {True, False}}]
       }, "\t"],
     {plotLabel, "Plot Label", Enabled -> showPlotLabel}
     ]
$\endgroup$
11
  • $\begingroup$ You can change the output cell to InputForm and see how the manually added bookmarks ended up as Bookmarks option of the Manipulate $\endgroup$
    – Rojo
    Commented Jan 17, 2013 at 16:38
  • $\begingroup$ @Rojo They are under Typeset`bookmarkList$$. But I'm not sure how to get at the context, since Manipulate does some slight of hand with variable localizations... $\endgroup$
    – Ajasja
    Commented Jan 17, 2013 at 20:54
  • $\begingroup$ @Ajasja, I meant the input form, the real mathematica expression that is given as a result, not the boxes. You could extract it simply with Cases["the manipulate", (Bookmarks->b_)->b, Infinity] $\endgroup$
    – Rojo
    Commented Jan 17, 2013 at 21:01
  • 1
    $\begingroup$ LocalizeVariables -> False might help. But I don't think it is necessary. $\endgroup$ Commented Jan 17, 2013 at 21:35
  • 1
    $\begingroup$ @Rojo Well, in this case I'm pretty sure (since I work with Iztok:). The OP would like to have a button inside manipulate to easily save all the manipulate control's values to a file and another button that would load the file back. This is most reminiscent of the Bookmarks mechanism. The real-life use case is that many people will be using a complex manipulate notebook for some experiential analysis. And will probably not appreciate there bookmarks list being deleted on each redeploy (the redeploys will be frequent at the beginning:) $\endgroup$
    – Ajasja
    Commented Jan 17, 2013 at 21:42

5 Answers 5

4
$\begingroup$

After reading some of the comments, I thought I'd post this solution I had done some years ago. It does not work through the Bookmarks. As noted, that requires converting things like FE`a$$712 to $CellContext`a$$ -- someone may know how to do that easily. I suspect it could be done.

The code below accomplishes the same intention as the OP. It saves the current state in a cell, and it can read the cell when the Manipulate is reevaluated. The cell is identified by a tag. If it doesn't exist, one is created at the current insertion point when the "Save" button is clicked.

Drawbacks: You have to define what a state is in the code -- in the example, it's {a, b}, which appears in both the save and reset button/menu actions. That can be inconvenient if in development you add and subtract a lot of variables. One also might wish the cell with the bookmarks was hidden.

SelectCellWithTag[tag_] := 
  If[NotebookFind[EvaluationNotebook[], tag, Next, CellTags, 
     AutoScroll -> False] =!= $Failed, 
   SelectionMove[EvaluationNotebook[], All, CellContents, 
    AutoScroll -> False],
   SelectionMove[EvaluationNotebook[], After, Cell, 
    AutoScroll -> False]; 
   NotebookWrite[EvaluationNotebook[], 
    Cell[BoxData["{}"], "Input", CellTags -> {tag}, 
     ShowCellTags -> True],
    All, AutoScroll -> False];
   SelectionMove[EvaluationNotebook[], All, CellContents, 
    AutoScroll -> False]
   ];
ReadCellContents[] := ToExpression@NotebookRead[EvaluationNotebook[]];

Manipulate[
 a + b,
 {a, 0, 1}, {b, 0, 1},
 {{save, SelectCellWithTag["BOOKMARKS"]; ReadCellContents[]}, 
  Button["Save", SelectCellWithTag["BOOKMARKS"]; 
    NotebookWrite[EvaluationNotebook[], 
     ToBoxes[save = Append[ReadCellContents[], {a, b}]], 
     AutoScroll -> False]] & },
 {reset, ActionMenu["Reset", (#1 :> ({a, b} = #1) & ) /@ save, 
    Appearance -> "PopupMenu"] & },
 SaveDefinitions -> True
 ]

Manipulate output BOOKMARKS cell

Addendum

Combining an idea from @Ajasja with the above, the following perhaps does the trick using bookmarks:

SelectCellWithTag[tag_] := 
  If[NotebookFind[EvaluationNotebook[], tag, Next, CellTags, 
     AutoScroll -> False] =!= $Failed, 
   SelectionMove[EvaluationNotebook[], All, CellContents, 
    AutoScroll -> False], 
   SelectionMove[EvaluationNotebook[], After, Cell, 
    AutoScroll -> False];
   NotebookWrite[EvaluationNotebook[], 
    Cell[BoxData@ToBoxes[ExportString[{}, "Package"]], "Input", 
     CellTags -> {tag}, ShowCellTags -> True], All, 
    AutoScroll -> False];
   SelectionMove[EvaluationNotebook[], All, CellContents, 
    AutoScroll -> False]];
ReadCellContents[] := ToExpression@NotebookRead[EvaluationNotebook[]];

Manipulate[a + b, {a, 0, 1}, {b, 0, 1}, 
 Button["Save bookmarks", SelectCellWithTag["BOOKMARKS"];
  NotebookWrite[EvaluationNotebook[], 
   ToBoxes[StringReplace[
     ExportString[Typeset`bookmarkList$$, "Package"], 
     Shortest["FE`" ~~ v : ___ ~~ "$$"] ~~ DigitCharacter ... :> "$CellContext`" <> v <> "$$"]], 
   AutoScroll -> False]], 
 Button["Restore bookmarks", SelectCellWithTag["BOOKMARKS"];
  Typeset`bookmarkList$$ = ImportString@ReadCellContents[]], 
 Initialization :> (SelectCellWithTag["BOOKMARKS"];
   Typeset`bookmarkList$$ = ImportString@ReadCellContents[]), 
 SaveDefinitions -> True]

I think if you change your variables during development, even bookmarks may become invalid.

Edits: 1. Added button as asked in comment. 2. Improved the StringReplace pattern after suggestion by @iztok.

$\endgroup$
11
  • $\begingroup$ +1 thanks, although as you mentioned, having to define the variables to be saved manually might get problematic... $\endgroup$
    – Ajasja
    Commented Jan 18, 2013 at 9:30
  • $\begingroup$ I like the idea, thanks. But - as Ajasja mentioned - we will try to avoid manual listing of all variables since they will surely be changing frequently, and introducing a new source of potential trouble to take care of is not desired. However, if anyone gets around the conversion you noted above, this would be a perfect solution. $\endgroup$
    – iztok
    Commented Jan 18, 2013 at 9:53
  • $\begingroup$ @Ajasja See the alternative I added. Thanks. $\endgroup$
    – Michael E2
    Commented Jan 18, 2013 at 13:51
  • $\begingroup$ @MichaelE2 great idea. Is it possible to have a button to restore the bookmarks inside manipulate? $\endgroup$
    – Ajasja
    Commented Jan 18, 2013 at 14:17
  • 1
    $\begingroup$ @iztok I put in a slightly different fix than your suggestion. Somehow I managed to get a bookmark with the symbol FE`b$$ with no following number, which wouldn't be converted by my pattern or your fix. $\endgroup$
    – Michael E2
    Commented Jan 18, 2013 at 21:50
3
$\begingroup$

This works for me:

Manipulate[
bookm = {"b1":>(Fun=Cos; freq=2)};
Plot[Fun[2 Pi freq x],{x,0,2},Axes->showAxes,PlotLabel->If[showPlotLabel,plotLabel,""]],{Fun,{Sin,Cos}},{freq,1,3},Row[{Control[{showAxes,{True,False}}],Control[{showPlotLabel,{True,False}}]},"\t"],{plotLabel,"Plot Label",Enabled->showPlotLabel},
Bookmarks->bookm,
SaveDefinitions->True
]
$\endgroup$
2
  • $\begingroup$ Hmm, but this is hard to change from inside manipulate. Also, when the original input cell is evaluated all the bookmarks are lost... $\endgroup$
    – Ajasja
    Commented Jan 17, 2013 at 21:15
  • $\begingroup$ You can add bookmarks through with "Add to Bookmarks" from the + control in the upper right corner. Works like a charm. I understood the OP that this should work on a deployed Manipulate, i.e., there is no input cell anymore really. $\endgroup$ Commented Jan 17, 2013 at 21:33
3
$\begingroup$

Here is a prof of principles that saves the bookmarks (Typeset`bookmarkList$$) to a string (it could equally well be a file). But it only works if LocalizeVariables -> False is used, which is quite a limitation.

Manipulate[
 Plot[Fun[2 Pi freq x], {x, 0, 2}, Axes -> showAxes, 
  PlotLabel -> If[showPlotLabel, plotLabel, ""]], {Fun, {Sin, Cos}}, {freq, 1, 3}, 
 Row[{Control[{showAxes, {True, False}}], 
      Control[{showPlotLabel, {True, False}}]}, "\t"], 
 {plotLabel, "Plot Label", Enabled -> showPlotLabel}, 
 Button["Save", 
  globalString = ExportString[Typeset`bookmarkList$$,  "Package"]; Print@globalString],
     Button["Load", 
      Typeset`bookmarkList$$ = ImportString[globalString,  "Package"]],
 LocalizeVariables -> False] 

To test, add some bookmarks, press Save, reinitialize the manipulate control and press Load. Thanks to Rojo and Rolf Mertig for their hints.

$\endgroup$
1
  • $\begingroup$ Thanks to all three contributors! Even if LocalizeVariables->False is not the cleanest solution, nor is splitting the action between existing Bookmarks and Manipulate controls, I think I will go with it - at least for the start. $\endgroup$
    – iztok
    Commented Jan 18, 2013 at 10:01
1
$\begingroup$

What about something along these lines?

Manipulate[ 
    Plot[Fun[2 Pi freq x], {x, 0, 2}, 
        Axes -> showAxes,  
        PlotLabel -> If[showPlotLabel, plotLabel, ""]
      ],
    {Fun, {Sin, Cos}},
    {freq, 1, 3},
    Row[{
       Control[{showAxes, {True, False}}],
       Control[{showPlotLabel, {True, False}}]
       }, "\t"],
     {plotLabel, "Plot Label", Enabled -> showPlotLabel}
     ]//addLoadSaveButtons

brings out

Mathematica graphics

I have barely tested it but it seems to be able to load and save states and bookmarks of Manipulate expressions

Here is the code:

ClearAll[putBookmarks, putOwnValues, getBookmarks, getOwnValues , \
getCellManipulate, replaceCellManipulate, getBookmarksAndOwnValues, \
putBookmaksAndOwnValues, addLoadSaveButtons]

(* puts the specified bookmarks options in a Manipulate *)
putBookmarks[HoldPattern@Manipulate[b__, op : OptionsPattern[]], 
   bookmarks_] := Manipulate[b, Bookmarks :> bookmarks, op];

(* puts the specified variable values options in a Manipulate, if \
they exist.
The format is {Hold[var=value]..} *)
putOwnValues[
   HoldPattern@
    Manipulate[b__, vars : Longest[Except[_?OptionQ, _List] ..], 
     rest___], {Hold[var_ = val_], restVars___}] := putOwnValues[
   Hold[vars] /. 
     HoldPattern[{{var, _, r2___} | var, r___}] :> {{var, val, r2}, 
       r} /. Hold[v___] :>
     Manipulate[b, v, rest],
   {restVars}];
putOwnValues[man_, {}] := man;

(* gets the bookmarks option in a Manipulate *)
getBookmarks[HoldPattern@Manipulate[___, op : OptionsPattern[]]] := 
  With[{res = Bookmarks /. Flatten@{op}}, res /; res =!= Bookmarks];
getBookmarks[_Manipulate] := {};

(* gets the values of the variables that have values in a manipulate. \
Format: {Hold[var=val]} *)
getOwnValues[
  HoldPattern@
   Manipulate[b__, vars : Longest[Except[_?OptionQ, _List] ..], 
    rest___]] := 
 Cases[Hold[vars], {{var_, val_, ___}, ___} :> Hold[var = val]]

(* gets the first manipulate it finds in a preorder depth first \
search of the cell expression *)
getCellManipulate[c_Cell] := 
 With[{res = 
    c /. BoxData[boxes_, ___] :> MakeExpression@boxes /. 
     m_Manipulate :> RuleCondition@Return[m, ReplaceAll]}, 
  res /; res =!= c]

(* replaces all the outermost manipulates in a cell expression by the \
specified manipulate *)
replaceCellManipulate[Cell[BoxData[boxes_, r1___], r2___], 
  mnew_Manipulate] := Cell[BoxData[
   Apply[MakeBoxes,
    MakeExpression@boxes /. m_Manipulate :> mnew], r1], r2]

(* the code speaks for itself *)
getBookmarksAndOwnValues[c_Cell] := 
 getCellManipulate[c] /. 
  man_ :> {"Variables State" -> getOwnValues[man], 
    "Bookmarks" -> getBookmarks[man]}

(* inserts the variables and bookmarks in the outermost manipulates \
of the cell expression *)
putBookmaksAndOwnValues[
  c_Cell, {"Variables State" -> ownVals_, 
   "Bookmarks" -> bookmarks_}] := 
 replaceCellManipulate[c, 
  getCellManipulate[c]~putOwnValues~ownVals~putBookmarks~bookmarks]

(* all of these functions default to $Failed *)
Scan[(Blank@# = $Failed) &, 
  {putBookmarks, putOwnValues, getBookmarks, getOwnValues , 
   getCellManipulate, replaceCellManipulate, getBookmarksAndOwnValues,
    putBookmaksAndOwnValues, addLoadSaveButtons}];

(*You wrap your manipulate with this to add the Save and Load buttons \
on the top*)
addLoadSaveButtons[m_Manipulate] := 
 Labeled[m, 
  Row[{Button["Save", 
     Export[SystemDialogInput["FileSave", ".wdx"], 
      getBookmarksAndOwnValues@readEvaluationCell[], "WDX"], 
     Method -> "Queued"], 
    Button["Load", 
     writeEvaluationCell[
      putBookmaksAndOwnValues[readEvaluationCell[], 
       Import[SystemDialogInput["FileOpen"]]]], Method -> "Queued"]}],
   Top]

writeEvaluationCell[stuff_] /; $VersionNumber >= 9 := 
  NotebookWrite[EvaluationCell[], stuff];
writeEvaluationCell[
  stuff_] := (SelectionMove[EvaluationNotebook[], All, 
   EvaluationCell]; NotebookWrite[EvaluationNotebook[], stuff])

readEvaluationCell[] /; $VersionNumber >= 9 := 
  NotebookRead@EvaluationCell[];
readEvaluationCell[] := (SelectionMove[EvaluationNotebook[], All, 
   EvaluationCell]; NotebookRead@EvaluationNotebook[])
$\endgroup$
5
  • $\begingroup$ I think what he is asking is what happens when you re-evaluate the manipulate and then import the bookmarks. $\endgroup$ Commented Jan 17, 2013 at 22:46
  • $\begingroup$ @MikeHoneychurch yes, I now understood he wants to reevaluate the manipulate with perhaps some added controls or tweaks, and be able to import the bookmarks and the common controls' state. This doesn't work for that, but I'm not sure if I should delete it $\endgroup$
    – Rojo
    Commented Jan 17, 2013 at 22:53
  • $\begingroup$ Hmm, it's not working for me. After pressing save nothing happens... Aha, got it, only works in MMA9. $\endgroup$
    – Ajasja
    Commented Jan 18, 2013 at 9:32
  • $\begingroup$ Seems as a neat solution, but I am not at v9 yet ... And I would prefer saving only the settings, not all the graphics and other output, especially to ensure compatibility with upgrades. $\endgroup$
    – iztok
    Commented Jan 18, 2013 at 10:07
  • $\begingroup$ @iztok, the code duuump edit only saves the settings, and works with v8 since the last edit $\endgroup$
    – Rojo
    Commented Jan 18, 2013 at 14:01
0
$\begingroup$

There is a great option at the end of Manipulate called Bookmarks. I was unaware of this until today.

What you might do in order to see the syntax of how to use it is to set the parameters to a desired value and then click the little + icon on the upper right and invoke the "Add to Bookmarks" option.

Say you give it a name (e.g., MyBookmark). To see what this looks like click the little + icon and again and invoke "Paste Bookmarks".

This will write to the screen the current values of the manipulate parameters.

What you would do then is to change your Manipulate code by adding the Bookmark as an option. It would something like this:

Manipulate[
 Plot[Fun[2 Pi freq x], {x, 0, 2}, Axes -> showAxes, 
  PlotLabel -> If[showPlotLabel, plotLabel, ""]], {Fun, {Sin, 
   Cos}}, {freq, 1, 3}, 
 Row[{Control[{showAxes, {True, False}}], 
   Control[{showPlotLabel, {True, False}}]}, "\t"], {plotLabel, 
  "Plot Label", Enabled -> showPlotLabel},
 Bookmarks -> {"Case 1" :> {freq = 1, Fun = Sin, 
     plotLabel = "Plot Label", showAxes = True, 
     showPlotLabel = False}, 
   "Case 2" :> {freq = 1.508`, Fun = Sin, plotLabel = "Plot Label", 
     showAxes = False, showPlotLabel = True}}]
$\endgroup$

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.