Hallo, ich bin Neuling in Sachen GUI, aber ich habe es schon fast
geschafft (siehe Bildchen).
Was will ich machen/was habe ich?
Ich habe eine Hardware der ich über UART Befehle schicken kann und auch
mit einem Befehl Samples eines ADCs lesen kann. Das klappt auch alles
fein aus der GUI. Jetzt will ich die Samples auch plotten. Nicht nur
einmal, sondern oft. Das wiederholt sich also, es werden neue Samples
gelesen und diese sollen wieder geplottet werden.
Für die GUI habe ich TKinter verwendet, das ist ganz brauchbar wie ich
finde. Darin habe ich dann eine Funktion aufgemacht die sich selbst
zylisch wieder aufruft.
1
def task_plot():
2
#...
3
root.after(1000,task_plot)
Sie wird einmalig gestartet mit
1
root.after(100,task_plot)
Das geht auch.
In dieser Funktion habe ich dann die Plotfunktion drinnen
1
fig = plt.figure()
2
ax1 = fig.add_subplot(211)
3
ax2 = fig.add_subplot(212)
Und es wird ein Canvas aufgemacht
1
canvas = FigureCanvasTkAgg(fig, master = root)
2
canvas._tkcanvas.place(x=100,y=10)
Das funktioniert auch, die neuen Daten werden gelesen, sie werden neu
geplottet und schön angezeigt. Aber: Der RAM läuft schnell voll.
Klar, kann ich auch verstehen, das ist ja nach meinem Verständniss eine
Funktion und immer wenn die neu aufgerufen wird, werden die Variablen
lokal neu erzeugt und nicht nur mit neuen Inhalten gefüllt.
Tja ... wie macht man das richtig?
Den ganzen Code habe ich in den Anhang gepackt, da sind bestimmt viele
unschöne Anfängerdinge drinnen. Die Serielle Schnittstelle ist dort
leider nötig um Daten zu bekommen.
Vielen Dank!
Ja, also tatsächlich kenne ich mehrere Parteien inkl. mir die matplotlib
für Echtzeit-Visualisierung benutzt haben und keine davon ist so
wirklich glücklich geworden, aus Gründen wie dem von dir beschriebenen.
Die Bibliothek ist einfach nicht dafür gedacht ...
Ich glaube, man muss da was anderes nehmen als matplotlib. So einen
richtig guten Vorschlag hab ich allerdings auch nicht.
Gustl B. schrieb:> Hallo, ich bin Neuling in Sachen GUI, aber ich habe es schon fast> geschafft (siehe Bildchen).
Das ist ja schonmal nicht schlecht für einen Anfänger. ;-)
> Den ganzen Code habe ich in den Anhang gepackt, da sind bestimmt viele> unschöne Anfängerdinge drinnen.
Das Schlüsselwort "global" dient in Python dazu, eine globale Variable
aus einem anderen Scope heraus anzulegen, zum Beispiel aus einer
Funktion:
1
#!/usr/bin/env python
2
importtraceback
3
4
defcreate_globals():
5
globala,b
6
a=5
7
b='hello'
8
9
defcreate_vars():
10
return5,'hello'
11
12
13
if__name__=='__main__':
14
15
try:print('a =',a)
16
except:traceback.print_exc()
17
18
try:print('b =',b)
19
except:traceback.print_exc()
20
21
print("before call")
22
create_globals()
23
print("after call")
24
25
print('a =',a)
26
print('b =',b)
27
28
c,d=create_vars()
29
print('c =',c)
30
print('d =',d)
Zudem würde ich für eine solche Applikation auf Matplotlib verzichten,
die Library ist zum einmaligen Plotten gedacht und eignet sich daher
nicht gut für Visualisierungen, die regelmäßig aktualisiert werden
sollen. Dafür ist Tkinters Canvas besser geeignet -- oder vielleicht
eine kleine Webanwendung mit einer Javascript-Plottinglibrary wie flot,
jqWidgets oder jqplot.
OK, keine Matplotlib. Kann dieses Tkinters Canvas auch plotten?
Wie man globale Variablen anlegt weiß ich. Sollte ich alles global
machen? Also auch fig und ax und den ganzen Rest?
Sheeva P. schrieb:> [Dinge]
Ach ja, noch so eine kleine Anregung: man kann Tkinter-Widgets natürlich
auch objektorientiert benutzen, also einfach von Tkinter.Tk erben. Da
Tkinter noch auf "old-style"-Klassen basiert, muß man dabei aber auf
super() verzichten und den Konstruktor der Parent-Klasse namentlich
aufrufen:
Gustl B. schrieb:> OK, keine Matplotlib. Kann dieses Tkinters Canvas auch plotten?> Wie man globale Variablen anlegt weiß ich.
Nein, eben nicht. Dieses ganze "global" auf der obersten Ebene kannst Du
Dir komplett sparen!
> Sollte ich alles global machen? Also auch fig und ax und den ganzen Rest?
Lieber nicht. Ich arbeite seit mittlerweile über zehn Jahren fast
täglich mit Python, und habe das Schlüsselwort "global" in dieser ganzen
Zeit noch nicht wirklich gebraucht. Arbeite lieber mit Parametern und
Rückgabewerten.
Auch wenn es nicht direkt eine Antwort auf die eigentliche Frage ist,
aber wie fixiert bist Du auf Python? Für QT/C++ gibt es beispielsweise
qcustomplot, wobei es scheinbar recht aktuell auch etwas QT-"natives"
gibt (Qt Charts, genutzt habe ich das nicht).
Es gibt ja auch irgendwie PyQt, eventuell lässt sich das damit
verbinden? Wirft natürlich die Tk UI wieder über den Haufen...
Also ich kann auch C, aber in Python ist halt schon echt viel Zeug
dabei. Ich will mir z. B. auch die FFT plotten lassen und mit Python
geht das echt einfach. Ich weiß nicht wie ich da in C herangehen würde.
Qt habe ich auch gesehen, habe aber diese TkInter verwendet weil es bei
Python dabei ist. Ich will möglichst wenig Abhängigkeiten haben.
Ne, wenn du in C einen Plot mit einer FFT drin haben willst, ist das der
Tod. Biste drei Tage beschäftigt. Ich hab's dann am Ende so gemacht,
aber wirklich zufrieden bin ich nicht, in Python wäre das alles
einfacher und viel weniger Aufwand. Naja.
Ist immer nur eine Frage der Zeit bis auf eine Frage der Art "Wie löse
ich Problem X in Sprache Y?" eine Antwort der Art "Schmeiß dein
bisheriges Programm weg und nimm Sprache Y!" kommt.
Hauptsache seinen Senf dazugeben.
Hallo,
noch eine Frage zur Struktur :
----------
Die Importe sind klar die stehen am Anfang des Programms.
----------
Tkinter ist Deine GUI und hat einen Mainloop.
root = tkinter.Tk()
root.wm_title("Programmname")
root.minsize(width=1280, height=640)
root.maxsize(width=1280, height=640)
root.mainloop()
-----------
Steht folgendes im Mainloop ? :
fig = pylab.figure(num=None, figsize=(16, 8), dpi=80, facecolor='w',
edgecolor='k')
plt.subplots_adjust(left=0.05, bottom=0.1, right=0.98, top=0.96,
wspace=0, hspace=0.1)
ax1 = fig.add_subplot(111)
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas.get_tk_widget().place(x=0,y=0)
canvas._tkcanvas.place(x=0,y=0)
-----------
Rufst Du dann die Funktion Plotter aus Deinem Mainloop auf und lässt die
Funktion immer neu starten wie
zum Beispiel mit Plotter.after(1000,Plotter) ?
Danke für die Hilfe !
Nur der Plotter ist in der Schleife. Ich lade mal das ganze Skript hoch.
Das hat noch mehrere Funktionen. Ganz grob:
Das fragt über UART am FPGA an, bekommt Sampledaten, die werden dann
jeweils ans Sampledatenarray angehängt und der älteste Wert entfernt.
Die Arrays werden dann geplottet.
> LTC2372_0_data = [0] * 1024
> LTC2372_1_data = [0] * 1024
> LTC2372_2_data = [0] * 1024
> LTC2372_3_data = [0] * 1024
> LTC2372_4_data = [0] * 1024
> LTC2372_5_data = [0] * 1024
> LTC2372_6_data = [0] * 1024
> LTC2372_7_data = [0] * 1024
Sowas schreit doch gerade zu nach einer list() und Behandlung in
Schleifen. Beim Programmieren ist unbedingt auf das Dry Prinzip zu
achten. Außerdem suggeriert Uppercase erfahrenden Entwicklern das es
sich um eine Konstante handelt.
Natürlich, das ist nur zum Testen der Hardware gedacht und von älteren
Skripten kopiert. Bevor ist da mit list anfange habe ich das mehrmals
kopiert.
imonbln schrieb:> Außerdem suggeriert Uppercase erfahrenden Entwicklern das es> sich um eine Konstante handelt.
Ist das so? Ja, sieht man oft, stimmt, aber ist das irgendwo so
definiert?
Gustl B. schrieb:> Ist das so? Ja, sieht man oft, stimmt, aber ist das irgendwo so> definiert?
Für Python in pep8 siehe
https://www.python.org/dev/peps/pep-0008/#constants. Aber noch viel mehr
ist es eine Art gutes Benehmen, ähnlich wie man grüßt wenn mein einen
Raum betritt, es ist einfach eine Höflichkeit die dafür sorgt das andere
sich in den eigen Sourcecode wohlfühlen.
Kannte ich noch nicht. Nun, das ist write-only Code. Den habe ich hier
nur hochgeladen damit nachvollziehbar wird wie ich mein Problem gelöst
habe.
Aber werde ich in Zukunft besser machen.