6
$\begingroup$

I want to select a point on a graph and display a function of the coordinates value. Asking here a related question I learned to use Setting. Consider the example, where I display the coordinate x and its double 2*x:

Manipulate[
 xp = Dynamic[First[pt]];
 z = Setting[2*xp];
 Column[{
   Style[StringForm["x=`1`, z=`2`", xp, z], Blue, 16],
   LocatorPane[Dynamic[pt],
    ListPlot[{{0, 0}},
     Epilog -> {Red, PointSize[Large], Point[Dynamic[pt]]}
     ]]}, Center],
 {{pt, {0, 0}}, None}
 ]

By clicking on the graph, the value of x and z = 2*x is correctly displayed above the graph. However, one cannot move the Locator smoothly, each point must be clicked!

The problem is caused by Setting. By removing it, the point can be moved around smoothly, x is displayed dynamically but then the z is not calculated but displayed as 2 x. Is it possible to display the value of z without loosing the fluency in the point selection? Is there a different way to get the value of z without using Setting?

$\endgroup$
1
  • $\begingroup$ I think using Setting here may not be proper. According to documentation, Setting is used to extract the first argument of a control object. $\endgroup$
    – Silvia
    Commented Jun 18, 2013 at 16:49

3 Answers 3

6
$\begingroup$

To initialize and localize pt, you should use DynamicModule instead of Manipulate. Though I think using Setting in your code is not the best way to do what it does, however, the un-movable locator issue is NOT simply due to Setting but also because both Manipulate and LocatorPane are trying to dynamically set the value of pt, which is the control variable for both of them. So there is a conflict. The solution is simply stripping out Manipulate scope.

But there is more thing that should be noticed. Manipulate keeps ALL code in its body dynamical. If you strip it out, you'll have to make sure those expressions you expect to be dynamical (e.g. xp = Dynamic[First[pt]], z = Setting[2*xp] and StringForm["x=`1`, z=`2`", xp, z]) still be. The simplest way is to wrap them with Dynamic.

So a possible solution:

DynamicModule[{pt = {0, 0}, xp, z},
 Column[{
   Dynamic[
    xp = First[pt];
    z = 2*xp;
    Style[StringForm["x=`1`, z=`2`", xp, z], Blue, 16]
    ],
   LocatorPane[Dynamic[pt],
    ListPlot[{{0, 0}},
     Epilog -> {Red, PointSize[Large], Point[Dynamic[pt]]},
     PlotRange -> {{-1, 1}, {-1, 1}}, ImageSize -> 600]
    ]
   }, Center]
 ]

Just keep in mind that dynamical objects are merely codes which are evaluated on a "thread" called FrontEnd, which is parallel to the main kernel thread with some shared variables.

Edit:

It seems the problem is indeed caused by conflicts among Setting, Manipulate and dynamical controller in Manipulate all together.

(I completely agree with Michael E2's explanation, so please forget what I said here. Nevertheless, I still suggest people using DynamicModule for complicated UI constructions!)

Interestingly, if we wrap the standalone y with Dynamic, the "freeze" disappears. This workaround also stands for OP's code. So we can simply write this:

Manipulate[
 xp = Dynamic[First[pt]];
 z = Setting[2*xp];
 Column[{
   Style[StringForm["x=`1`, z=`2`", Dynamic[xp], Dynamic[z] ], Blue, 16],
   LocatorPane[Dynamic[pt],
    ListPlot[{{0, 0}},
     Epilog -> {Red, PointSize[Large], Point[Dynamic[pt]]}
     ]]}, Center],
 {{pt, {0, 0}}, None}
 ]

However one should be aware this method is not as efficient as the DynamicModule solution at the beginning of this answer.

Conclusion:

In general, I suggest people always avoiding using Setting inside Manipulate.

$\endgroup$
7
  • $\begingroup$ Thanks a lot! Your solution is simple, elegant and does work, so I will use it. However, I am still not sure I understand. When in my example I remove Setting, there seems to be no conflict between Manipulate and LocatorPane. The pt coordinates are OK and only 'z' is wrong. What seems to be crucial is having the calculation of xp, z, and the text string within the same Dynamic wrap. I took your code and changed DynamicModule back to Manipulate and it works perfectly as well! $\endgroup$ Commented Jun 18, 2013 at 18:51
  • $\begingroup$ @MarekPfutzner Thanks. Yes you're right. There is something more here. Though I'm not quite sure what it is right now... $\endgroup$
    – Silvia
    Commented Jun 18, 2013 at 19:40
  • $\begingroup$ @MarekPfutzner Please see my edit. I think generally one should avoid using Setting inside Manipulate. $\endgroup$
    – Silvia
    Commented Jun 18, 2013 at 20:56
  • $\begingroup$ Thanks again! I will try to switch into DynamicModule. $\endgroup$ Commented Jun 19, 2013 at 9:23
  • $\begingroup$ @MarekPfutzner You're welcome.:) I suggest always to construct the interface manually if it's supposed to be complex. $\endgroup$
    – Silvia
    Commented Jun 19, 2013 at 9:28
4
$\begingroup$

Your code is very close to correct. I would like to point out some simple changes will put it into a more concise form that still gives everything you wanted.

Manipulate[
  Column[{
    Dynamic[xp = First[pt]; z = 2*xp; 
      Style[Row[{xp, "  ", z}], Blue, 16]], 
    LocatorPane[Dynamic[pt], ListPlot[{{0, 0}}],
      Appearance -> Graphics@{Red, PointSize[Large], Point[{0, 0}]}]},
    Center],
  {{pt, {0, 0}}, None}]

red_locator.png

Beside the changes involving Dyanamic and Setting already discussed by Silvia, note the following:

  1. Epilog has been eliminated. It has been replaced by the Appearance option of LocatorPane, which is intended to be used to customize the appearance of a locator.

  2. StringForm has been replaced by Row, which is a newer Mathematica feature, much more versatile than StringForm and something you should be acquainted with.

$\endgroup$
2
  • 1
    $\begingroup$ +1 for Appearance. btw I think Appearance -> Graphics@{Red,PointSize[Large],Point[{0,0}]} would be sufficient. $\endgroup$
    – Silvia
    Commented Jun 20, 2013 at 21:21
  • $\begingroup$ @Silvia. Thanks for pointing that out. I made an edit incorporating your improvement. $\endgroup$
    – m_goldberg
    Commented Jun 21, 2013 at 8:31
2
$\begingroup$

I do not think the problem is with Setting. However, one can avoid using Setting, unless for some reason the variable it depends on is unaccessible (a local variable created by a function call, inside a Module say).

Simplest fix to the OP's code

Put Dynamic@ in front of Setting:

Manipulate[
 xp = Dynamic[First[pt]];
 z = Dynamic@Setting[2*xp];
 Column[{Style[StringForm["x=`1`, z=`2`", xp, NumberForm[z, 3]], Blue, 16],
   LocatorPane[Dynamic[pt], 
    ListPlot[{{0, 0}}, Epilog -> {Red, PointSize[Large], Point[Dynamic[pt]]}]]}, Center],
 {{pt, {0, 0}}, None}]

The way I might do it

f[{x_, y_}] := 2 x;
Manipulate[
 Column[{
   Dynamic@Style[StringForm["x=`1`, z=`2`", NumberForm[First[pt], 3],  NumberForm[f[pt], 3]],
          Blue, 16],
   LocatorPane[Dynamic[pt], 
    ListPlot[{{0, 0}}, 
     Epilog -> {Red, PointSize[Large], Point[Dynamic[pt]]}]]}, Center],
 {{pt, {0, 0}}, None},
 SaveDefinitions -> True]

I used a generic f as a placed holder for an arbitrary function; SaveDefinitions -> True makes the definition of f be saved in the DynamicModule created by Manipulate. I also used NumberForm to control how many decimals show up. I might use the Appearance option the way @m_goldberg does, too. Whatever you might think of these alterations, I would avoid using Setting.

Some explanation

The original code has some constructs that make it a little complicated to understand with respect to dynamic updating. Nominally the body contains the symbols xp, z, and of course pt, all of which will be tracked. However Dynamic[expr] effectively shields variables in expr, which I can perhaps explain most easily by an example from the code. The expression xp = Dynamic[pt] does not depend on pt. If pt changes value, the expression inside Dynamic will be updated, but expressions outside of Dynamic will not be updated (unless for other reasons an update is called for). In this case the expression inside Dynamic is simply pt, and I wouldn't be surprised if it is not updated at all, since such expressions are common and have no effect.

Now if we consider the code carefully, we see that all the symbols pt appear inside Dynamic, except the expression for z. For z, we have Setting[2 * xp], which translates into 2 * First[pt], without Dynamic. Therefore the body of Manipulate depends on pt and will be updated when the Locator for pt is moved. This causes a new column with a new LocatorPane and Locator to be created, and it replaces the old one. Thus the dragging of the Locator by the mouse is interrupted and stopped.

Now if we remove Setting, we see that all the symbols pt appear inside Dynamic. The variable z now equals 2 * Dynamic[First[pt]]. Therefore the body of Manipulate does not depend on pt, and the body will never be updated. In particular, the line z = 2 * xp is executed only once, when Manipulate first starts up.

In the "simplest fix" above, the variable becomes basically equivalent to Dynamic[2 * First[pt]]. While z is never updated, the inside of the Dynamic, that is, 2 * First[pt], is updated whenever the Locator moves.

Thus there does not seem to be any special problem with using Manipulate here. The main difference between Manipulate and DynamicModule is that Manipulate, while it creates a DynamicModule, does a number of things automatically for you, which can be either convenient or frustrating. DynamicModule allows greater control over things, you have to set everything up yourself, but you get to set it up the way you like.

$\endgroup$
1
  • $\begingroup$ +1 You're absolutely right! Why I didn't try Manipulate[{y, Slider[Dynamic[y]]}, {x, 0, 1}]! $\endgroup$
    – Silvia
    Commented Jun 21, 2013 at 9:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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