实战PyQt5: 151-QChart图表之给图表添加标注


实战PyQt5: 151-QChart图表之给图表添加标注

在数据可视化应用中,对图表里某些点,我们期望将其特别标注出来,比如对曲线上的某些点的坐标值数据标注出来 。在这种情况下 , 我们可以自定义一个绘制标注的类来实现 。在本文的示例中 , 定义类Callout, 用于实现标注的绘制 。

Callout的实现

QChart继承自QGraphicsWidget, 标注对象可以看做是QGraphicsWidget中的条目,因此Callout自然而然继承自QGraphicsItem 。并重载函数boundingRect()以计算Callout的外框大小 , paint()函数实现对图标的绘制 。

标注演示示例

根据Qt演示代码 , 在图标中添加一条折线和一条曲线,当鼠标移动到这些线上的某个点时,则会显示该点的坐标标注,如果此时按下鼠标左键,则可以将标注添加在图标中 。完整代码如下:
import sysfrom PyQt5.QtCore import Qt, QPoint, QPointF, QRect, QRectFfrom PyQt5.QtGui import QFont, QPainter, QPainterPath, QColor, QFontMetricsfrom PyQt5.QtWidgets import (QApplication, QWidget, QGraphicsItem, QGraphicsSimpleTextItem,QStyleOptionGraphicsItem, QGraphicsView, QGraphicsScene)from PyQt5.QtChart import QChart, QChartView, QLineSeries, QSplineSeries #实现标注绘制class Callout(QGraphicsItem):def __init__(self, chart):super(Callout, self).__init__(chart)self.chart = chartself.text=''self.anchor = QPointF()self.rect = QRectF()self.textRect = QRectF()self.font = QFont()def boundingRect(self):anchor = self.mapFromParent(self.chart.mapToPosition(self.anchor))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 rectdef paint(self, painter, option, widget):path = QPainterPath()path.addRoundedRect(self.rect, 5, 5)anchor = self.mapFromParent(self.chart.mapToPosition(self.anchor))if not (self.rect.contains(anchor) and self.anchor.isNull()):point1 = QPointF()point2 = QPointF()#相对于self.rect的位置建立锚点above = anchor.y() <= self.rect.top()aboveCenter = anchor.y() > self.rect.top() and anchor.y() <= self.rect.center().y()belowCenter = anchor.y() > self.rect.center().y() and anchor.y() <= self.rect.bottom()below = anchor.y() > self.rect.bottom()left = anchor.x() <= self.rect.left()leftCenter = anchor.x() > self.rect.left() and anchor.x() <= self.rect.center().x()rightCenter = anchor.x() > self.rect.center().x() and anchor.x() <= self.rect.right()right = anchor.x() > self.rect.right()#得到self.rect最近的角落位置x = (rightrightCenter) * self.rect.width()y = (belowbelowCenter) * self.rect.height()cornerCase = (above and left) or (above and right) or (below and left) or (below and right)vertical = abs(anchor.x() - x) > abs(anchor.y() - y)x1 = xleftCenter * 10 - rightCenter * 20cornerCase * (not vertical) * (left * 10 - right * 20)y1 = yaboveCenter * 10 - belowCenter * 20cornerCase * vertical * (above * 10 - below * 20)point1.setX(x1)point1.setY(y1)x2 = xleftCenter * 20 - rightCenter * 10cornerCase * (not vertical) * (left * 20 - right * 10)y2 = yaboveCenter * 20 - belowCenter * 10cornerCase * 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 mousePressEvent(self, event):event.setAccepted(True)def mouseMoveEvent(self, event):if event.buttons() & Qt.LeftButton:self.setPos(self.mapToParent(event.pos() - event.buttonDownPos(Qt.LeftButton)))event.setAccepted(True)else:event.setAccepted(False)def setText(self, text):self.text = textmetrics = QFontMetrics(self.font)self.textRect = QRectF(metrics.boundingRect(QRect(0, 0, 150, 150), Qt.AlignLeft, self.text))self.textRect.translate(5, 5)self.prepareGeometryChange()self.rect = self.textRect.adjusted(-5, -5, 5, 5)def setAnchor(self, point):self.anchor = pointdef updateGeometry(self):self.prepareGeometryChange()self.setPos(self.chart.mapToPosition(self.anchor)QPoint(10, 50))class DemoCallout(QGraphicsView):def __init__(self, parent=None):super(DemoCallout, self).__init__(QGraphicsScene(), parent)# 设置窗口标题self.setWindowTitle('实战 Qt for Python: 给图表添加标记')# 设置窗口大小self.setMinimumSize(640, 480)self.tooltip = Noneself.callouts = []self.setDragMode(QGraphicsView.NoDrag)self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)#图表self.chart = QChart()self.chart.setMinimumSize(640, 480)self.chart.setTitle('悬停在线上显示标注, 点击在该点添加标注')self.chart.legend().hide()lineSeries = QLineSeries()lineSeries.append(1, 3)lineSeries.append(4, 5)lineSeries.append(5, 4.5)lineSeries.append(7, 1)lineSeries.append(11, 2)self.chart.addSeries(lineSeries)splineSeries = QSplineSeries()splineSeries.append(1.6, 1.4)splineSeries.append(2.4, 3.5)splineSeries.append(3.7, 2.5)splineSeries.append(7, 4)splineSeries.append(10, 2)self.chart.addSeries(splineSeries)self.chart.createDefaultAxes()self.chart.setAcceptHoverEvents(True)self.setRenderHint(QPainter.Antialiasing)self.scene().addItem(self.chart)self.coordX = QGraphicsSimpleTextItem(self.chart)self.coordX.setPos(self.chart.size().width()/2 - 50, self.chart.size().height())self.coordX.setText('X: ')self.coordY = QGraphicsSimpleTextItem(self.chart)self.coordY.setPos(self.chart.size().width()/250, self.chart.size().height())self.coordY.setText('Y: ')lineSeries.clicked.connect(self.keepCallout)lineSeries.hovered.connect(self.showTooltip)splineSeries.clicked.connect(self.keepCallout)splineSeries.hovered.connect(self.showTooltip)def resizeEvent(self, event):if self.scene():event_w = event.size().width()event_h = event.size().height()self.scene().setSceneRect(0, 0, event_w, event_h)self.chart.resize(event_w, event_h)chart_w = self.chart.size().width()chart_h = self.chart.size().height()self.coordX.setPos(chart_w/2 - 50, chart_h - 20)self.coordY.setPos(chart_w/250, chart_h - 20)for callout in self.callouts:callout.updateGeometry()QGraphicsView.resizeEvent(self, event)def mouseMoveEvent(self, event):self.coordX.setText('X: %.5f' % self.chart.mapToValue(event.pos()).x())self.coordY.setText('Y: %.5f' % self.chart.mapToValue(event.pos()).y())QGraphicsView.mouseMoveEvent(self, event)def keepCallout(self):self.callouts.append(self.tooltip)self.tooltip = Callout(self.chart)def showTooltip(self, point, state):if self.tooltip is None:self.tooltip = Callout(self.chart)if state:self.tooltip.setText('X: %.5fn Y: %.5f' % (point.x(), point.y()))self.tooltip.setAnchor(point)self.tooltip.setZValue(11)self.tooltip.updateGeometry()self.tooltip.show()else:self.tooltip.hide()if __name__ == '__main__':app = QApplication(sys.argv)window = DemoCallout()window.show()sys.exit(app.exec())
运行结果如下图:
实战PyQt5: 151-QChart图表之给图表添加标注

为图表添加标注

本文知识点

  • 怎样为图表自定义一个标注对象 。
  • 在图表中添加标注 。
请多多关注,评论 , 收藏,点赞,和转发 。

【实战PyQt5: 151-QChart图表之给图表添加标注】前一篇:

相关经验推荐