Ich arbeite an einem Programm, wo ich zwei verschiedene Grafiken benötigt, um animiert zu werden. Ich habe Schwierigkeiten, mit der Struktur, die ich benutze, zu verfahren. Ich werde meinen Code unten einfügen, damit Sie es ausprobieren können. Ich habe es so weit wie möglich abgespeckt und gleichzeitig die Kernfunktionalität beibehalten, so dass es hoffentlich nicht zu schwer zu verstehen ist. In ihrem momentanen Zustand machen die Animationslinien nichts, also lass mich wissen, wo ich falsch gelaufen bin.Tkinter/Matplotlib Animation Hilfe
from Tkinter import * #Used for GUI elements
import time #Used for timing elements
import matplotlib #Used for graphing
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
import numpy as np #Used for arrays to find min/max of float array
import random #Only used for fake data input
class tkgui:
def __init__(self, parent):
#--------------The following are variables that need to be accessed by other functions----------------------
#Raw input values
self.x = 209500
self.y = 0
self.timeElapsed = 0
#State values
self.curFrame = 1
#List Values
self.timeList = np.array([])
self.yList = np.array([])
self.xList = np.array([])
self.lastX = 0
#----------------------------------------------------------------------------------------------------------
#Make Tkinter fullscreen
w, h = 320,240 #int(str(root.winfo_screenwidth())), int(str(root.winfo_screenheight())) #320, 240 is the RPiTFT
#The base layer of the GUI
topLevelContainer = Frame(parent)
topLevelContainer.pack()
#The two 'screens' to switch between. They contain everything on the GUI
self.buttonsFrame = Frame(topLevelContainer)
self.graphFrame = Frame(topLevelContainer)
#Stack the frames so that they are switchable
for frame in self.buttonsFrame, self.graphFrame:
frame.grid(row=0, column=0, sticky='news', padx=5, pady=(10, 10))
buttonsFrameButtons = Frame(self.buttonsFrame)
buttonsFrameButtons.pack(side=LEFT, padx=(0, 50))
#X button
self.xButton = Button(buttonsFrameButtons, command=self.xButtonClick)
self.xButton.configure(text="X", background="#C8C8C8", width=6, padx=35, pady=35)
self.xButton.pack(side=TOP, pady=10)
#Y button
self.yButton = Button(buttonsFrameButtons, command=self.yButtonClick)
self.yButton.configure(text="Y", background="#C8C8C8", width=6, padx=35, pady=35)
self.yButton.pack(side=TOP, pady=10)
#Bar graph
buttonsFrameBar = Frame(self.buttonsFrame)
buttonsFrameBar.pack(side=LEFT)
self.fBar = Figure(figsize=(2, 4), dpi=50)
aBar = self.fBar.add_subplot(111)
self.xBar = aBar.bar([0, 1], [0, 0], width=1)
lAxes = self.fBar.gca()
lAxes.axes.get_xaxis().set_ticklabels([])
aBar.set_ylim([-30000, 30000])
self.fBar.tight_layout()
self.buttonsFrame.tkraise()
#Setup the matplotlib graph
self.fGraph = Figure(figsize=(5, 3), dpi=50)
#Create the Y axis
aGraph = self.fGraph.add_subplot(111)
aGraph.set_xlabel("Time (s)")
aGraph.set_ylabel("Y")
self.yLine, = aGraph.plot([],[], "r-")
#Create the X axis
a2Graph = aGraph.twinx()
self.xLine, = a2Graph.plot([], [])
a2Graph.set_ylabel("X")
#Final matplotlib/Tkinter setup
self.canvasGraph = FigureCanvasTkAgg(self.fGraph, master=self.graphFrame)
self.canvasGraph.show()
self.canvasGraph.get_tk_widget().pack(side=LEFT, fill=BOTH, expand=1)
self.canvasBar = FigureCanvasTkAgg(self.fBar, master=buttonsFrameBar)
self.canvasBar.show()
self.canvasBar.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=1)
#Resize the plot to fit all of the labels in
self.fGraph.subplots_adjust(bottom=0.13, left=0.15, right=0.87)
def refreshGraph(self, frameno): #Redraw the graph with the updated arrays and resize it accordingly
#Update data
self.yLine.set_data(self.timeList, self.yList)
self.xLine.set_data(self.timeList, self.xList)
#Update y axis
ax = self.canvasGraph.figure.axes[0]
ax.set_xlim(self.timeList.min(), self.timeList.max())
ax.set_ylim(self.yList.min(), self.yList.max())
#Update x axis
ax2 = self.canvasGraph.figure.axes[1]
ax2.set_xlim(self.timeList.min(), self.timeList.max())
ax2.set_ylim(self.xList.min(), self.xList.max())
#Redraw
self.canvasGraph.draw()
def refreshBar(self, frameno):
curX = self.x
dif = curX - self.lastX
i = [dif]
for rect, h in zip(self.xBar, i):
rect.set_height(h)
if dif > 0:
rect.set_color('b')
else:
rect.set_color('r')
self.canvasBar.draw()
self.lastX=curX
def switchFrame(self): #Switch the current screen. Either x/y buttons or graph
if self.curFrame:
self.graphFrame.tkraise()
self.curFrame = 0
else:
self.buttonsFrame.tkraise()
self.curFrame = 1
def xButtonClick(self):
self.switchFrame()
def yButtonClick(self):
self.close()
def close(e): #Exit the program
sys.exit()
#Initialisation of global variables
lastTime = 0 #Used for the 'last time' iterated
yState = 0
def updateNumbers(): #Used to generate fake input variables. Will be replaced by ADC values
global lastTime
global yState
curTime = time.time() #Update the time each time the function is called
if curTime - lastTime > 0.5: #Only update numbers every 0.5 seconds
gui.x = random.randrange(200000, 230000) #Generates x
if yState:
gui.y = gui.y - 20 #Decrease y
if gui.y < 1:
yState = 0 #Until it gets to a minimum of 0
else:
gui.y = gui.y + 20 #Increase y
if gui.y > 1300:
yState = 1 #Until it reaches a maximum of 1300
gui.yList = np.append(gui.yList, gui.y) #Add the new y values to the array
gui.xList = np.append(gui.xList, gui.x/10000.0) #Add the new x values to the array
lastTime = time.time() #Record the last time iterated for timing purposes
gui.timeElapsed += 0.5
gui.timeList = np.append(gui.timeList, gui.timeElapsed) #Add the latest time to the array
## gui.refreshGraph() #Call the function that will redraw the graph with the new figures
if __name__ == "__main__":
root = Tk() #Root Tkinter setup
gui = tkgui(root) #Setup the gui class
updateNumbers()
aniGraph = animation.FuncAnimation(gui.fGraph,gui.refreshGraph,interval=500,frames=100,repeat=True)
aniBar = animation.FuncAnimation(gui.fBar,gui.refreshBar,interval=500,frames=100,repeat=True)
while(1): #Main loop
updateNumbers() #Update fake values
root.update() #Update the gui loop
root.mainloop() #Tkinter main loop
Um klar zu sein, frage ich nur, wie man die Animation für diesen Code funktioniert.
wenn Sie 'while (1):' 'dann root.mainloop () 'wird nie benutzt werden. Am Ende von 'updateNumber' können Sie' root.after (500, updateNumber) 'verwenden und nach 500ms (0.5s) wird' updateNumber' erneut ausgeführt, so dass Sie keine while (1) 'Schleife benötigen. – furas
Beim Start sehe ich Balkenanimation und nachdem ich auf X geklickt habe, sehe ich Linienanimation - es funktioniert. Ich weiß nicht, welches Problem ist. – furas
Es ist nicht in dieser Version des Codes gezeigt, aber ich brauche die konstante Schleife aus anderen Gründen. Ich hatte den Eindruck, dass root.update() innerhalb der while (1) dieses Problem behoben hat? Und hast du irgendwas geändert, denn wenn ich denselben Code laufe, sehe ich keine Animationen. –