Drawing and Displaying objects and labels over the Axis in pyqtgraph - How to do it effectively?

Viewed 1938

I'm attempting to display QT's graphics objects over the top of AxisItems in pyqtgraph.

It took quite a bit of head bashing to figure out how to do this, and I think that perhaps there is a better way that uses the built in pyqtgraph mapToScene / mapToView funtions more efficently.

I thought initially that it would be easy and from the documentation (http://www.pyqtgraph.org/documentation/plotting.html#organization-of-plotting-classes) it would just be a case of drawing an object and referencing the pyqtgraph co-ordinates within PlotItem(GraphicsItem) with a higher Z value should make the objects float on top of the AxisItems.

However, they disappear behind the Axis when I try this no matter how high I set the Z value or whatever object(viewbox/plotitem/plotwidget) I select as the parent. As a workaround I reference the QTGraphicsScene instead and it does work but the co-ordinates are slightly off by a couple of pixels as you can see from my demo code whenever the mouse is moved which is to be expected as it's translating between pyqtgraph and Qt co-ordinate systems.

Can anyone suggest a better way to do this or how to line up the arrows in the demo with the exact values ?

from: http://www.pyqtgraph.org/documentation/plotting.html#organization-of-plotting-classes

Screenshot and code:

Crosshair with arrows on axis

from PyQt5.QtWidgets import QWidget, QDesktopWidget, QApplication, QLabel, QMainWindow, QHBoxLayout, QVBoxLayout
from PyQt5.QtCore import QThread
from PyQt5.QtCore import QObject
from PyQt5.QtCore import pyqtSlot, pyqtSignal

import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
from mainwindowgraph import Ui_MainWindow as QTestGraphMainWindow 
import sys

class TestGraphWidget(QMainWindow):

    def __init__(self):
        super().__init__()

        self.initUI()


    def initUI(self):               
        self.ui = QTestGraphMainWindow()
        self.ui.setupUi(self)
        self.setWindowTitle('Test Graphwindow')
        #This line is required to get the corect  viewbox
        self.vb = self.ui.mainplot.plotItem.vb

        proxy = pg.SignalProxy(self.ui.mainplot.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.ui.mainplot.scene().sigMouseMoved.connect(self.mouseMoved)

        #cross hair
        self.vLine = pg.InfiniteLine(angle=90, movable=False)
        self.hLine = pg.InfiniteLine(angle=0, movable=False)
        self.vLine.setZValue(2)
        self.hLine.setZValue(2)
        self.ui.mainplot.addItem(self.vLine, ignoreBounds=True)
        self.ui.mainplot.addItem(self.hLine, ignoreBounds=True)
        self.h_arrow = pg.ArrowItem(angle=0)
        self.v_arrow = pg.ArrowItem(angle=90)

        self.ui.mainplot.scene().addItem(self.v_arrow)
        self.ui.mainplot.scene().addItem(self.h_arrow)

        self.h_arrow.setZValue(10)
        self.v_arrow.setZValue(10)
        self.ui.mainplot.addItem(pg.PlotCurveItem([99,20,40,31,40,1], pen='b'))

    def mouseMoved(self, evt):
        pos = evt
        if self.ui.mainplot.sceneBoundingRect().contains(pos):
            mousePoint = self.vb.mapSceneToView(pos)
            #TODO - link  to axisitem instead of plotItemvb  <ViewBox>
            axis_offset = 0
            rightaxis_x = self.ui.mainplot.plotItem.vb.x() + self.ui.mainplot.plotItem.vb.width() + axis_offset 
            bottomaxis_y = self.ui.mainplot.plotItem.vb.y() + self.ui.mainplot.plotItem.vb.height() + axis_offset 
            index_x = mousePoint.x()
            print('x= {}, y = {}'.format(mousePoint.x() , mousePoint.y()))
            self.vLine.setPos(index_x)
            self.hLine.setPos(mousePoint.y())
            self.h_arrow.setPos(rightaxis_x, pos.y())
            self.v_arrow.setPos(pos.x(), bottomaxis_y)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    testgraphwindow = TestGraphWidget()
    testgraphwindow.ui.mainplot.showAxis('right')
    testgraphwindow.ui.mainplot.hideAxis('left')
    testgraphwindow.show()
    sys.exit(app.exec_())

mainwindowgraph.py :

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file ''
#
# Created by: PyQt5 UI code generator 5.11.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(921, 545)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.graphbuttons_horizontalLayout = QtWidgets.QHBoxLayout()
        self.graphbuttons_horizontalLayout.setObjectName("graphbuttons_horizontalLayout")
        spacerItem = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.graphbuttons_horizontalLayout.addItem(spacerItem)
        spacerItem1 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
        self.graphbuttons_horizontalLayout.addItem(spacerItem1)


        spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.graphbuttons_horizontalLayout.addItem(spacerItem2)
        spacerItem3 = QtWidgets.QSpacerItem(10, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.graphbuttons_horizontalLayout.addItem(spacerItem3)
        self.verticalLayout.addLayout(self.graphbuttons_horizontalLayout)
        self.mainplot = PlotWidget(self.centralwidget)
        self.mainplot.setObjectName("mainplot")
        self.verticalLayout.addWidget(self.mainplot)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 921, 22))
        self.menubar.setObjectName("menubar")
        self.menuFile = QtWidgets.QMenu(self.menubar)
        self.menuFile.setObjectName("menuFile")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.actionClose = QtWidgets.QAction(MainWindow)
        self.actionClose.setObjectName("actionClose")


        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

        self.menuFile.setTitle(_translate("MainWindow", "File"))
        self.actionClose.setText(_translate("MainWindow", "Close"))

from pyqtgraph import PlotWidget

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
0 Answers
Related