我正在开发一个程序,我需要两个不同的动画图形。我无法用我正在使用的结构解决这个问题。我将在下面粘贴我的代码,以便您可以尝试。我尽可能地删除它,同时仍然保留核心功能,所以希望它不是很难理解。在它的当前状态下,动画线没有做任何事情所以请告诉我出错的地方。
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
要清楚,我只是想知道如何使动画适用于此代码。
答案 0 :(得分:1)
您的代码适合我 - 我看到了所有动画 - 但如果您在没有y = c(" word ", " another ", " final ", " more ")
(或更多pythonic While(1):
)的情况下运行它,那么您可以使用While True:
。您可以使用它代替root.after(milliseconds, function_name)
。
它可以让你控制功能 - 开始/停止它。
FuncAnimation
您使用启动它(或重新启动它)
if self.run_bar:
root.after(100, self.refreshBar)
你可以阻止它
self.run_bar = True
self.refreshBar()
查看代码中的所有self.run_bar = False
。
# <--
编辑:当然,您可以在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: # <-- CamelCase names for classes
# <-- empty line for readabelity
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): # <-- without argument
'''Redraw the graph with the updated arrays and resize it accordingly''' # <-- docstring used by documentation generator and IDE as help
#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()
# run again after 100ms (0.1s)
root.after(100, self.refreshGraph) # <-- run again like in loop
def refreshBar(self): # <-- without argument
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
# run again after 100ms (0.1s)
root.after(100, self.refreshBar) # <-- run again like in loop
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
# run again after 100ms (0.1s)
root.after(100, updateNumbers) # <-- run again like in loop
if __name__ == "__main__":
root = Tk()
gui = TkGUI(root)
# <-- vvv - without While and without FuncAnimation - vvv
updateNumbers() # run first time
gui.refreshBar() # run first time
gui.refreshGraph() # run first time
# <-- ^^^ - without While and without FuncAnimation - ^^^
root.mainloop() # Tkinter main loop
之后保留FuncAnimation
并仅在after
after
updateNumbers