Обновление pyplot.vlines в интерактивном сюжете

Мне нужна ваша помощь. Пожалуйста, рассмотрите приведенный ниже код, который строит синусоиду, используя pylab в IPython. Ползунок под осью позволяет пользователю интерактивно регулировать частоту синусоиды.

%pylab
# setup figure
fig, ax = subplots(1)
fig.subplots_adjust(left=0.25, bottom=0.25)

# add a slider
axcolor = 'lightgoldenrodyellow'
ax_freq = axes([0.3, 0.13, 0.5, 0.03], axisbg=axcolor)
s_freq = Slider(ax_freq, 'Frequency [Hz]', 0, 100, valinit=a0)

# plot 
g = linspace(0, 1, 100)
f0 = 1
sig = sin(2*pi*f0*t)
myline, = ax.plot(sig)

# update plot
def update(value):
    f = s_freq.val
    new_data = sin(2*pi*f*t)
    myline.set_ydata(new_data)     # crucial line
    fig.canvas.draw_idle()

s_freq.on_changed(update)

Вместо вышеперечисленного мне нужно построить сигнал в виде вертикальных линий, начиная от амплитуды каждой точки в t до оси X. Таким образом, моей первой идеей было использовать vlines вместо plot в строке 15:

myline = ax.vlines(range(len(sig)), 0, sig)

Это решение работает в неинтерактивном случае. Проблема в том, что plot возвращает объект matplotlib.lines.Line2D, который предоставляет метод set_ydata для интерактивного обновления данных. Объект, возвращаемый vlines, имеет тип matplotlib.collections.LineCollection и не предоставляет такой метод. Мой вопрос: как мне обновить LineCollection в интерактивном режиме?


person MaxPowers    schedule 29.03.2015    source источник
comment
Возможно set_offsetsили set_verts.   -  person tacaswell    schedule 29.03.2015
comment
Мне не удалось заставить работать set_offset или set_verts. set_segments работает, но вы должны предоставить его в формате трехмерного массива, где каждый элемент имеет форму [[x, ymin], [x, ymax]].   -  person Aaron Voelker    schedule 31.03.2020


Ответы (2)


Используя комментарий @Aaron Voelker об использовании set_segments и заключении его в функцию:

def update_vlines(*, h, x, ymin=None, ymax=None):
    seg_old = h.get_segments()
    if ymin is None:
        ymin = seg_old[0][0, 1]
    if ymax is None:
        ymax = seg_old[0][1, 1]

    seg_new = [np.array([[xx, ymin],
                         [xx, ymax]]) for xx in x]

    h.set_segments(seg_new)

Аналог для hlines:

def update_hlines(*, h, y, xmin=None, xmax=None):
    seg_old = h.get_segments()
    if xmin is None:
        xmin = seg_old[0][0, 0]
    if xmax is None:
        xmax = seg_old[0][1, 0]

    seg_new = [np.array([[xmin, yy],
                         [xmax, yy]]) for yy in y]

    h.set_segments(seg_new)
person scleronomic    schedule 06.05.2020

Я приведу примеры для vlines здесь.

Если у вас несколько строк, решение @scleronomic работает идеально. Вы также можете предпочесть однострочный:

myline.set_segments([np.array([[x, x_min], [x, x_max]]) for x in xx])

Если вам нужно обновить только максимумы, то можно сделать так:

def update_maxs(vline):
    vline[:,1] = x_min, x_max
    return vline

myline.set_segments(list(map(update_maxs, x.get_segments())))

Также может быть полезен этот пример: ССЫЛКА

person sataset    schedule 17.09.2020