20
$\begingroup$

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.

$\endgroup$

3 Answers 3

22
$\begingroup$

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]

enter image description here

On mouseover:

enter image description here

Click on a point:

enter image description here

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]

enter image description here

Update 2: Collecting point coordinates:

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

enter image description here

$\endgroup$
14
  • $\begingroup$ +1. It works in v.8.0.4 too. $\endgroup$ Dec 25, 2012 at 10:18
  • $\begingroup$ @Alexey, thanks for the vote. Perhaps, I should edit to remove the reference to version 9. $\endgroup$
    – kglr
    Dec 25, 2012 at 10:28
  • $\begingroup$ I had no idea this would work, from v7 no less. +1! $\endgroup$
    – Mr.Wizard
    Dec 25, 2012 at 11:05
  • 1
    $\begingroup$ Although the Print method doesn't work in version 7: it prints to the Messages window which is why I had to resort to NotebookWrite. $\endgroup$
    – Mr.Wizard
    Dec 25, 2012 at 11:06
  • $\begingroup$ @Mr.Wizard I tested the Button function into DateListPlot instead of ListPlot and don't work. Some clue? Tooltip worked nice. $\endgroup$
    – Murta
    Dec 25, 2012 at 13:09
12
$\begingroup$

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:

popupwindow

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

contour plot

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

spirals

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.

$\endgroup$
4
  • $\begingroup$ That's pretty slick. +1 $\endgroup$
    – Mr.Wizard
    Dec 25, 2012 at 7:52
  • $\begingroup$ @Mr.Wizard Thanks - and this works for Tooltips in all sorts of scenarios. $\endgroup$
    – Jens
    Dec 25, 2012 at 7:55
  • $\begingroup$ A bit shorter: ListPlot[Tooltip @ data] /. Tooltip :> (Tooltip@## ~PopupWindow~ #2 &) $\endgroup$
    – Mr.Wizard
    Dec 25, 2012 at 7:55
  • $\begingroup$ @Mr.Wizard Ah yes, your favorite notation. $\endgroup$
    – Jens
    Dec 25, 2012 at 7:56
9
$\begingroup$

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

Mathematica graphics


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

ListPlot[Tooltip @ data]

Mathematica graphics

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

ListPlot @ data

Mathematica graphics

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.

$\endgroup$
1
  • $\begingroup$ Thanks ToolTip is just what I want. $\endgroup$
    – Gosere
    Dec 25, 2012 at 7:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.