如何仅重画某些 matplotlib 艺术家?

我正在为电生理学数据开发一个自定义交互式图形,将 10-400 条线(EEG 或 MEG 数据通道)绘制为带有偏移的 LineCollection。使用垂直线来评估不同通道上的信号特征如何在时间上对齐通常很有用,因此我有一个button_press_event监听器来创建axvline(或更新该xdata线,如果它已经存在)。axvline如果 LineCollection 中有很多通道,则重绘的成本很高,但据说更有效的重绘方法 ( 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)

实际结果


如果我使用该ax.draw_artist(ax.my_vline)线,无论我单击何处,结果都是空白轴(除非我随后调整图形大小,这会触发重绘,然后出现该线)。


如果我使用这ax.redraw_in_frame()条线,我会得到:


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

如果我使用ax.figure.canvas.draw_idle()它,它会按预期工作,但是一旦图形中有实际数据,速度就会非常慢。这是一个较长的代码片段,您可以在本地运行以查看缓慢情况:

import numpy as np

import matplotlib.pyplot as plt

from matplotlib.collections import LineCollection

plt.ion()

rng = np.random.default_rng()

问题

  1. 什么时候ax.draw_artist(my_artist)真正起作用/它应该做什么?

  2. 我的示例是位块传输有益的情况吗?

  3. 关于如何加快(重新)绘制速度还有其他想法吗?

Matplotlib 版本

  • 操作系统:Xubuntu 20.04

  • Matplotlib 版本:3.3.1(conda-forge)

  • Matplotlib 后端:Qt5Agg

  • Python版本:3.8.5

  • Jupyter 版本(如果适用):不适用

  • 其他库:numpy 1.19.1(conda-forge)


紫衣仙女
浏览 85回答 1
1回答

MM们

import numpy as npimport matplotlib.pyplot as pltfrom matplotlib.collections import LineCollectionplt.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在调整大小侦听器中重新运行该行。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python