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

PySide6多Y轴QChart下Callout提示位置偏移问题求助

多Y轴场景下QChart Callout提示偏移修复方案

偏移的核心原因是QChart.mapToPosition方法默认使用图表的默认轴做坐标转换,多Y轴场景下不同序列绑定的Y轴范围、对齐方式都不同,必须指定对应序列才能计算出正确的屏幕坐标。以下是具体修改步骤:


1. 修改Callout类

新增序列存储属性,所有坐标转换逻辑都指定对应序列:

class Callout(QGraphicsItem):
    def __init__(self, chart):
        QGraphicsItem.__init__(self, chart)
        self.chart = chart
        self._text = ""
        self._textRect = QRectF()
        self._anchor = QPointF()
        self._font = QFont()
        self._rect = QRectF()
        # 新增:存储当前提示对应的序列
        self._series = None

    # 新增:设置对应序列的方法
    def set_series(self, series):
        self._series = series

    def boundingRect(self):
        # 修改:坐标转换传入对应序列
        anchor = self.mapFromParent(self.chart.mapToPosition(self._anchor, self._series))
        rect = QRectF()
        rect.setLeft(min(self._rect.left(), anchor.x()))
        rect.setRight(max(self._rect.right(), anchor.x()))
        rect.setTop(min(self._rect.top(), anchor.y()))
        rect.setBottom(max(self._rect.bottom(), anchor.y()))
        return rect

    def paint(self, painter, option, widget):
        path = QPainterPath()
        path.addRoundedRect(self._rect, 5, 5)
        # 修改:坐标转换传入对应序列
        anchor = self.mapFromParent(self.chart.mapToPosition(self._anchor, self._series))
        # 以下原有paint逻辑无需修改
        if not self._rect.contains(anchor) and not self._anchor.isNull():
            point1 = QPointF()
            point2 = QPointF()

            # 确定锚点相对于_rect的位置
            above = anchor.y() <= self._rect.top()
            above_center = (anchor.y() > self._rect.top() and
                anchor.y() <= self._rect.center().y())
            below_center = (anchor.y() > self._rect.center().y() and
                anchor.y() <= self._rect.bottom())
            below = anchor.y() > self._rect.bottom()

            on_left = anchor.x() <= self._rect.left()
            left_of_center = (anchor.x() > self._rect.left() and
                anchor.x() <= self._rect.center().x())
            right_of_center = (anchor.x() > self._rect.center().x() and
                anchor.x() <= self._rect.right())
            on_right = anchor.x() > self._rect.right()

            # 获取最近的_rect边角
            x = (on_right + right_of_center) * self._rect.width()
            y = (below + below_center) * self._rect.height()
            corner_case = ((above and on_left) or (above and on_right) or
                (below and on_left) or (below and on_right))
            vertical = abs(anchor.x() - x) > abs(anchor.y() - y)

            x1 = (x + left_of_center * 10 - right_of_center * 20 + corner_case *
                int(not vertical) * (on_left * 10 - on_right * 20))
            y1 = (y + above_center * 10 - below_center * 20 + corner_case *
                vertical * (above * 10 - below * 20))
            point1.setX(x1)
            point1.setY(y1)

            x2 = (x + left_of_center * 20 - right_of_center * 10 + corner_case *
                int(not vertical) * (on_left * 20 - on_right * 10))
            y2 = (y + above_center * 20 - below_center * 10 + corner_case *
                vertical * (above * 20 - below * 10))
            point2.setX(x2)
            point2.setY(y2)

            path.moveTo(point1)
            path.lineTo(anchor)
            path.lineTo(point2)
            path = path.simplified()

        painter.setBrush(QColor(255, 255, 255))
        painter.drawPath(path)
        painter.drawText(self._textRect, self._text)

    def update_geometry(self):
        self.prepareGeometryChange()
        # 修改:坐标转换传入对应序列
        self.setPos(self.chart.mapToPosition(self._anchor, self._series) + QPointF(10, -50))

    # 其余原有方法无需修改,保持不变即可

2. 修改CreateChart类的tooltip方法

悬浮触发时获取当前序列并传递给Callout:

def tooltip(self, point, state):
    if self._tooltip == 0:
        self._tooltip = Callout(self.chart)

    if state:
        # 新增:获取触发悬浮信号的当前序列
        current_series = self.sender()
        x = point.x()
        y = point.y()
        self._tooltip.set_text(f"X: {x:.1f} \nY: {y:.1f} ")
        self._tooltip.set_anchor(point)
        # 新增:给Callout设置当前序列
        self._tooltip.set_series(current_series)
        self._tooltip.setZValue(11)
        self._tooltip.update_geometry()
        self._tooltip.show()
    else:
        self._tooltip.hide()

修改完成后所有序列的Callout都会匹配自身绑定的Y轴计算坐标,偏移问题即可解决。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 21:48:04