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 ?
Screenshot and code:
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_())

