我怎样才能只重绘某些 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)
实际结果
如果我使用 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()
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)
问题
ax.draw_artist(my_artist)
什么时候真正起作用/它应该做什么?
- 我的例子是 blitting 有益的例子吗?
- 关于如何在此处加速(重新)绘制的任何其他想法?
Matplotlib 版本
- 操作系统:Xubuntu 20.04
- Matplotlib 版本:3.3.1 (conda-forge)
- Matplotlib 后端:Qt5Agg
- Python版本:3.8.5
- Jupyter 版本(如果适用):n/a
- 其他库:numpy 1.19.1 (conda-forge)
我根据 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
行。
我正在为电生理学数据制作一个自定义交互式图形,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)
实际结果
如果我使用
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()
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)
问题
ax.draw_artist(my_artist)
什么时候真正起作用/它应该做什么?- 我的例子是 blitting 有益的例子吗?
- 关于如何在此处加速(重新)绘制的任何其他想法?
Matplotlib 版本
- 操作系统:Xubuntu 20.04
- Matplotlib 版本:3.3.1 (conda-forge)
- Matplotlib 后端:Qt5Agg
- Python版本:3.8.5
- Jupyter 版本(如果适用):n/a
- 其他库:numpy 1.19.1 (conda-forge)
我根据 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
行。