7

I'm confused about the best approach to localizing symbols used in a Manipulate. I understand that Manipulate does a good job by default of localizing symbols defined in its list of controls (even if these are custom controls). But it appears that symbols defined in the first argument, or those initialized with an Initialization option, are not localized. For example, in the following, z, r, and q (and naturally x) are local, but y and t are not:

Manipulate[
    y = 4*x;
    Plot[y*x^z+t[q], {x, 0, r}],
    {z, 0, 5},
    Row[{Control@{{r,2}, 2, Dynamic@q}}],
    {{q,10}, 5, 20},
    Initialization:> (t[i_]:=5*i)
]

Wrapping the whole Manipulate in a Model[{y,t}, ... seems to work, but marks y and t in the Manipulate in red (on macOS) which leaves me wondering if it's the right thing to do.

There are two approaches that seem to work partially, but not altogether:

DynamicModule

Wrapping in DynamicModule works to localize any symbols not localized by Manipulate

DynamicModule[{y,t},
    Manipulate[
        y = 4*x;
        Plot[y*x^z+t[q], {x, 0, r}],
        {z, 0,5},
        Row[{Control@{{r,2}, 2, Dynamic@q}}],
        {{q,10}, 5, 20},
        Initialization:> (t[i_]:=5*i)
]]

but this places y and t in an outer scope, which seems the wrong way to proceed.

ControlType -> None

For some symbols, the form {sym, None} works to localize sym, but only it seems for limited cases. For example

Manipulate[
    y = 4*x;
    Plot[y*x^z+t[q], {x, 0, r}],
    {z, 0, 5},
    Row[{Control@{{r,2},2,Dynamic@q}}],
    {{q,10}, 5,20},
    {y, None},
    Initialization:> (t[i_]:=5*i)
]

localizes y. But similar attempts to localize a function such as t fail.


What is the correct approach to localizing symbols inside Manipulate? Is there are reason to prefer DynamicModule over ControlType -> None in general, or vice versa? How should local functions be localized (esp. if the natural thing to be ding is specifying them in Initialization)?



Additionally, controls defined with Control@ don't highlight the associated symbols to indicate localization, which makes it very hard to read through code and understand how things are scoped. DynamicModule can be used to fix this (and even leaves the symbol in the inner Manipulate scope).

orome
  • 12,819
  • 3
  • 52
  • 100

2 Answers2

5

Because of the interactions of the various sliders, I would wrap the Manipulate expression in a DynamicModule expression that defines and localizes y and t. I would also define y as a function. Like so:

DynamicModule[{y, t},
  Manipulate[
    Plot[y[x]*x^z + t[q], {x, 0, r}],
    {z, 0, 5, Appearance -> "Labeled"},
    Row[{Control @ {{r, 2}, 2, q, Appearance -> "Labeled"}}],
    {{q, 5}, 5, t[i], Appearance -> "Labeled"},
    {{i, 3}, 1, 5, 1, Appearance -> "Labeled"}],
  Initialization :> (y[x_] := 4*x; t[i_] := 5*i)]

demo

I had to introduce the i slider because, without something like it, the OP's code as given in the question is not functional.

Update

My experience is that the form {{var, intitVal}, None} works well when var is used to introduce a simple variable, such as temporary used to help break up a complicated computation. To localize more complex things, such as function definitions, I prefer to take the route I show in this answer.

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
  • Fixed the bug in the code. Also focused on the several issues raised. – orome Sep 05 '17 at 18:10
  • And r? What's the reason for the different coloring; is it meant to mean something? DynamicModule fixes it (and even keeps it in the the right scope). – orome Sep 05 '17 at 19:48
  • So this method appears superior in terms of brevity and clarity. Is there any real drawback to pulling things — here y and t — out into a new nesting scope? – orome Sep 05 '17 at 20:14
  • @raxacoricofallapatorius. Not that I know of. – m_goldberg Sep 06 '17 at 00:10
3

The {var, None} spec does work for functions if you use Clear. It just initially assigns 0 to them. So you can do this:

Manipulate[
 Plot[y[x]*x^z + t[q], {x, 0, r}], {z, 0, 5, Appearance -> "Labeled"},
  Row[{Control@{{r, 2}, 2, q, Appearance -> "Labeled"}}], {{q, 5}, 5, 
  t[i], Appearance -> "Labeled"}, {{i, 3}, 1, 5, 1, 
  Appearance -> "Labeled"},
 {y, None},
 {t, None},
 Initialization :> (
   Clear[y, t];
   y[x_] := 4*x; t[i_] := 5*i)
 ]
b3m2a1
  • 46,870
  • 3
  • 92
  • 239
  • And r? What's the reason for the different coloring? (It seem the only way to avoid it is with DynamicModule; or initializing it a second time in a ControlType -> None control.) – orome Sep 05 '17 at 19:47
  • What's wrong with r? It's colored differently because it doesn't match SyntaxInformation[Manipulate]. – b3m2a1 Sep 05 '17 at 19:48
  • That's a bit circular though. The question is: if the coloring is meant to convey something, what is it meant to convey? Locals are clearly indicated, as are undefined symbols. The coloring for r corresponds to the latter. – orome Sep 05 '17 at 19:51
  • The coloring isn't handled by the kernel at all. It's handled by the front-end. The front end does static analysis to try to figure out what is what, but the front end is sometimes wrong. The coloring should be seen as a guideline. Usually the FE is right, but sometimes it misses things. – b3m2a1 Sep 05 '17 at 19:52
  • Ah, ok, that makes more sense: it's wrong. – orome Sep 05 '17 at 19:54
  • @raxacoricofallapatorius sorry I thought I had made that clear in chat. In any case, might be worth reading up on the FE and the kernel. Hope that helps. – b3m2a1 Sep 05 '17 at 19:56
  • It seems that {{y,y},None} and {{t,t},None} also works and eliminates the need for Clear without requiring repeating a specific value for the control initialization. – orome Sep 06 '17 at 15:58
  • @raxacoricofallapatorius makes sense – b3m2a1 Sep 06 '17 at 16:17