Python做一个绘图系统3:从文本文件导入数据并绘图

文章目录

Python绘图系统系列:将matplotlib嵌入到tkinter 简单的绘图系统

导入数据

单纯从作图的角度来说,更多情况是已经有了一组数据,然后需要将其绘制。这组数据可能是txt格式的,也可能是csv格式的,还可能是二进制数据。当然,这些一会儿在想,首先就是要添加一个按钮,将setCtrlButtons函数添加一行:

python 复制代码
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)

然后就可以考虑self.btnLoadData函数了。

简洁起见,以后将不再具体展示setCtrlButtons的具体代码,而只是写出新增的代码。

文件对话框

加载数据,其实就是加载文件,那么文件对话框就很重要。

tkinter.filedialog中的askopenfilename就是文件对话框,预感这个函数可能不止一处出现,故而导入一下,以方便调用

python 复制代码
from tkinter.filedialog import askopenfilename

这个函数的好处是,只返回读取到的文件名,而不像askopenfile一样返回一个文件对象。

而self.btnLoadData函数,如果只是想实现一个最简单的功能,那么

可以写为

python 复制代码
def btnLoadData(self):
    name = askopenfilename()
    data = np.genfromtxt(name)
    if data.shape[1] < 2:
        return
    self.xs = data[:,0]
    self.ys = data[:,1]
    self.drawPlot()

效果如下

修改绘图逻辑

现在,我们有了两种数据生成模式,一是用语法生成,二是通过加载得到。但目前来说这两种生成方式并不兼容。为了解决这个问题,可以为x和y的输入框添加一个标识,比如当x或者y的输入框中是data的时候,再点击绘图,就可以选中加载后的数据。

由于tkinter中输入Entry内容比较繁琐,所以封装一个全局的函数专门用于更改Entry内容

python 复制代码
def setEntry(e, text):
    e.delete(0, "end")
    e.insert(0, text)

接下来,将加载数据函数和绘图函数分别改写为

python 复制代码
def btnLoadData(self):
    name = askopenfilename()
    data = np.genfromtxt(name)
    if data.shape[1] < 2:
        return
    self.xs = data[:,0]
    setEntry(self.xEntry, "data")
    self.ys = data[:,1]
    setEntry(self.yEntry, "data")

def btnDrawImg(self):
    xLab = self.xEntry.get()
    if xLab != "data":
        x = eval(f"np.linspace({xLab})")
        self.xs = x
    else:
        x = self.xs
    yLab = self.yEntry.get()
    if yLab != "data":
        self.ys = eval(yLab)
    self.drawPlot()

在btnLoadData函数中,取消了绘图功能,而是在导入数据后,将xEntry和yEntry的内容设置为"data"。

而绘图函数中,检测xEntry和yEntry的内容,如果是data,那么说明已经读取到了相关数据,就直接调用,而非重新生成。

源代码

最后,把源代码附在下面

python 复制代码
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)

class DarwSystem():
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("数据展示工具")

        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)

        frm = ttk.Frame(frmCtrl)
        frm.pack(side=tk.TOP, fill=tk.X)
        self.setFrmX(frm)

        frm = ttk.Frame(frmCtrl)
        frm.pack(side=tk.TOP, fill=tk.X)
        self.setFrmY(frm)

    def setFrmX(self, frm):
        tk.Label(frm, text="x").pack(side=tk.LEFT)
        self.xEntry = tk.Entry(frm)
        self.xEntry.pack(side=tk.LEFT, fill=tk.X)
        
    def setFrmY(self, frm):
        tk.Label(frm, text="y").pack(side=tk.LEFT)
        self.yEntry = tk.Entry(frm)
        self.yEntry.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)
        if data.shape[1] < 2:
            return
        self.xs = data[:,0]
        setEntry(self.xEntry, "data")
        self.ys = data[:,1]
        setEntry(self.yEntry, "data")

    def btnDrawImg(self):
        xLab = self.xEntry.get()
        if xLab != "data":
            x = eval(f"np.linspace({xLab})")
            self.xs = x
        else:
            x = self.xs
        yLab = self.yEntry.get()
        if yLab != "data":
            self.ys = eval(yLab)
        self.drawPlot()
    
    def drawPlot(self):
        self.fig.clf()
        ax = self.fig.add_subplot()
        ax.plot(self.xs, self.ys)
        self.fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.08)
        self.canvas.draw()
        pass

    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()
相关推荐
卷无止境7 小时前
暗流与破局:AI时代的代码安全审查工具全景指南
后端·python
卷无止境10 小时前
一人公司的全栈选型指南:让 AI Agent 写得快,也让生意跑得稳
后端·python
滴啦嘟啦哒12 小时前
【具身笔记】【π0.5 微调与仿真】五、在MuJoCo中实现可视化仿真
笔记·python·vla·具身
全栈练习生12 小时前
AI安全与红队测试
python·ai
费曼学习法12 小时前
把「发送成功」当「送达」?我排查 IM 长消息被静默吞掉的完整过程
python·ai编程·自动化运维
鸽鸽程序猿12 小时前
【项目】【在线判题系统】b端题目增删改
开发语言·python
NetX行者12 小时前
Python 工程化入门:从脚本到规范的 Python 项目结构
网络·python
MasonYyp12 小时前
asyncio并发协程
python
小小张说故事13 小时前
Python 的整数为什么永远不会溢出?拆开大整数对象,看 30 位一节的存储与运算代价
python
用户2986985301413 小时前
Python 实现 Word 与 TIFF 双向转换的方案
后端·python·api