PyQtGraph用QPainterPath替代TextItem优化性能遇显示异常求助
问题描述
在PyQtGraph中,我原本通过循环为每个pg.ScatterPlotItem添加pg.TextItem标签,代码如下:
label = pg.TextItem(text=str(i), color=HEX_ORANGE, anchor=([1, 1])) label.setPos(x, y) self.plot.addItem(label)
但这种循环添加的方式性能较差,于是我尝试用QPainterPath作为自定义符号来实现标签功能,写了如下代码:
from PySide6.QtGui import QTransform, QPainterPath, QFont def genSymbol(label): # 参考pyqtgraph/examples/ScatterPlotItem中的示例 symbol = QPainterPath() f = QFont() f.setPointSize(5) symbol.addText(0, 0, f, label) br = symbol.boundingRect() scale = min(1. / br.width(), 1. / br.height()) tr = QTransform() tr.scale(scale, scale) tr.translate(-br.x() - br.width()/2., -br.y() - br.height()/2.) return symbol if __name__ == '__main__': import pyqtgraph as pg from PySide6.QtWidgets import QMainWindow from PySide6.QtGui import QColor app = pg.mkQApp("PerPlotHelper") w = QMainWindow() cw = pg.GraphicsLayoutWidget() w.show() w.resize(600, 600) w.setCentralWidget(cw) w.setWindowTitle('pyqtgraph example: Arrow') p = cw.addPlot(row=0, col=0) #### point_xs = [1, 2, 3, 4, 5, 6] point_ys = [1, 2, 3, 4, 5, 6] points = pg.ScatterPlotItem(point_xs, point_ys, symbol='o', size=9, pen=pg.mkPen(QColor("#ff9900")), brush=pg.mkBrush(QColor("#ff9900")), data="w/e") p.addItem(points) symbols = [genSymbol(str(i)) for i in range(len(point_xs))] # 绘制文本标签 spots = [{'x': point_xs[i], 'y': point_ys[i], 'data': "w/e", 'brush': "#ff9900", 'symbol': symbols[i]} for i in range(len(point_xs))] textLabelsP = pg.ScatterPlotItem(pen=pg.mkPen('w'), pxMode=True) textLabelsP.addPoints(spots) p.addItem(textLabelsP) app.exec()
运行后发现两个问题:
- 当
pxMode=True时,文字极小几乎看不见; - 当
pxMode=False时,显示严重异常。
请问问题出在哪里?
问题原因与解决方法
核心问题分析
pxMode=True时文字过小:
你的genSymbol函数把路径缩放到了1x1的单位尺寸,而pxMode=True下,ScatterPlotItem的size参数默认是像素,且你没有给自定义符号设置size,默认尺寸极小,导致文字几乎不可见。pxMode=False时显示异常:
这种模式下尺寸基于绘图坐标系,你的缩放逻辑把路径缩到了单位尺寸,而绘图坐标系的1单位可能对应很大的屏幕空间,再加上没有设置合适的size,导致文字要么过度拉伸,要么位置偏移混乱。
修复后的代码
调整genSymbol函数的缩放逻辑,同时给自定义符号的ScatterPlotItem设置合适的size:
from PySide6.QtGui import QTransform, QPainterPath, QFont def genSymbol(label): symbol = QPainterPath() f = QFont() f.setPointSize(12) # 直接设置合适的字体大小,无需缩放到1x1 symbol.addText(0, 0, f, label) br = symbol.boundingRect() # 仅做居中平移,不进行缩放 tr = QTransform() tr.translate(-br.center().x(), -br.center().y()) return tr.map(symbol) # 将变换应用到路径上 if __name__ == '__main__': import pyqtgraph as pg from PySide6.QtWidgets import QMainWindow from PySide6.QtGui import QColor app = pg.mkQApp("PerPlotHelper") w = QMainWindow() cw = pg.GraphicsLayoutWidget() w.show() w.resize(600, 600) w.setCentralWidget(cw) w.setWindowTitle('pyqtgraph example: Text as Symbol') p = cw.addPlot(row=0, col=0) point_xs = [1, 2, 3, 4, 5, 6] point_ys = [1, 2, 3, 4, 5, 6] points = pg.ScatterPlotItem(point_xs, point_ys, symbol='o', size=9, pen=pg.mkPen(QColor("#ff9900")), brush=pg.mkBrush(QColor("#ff9900")), data="w/e") p.addItem(points) symbols = [genSymbol(str(i)) for i in range(len(point_xs))] spots = [{'x': point_xs[i], 'y': point_ys[i], 'data': "w/e", 'brush': "#ff9900", 'symbol': symbols[i]} for i in range(len(point_xs))] # pxMode=True时,size设置为与字体大小匹配的像素值 textLabelsP = pg.ScatterPlotItem(pen=pg.mkPen('w'), pxMode=True, size=12) textLabelsP.addPoints(spots) p.addItem(textLabelsP) app.exec()
额外说明
如果需要使用pxMode=False(基于坐标系的缩放),可以修改genSymbol函数,用单位尺寸字体,后续通过ScatterPlotItem的size控制大小:
def genSymbol(label): symbol = QPainterPath() f = QFont() f.setPointSize(1) # 使用单位尺寸字体,后续通过size参数缩放 symbol.addText(0, 0, f, label) br = symbol.boundingRect() tr = QTransform() tr.translate(-br.center().x(), -br.center().y()) return tr.map(symbol)
创建ScatterPlotItem时设置pxMode=False和合适的size(比如size=0.5,对应坐标系中的0.5单位)即可。
内容的提问来源于stack exchange,提问作者Andrei M.
相关产品推荐
相关产品推荐

