微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决如何只重画某些matplotlib艺术家?

我正在为电生理数据制作一个自定义的交互式图形,该图形从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,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. 我的例子是发短信会有益吗?
  3. 关于如何加快此处的绘制速度的其他想法?

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行。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?