4

I have a set of variables which are used in various places in my calculations (solving a system, initial conditions, etc.). In order to make this easier to deal with, I want to make a control-like thing which makes them easier to manipulate, rather than just using long lists of unlabeled values such as

calculateValues[{0, 0, π, 0.5, 3}]

So far I have something like this:

This clearly doesn't work, and I expect in order to get it working properly I'll need to use Interpretation or more Dynamic incantations, but I can't figure out exactly what needs to happen. Any advice would be appreciated. Thanks in advance!

István Zachar
  • 47,032
  • 20
  • 143
  • 291
jtbandes
  • 1,422
  • 1
  • 11
  • 20

3 Answers3

3

You could do

myControl[varNames_List, start_: 0] := 
 myControl[varNames, ConstantArray[start, Length@varNames]]

myControl[varNames_List, start_List] := 
 Interpretation[{vars = start}, 
  Panel[Grid[{varNames, 
     Array[InputField[Dynamic@vars[[#]], 
        FieldSize -> {{0, Infinity}, 1}] &, Length@vars]}]], vars]

Now you can run that function to create a control myControl["a"~CharacterRange~"g"]. Each instance will have its own values and they all evaluate to their values when supplied as input

Rojo
  • 42,601
  • 7
  • 96
  • 188
  • This works great, thanks! But what is the purpose of the DynamicSetting and Evaluate? It seems that if I remove them, it works just the same way. Also, I would expect to need Dynamic[vars] instead of vars at the end... – jtbandes Nov 23 '12 at 20:10
  • @jtbandes, without the DynamicSetting it shouldn't work as I thought you wanted. Try running myControl["a"~CharacterRange~"g"] and then adding +3 to the output in the output cell with and without the DynamicSetting – Rojo Nov 23 '12 at 21:14
  • The Evaluate is probably useless, but since Interpretation has attribute HoldAll and I don't know why it's not simply HoldRest, I wanted to make sure it evaluated the first argument. However, it seems to evaluate it anyway – Rojo Nov 23 '12 at 21:21
  • The second argument of Interpretation needs to be what you want the kernel to receive when you use that control as input. You want the values of vars, and not a visual GUI that shows the dynamically updated value of vars. Always remember that Dynamic is only for SHOWING updated output (or in a control such as Slider[Dynamic@..] "as a notation" for input in controls). – Rojo Nov 23 '12 at 21:25
  • To the kernel, Dynamic[vars] will always stay as Dynamic[vars] no matter if vars has a value. It's the front end who decides to show you a Dynamic[vars] as the dynamically updated value of vars, just like Graphics[Disk[]] will be shown as a black disk – Rojo Nov 23 '12 at 21:26
  • 1
    @jtbandes, I just passed through the docs of Interpretation and saw that it can take an extra argument, specifying the local variables, and using it expands to the same code that I had used before: DynamicSetting@DynamicModule[..., but is way neater. Edited – Rojo Nov 25 '12 at 05:17
2

You could use interpretation.

Here's the idea.

SetAttributes[makeDynamicPanel, HoldFirst]
makeDynamicPanel[x_, defaultValue_] :=
 Module[{y},
    y = 
       Interpretation[
          Panel@InputField[Dynamic[x]]
          ,
          x
       ];
    x = defaultValue;
    y
 ]

Then you do for example

makeDynamicPanel[z, {0, 0, π, 0.5, 3}]

and you get a panel that allows to edit the value of z and can be used as argument to your function, you can even do for example panel + 2 and get a valid value, it's quite practical.

faysou
  • 10,999
  • 3
  • 50
  • 125
1

I would suggest using another list (vals) to store values for the variables vars. To set up a list of controllers (InputFields here) programmatically, some clever construct is required. Here I used an explicit Function call to save the changed value of the $i^{th}$ element of vals inside the Dynamic (as the # stands for the index of the list element, not the actual controller value, which is denoted as $x), but this can also be achieved using With.

calculateValues[v_List] := Plus @@ (v^Range@Length@v);

vars = {a, b, c, d, e};
vals = {1, 2, 3, 4, 5};

Panel[
 Grid[{
   Text /@ vars,
   InputField[Dynamic[vals[[#]], Function[{$x}, vals[[#]] = $x]], 
      FieldSize -> {{0, Infinity}, 1}] & /@ Range@Length@vals
   }]]

Mathematica graphics

Dynamic@vals
{1, 2, 3, 4, 5}
calculateValues@vars
a + b^2 + c^3 + d^4 + e^5
Dynamic[calculateValues@vars /. Thread[vars -> vals]]
3413
István Zachar
  • 47,032
  • 20
  • 143
  • 291