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

如何用鼠标在Matplotlib/PyQt5中绘制交互式固定m×n网格?

实现交互式m×n固定网格绘制(替代矩形选择)

现有代码可通过鼠标绘制交互式矩形,并能控制其尺寸与位置。请问如何修改代码,实现绘制固定m×n的交互式网格(整体可像矩形一样拖动、调整大小,内部自动划分成m行n列的网格线),而非单一矩形?

原代码

from matplotlib.widgets import RectangleSelector
import numpy as np
import matplotlib.pyplot as plt


def line_select_callback(eclick, erelease):
    'eclick and erelease are the press and release events'
    x1, y1 = eclick.xdata, eclick.ydata
    x2, y2 = erelease.xdata, erelease.ydata
    print("(%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1, y1, x2, y2))
    print(" The button you used were: %s %s" % (eclick.button, erelease.button))


def toggle_selector(event):
    print(' Key pressed.')
    if event.key in ['Q', 'q'] and toggle_selector.RS.active:
        print(' RectangleSelector deactivated.')
        toggle_selector.RS.set_active(False)
    if event.key in ['A', 'a'] and not toggle_selector.RS.active:
        print(' RectangleSelector activated.')
        toggle_selector.RS.set_active(True)


fig, current_ax = plt.subplots()                 # make a new plotting range
N = 100000                                       # If N is large one can see
x = np.linspace(0.0, 10.0, N)                    # improvement by use blitting!

plt.plot(x, +np.sin(.2*np.pi*x), lw=3.5, c='b', alpha=.7)  # plot something
plt.plot(x, +np.cos(.2*np.pi*x), lw=3.5, c='r', alpha=.5)
plt.plot(x, -np.sin(.2*np.pi*x), lw=3.5, c='g', alpha=.3)

print("\n      click  -->  release")

# drawtype is 'box' or 'line' or 'none'
toggle_selector.RS = RectangleSelector(current_ax, line_select_callback,
                                       drawtype='box', useblit=True,
                                       button=[1, 3],  # don't use middle button
                                       minspanx=5, minspany=5,
                                       spancoords='pixels',
                                       interactive=True)
plt.connect('key_press_event', toggle_selector)
plt.show()

修改方案

通过继承RectangleSelector自定义网格选择器,保留原交互逻辑的同时添加网格绘制功能:

from matplotlib.widgets import RectangleSelector
import numpy as np
import matplotlib.pyplot as plt


class GridSelector(RectangleSelector):
    def __init__(self, ax, onselect, m=3, n=3, **kwargs):
        self.m = m  # 网格行数
        self.n = n  # 网格列数
        super().__init__(ax, onselect, **kwargs)

    def _draw_shape(self, extents):
        # 先绘制基础矩形框
        super()._draw_shape(extents)
        x1, x2, y1, y2 = extents
        # 计算垂直网格线(列方向)
        x_grid = np.linspace(x1, x2, self.n + 1)
        # 计算水平网格线(行方向)
        y_grid = np.linspace(y1, y2, self.m + 1)
        
        # 绘制垂直网格线
        for x in x_grid:
            self.ax.plot([x, x], [y1, y2], color='gray', linestyle='--', linewidth=1)
        # 绘制水平网格线
        for y in y_grid:
            self.ax.plot([x1, x2], [y, y], color='gray', linestyle='--', linewidth=1)


def line_select_callback(eclick, erelease):
    'eclick and erelease are the press and release events'
    x1, y1 = eclick.xdata, eclick.ydata
    x2, y2 = erelease.xdata, erelease.ydata
    print(f"({x1:.2f}, {y1:.2f}) --> ({x2:.2f}, {y2:.2f})")
    print(f" 使用的按键: {eclick.button} {erelease.button}")


def toggle_selector(event):
    print(' 按键已按下.')
    if event.key in ['Q', 'q'] and toggle_selector.GS.active:
        print(' GridSelector 已关闭.')
        toggle_selector.GS.set_active(False)
    if event.key in ['A', 'a'] and not toggle_selector.GS.active:
        print(' GridSelector 已激活.')
        toggle_selector.GS.set_active(True)


fig, current_ax = plt.subplots()
N = 100000
x = np.linspace(0.0, 10.0, N)

plt.plot(x, +np.sin(.2*np.pi*x), lw=3.5, c='b', alpha=.7)
plt.plot(x, +np.cos(.2*np.pi*x), lw=3.5, c='r', alpha=.5)
plt.plot(x, -np.sin(.2*np.pi*x), lw=3.5, c='g', alpha=.3)

print("\n      点击 --> 释放")

# 初始化GridSelector,可自定义m和n调整网格行列数
toggle_selector.GS = GridSelector(current_ax, line_select_callback,
                                  m=3, n=3, drawtype='box', useblit=False,
                                  button=[1, 3], minspanx=5, minspany=5,
                                  spancoords='pixels', interactive=True)
plt.connect('key_press_event', toggle_selector)
plt.show()

关键说明

  • 自定义GridSelector类,新增m(行数)和n(列数)参数,按需调整网格密度
  • 重写_draw_shape方法,在矩形框基础上绘制灰色虚线网格,网格会跟随矩形的拖动、缩放实时更新
  • 关闭useblit参数(若保留blitting,需自定义缓存更新逻辑,否则网格线无法实时刷新)
  • 保留原有的快捷键操作:按A激活网格选择器,按Q关闭

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 16:24:21