尽管从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个类被放在同一个文件中,修改起来已经有些不便了。为了开发工作得以继续,有必要把这几个类分发到不同的文件中。
下面新建四个文件,分别放入以下内容