Python添加时间轴以实现动态绘图详解
作者:微小冷
这篇文章主要为大家详细介绍了Python如何添加时间轴以实现动态绘图,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以参考一下
时间轴
三维并不是人类理解的极限,毕竟我们生活在思维时空中。所以接下来要做的,就是四维图形——加一个时间轴。
实际上,这个项目创建之初就已经考虑到动图绘制的问题,毕竟默认的绘图坐标是txyz。但是,如果想实现动图绘制,就必须要先设置一个额外的线程,用于动态更新图像,否则绘图循环压迫主进程,会导致界面变得奇卡无比。
接下来,就开始实现绘制动图的需求,第一步,绘制UI。先在setFrmCtrl中添加
# 动画控制 frm = ttk.Frame(frmCtrl, width=320) frm.pack(side=tk.TOP, fill=tk.X) self.setAnimateFrame(frm)
然后实现具体的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="延时/毫秒").pack(**pDct) ttk.Entry(frm, width=5, textvariable=self.aniDelay).pack(**pDct) self.aniFrameNum = tk.StringVar() self.aniFrameNum.set(100) ttk.Label(frm, text="帧数").pack(**pDct) ttk.Entry(frm, width=5, textvariable=self.aniFrameNum).pack(**pDct) self.tIndex = 0 # 当前帧数 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
延时表示当自动绘制动图时,两帧间隔时间;帧数表示总共绘制的时间个数。三个按钮,分别用于向前一帧、向后一帧以及动态播放。
单帧跳转
坐标t的工作原理和xyz并不相同,毕竟每次调用时间参数的时候,都只需要调用某一点的时间。所以,现有的设置坐标数据的方法就不适用了,需要更改readDatas函数
# 读取坐标轴al的数据 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
然后再更新一下绘图函数:其实只是取消t作为绘图坐标轴的地位
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()
最后,实现一下btnNextFrame
def btnNextFrame(self): num = int(self.aniFrameNum.get()) self.tIndex = (self.tIndex + 1) % num self.btnDrawImg()
效果如下,至此,我们离自动化动态绘图,只剩下一个多线程了。
源代码
本文只更改了ds.py中的源代码,其他代码可查看这篇博客:定制风格的绘图系统
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("数据展示工具") 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 = ("点线图", "散点图", "条形图") self.drawDct = { "点线图" : self.drawPlot, "散点图" : self.drawScatter, "条形图" : self.drawBar } # ! 设置 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) # 动画控制 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) # ! 动画控制 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="延时/毫秒").pack(**pDct) ttk.Entry(frm, width=5, textvariable=self.aniDelay).pack(**pDct) self.aniFrameNum = tk.IntVar() self.aniFrameNum.set(100) ttk.Label(frm, text="帧数").pack(**pDct) ttk.Entry(frm, width=5, textvariable=self.aniFrameNum).pack(**pDct) self.tIndex = 0 # 当前帧数 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() # 添加一组坐标系 def addLast(self, evt): title = f"坐标{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) # 删除一组坐标系 def deleteLast(self, evt): self.als[-1].pack_forget() del self.als[-1] # 加载数据 // 暂时处于弃用状态 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, "外部导入") self.data[flag] = self.AL.setData(flag, data = data[:,i]) # 读取坐标轴al的数据 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 # 设置绘图坐标 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] # 单帧绘图函数 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添加时间轴以实现动态绘图详解的详细内容,更多关于Python动态绘图的资料请关注脚本之家其它相关文章!