Re: Re: How to find which variable caused the trigger in Manipulate[]
- To: mathgroup at smc.vnet.net
- Subject: [mg104160] Re: [mg104136] Re: How to find which variable caused the trigger in Manipulate[]
- From: John Fultz <jfultz at wolfram.com>
- Date: Wed, 21 Oct 2009 06:31:33 -0400 (EDT)
- Reply-to: jfultz at wolfram.com
On Tue, 20 Oct 2009 22:13:15 -0500, Nasser M. Abbasi wrote: > > > From: "John Fultz" > > "Now this code has the distinct advantage that it works, and it's not so > complicated, but there's one fatal flaw in it. It relies on the same > undocumented assumption I discussed earlier...that Dynamics are validated > left-to-right. It would fall down if you flipped the order of the Row[], > or in a hypothetical future implementation of Dynamic that violates this > assumption. So that's not my final solution. But I wanted you to see > this so you could understand better how I built my final solution. My > final solution takes the same approach, but tracks the Dynamics as > they're initialized, forcing the Text[] Dynamic to evaluate (possibly > again) after the others. The solution doesn't seem very elegant, but it > does work. I'm afraid that the educational value of this example will > require some study of the code, but you seem willing to do that. I > reversed the Row[] in this example to prove that it does, in fact, work > as advertised. > > Manipulate[Row[{ > > Dynamic[Refresh[ > Switch[dynamicsInitialized, > {True, True, False}, dynamicsInitialized[[3]] = True;r = initialState, > {True, True, True}, initialState = r]; > Text[r], TrackedSymbols -> {y, x, dynamicsInitialized}]], > > Dynamic[Refresh[dynamicsInitialized[[1]] = True; r = x; > "",TrackedSymbols -> {x}]], > > Dynamic[Refresh[dynamicsInitialized[[2]] = True; r = y; > "",TrackedSymbols -> {y}]]} > ], > > {x, 0, 1, 0.01}, > {y, 0, 1, 0.01}, > {r, "", "", ControlType -> None}, > {{initialState, 0}, ControlType ->None}, > {{dynamicsInitialized, {False, False, False}}, ControlType -> None}, > > Initialization :> (dynamicsInitialized = {False, False, False}) > ] > > " > > Brilliant John as always. > > Studying your code, I just learned something I never knew about > Manipulate, which is probably why I could not come up with a solution. > > I was wondering, since in the code above, dynamicsInitialized variable is > initialized to {False, False, False}, then, assuming does not "touch" the > "y" slider at all the whole time, then how could the Switch statement, > which checks only for {True, True, False} and {True, True, True}, ever > gets executed? > > Since only when the "y" slider is moved, would you set the > dynamicsInitialized[[2]] to true. > > Yet, when I look at the DynamicModule[] code generated by the hitting the > "Paste snapshot" button in the corner of the Manipulate display, it says > that dynamicsInitialized has the value {True, True, True} each time ! > But how could it be so, I have not even touched the "y" slider! even if I > do not touch the "x" slider, this variable will have this value. > > But when I click the "initial settings" button, then look at the "Paste > snaphot", then I see this variable having the value {False, False,= False}. > > I came up with a theory on how this could be: > > Just by the act of displaying the Manipulate result on the screen, or > scrolling over it, all the control variables will be "activated", or > "triggered" initially, even when one has not physically moved the > slides/the controls yet. > > This means there will be some initial evaluations of the Manipulate > expression. 3 initial evaluations that occur behind the scene before I > ever get to touch the sliders. > > The first evaluation detects that "x" is triggered (or maybe "y", since > the order is not defined), so this will cause dynamicsInitialized to > become {True, False, False}. > > The second evaluation will detect that "y" control variable is triggered, > so now dynamicsInitialized becomes {True, True, False}. > > And now in the third evaluation, since dynamicsInitialized is being > tracked also, and it has changed from the above evaluations, then now and > only now, would one of the Switch statement conditions be used, the one > which checks for {True, True, False}.and this will finally cause > dynamicsInitialized becomes {True, True, True}. And now the rest will > follow as the user moves the "x" or the "y" slides. > > Thanks again for your help John. > > --Nasser Yes, you've largely got it. For purposes of full understanding, I'll just correct a very forgivable oversight. Not three evaluations, but six. Evaluation 1: The code in Initialization comes first. That's a documented, ironclad guarantee. My solution relies on that guarantee. The remaining evaluations, as I've stressed, could hypothetically come in any order, but in version 7, here's how they come... Evaluation 2: The Switch[] code. But the Switch[] fails, as dynamicsInitialized will be {False, False, False}, remains unevaluated, and r is left unchanged. Evaluation 3: The x initialization, as you say. Evaluation 4: The y initialization, as you say. Evaluation 5: Evaluations 3 and 4 have now re-tickled the Switch[] code, by virtue of changing dynamicsInitialized (you'll note that I added dynamicsInitialized to that particular Refresh). So now the Switch[] code evaluates again, but this time with dynamicsInitialized set to {True, True, False} Evaluation 6: Evaluation 5 now tickles *again* the Switch[] statement by virtue of changing dynamicsInitialized to {True, True, True}. So one last re-evaluation. And now things are in a stable state and no further evaluations happen until you start moving sliders. Sincerely, John Fultz jfultz at wolfram.com User Interface Group Wolfram Research, Inc.