Introduction
It appears to me that this might be a bug. I certainly cannot think of any other explanation, but I would be glad if there is one.
The issue is with ParametricPlot
, but I cannot explain why there should be a problem. Each Locator
is basically an EventHandler
that, when activated, tracks changes in position of the mouse and updates the coordinates of the Locator
accordingly. What seems to happen is that a mousedown in one Locator
activates all Locators
when the graphics includes a ParametricPlot
that depends on the Locator
points. This somehow causes all dynamic locators to be updated whenever one dynamic locator is dragged.
It does not appear to be a localization issue or a kernel vs. front end variable issue -- that is, putting variables in Module
or DynamicModule
did not help.
As shown in other answers, the issue does not occur with LocatorPane
, which creates a single event handler for the locators.
There is another issue in the OP's code. Since p
is not localized and is set (several times) inside a Dynamic
, there is continual updating.
One fix
Here is a fix of the OP's code that preserves the behavior of Locators
, in case that is preferred over the behavior of LocatorPane
.
Dynamic[With[{param = BezierPoint[t, ControlPoints]},
Show[
(* replace ParametricPlot *)
Graphics[Line[Table[param, {t, 0, 1, 1/100}]]],
(* localize p *)
Graphics[Table[With[{p = param}, {Text[t, p], Circle[p, 5]}], {t, 0, 1, 0.1}]],
Graphics[{
Line[ControlPoints[[1 ;; 2]]], Line[ControlPoints[[3 ;; 4]]],
Blue,
Locator[Dynamic[ControlPoints[[1]]]],
Locator[Dynamic[ControlPoints[[2]]]],
Locator[(*Dynamic@*)ControlPoints[[3]]],
Locator[(*Dynamic@*)ControlPoints[[4]]]}],
Axes -> None, AspectRatio -> Automatic,
PlotRange -> {{0, 400}, {0, 400}}]
]]
Another example and some evidence
Here is further evidence that the issue lies with ParametricPlot
. This example from the Locator
reference page works fine:
DynamicModule[{v1 = {2, 0}, v2 = {-1, 1}},
Dynamic @ Graphics[{Circle[], Red,
GeometricTransformation[Circle[], Transpose[{v1, v2}]], Green,
Line[{{0, 0}, v1}], Line[{{0, 0}, v2}], Locator[Dynamic[v1]],
Locator[Dynamic[v2]]}, PlotRange -> 3]]
But if we replace the circles with a ParametricPlot
, we get an example similar to the OP's, and the locators are linked as in the OP's.
DynamicModule[{v1 = {2, 0}, v2 = {-1, 1}},
Dynamic @ Show[
ParametricPlot[{{Cos[t], Sin[t]}, v1 Cos[t] + v2 Sin[t]}, {t, 0, 2 Pi}],
Graphics[{(*Circle[],Red,GeometricTransformation[Circle[],
Transpose[{v1,v2}]],*)
Green, Line[{{0, 0}, v1}], Line[{{0, 0}, v2}],
Locator[Dynamic[v1]], Locator[Dynamic[v2]]}],
Axes -> False, PlotRange -> 3
]]
The locators are still linked if we move the symbols outside ParametricPlot
and insert an evaluated parametrization:
DynamicModule[{v1 = {2, 0}, v2 = {-1, 1}},
Dynamic @ With[{param = v1 Cos[t] + v2 Sin[t]},
Show[
ParametricPlot[{{Cos[t], Sin[t]}, param}, {t, 0, 2 Pi}],
Graphics[{
Green, Line[{{0, 0}, v1}], Line[{{0, 0}, v2}],
Locator[Dynamic[v1]], Locator[Dynamic[v2]]}],
Axes -> False, PlotRange -> 3
]]]
Even if extract the Lines
from the ParametricPlot
, the locators are still linked.
DynamicModule[{v1 = {2, 0}, v2 = {-1, 1}},
Dynamic @ With[{plot =
ParametricPlot[{{Cos[t], Sin[t]}, v1 Cos[t] + v2 Sin[t]}, {t, 0, 2 Pi}]},
Graphics[{
Cases[plot, _Line, Infinity],
Green, Line[{{0, 0}, v1}], Line[{{0, 0}, v2}],
Locator[Dynamic[v1]], Locator[Dynamic[v2]]},
PlotRange -> 3
]]]
It happens with Plot
, too.
However, the locators work independently if I define the function,
SetAttributes[myParamPlot, HoldAll];
myParamPlot[param_, dom_] := Graphics[Line[Table[param, dom]]]
and replace ParametricPlot[..]
with myParamPlot[param, {t, 0, 1, 1/100}]
in the OP's example or with two calls to myParamPlot
, one for the circle and one for the transformed circle, in the modified doc. ctr. example.
The OP's approach seems reasonable to me, if Locator
is preferred to LocatorPane
. If LocatorPane
is acceptable, then the Manipulate
/DynamicModule
approaches of other answers do not have the unexpected pitfall that the OP encountered.