python使用tkinter打造三维绘图系统的示例代码

 更新时间:2023年08月14日 09:54:20   作者:微小冷  
Python 的 tkinter 模块是一个常用的 GUI(图形用户界面)工具包,它能够让你创建窗口应用程序,你可以使用它来构建用户友好的界面,包括按钮、标签、文本框、列表框等各种控件,本文讲给大家介绍如何使用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三维绘图系统的资料请关注脚本之家其它相关文章!

相关文章

最新评论