6
$\begingroup$

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).

$\endgroup$

1 Answer 1

4
$\begingroup$

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}]]
$\endgroup$
7
  • $\begingroup$ 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? $\endgroup$ Commented Mar 18, 2013 at 16:36
  • $\begingroup$ @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. $\endgroup$ Commented Mar 18, 2013 at 16:39
  • $\begingroup$ 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. $\endgroup$ Commented Mar 19, 2013 at 13:47
  • $\begingroup$ @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. $\endgroup$ Commented Mar 19, 2013 at 13:55
  • $\begingroup$ Yes, usually I don't explain, but here I got so excited thanks to you, that I had to write something! $\endgroup$ Commented Mar 19, 2013 at 14:06

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.