4
$\begingroup$

[Apologies if this is a duplicate: I have looked at quite a few related questions but have not seen this issue dealt with]

I have built a custom control, using the following method:

customControl[Dynamic[x_]] := True;
Manipulate[{x, 1, other}, 
     {{x, 0}, customControl[#1] &}, 
     {{y, 0}, ControlType -> None}, 
     {other, 0, 1}])]

and now all I need to do is wrap the definition of customControl inside DynamicModule.

I thought I would know how to do this, from questions such as this and answers such as Federico's. But I'm meeting a problem with internalising a custom control to a DynamicModule and/or Manipulate. The example below is the simplest one I could come up with that illustrates the problem, which appears to be one of pattern-matching rather than the definition of my customControl. This is why the controls I'm defining don't actually do anything: if I can get the pattern to match, then I think I'm in business. So consider the following, which yields the same output as my example above:

Clear[customControl] 
DynamicModule[{customControl}, 
  (customControl[Dynamic[x_], _] := True;
   Manipulate[{x, 1, other},
     {{x, 0}, customControl[#1, y] &}, 
     {{y, 0}, ControlType -> None}, {other, 0, 1}])]

image of output of this code

So far so good: customControl is called and returns True as expected. A small change--which you might think is inconsequential, because it involves dropping an argument to customControl which is never used, yields a different result:

Clear[customControl] 
DynamicModule[{customControl}, 
  (customControl[Dynamic[x_]] := True;
   Manipulate[{x, 1, other},
     {{x, 0}, customControl[#1] &}, 
     {{y, 0}, ControlType -> None}, {other, 0, 1}])]

image of output of above code

So it might seem that x is not considered as a Dynamic object when customControl is called on it unless it is somehow linked to another Dynamic object through a common invocation, even if that invocation doesn't actually do anything. My first example does not work if the 2nd argument to customControl is a constant such as 0; it needs to be y. [Or x? I didn't try that...]

[The reason I'm asking this specific question: the code is destined for a CDF interface. SaveDefinitions -> True is of no help or hope in my application; I need to localise everything within DynamicModules. It works fine with Module but of course that's deprecated (and in Mma10 this is very visible with red highlighting)]

Now I've written all that, I do have a dim memory of a similar question involving dynamic variables and needing to have more than one around...but I haven't found it.

$\endgroup$
  • $\begingroup$ I tried using x instead of y as a dummy argument. It worked just fine. $\endgroup$ – fairflow Nov 18 '14 at 17:51
  • 1
    $\begingroup$ does this work: {{x,0},Dynamic@customControl[#] &} ? $\endgroup$ – kglr Nov 18 '14 at 17:55
  • $\begingroup$ ... or {{x, 0}, (y; customControl[#]) &} or {{x, 0}, (other; customControl[#]) &} ? $\endgroup$ – kglr Nov 18 '14 at 17:58
  • $\begingroup$ @kguler Both work. Odd thing is, I met this problem in a much more complex situation where many variables were being evaluated; but perhaps it was precisely because I tried to develop these techniques in isolation from the concrete problem I had that I fell into this trap. $\endgroup$ – fairflow Nov 18 '14 at 18:04
  • $\begingroup$ So do these then: Dynamic[Control[{{x, 0}, customControl[#]&}]] and {{x, 0}, customControl[Dynamic[x]] &}? $\endgroup$ – kglr Nov 18 '14 at 18:04
3
$\begingroup$

Since this has gone unanswered for so long and I can add one clarification to the comments under the question, I'll fill out an answer.

In the comments, it has been observed that the following work (with the appropriate definition of customControl):

{{x, 0}, customControl[#1, y] &}
{{x, 0}, customControl[Dynamic[x]] &}
{{x, 0}, Dynamic@customControl[#1] &}

And the following does not:

{{x, 0}, customControl[#1] &}

Why is that?

Manipulate does many things automatically. When an expression contains a variable declared in the Manipulate, it makes sure that the expression is wrapped in Dynamic. This happens anyway with the body of the Manipulate, but it also happens for controls. (User expressions other than controls that are formatted in the control area need to be wrapped in Dynamic by the programmer.) The first two specifications above that work explicitly contain Manipulate variables, x or y, and so they get wrapped in Dynamic. The third example is explicitly wrapped in Dynamic by the programmer.

The one that does not work does not contain a Manipulate variable and does not wrapped in Dynamic. Consequently, the front end does not update $CellContext`customControl$$ with its DynamicModule value. Therefore it is not evaluated.

One can discover evidence of this analysis by examining Typeset`specs$$ in the cell expression (menu command Cell > Show Expression). The following is from the first example, in which Dynamic wraps the whole function:

{{Hold[$CellContext`x$$], 0}, 
       Dynamic[$CellContext`customControl$$[#, $CellContext`y$$] & ]}

This is from the non-working example (no Dynamic):

{{Hold[$CellContext`x$$], 0}, $CellContext`customControl$$[#] & }

The working one suggests another way to get Manipulate to work:

{{x, 0}, Dynamic[customControl[#1] &]}

And indeed it does, though for some reason I don't like it.

The way I usually localize functions like customControl is completely within Manipulate, like this:

Manipulate[
 {x, 1, other},
 {{x, 0}, customControl[#] &},
 {{y, 0}, ControlType -> None},
 {other, 0, 1},
 {{customControl, customControl}, ControlType -> None},
 Initialization :> (customControl[Dynamic[x_]] := True;)]

This keeps everything inside a single DynamicModule. (An alternative is to forego Manipulate and construct one's own user-interface using DynamicModule.) Note the declaration:

{{customControl, customControl}, ControlType -> None},

The {customControl, customControl} initializes the symbol customControl to its undefined self. Omit it and it will be initialized to 0, and then the function definition in the Initialization code will fail. One could/should put Clear[customControl] in the initialization code instead (but that is not allowed on the Demonstrations site, hence my roundabout, kludgy habit).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.