python实现多图绘制系统

文章目录

    • 需求和框架
    • AxisFrame
    • AxisList
    • DarwSystem

从零开始实现一个三维绘图系统

需求和框架

本文希望实现下图所示的绘图系统,下面详细分析需求变化。

在这里插入图片描述

和之前实现的绘图系统相比,首先是多了【新增】和【删除】这两个按钮,其功能是控制绘图数据的个数,即下方的【坐标0】和【坐标1】。由于不同的坐标之间有着相同的组成,故而需要封装成类;而每个坐标中的 x , y , z x,y,z x,y,z坐标轴,又十分相似,故而也需要封装成类。

综合来看,和此前的简单绘图系统相比,若想实现多图绘制的功能,至少需要实现三个类,分别表示坐标轴、坐标系以及坐标系统。

下面列出整个项目需要导入的模块,以及这三个类的命名

import tkinter as tk
import tkinter.ttk as ttk

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):
    pass

class AxisList(ttk.Frame):
    pass

class DarwSystem():
    pass

下面逐一实现,并讲解。

AxisFrame

下图是自定义的AxisList组件,其中每一项 x , y , z x,y,z x,y,z均对应一组AxisFrame对象,下面就分析AxisFrame对象的特点。

在这里插入图片描述

首先,AxisFrame由三部分组成:坐标标签、输入类型和输入框。目前来说,由于只实现了读取Python源码这种方法,故而输入类型的下拉框显得有些多余,其目的是便于后期扩展。

据此,可得到其代码

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 setMode(self, mode):
        if type(mode) != str:
            mode = self.MODES[mode]
        self.mode.set(mode)

    def getData(self, **txyz):
        if self.mode.get() == "源代码":
            self.readPython(**txyz)
        return self.data

    def readPython(self, t=None, x=None, y=None, z=None):
        self.data = eval(self.entry.get())

其中,initVar用于初始化输入模式;setMode用于设置输入模式;initWidgets用于布局,这三个函数只需了解tkinter的工作原理,便无需详解。

getData用于将输入框中的内容转换为数值,由于目前只有【源代码】这一种模式,所以只用到了readPython这一种读取函数。readPython的逻辑很简单,根据输入的 t , x , y , z t,x,y,z t,x,y,z的值,以及输入框中的表达式,来实现python数据的读取。

AxisList

继续分析AxisList组件,除了三个AxisFrame之外,还有一个显隐开关【坐标0】,以及坐标选框【xyz】,用于调整是否使用 x , y , z x,y,z x,y,z等坐标轴,即实现下面的效果。

在这里插入图片描述

从交互逻辑而言,这里有两个功能,一是点击【坐标0】以显示或隐藏其内容,二是选择下拉框,以筛选 x , y , z x,y,z x,y,z等坐标轴。实现代码如下

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.initVar()
        self.initFeature()

    def initVar(self):
        self.AXISES = ("x", "xy", "xyz", "tx", "txy", "txyz")
        self.axMode = tk.StringVar()
        self.axMode.set("xyz")

    def initAxis(self, mode, widths):
        for flag in 'txyz':
            self.afs[flag] = AxisFrame(self._c, flag, mode, widths)
        self.axChanged()

    def initFeature(self):
        frm = ttk.Frame(self._c)
        frm.pack(pady=2, side=tk.TOP, fill=tk.X)

        slct = ttk.Combobox(frm, width=5, textvariable=self.axMode)
        slct["value"] = self.AXISES
        slct.pack(side=tk.LEFT)
        slct.bind('<<ComboboxSelected>>', self.axChanged)

    def axChanged(self, evt=None):
        for flag in 'txyz':
            self.afs[flag].pack_forget()
        for flag in self.axMode.get():
            self.afs[flag].pack(side=tk.TOP, fill=tk.X)

    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 getDatas(self):
        dct = {}
        data = {}
        for flag in self.axMode.get():
            data[flag] = self.afs[flag].getData(**dct)
            dct[flag] = data[flag]
        return data

首先,点击【坐标0】之后,除了【坐标0】之外其他的内容全部隐藏,所以【坐标0】与其内容需要分开处理,从而为其他内容分配一个Frame,由于这个Frame将会频繁地被用到,所以给一个简短的名称_c。

然后,下拉框中共给定6种坐标类型,之所以有 t t t选项,目的是日后可能会实现的动图绘制。

接下来,initVar, initWidgets, initAxis, initFeature是布局函数,无需多言。

axChanged即更改坐标轴系组成时的响应函数,首先隐藏所有坐标轴,再根据选择的坐标轴一个一个重新放出来。

click是点击【坐标0】时的相应,如果_c已经隐藏,就将其显示出来;如果当前可见,就让其变得不可见。

最后,getDatas是坐标系的关键函数,其功能是调用AxisFrame种中的getData函数,其中的dct装载已经获取到的数值,通过字典的双星号索引方法,将字符串key转换为变量名称,以实现最终的数值读取。

DarwSystem

DrawSystem的代码虽然较长,但内容并不复杂,其中setFrmFig更是几乎原封不动地沿用了此前的代码。

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

        self.setFrmCtrl()
        self.setFrmFig()
        self.root.mainloop()

    def setFrmCtrl(self):
        frmCtrl = ttk.Frame(self.root,width=320)
        frmCtrl.pack(side=tk.RIGHT, fill=tk.Y)
        frm = ttk.Frame(frmCtrl, width=320)
        frm.pack(side=tk.TOP, fill=tk.X)
        self.setCtrlButtons(frm)
        self.frmAxis = ttk.Frame(frmCtrl)
        self.frmAxis.pack(side=tk.TOP, fill=tk.X)
        self.addLast(None)

    def addLast(self, evt):
        title = f"坐标{len(self.als)}"
        al = AxisList(self.frmAxis, title, 0, [5,10,20])
        al.pack(side=tk.TOP, fill=tk.X)
        self.als.append(al)

    def deleteLast(self, evt):
        self.als[-1].pack_forget()
        del self.als[-1]

    def setCtrlButtons(self, frm):
        ttk.Button(frm, text="绘图",width=5,
            command=self.btnDrawImg).pack(side=tk.LEFT)
        btn = ttk.Button(frm, text="新增", width=5)
        btn.pack(side=tk.LEFT)
        btn.bind("<Button-1>", self.addLast)

        btn = ttk.Button(frm, text="删除", width=5)
        btn.pack(side=tk.LEFT)
        btn.bind("<Button-1>", self.deleteLast)

    def btnDrawImg(self):
        self.fig.clf()
        ds = [al.getDatas() for al in self.als]
        self.drawPlot(ds)
        self.fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.08)
        self.canvas.draw()

    def drawPlot(self, ds):
        keys = 'xyz' if 'z' in ds[0] else 'xy'
        p = '3d' if 'z' in ds[0] else None
        ax = self.fig.add_subplot(projection=p)
        for data in ds:
            ax.plot(*[data[key] for key in keys])

    def setFrmFig(self):
        frmFig = ttk.Frame(self.root)
        frmFig.pack(side=tk.LEFT,fill=tk.BOTH,expand=tk.YES)
        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)

相比之下,其实只添加了两个功能:

  1. 【添加】和【删除】坐标系
  2. 多个坐标轴的绘图函数

对于前者,其通过addLast在最后面新增一个坐标列表,delLast则删除最后一个坐标列表,实现并不复杂。

对于后者,只需遍历所有AxisList并提取数据,然后将所有数据传递给绘图函数进行图像绘制。

至此,需求得以实现,下面演示一下其工作流程

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

spring boot3登录开发-2(1图形验证码接口实现)

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 &#x1f30a;山高路远&#xff0c;行路漫漫&#xff0c;终有归途。 目录 前置条件 内容简介 图形验证码接口实现 导入糊涂工具依赖 接口分析 编写验证码接口 测试验证码接口 前置条件 …

【Python---六大数据结构】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Python &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; Python---六大数据结构 往期内容前言概述一下可变与不可变 Number四种不同的数值类型Number类型的创建i…

一、ActiveMQ介绍

ActiveMQ介绍 一、JMS1.jms介绍2.jms消息传递模式3.JMS编码总体架构 二、消息中间件三、ActiveMQ介绍1.引入的原因1.1 原因1.2 遇到的问题1.3 解决思路 2.定义3.特点3.1 异步处理3.2 应用系统之间解耦3.3 实际-整体架构 4.作用 一、JMS 1.jms介绍 jms是java消息服务接口规范&…

Android安卓架构MVC、MVP、MVVM模式的概念与区别

目录 MVC框架 MVP框架 MVVM框架 MVVM与MVP区别 MVVM与MVC区别 MVC、MVP、MVVM模式哪个要好一些 MVC&#xff08;Model-View-Controller&#xff09;、MVP&#xff08;Model-View-Presenter&#xff09;、MVVM&#xff08;Model-View-ViewModel&#xff09;是三种常见的软…

Flume(二)【Flume 进阶使用】

前言 学数仓的时候发现 flume 落了一点&#xff0c;赶紧补齐。 1、Flume 事务 Source 在往 Channel 发送数据之前会开启一个 Put 事务&#xff1a; doPut&#xff1a;将批量数据写入临时缓冲区 putList&#xff08;当 source 中的数据达到 batchsize 或者 超过特定的时间就会…

元器件焊盘的PCB处理方式分析与总结

对于高速信号走线的特性阻抗&#xff0c;都需要按照实际要求进行精度控制&#xff0c;所以&#xff0c;任何因设计因素带来的阻抗波动都应该进行优化&#xff0c;如下图所示&#xff0c;为一个12层板设计中的50Ω微带走线&#xff0c;需要在走线之上放置电感&#xff1b; 但是&…

N-144基于微信小程序在线订餐系统

开发工具&#xff1a;IDEA、微信小程序 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 前端技术&#xff1a;vue、ElementUI、 Vant Weapp 服务端技术&#xff1a;springbootmybatisredis 本系统分微信小程序和…

Sora时代,我们的AI应该何去何从?——关于Sora大模型的思考

Sora时代&#xff0c;我们的AI应该何去何从?——关于Sora大模型的思考 一、Sora大模型&#xff1a;横空出世&#xff0c;让AI生成所有领域瑟瑟发抖二、Sora的出现代表了相关行业的灭亡&#xff1f;三、我们将何去何从&#xff1f; 一、Sora大模型&#xff1a;横空出世&#xf…

【数据结构】二叉查找树和平衡二叉树,以及二者的区别

目录 1、二叉查找树 1.1、定义 1.2、查找二叉树的优点 1.2、查找二叉树的弊端 2、平衡二叉树 2.1、定义 2.2、 实现树结构平衡的方法&#xff08;旋转机制&#xff09; 2.2.1、左旋 2.2.2、右旋 3、总结 1、二叉查找树 二叉查找树又名二叉排序树&#xff0c;亦称二叉搜…

WebStorm | 如何修改webstorm中新建html文件默认生成模板中title的初始值

在近期的JS的学习中&#xff0c;使用webstorm&#xff0c;总是要先新建一个html文件&#xff0c;然后再到里面书写<script>标签&#xff0c;真是麻烦&#xff0c;而且标题也是默认的title&#xff0c;想改成文件名还总是需要手动去改 经过小小的研究&#xff0c;找到了修…

阅读笔记(BMSB 2018)Video Stitching Based on Optical Flow

参考文献 Xie C, Zhang X, Yang H, et al. Video Stitching Based on Optical Flow[C]//2018 IEEE International Symposium on Broadband Multimedia Systems and Broadcasting (BMSB). IEEE, 2018: 1-5. 摘要 视频拼接在计算机视觉中仍然是一个具有挑战性的问题&#xff0…

软件工程师,为什么不喜欢关电脑

概述 你是否注意到&#xff0c;软件工程师们似乎从不关电脑&#xff0c;也不喜欢关电脑&#xff1f;别以为他们是电脑“上瘾”&#xff0c;或是沉迷于电脑&#xff0c;这一现象背后蕴含着多种实际原因。 1、代码保存与恢复。 在编写代码过程中&#xff0c;遇到问题时可能会暂时…

【打工日常】使用docker部署Dashdot工具箱

一、Dashdot介绍 dashdot是一个简洁清晰的服务器数据仪表板&#xff0c;基于React实现 &#xff0c;主要是显示操作系统、进程、存储、内存、网络这五个的数据。 二、本次实践介绍 1. 本次实践简介 本次实践部署环境为个人测试环境 2. 本地环境规划 本次实践环境规划&#xf…

【leetcode】深搜、暴搜、回溯、剪枝(C++)3

深搜、暴搜、回溯、剪枝&#xff08;C&#xff09;3 一、解数独1、题目描述2、代码3、解析 二、单词搜索1、题目描述2、代码3、解析 三、黄金矿工1、题目描述2、代码3、解析 四、不同路径III1、题目描述2、代码3、解析 一、解数独 1、题目描述 leetcode链接 2、代码 class…

机器学习西瓜书之决策树

目录 算法原理剪枝处理连续值处理缺失值处理多变量决策树 算法原理 从逻辑角度&#xff1a;通过一系列if-else语句进行多重判断&#xff0c;比如白富美的判断条件&#xff08;“白”“富”“美”&#xff09;。 从几何角度&#xff1a;根据定义的标准进行样本空间的划分。 以二…

如何在CSS中实现背景图片的渐变?

--引言 在CSS中&#xff0c;实现背景图片的渐变通常需要使用linear-gradient或者radial-gradient函数&#xff0c;这些函数可以与背景图像一起使用来创建渐变效果。然而&#xff0c;CSS的渐变并不直接支持使用图像作为渐变的颜色停止点。但你可以通过一些技巧来实现类似的效果…

每日一题 429.N叉树的层序遍历

429. N 叉树的层序遍历 描述&#xff1a; 给定一个 N 叉树&#xff0c;返回其节点值的层序遍历。&#xff08;即从左到右&#xff0c;逐层遍历&#xff09;。 树的序列化输入是用层序遍历&#xff0c;每组子节点都由 null 值分隔&#xff08;参见示例&#xff09;。 示例 1…

谷歌新动作:双子模型大放送,开发者福音来了!

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

SQL29 计算用户的平均次日留存率(lead函数的用法)

代码 with t1 as(select distinct device_id,date --去重防止单日多次答题的情况from question_practice_detail ) select avg(if(datediff(date2,date1)1,1,0)) as avg_ret from (selectdistinct device_id,date as date1,lead(date) over(partition by device_id order by d…

神经网络学习小记录78——Keras CA(Coordinate attention)注意力机制的解析与代码详解

神经网络学习小记录78——Keras CA&#xff08;Coordinate attention&#xff09;注意力机制的解析与代码详解 学习前言代码下载CA注意力机制的概念与实现注意力机制的应用 学习前言 CA注意力机制是最近提出的一种注意力机制&#xff0c;全面关注特征层的空间信息和通道信息。…