Событие выбора Matplotlib из нескольких серий

Я делаю диаграмму рассеяния, где я хочу щелкнуть отдельные точки, чтобы что-то сделать. Это похоже на существующий пример кода.

https://matplotlib.org/examples/event_handling/pick_event_demo.html

Я реализовал метод on_pick

def on_pick(event):
    ind = event.ind
    for i in ind:
        ...do something here with blue or red data...

Однако я застрял, потому что я помещаю несколько серий (красный и синий) в один и тот же сюжет.

fig, ax = plt.subplots()
ax.set_title('click on a point...')
line, = ax.plot(red_xs, red_ys, 'o', picker=5, color='red') 
line, = ax.plot(blue_xs, blue_ys, 'o', picker=5, color='blue')  

Event.ind представляет собой набор целых чисел. Они являются индексами в серии. Однако, по-видимому, нет способа определить, к какой серии они относятся.

Должен быть способ сделать это. Кто-нибудь знает трюк?

Спасибо, Питер.


person opus111    schedule 10.08.2017    source источник


Ответы (2)


Вот решение, которое я нашел. Это кажется неуклюжим, но, возможно, это лучший.

Написав «настраиваемый сборщик», можно добавить к событию метаданные. Здесь я добавляю "инд" и "серия"

def picker(self,line,mouseevent,series):
    if mouseevent.xdata is None:
        return False, dict()
    xdata = line.get_xdata()
    ydata = line.get_ydata()
    maxd = 0.05
    d = np.sqrt((xdata - mouseevent.xdata) ** 2. + (ydata - mouseevent.ydata) ** 2.)

    ind = np.nonzero(np.less_equal(d, maxd))
    if len(ind):
        props = dict(ind=ind, series=series)
        return True, props
    else:
        return False, dict()

Затем к каждому точечному графику можно прикрепить разные «настраиваемые средства выбора».

    line, = ax.plot(self.red['False'], self.red['True'], 'o', picker=lambda line,mouseevent: self.picker(line,mouseevent,self.red), color='red')
    line, = ax.plot(self.blue['False'], self.blue['True'], 'o', picker=lambda line,mouseevent: self.picker(line,mouseevent,self.blue), color='blue')

А затем извлеките метаданные в функции on_pick().

fig.canvas.mpl_connect('pick_event', lambda e: self.on_pick(e))

...

def on_pick(self,event):
    for i in event.ind:
        for j in i:
            series = event.series
            ...do something with item j of series...
person opus111    schedule 11.08.2017

pick_event_demo, на который вы ссылаетесь, действительно говорит вам, как узнать, какая строка является какой. Это говорит

thisline = event.artist
xdata = thisline.get_xdata()
ydata = thisline.get_ydata()
ind = event.ind

Таким образом, ind будет индексировать все, что есть thisline.

Чтобы привести более подробный пример

line1, = ax.plot(self.red['False'], self.red['True'], 'o', picker=5, color='red') 
line2, = ax.plot(self.blue['False'], self.blue['True'], 'o', picker=5, color='blue') 

dic = {line1 : self.red, line2 : self.blue}

def on_pick(self,event):
    series = dic[event.artist]
    # do something with series
    for i in event.ind:
         print(series[i])


fig.canvas.mpl_connect('pick_event', on_pick)
person ImportanceOfBeingErnest    schedule 10.08.2017
comment
Спасибо ИОБЕ. Я думаю, что я не был ясен в своем вопросе. Мне нужно прикрепить дополнительные метаданные к событию, в моем случае это кадр данных Pandas, который сгенерировал x и y. Я нашел один способ сделать это. Может быть, вы знаете лучший способ. - person opus111; 11.08.2017
comment
Если ваше решение работает, это нормально. Я хотел сказать, что у вас уже есть данные, доступные как xdata и ydata внутри функции on_pick. Если вместо этого вам нужны исходные данные, вы можете использовать простое сопоставление исполнителя с исходными данными. Я обновил ответ, чтобы показать, как это можно сделать. - person ImportanceOfBeingErnest; 12.08.2017
comment
Это хороший ответ, event.artist фактически показывает, в какой серии вызывается событие. - person Long Le; 06.09.2018