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

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时,显示严重异常。

请问问题出在哪里?


问题原因与解决方法

核心问题分析

  1. pxMode=True时文字过小:
    你的genSymbol函数把路径缩放到了1x1的单位尺寸,而pxMode=True下,ScatterPlotItem的size参数默认是像素,且你没有给自定义符号设置size,默认尺寸极小,导致文字几乎不可见。

  2. 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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 01:27:32