datacathy
datacathy

Reputation: 135

Multiple pick events interfering

I have several data series scattered in a figure and want to be able to toggle annotations for them. The problem is, sometimes there are two pick events triggered (when the user clicks on a spot that is within both an annotation and a dot). The "annotation" pick event clears the annotation, but the "dot" pick event puts it right back, so the effect is the toggle doesn't work.

df = pd.DataFrame({'a': np.random.rand(25)*1000,
                   'b': np.random.rand(25)*1000,
                   'c': np.random.rand(25)})

def handlepick(event):
    artist = event.artist
    if isinstance(artist, matplotlib.text.Annotation):
        artist.set_visible(not artist.get_visible())
    else:
        x = event.mouseevent.xdata
        y = event.mouseevent.ydata
        if artist.get_label() == 'a':
            ann = matplotlib.text.Annotation('blue', xy=(x,y), picker=5)
        else: # label == 'b'
            ann = matplotlib.text.Annotation('red', xy=(x,y), picker=5)
        plt.gca().add_artist(ann)

plt.figure()
plt.scatter(data=df, x='a', y='c', c='blue', s='a', alpha=0.5, picker=5, label='a')
plt.scatter(data=df, x='b', y='c', c='red', s='b', alpha=0.5, picker=5, label='b')
plt.gcf().canvas.mpl_connect('pick_event', handlepick)
plt.show()

How can I separate the annotate and dot pick events and tell it not to annotate if the dot already has an annotation? I'm already using the labels to decide which scatter series is picked.

Thanks very much.

Upvotes: 3

Views: 519

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339052

You could create an annotation for every scatter point beforehands and set all of those invisible. A click on the scatterpoint would toggle visibility of the respective annotation. A click on the annotation would simply do nothing.

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

df = pd.DataFrame({'a': np.random.rand(25)*1000,
                   'b': np.random.rand(25)*1000,
                   'c': np.random.rand(25)})

def handlepick(event):
    artist = event.artist
    lab = artist.get_label()
    if lab in d:
        for ind in event.ind:
            ann = d[lab][ind]
            ann.set_visible(not ann.get_visible() )
    plt.gcf().canvas.draw()


plt.figure()
plt.scatter(data=df, x='a', y='c', c='blue', s='a', alpha=0.5, picker=5, label='a')
plt.scatter(data=df, x='b', y='c', c='red', s='b', alpha=0.5, picker=5, label='b')

d = {"a" : [], "b": []}
for i  in range(len(df)):
    ann = plt.annotate("blue", xy=(df["a"].iloc[i], df["c"].iloc[i]), visible=False)
    d["a"].append(ann)
    ann = plt.annotate("red", xy=(df["b"].iloc[i], df["c"].iloc[i]), visible=False)
    d["b"].append(ann)
plt.gcf().canvas.mpl_connect('pick_event', handlepick)
plt.show()

Upvotes: 2

Related Questions