PyQtGraph中批量ScatterplotItem(spots)的旋转实现问题
实现PyQtGraph批量散点的单个旋转功能
我之前在处理PyQtGraph大型散点数据集时也遇到过完全一样的问题——批量绘制spots确实性能拉满,但默认不支持单个散点旋转,单独加散点又直接卡成PPT。摸索了一阵后,找到了一个通过子类化ScatterPlotItem来实现的方案,分享给你:
核心思路
PyQtGraph的ScatterPlotItem在批量模式下通过复用绘制路径来提升性能,但默认逻辑没有考虑旋转角度。我们可以重写它的路径生成和绘制逻辑,给每个spot添加自定义旋转属性,同时保持批量绘制的高效性。
实现步骤
1. 自定义带旋转支持的ScatterPlotItem子类
我们需要重写两个关键方法:
generateSpotPath:根据每个spot的旋转角度生成对应的路径paint:遍历所有spot,使用旋转后的路径批量绘制
import pyqtgraph as pg from PyQt5.QtGui import QPainter, QTransform class RotatableScatterPlotItem(pg.ScatterPlotItem): def generateSpotPath(self, symbol, size, spot=None): # 先调用父类生成基础符号路径 base_path = super().generateSpotPath(symbol, size) # 如果当前spot有angle属性,应用旋转变换 if spot and 'angle' in spot: transform = QTransform().rotate(spot['angle']) return transform.map(base_path) return base_path def paint(self, painter, opt, widget): painter.setRenderHint(QPainter.Antialiasing) if not self.scatterPlot: return spots = self.scatterPlot.spots() if not spots: return # 遍历每个spot,绘制带旋转的符号 for spot in spots: pos = spot['pos'] size = spot['size'] symbol = spot.get('symbol', self.symbol()) pen = spot.get('pen', self.pen()) brush = spot.get('brush', self.brush()) # 设置当前绘制的笔刷 painter.setPen(pen) painter.setBrush(brush) # 获取带旋转的路径并绘制 rotated_path = self.generateSpotPath(symbol, size, spot) # 平移到散点位置绘制 painter.translate(pos.x(), pos.y()) painter.drawPath(rotated_path) painter.translate(-pos.x(), -pos.y())
2. 使用自定义子类创建带旋转的散点
在构建spots数据时,给需要旋转的散点添加angle属性(单位:度),然后用我们的子类实例化散点项:
import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout if __name__ == "__main__": app = QApplication(sys.argv) win = QMainWindow() central_widget = QWidget() win.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) # 创建绘图组件 plot_widget = pg.PlotWidget() layout.addWidget(plot_widget) # 生成1000个带旋转角度的散点数据 spots = [] for idx in range(1000): # 每个散点的旋转角度从0到360循环 rotation_angle = idx % 360 spots.append({ 'pos': (idx / 50, pg.gaussianFilter([idx / 50], sigma=3)[0]), 'size': 10, 'brush': pg.intColor(idx, 1000), 'angle': rotation_angle }) # 使用自定义子类创建散点项并添加到绘图 scatter_item = RotatableScatterPlotItem(spots=spots) plot_widget.addItem(scatter_item) win.show() sys.exit(app.exec_())
性能说明
这个方案虽然是逐个绘制散点,但直接操作QPainter的路径对象,避免了创建多个ScatterPlotItem带来的资源开销,性能和原生批量绘制模式接近,拖动时不会出现严重卡顿。如果你的场景需要极致性能(比如十万级以上散点),可以考虑基于GLScatterPlotItem做OpenGL层面的改造,修改顶点着色器来处理旋转,但上述方案对大多数大型数据集已经足够。
内容的提问来源于stack exchange,提问作者frodo4fingers
相关产品推荐
相关产品推荐

