当前位置:   article > 正文

实战PyQt5: 151-QChart图表之给图表添加标注_pyqt 在qchart上添加qpainter

pyqt 在qchart上添加qpainter

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

Callout的实现

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

标注演示示例

根据Qt演示代码,在图标中添加一条折线和一条曲线,当鼠标移动到这些线上的某个点时,则会显示该点的坐标标注,如果此时按下鼠标左键,则可以将标注添加在图标中。完整代码如下:

  1. import sys
  2. from PyQt5.QtCore import Qt, QPoint, QPointF, QRect, QRectF
  3. from PyQt5.QtGui import QFont, QPainter, QPainterPath, QColor, QFontMetrics
  4. from PyQt5.QtWidgets import (QApplication, QWidget, QGraphicsItem, QGraphicsSimpleTextItem,
  5.                              QStyleOptionGraphicsItem, QGraphicsView, QGraphicsScene)
  6. from PyQt5.QtChart import QChart, QChartView, QLineSeries, QSplineSeries
  7.  
  8. #实现标注绘制
  9. class Callout(QGraphicsItem):
  10.     def __init__(self, chart):
  11.         super(Callout, self).__init__(chart)
  12.         self.chart = chart
  13.         self.text=''
  14.         self.anchor = QPointF()
  15.         self.rect = QRectF()
  16.         self.textRect = QRectF()
  17.         self.font = QFont()
  18.         
  19.     def boundingRect(self):
  20.         anchor = self.mapFromParent(self.chart.mapToPosition(self.anchor))
  21.         rect = QRectF()
  22.         rect.setLeft(min(self.rect.left(), anchor.x()))
  23.         rect.setRight(max(self.rect.right(), anchor.x()))
  24.         rect.setTop(min(self.rect.top(), anchor.y()))
  25.         rect.setBottom(max(self.rect.bottom(), anchor.y()))
  26.         
  27.         return rect
  28.         
  29.     def paint(self, painter, option, widget):
  30.         path = QPainterPath()
  31.         path.addRoundedRect(self.rect, 55)
  32.         
  33.         anchor = self.mapFromParent(self.chart.mapToPosition(self.anchor))
  34.         if not (self.rect.contains(anchor) and self.anchor.isNull()):
  35.             point1 = QPointF()
  36.             point2 = QPointF()
  37.             
  38.             #相对于self.rect的位置建立锚点
  39.             above = anchor.y() <= self.rect.top()
  40.             aboveCenter = anchor.y() > self.rect.top() and anchor.y() <= self.rect.center().y()
  41.             belowCenter = anchor.y() > self.rect.center().y() and anchor.y() <= self.rect.bottom()
  42.             below = anchor.y() > self.rect.bottom()
  43.             
  44.             left = anchor.x() <= self.rect.left()
  45.             leftCenter = anchor.x() > self.rect.left() and anchor.x() <= self.rect.center().x()
  46.             rightCenter = anchor.x() > self.rect.center().x() and anchor.x() <= self.rect.right()
  47.             right = anchor.x() > self.rect.right()
  48.             
  49.             #得到self.rect最近的角落位置
  50.             x = (right + rightCenter) * self.rect.width()
  51.             y = (below + belowCenter) * self.rect.height()
  52.             cornerCase = (above and leftor (above and rightor (below and leftor (below and right)
  53.             vertical = abs(anchor.x() - x) > abs(anchor.y() - y)
  54.             
  55.             x1 = x + leftCenter * 10 - rightCenter * 20 + cornerCase * (not vertical) * (left * 10 - right * 20)
  56.             y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * (above * 10 - below * 20)
  57.             point1.setX(x1)
  58.             point1.setY(y1)
  59.             
  60.             x2 = x + leftCenter * 20 - rightCenter * 10 + cornerCase * (not vertical) * (left * 20 - right * 10)
  61.             y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * (above * 20 -below * 10)
  62.             point2.setX(x2)
  63.             point2.setY(y2)
  64.             
  65.             path.moveTo(point1)
  66.             path.lineTo(anchor)
  67.             path.lineTo(point2)
  68.             path = path.simplified()
  69.         
  70.         painter.setBrush(QColor(255255255))
  71.         painter.drawPath(path)
  72.         painter.drawText(self.textRect, self.text)
  73.  
  74.         
  75.     def mousePressEvent(self, event):
  76.         event.setAccepted(True)
  77.         
  78.     def mouseMoveEvent(self, event):
  79.         if event.buttons() & Qt.LeftButton:
  80.             self.setPos(self.mapToParent(event.pos() - event.buttonDownPos(Qt.LeftButton)))
  81.             event.setAccepted(True)
  82.         else:
  83.             event.setAccepted(False)
  84.             
  85.     def setText(self, text):
  86.         self.text = text
  87.         metrics = QFontMetrics(self.font)
  88.         self.textRect = QRectF(metrics.boundingRect(QRect(00150150), Qt.AlignLeft, self.text))
  89.         self.textRect.translate(55)
  90.         self.prepareGeometryChange()
  91.         self.rect = self.textRect.adjusted(-5, -555)
  92.         
  93.     def setAnchor(self, point):
  94.         self.anchor = point
  95.         
  96.     def updateGeometry(self):
  97.         self.prepareGeometryChange()
  98.         self.setPos(self.chart.mapToPosition(self.anchor) + QPoint(1050))        
  99.  
  100. class DemoCallout(QGraphicsView):
  101.     def __init__(self, parent=None):
  102.         super(DemoCallout, self).__init__(QGraphicsScene(), parent)   
  103.         
  104.          # 设置窗口标题
  105.         self.setWindowTitle('实战 Qt for Python: 给图表添加标记')      
  106.         # 设置窗口大小
  107.         self.setMinimumSize(640480)
  108.       
  109.         self.tooltip = None
  110.         self.callouts = []
  111.         
  112.         self.setDragMode(QGraphicsView.NoDrag)
  113.         self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
  114.         self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
  115.         
  116.         #图表
  117.         self.chart = QChart()
  118.         self.chart.setMinimumSize(640480)
  119.         self.chart.setTitle('悬停在线上显示标注, 点击在该点添加标注')
  120.         self.chart.legend().hide()
  121.         lineSeries = QLineSeries()
  122.         lineSeries.append(13)
  123.         lineSeries.append(45)
  124.         lineSeries.append(54.5)
  125.         lineSeries.append(71)
  126.         lineSeries.append(112)
  127.         self.chart.addSeries(lineSeries)
  128.         
  129.         splineSeries = QSplineSeries()
  130.         splineSeries.append(1.61.4)
  131.         splineSeries.append(2.43.5)
  132.         splineSeries.append(3.72.5)
  133.         splineSeries.append(74)
  134.         splineSeries.append(102)
  135.         self.chart.addSeries(splineSeries)
  136.         
  137.         self.chart.createDefaultAxes()
  138.         self.chart.setAcceptHoverEvents(True)
  139.         
  140.         self.setRenderHint(QPainter.Antialiasing)
  141.         self.scene().addItem(self.chart)
  142.         
  143.         self.coordX = QGraphicsSimpleTextItem(self.chart)
  144.         self.coordX.setPos(self.chart.size().width()/2 - 50self.chart.size().height())
  145.         self.coordX.setText('X: ')
  146.         self.coordY = QGraphicsSimpleTextItem(self.chart)
  147.         self.coordY.setPos(self.chart.size().width()/2 + 50self.chart.size().height())
  148.         self.coordY.setText('Y: ')
  149.         
  150.         lineSeries.clicked.connect(self.keepCallout)
  151.         lineSeries.hovered.connect(self.showTooltip)
  152.         
  153.         splineSeries.clicked.connect(self.keepCallout)
  154.         splineSeries.hovered.connect(self.showTooltip)
  155.         
  156.     def resizeEvent(self, event):
  157.         if self.scene():
  158.             event_w = event.size().width()
  159.             event_h = event.size().height()
  160.             self.scene().setSceneRect(00, event_w, event_h)
  161.             self.chart.resize(event_w, event_h)
  162.             chart_w = self.chart.size().width()
  163.             chart_h = self.chart.size().height()
  164.             self.coordX.setPos(chart_w/2 - 50, chart_h - 20)
  165.             self.coordY.setPos(chart_w/2 + 50, chart_h - 20)
  166.             for callout in self.callouts:
  167.                 callout.updateGeometry()
  168.         QGraphicsView.resizeEvent(self, event)
  169.         
  170.     def mouseMoveEvent(self, event):
  171.         self.coordX.setText('X: %.5f' % self.chart.mapToValue(event.pos()).x())
  172.         self.coordY.setText('Y: %.5f' % self.chart.mapToValue(event.pos()).y())
  173.         QGraphicsView.mouseMoveEvent(self, event)
  174.         
  175.     def keepCallout(self):
  176.         self.callouts.append(self.tooltip)
  177.         self.tooltip = Callout(self.chart)
  178.         
  179.     def showTooltip(self, point, state):
  180.         if self.tooltip is None:
  181.             self.tooltip = Callout(self.chart)
  182.         if state:
  183.             self.tooltip.setText('X: %.5f\n Y: %.5f' % (point.x(), point.y()))
  184.             self.tooltip.setAnchor(point)
  185.             self.tooltip.setZValue(11)
  186.             self.tooltip.updateGeometry()
  187.             self.tooltip.show()
  188.         else:
  189.             self.tooltip.hide()
  190.     
  191. if __name__ == '__main__':
  192.     app = QApplication(sys.argv)
  193.     window = DemoCallout()
  194.     window.show()
  195.     sys.exit(app.exec())   

运行结果如下图:

 为图表添加标注

本文知识点

  • 怎样为图表自定义一个标注对象。
  • 在图表中添加标注。

请多多关注,评论,收藏,点赞,和转发。


前一篇: 实战PyQt5: 150-QChart图表之如何使用图例标记

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/805488
推荐阅读
相关标签
  

闽ICP备14008679号