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()
相关推荐
databook3 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar4 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户8356290780514 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_4 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机11 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机12 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机12 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机12 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i12 小时前
drf初步梳理
python·django
每日AI新事件12 小时前
python的异步函数
python