Python绘图系统6:自定义坐标列表控件

news2025/1/12 1:41:18

文章目录

    • 自定义坐标列表控件
    • 显示和隐藏
    • 加载按钮
    • 坐标设置控件的显示和隐藏
    • 源代码

Python绘图系统:

  • 基础:将matplotlib嵌入到tkinter 📈简单的绘图系统 📈数据导入📈三维绘图系统
  • 自定义控件:坐标设置控件📉坐标列表控件

自定义坐标列表控件

绘制多组数据是很自然的一个需求,但目前来说只有一套坐标轴,除非是叠加绘制,否则是没法绘制多组数据的。

为了解决这个问题,最简单的方案当然是疯狂地添加坐标轴,x,y,z用完之后再来x1,y1,z1,然后x2,y2,z2,子子孙孙无穷匮也。简单地说,就是设置一个按钮,点击按钮之后,就会出现一组新的xyz输入框。

为了实现这个功能,最好把多个坐标输入控件AxisFrame列在一起,封装成一个新的控件。由于此前已经做了AxisFrame的自定义,所以这一步不存在难度,初步的代码如下

class AxisList(ttk.Frame):
    def __init__(self, master, mode, widths, **options):
        super().__init__(master, **options)
        self.pack()
        self.afs = {}
        self.initWidgets(mode, widths)
    
    def initWidgets(self, mode, widths):
        for flag in 'xyz':
            self.afs[flag] = AxisFrame(self, flag, mode, widths)
            self.afs[flag].pack(side=tk.TOP, fill=tk.X)
    

    def setData(self, flag, data=None, **options):
        return self.afs[flag].setData(data, **options)
    
    def setOneMode(self, flag, mode):
        self.afs[flag].setMode(mode)

然后将DrawSystem中需要更改的地方修改一下就可以了,首先是setFrmCtrl中做下修改,把self.AL作为AxisList对象的名字。其余类似self.afs[flag].XXX(YYY)之类的写法,均换成self.AL.XXX(flag, YYY)就可以了。

# setFrmCtrl函数
self.AL = AxisList(frmCtrl, 1, [5,10,20])
self.AL.pack(side=tk.TOP, fill=tk.X)

这一步在界面上尚看不出任何端倪。

显示和隐藏

如果想绘制多组数据,那么就需要很多AxisList,但这玩意一多了之后特别占地方,很难看。解决这个问题,一个比较好的方案是设置一个隐藏按钮,将这个AxisList做成类似Expander的形式。更改initWidgets函数如下

# 这些代码都在类中,注意缩进
def initWidgets(self, title, mode, 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.collapsed = True
    self.Click()
    for flag in 'txyz':
        self.afs[flag] = AxisFrame(self._c, flag, mode, widths)
        self.afs[flag].pack(side=tk.TOP, fill=tk.X)
```python

其中Click函数是控制显隐的关键函数,内容如下。

```python
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

效果为

在这里插入图片描述

加载按钮

现在这个测试坐标列表上面还有两个按键,分别是绘图和加载。绘图倒是没什么可说的,但加载按钮却很可疑。当我们有多套坐标的时候,一个全局的加载按钮是让人疑惑的。

为此,可以将加载按钮挪到AxisList控件中。由于功能的相似性,这里的确相当于是直接挪过去的,代码如下

def initFeature(self):
    frm = ttk.Frame(self._c)
    frm.pack(side=tk.TOP, fill=tk.X)
    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.setOneMode(flag, "外部导入")
        self.data[flag] = self.setData(flag, data[:,i])

坐标设置控件的显示和隐藏

最后,考虑到实际绘图时,有时要用到两个坐标轴,有时需要三个,所以最好能对单个的坐标轴进行显示和隐藏,实现方法与Expander的逻辑如出一辙,在initFeature方法中添加如下内容

self.vis = {L : True for L in 'txyz'}
for flag in 'txyz':
    btn = ttk.Button(frm, text=flag, width=3)
    btn.pack(side=tk.LEFT)
    btn.bind("<Button-1>", self.btnAxisCollapse)

其中self.vis是描述某个坐标控件是否显示的布尔标记,btn就是对应的按钮,而self.btnAxisCollapse则是具体的显示隐藏函数,内容如下

def btnAxisCollapse(self, evt):
    flag = evt.widget['text']
    self.vis[flag] = not self.vis[flag]
    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)

这里的实现过程稍显繁琐,主要是考虑到要保证txyz的显示顺序,结果如下

在这里插入图片描述

源代码

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

class AxisFrame(ttk.Frame):
    # widths 是每个控件的宽度
    def __init__(self, master, label, mode, widths, **options):
        super().__init__(master, **options)
        self.pack()
        self.label = label
        self.initVar(mode)
        self.initWidgets(widths)
    
    def initVar(self, mode):
        self.MODES = ("外部导入", "序列化", "源代码", "无数据")
        self.mode = tk.StringVar()
        self.setMode(mode)
    
    def initWidgets(self, widths):
        tk.Label(self, text=self.label, width=widths[0]).pack(side=tk.LEFT)
        self.slct = ttk.Combobox(self, width=widths[1], textvariable=self.mode)
        self.slct['value'] = self.MODES
        self.slct.pack(side=tk.LEFT)
        self.entry = tk.Entry(self, width=widths[2])
        self.entry.pack(padx=5, side=tk.LEFT, fill=tk.X)
    
    def setText(self, text):
        self.entry.delete(0, "end")
        self.entry.insert(0, text)

    def get(self):
        return self.entry.get()

    def setMode(self, mode):
        if type(mode) != str:
            mode = self.MODES[mode]
        self.mode.set(mode)

    def setData(self, data=None, **txyz):
        if self.mode.get() == "序列化":
            return self.getArray()
        elif self.mode.get() == "外部导入":
            return self.loadData(data)
        else:
            return self.readPython(**txyz)
    
    def readPython(self, t=None, x=None, y=None, z=None):
        self.data = eval(self.get())
        return self.data

    def loadData(self, data):
        if type(data) != type(None):
            self.data = data
        return self.data

    def getArray(self):
        val = self.get()
        self.data = eval(f"np.linspace({val})")
        return self.data

class AxisList(ttk.Frame):
    def __init__(self, master, title, mode, widths, **options):
        super().__init__(master, **options)
        self.pack()
        self.afs = {}
        self.data = {}
        self.initWidgets(title, widths)
        self.initAxis(mode, widths)
    
    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.collapsed = True
        self.Click()
        self.initFeature()
    
    def initAxis(self, mode, widths):
        for flag in 'txyz':
            self.afs[flag] = AxisFrame(self._c, flag, mode, widths)
            self.afs[flag].pack(side=tk.TOP, fill=tk.X)
    
    def initFeature(self):
        frm = ttk.Frame(self._c)
        frm.pack(pady=2, side=tk.TOP, fill=tk.X)
        ttk.Button(frm, text="加载",width=5,
            command=self.btnLoadData).pack(side=tk.LEFT)
        
        self.vis = {L : True for L in 'txyz'}
        for flag in 'txyz':
            btn = ttk.Button(frm, text=flag, width=3)
            btn.pack(side=tk.LEFT)
            btn.bind("<Button-1>", self.btnAxisCollapse)
    
    def btnAxisCollapse(self, evt):
        flag = evt.widget['text']
        self.vis[flag] = not self.vis[flag]
        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 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)


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.AL = AxisList(frmCtrl, "测试坐标列表", 1, [5,10,20])
        self.AL.pack(side=tk.TOP, 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.AL.setOneMode(flag, "外部导入")
            self.data[flag] = self.AL.setData(flag, data[:,i])
    
    def readDatas(self):
        dct = {}
        for flag in 'xyz':
            self.data[flag] = self.AL.setData(flag, **dct)
            dct[flag] = self.data[flag]


    def btnDrawImg(self):
        self.readDatas()
        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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/897732.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Threejs学习04——球缓冲几何体环境光以及直线光源

实现随机多个三角形随机位置随机颜色展示效果 这是一个非常简单基础的threejs的学习应用&#xff01;本节主要学习的是球面缓冲几何体在环境光合直线光源下的效果&#xff0c;可以学习到环境光和直线光源的生成效果等功能&#xff01;主要使用的是球缓冲几何体对象SphereGeome…

综合能源系统(8)——综合能源系统支撑技术

1、大数据技术 1.1、大数据技术概述 大数据是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 维克托迈尔舍恩伯格和肯尼斯克耶编写…

【面试八股文】每日一题:谈谈你对IO的理解

谈谈你对IO的理解 每日一题-Java核心-谈谈你对对IO的理解【面试八股文】 1.Java基础知识 Java IO&#xff08;Input/Output&#xff09;是Java编程语言中用于处理输入和输出的一组类和接口。它提供了一种在Java程序中读取和写入数据的方法。 Java IO包括两个主要的部分&#x…

从零开始学习 Java:简单易懂的入门指南之Objects、BigInteger、BigDecimal(十四)

常用API&#xff0c;Objects、BigInteger、BigDecimal 5 Objects类5.1 概述5.2 常见方法 6 BigInteger类6.1 引入6.2 概述6.3 常见方法6.4 底层存储方式&#xff1a; 7 BigDecimal类7.1 引入7.2 概述7.3 常见方法7.4 底层存储方式&#xff1a; 5 Objects类 5.1 概述 tips&…

optee中如何开启或关闭所有中断的

我们知道在Linux Kernel中开启或关闭中断的函数是:local_irq_enable()和local_irq_disable(), 那么在optee os中是怎样做到的呢? optee中通过使用thread_mask_exceptions()和thread_unmask_exceptions()来开启或关闭中断。 thread_mask_exceptions()和thread_unmask_excepti…

C语言:选择+编程(每日一练)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;尼科彻斯定理 示例1 题二&#xff1a;等差数列 示例2 本人实力有限可能对一些地方解释和理解的不够清晰&…

【C++深入浅出】初识C++中篇(引用、内联函数)

目录 一. 前言 二. 引用 2.1 引用的概念 2.2 引用的使用 2.3 引用的特性 2.4 常引用 2.5 引用的使用场景 2.6 传值、传引用效率比较 2.7 引用和指针的区别 三. 内联函数 3.1 内联函数的概念 3.2 内联函数的特性 一. 前言 上期说道&#xff0c;C是在C的基础之上&…

Linux Kernel的local_irq_enable()和local_irq_disable()函数

代码如下图所示&#xff0c;最终操作的是msr daifset, #3 和 msr daifclr, #3 寄存器。 (include/linux/irqflags.h) #define local_irq_enable() do { raw_local_irq_enable(); } while (0) #define local_irq_disable() do { raw_local_irq_disable(); } while (0)#define ra…

历数浙大MPA提前批面试的三大变化

从2019年招生开始&#xff0c;浙大mpa项目的招生趋势一直处于稳增状态&#xff0c;特别是提前批面试政策的出现&#xff0c;更加为项目的整体招录添上神奇的一笔。为什么要举行提面&#xff1f;一方面报考的人数比较多&#xff0c;有了选拔的余地和基础&#xff1b;另一方面也能…

Python学习笔记_进阶篇(一)_浅析tornado web框架

tornado简介 1、tornado概述 Tornado就是我们在 FriendFeed 的 Web 服务器及其常用工具的开源版本。Tornado 和现在的主流 Web 服务器框架&#xff08;包括大多数 Python 的框架&#xff09;有着明显的区别&#xff1a;它是非阻塞式服务器&#xff0c;而且速度相当快。得利于…

【办公自动化】使用Python批量生成PPT版荣誉证书

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

LeetCode--HOT100题(33)

目录 题目描述&#xff1a;148. 排序链表&#xff08;中等&#xff09;题目接口解题思路代码 PS: 题目描述&#xff1a;148. 排序链表&#xff08;中等&#xff09; 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 LeetCode做题链接&#xff1…

SpringBoot项目集成ElasticSearch服务

本文已收录于专栏 《中间件合集》 目录 版本介绍背景介绍优势说明集成过程1.引入依赖2.添加配置文件3.初始化 示例说明代码结果 总结提升 版本介绍 Spring boot的版本是&#xff1a; 2.3.12   ElasticSearch的版本是&#xff1a;7.6.2 背景介绍 在我们的项目中经常会遇到对于…

《Linux从练气到飞升》No.15 Linux 环境变量

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的…

Java算法_ 验证二叉搜索树(LeetCode_Hot100)

题目描述&#xff1a; 给你一个二叉树的根节点 &#xff0c;判断其是否是一个有效的二叉搜索树。root 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 获得…

iTOP-STM32MP157开发板编写驱动程序和应用程序

通过 40.1 章节的学习&#xff0c;我们已经把内核层和用户层实现数据交互的基本概念搞懂了&#xff0c;在上一章节的基础上我们编写驱动程序实现在内核层与应用层传数据。 新建 file_operation.c 文件在 Ubuntu 的/home/driver/04_file_operation 目录下&#xff0c;可以在上次…

基于Javaweb的摄影作品网站/摄影网站

摘 要 随着信息化时代的到来&#xff0c;系统管理都趋向于智能化、系统化&#xff0c;摄影作品网站也不例外&#xff0c;但目前国内的有些网站仍然都使用人工管理&#xff0c;浏览网站人数越来越多&#xff0c;同时信息量也越来越庞大&#xff0c;人工管理显然已无法应对时代的…

智慧二维码门牌管理系统:便捷、高效、智能的服务体验

文章目录 前言一、便捷的获取信息和服务二、提升管理和服务效率三、地区定制化应用四、展望未来 前言 随着信息技术的飞速发展&#xff0c;人们的生活方式正在发生翻天覆地的变化。为了更好地适应这种变化&#xff0c;智慧城市建设项目应运而生&#xff0c;而其中智慧二维码门…

LRU算法源码实现

算法介绍&#xff1a; 最近最久未使用&#xff08;Least Recently Used LRU&#xff09;算法是⼀种缓存淘汰策略。该算法的思路是&#xff0c;将最近一段时间内最久未使用的页面置换出去。 升级版LRUK算法见 基于LRU-K算法设计本地缓存实现流量削峰https://blog.csdn.net/l…

如何通过时间跟踪改进项目管理?

领导一家成功企业难免面临一系列挑战&#xff1a;如未能制定清晰明确的目标、管理不善的团队成员、将错误的任务分配给错误的人……如果没有适当的项目管理&#xff0c;企业管理可能会举步维艰。 虽然提高项目管理技能的方法有很多&#xff0c;但最有效、最快捷的方法之一就是…