Python绘图系统24:绘图类型和坐标映射的关系

文章目录

    • 类别与轴数
    • 坐标类别对映射的影像
    • 绘图类别对坐标轴的影响
    • 源代码

Python绘图系统:

  • 前置源码: Python打造动态绘图系统
  • 一 三维绘图系统 二 多图绘制系统三 坐 标 轴 定 制
  • 四 定制绘图风格 五 数据生成导入六 三维动态演示
  • 坐标列表进阶:导出数据系统菜单批量文件导入辅助坐标轴

类别与轴数

DrawType是用于设置绘图类型的class,目前由4个部分组成,分别是绘图窗口、绘图类型、坐标映射以及绘图坐标。

其中,除了绘图窗口外,后面三个绘图属性是息息相关的。比如imshow函数就只能接收一个数组作为绘图数据,而plot既可以接受一个,也可以接受两个,当指定projection为3d的时候,还可以接受三个。换句话说,绘图坐标这个combobox中的内容,应该受到绘图类型以及坐标映射的调节。所以,首先为这两个Combobox添加事件。

wDct['type'].bind('<>', self.cbTypeChanged)
wDct['proj'].bind('<>', 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')

最后效果如下

Python绘图系统24:绘图类型和坐标映射的关系_第1张图片

源代码

最后,附上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('<>', self.cbTypeChanged)
        self.wDct['proj'].bind('<>', self.cbProjChanged)
        self.wDct['dim'].bind('<>', 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}

你可能感兴趣的:(#,Python可视化,python,matplotlib,tkinter,combobox,坐标映射,plot,bar)