Probleme mit dynamischen Graphen - matplotlib

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
InDieRöhreGucker
User
Beiträge: 2
Registriert: Dienstag 31. August 2021, 14:26

Hey liebe Leute,

ich habe folgendes Problem:
Ich möchte analoge Werte von einer analogen Box(Gantner A5) lesen und grafisch darstellen. Diese Werte sollen dann grafisch dargestellt werden. Also es soll ein Graph in "Echtzeit" gezeichnet werden.
Soweit so gut.
Ich habe die Kommunikation über eine rs485 Verbindung realisiert. Auch die Werte lassen sich grafisch darstellen und es funktioniert soweit.

Jetzt kommt das "Problem": Sobald ich ein paar Buttons einfüge um das Event zu starten (siehe Code: thread_f), bzw. zu stoppen, oder anzuhalten, funktioniert das zeichnen nicht mehr. Und ich kann mir nicht erklären wieso.

Hier einmal der Code:

Code: Alles auswählen


from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.widgets import Button

from threading import Thread

class ZeichneGraph:
def __init__(self): #konstruktor
        self.x_data, self.y_data = [], []
        self.m_figure = plt.figure()
        self.line, = plt.plot(self.x_data, self.y_data)            
        self.animation = FuncAnimation(self.m_figure, self.update, interval=500)

    def update(self, frame):
        if(len(self.x_data)==len(self.y_data)): # manchmal passiert es, dass der Thread den Wert zu früh schickt -> Fehler-> daher len vgl.
            self.line.set_data(self.x_data, self.y_data)
            self.m_figure.gca().relim()
            self.m_figure.gca().autoscale_view()
        return self.line,

    def show(self):
        plt.show()

    def thread_f(self): # füllt durch Thread Daten in die Container
        x = 0
        while True:
            self.x_data.append(x)
            x += 1
            self.y_data.append(get_Data_from_A5(ser,0))   # hole Daten von Analogbox / anstatt dieser Werte können auch einfach rnd. Werte erzeut werden
            time.sleep(1) 

    def thrd_start(self, event):
        self.th = Thread(target=self.thread_f, daemon=True)
        self.th.start()

   def b_test(self,k1,k2,k3,k4,name):
        m_funk = Button(plt.axes([k1, k2, k3, k4]), name)
        return m_funk      

g = ZeichneGraph()

start = g.b_test(0.8, 0.01, 0.1, 0.04,'Start')
start.on_clicked(g.thrd_start)

g.show()


Ich hatte davor den Thread im Konstruktor gestartet. Damit hat das super funktioniert.

Code: Alles auswählen

 def __init__(self): #konstruktor
        self.x_data, self.y_data = [], []
        self.m_figure = plt.figure()
        self.line, = plt.plot(self.x_data, self.y_data)            
        self.animation = FuncAnimation(self.m_figure, self.update, interval=500)
        self.th = Thread(target=self.thread_f, daemon=True)
        self.th.start()
Dann hab ich einen Button hinzugefügt um das Event per Knopfdruck starten zu können, seitdem wird es leider nicht mehr grafisch dargestellt. Also die Werte werden abgeholt (hab sie mir mit print() ausgeben lassen), nur nicht mehr grafisch angezeigt.. und ich weiß einfach nicht warum...

Die Funktion:

Code: Alles auswählen

   def b_test(self,k1,k2,k3,k4,name):
        m_funk = Button(plt.axes([k1, k2, k3, k4]), name)
        return m_funk
 
... hab ich nur zu testzwecken hinzugefügt. Ich will, wenn ich das Problem gelöst habe, weitere Buttons erstellen, die das Programm steuern.


Kann mir hier wer helfen?
tonikae
User
Beiträge: 90
Registriert: Sonntag 23. Februar 2020, 10:27

Nach "on_clicked" springst du in: "thrd_start".
Bis dahin ist es auch OK
Nur in "thrd-start" sehe ich dann kein:

fig.canvas.draw_idle()

um den Plot nach dem auftreten eines Widget-Events zu aktualisieren.

Vereinfacht sollte es so aussehen:

Code: Alles auswählen

def myFunc(event):
    <Mach irgendwas>
    fig.canvas.draw_idle()   # Plot aktualisieren

 button.on_clicked(myFunc)
InDieRöhreGucker
User
Beiträge: 2
Registriert: Dienstag 31. August 2021, 14:26

Danke tonikae für deine Antwort.

Leider funktioniert das damit immer noch nicht =/

ich habe ausprobiert:

Code: Alles auswählen

    def thrd_start(self, event):
        self.m_figure.canvas.draw_idle()
        self.th = Thread(target=self.thread_f, daemon=True)
        self.th.start()
        #hab es auch an dieser Stelle eingefügt
das hat nicht funktioniert.
Dann hab ich es an dieser Stelle mal versucht:

Code: Alles auswählen

    def thread_f(self): # füllt selbststädnig Daten in die Container
        x = 0
        while True:
            self.x_data.append(x)
            x += 1
            self.y_data.append(get_Data_from_A5(ser,0))   # hole Daten von Analogbox / anstatt dieser Werte können auch einfach rnd. Werte erzeut werden
            self.m_figure.canvas.draw_idle()
            time.sleep(1) 
leider auch ohne Erfolg =/

Gibt es noch andere Lösungsansätze?
Grüße
Antworten