Matplotlib y_achse bei live Graph festsetzen

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Finn_h
User
Beiträge: 12
Registriert: Samstag 30. Mai 2020, 08:51

Hallo,
Ich möchte aktuelle Temperaturdaten (hier mit random.randint simuliert) in einen live Graphen schreiben. Alte Werte sollen nach links "rausgedrückt" werden. Das funktioniert auch soweit, nur dass meine y-Achse sich seltsam verhält. Normalerweise sollten größere Wert höher stehen als kleinere Werte. Bei mir werden die allerdings einfach nach der Reihenfolge in der sie ankommen (zufällig) angeheftet.
Meine Vermutung ist, dass das relativ leicht machbar ist. Ich finde dazu allerdings nichts.
Ich hoffe es findet sich jemand, der mir helfen kann.

Code: Alles auswählen


import time
import threading
import random
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation


def temperature_to_txt():
    file = open("Temperatur3.txt", "w")
    file.close()
    while True:
        zufalls_temp = random.randint(25, 30)
        print(zufalls_temp)
        aktuelle_zeit = time.strftime("%H:%M:%S")


        with open('Temperatur3.txt') as f:
            list_length = (sum(1 for _ in f))

        if list_length <= 5:
            file = open("Temperatur3.txt", "a")
            file.write(str(aktuelle_zeit) + "," + str(zufalls_temp) + "\n")
            file.close()

        elif list_length > 5:
            file = open("Temperatur3.txt", "r")
            lines = file.readlines()
            lines.pop(0)
            file = open("Temperatur3.txt", "w")
            file.write(str(lines[0])+str(lines[2])+str(lines[3])+str(lines[4]))
            file.write(str(aktuelle_zeit) + "," + str(zufalls_temp) + "\n")
            file.close()

        time.sleep(1)


def animate(i):
    graph_data = open("Temperatur3.txt", "r").read()
    lines = graph_data.split("\n")
    xs = []
    ys = []
    for line in lines:
        if len(line) > 1:
            x, y = line.split(",")
            xs.append(x)
            ys.append(y)
    plt.cla()
    plt.plot(xs, ys)
    plt.tight_layout()


def main():

    threading.Thread(
        target = temperature_to_txt, daemon= True
    ).start()

    plt.style.use("fivethirtyeight")
    ani = FuncAnimation(plt.gcf(), animate, interval = 1000)


    plt.show()

if __name__ == "__main__":
    main()




MfG
Sirius3
User
Beiträge: 17752
Registriert: Sonntag 21. Oktober 2012, 17:20

Dateien, die man öffnet, sollte man auch wieder schließen. Am besten benutzt man dazu das with-Statement.
Wenn Du eh die ganze Datei liest, um die Anzahl der Zeilen herauszu bekommen, kannst Du Dir auch gleich den Inhalt merken.
Beim Lesen und Schreiben immer ein Encoding angeben. Strings stückelt man nicht mit + zusammen, sondern benutzt Format-Strings.
Benutzt keine Abkürzungen.

Code: Alles auswählen

TEMPERATURE_FILENAME = "Temperatur3.txt"

def temperature_to_txt():
    with open(TEMPERATURE_FILENAME, "w", encoding="ASCII"):
        pass
    while True:
        zufalls_temperatur = random.randint(25, 30)
        with open(TEMPERATURE_FILENAME, encoding="ASCII") as input:
            lines = input.readlines()
        lines.append(f"{DateTime.now():%H%M:%S},{zufalls_temperatur}\n")
        lines = lines[-5:]
        with open(TEMPERATURE_FILENAME, "w", encoding="ASCII") as output:
            output.writelines(lines)
        time.sleep(1)
Da Du sowieso nur eine Schleife hast, die schreibt, brauchst Du auch nicht die Dateien immer wieder zu lesen.

Code: Alles auswählen

def temperature_to_txt():
    lines = []
    while True:
        zufalls_temperatur = random.randint(25, 30)
        print(zufalls_temp)
        lines.append(f"{DateTime.now():%H%M:%S},{zufalls_temperatur}\n")
        lines = lines[-5:]
        with open(TEMPERATURE_FILENAME, "w", encoding="ASCII") as output:
            output.writelines(lines)
        time.sleep(1)
Und eigentlich brauchst Du die Daten gar nicht in eine Datei schreiben, sondern kannst sie auch direkt übergeben:

Code: Alles auswählen

import time
import threading
import random
import matplotlib.pyplot as plt
from datetime import datetime as DateTime
from matplotlib.animation import FuncAnimation
from collections import deque

def temperature_to_queue(queue):
    while True:
        zufalls_temperatur = random.randint(25, 30)
        queue.append((DateTime.now(), zufalls_temperatur))
        time.sleep(1)

def animate(frame, ax, queue):
    ax.cla()
    return ax.plot(*zip(*queue))

def main():
    queue = deque([],maxlen=5)
    threading.Thread(
        target=temperature_to_queue, args=(queue,), daemon=True
    ).start()
    fig, ax = plt.subplots()
    ani = FuncAnimation(fig, animate, fargs=(ax, queue,), interval=1000)
    plt.show()

if __name__ == "__main__":
    main()
Finn_h
User
Beiträge: 12
Registriert: Samstag 30. Mai 2020, 08:51

Das ist natürlich sehr schlank. Danke dir. Das hilft mir sehr weiter!

Nur mal aus Interesse, wodran lag das bei meinem Code, dass die y-Achse sich so seltsam verhält und wäre mein Code noch zu retten?
Antworten