我怎样才能只重绘某些 matplotlib 艺术家?

How can I redraw only certain matplotlib artists?

我正在为电生理学数据制作一个自定义交互式图形,10-400 行(EEG 或 MEG 数据通道)绘制为带偏移的 LineCollection。用一条垂直线来评估不同通道上的信号特征如何在时间上对齐通常很有用,所以我有一个 button_press_event 监听器创建一个 axvline (或更新线的 xdata ,如果它已经存在)。如果 LineCollection 中有很多通道,重绘 axvline 会很昂贵,但据称更有效的重绘方法 (ax.draw_artist(my_vline)) 根本不起作用(很可能我只是误解了如何draw_artist 应该有效)。

复制代码

import matplotlib.pyplot as plt
plt.ion()


def make_vline(event):
    ax = event.inaxes
    if getattr(ax, 'my_vline', None) is None:
        ax.my_vline = ax.axvline(event.xdata, linewidth=4, color='r')
    else:
        ax.my_vline.set_xdata(event.xdata)
    # I thought any 1 of these 3 lines would move the vline to the click location:
    ax.draw_artist(ax.my_vline)  # this has no visible effect
    ax.redraw_in_frame()  # TypeError (see below for traceback)
    ax.figure.canvas.draw_idle()  # works, but slow when figure has many lines


fig, ax = plt.subplots()
callback_id = fig.canvas.mpl_connect('button_press_event', make_vline)

实际结果

Traceback (most recent call last):
  File "/opt/miniconda3/envs/mnedev/lib/python3.8/site-packages/matplotlib/cbook/__init__.py", line 224, in process
    func(*args, **kwargs)
  File "<ipython-input-1-08572d18e6b3>", line 11, in make_vline
    ax.redraw_in_frame()
  File "/opt/miniconda3/envs/mnedev/lib/python3.8/site-packages/matplotlib/axes/_base.py", line 2778, in redraw_in_frame
    stack.push(artist.set_visible, artist.get_visible())
TypeError: push() takes 2 positional arguments but 3 were given
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
plt.ion()
rng = np.random.default_rng()


def make_vline(event):
    ax = event.inaxes
    if getattr(ax, 'my_vline', None) is None:
        ax.my_vline = ax.axvline(event.xdata, linewidth=4, color='r', zorder=3)
    else:
        ax.my_vline.set_xdata(event.xdata)
    ax.figure.canvas.draw_idle()  # works, but slow when figure has many lines


def add_line_collection(ax):
    n_chans = 400
    n_times = 10001
    xs = np.linspace(0, 10, n_times)
    ys = rng.normal(size=(n_chans, n_times)) * 1e-6
    segments = [np.vstack((xs, ys[n])).T for n in range(n_chans)]
    yoffsets = np.arange(n_chans)
    offsets = np.vstack((np.zeros_like(yoffsets), yoffsets)).T
    lc = LineCollection(segments, offsets=offsets, linewidths=0.5, colors='k')
    ax.add_collection(lc)
    ax.set_xlim(xs[0], xs[-1])
    ax.set_ylim(yoffsets[0] - 0.5, yoffsets[-1] + 0.5)
    ax.set_yticks(yoffsets)


fig, ax = plt.subplots()
add_line_collection(ax)
callback_id = fig.canvas.mpl_connect('button_press_event', make_vline)

问题

  1. ax.draw_artist(my_artist) 什么时候真正起作用/它应该做什么?
  2. 我的例子是 blitting 有益的例子吗?
  3. 关于如何在此处加速(重新)绘制的任何其他想法?

Matplotlib 版本

我根据 the MPL blitting tutorial:

用 blitting 解决了这个问题
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
plt.ion()
rng = np.random.default_rng()


def make_vline(event):
    fig.canvas.restore_region(fig.my_bg)
    ax = event.inaxes
    if getattr(ax, 'my_vline', None) is None:
        ax.my_vline = ax.axvline(event.xdata, linewidth=4, color='r', zorder=3)
    else:
        ax.my_vline.set_xdata(event.xdata)
    ax.draw_artist(ax.my_vline)
    ax.figure.canvas.blit()
    ax.figure.canvas.flush_events()


def add_line_collection(ax):
    n_chans = 400
    n_times = 10001
    xs = np.linspace(0, 10, n_times)
    ys = rng.normal(size=(n_chans, n_times)) * 1e-6
    segments = [np.vstack((xs, ys[n])).T for n in range(n_chans)]
    yoffsets = np.arange(n_chans)
    offsets = np.vstack((np.zeros_like(yoffsets), yoffsets)).T
    lc = LineCollection(segments, offsets=offsets, linewidths=0.5, colors='k')
    ax.add_collection(lc)
    ax.set_xlim(xs[0], xs[-1])
    ax.set_ylim(yoffsets[0] - 0.5, yoffsets[-1] + 0.5)
    ax.set_yticks(yoffsets)


fig, ax = plt.subplots()
add_line_collection(ax)
callback_id = fig.canvas.mpl_connect('button_press_event', make_vline)
plt.pause(0.1)
fig.my_bg = fig.canvas.copy_from_bbox(fig.bbox)

请注意,如果调整图形大小,这将不起作用,您需要在调整大小侦听器中重新运行 copy_from_bbox 行。