问题描述
我正在为电生理数据制作一个自定义的交互式图形,该图形从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
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,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)
何时生效/应该做什么? - 我的例子是发短信会有益吗?
- 关于如何加快此处的绘制速度的其他想法?
Matplotlib版本
- 操作系统:Xubuntu 20.04
- Matplotlib版本:3.3.1(conda-forge)
- Matplotlib后端:Qt5Agg
- Python版本:3.8.5
- Jupyter版本(如果适用):不适用
- 其他库:numpy 1.19.1(conda-forge)
解决方法
我根据the MPL blitting tutorial通过发短信解决了这个问题:
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
行。