文章目录
- 类别与轴数
- 坐标类别对映射的影像
- 绘图类别对坐标轴的影响
- 源代码
Python绘图系统:
- 前置源码: Python打造动态绘图系统
- 📈一 三维绘图系统 📈二 多图绘制系统📈三 坐 标 轴 定 制
- 📈四 定制绘图风格 📈五 数据生成导入📈六 三维动态演示
- 坐标列表进阶:导出数据📌系统菜单📌批量文件导入📌辅助坐标轴
类别与轴数
DrawType是用于设置绘图类型的class,目前由4个部分组成,分别是绘图窗口、绘图类型、坐标映射以及绘图坐标。
其中,除了绘图窗口外,后面三个绘图属性是息息相关的。比如imshow函数就只能接收一个数组作为绘图数据,而plot既可以接受一个,也可以接受两个,当指定projection为3d的时候,还可以接受三个。换句话说,绘图坐标这个combobox中的内容,应该受到绘图类型以及坐标映射的调节。所以,首先为这两个Combobox添加事件。
wDct['type'].bind('<<ComboboxSelected>>', self.cbTypeChanged)
wDct['proj'].bind('<<ComboboxSelected>>', self.cbProjChanged)
其中type发生变化时,proj的可选项也要跟着发生变化。而proj的可选项发生变化后,dim也要跟着变化。
为了实现这种变化,需要把这几个combobox都变成全局变量,只需把所有的wDct变成self.wDct即可。
目前有三种绘图函数,分别是点线图、散点图和条形图,这三种图形均可在2d坐标、3d坐标和极坐标下绘制。而在不同坐标映射的情况下,不同绘图函数的坐标数如下表所示
2D | polar | 3D | |
---|---|---|---|
plot | x[,y] | x[,y] | x,y[,z] |
scatter | x,y | x,y | x,y[,z] |
bar | x,y | x,y | x,y[,z] |
坐标类别对映射的影像
首先更改type对proj的影响
def cbTypeChanged(self, evt):
t = self.drawVars['type'].get()
p = self.drawVars['proj'].get()
if t in ("点线图", "散点图", "条形图"):
self.wDct['proj']['value'] = ("None", "3d", "polar")
projs = self.wDct['proj']['value']
if p not in projs:
self.drawVars['proj'].set(projs[0])
self.cbTypeChanged(None)
其中,p表示当前的坐标映射,如果在选定的新的坐标映射元组,不支持p,那么就重新选择。
绘图类别对坐标轴的影响
matplotlib种总共有30多种绘图函数,结合3种坐标映射,那么总共有90种组合,如果用字典来写,虽然直观,但行数太多了,所以一步一步来,先看坐标的映射类型,然后再对绘图类型进行分类定制。这部分代码比较长,但逻辑十分简单,与cbTypeChanged几乎是一个模子刻出来的。
def cbProjChanged(self, evt):
p = self.drawVars['proj'].get()
func = {
'None': self.cbProjNone,
'3d': self.cbProj3d,
'polar' : self.cbProjPolar}
d = self.wDct['dim'].get()
t = self.drawVars['type'].get()
func[p](t)
dims = self.wDct['dim']['value']
if d not in dims:
self.drawVars['dim'].set(dims[0])
self.dimChanged(None)
def cbProjNone(self, t):
if t in ("点线图"):
self.wDct['dim']['value'] = ('x', 'xy')
elif t in ("散点图", "条形图"):
self.wDct['dim']['value'] = ('xy')
def cbProjPolar(self, t):
if t in ("点线图"):
self.wDct['dim']['value'] = ('x', 'xy')
elif t in ("散点图", "条形图"):
self.wDct['dim']['value'] = ('xy')
def cbProj3d(self, t):
if t in ("点线图", "散点图", "条形图"):
self.wDct['dim']['value'] = ('xy', 'xyz')
最后效果如下
源代码
最后,附上base.py修改之后的源代码。
import numpy as np
import tkinter as tk
import tkinter.ttk as ttk
class DrawStyle(ttk.Frame):
def __init__(self, master,
varDct={}, ws=None, func=None, **options):
super().__init__(master, **options)
self.pack()
self.initConst()
self.initVars()
self.initWidgets()
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 = ["线色", "点色"]
def initVars(self):
self.varDct = {key:tk.StringVar() for key in self.VAR_LABS}
def newFrame(self):
frm = ttk.Frame(self)
frm.pack(side=tk.TOP, fill=tk.X)
return frm
def initWidgets(self):
frm = self.newFrame()
for i,key in enumerate(["标签", "层号", "透明度"]):
tk.Label(frm, text=key).grid(row=0, column=i*2, padx=2)
tmp = ttk.Entry(frm, width=10, textvariable=self.varDct[key])
tmp.grid(row=0, column=i*2+1, padx=2, pady=2)
self.initLineMarker(frm)
def initLineMarker(self, frm):
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'],
"线型" : ['-', '--', '-.', ':']
}
for i in range(2):
key = self.COM_KEYS[i]
ttk.Label(frm, text=key).grid(row=i+1, column=0, padx=2)
tmp = ttk.Combobox(frm, width=10, textvariable=self.varDct[key])
tmp.grid(row=i+1, column=1, padx=2, pady=2)
tmp['value'] = enumDct[key]
key = self.NUM_KEYS[i]
ttk.Label(frm, text=key).grid(row=i+1, column=2, padx=2)
tmp = ttk.Entry(frm, width=10, textvariable=self.varDct[key])
tmp.grid(row=i+1, column=3, padx=2, pady=2)
key = self.CLR_KEYS[i]
ttk.Label(frm, text=key).grid(row=i+1, column=4, padx=2)
tmp = ttk.Entry(frm, width=10, textvariable=self.varDct[key])
tmp.grid(row=i+1, column=5, padx=2, pady=2)
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]!=""}
# 绘图类型和维度
# varDct 的格式是 {"sub":sub, "type":slctType, "dim":dim, "proj": proj}
class DrawType(ttk.Frame):
# ws为两个combobox的宽
def __init__(self, master,
varDct = {"sub":"111", "type":'点线图', "dim":"xyz", "proj": "3d"},
ws=None, func=None, **options):
super().__init__(master, **options)
self.pack()
self.dimChanged = func
self.initVar(varDct)
self.initWidgets(ws)
def initVar(self, varDct):
self.drawVars = {key:tk.StringVar() for key in varDct}
for key in self.drawVars:
self.drawVars[key].set(varDct[key])
def initWidgets(self, ws):
if ws==None: ws = [5, 5, 5, 3]
slctDct = {'type':("点线图", "散点图", "条形图"),
'proj': ("None", "3d", "polar"),
'dim' : ("x", "xy", "xyz", "tx", "txy", "txyz")} # 绘图维度
keys = ['sub', 'type', 'proj', 'dim']
self.wDct = {} # 控件字典
# 此为设置子图的Entry控件
self.wDct['sub'] = ttk.Entry(self, width=ws[0],
textvariable=self.drawVars['sub'])
for i, key in enumerate(keys[1:], 1):
self.wDct[key] = ttk.Combobox(self, width=ws[i],
textvariable=self.drawVars[key])
self.wDct[key]['value'] = slctDct[key]
for key in keys:
self.wDct[key].pack(side=tk.LEFT, padx=2)
self.wDct['type'].bind('<<ComboboxSelected>>', self.cbTypeChanged)
self.wDct['proj'].bind('<<ComboboxSelected>>', self.cbProjChanged)
self.wDct['dim'].bind('<<ComboboxSelected>>', self.dimChanged)
def cbTypeChanged(self, evt):
t = self.drawVars['type'].get()
p = self.drawVars['proj'].get()
if t in ("点线图", "散点图", "条形图"):
self.wDct['proj']['value'] = ("None", "3d", "polar")
projs = self.wDct['proj']['value']
if p not in projs:
self.drawVars['proj'].set(projs[0])
self.cbProjChanged(None)
def cbProjChanged(self, evt):
p = self.drawVars['proj'].get()
func = {
'None': self.cbProjNone,
'3d': self.cbProj3d,
'polar' : self.cbProjPolar}
d = self.wDct['dim'].get()
t = self.drawVars['type'].get()
func[p](t)
dims = self.wDct['dim']['value']
if d not in dims:
self.drawVars['dim'].set(dims[0])
self.dimChanged(None)
def cbProjNone(self, t):
if t in ("点线图"):
self.wDct['dim']['value'] = ('x', 'xy')
elif t in ("散点图", "条形图"):
self.wDct['dim']['value'] = ('xy')
def cbProjPolar(self, t):
if t in ("点线图"):
self.wDct['dim']['value'] = ('x', 'xy')
elif t in ("散点图", "条形图"):
self.wDct['dim']['value'] = ('xy')
def cbProj3d(self, t):
if t in ("点线图", "散点图", "条形图"):
self.wDct['dim']['value'] = ('xy', 'xyz')
def getSub(self):
return self.drawVars['sub'].get()
def getType(self):
return self.drawVars['type'].get()
def getDim(self):
return self.drawVars['dim'].get()
def getProj(self):
return self.drawVars['proj'].get()
def getDct(self):
return {key:self.drawVars[key].get() for key in self.drawVars}