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.

In this example, I want a series of four buttons to change the value of a variable that is used dynamically to drive a plot. I am trying to figure out why using Table around the buttons causes a problem.

This works:

{Button["1", freq = 1], Button["2", freq = 2], Button["3", freq = 3], 
 Button["4", freq = 4]}
 Dynamic[Plot[Sin[freq * x], {x, 0, 2 \[Pi]}]]

Why doesn't this work:

Table[Button[ToString[i], freq2 = i], {i, 4}]
Dynamic[Plot[Sin[freq2 * x], {x, 0, 2 \[Pi]}]]
share|improve this question
    
Strongly related: mathematica.stackexchange.com/q/7756/121 –  Mr.Wizard Jul 14 '12 at 4:44
add comment

3 Answers 3

The second one does not work, because Button has HoldRest property:

In[1]:= Attributes[Button]
Out[1]= {HoldRest, Protected, ReadProtected}

Thus, i in your buttons are interpreted as literal i, not numbers.

The easiest way to solve this is using a Map:

Map[(Button[ToString[#], freq2 = #]) &, Range[4]]
Dynamic[Plot[Sin[freq2*x], {x, 0, 2 \[Pi]}]]

When each value is applied to the pure function, # will be replaced with the actual value.

PS

Just for fun, you can confirm these by using Shift-Ctrl-E (or Shift-Cmd-E on Mac) on your button cell (exposing underlying FE language). This is what you see when expanding the button cell from the original code:

cell

As you can see, the action assigns i to freq (all in $CellContext), not actual value (1, this case).

share|improve this answer
    
Thank you, that makes perfect sense. –  ebergerson Jul 17 '12 at 19:10
add comment

Look at the FullForm of the two lists:

{Button["1", freq = 1], Button["2", freq = 2], Button["3", freq = 3], Button["4", freq = 4]} //FullForm
(* List[Button["1",Set[freq,1]],Button["2",Set[freq,2]],Button["3",Set[freq,3]],Button["4",Set[freq,4]]] *)

Table[Button[ToString[i], freq2 = i], {i, 4}] // FullForm
(* List[Button["1",Set[freq2,i]],Button["2",Set[freq2,i]],Button["3",Set[freq2,i]],Button["4",Set[freq2,i]]] *)

In the second case you Set your freq2 equal to the symbolic i, not to the value of the iteration variable. That's because Button has the attribute HoldRest.

A possible way out would be to inject the value in the variable using With, i.e.

Table[With[{j = i}, Button[ToString[i], freq2 = j]], {i, 4}] //FullForm
(* List[Button["1",Set[freq2,1]],Button["2",Set[freq2,2]],Button["3",Set[freq2,3]],Button["4",Set[freq2,4]]] *)

Moreover, this is referenced in the documentation for Button, at Scope $\rightarrow$ Button Control.

share|improve this answer
    
Yes, I see here, as above, the i was not being evaluated. Thank you for your help. –  ebergerson Jul 17 '12 at 19:10
add comment

As already stated this is an evaluation problem because of the Hold attribute that Button has, and the mechanism of Table which is akin to Block. You need a way to get the value into the expression. In this case I would use Function and Array:

Array[Button[#, freq2 = #] &, 4]

Dynamic @ Plot[Sin[freq2*x], {x, 0, 2 π}]

(ToString is unnecessary.)

See the answers to this question for other options:

Using pure functions in Table

share|improve this answer
    
+1 for the minimalistic cool code –  R Hall Jul 14 '12 at 15:54
    
Thank you. Nice to see the alternative Array to Map above. I would not have thought of the alternative. –  ebergerson Jul 17 '12 at 19:12
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.