Интерактивно добавлять и удалять точки разброса в matplotlib

Вот проблема, которую я хотел бы решить: Я хотел бы иметь возможность интерактивно (i) удалять точки разброса (серые точки), (ii) добавлять новые точки разброса, нажимая на график.

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(figsize=(16,4))
a = np.sin(range(100))*np.random.normal(20,10,100)
b = [ 5, 15, 25, 30, 40, 50, 75, 85]

aa = plt.plot(range(len(a)),a,color='red')
bb = plt.scatter(b,a[b],color='grey',s=50)

введите здесь описание изображения


person themachinist    schedule 22.03.2017    source источник
comment
Поскольку это не служба написания кода, вы можете начать с просмотра страницы обработки событий.   -  person ImportanceOfBeingErnest    schedule 22.03.2017
comment
я думаю, что мой вопрос мало чем отличается от большинства вопросов, найденных в stackoverflow. Я думаю, ты немного резок. я читал страницу обработки событий, но был бы признателен за некоторые указания от других пользователей.   -  person themachinist    schedule 22.03.2017
comment
@themachinist - я ценю, что вы, по крайней мере, провели некоторое исследование обработки событий, но, конечно же, вы могли бы попытаться написать какой-нибудь код, каким бы плохим он ни был. Затем вы можете точно описать, что он делает не так, как вы хотите (или что он делает, чего вы не хотите делать ;-)) и вы не подвержен шквалу мнений.   -  person holdenweb    schedule 22.03.2017
comment
Спасибо за совет. Мое скромное мнение состоит в том, что до тех пор, пока вопрос ясен, он повышает ценность для других, с указанием или без показа неудачных попыток решить его, например. stackoverflow .com/questions/4700614/. Если мой вопрос не был ясен, значит, это моя вина, и я согласен, что иногда включение попытки его решения может помочь прояснить вопрос. Для протокола я решил, что с этого момента я буду показывать свои неудачные попытки, чтобы избежать каких-либо обид.   -  person themachinist    schedule 23.03.2017
comment
Что касается того, является ли SO службой написания кода, большую часть контента можно истолковать как код, написанный для сообщества. Я загрузил ответ на свой первоначальный вопрос.   -  person themachinist    schedule 23.03.2017
comment
Отличная работа! Поэтому, если вам нужен лучший способ сделать это, примите свой собственный ответ, а затем опубликуйте новый вопрос с вопросом, как улучшить (работает, снова молодец!) Код, который вы написали.   -  person holdenweb    schedule 23.03.2017


Ответы (1)


Это может быть не элегантно, но это работает. Щелкните левой кнопкой мыши, чтобы добавить точку, щелкните правой кнопкой мыши, чтобы удалить точку.

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(figsize=(16,4))
a_input = np.sin(range(100))*np.random.normal(20,10,100)
b_input = [ 5, 15, 25, 30, 40, 50, 75, 85]

a = plt.plot(range(len(a_input)),a_input,color='red')[0]
b = plt.scatter(b_input,a_input[b_input],color='grey',s=50,picker=5)

def add_or_remove_point(event):
    global a
    xydata_a = np.stack(a.get_data(),axis=1)
    xdata_a = a.get_xdata()
    ydata_a = a.get_ydata()
    global b
    xydata_b = b.get_offsets()
    xdata_b = b.get_offsets()[:,0]
    ydata_b = b.get_offsets()[:,1]

    #click x-value
    xdata_click = event.xdata
    #index of nearest x-value in a
    xdata_nearest_index_a = (np.abs(xdata_a-xdata_click)).argmin()
    #new scatter point x-value
    new_xdata_point_b = xdata_a[xdata_nearest_index_a]
    #new scatter point [x-value, y-value]
    new_xydata_point_b = xydata_a[new_xdata_point_b,:]

    if event.button == 1:
        if new_xdata_point_b not in xdata_b:

            #insert new scatter point into b
            new_xydata_b = np.insert(xydata_b,0,new_xydata_point_b,axis=0)
            #sort b based on x-axis values
            new_xydata_b = new_xydata_b[np.argsort(new_xydata_b[:,0])]
            #update b
            b.set_offsets(new_xydata_b)
            plt.draw()
    elif event.button == 3:
        if new_xdata_point_b in xdata_b:
            #remove xdata point b
            new_xydata_b = np.delete(xydata_b,np.where(xdata_b==new_xdata_point_b),axis=0)
            print(new_xdata_point_b)
            #update b
            b.set_offsets(new_xydata_b)
        plt.draw()

fig.canvas.mpl_connect('button_press_event',add_or_remove_point)
person themachinist    schedule 23.03.2017
comment
Отлично, @themahnist! Именно то, что я искал. Спасибо. - person maurobio; 17.10.2017