2
$\begingroup$

lets take this small example code:

Manipulate[Plot[Sin[x (1 + a* x)], {x, 0, 6}], {a, 0, 100},
Button["a=90", ToExpression["a=90"]]]

By clicking the button I want to set the manipulate variable a to 90. An important thing is, that the variable name comes out of an imported sting in the real application. It seems, that ToExpression works for a global variable but not in the manipulate function.

How could I get to the desired functionality?

Regards!


I think I should explain my target more detailed. I have a manipulate output with approx. 20 manipulators. Furthermore I have got two buttons in the manipulate output. One button is for exporting the names and values of the manipulators in an excel spreadsheet. First column names, second column values. My intention is to save different configurations of the manipulated variables. The second button is for importing these variables. To avoid mistakes in defining the correct order of variable import (exported and imported order of variables have to match) I want to get the variable name out of the first column. So the order of import would not be relevant any more. Furthermore the code would be very compact by using a loop for importing all the variables. With the following command I have to take care about the correct order, because of the first argument of the Setter command. Dynamic@Setter[Dynamic@a, ToExpression["a=90"], "a=90"]

Here is my (not working) Import Button:

Button["Import", 
 ImportData = Import[SystemDialogInput["FileOpen", ".xlsx"]];
  For[i = 1, i < Length[ImportData[[1]]], i++, 
  ToExpression[
   ImportData[[1]][[i]][[1]] <> "=" <> 
    ToString[ImportData[[1]][[i]][[2]]]]]]

SetAttributes[fullName, HoldFirst];

fullName[anyVariable_, stringName_] := Module[{varFullName},
  varFullName = StringReplace[
    SymbolName[ Unevaluated[anyVariable]],
     __ ~~  scope : ("$$" ~~ DigitCharacter .. ~~ EndOfString) :> 
     "FE`" <> stringName <> scope]
  ]



Manipulate[Plot[Sin[x (1 + a*x)], {x, 0, 6}], {a, 0, 100}, {b, 0, 10},
 Button["a",  ToExpression[fullName[b, "a"] <> "=90"]
 ]
]

This seems to work but I don't understand all the special characters... May you explain the fullname function? LocalizeVariables -> False does not work for me.

$\endgroup$
8
  • 1
    $\begingroup$ Welcome to Mathematica.SE! 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Take the tour and check the faqs! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! $\endgroup$
    – user9660
    Commented Jun 25, 2015 at 7:33
  • $\begingroup$ related $\endgroup$
    – Kuba
    Commented Jun 25, 2015 at 7:43
  • $\begingroup$ @Kuba I don't thing it is a duplicate of that question, as the problem here is about scoping. The button does work, but it is setting the value of global a instead of the local a used within Manipulate. $\endgroup$
    – Karsten7
    Commented Jun 25, 2015 at 7:46
  • $\begingroup$ @Karsten7. Yep, corrected my comment. I wasn't focused :) $\endgroup$
    – Kuba
    Commented Jun 25, 2015 at 7:46
  • $\begingroup$ Updates need to be made to the Question, not posted as Answers. I tried to convert your posts to edits and format your code but it doesn't look right. Please fix what you can. $\endgroup$
    – Mr.Wizard
    Commented Jun 25, 2015 at 10:36

4 Answers 4

2
$\begingroup$

As I understand the OP's request, the following does what is desired. It may or may not be the best way to solve the actual problem, but I think it would help the OP pursue the approach in the question. Note one has to have the list of all the variables to be reset in the form

Hold[a, b,...]

Typing this by hand is perhaps easiest if there are only twenty variables and they are fairly stable over time. This list is then converted to replacement rules mapping global a to local a.

man = Manipulate[Plot[Sin[x (b + a*x)], {x, 0, 6}, ImageSize -> Small],
 {a, 0, 10}, {b, 0, 10},
 {globalToLocal, None},
 Button["a=1; b=2", 
  ToExpression["a=1; b=2", StandardForm, Hold] /. globalToLocal // 
   ReleaseHold],
 Initialization :>
   (debugG2L = globalToLocal = 
     Hold[a, b] /. {Hold -> List, 
       s_Symbol :> 
        ToExpression[
          StringTrim[SymbolName@Unevaluated@s, 
           "$$" ~~ DigitCharacter ..], StandardForm, HoldPattern] :> s})
 ]

Mathematica graphics
Before and after pressing the button.

We can inspect the globalToLocal rules, since they are saved in the global variable debugG2L:

debugG2L
(*  {HoldPattern[a] :> FE`a$$911, HoldPattern[b] :> FE`b$$911}  *)

Note the full local variable name for a is FE`a$$911. The 911 is a unique number added by the Front End when the Manipulate output is instantiated (shown) in the notebook. To get the global name a, b, etc., we have to strip (StringTrim) the $$ and the digits to get the base name used in the Manipulate code. I haven't figured out an easier way to do this. The symbols a and b must be instantiated by the FE before we can construct the replacement rule. (This is why it is done in the Initialization phase.) At that point, it is hard to get the global a symbol. One could type out the rules explicitly, one for each variable, if it's clearer:

globalToLocal = {ToExpression["a", StandardForm, HoldPattern] :> a, ...}

It may be advisable to keep lists of variables to check against your code. The following (I think) pulls out all of the Manipulator sliders:

sliders[man_Manipulate] := 
 Cases[man[[2 ;;]], {s_Symbol, 
     Repeated[_?NumericQ, {2, 3}], ___?OptionQ} | {{s_Symbol, __}, 
     Repeated[_?NumericQ, {2, 3}], ___?OptionQ} :> 
   SymbolName@Unevaluated@s]

sliders[man]
(*  {"a", "b"}  *)

Using Bookmarks, maybe...

As a side note, perhaps the "Add To Bookmarks..." menu item from the circled + menu in the upper right corner of the Manipulate can be used for exporting. The list of added bookmarks is available in Typeset`bookmarkList. One could access the settings through this variable, but the variable names saved are the current FE symbols, which probably will not be valid in a new session. (I've included buttons for access to Typeset`bookmarkList, but they can be ignored, omitted, or used for amusement. I have sometimes used it to find and save settings for classroom apps or other demonstrations, but there is a better way that seems potentially applicable to the OP's case.) Another way is to read the cell from the Front End and get the Bookmarks option value from it.

Manipulate[Typeset`bookmarkList,
 {a, 0, 10}, {b, 0, 10},
 Button["Reset Bookmarks", Typeset`bookmarkList = {}],
 Button["Save Bookmarks", saved = Typeset`bookmarkList]
 ] 

Mathematica graphics
After clicking the + > Add To Bookmarks... menu item

 

Mathematica graphics
After clicking the add button

Now if the following is placed directly below the Manipulate output, then executing it will save the settings of the local variables. One adjustment that may be necessary is that with bookmarks, all the Manipulate variables are saved and not a selected subset. The list of settings may have to be pruned in an actual application.

With[{bm = 
   Quiet[Check[
     Options[ToExpression@First@NotebookRead@PreviousCell[], 
      Bookmarks], Print["No Bookmarks are set."]; $Failed], 
    Options::optnf]},
 If[bm =!= $Failed,
  Export["/tmp/foo.xls", 
   settings = 
    "FOO" /. 
     Cases[Bookmarks /. bm, r_RuleDelayed :> (r /. Set -> List), 
      Infinity]]
  ]
 ]
(*  "/tmp/foo.xls"  *)

SystemOpen[%]   (* if you want to open the file *)

settings        (* if you want to check the settings *)
(*  {{a, 2.32}, {b, 6.22}}  *)

Of course "FOO" may be replaced by whatever name, or another way of extracting the bookmarked values may be used.

A more sophisticated approach might use SelectionMove instead of PreviousCell, CellPrint, CellTags, etc.

$\endgroup$
1
$\begingroup$

Quick fix is to use LocalizeVariables -> False but then you will have all a etc in Global context.

Other way is ugly, but works, we can use any existing variable to extract current context in DynamicModule:

SetAttributes[fullName, HoldFirst];

fullName[anyVariable_, stringName_] := Module[{varFullName},
  varFullName = StringReplace[
    SymbolName[ Unevaluated[anyVariable]],
     __ ~~  scope : ("$$" ~~ DigitCharacter .. ~~ EndOfString) :> 
     "FE`" <> stringName <> scope]
  ]



Manipulate[Plot[Sin[x (1 + a*x)], {x, 0, 6}], {a, 0, 100}, {b, 0, 10},
 Button["a",  ToExpression[fullName[b, "a"] <> "=90"]
 ]
]
$\endgroup$
1
$\begingroup$

Not sure if I understood your question correct, but I think this is what you would get from a standard import of your files:

setterDefinitions = {{"a", 10}, {"a", 50}, {"a", 90}, {"b", 1}, {"b", 2}}

With such a list of variable names and values, you could do the following to get a working Manipulate:

Manipulate[
  Plot[Sin[x (b + a*x)], {x, 0, 6}],
  {a, 0, 100}, {{b, 1}, None},
  Evaluate[
    Row@(
      Function[Null, 
        With[{heldSymbol = ToExpression[#1, InputForm, Hold]},
          Button[Row[{#1, "=", #2}], Set @@ Append[heldSymbol, #2]]
      ], HoldFirst] @@@ setterDefinitions
    )
  ]
]

the point here is that you have to understand when which part is evaluated. In your first try the ToExpression is evaluated after the Manipulate is rendered in the FrontEnd, so all local variables do now have those local names which we only can access with tricks like the one Kuba has shown. But if we do the evaluation before we send the Manipulate to the FrontEnd, the symbols are still the unevaluated global symbols in the current context, so we can just create symbols from strings and these will match those in the body. That is what I'm doing in the last argument, taking some care that these are inserted without being evaluated in case there are (own-)values defined for them (that part could also be done differently and presumably also more elegant).

$\endgroup$
1
$\begingroup$

Update:

Based on your updated question I guess you want something like

Manipulate[{a, b}, {a, 1, 10}, {b, 1, 10},
 Button["export", Export[SystemDialogInput["FileSave",".txt"], {{"a", a}, {"b", b}}, "Table"], 
  Method -> "Queued"],
 Button["import", {a, b} = Import[SystemDialogInput["FileOpen", ".txt"], "Table"][[All, 2]], 
  Method -> "Queued"]]

Old post:

You could use a Setter instead of a Button to get the intended scoping

Manipulate[Plot[Sin[x (1 + a*x)], {x, 0, 6}], {a, 0, 100}, 
 Dynamic@Setter[Dynamic@a, ToExpression["a=90"], "a=90"]]

One can make the Setter looker like a Button by adding the option Appearance -> "Button".

$\endgroup$
3
  • $\begingroup$ @Kuba But the symbol a is used within Plot, why shouldn't it be possible to use it within Setter? $\endgroup$
    – Karsten7
    Commented Jun 25, 2015 at 8:21
  • $\begingroup$ An explicit a is also used for the Manipulator, why not for the Setter. $\endgroup$
    – Karsten7
    Commented Jun 25, 2015 at 9:10
  • $\begingroup$ This is how I see this question, you have "a=90" as an input, update variable a which is local to Manipulate. Next input is "b=25" your setter still updates a. $\endgroup$
    – Kuba
    Commented Jun 25, 2015 at 10:10

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.