When working with PyQtGraph plots, changing the cursor can help with pointing accuracy. For example, if you need to isolate particular points in a scatter plot, a crosshair cursor gives you a more accurate view of where you are pointing than the standard arrow cursor.
In this tutorial, you'll learn two approaches: using Qt's built-in cursor shapes and drawing a fully custom crosshair overlay using PyQtGraph's InfiniteLine.
Changing the mouse cursor on a PyQtGraph PlotWidget
Changing the mouse cursor in a PyQtGraph plot is fairly simple and uses Qt's built-in support for custom cursors over a widget. Since the PyQtGraph PlotWidget is a subclass of QGraphicsWidget (and therefore QWidget) you can use the standard Qt cursor methods.
cursor = Qt.CrossCursor
self.graphWidget.setCursor(cursor)
For the complete list of cursor types, see the Qt documentation.
The example below shows this in action on a simple PyQtGraph plot.
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QApplication
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys # We need sys so that we can pass argv to QApplication
import os
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.graphWidget = pg.PlotWidget()
self.setCentralWidget(self.graphWidget)
hour = [1,2,3,4,5,6,7,8,9,10]
temperature = [30,32,34,32,33,31,29,32,35,45]
#Add Background colour to white
self.graphWidget.setBackground('w')
# Add Title
self.graphWidget.setTitle("Your Title Here", color="b", size="30pt")
# Add Axis Labels
styles = {"color": "#f00", "font-size": "20px"}
self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
#Add legend
self.graphWidget.addLegend()
#Add grid
self.graphWidget.showGrid(x=True, y=True)
#Set Range
self.graphWidget.setXRange(0, 10, padding=0)
self.graphWidget.setYRange(20, 55, padding=0)
pen = pg.mkPen(color=(255, 0, 0))
self.graphWidget.plot(hour, temperature, name="Sensor 1", pen=pen, symbol='+', symbolSize=30, symbolBrush=('b'))
# Set the cursor for the plotwidget. The mouse cursor will change when over the plot.
cursor = Qt.CrossCursor
self.graphWidget.setCursor(cursor)
app = QApplication(sys.argv)
main = MainWindow()
main.show()
app.exec_()
If you run this you'll see a crosshair cursor appear when you hover your mouse over the plot.
Crosshair cursor on a PyQtGraph PlotWidget
Drawing a custom crosshair cursor with InfiniteLine
If you want to show a completely custom cursor — for example, a full-size crosshair overlay spanning the entire plot — things are a little trickier. In this case you need to draw the cursor yourself by adding elements to the plot and then listening for mouse events to update their position.
The code below is an updated version of the plot above, with two crosshair lines added using PyQtGraph's InfiniteLine objects. The lines are created in the __init__ method and then updated in the update_crosshair method whenever the mouse moves.
You could also add any other QGraphicsScene item here instead.
The important part is the SignalProxy which forwards mouse movement signals to our custom update_crosshair method. The rateLimit parameter
sets the maximum number of signals per second which will be sent, to avoid overloading our handler/app with excessive events.
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import Qt
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys # We need sys so that we can pass argv to QApplication
import os
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.graphWidget = pg.PlotWidget()
self.setCentralWidget(self.graphWidget)
hour = [1,2,3,4,5,6,7,8,9,10]
temperature = [30,32,34,32,33,31,29,32,35,45]
#Add Background colour to white
self.graphWidget.setBackground('w')
# Add Title
self.graphWidget.setTitle("Your Title Here", color="b", size="30pt")
# Add Axis Labels
styles = {"color": "#f00", "font-size": "20px"}
self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
#Add legend
self.graphWidget.addLegend()
#Add grid
self.graphWidget.showGrid(x=True, y=True)
#Set Range
self.graphWidget.setXRange(0, 10, padding=0)
self.graphWidget.setYRange(20, 55, padding=0)
pen = pg.mkPen(color=(255, 0, 0))
self.graphWidget.plot(hour, temperature, name="Sensor 1", pen=pen, symbol='+', symbolSize=30, symbolBrush=('b'))
# Add crosshair lines.
self.crosshair_v = pg.InfiniteLine(angle=90, movable=False)
self.crosshair_h = pg.InfiniteLine(angle=0, movable=False)
self.graphWidget.addItem(self.crosshair_v, ignoreBounds=True)
self.graphWidget.addItem(self.crosshair_h, ignoreBounds=True)
self.proxy = pg.SignalProxy(self.graphWidget.scene().sigMouseMoved, rateLimit=60, slot=self.update_crosshair)
def update_crosshair(self, e):
pos = e[0]
if self.graphWidget.sceneBoundingRect().contains(pos):
mousePoint = self.graphWidget.getPlotItem().vb.mapSceneToView(pos)
self.crosshair_v.setPos(mousePoint.x())
self.crosshair_h.setPos(mousePoint.y())
app = QApplication(sys.argv)
main = MainWindow()
main.show()
app.exec_()
If you run this example, in addition to the mouse cursor you'll also see a faint yellow line overlaying the plot.
Custom crosshair overlay with the default mouse cursor still visible
Hiding the default mouse cursor over the plot
To hide the default mouse cursor over the plot, set the cursor type to Qt.BlankCursor. This gives you a clean crosshair-only cursor experience.
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# ... rest of __init__ as before
# Hide the cursor over the plot.
cursor = Qt.BlankCursor
self.graphWidget.setCursor(cursor)
This will give the following result when hovering over the plot.
The custom crosshair cursor with the default mouse cursor hidden
PyQt/PySide 1:1 Coaching with Martin Fitzpatrick
Save yourself time and frustration. Get one on one help with your Python GUI projects. Working together with you I'll identify issues and suggest fixes, from bugs and usability to architecture and maintainability.