Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a LocatorPane within a Manipulate such that the range of the plot behind the Locator can vary. When it does, this naturally causes the Locator to move on-screen to remain at a constant position with respect to the plot data. However, for my purposes, I need to prevent it from doing that. Ideally, it should stay at the same spot on-screen when the plot range is changed.

Here's a minimal example of the situation. Dragging the slider causes the Locator to move on-screen. Calculating the approximate position of the Locator as a fraction of the total plot size is easy, and a Dynamic displaying that is included. As mentioned in the Manipulate code, that value will ideally not change when the plot range is modified.

(* I need "point" (the locator's position) to always remain at the
   same position on-screen when end is changed. *)
Manipulate[
    Row[{
        LocatorPane[
            Dynamic[point],
            Plot[x, {x, 0, end}, ImageSize -> 400]
        ],
        "This value should change ONLY when the Locator is dragged: ",
        Dynamic[point / end]
    }],
    {end, 1, 2}
]

Notes:

  • Using a Locator directly or via a Manipulate control is not allowed -- the locator must come from a LocatorPane. (Reason: I also need to be able to restrict the Locator to a certain rectangular region, and doing that with a raw Locator is possible but relatively slow.)
  • Preventing the range of the plot within the LocatorPane from changing is also impossible (although wrapping it in another plot somehow is fine, if that is possible and helps).
  • Using intermediate variables is fine: my attempts to solve the problem thus far have mainly involved separate abspt and relpt (absolute/relative point position) variables.

I have a feeling that there's some clever way to accomplish this with Dynamic, but I'm not familiar enough with Dynamic to know how.

share|improve this question
up vote 0 down vote accepted

Using the same logic as Edmund in his answer.

Manipulate[
  Row[{
   LocatorPane[
    Dynamic[point],
    Plot[x, {x, 0, end}, ImageSize -> 400]],
   "This value should change ONLY when the Locator is dragged: ", 
   Dynamic[point/end]}], 
  {{point, {0.5, 0.5}}, None}, {{scaledPoint, {0.5, 0.5}}, None}, 
  {end, 1, 2, 
   TrackingFunction :> {(scaledPoint = point/end; &), 
    (end = #; point = end*scaledPoint; &), None}}]

outGIF

share|improve this answer

You may use the function evaluation syntax of Manipulate.

Manipulate[
 Row[{LocatorPane[Dynamic[point], 
    Plot[x, {x, 0, end}, ImageSize -> 400]], 
   "This value should change ONLY when the Locator is dragged: ", 
   Dynamic[point/end]}],
 Row[{Slider[Dynamic[end, {(ss = point/end;) &, (end = #; point = end ss) &}], {1, 2}]}],
 Initialization :> {point = {1, 1};}
]

From the documentation for LocatorPane:

For a Graphics object g, LocatorPane[pt,g] by default takes the range of coordinates for pt to be the range of graphics coordinates corresponding to PlotRange in g.

We can get around this. The Dynamic for end in Slider captures the scaled position of the Locator at the start of moving the slider. Then, as it is moved it updates point to the new scaled position. In the case were the x- and y-axis plot range changes non-linearly and/or at different rates you will need to account for this in your rescaling.

Hope this helps.

share|improve this answer
    
Thank you for your answer! Unfortunately, this causes recursion errors on a fresh kernel session until the locator is first dragged: image 1 , image 2 . Also, the Slider no longer seems to slide smoothly, even with ContinuousAction -> True explicitly set. Can these issues be worked around? (I'm writing a Wolfram Demonstration submission, so I need everything to work as smoothly as possible.) – KevinS May 26 at 3:04
    
@KevinS Initialize point to stop recursion error in fresh kernel. See update. – Edmund May 26 at 11:59

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.