绘图系统四:定制绘图风格

2023-09-21 09:00:00

创建控件

尽管从matplotlib的角度来说,绘图风格也算是图像类型的一部分,但诸如点线字体标题等内容太过复杂,为了减轻DrawType的负担,所以新建一个组件。有了DrawType的经验,那么DrawStyle类在参数设置上就比较轻车熟路,整体框架大致如下

class DrawStyle(ttk.Frame):
    def __init__(self, master, 
        varDct, ws=None, func=None, **options):
        super().__init__(master, **options)
        self.pack()
    
    def initVars(self):
        pass

    def initWidgets(self):
        pass

但在丰富细节之前,需要修改一下AxisList的布局。考虑到绘图风格并不是经常会用到的控件,所以平时给隐藏起来。其initWidgets函数修改如下,之前直接依托在主frame中的AxisFrame,如今都要放到self._a中。而各种按钮都放在工具栏self._b中。

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)       # 此为主frame
    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
    # ...中间内容不变
    ttk.Button(frm, text="风格",width=5,
        command=self.btnShowStyle).pack(side=tk.LEFT)
    self.showStyle = False

btnShowStyle的逻辑也是老生常谈了

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 initStyleFrame(self):
    self.sf = DrawStyle(self._s)
    ttk.Button(self.sf, text="点我").pack(side=tk.LEFT)

这个按钮存粹为了演示,后期要删掉的,演示结果如下

在这里插入图片描述

绘图风格

以plot为例,下面列出常用参数,其中枚举类型表示有有限个可选择的值,说明适用于Combobox控件。

参数类型功能参数类型功能
label字符串图例标签
linestyle枚举线条类型linewidth小数线条宽度
marker枚举散点形状markersize小数散点尺寸
alpha小数透明度zorder整数所在绘图层
color字符串颜色markeredgecolor字符串点的边框色

为了便于调用,将这些参数封装为字典

def initConst(self):
    self.VAR_LABS = {
        "线型" : "linestyle", "线宽" : "linewidth",  "线色" : "color",
        "点型" : "marker"   , "点径" : "markersize", "点色" : "markeredgecolor",
        "标签" : "label"    , "透明度"    : "alpha", "层号" : "zorder" 
    }
    self.STR_KEYS = ["标签"]
    self.COM_KEYS = ["线型", "点型"]
    self.NUM_KEYS = ["线宽", "点径", "透明度"]
    self.INT_KEYS = ["层号"]
    self.CLR_KEYS = ["线色", "点色"]

这样一来,初始化StringVar就方便很多

def initVars(self):
    self.varDct = {key:tk.StringVar() for key in self.VAR_LABS}

但接下来才是重头戏,UI绘制。

matplotlib中有四种线型,点型相对较多,而点和线的设置均包含形状、尺寸以及颜色,基于这种对偶关系,可以将这些参数设成下列形式

def initLineMarker(self):
    enumDct = {
        "点型" : ['.', ',', '1', '2', '3', '4', '+', 'x', '|', '_', 
            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
            'o', 'v', '^', '<', '>', '8', 's', 'p', '*', 
            'h', 'H', 'D', 'd', 'P', 'X'],
        "线型" : ['-', '--', '-.', ':']
    }
    frm = self.newFrame()
    for i in range(2):
        key = self.COM_KEYS[i]
        ttk.Label(frm, text=key).grid(row=i, column=0, padx=2)
        tmp = ttk.Combobox(frm, width=10, textvariable=self.varDct[key])
        tmp.grid(row=i, column=1, padx=2, pady=2)
        tmp['value'] = enumDct[key]
        
        key = self.NUM_KEYS[i]
        ttk.Label(frm, text=key).grid(row=i, column=2, padx=2)
        tmp = ttk.Entry(frm, width=10, textvariable=self.varDct[key])
        tmp.grid(row=i, column=3, padx=2, pady=2)

        key = self.CLR_KEYS[i]
        ttk.Label(frm, text=key).grid(row=i, column=4, padx=2)
        tmp = ttk.Entry(frm, width=10, textvariable=self.varDct[key])
        tmp.grid(row=i, column=5, padx=2, pady=2)

在这里插入图片描述

这样一来就只剩下标签,层号和透明度这三个参数了,由于标签颇有标题的意味,所以把这三个参数放在线型上面。

最后得到

在这里插入图片描述

可定制绘图风格的绘图系统

如果想在DrawSystem中调用绘图风格,那么就需要DrawStyle对象可以输出绘图参数,由于这里面所有的参数都在字典里面,所以这一步非常容易

def getOneVar(self, key):
    v = self.varDct[key].get()
    if v=="": return ""
    if key in NUM_KEYS: return float(v)
    elif key in INT_KEYS: return int(v)
    else: return v

def getVarDct(self):
    dct = {self.VAR_LABS[key] : self.varDct[key].get() 
        for key in self.varDct}
    return {key : dct[key] for key in dct if dct[key]!=""}

第一个函数用于得到某个绘图参数,第二个则用字典的形式,返回所有已经设置的绘图参数。毕竟,在plot绘图过程中,并不是需要设置所有的绘图参数。

由于DrawStyle是在AxisList中被调用的,所以这个getVarDct函数最好在AxisList中重新封装一下

def getStyle(self):
    return self.DrawStyle.getVarDct()

最后,绘图风格实现的临门一脚,自然是DrawSystem中的plot函数

def drawPlot(self, ax, data, keys, style):
    ax.plot(*[data[key] for key in keys], **style)

多了一个style参数,由于绘图函数被重新赋给了func,从而所有绘图函数都要有相同的绘图接口,所以尽管暂时不用,drawScatter和drawBar也要加上style参数。同时更改绘图函数。代码如下,主要添加了一个al.getStyle()的调用。

def btnDrawImg(self):
    self.fig.clf()
    keys = self.drawTypeDim.getDim()
    self.axDct = {}
    for al in self.als:
        ax = self.setDrawAxis(al)
        data = self.readDatas(al)
        draw = self.drawDct[al.getDrawType()]
        style = al.getStyle()
        draw(ax, data, keys, style)
    self.fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.08)
    self.canvas.draw()

最后得到下面的效果。

在这里插入图片描述

代码组织

目前,这个绘图系统已经有了400多行代码,5个类被放在同一个文件中,修改起来已经有些不便了。为了开发工作得以继续,有必要把这几个类分发到不同的文件中。

在这里插入图片描述

下面新建四个文件,分别放入以下内容

  • base.py:DrawType, DrawStyle
  • aframe.py: AxisFrame
  • alist.py: AxisList
  • ds.py: DrawSystem
更多推荐

runc和docker

在Docker中,runc是一个轻量级的运行时工具,用于创建和运行容器。它是OpenContainerInitiative(OCI)的一部分,负责管理和执行容器中的进程。runc负责创建和管理Linux命名空间、控制组(cgroups)和文件系统挂载等功能,以便隔离容器中的进程、资源和文件系统。它还提供了容器的生命周期

在项目中,关于前端实现数据可视化的技术选择

前言在项目中,数据可视化以图表、报表类型为主。需求背景技术框架是Vue2.x版本,组件库是AntDesignofVue能够支撑足够多的图表类型开发图表大小/位置能够随意变动图表样式需要支持丰富多样的用户配置强大、开放的图表语法支持复杂的数据可视化场景兼顾电脑端和手机端、同时兼顾开发周期和后期维护版本稳定、社区活跃,方便

【数据结构】二叉树

树的概念及结构树的概念树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。有一个特殊的结点,称为根结点,根节点没有前驱结点(上图中的A结点就是根节点)除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、

SpringCLoud——RabbitMQ的消息模型

WorkQueue工作队列他的主要作用就是增加消费者的个数,可以提高消息处理速度,避免队列消息堆积。案例实现一个队列绑定多个消费者首先修改一下之前的发送消息的代码,让他循环发送50次,但是不要一次性发完:@TestvoidLoopSend()throwsInterruptedException{StringqueueN

计算机网络知识补充(1)

计算机网络:是一个将分散的,具有独立功能的计算机系统,通过通信设备和线路进行连接起来,由功能完善的软件实现资源共享和信息共享的系统,计算机网络是互连的,自治的计算机集合互连:通过通信链路来进行互联互通自治:没有主从关系1)电路交换:电路交换是一种通信方式,它是通过建立点对点的电路连接来传输数据的,在电路交换中,如果两个

同为科技(TOWE)工业用插头插座及配电箱产品选型推荐

工业用插头插座及配电箱产品是专用于工业环境中的电源连接和电气设备控制,与普通家用插头插座相比,通常具有更高的功率和电流容量,并且设计上考虑了耐用性、安全性和适应各种环境条件的能力。工业用插头插座产品类型多样,包括插头插座、工业连接器、防水配电箱等,满足户内外工业用电的各种需求,适用于工业、建筑、船舶、交通、能源、通信等

【linux基础(八)】计算机体系结构--冯诺依曼系统&操作系统的再理解

💓博主CSDN主页:杭电码农-NEO💓⏩专栏分类:Linux从入门到精通⏪🚚代码仓库:NEO的学习日记🚚🌹关注我🫵带你学更多操作系统知识🔝🔝计算机体系结构1.前言2.冯诺依曼系统介绍3.为什么冯诺依曼系统如此流行?4.对硬件系统的再理解5.校长对学生的管理6.操作系统对硬件的管理7.总结1.前言为了更好

小米发布会:雷军成长故事与创新壮举,AI大模型技术引领未来,雷军探索之路之从创业波折到小米AI领航,成就高端化传奇!

🌷🍁博主猫头虎带您GotoNewWorld.✨🍁🦄博客首页——猫头虎的博客🎐🐳《面试题大全专栏》文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大

JS学习笔记

1.CSS1.1文档流-所有的元素默认情况下都是在文档流中存在的-文档流是网页的最底层-元素在文档流中的特点:-块元素1.默认宽度是父元素的全部2.默认高度被内容(子元素)撑开3.在页面中自上而下垂直排列-内联元素1.默认高度和宽度都被内容撑开2.在页面中自左向右水平排列,如果一行不足以容下所有的元素则换到下一行继续从

Scala编程语言

Scala编程语言一、Scala引入1、学习Scala的目的2、Scala的基本概念二、Scala环境搭建1、安装步骤2、配置环境变量3、测试Scala4、Scala与idea的集成5、关联源码6、class和object说明三、常用语法、变量和数据类型1、注释2、变量和常量3、标识符的命名规范4、字符串输出5、键盘输

Oracle 游标&子程序&触发器

文章目录一、游标1.隐式游标2.显示游标3.REF游标二、子程序1.存储过程1.1语法结构1.2案例讲解2.存储函数2.1语法结构2.2案例讲解3.程序包三、触发器1.触发器的基本讲解2.触发器的类型2.1语句级触发器2.2行级触发器2.3限制行级触发器一、游标游标的作用:处理多行数据,类似与java中的集合1.隐式游

热文推荐