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()
相关推荐
郭庆汝5 小时前
pytorch、torchvision与python版本对应关系
人工智能·pytorch·python
思则变8 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
漫谈网络8 小时前
WebSocket 在前后端的完整使用流程
javascript·python·websocket
try2find10 小时前
安装llama-cpp-python踩坑记
开发语言·python·llama
DataGear10 小时前
如何在DataGear 5.4.1 中快速制作SQL服务端分页的数据表格看板
javascript·数据库·sql·信息可视化·数据分析·echarts·数据可视化
博观而约取11 小时前
Django ORM 1. 创建模型(Model)
数据库·python·django
精灵vector12 小时前
构建专家级SQL Agent交互
python·aigc·ai编程
Zonda要好好学习12 小时前
Python入门Day2
开发语言·python
Vertira12 小时前
pdf 合并 python实现(已解决)
前端·python·pdf
太凉13 小时前
Python之 sorted() 函数的基本语法
python