You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Matplotlib中轴外Artist的Blit重绘失效问题?

解决Matplotlib带轴外标注的Blit十字光标失效问题

问题场景

基于Matplotlib实现的Blit十字光标,当右侧轴的Y值标注(文本Artist)超出轴区域时,Blit技术失效;若每次鼠标移动调用canvas.draw(),因图表数据量大,每次绘制耗时0.5-0.7秒,光标操作严重卡顿。根源在于保存背景时仅使用ax.bbox,只覆盖轴内区域,轴外部分未被纳入背景缓存,导致Blit无法正确清除旧标注。

解决方案

核心是扩展背景缓存的范围,覆盖标注可能出现的轴外区域,具体修改如下:

import matplotlib.pyplot as plt
import numpy as np

class BlittedCursor:
    """
    A cross hair cursor using blitting for faster redraw.
    """
    def __init__(self, ax):
        self.ax = ax
        self.background = None
        self.horizontal_line = ax.axhline(color='k', lw=0.8, ls='--')
        self.vertical_line = ax.axvline(color='k', lw=0.8, ls='--')
        # text location in axes coordinates
        self.text = ax.text(0.95, 0, '', transform=ax.get_yaxis_transform())
        self._creating_background = False
        ax.figure.canvas.mpl_connect('draw_event', self.on_draw)

    def on_draw(self, event):
        self.create_new_background()

    def set_cross_hair_visible(self, visible):
        need_redraw = self.horizontal_line.get_visible() != visible
        self.horizontal_line.set_visible(visible)
        self.vertical_line.set_visible(visible)
        self.text.set_visible(visible)
        return need_redraw

    def create_new_background(self):
        if self._creating_background:
            # discard calls triggered from within this function
            return
        self._creating_background = True
        self.set_cross_hair_visible(False)
        self.ax.figure.canvas.draw()
        # 修改:保存整个画布的背景,而非仅轴区域
        self.background = self.ax.figure.canvas.copy_from_bbox(
            self.ax.figure.canvas.get_window_extent()
        )
        self.set_cross_hair_visible(True)
        self._creating_background = False

    def on_mouse_move(self, event):
        if self.background is None:
            self.create_new_background()
        if not event.inaxes:
            need_redraw = self.set_cross_hair_visible(False)
            if need_redraw:
                self.ax.figure.canvas.restore_region(self.background)
                # 修改:Blit整个画布范围
                self.ax.figure.canvas.blit(self.ax.figure.canvas.get_window_extent())
        else:
            self.set_cross_hair_visible(True)
            # update the line positions
            x, y = event.xdata, event.ydata
            self.horizontal_line.set_ydata(y)
            self.vertical_line.set_xdata(x)
            self.text.set_text('y=%1.2f' % (y))
            self.text.set_y(y)

            self.ax.figure.canvas.restore_region(self.background)
            self.ax.draw_artist(self.horizontal_line)
            self.ax.draw_artist(self.vertical_line)
            self.ax.draw_artist(self.text)
            # 修改:Blit整个画布范围
            self.ax.figure.canvas.blit(self.ax.figure.canvas.get_window_extent())


x = np.arange(0, 1, 0.01)
y = np.sin(2 * 2 * np.pi * x)

fig, ax = plt.subplots()
ax.set_title('Blitted cursor')
ax.plot(x, y, 'o')
blitted_cursor = BlittedCursor(ax)
fig.canvas.mpl_connect('motion_notify_event', blitted_cursor.on_mouse_move)
plt.show()

关键修改说明

  • 将背景缓存的范围从ax.bbox(仅轴内区域)改为canvas.get_window_extent()(整个画布区域),确保轴外的标注区域也被纳入背景缓存
  • Blit更新时同步使用整个画布范围,保证旧标注能被背景正确覆盖,新标注正常绘制

内容的提问来源于stack exchange,提问作者Beginner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:20:39