Blog der Heimetli Software AG

Dynamisches Diagramm mit matplotlib

Dass matplotlib recht cool ist wusste ich schon lange, aber dass es ein animation-Modul enthält war mir neu. Das musste ich selbstverständlich gleich ausprobieren.

Es finden sich diverse Beispiele im Internet, aber genau das was ich haben wollte war nicht dabei. Also blieb nur selbermachen.

Das Ziel: ein CSV mit einer Zeitreihe als Liniendiagramm darstellen und die Graphik periodisch mit den aktuellsten Daten neu zeichnen.

Dank matplotlib ist das gar nicht so schwer wenn man mal herausgefunden hat wie es geht. Am meisten Probleme machte die Zeitachse. Die Format-Einstellungen gehen beim clear() des Plots verloren und müssen immer wieder neu gesetzt werden.

Das Resultat

Diagramm, gespeichert aus dem Matplotlib-Window

Zugegeben, das sieht nicht überwältigend aus. Für die paar Zeilen Code ist es aber schon ganz überzeugend.

Die zu Testzwecken frei erfundenen Daten verbessern den Eindruck natürlich auch nicht. Mit realen Daten und ein paar Punkten mehr dürfte es ganz vernünftig aussehen.

Der Code

# Import the required modules
from datetime import datetime
from matplotlib.animation import FuncAnimation
from matplotlib import style
import matplotlib.pyplot as plt
import matplotlib.dates  as dates
import csv
import sys

# Set the style of the plot
style.use( 'ggplot' )

# Create figure and axes
fig, ax = plt.subplots()

# Update the plot
def update( frame ):
    try:
        xs = []
        ys = []

        # Read and parse the CSV file
        with open("data.csv",newline="") as file:
            reader = csv.reader( file )

            for row in reader:
                if len(row) > 1:
                    xs.append( datetime.strptime(row[0],"%H:%M") )
                    ys.append( float(row[1]) )

        if len(xs) > 0:
            # Renew the plot
            ax.clear()
            ax.xaxis.set_major_formatter( dates.DateFormatter("%H:%M") )
            ax.plot( xs, ys )
    except:
        print( "Error: can't read file, ", sys.exc_info()[0] )

# Draw the initial graph
update( None )

# Update the graph every twenty seconds
ref = FuncAnimation( fig, update, interval=20000 )

# Show the plot
plt.show()

Die Hauptarbeit wird von der Funktion update geleistet. Sie liest und parst das CSV, löscht den Graph und lässt ihn neu zeichnen.

Die Fehlerbehandlung ist eher simpel gehalten, weil es bei einem interaktiven Programm dieser Art auffallen müsste wenn nichts dargestellt wird.

Speziell ist die Abfrage ob es überhaupt Messwerte gibt. Wenn plot mit einer leeren Zeitachse aufgerufen wird, dann wirft die Funktion eine recht unverständliche Exception...

Zwei Angaben sind hart codiert die wohl besser Parameter wären: das Datenfile muss data.csv heissen, und die Refresh-Zeit ist auf 20 Sekunden festgelegt.

Die Daten

Das Bild oben wurde mit folgendem File erzeugt:

11:05,11
11:06,13
11:07,12
11:10,10
11:11,11
11:12,11
11:13,12
11:15,15
11:16,13
11:17,14

Der Aufbau ist trivial: Uhrzeit in der Form hh:mm, gefolgt vom Wert.

Wenn ein neuer Messwert dazukommt, wird das Diagramm nach spätestens 20 Sekunden aktualisiert. Für eine Temperaturmessung oder etwas ähnlich träges müsste das ausreichend sein.