4
$\begingroup$

I would like to add a Locator to a figure displayed by Manipulate when I click inside the figure, at the location where I click, and to have this trigger an update of the figure. I would also like to have clicking on an existing Locator remove it, and dragging a locator reposition it (again, redrawing the figure in response in each case).

For (a silly) example, I would like clicking anywhere in the region displayed by

With[{locs = {}}, 
 Manipulate[Graphics[Text[locs, {0, 0}], PlotRange -> 2],
  {{q, {1, 1}}, Locator, 
   Appearance -> Graphics[{Green, Disk[{0, 0}, .1]}, ImageSize -> 10]},
  {{p, locs}, Locator, 
   Appearance -> Graphics[{Red, Disk[{0, 0}, .1]}, ImageSize -> 10]}]]

to add the corresponding Point to locs, and for clicking on any p Locator to remove it from locs, with the text, updating accordingly in response to additions, deletions or repositionings of a Locator.

To make things hard, I have another locator q that needs to coexist with the one to which I would like to add/remove; and p and q have different appearances.

$\endgroup$
  • $\begingroup$ Check the docs for LocatorAutoCreate. $\endgroup$ – kglr Apr 9 '14 at 22:17
  • $\begingroup$ @kguler: Good suggestion, but I actually have another locator in the Manipulate that seems to "get in the way": nothing happens when I click, even with LocatorAutoCreate -> All. $\endgroup$ – orome Apr 9 '14 at 22:48
  • 1
    $\begingroup$ Seen this Q/A? $\endgroup$ – kglr Apr 9 '14 at 23:02
  • $\begingroup$ @kguler: I've asked to have this reopened. The linked question does not, in fact, answer this one: how do I add (remove) Locators by clicking on the location where I want the locator (of the locator I want to remove)? I should have thought that (and not adding at random locations, or removing the last-added Locator) was implicit. $\endgroup$ – orome Apr 10 '14 at 13:32
  • 1
    $\begingroup$ voted to reopen. $\endgroup$ – kglr Apr 10 '14 at 13:35
2
$\begingroup$

I would approach the overall goal of the program in a different way that avoids the limitations* of Manipulate. I would store a list of all the locators in one variable, with the permanent locator(s) at the beginning of the list. The transient locators can be added and removed with ALT+click. The permanent locators are maintained by the option of the form LocatorAutoCreate -> min, where min is the number of permanent locators.

Using With to assign symbols to represent the parts of the list locs of locators seems slightly inelegant, but overall the approach has the advantage of being simple.

Manipulate[
 With[{q = locs[[1]], p = Drop[locs, 1]}, 
  Graphics[Text[locs, {0, 0}], PlotRange -> 2]
  ],
 {{locs, {{1, 1}}}, Locator, LocatorAutoCreate -> 1}
 ]

*Limitation: When several Locator controls, p, q, ..., appear in a Manipulate, a LocatorPane is created of the form

LocatorPane[Dynamic[{p, q, ...}], ...]

The option LocatorAutoCreate can be passed to the LocatorPane; however, it does not work because the length of the list {p, q, ...} cannot be changed.


Update: Appearance

The appearance of the locators may be controlled in two ways. The documented, and hence common, solution is to use invisible locators and insert graphics primitives into the Graphics:

Manipulate[
 With[{q = locs[[1]], p = Drop[locs, 1]}, 
  Graphics[{
    Text[locs, {0, 0}],
    Locator[q], {Red, PointSize[Large], Point[p]},
   PlotRange -> 2]
  ],
 {{locs, {{1, 1}}}, Locator, LocatorAutoCreate -> 1}
 ]

Another way is to use the option setting

Appearance -> {Automatic, Graphics[{Red, Disk[]}, ImageSize -> 10]}

The last specification is repeated when there are more than two locators, a behavior that I could not find documented.

$\endgroup$
  • $\begingroup$ I've been balking at the complex solutions and had settled on exactly this as a possible approach. $\endgroup$ – orome Apr 10 '14 at 12:03
  • $\begingroup$ It looks like I'm stuck with a single Appearance with this approach. Is that correct? The first and rest need to look different. $\endgroup$ – orome Apr 10 '14 at 13:15
  • 1
    $\begingroup$ @raxacoricofallapatorius No, you can set Appearance -> None and use Locator[q], {Red, Point[p]} inside the graphics. You might be able to use a different setting for appearance, but I'm not where I can check at this time. $\endgroup$ – Michael E2 Apr 10 '14 at 13:34
  • 1
    $\begingroup$ @raxacoricofallapatorius It also turns out that you can use another setting for Appearance. See update. :) $\endgroup$ – Michael E2 Apr 12 '14 at 13:17
  • $\begingroup$ Excellent, thanks for the follow up. I tired that earlier and couldn't get it to work; I must have mistyped. $\endgroup$ – orome Apr 12 '14 at 14:32
3
$\begingroup$

As kguler points out, this question appears to have be treated previously here. However, jVincent's answer only treats the case of adding additional locators. Here is an example that where locators can be both added and deleted.

SetAttributes[canDelete, HoldFirst]
canDelete[locatorGroup_Symbol] :=
  Switch[locatorGroup,
    {}, False,
    {_}, Unevaluated@locatorGroup = {}; False,
    {__}, Unevaluated@locatorGroup = Most[locatorGroup]; True]

DynamicModule[{black = {}, red = {}, deleteQ},
  deleteQ["black"] = False;
  deleteQ["red"] = False; 
  Grid[{
    {Framed[
       Graphics[{
         Dynamic[
           With[{i = #}, Locator[Dynamic[black[[i]]], Style[\[FilledSquare], Black]]] &
             /@ Range@Length@black], 
         Dynamic[
           With[{i = #}, Locator[Dynamic[red[[i]]], Style[\[FilledCircle], Red]]] &
             /@ Range@Length@red]},
      PlotRange -> {{0, 1}, {0, 1}}]], 
    SpanFromLeft}, 
   {Button["Add Black", AppendTo[black, RandomReal[1, 2]]; deleteQ["black"] = True], 
    Button["Add Red", AppendTo[red, RandomReal[1, 2]]; deleteQ["red"] = True]},
   {Dynamic[Button["Delete Black", deleteQ["black"] = canDelete[black], 
              Enabled -> deleteQ["black"]]],
    Dynamic[Button["Delete Red", deleteQ["red"] = canDelete[red], 
              Enabled -> deleteQ["red"]]]}}]]

two-locator-groups

$\endgroup$
  • $\begingroup$ Note that this does not really answer the question, since the whole point of adding locators is that they appears where I click, not in some Random location (likewise for removing). I would have thought this was implicit. $\endgroup$ – orome Apr 10 '14 at 13:28

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.