python使用tkinter打造三维绘图系统的示例代码
作者:微小冷
Python绘图系统系列:python将matplotlib嵌入到tkinter中的步骤详解_python_脚本之家 (jb51.net)
输入数据
三维绘图需要一个新的坐标变量,设置为z,这个改改UI就可以办到,并不困难。但是,此前用于设置x和y数据的函数实在是过于雷同,如果再写一个设置z轴的,那么这个绘图系统里就相当于是有了3个一毛一样的函数,十分离谱,所以为了简化代码,可以将所有的数据输入框设为一个字典,然后挨个生成xyz的输入框,其中setFrmCtrl函数如下
def setFrmCtrl(self, frmCtrl): frm = ttk.Frame(frmCtrl, width=320) frm.pack(side=tk.TOP, fill=tk.X) self.setCtrlButtons(frm) self.entrys = {} for flag in 'xyz': frm = ttk.Frame(frmCtrl) frm.pack(side=tk.TOP, fill=tk.X) self.setFrmAxis(frm, flag)
setFrmAxis
则没什么好说的,只是新增了一个参数而已。
def setFrmAxis(self, frm, flag): tk.Label(frm, text=flag).pack(side=tk.LEFT) self.entrys[flag] = tk.Entry(frm) self.entrys[flag].pack(side=tk.LEFT, fill=tk.X)
加载数据
此前,分别用 self.xs
和 self.ys
来表示x和y轴数据,这又是一个雷同。为了简化代码,将变量也设做字典,在初始化的init函数中添加
self.data = {}
然后将加载数据的函数改写为
def btnLoadData(self): name = askopenfilename() data = np.genfromtxt(name) for flag, i in enumerate()'xyz': if i >= data.shape[1]: return self.data[flag] = data[:,i] setEntry(self.entrys[flag], 'data')
然后新建一个用来读取Entry的函数,考虑到x和y都有可能用类似 1,1,5
的形式生成,所以先做一个检测数组的全局函数
def detectArray(s): return s.rstrip('0123456789:, ')==''
然后是readEntrys函数,考虑到在函数表达式中,用x和y指代self.data[‘x’]和selfdata[‘y’],所以需要新建局部变量x和y,以确保eval函数的正常使用。
def readEntrys(self): for flag in 'xyz': label = self.entrys[flag].get() if label != 'data': if detectArray(label): label = f"np.linspace({label})" self.data[flag] = eval(self.entrys[flag].get()) if flag =='x' : x = self.data['x'] elif flag =='y' : y = self.data['y'] if self.entrys['z'].get()=="": del self.data['z']
绘图函数
最后,就是绘图功能的实现,由于有了readEntrys函数,从而btnDrawImg函数变得更加专注,只需复制调用专门的绘图函数就可以了。三维绘图函数和二维绘图函数其实没什么区别,只要绘制的还是plot图,区别只是多加了一个z轴坐标而已。
def btnDrawImg(self): self.readEntrys() self.fig.clf() if 'z' in self.data: self.drawPlot3D() else: self.drawPlot() self.fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.08) self.canvas.draw()
由于把用于设置边框宽度的subplots_adjust以及canvas.draw放在了btnDrawImg这个函数中,所以drawPlot函数也需要做适当的精简。而drawPlot3D只是将projection设为‘3d’,同时添加一组z坐标而已。
def drawPlot(self): ax = self.fig.add_subplot() ax.plot(self.data['x'], self.data['y']) def drawPlot3D(self): ax = self.fig.add_subplot(projection='3d') ax.plot(self.data['x'], self.data['y'], self.data['z'])
至此,就可以看一下效果了
源代码
最后,附上源代码
import tkinter as tk import tkinter.ttk as ttk from tkinter.filedialog import askopenfilename import matplotlib as mpl mpl.use('TkAgg') import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import ( FigureCanvasTkAgg, NavigationToolbar2Tk) from matplotlib.figure import Figure import numpy as np def setEntry(e, text): e.delete(0, "end") e.insert(0, text) def detectArray(s): return s.rstrip('0123456789:, ')=='' class DarwSystem(): def __init__(self): self.root = tk.Tk() self.root.title("数据展示工具") self.data = {} frmCtrl = ttk.Frame(self.root,width=320) frmCtrl.pack(side=tk.RIGHT, fill=tk.Y) self.setFrmCtrl(frmCtrl) frmFig = ttk.Frame(self.root) frmFig.pack(side=tk.LEFT,fill=tk.BOTH,expand=tk.YES) self.setFrmFig(frmFig) self.root.mainloop() def setFrmCtrl(self, frmCtrl): frm = ttk.Frame(frmCtrl, width=320) frm.pack(side=tk.TOP, fill=tk.X) self.setCtrlButtons(frm) self.entrys = {} for flag in 'xyz': frm = ttk.Frame(frmCtrl) frm.pack(side=tk.TOP, fill=tk.X) self.setFrmAxis(frm, flag) def setFrmAxis(self, frm, flag): tk.Label(frm, text=flag).pack(side=tk.LEFT) self.entrys[flag] = tk.Entry(frm) self.entrys[flag].pack(side=tk.LEFT, fill=tk.X) def setCtrlButtons(self, frm): ttk.Button(frm, text="绘图",width=5, command=self.btnDrawImg).pack(side=tk.LEFT) ttk.Button(frm, text="加载",width=5, command=self.btnLoadData).pack(side=tk.LEFT) def btnLoadData(self): name = askopenfilename() data = np.genfromtxt(name) for i, flag in enumerate('xyz'): if i >= data.shape[1]: return self.data[flag] = data[:,i] setEntry(self.entrys[flag], 'data') def readEntrys(self): for flag in 'xyz': label = self.entrys[flag].get() if label=="": continue if label != 'data': if detectArray(label): label = f"np.linspace({label})" self.data[flag] = eval(self.entrys[flag].get()) if flag =='x' : x = self.data['x'] elif flag =='y' : y = self.data['y'] if self.entrys['z'].get()=="": del self.data['z'] def btnDrawImg(self): self.readEntrys() self.fig.clf() if 'z' in self.data: self.drawPlot3D() else: self.drawPlot() self.fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.08) self.canvas.draw() def drawPlot3D(self): ax = self.fig.add_subplot(projection='3d') ax.plot(self.data['x'], self.data['y'], self.data['z']) def drawPlot(self): ax = self.fig.add_subplot() ax.plot(self.data['x'], self.data['y']) def setFrmFig(self, frmFig): self.fig = Figure() self.canvas = FigureCanvasTkAgg(self.fig,frmFig) self.canvas.get_tk_widget().pack( side=tk.TOP,fill=tk.BOTH,expand=tk.YES) self.toolbar = NavigationToolbar2Tk(self.canvas,frmFig, pack_toolbar=False) self.toolbar.update() self.toolbar.pack(side=tk.RIGHT) if __name__ == "__main__": test = DarwSystem()
以上就是python使用tkinter打造三维绘图系统的示例代码的详细内容,更多关于python tkinter三维绘图系统的资料请关注脚本之家其它相关文章!