Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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.

share|improve this question
add comment

3 Answers

up vote 16 down vote accepted

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

share|improve this answer
    
+1. It works in v.8.0.4 too. –  Alexey Popkov Dec 25 '12 at 10:18
    
@Alexey, thanks for the vote. Perhaps, I should edit to remove the reference to version 9. –  kguler Dec 25 '12 at 10:28
    
I had no idea this would work, from v7 no less. +1! –  Mr.Wizard Dec 25 '12 at 11:05
1  
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. –  Mr.Wizard Dec 25 '12 at 11:06
    
@Mr.Wizard I tested the Button function into DateListPlot instead of ListPlot and don't work. Some clue? Tooltip worked nice. –  Murta Dec 25 '12 at 13:09
show 9 more comments

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.

share|improve this answer
    
Thanks ToolTip is just what I want. –  Sheng Dec 25 '12 at 7:19
add comment

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.

share|improve this answer
    
That's pretty slick. +1 –  Mr.Wizard Dec 25 '12 at 7:52
    
@Mr.Wizard Thanks - and this works for Tooltips in all sorts of scenarios. –  Jens Dec 25 '12 at 7:55
    
A bit shorter: ListPlot[Tooltip @ data] /. Tooltip :> (Tooltip@## ~PopupWindow~ #2 &) –  Mr.Wizard Dec 25 '12 at 7:55
    
@Mr.Wizard Ah yes, your favorite notation. –  Jens Dec 25 '12 at 7:56
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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