• Python绘图系统21:导出数据


    Python绘图系统:

    文件导出

    在作图过程中必然会产生大量数据,所以AxisList这个类预留了导出按钮。在具体实现之前,不妨分析一下数据导出所需要的参数。

    首先,AxisList类中往往不止有一个坐标轴,所以在导出数据之前,有必要想清楚要导出哪些坐标轴的文件,或者将所有坐标轴的数据都导出。如果都导出,那么是将所有轴的数据合在一处,还是每个坐标轴一个文件。

    正因为选择太多,所以一个按钮可能不太够用了,所以采用Menubutton来实现。

    首先,将initFeature中有关导出按钮的部分改为如下形式

    btn = ttk.Menubutton(frm, text="导出",width=4)
    btn.pack(side=tk.LEFT)
    m = self.initExportMenu(btn)
    btn.config(menu=m)
    
    • 1
    • 2
    • 3
    • 4

    然后设置菜单

    def initExportMenu(self, btn):
        m = tk.Menu(btn)
        m.add_command(label="合并导出", command = self.mExportMerge)
        m.add_command(label="全部导出", command = self.mExportAll)
        m.add_command(label="导出导出", command = self.mExportOne)
        return m
    
    def mExportMerge(self):
        pass
    
    def mExportAll(self):
        pass
    
    def mExportOne(self):
        pass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    效果如下

    在这里插入图片描述

    单轴导出和全部导出

    单轴导出和全部导出其实是一码事,区别只是后者需要跑一个循环而已,这个功能做在AxisFrame类中显然更合适,考虑到本文只对Axis进行修改,所以这里只做出一个接口,等到日后再去编辑AxisFrame时再行实现。

    其单轴另存的代码如下,self.als[flag].save()是尚未实现的功能。

    def mExportOne(self):
        flag = askstring("请选择输出的轴")
        if flag not in self.getDim():
            showwarning("您输入的坐标轴并不存在")
        #self.afs[flag].save()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    相应地,全部导出可以做成下面的形式:把所有轴的数据导入到同一个文件夹中。

    def mExportAll(self):
        path = askdirectory()
        for flag in self.getDim():
            #self.afs[flag].save(path)
            pass
    
    • 1
    • 2
    • 3
    • 4
    • 5

    合并导出

    合并导出却并不是应该在AxisFrame中完成的工作,而且考虑到数据合并后将使得坐标轴的信息丢失,所以不适合用纯粹的二进制格式,而是采用numpy的.npy或者是csv格式作为输出方案。

    def mExportMerge(self):
        FILES = [('numpy数组', 'npy'), ('文本文件', 'csv')]
        path = asksaveasfilename(filetypes=FILES)
        arr = np.array([self.afs[flag].data for flag in self.getDim()])
        if path.endswith('.npy'):
            arr.tofile(path)
        else:
            np.savetxt(path, arr, delimiter=', ')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    源代码

    最后,附上AxisList的源代码。

    import tkinter as tk
    import tkinter.ttk as ttk
    from tkinter.filedialog import *
    from tkinter.messagebox import showwarning
    import numpy as np
    
    from aframe import AxisFrame, AskDct
    from base import DrawType, DrawStyle
    
    class AxisList(ttk.Frame):
        def __init__(self, master, 
            title, mode, widths, 
            types, typeDct,        # 绘图类型Combobox的参数
            **options):
            super().__init__(master, **options)
            self.pack()
            self.afs = {}
            self.data = {}
    
            self.initWidgets(title, widths)
            self.initFeature(types, typeDct)
            self.initAxis(mode, widths)
            self.initStyleFrame()
        
        def initWidgets(self, title, widths):
            self.btn = ttk.Button(self, text=title, width=sum(widths)+5,
                command=self.Click)
            self.btn.pack(side=tk.TOP, fill=tk.X, expand=tk.YES)
            self._c = ttk.Frame(self)       # 此为主控件
            self._b = ttk.Frame(self._c)    # 此外工具栏控件
            self._a = ttk.Frame(self._c)    # 此为坐标轴
            self._s = ttk.Frame(self._c)    # 此为绘图风格控件
            
            self._b.pack(side=tk.TOP)
            self._a.pack(side=tk.TOP)
            self._s.pack(side=tk.TOP)
            
            self.collapsed = True
            self.Click()
        
        # 初始化工具栏
        def initFeature(self, types, typeDct):
            frm = self._b
            frm.pack(pady=2, side=tk.TOP, fill=tk.X)
            ttk.Button(frm, text="导入",width=4,
                command=self.btnLoadData).pack(side=tk.LEFT)
            btn = ttk.Menubutton(frm, text="导出",width=4)
            btn.pack(side=tk.LEFT)
            m = self.initExportMenu(btn)
            btn.config(menu=m)
    
            self.drawType = DrawType(frm, typeDct, 
                func=self.dimChanged)
            self.drawType.pack(side=tk.LEFT, padx=2)
            self.vis = {L : True for L in 'txyz'}
            ttk.Button(frm, text="风格",width=5,
                command=self.btnShowStyle).pack(side=tk.LEFT)
            self.showStyle = False
    
        # 设置导出按钮的菜单
        def initExportMenu(self, btn):
            m = tk.Menu(btn)
            m.add_command(label="合并导出", command = self.mExportMerge)
            m.add_command(label="全部导出", command = self.mExportAll)
            m.add_command(label="单轴导出", command = self.mExportOne)
            return m
        
        def mExportMerge(self):
            FILES = [('numpy数组', 'npy'), ('文本文件', 'csv')]
            path = asksaveasfilename(filetypes=FILES, initialfile=True)
            arr = np.array([self.afs[flag].data for flag in self.getDim()])
            if path.endswith('.npy'):
                arr.tofile(path)
            else:
                np.savetxt(path, arr, delimiter=', ')
    
        def mExportAll(self):
            path = askdirectory()
            for flag in self.getDim():
                #self.afs[flag].save(path)
                pass
        
        def mExportOne(self):
            flag = askstring("请选择输出的轴")
            if flag not in self.getDim():
                showwarning("您输入的坐标轴并不存在")
            #self.afs[flag].save()
    
        # 初始化坐标轴
        def initAxis(self, mode, widths):
            for flag in 'txyz':
                self.afs[flag] = AxisFrame(self._a, flag, mode, widths)
                self.afs[flag].pack(side=tk.TOP, fill=tk.X)
            self.vis = {L : L in self.getDim() for L in 'txyz'}
            self.updateVisible()
        
        # 初始化风格控件
        def initStyleFrame(self):
            self.sf = ttk.LabelFrame(self._s, text="绘图风格")
            self.drawStyle = DrawStyle(self.sf)
            self.drawStyle.pack(side=tk.TOP, fill=tk.X)
            
        # 维度改变时的回调函数
        def dimChanged(self, evt):
            txyz = self.getDim()
            for flag in 'txyz':
                self.vis[flag] = flag in txyz
            self.updateVisible()
        
        # 更新隐藏和显示
        def updateVisible(self):
            for flag in 'txyz':
                self.afs[flag].pack_forget()
            for flag in 'txyz':
                if self.vis[flag]:
                    self.afs[flag].pack(side=tk.TOP, fill=tk.X)
        
        def btnShowStyle(self):
            self.showStyle = not self.showStyle
            if self.showStyle:
                self.sf.pack(side=tk.TOP, fill=tk.X)
            else:
                self.sf.pack_forget()
    
        def getSub(self):
            return self.drawType.getSub()
    
        def getProj(self):
            return self.drawType.getProj()
    
        def getType(self):
            return self.drawType.getType()
        
        def getDim(self):
            return self.drawType.getDim()
    
        def getXYZ(self):
            return self.getDim().replace("t", "")
        
        def hasTimeAxis(self):
            return "t" in self.getDim()
        
        def getStyle(self):
            return self.drawStyle.getVarDct()
    
        # 加载数据
        def btnLoadData(self):
            name = askopenfilename()
            data = np.genfromtxt(name)
            for i, flag in enumerate('xyz'):
                if i >= data.shape[1]:
                    return
                self.setOneMode(flag, "外部导入")
                self.data[flag] = self.setData(flag, data[:,i])
    
        def Click(self):
            if self.collapsed:
                self._c.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES)            
            else:
                self._c.pack_forget()
            self.collapsed = not self.collapsed
    
        # 设置数据
        def setData(self, flag, data=None, **options):
            return self.afs[flag].setData(data, **options)
        
        # 设置模式
        def setOneMode(self, flag, mode):
            self.afs[flag].setMode(mode)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
  • 相关阅读:
    Appium的使用教程
    rabbitmq入门、springboot集成rabbitmq
    计算机毕业设计asp.net社团人员信息系统VS开发sqlserver数据库web结构c#编程计算机网页项目
    腾讯云大数据ES Serverless
    如何在macbook上删除文件?Mac删除文件的多种方法
    Windows 上杀端口和相关进程
    Arduino框架下通过TFT_eSPI库驱动ESP32+合宙1.54“ 电子墨水屏(e-paper)显示
    lc marathon 6.30
    Elasticsearch系列-基础知识
    mAP,PR-curve解释及计算等
  • 原文地址:https://blog.csdn.net/m0_37816922/article/details/132241089