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.

I am looking for a solution to selectively update a dynamic expression expr which is dependent on multiple control variables {x, y, ...}. I need to update expr differently (using xUpdate and yUpdate) according to which controller is manipulated, i.e. which control variable triggers an update, but without including update code in any of the controllers! That is, Dynamic[expr] itself has to include the different update modes.

Question: Is there a method to update a dynamic expression differently depending on which parent-variable triggers an update?

1. Include update in controller

The easy way would be to simply include the different update codes in the controllers, but as I said, this is not the desired way. The code is included here only for reference:

xUpdate[xin_, yin_] := {"x-trigger", yin + xin, yin};
yUpdate[xin_, yin_] := {"y-trigger", yin*10, yin};

x = y = 0; expr = yUpdate[x, y];
{Row@{"update x: ", 
   Slider[Dynamic[x, (x = #; expr = xUpdate[x, y]) &]]}, 
 Button["Update y", y = RandomReal[]; expr = yUpdate[x, y]]}
Dynamic[expr]

This works as expected, but in my use case I cannot update expr directly from the controllers. I have to do it in a way that is restricted to the last line, i.e. the expr itself has to do the updating according to which controller was manipulated.

2. Using $ControlActiveSetting

An alternative method is to rely on the global value of $ControlActiveSetting:

xUpdate[xin_, yin_] := {"x-trigger", yin + xin, yin};
yUpdate[xin_, yin_] := {"y-trigger", yin*10, yin};

x = y = 0;    
{Button["Update y", y = RandomReal[]], 
 Row@{"update x: ", Slider[Dynamic@x]}}
Dynamic[expr = If[$ControlActiveSetting, xUpdate[x, y], yUpdate[x, y]]; expr, 
 TrackedSymbols :> {x, y}]

This correctly differentiates between the two update modes, but it incorrectly reverts to y-trigger whenever the x-slider is released. This is unwanted behaviour. A second problem with this is that $ControlActiveSetting cannot differentiate between multiple sliders (i.e. imagine a third z controller).

3. Intermediate solution a'la $ControlActiveSetting

A global flag (trigger, substituting $ControlActiveSetting) is set to either "x", "y" or "z", depending on which controller is being manipulated. This works as expected and can be extended to any number of controllers, but has the problem that I still have to set trigger in each controller, which I want to avoid.

xUpdate[xin_, yin_, zin_] := {"x-trigger", yin + xin, yin, zin};
yUpdate[xin_, yin_, zin_] := {"y-trigger", yin*10, yin, zin};
zUpdate[xin_, yin_, zin_] := {"z-trigger", zin*20, yin - 1, zin};

x = y = z = 0;
trigger = "x";    
{Button["Update y", trigger = "y"; y = RandomReal[]], 
 Row@{"update x: ", Slider[Dynamic[x, (trigger = "x"; x = #) &]]}, 
 Row@{"update z: ", Slider[Dynamic[z, (trigger = "z"; z = #) &]]}}
Dynamic[Switch[trigger, "x", xUpdate[x, y, z], "y", yUpdate[x, y, z], 
  "z", zUpdate[x, y, z]], TrackedSymbols :> {x, y, z}]

But it brings me closer to my real question:

Question:

Is there a way to check globally which control variable is being actively manipulated/changed in the front-end? Surely Dynamic[expr] knows about it as it has the TrackedSymbols option, but I cannot access this information from inside the Dynamic. I think of something like CurrentValue["ManipulatedVariable"] or CurrentValue["ActualDynamicUpdatingTrigger"] (which are nonexistent).

share|improve this question

1 Answer 1

up vote 2 down vote accepted

Here is one way, which is probably not optimal, and also is kind of cheating, but. This is a generator for a "trigger":

ClearAll[makeTrigger]
SetAttributes[makeTrigger, HoldAll];
makeTrigger[res_, var_, updateCode_] :=
  Module[{varOld = var, trigger},
    trigger /; varOld =!= var := (
      varOld = var;
      res = updateCode
    );
    trigger];

now,

ClearAll[expr, x, y, z];
x = y = z = 0;
triggers = {
   makeTrigger[expr, x, xUpdate[x, y, z]],
   makeTrigger[expr, y, yUpdate[x, y, z]],
   makeTrigger[expr, z, zUpdate[x, y, z]]
};

and we can check, that this works:

{
  Button["Update y", y = RandomReal[]], 
  Row@{"update x: ", Slider[Dynamic[x]]}, 
  Row@{"update z: ", Slider[Dynamic[z]]}
}

With[{tr = triggers}, Dynamic[tr ; expr, TrackedSymbols :> {x, y, z}]]
share|improve this answer
    
This seems to be promising, as it approaches from a different angle. Why do you say it is not optimal? Because it does the /; checking for all three triggers at every update? –  István Zachar Mar 18 '13 at 16:36
    
@IstvánZachar Well, it just seems a bit of a round-about method. There may be a more direct one which I am not aware of. –  Leonid Shifrin Mar 18 '13 at 16:39
    
Though this is working marvellously in my use case (stay tuned), I really hope that there are other solutions, as I wan't to explore this particular field in total depth. So for the moment, I won't accept the answer, but wait a bit for others. –  István Zachar Mar 19 '13 at 13:47
    
@István You don't have to explain your decisions regarding answer acceptance :-). Besides, I never thought of this answer as the solutiion, it feels more like a hack to me. –  Leonid Shifrin Mar 19 '13 at 13:55
    
Yes, usually I don't explain, but here I got so excited thanks to you, that I had to write something! –  István Zachar Mar 19 '13 at 14:06

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.