Python添加時(shí)間軸以實(shí)現(xiàn)動(dòng)態(tài)繪圖詳解
時(shí)間軸
三維并不是人類理解的極限,畢竟我們生活在思維時(shí)空中。所以接下來要做的,就是四維圖形——加一個(gè)時(shí)間軸。
實(shí)際上,這個(gè)項(xiàng)目創(chuàng)建之初就已經(jīng)考慮到動(dòng)圖繪制的問題,畢竟默認(rèn)的繪圖坐標(biāo)是txyz。但是,如果想實(shí)現(xiàn)動(dòng)圖繪制,就必須要先設(shè)置一個(gè)額外的線程,用于動(dòng)態(tài)更新圖像,否則繪圖循環(huán)壓迫主進(jìn)程,會(huì)導(dǎo)致界面變得奇卡無比。
接下來,就開始實(shí)現(xiàn)繪制動(dòng)圖的需求,第一步,繪制UI。先在setFrmCtrl中添加
# 動(dòng)畫控制 frm = ttk.Frame(frmCtrl, width=320) frm.pack(side=tk.TOP, fill=tk.X) self.setAnimateFrame(frm)
然后實(shí)現(xiàn)具體的self.setAnimateFrame
def setAnimateFrame(self, frm): pDct = dict(side=tk.LEFT, fill=tk.X, padx=2) self.aniDelay = tk.StringVar() self.aniDelay.set(100) ttk.Label(frm, text="延時(shí)/毫秒").pack(**pDct) ttk.Entry(frm, width=5, textvariable=self.aniDelay).pack(**pDct) self.aniFrameNum = tk.StringVar() self.aniFrameNum.set(100) ttk.Label(frm, text="幀數(shù)").pack(**pDct) ttk.Entry(frm, width=5, textvariable=self.aniFrameNum).pack(**pDct) self.tIndex = 0 # 當(dāng)前幀數(shù) ttk.Button(frm, width=3, text= "?", command=self.btnPreFrame).pack(**pDct) ttk.Button(frm, width=3, text="?", command=self.btnAniStart).pack(**pDct) ttk.Button(frm, width=3, text="?", command=self.btnNextFrame).pack(**pDct) def btnAniStart(self): pass def btnPreFrame(self): pass def btnNextFrame(self): pass
延時(shí)表示當(dāng)自動(dòng)繪制動(dòng)圖時(shí),兩幀間隔時(shí)間;幀數(shù)表示總共繪制的時(shí)間個(gè)數(shù)。三個(gè)按鈕,分別用于向前一幀、向后一幀以及動(dòng)態(tài)播放。
單幀跳轉(zhuǎn)
坐標(biāo)t的工作原理和xyz并不相同,畢竟每次調(diào)用時(shí)間參數(shù)的時(shí)候,都只需要調(diào)用某一點(diǎn)的時(shí)間。所以,現(xiàn)有的設(shè)置坐標(biāo)數(shù)據(jù)的方法就不適用了,需要更改readDatas函數(shù)
# 讀取坐標(biāo)軸al的數(shù)據(jù) def readDatas(self, al): dct = {} data = {} for flag in self.drawTypeDim.getDim(): data[flag] = al.setData(flag, **dct) if flag=='t': dct['t'] = data['t'][self.tIndex] else: dct[flag] = data[flag] return data
然后再更新一下繪圖函數(shù):其實(shí)只是取消t作為繪圖坐標(biāo)軸的地位
def btnDrawImg(self): self.fig.clf() self.axDct = {} for al in self.als: ax = self.setDrawAxis(al) data = self.readDatas(al) draw = self.drawDct[al.getDrawType()] style = al.getStyle() keys = al.getDrawDim().replace('t',"") draw(ax, data, keys, style) self.fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.08) self.canvas.draw()
最后,實(shí)現(xiàn)一下btnNextFrame
def btnNextFrame(self): num = int(self.aniFrameNum.get()) self.tIndex = (self.tIndex + 1) % num self.btnDrawImg()
效果如下,至此,我們離自動(dòng)化動(dòng)態(tài)繪圖,只剩下一個(gè)多線程了。
源代碼
本文只更改了ds.py中的源代碼,其他代碼可查看這篇博客:定制風(fēng)格的繪圖系統(tǒng)
import tkinter as tk import tkinter.ttk as ttk from tkinter.filedialog import askopenfilename import matplotlib import matplotlib as mpl mpl.use('TkAgg') import matplotlib.backends.backend_tkagg as mbb from matplotlib.figure import Figure import numpy as np from alist import AxisList from base import DrawType class DarwSystem(): def __init__(self): self.root = tk.Tk() self.root.title("數(shù)據(jù)展示工具") self.data = {} self.als = [] self.initConst() self.setFrmCtrl() frmFig = ttk.Frame(self.root) frmFig.pack(side=tk.LEFT,fill=tk.BOTH,expand=tk.YES) self.setFrmFig(frmFig) self.root.mainloop() def initConst(self): self.TYPES = ("點(diǎn)線圖", "散點(diǎn)圖", "條形圖") self.drawDct = { "點(diǎn)線圖" : self.drawPlot, "散點(diǎn)圖" : self.drawScatter, "條形圖" : self.drawBar } # ! 設(shè)置 def setFrmCtrl(self): frmCtrl = ttk.Frame(self.root,width=320) frmCtrl.pack(side=tk.RIGHT, fill=tk.Y) # 主控Frame frm = ttk.Frame(frmCtrl, width=320) frm.pack(side=tk.TOP, fill=tk.X) self.setCtrlButtons(frm) # 動(dòng)畫控制 frm = ttk.Frame(frmCtrl, width=320) frm.pack(side=tk.TOP, fill=tk.X) self.setAnimateFrame(frm) self.frmAxis = ttk.Frame(frmCtrl) self.frmAxis.pack(side=tk.TOP, fill=tk.X) self.addLast(None) # ! 工具欄 def setCtrlButtons(self, frm): self.drawTypeDim = DrawType(frm) self.drawTypeDim.pack(side=tk.LEFT) ttk.Button(frm, text="??",width=3, command=self.btnDrawImg).pack(side=tk.LEFT) ttk.Button(frm, text="??",width=3, command=self.btnLoadData).pack(side=tk.LEFT) btn = ttk.Button(frm, text="+", width=3) btn.pack(side=tk.LEFT) btn.bind("<Button-1>", self.addLast) btn = ttk.Button(frm, text="-", width=3) btn.pack(side=tk.LEFT) btn.bind("<Button-1>", self.deleteLast) # ! 動(dòng)畫控制 def setAnimateFrame(self, frm): pDct = dict(side=tk.LEFT, fill=tk.X, padx=2) self.aniDelay = tk.IntVar() self.aniDelay.set(100) ttk.Label(frm, text="延時(shí)/毫秒").pack(**pDct) ttk.Entry(frm, width=5, textvariable=self.aniDelay).pack(**pDct) self.aniFrameNum = tk.IntVar() self.aniFrameNum.set(100) ttk.Label(frm, text="幀數(shù)").pack(**pDct) ttk.Entry(frm, width=5, textvariable=self.aniFrameNum).pack(**pDct) self.tIndex = 0 # 當(dāng)前幀數(shù) ttk.Button(frm, width=3, text= "?", command=self.btnPreFrame).pack(**pDct) ttk.Button(frm, width=3, text="?", command=self.btnAniStart).pack(**pDct) ttk.Button(frm, width=3, text="?", command=self.btnNextFrame).pack(**pDct) def btnAniStart(self): pass def btnPreFrame(self): pass def btnNextFrame(self): num = self.aniFrameNum.get() self.tIndex = (self.tIndex + 1) % num self.btnDrawImg() # 添加一組坐標(biāo)系 def addLast(self, evt): title = f"坐標(biāo){len(self.als)}" al = AxisList(self.frmAxis, title, 1, [5,10,30], self.TYPES, self.drawTypeDim.getDct()) al.pack(side=tk.TOP, fill=tk.X) self.als.append(al) # 刪除一組坐標(biāo)系 def deleteLast(self, evt): self.als[-1].pack_forget() del self.als[-1] # 加載數(shù)據(jù) // 暫時(shí)處于棄用狀態(tài) def btnLoadData(self): name = askopenfilename() data = np.genfromtxt(name) for i, flag in enumerate('xyz'): if i >= data.shape[1]: return self.AL.setOneMode(flag, "外部導(dǎo)入") self.data[flag] = self.AL.setData(flag, data = data[:,i]) # 讀取坐標(biāo)軸al的數(shù)據(jù) def readDatas(self, al): dct = {} data = {} for flag in al.getDrawDim(): data[flag] = al.setData(flag, **dct) if flag=='t': dct['t'] = data['t'][self.tIndex] else: dct[flag] = data[flag] return data # 設(shè)置繪圖坐標(biāo) def setDrawAxis(self, al): sub = int(al.getSub()) print(sub) if sub in self.axDct: return self.axDct[sub] p = al.getProj() if p == "None": self.axDct[sub] = self.fig.add_subplot(sub) else: self.axDct[sub] = self.fig.add_subplot(sub, projection=p) return self.axDct[sub] # 單幀繪圖函數(shù) def btnDrawImg(self): self.fig.clf() self.axDct = {} for al in self.als: ax = self.setDrawAxis(al) data = self.readDatas(al) draw = self.drawDct[al.getDrawType()] style = al.getStyle() keys = al.getDrawDim().replace('t',"") draw(ax, data, keys, style) self.fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.08) self.canvas.draw() def drawBar(self, ax, data, keys, style): ax.bar(data['x'], data['y']) def drawPlot(self, ax, data, keys, style): ax.plot(*[data[key] for key in keys], **style) def drawScatter(self, ax, data, keys, style): ax.scatter(*[data[key] for key in keys]) def setFrmFig(self, frmFig): self.fig = Figure() self.canvas = mbb.FigureCanvasTkAgg(self.fig,frmFig) self.canvas.get_tk_widget().pack( side=tk.TOP,fill=tk.BOTH,expand=tk.YES) self.toolbar = mbb.NavigationToolbar2Tk(self.canvas,frmFig, pack_toolbar=False) self.toolbar.update() self.toolbar.pack(side=tk.RIGHT) if __name__ == "__main__": test = DarwSystem()
以上就是Python添加時(shí)間軸以實(shí)現(xiàn)動(dòng)態(tài)繪圖詳解的詳細(xì)內(nèi)容,更多關(guān)于Python動(dòng)態(tài)繪圖的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python入門學(xué)習(xí)之Python流處理過程
本篇文章屬于Python入門篇,本文主要教大家學(xué)習(xí)Python流處理過程,通過Faust流處理庫來為大家詳細(xì)講解,有需要的朋友可以借鑒參考下2021-09-09python except異常處理之后不退出,解決異常繼續(xù)執(zhí)行的實(shí)現(xiàn)
這篇文章主要介紹了python except異常處理之后不退出,解決異常繼續(xù)執(zhí)行的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-04-04在Python中使用xlrd和xlwt讀寫Excel文件代碼實(shí)例
這篇文章主要介紹了在Python中使用xlrd和xlwt讀寫Excel文件代碼實(shí)例,python操作excel主要用到xlrd和xlwt兩個(gè)庫,即xlrd是讀excel,xlwt是寫excel庫,文中提供了部分實(shí)例代碼,需要的朋友可以參考下2023-08-08使用Python實(shí)現(xiàn)繪制地圖的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何使用Python實(shí)現(xiàn)繪制地圖相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01Python應(yīng)用開發(fā)之實(shí)現(xiàn)串口通信
在嵌入式開發(fā)中我們經(jīng)常會(huì)用到串口,串口通信簡單,使用起來方便,且適用場景多。本文為大家準(zhǔn)備了Python實(shí)現(xiàn)串口通信的示例代碼,需要的可以參考一下2022-11-11