Matplotlib / python clickable points

19,819

Solution 1

To expand on what @tcaswell said, see the documentation here: http://matplotlib.org/users/event_handling.html

However, you might find a quick demo of pick events useful:

import matplotlib.pyplot as plt

def on_pick(event):
    artist = event.artist
    xmouse, ymouse = event.mouseevent.xdata, event.mouseevent.ydata
    x, y = artist.get_xdata(), artist.get_ydata()
    ind = event.ind
    print 'Artist picked:', event.artist
    print '{} vertices picked'.format(len(ind))
    print 'Pick between vertices {} and {}'.format(min(ind), max(ind)+1)
    print 'x, y of mouse: {:.2f},{:.2f}'.format(xmouse, ymouse)
    print 'Data point:', x[ind[0]], y[ind[0]]
    print

fig, ax = plt.subplots()

tolerance = 10 # points
ax.plot(range(10), 'ro-', picker=tolerance)

fig.canvas.callbacks.connect('pick_event', on_pick)

plt.show()

Exactly how you approach this will depend on what artist you're using (In other words, did you use ax.plot vs. ax.scatter vs. ax.imshow?).

Pick events will have different attributes depending on the artist selected. There will always be event.artist and event.mouseevent. Most artists that have individual elements (e.g. Line2Ds, Collections, etc) will have a list of the index of the items selected as event.ind.

If you'd like to draw a polygon and select points inside, see: http://matplotlib.org/examples/event_handling/lasso_demo.html#event-handling-example-code-lasso-demo-py

Solution 2

If in case you want to bind extra property to your artist object, for example you are plotting IMDB ratings of several movies, and you want to see by clicking on a point which movie it corresponds to, you can do that by adding a custom object to the point that you plotted, like this:

import matplotlib.pyplot as plt

class custom_objects_to_plot:
    def __init__(self, x, y, name):
        self.x = x
        self.y = y
        self.name = name

a = custom_objects_to_plot(10, 20, "a")
b = custom_objects_to_plot(30, 5, "b")
c = custom_objects_to_plot(40, 30, "c")
d = custom_objects_to_plot(120, 10, "d")

def on_pick(event):
    print(event.artist.obj.name)

fig, ax = plt.subplots()
for obj in [a, b, c, d]:
    artist = ax.plot(obj.x, obj.y, 'ro', picker=5)[0]
    artist.obj = obj

fig.canvas.callbacks.connect('pick_event', on_pick)

plt.show()

Now when you click one of the points on the plot, the name property of the corresponding object will be printed.

Share:
19,819
intl
Author by

intl

Updated on June 18, 2022

Comments

  • intl
    intl almost 2 years

    I have a bunch of time series data with points every 5 seconds. So, I can create a line plot and even smooth the data to have a smoother plot. The question is, is there any way in matplotlib or anything in python that will allow me to click on a valid point to do something? So, for example, I would be able to click on (10, 75) if that datum exists in my original data and then I would be able to do something in Python.

    Any thoughts? Thanks.

  • Admin
    Admin over 5 years
    I am getting the following error: x, y = artist.get_xdata(), artist.get_ydata() AttributeError: 'PathCollection' object has no attribute 'get_xdata'