Liniendiagramm mit PyQt6 und PyQtGraph erstellen

In den bisher hier vorgestellten Beispielen zur Datenvisualisierung wurde auf Matplotlib (und Jupyter Notebook) zurückgegriffen. Es gibt aber auch noch andere Wege. Und die führen uns zu PyQt6 und PyQtGraph. Die Installation kann mit pip vorgenommen werden:

$ pip install PyQt6 pyqtgraph  # Windows
$ pip3 install PyQt6 pyqtgraph # macOS

Hinsichtlich der darzustellenden Daten geht es in diesem Beispiel um die Schulden der Landeshauptstadt Kiel. Der Datensatz liegt im CSV-Format vor. Nach dem Download habe ich diese Datei zu „kiel_debt.csv“ umbenannt.

Wie zu erwarten, geht es mit den Import-Anweisungen los:

import sys
import csv

from PyQt6 import QtWidgets, QtCore
import pyqtgraph as pg

Es ist zu beachten, das pyqtgraph nach PyQt6 importiert werden sollte.

Das Lesen der CSV-Datei, die sich hier im gleichen Verzeichnis befindet, erledigt eine Funktion mit der Bezeichnung read_csv():

def read_csv() -> tuple:
    filename = 'kiel_debt.csv'
    with open(filename) as csv_file:
        reader = csv.reader(csv_file, delimiter=';')
        _ = next(reader)

        years, values = [], []

        for row in reader:
            year = int(row[4])
            years.append(year)
            value = int(row[5])
            values.append(value)

    return (years, values)

Die CSV-Datei enthält mehrere Spalten. Von Interessen sind in diesem Fall aber nur die Jahre (Spalte 5) und die Höhe der Schulden (Spalte 6). Im Ergebnis werden diese Werte dann als Tuple zurückgegeben.

Für das Erzeugen des Fenster MainWindow ist die gleichnamige Klasse zuständig. Von hier aus wird außerdem die Funktion read_csv() aufgerufen.

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        years, values = read_csv()

Zur Visualisierung der Daten wird PlotWidget() benötigt:

 self.graphWidget = pg.PlotWidget()
 self.setCentralWidget(self.graphWidget)

Dann folgen einige Angaben hinsichtlich des Aussehens (Überschrift, Hintergrund, Schriftgröße, Bezeichnung der X- und der Y-Achse):

 self.graphWidget.setTitle("Kiel Debt", color="b", size="30pt")
 self.graphWidget.setBackground("w")

 styles = {'color': 'r', 'font-size': '12pt'}
 self.graphWidget.setLabel('left', 'Euro', **styles)
 self.graphWidget.setLabel('bottom', 'Years', **styles)

Soll ein Hintergrundgitter erscheinen, ist noch folgende Zeile erforderlich:

self.graphWidget.showGrid(x=True, y=True)

Die zu zeichnende Linie kann ebenfalls individualisiert werden, wobei hier eine gestrichelte Linie (DashLine) definiert wird:

pen = pg.mkPen(color=(255, 0, 0), width=6, style=QtCore.Qt.PenStyle.DashLine)

Und dann kann die Grafik auch schon erstellt werden:

self.graphWidget.plot(years, values, pen=pen)

Die Klasse muss selbstverständlich auch noch instanziiert werden, was in PyQt6 wie folgt aussieht:

def main():
    app = QtWidgets.QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    app.exec()


if __name__ == '__main__':
    main()

Um nicht den Überblick zu verlieren, zum Schluss noch der komplette Code:

import sys
import csv

from PyQt6 import QtWidgets, QtCore
import pyqtgraph as pg


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        years, values = read_csv()

        self.graphWidget = pg.PlotWidget()
        self.setCentralWidget(self.graphWidget)

        self.graphWidget.setTitle('Kiel Debt', color='b', size='30pt')
        self.graphWidget.setBackground('w')

        styles = {'color': 'r', 'font-size': '12pt'}
        self.graphWidget.setLabel('left', 'Euro', **styles)
        self.graphWidget.setLabel('bottom', 'Years', **styles)

        self.graphWidget.showGrid(x=True, y=True)

        pen = pg.mkPen(color=(255, 0, 0), width=6, style=QtCore.Qt.PenStyle.DashLine)

        self.graphWidget.plot(years, values, pen=pen)


def read_csv() -> tuple:
    filename = 'kiel_debt.csv'
    with open(filename) as csv_file:
        reader = csv.reader(csv_file, delimiter=';')
        _ = next(reader)

        years, values = [], []

        for row in reader:
            year = int(row[4])
            years.append(year)
            value = int(row[5])
            values.append(value)

    return (years, values)


def main():
    app = QtWidgets.QApplication(sys.argv)
    main_window = MainWindow()
    main_window.show()
    app.exec()


if __name__ == '__main__':
    main()