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 have two variables A and B that are linked such that changes to one causes the other to be updated to the same value. However at each change I'd also like to know which variable cause the update to happen. I've implemented this functionality using two Dynamic expressions.

 label = "Initial";
 A = 0; B = 0;

 {Dynamic[(If[B != A, (B = A); label = "A"]);, TrackedSymbols :> {A}], 
  Dynamic[(If[A != B, (A = B); label = "B"]);, TrackedSymbols :> {B}]}

 Dynamic[{label, A, B}]
 Row[{Button["++A", ++A],Button["++B", ++B]}] 

I would like to hide the output of these dynamic expressions in a similar fashion to DynamicWrapper, however there seems to be a problem in that DynamicWrapper doesn't respect TrackedSymbols, and of course only allows a single expression to be tied to an object.

The mentioned problem with DynamicWrapper is present if the Dynamic elements are simply substituted for Dynamic wrappers thus this instead. This, however, is not the main problem, since it seems impossible to have a single DynamicWrapper with

DynamicWrapper["Something",
{Dynamic[(If[B != A, (B = A); label = "A"]);, TrackedSymbols :> {A}],
 , Dynamic[(If[A != B, (A = B); label = "B"]), TrackedSymbols :> {B}]}
]

It seems that it will reevaluate the entire expression no matter which symbol changes, however even using multiple wrappers does not work, so the following is not what I want, since I still need multiple elements associated with each event, however I would expect that it worked if it did indeed respect the TrackedSymbols:

DynamicWrapper["Something", (Print["A event"];If[B != A, (B = A); label = "A"]);, TrackedSymbols :> {A}]
DynamicWrapper["Something", (Print["B event"];If[A != B, (A = B); label = "B"]),  TrackedSymbols :> {B}]

This to the original working example with Print statements inserted the difference is that the DynamicWrapper calls the A event first no matter which variable changed, which seems wrong since changing B should call B event first, then call A event. This seems consistent with DynamicWrapper not respecting TrackedSymbols, and thus triggering both events on the change, and then adding an additional triggering of B when B=A is set in the A event.

Clarification

There seems to be some confusion, so let me clarify I do not just want an invisible object that when in sight will run the events, ideally I would like to have something akin to:

 DynamicWrapper[
 Dynamic[{label, A, B}],
 {Dynamic[(If[B != A, (B = A); label = "A"]);, TrackedSymbols :> {A}], 
  Dynamic[(If[A != B, (A = B); label = "B"]);, TrackedSymbols :> {B}]}
 ]

Which displays as the expression but keeps the dynamic evaluations "in scope" if it is visible.

share|improve this question
    
Why not put your calculation all in Button? eg. Button["++A", ++A; B = A; label = "A"] –  Silvia Aug 1 '12 at 13:29
1  
You should put all the code that helps understand your problem. DynamicWrapper should respect TrackedSymbols if done properly. How to know where your problem is? Ping me up @ if you edit –  Rojo Aug 1 '12 at 13:34
    
@Rojo I added the cases where DynamicWrapper didn't work for me. –  jVincent Aug 1 '12 at 14:39
    
Couldn't you just do Row[{Button["++A", label = "A";B=++A],Button["++B", label = "B";A=++B]}]? –  Sjoerd C. de Vries Aug 1 '12 at 17:47
    
@SjoerdC.deVries The dynamic nature of the variables is pretty essential in the case. I may end up having any number of ways of changing A and B, the buttons are just there to illustrate as simply as possible the problem. –  jVincent Aug 1 '12 at 21:27
add comment

1 Answer

up vote 6 down vote accepted

Thanks for the clarification. I don't have time to look into it much right now, and of the top of my head I don't understand the behaviour of the TrackedSymbols option in your DynamicWrapper. But, you can always use a Refresh

DynamicWrapper["Something", 
 Refresh[Print["A event"]; If[B != A, (B = A); label = "A"], 
  TrackedSymbols :> {A}]]
DynamicWrapper["Something", 
 Refresh[Print["B event"]; If[A != B, (A = B); label = "B"], 
  TrackedSymbols :> {B}]]

Further clarification: the second argument of DynamicWrapper doesn't expect a Dynamic object. In fact, they serve no purpose since they will never be shown on the screen.

You proposed this as your ideal solution

DynamicWrapper[
 Dynamic[{label, A, B}],
 {Dynamic[(If[B != A, (B = A); label = "A"]);, TrackedSymbols :> {A}], 
  Dynamic[(If[A != B, (A = B); label = "B"]);, TrackedSymbols :> {B}]}
 ]

To make that work, simply change Dynamic to Refresh, and fold the DynamicWrappers so they update independently

label = "Initial";
A = 0; B = 0;


Fold[DynamicWrapper, Dynamic[{label, A, B}], 
 Unevaluated@{
  Refresh[(If[B != A, (B = A); label = "A"]);, 
    TrackedSymbols :> {A}], 
  Refresh[(If[A != B, (A = B); label = "B"]);, 
    TrackedSymbols :> {B}]}]


Row[{Button["++A", ++A], Button["++B", ++B]}]
share|improve this answer
    
Thanks, this is great. The whole passing Dynamic objects to DynamicWrapper was just my way of stating that I needed some code to track one symbol and some code to track the other. I still don't understand why DynamicWrapper doesn't respect tracked symbols, though using refresh solves that problem perfectly. –  jVincent Aug 1 '12 at 21:37
add comment

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.