22

In R, there is a function locator which is like Matlab's ginput where you can click on the figure with a mouse and select any x,y coordinate. In addition, there is a function called identify(x,y) where if you give it a set of points x,y that you have plotted and then click on the figure, it will return the index of the x,y point which lies nearest (within an adjustable tolerance) to the location you have selected (or multiple indices, if multiple points are selected). Is there such a functionality in Matplotlib?

hatmatrix
  • 42,883
  • 45
  • 137
  • 231
  • 1
    FWIW: There's also `iselect()` in the `iplots` package (for R). This is a generalization: it involves linking and brushing. The same can be done via the `get(,'BrushData')` function in Matlab. – Iterator Nov 01 '11 at 18:29
  • Right, and Rggobi as well. But I was not aware of Matlab's capability for this -- last time I used it intensively was back in the days of version 6.5. Seems to have gotten fancy since then. – hatmatrix Nov 03 '11 at 10:09
  • 3
    Fancy and pricey. The cost of R has also tripled in the last decade, but it remains a bargain. :) – Iterator Nov 03 '11 at 12:24

4 Answers4

18

You may want to use a pick event :

fig = figure()
ax1 = fig.add_subplot(111)
ax1.set_title('custom picker for line data')
line, = ax1.plot(rand(100), rand(100), 'o', picker=line_picker)
fig.canvas.mpl_connect('pick_event', onpick2)

Tolerance set by picker parameter there:

line, = ax1.plot(rand(100), 'o', picker=5)  # 5 points tolerance
cyborg
  • 9,989
  • 4
  • 38
  • 56
  • 1
    Updated tutorial for [pick_event](https://matplotlib.org/stable/gallery/event_handling/pick_event_demo.html) – Dawierha Sep 20 '21 at 14:09
8
from __future__ import print_function
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from matplotlib.patches import Rectangle
from matplotlib.text import Text
from matplotlib.image import AxesImage
import numpy as np
from numpy.random import rand

if 1:
    fig, ax = plt.subplots()
    ax.set_title('click on points', picker=True)
    ax.set_ylabel('ylabel', picker=True, bbox=dict(facecolor='red'))
    line, = ax.plot(rand(100), 'o', picker=5)

    def onpick1(event):
        if isinstance(event.artist, Line2D):
            thisline = event.artist
            xdata = thisline.get_xdata()
            ydata = thisline.get_ydata()
            ind = event.ind
            print 'X='+str(np.take(xdata, ind)[0]) # Print X point
            print 'Y='+str(np.take(ydata, ind)[0]) # Print Y point

    fig.canvas.mpl_connect('pick_event', onpick1)
meduvigo
  • 1,523
  • 12
  • 7
  • 4
    If you import print function from future you have to add the brakets: print('X='+str(np.take(xdata, ind)[0])) – G M Apr 22 '16 at 09:38
7

Wow many years have passed! Now matplotlib also support the ginput function which has almost the same API as Matlab. So there is no need to hack by the mpl-connect and so on any more! (https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.ginput.html) For instance,

plt.ginput(4)

will let the user to select 4 points.

ch271828n
  • 15,854
  • 5
  • 53
  • 88
0

The ginput() is a handy tool to select x, y coordinates of any random point from a plotted window, however that point may not belong to the plotted data. To select x, y coordinates of a point from the plotted data, an efficient tool still is to use 'pick_event' property with mpl_connect as the example given in the documentation. For example:

import matplotlib.pyplot as plt 
import numpy as np
from numpy.random import rand

fig, ax = plt.subplots()
ax.plot(rand(100), rand(100), picker=3)
# 3, for example, is tolerance for picker i.e, how far a mouse click from
# the plotted point can be registered to select nearby data point/points.

def on_pick(event):
    global points
    line = event.artist
    xdata, ydata = line.get_data()
    print('selected point is:',np.array([xdata[ind], ydata[ind]]).T)

cid = fig.canvas.mpl_connect('pick_event', on_pick)

The last line above will connect the plot with the 'pick_event' and the corrdinates of the nearest plot points will keep printing after each mouse click on plot, to end this process, we need to use mpl_disconnect as:

fig.canvas.mpl_disconnect(cid)