# Data Entry via 2D Graphic (formerly: Using a Slider2D to add data points to a list)

This bit of code sets up a list with the first entry already in it -- {{1,1}}:

Clear[x, y]
x = 1
y = 1
datalist = List[List[x, y]]


Here is a slider by which I can alter x and y by depressing the mouse:

Slider2D[{x, y}, {{0, 0}, {5, 8}, {1, 2}}]


But when I release the mouse button nothing happens of course, except that {x,y} are at some new value inside the slider.

Suppose I have moved the slider to location {3,6}. When I release the mouse button, I want {3,6} to be appended to datalist so it now becomes {{1,1},{3,6}}.

When I am done adding data points I want to save datalist.

How do I create this functionality with making as few changes/additions to the above code as possible?

-

## 4 Answers

Another way is to make use of the second argument of Dynamic. When given as a list of two functions, the first element of the second argument will be evaluated when the mouse is dragged, and the second one at the moment that the mouse is released, so in this case the the final value of the slider will be added to dataList.

pt = {1, 1};
dataList = {pt};
Slider2D[Dynamic[pt, {(pt = #) &, AppendTo[dataList, pt] &}],
{{0, 0}, {5, 8}, {1, 2}}]

-
+1 for reminding me to use the $f_{start}$ and $f_{end}$ arguments of Dynamic more often. –  István Zachar Jun 20 '12 at 8:11

Alternatively, you may use LocatorAutoCreate, which adds the oportunity of adding, moving and removing points "a piaccere":

DynamicModule[{pts = {{-1, 1}/2, {1, 1}/2}},
Column[{LocatorPane[Dynamic[pts], Framed@Graphics[{}], LocatorAutoCreate -> All],
Dynamic@pts}]]


Usage sample:

i = Import@ "http://worldmapsonline.com/images/OutlineMaps/Flags/Argentina2.jpg"
DynamicModule[{pts = {{-1, 1}/2, {1, 1}/2}},
LocatorPane[Dynamic[pts],
Show[{i, Graphics@Polygon@Dynamic@pts}, ImageSize -> {300, 300}],
LocatorAutoCreate -> All]]


-
+1 for the usage sample –  Rojo Jun 16 '12 at 22:58
@Rojo Somehow I knew I'll get at least one upvote b/c of that :) –  belisarius Jun 16 '12 at 23:00

This is a job for EventHandler:

EventHandler[
Slider2D[Dynamic[{x, y}], {{0, 0}, {5, 8}, {1, 2}}],
{"MouseUp" :> AppendTo[datalist, {x, y}]},
PassEventsDown -> True
]


Follow the data acquisition with a Dynamic:

Dynamic[datalist]


{{1,1},{3,4},{2,2},{2,4}}

PassEventsDown -> True is necessary to prevent EventHandler from eating up the MouseDrag events that are necessary to make the Slider2D move. To let Slider2D update x and y the Dynamic is necessary. This is well documented in the Slider2D documentation.

-

The following code is usable and does the trick, except it does not permit constraining entry points to specific values, for example even numbers on the horizontal axis (like years for example). Still, it does everything else, and also permits very flexible adjustment of the size and shape of the input space, so I think it is worth sharing. Instructions follow, and the code begins at the row of ================ signs

Instructions:
You can: add to and adjust data in pts which initially contains one point located at {0,0}. Then save the result by clicking the Button called "Press to Save Edited Data"

Detailed directions: 1--Drag the initial point, located at {0,0} , to where your first point should be. 2--To move a data point, drag it with left mouse button. 3--To add a datapoint you must use alt-click. 4--To remove a datapoint cover it and press alt-click. 5--Once the points are as you like them, press the Save Edited Data Button.

======================================= Remove[pts, newpts, numbrHgrdLns, vmax, vmin, disTweenHgrdLns, locsHgrdLns, numbrVgrdLns, hmax, hmin, disTweenVgrdLns, locsVgrdLns, i, j, imgSze, data, asPr]

Manipulate[Column[{ {"Number of horizontal gridlines: ", numbrHgrdLns = IntegerPart[(vmax - vmin)/disTweenHgrdLns]}; locsHgrdLns = vmin + Table[i disTweenHgrdLns, {i, 1, numbrHgrdLns}];

{"Number of vertical gridlines: ", numbrVgrdLns = IntegerPart[(hmax - hmin)/disTweenVgrdLns]};

locsVgrdLns = hmin + Table[j disTweenVgrdLns, {j, 1, numbrVgrdLns}];

ListPlot[{{{hmin, vmin}, {hmax, vmax}}, pts}, PlotRange -> {{hmin, hmax}, {vmin, vmax}}, PlotStyle -> Directive[Red, PointSize[.03]], GridLines -> {locsVgrdLns, locsHgrdLns}, GridLinesStyle -> {{Red, Thick}, {Orange, Thick}}, ImageSize -> imgSze, AspectRatio -> 2/asPr], Dynamic[newpts = pts]}],

{{vmax, 11, "Vertical max. of graph space: "}, FieldSize -> Tiny}, {{vmin, 0, "Vertical min. of graph space (Neg. value ok): "}, FieldSize -> Tiny}, {{disTweenHgrdLns, 1.000, "Distance between horizontal gridlines: "}, FieldSize -> Tiny}, {{hmax, 23, "Horizontal max. of graph space: "}, FieldSize -> Tiny}, {{hmin, 0, "Horiz. min. of graph space: "}, FieldSize -> Tiny}, {{disTweenVgrdLns, 2.000, "Distance between vertical gridlines: "}, FieldSize -> Tiny}, {{imgSze, 200, "Enlarge size of graph via slider: "}, 200, 2000},

{{asPr, 2, "Graph aspect ratio --make graph flatter/taller: "}, .5, 10},

{{pts, {{0, 0}}}, Locator, LocatorAutoCreate -> True}, ControlPlacement -> Top] pts Button["Press to Save Edited Data", Put[newpts, StringJoin[NotebookDirectory[], "savedDta.m"]]]

-