## Extracting the coordinate of a particular point of interest from a ListPlot

19

13

Is there a way to obtain the coordinate of a point of interest in a ListPlot?

As an example, I have a list containing many sets of 2D coordinates and the plot drawn is discontinuous at one point (the first derivative is not continuous and the gradient increases suddenly).

Can I extract the location of that point interactively? Otherwise, I have to search through the list of data myself to determine the change of gradient, which defeats the whole purpose of drawing a plot. Also, using the Get Coordinates function from the right click menu does not give very accurate results.

22

### ListPlot accepts data wrappers besides Tooltip

(although I could not find any mention of this feature in the docs).

So, @Jens' method can be achieved without post-processing:

 data = Table[{Sin[n], Sin[2 n]}, {n, 50}];
ListPlot[PopupWindow[Tooltip[#], #] & /@ data]


On mouseover:

Click on a point:

Note: Thought this was a new feature added in Version-9, but as @Alexey Popkov noted it also works in version 8.0.4, so it has been around for some time.

Update: A simpler version of @Mr.Wizard's printTip can also be used as a wrapper directly inside ListPlot:

 ListPlot[Button[Tooltip@#, Print[#]] & /@ N@data]


Update 2: Collecting point coordinates:

 clicks = {};
Column[{ListPlot[Button[Tooltip@#, AppendTo[clicks, #]] & /@ N@data,
ImageSize -> 300],
"\n\t", Row[{"clicks = " , Dynamic[clicks // TableForm]}]}]


+1. It works in v.8.0.4 too. – Alexey Popkov – 2012-12-25T10:18:13.707

@Alexey, thanks for the vote. Perhaps, I should edit to remove the reference to version 9. – kglr – 2012-12-25T10:28:22.157

I had no idea this would work, from v7 no less. +1! – Mr.Wizard – 2012-12-25T11:05:25.007

1Although the Print method doesn't work in version 7: it prints to the Messages window which is why I had to resort to NotebookWrite. – Mr.Wizard – 2012-12-25T11:06:57.257

@Mr.Wizard I tested the Button function into DateListPlot instead of ListPlot and don't work. Some clue? Tooltip worked nice. – Murta – 2012-12-25T13:09:22.460

@Murta We're in undocumented territory here. The replacement rule (/.) methods should still work. – Mr.Wizard – 2012-12-25T13:40:26.353

@Murta, I tried several --Plot funtions; this seems to work only with ListPlot. – kglr – 2012-12-25T14:33:04.983

@kguler, I converted my DateListPlot into a ListPlot. Not so nice, but worked :) tks – Murta – 2012-12-25T14:35:36.283

I can't make your method work for anything but simple ListPlot with one data set. Try it with two sets, as in {data1, data2} and it doesn't seem to produce anything useful. – Jens – 2012-12-25T17:00:42.390

@Jens, both PopupWindow and Button work fine with ListPlot with multiple data sets, provided you add the extra layer of Map to push the wrapper to the level of individual data elements. Try, for example, ListPlot[Button[Tooltip@#, Print[#]] & /@ # & /@ {N@data1, N@data2}] or ListPlot[PopupWindow[Tooltip@#, #] & /@ # & /@ {N@data1, N@data2}] (Windows Vista 64b, version 9; haven't checked if it works the same way in version 8.0.4) – kglr – 2012-12-25T20:03:44.230

Yes, that works, but I like my own approach better. With your solution you have to use Map in different ways depending on the plot argument, whereas my rule works equally in all cases, without requiring Map at all (instead leveraging the internal mapping done by Tooltip). – Jens – 2012-12-25T20:12:31.173

I was mislead by the title of your answer. It suggests that it should be possible to replace Tooltip by PopupWindow[Tooltip@#, #]& in the standard command ListPlot[Tooltip[{data1, data2}]]. But that does not work. So maybe you should change the bold-face title because you're not really using a wrapper around all the data, as one would expect for Tooltip. – Jens – 2012-12-25T20:42:23.063

@Jens, I too like your approach better. Regarding "suggests that it should be possible to replace ...": please note that the wrappers are Mapped (.../@) to data even with a single data set. And, regarding "... not really using a wrapper around all the data": correct, but this is never claimed/implied anywhere in my post... Besides, wrappers can be "on individual data, datasets or collection of datasets" and not all wrappers are used "as one would expect for Tooltip". – kglr – 2012-12-25T22:53:37.233

@kguler - referring to the bit from update 2, would it be possible to add a checkbox to chose to add or remove the point from the list? or perhaps maybe right-click to remove? sorry for asking so much, but I thought it would be useful for many people seeing this question. – Vincent Tjeng – 2013-05-15T07:59:10.640

12

The answer by Mr. Wizard covers the built-in options, but one thing that you may be missing is that the tooltip alone isn't very convenient when it comes to recording the desired coordinates for later use. You'd have to read off the numbers and type them in again.

If you want to automate this process too, then you might be interested in the following:

data = Table[{Cos[n], Cos[2 n]}, {n, 50}];
ListPlot[Tooltip[data]] /.
Tooltip[x__] :> PopupWindow[Tooltip[x], Last[{x}]]


Here I appended a replacement rule to the ListPlot that attaches a PopupWindow to every single instance of a Tooltip that is found in the graphic. Since a separate Tooltip automatically wraps each generated point in the plot, we will now also get a PopupWindow for every point. The contents of the window is set to be the same as the tool tip content:

The window pops up when you click on the point of interest. From this window, you can textually copy the desired coordinate.

By the way, I put together a list of other coordinate-picking options here quite some time ago.

Edit

To make this post-processing really easy, just define a rule:

toolRule = Tooltip[x__] :> PopupWindow[Tooltip[x], Last[{x}]];


and apply it to any plot with Tooltips as

ListPlot[Tooltip[...]]/.toolRule


It's important to remember that ListPlot accepts lists of lists as argument, in order to plot separate point sets. My method works without change for that case, e.g., try

data2 = Table[{Cos[n], Cos[2 n]}, {n, 50}];
ListPlot[Tooltip[{data, data2}]] /. toolRule


In fact, it works for any expression containing Tooltips.

Edit 2

This solution is more robust than the one by kguler which relies on an undocumented feature apparently present only in ListPlot, which moreover has to be applied in different ways depending on the structure of the plot argument.

To illustrate the robustness, take a completely different example:

ContourPlot[
1/(1 + Cos[x - 1]^20) - 1/(1 + Cos[(y - 1)^2 + x^2]^20), {x, -2,
2}, {y, -2, 2}, ColorFunction -> ColorData["Rainbow"],
Contours -> {-.25, -.31, -.15, .1, .28, .38, .45},
PlotPoints -> 80] /. toolRule


Without making any changes to my answer whatsoever, I can use it to copy the contour values in this ContourPlot exactly the same way I did for the coordinates in the ListPlot, again leveraging the built-in Tooltip mapping done behind the scenes.

Edit 3: accumulating clicked points on the clipboard

I thought of another interesting extension of the above rule-based post-processing:

Click any number of points with a Tooltip, and get their coordinates as a list on the clipboard.

Here's how that can be done. The rule is defined first, then I show an example (you can change the name of the rule to something more cool, I was just... fooling around):

toolSpoolRule = Tooltip[t__] :> Button[Tooltip[t], CopyToClipboard[
First@
Append[Cases[NotebookGet[ClipboardNotebook[]],
TooltipBox[x_, "\"Clicked Points\"", ___] :>
Tooltip[Append[ToExpression[x], Last[{t}]],
"Clicked Points"], Infinity],
Tooltip[{Last[{t}]}, "Clicked Points"]]
]];

ListPlot[Tooltip@
Evaluate[
Table[N@Table[
p + Exp[-t/10] {Cos[t], Sin[t]}/2, {t, 0, 10, .5}], {p, {{.5,
0}, {1, 0}}}]], Joined -> True,
PlotMarkers -> Automatic] /. toolSpoolRule


Now click a bunch of points - nothing visible happens, except that the contents of your clipboard is silently growing. When you're done, press the paste keys, and you'll get something like this:

{{0.530442,0.429276},{0.329644,0.372235},{0.188034,0.233045},{1.5,0.}}

This gives you the freedom to insert the data you just collected at a location of your choosing.

Clearly this rule definition is more complex, but one nice thing about all these rules is that you define them only once. Then at a later point, you can apply them to any existing plots you may already have (as long as they use Tooltip), and make them interactive. The ability to do this without having to regenerate the plot can be quite useful if it takes a lot of computation to do so. And if you want popup windows instead of clipboard storage, just change the rule back to toolRule.

That's pretty slick. +1 – Mr.Wizard – 2012-12-25T07:52:32.203

@Mr.Wizard Thanks - and this works for Tooltips in all sorts of scenarios. – Jens – 2012-12-25T07:55:35.600

A bit shorter: ListPlot[Tooltip @ data] /. Tooltip :> (Tooltip@## ~PopupWindow~ #2 &) – Mr.Wizard – 2012-12-25T07:55:39.727

@Mr.Wizard Ah yes, your favorite notation. – Jens – 2012-12-25T07:56:47.363

9

Inspired by Jens' answer, here is a method that will print below the plot the coordinates of each point clicked.

printTip = Button[Tooltip@##,
SelectionMove[ButtonNotebook[], After, Cell];
NotebookWrite[ButtonNotebook[], ToBoxes@#2],
Appearance -> "Frameless"] &;

data = N @ Table[{Sin[n], Sin[2 n]}, {n, 50}];

ListPlot[Tooltip @ data] /. Tooltip -> printTip


Sure. There are a few ways to do this. You can use Tooltip:

ListPlot[Tooltip @ data]


Or you can use the Get Coordinates tool by right-clicking the graphic:

ListPlot @ data


When using this tool you will see a continuous coordinate tooltip, but you can also click (repeatedly) to mark points, then use Ctrl+C and Ctrl+V (Windows) to copy and paste these coordinates.

Thanks ToolTip is just what I want. – Gosere – 2012-12-25T07:19:02.133