Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Is there a way to update dynamic variables through a function. I was looking back at one of the answers from Heike where she showed me how to make my custom Manipulate. What I'm finding very annoying is having to copy and paste code for every variable I have to update. Consider this:

Panel[
    DynamicModule[
        {
        a = 1, b = 100,
        c = a + b + 1, d = a - b + 1
        }, 
        Column[{
            Grid[{
                {
                MyControl[Manipulator[Dynamic[a, (a = #; c = a + b + 1; d = a - b + 1) &], {0, 1}],"a", Dynamic[PaddedForm[a, 5]]],
                MyControl[Manipulator[Dynamic[b, (b = #; c = a + b + 1; d = a - b + 1) &], {100, 200}], "b", Dynamic[PaddedForm[b, 5]]],
                }
                }, Alignment -> Left],
            {Dynamic@c, Dynamic@d}
        }],
        Initialization :> (
            MyControl[manip_, left_String, right_] := Row[{Style[left, "TI", 14], manip, right}, Spacer[1]];
        )
    ], 
    ImageSize -> {600, 100}
]

This allows me to change a and b and every time I change them c and d get updated and they are displayed:

screenshot

Question, is there any way to remove the redundancy of the code? I would love to have a function which updates all the variables, in this case, c and d. For instance I want something like this:

Panel[
    DynamicModule[
        {
        a = 1, b = 100,
        c = a + b + 1, d = a - b + 1
        }, 
        Column[{
            Grid[{
                {
                MyControl[Manipulator[Dynamic[a, (a = #; updateVars[]) &], {0, 1}],"a", Dynamic[PaddedForm[a, 5]]],
                MyControl[Manipulator[Dynamic[b, (b = #; updateVars[]) &], {100, 200}], "b", Dynamic[PaddedForm[b, 5]]],
                }
                }, Alignment -> Left],
            {Dynamic@c, Dynamic@d}
        }],
        Initialization :> (
            MyControl[manip_, left_String, right_] := Row[{Style[left, "TI", 14], manip, right}, Spacer[1]];
            updateVars[] := (c = a + b + 1; d = a - b + 1);
        )
    ], 
    ImageSize -> {600, 100}
]

That way, if later on I introduce something else that needs to be updated every time I move a single sliders then I can just add it to updateVars. Unfortunately, the above does not work. Anyone knows how to make it work?

share|improve this question
    
Your code works OK in my machine, with a minor quirk solved by declaring MyControl in the DynamicModule vars section, and adding a Dynamic@ before each MyControl[] invocation –  belisarius May 29 '12 at 4:55

2 Answers 2

up vote 6 down vote accepted

What you need is the following set of golden rules:

  • Use internal (local to the enclosing DynamicModule) update functions in the Dynamic controls to update common variables depending on other dynamic variables.
  • Define the update function(s) in the body of the DynamicModule (instead of using Initialization :> (...) as Initialization is only evaluated when the body is first displayed on screen, which might be too late, see details of evaluation sequence here).
  • Initialize dependent variables by calling the update function early, earlier than the actual output is displayed first (which is the Column[...] object). Without this, you will only see unevaluated front-end variables until you first move any of the sliders, which in turn would trigger an update call, assigning all dependent front-end variables their appropriate numerical values.

Like this:

Panel[DynamicModule[{a = 1, b = 100, c, d, update, MyControl},
  MyControl[manip_, left_, right_] := Row[{Style[left, "TI", 14], manip, right}, Spacer@1];
  update[] := (
    c = a + b + 1;
    d = a - b + 1;
    );
  update[]; (* actual initialization *)
  Column[{Grid[{
      {MyControl[Manipulator[Dynamic[a, (a = #; update[]) &], {0, 1}],
         "a", Dynamic[PaddedForm[a, 5]]],
       MyControl[
        Manipulator[Dynamic[b, (b = #; update[]) &], {100, 200}], "b",
         Dynamic[PaddedForm[b, 5]]]}
      }, Alignment -> Left],
    {Dynamic@c, Dynamic@d}
    }]], ImageSize -> {600, 100}]

Mathematica graphics

share|improve this answer
    
Thank you for the set of rules. Just one question, why does MyControl not included as local as you did with update? –  jmlopez May 29 '12 at 13:24
1  
Oh, good point, I simply forgot. It's there now. Thanks for the accept. –  István Zachar May 29 '12 at 13:38
    
I have one problem. I just made a nice GUI using the rules you specified (love them by the way) but now when I made a CDF all the dynamic content is grayed out. Could this be due to the lack of initialization? –  jmlopez May 29 '12 at 17:33
    
@jmlopez: Yes, functions with DownValues might cause security issues in deployed CDF's. Please see this answer for a workaround, and this thread (especially the parts about Securiy issues) to understand a bit better what is happening. –  István Zachar May 29 '12 at 17:56
    
I don't think this is because of a security issue. I have the version in which I did it the old way and it worked fine. But now instead I get this: i.imgur.com/RE31Z.png –  jmlopez May 29 '12 at 18:09

As I commented above, this is your code running OK in my machine. I commented on the (very) small modifications I did:

Panel[DynamicModule[{MyControl (*add*), a = 1, b = 100, c = a + b + 1,  d = a - b + 1}, 
  Column[{Grid[{{Dynamic@ (*add Dynamic*)
        MyControl[
         Manipulator[Dynamic[a, (a = #; updateVars[]) &], {0, 1}], 
         "a", Dynamic[PaddedForm[a, 5]]], 
       Dynamic@MyControl[  (*add Dynamic*)
         Manipulator[Dynamic[b, (b = #; updateVars[]) &], {100, 200}],
          "b", Dynamic[PaddedForm[b, 5]]],}}, 
     Alignment -> Left], {Dynamic@c, Dynamic@d}}], 
  Initialization :> (MyControl[manip_, left_String, right_] := 
     Row[{Style[left, "TI", 14], manip, right}, Spacer[1]];
    updateVars[] := (c = a + b + 1; d = a - b + 1);)], 
 ImageSize -> {600, 100}]

enter image description here

share|improve this answer
    
I don't understand why the example I posted still doesn't work (left it overnight), and now I copy and paste the exact same code on another cell and now it works as you mentioned.Even without adding Dynamic. In any case, I think I will go with István set of golden rules. –  jmlopez May 29 '12 at 12:44

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.