为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

紫衣仙女 2023-07-27 16:27:03
我正在为电生理学数据开发一个自定义交互式图形,将 10-400 条线(EEG 或 MEG 数据通道)绘制为带有偏移的 LineCollection。使用垂直线来评估不同通道上的信号特征如何在时间上对齐通常很有用,因此我有一个button_press_event监听器来创建axvline(或更新该xdata线,如果它已经存在)。axvline如果 LineCollection 中有很多通道,则重绘的成本很高,但据说更有效的重绘方法 ( ax.draw_artist(my_vline)) 根本不起作用(很可能我只是误解了draw_artist应该如何工作)。复制代码import matplotlib.pyplot as pltplt.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 linesfig, 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 npimport matplotlib.pyplot as pltfrom matplotlib.collections import LineCollectionplt.ion()rng = np.random.default_rng()问题什么时候ax.draw_artist(my_artist)真正起作用/它应该做什么?我的示例是位块传输有益的情况吗?关于如何加快(重新)绘制速度还有其他想法吗?Matplotlib 版本操作系统:Xubuntu 20.04Matplotlib 版本:3.3.1(conda-forge)Matplotlib 后端:Qt5AggPython版本:3.8.5Jupyter 版本(如果适用):不适用其他库:numpy 1.19.1(conda-forge)
查看完整描述

1 回答

?
MM们

TA贡献1886条经验 获得超2个赞

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在调整大小侦听器中重新运行该行。


查看完整回答
反对 回复 2023-07-27
  • 1 回答
  • 0 关注
  • 78 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信