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

文章目录

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

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 = Trueself.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]:returnself.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 askopenfilenameimport matplotlib as mpl
mpl.use('TkAgg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figureimport numpy as npclass AxisFrame(ttk.Frame):# widths 是每个控件的宽度def __init__(self, master, label, mode, widths, **options):super().__init__(master, **options)self.pack()self.label = labelself.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.MODESself.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.datadef loadData(self, data):if type(data) != type(None):self.data = datareturn self.datadef getArray(self):val = self.get()self.data = eval(f"np.linspace({val})")return self.dataclass 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 = Trueself.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]:returnself.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.collapseddef 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]:returnself.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.mzph.cn/news/42850.shtml

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

相关文章

android resoure资源图片颜色值错乱

最近androidstudio开发&#xff0c;添加一些颜色值或者drawable资源文件时&#xff0c;运行app,颜色值或者图片对应不上&#xff0c;暂时找不到原因&#xff0c;望告知。 暂时解决方法&#xff1a;

链游再进化 Web3版CSGO来袭

过去几年&#xff0c;游戏开发者们一直希望借Web3这个价值流通网络&#xff0c;改造传统游戏的经济系统&#xff0c;将虚拟资产的掌管权交给用户&#xff0c;让资产自由地在市场流通。 Web3游戏发展史上&#xff0c;涌现过CryptoKitties、Axie Infinity两大爆款&#xff0c;但…

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

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

onvif中imaging setting图像画质总结!

前言&#xff1a; 大家好&#xff0c;今天给大家来分享一篇关于图像质量的内容&#xff0c;这个内容是我在做onvif中的imaging setting的时候&#xff0c;关注到里面有关于: brightness(亮度)color saturation(色彩饱和度)contrast(对比度)sharpness(锐度)white balance(白平衡…

C语言刷题指南(二)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

kubesphere 集成 sonar

文章目录 安装 helm通过 helm 安装 sonar配置 SonarQube 服务器创建 SonarQube 管理员令牌SonarQube 配置添加到 ks-installer创建 Webhook 服务器将 SonarQube 服务器添加至 Jenkins将 sonarqubeURL 添加到 KubeSphere 控制台重启服务 为新项目创建 SonarQube Token 官方文档&…

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

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

使用el-tree实现自定义树结构样式

实现效果: 直接上代码: <template><div><div class"tops"><el-tree :default-expanded-keys"[1]" ref"myTree" :data"data" :props"defaultProps" node-click"handleNodeClick" highlight…

【uniapp】picker mode=“region“ 最简单的省市区 三级联动

省市区 picker template <picker mode"region" :value"date" class"u-w-440" change"bindTimeChange"><u--inputborder"bottom"class"u-fb u-f-s-28"placeholder"请选择省市区"type"te…

ARM 作业1

一、思维导图 二、 1. 2. .text 文本段 .globl _start 声明_start:mov r0,#0mov r1,#0fun:cmp r1,#100bhi stopadd r0,r0,r1add r1,r1,#1b fun stop:b stop .end

C++函数模板和类模板

C另一种编程思想称为泛型编程&#xff0c;主要利用的技术是模板 C提供两种模板机制&#xff1a;函数模板和类模板 C提供了模板(template)编程的概念。所谓模板&#xff0c;实际上是建立一个通用函数或类&#xff0c; 其类内部的类型和函数的形参类型不具体指定&#xff0c; 用…

Axios使用CancelToken取消重复请求

处理重复请求&#xff1a;没有响应完成的请求&#xff0c;再去请求一个相同的请求&#xff0c;会把之前的请求取消掉 新增一个cancelRequest.js文件 import axios from "axios" const cancelTokens {}export const addPending (config) > {const requestKey …

如何区分闰年与平年

首先要明白 地球绕太阳运行周期为365天5小时48分46秒&#xff08;合365.24219天&#xff09;&#xff0c;即一回归年&#xff08;tropical year&#xff09;。公历的平年只有365日&#xff0c;比回归年短约0.2422 日&#xff0c;每四年累积约一天&#xff0c;把这一天加于2月末…

Docker安装基础使用练习

目录 1、安装Docker-CE 1&#xff09;简单使用yum方式安装 ! 2&#xff09;配置镜像加速&#xff1a; 2、下载系统镜像&#xff08;Ubuntu、 centos&#xff09; 1&#xff09;先查看我们所需的镜像有哪些版本。使用search命令&#xff01; 2&#xff09;下载镜像使用的是pul…

【爬虫】P1 对目标网站的背景调研(robot.txt,advanced_search,builtwith,whois)

对目标网站的背景调研 检查 robot.txt估算网站大小识别网站所用技术寻找网站的所有者 检查 robot.txt 目的&#xff1a; 大多数的网站都会包含 robot.txt 文件。该文件用于指出使用爬虫爬取网站时有哪些限制。而我们通过读 robot.txt 文件&#xff0c;亦可以最小化爬虫被封禁的…

vue中实现文字检索时候将搜索内容标红

实现结果 html&#xff1a; <div class"searchBox"><span class"bt">标&#8195&#8195题</span><div class"search"><div class"shuru"><!-- <span class"title">生产经营<…

如何批量修改图片名为不同名称

如何批量修改图片名为不同名称&#xff1f;当今社会&#xff0c;因为人们都养成了随手拍照的习惯&#xff0c;所以拥有上千上万张照片的相册已经司空见惯不足为奇。然而&#xff0c;我们在保存这些照片时往往都会碰到一个大难题——电脑中的图片名称千奇百怪&#xff0c;让整个…

完美解决微信小程序使用复选框van-checkbox无法选中

由于小程序使用了vant-ui框架&#xff0c;导致checkbox点击无法选中问题 <van-checkbox value"{{ checked }}" shape"square"><view class"check-content"><view class"checktext">我已阅读并同意>《用户协议》…

opencv-目标追踪

import argparse import time import cv2 import numpy as np# 配置参数 ap argparse.ArgumentParser() ap.add_argument("-v", "--video", typestr,help"path to input video file") ap.add_argument("-t", "--tracker", …

第1天----验证一个字符串是否是另一个字符串的子串

本文我们将学习如何去验证一个字符串是否是另一个字符串的子串。 一、小试牛刀&#xff1a; 题目描述 输入两个字符串&#xff0c;验证其中一个串是否为另一个串的子串。 输入格式 两行&#xff0c;每行一个字符串。 输出格式 若第一个串 s 1 是第二个串 s 2 的子串&#xff0c…