4

I have a scatter plot that is composed of different calls for scatter:

import matplotlib.pyplot as plt
import numpy as np

def onpick3(event):
    index = event.ind
    print '--------------'
    print index
    artist = event.artist
    print artist

fig_handle = plt.figure()

x,y = np.random.rand(10),np.random.rand(10)
x1,y1 = np.random.rand(10),np.random.rand(10)

axes_size = 0.1,0.1,0.9,0.9
ax = fig_handle.add_axes(axes_size)

p = ax.scatter (x,y, marker='*', s=60, color='r', picker=True, lw=2)
p1 = ax.scatter (x1,y1, marker='*', s=60, color='b', picker=True, lw=2)

fig_handle.canvas.mpl_connect('pick_event', onpick3)
plt.show()

I'd like the points to be clickable, and get the x,y of the selected indexes. However since scatter is being called more than once, I get the same indexes twice, so I cant use x[index] inside the onpick3 method

Is there a straightforward way to get the points?

It seems that event.artist gives back the same PathCollection that is given back from scatter (p and p1 in this case). But I couldn't find any way to use it to extract the x,y of the selected indexes Tried using event.artist.get_paths() - but it doesn't seem to be giving back all the scatter points, but only the one that I clicked on..so I'm really not sure what event.artist is giving back and what are the event.artist.get_paths() function is giving back

EDIT

it seems that event.artist._offsets gives an array with the relevant offsets, but for some reason when trying to use event.artist.offsetsI get

AttributeError: 'PathCollection' object has no attribute 'offsets'

(although if I understand the docs, it should be there)

1 Answer 1

5

To get the x, y coordinates for the collection that scatter returns, use event.artist.get_offsets() (Matplotlib has explicit getters and setters for mostly historical reasons. All get_offsets does is return self._offsets, but the public interface is through the "getter".).

So, to complete your example:

import matplotlib.pyplot as plt
import numpy as np

def onpick3(event):
    index = event.ind
    xy = event.artist.get_offsets()
    print '--------------'
    print xy[index]


fig, ax = plt.subplots()

x, y = np.random.random((2, 10))
x1, y1 = np.random.random((2, 10))

p = ax.scatter(x, y, marker='*', s=60, color='r', picker=True)
p1 = ax.scatter(x1, y1, marker='*', s=60, color='b', picker=True)

fig.canvas.mpl_connect('pick_event', onpick3)
plt.show()

However, if you're not varying things by a 3rd or 4th variable, you may not want to use scatter to plot points. Use plot instead. scatter returns a collection that's much more difficult to work with than the Line2D that plot returns. (If you do go the route of using plot, you'd use x, y = artist.get_data().)

Finally, not to plug my own project too much, but if you might find mpldatacursor useful. It abstracts away a lot of you're doing here.

If you decide to go that route, your code would look similar to:

Sign up to request clarification or add additional context in comments.

3 Comments

thanks! I don't know how I missed that in the documentation.Actually mpldatacursor seems very nice, but I couldn't find how to two things: 1. when I have two adjacent points and I click I see only one [I'd like to know how many points are there]. 2. sometimes I'd like to save the figure, but I couldn't find how to remove the annotation after clicking on it.
@nopede11 - Sorry I didn't reply before now! 1) To display the number of points, use something like datacursor(formatter=lambda **kwargs: len(kwargs['ind'])) (that won't display the x,y position, but it's easy to modify the formatter function to display x,y as well). 2) With the latest version, just hit the "d" key on the keyboard to hide the annotation boxes. Thanks!
For 3-dimensional scatter plots, is there a way to get the z data as well?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.