Python绘图系统9:新建绘图类型控件,实现混合类型图表

这篇具有很好参考价值的文章主要介绍了Python绘图系统9:新建绘图类型控件,实现混合类型图表。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Python绘图系统:

  • 📈从0开始的3D绘图系统📉一个3D坐标系,多个函数
  • 图表类型和风格:散点图和条形图📊混合类型图表

绘图类型控件

很多时候我们都有在一张图上绘制多种图标的需求,比如数据拟合的时候,用散点图表示原始数据,用曲线图来表示绘图后的结果。从这个角度来说,每一组绘图数据都应该有其自身的绘图类别。换言之,我们在DrawSystem中建立的绘图类型选择框,也需要在AxisFrame中使用。

为了降低代码重复,最好还是新建一个控件,专门用于约定绘图类型。而且更加广泛地讲,除了散点图条形图这种,是二维还是三维,也可算在绘图类型里面。所以,这个绘图类型控件,至少包含两个ComboBox,这对于已经创建过AxisFrame和AxisList的我们来说,属于小儿科水平

class DrawType(ttk.Frame):
    # ws为两个combobox的宽
    def __init__(self, master, types, slctType, 
        slctDim="3", ws=None, **options):
        super().__init__(master, **options)
        self.pack()
        self.types = types  # 绘图类型
        self.dims = ("1", "2", "3", "1+1", "2+1", "3+1")    # 绘图维度
        
        self.initVar(slctType, slctDim)
        self.initWidgets(ws)

    def initVar(self, slctType, slctDim):
        self.drawType = tk.StringVar()
        self.drawType.set(slctType)
        
        self.drawDim = tk.StringVar()
        if type(slctDim) != str:
            slctDim = self.dims[int(slctDim)]
        self.drawDim.set(slctDim)

    def initWidgets(self, ws):
        if ws==None: ws = [8, 3]
        vs = [self.drawType, self.drawDim]
        slcts = [self.types, self.dims]
        for i in range(2):
            slct = ttk.Combobox(self, width=ws[i], textvariable=vs[i])
            slct['value'] = slcts[i]
            slct.pack(side=tk.LEFT)
    
    def getType(self):
        return self.drawType.get()
    
    def getDim(self):
        dim = self.drawDim.get()
        dimDct = {"1"  :  "x", "2"  :  "xy", "3"  : "xyz", 
                  "1+1": "tx", "2+1": "txy", "3+1":  "txyz"}
        return dimDct[dim]

然后更改DrawSystem,主要是把setCtrlButtons(self, frm)函数的前两句改为

def setCtrlButtons(self, frm):
    self.drawTypeDim = DrawType(frm, self.TYPES, "点线图")
    self.drawTypeDim.pack(side=tk.LEFT)
    # ...

另一方面,两个ComboBox太大了,为了美观,把新增和删除两个按钮上的文字改为加号和减号。修改过后的UI如下

Python绘图系统9:新建绘图类型控件,实现混合类型图表,# Python可视化,python,tkinter,自定义控件,matplotlib,scatter,plot

改造AxisList

首先,在AxisList的初始化代码中添加初始化绘图类型的参数

def __init__(self, master, 
    title, mode, widths, 
    types, slctType,        # 绘图类型Combobox的参数
    **options):
    super().__init__(master, **options)
    self.pack()
    self.afs = {}
    self.data = {}

    self.initWidgets(title, widths)
    self.initFeature(types, slctType)
    self.initAxis(mode, widths)

由于更改是输入参数的个数,所以在DrawSystem中调用时,需要把types和slctType这两个参数补上。

然后在initFeature中添加drawTypeDim,

def initFeature(self, types, slctType):
    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)
    
    frm = ttk.Frame(self._c)
    frm.pack(pady=2, side=tk.TOP, fill=tk.X)
    self.drawTypeDim = DrawType(frm, types, slctType)

    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)

更改绘图逻辑

最后,更改绘图逻辑。首先,考虑到drawDct的特点,将其改为全局变量。

self.drawDct = {
    "点线图" : self.drawPlot,
    "散点图" : self.drawScatter,
    "条形图" : self.drawBar
}

然后,考虑到每次绘图都需要读取AxisList中的绘图类型,从而需要分次调用绘图函数,所以创建窗口这一步也交给btnDrawImg函数,从而绘图函数就只剩下了完完全全的绘图功能。相关代码如下

def btnDrawImg(self):
    self.fig.clf()
    keys = self.drawTypeDim.getDim()
    p = '3d' if 'z' in keys else None
    ax = self.fig.add_subplot(projection=p)
    for al in self.als:
        data = self.readDatas(al)
        draw = self.drawDct[al.getDrawType()]
        draw(ax, data, keys)
    self.fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.08)
    self.canvas.draw()

def drawBar(self, ax, data, keys):
    ax.bar(data['x'], data['y'])

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

def drawScatter(self, ax, data, keys):
    ax.scatter(*[data[key] for key in keys])

最后运行结果如下,分别绘制的散点图和曲线图。

Python绘图系统9:新建绘图类型控件,实现混合类型图表,# Python可视化,python,tkinter,自定义控件,matplotlib,scatter,plot

源代码

最后附上源代码,写在.py文件里,然后python xx.py就可以正常运行。文章来源地址https://www.toymoban.com/news/detail-677480.html

import tkinter as tk
import tkinter.ttk as ttk
from tkinter.filedialog import askopenfilename

import matplotlib as mpl
mpl.use('TkAgg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure

import numpy as np


class AxisFrame(ttk.Frame):
    # widths 是每个控件的宽度
    def __init__(self, master, label, mode, widths, **options):
        super().__init__(master, **options)
        self.pack()
        self.label = label
        self.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.MODES
        self.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.data

    def loadData(self, data):
        if type(data) != type(None):
            self.data = data
        return self.data

    def getArray(self):
        val = self.get()
        self.data = eval(f"np.linspace({val})")
        return self.data

class AxisList(ttk.Frame):
    def __init__(self, master, 
        title, mode, widths, 
        types, slctType,        # 绘图类型Combobox的参数
        **options):
        super().__init__(master, **options)
        self.pack()
        self.afs = {}
        self.data = {}

        self.initWidgets(title, widths)
        self.initFeature(types, slctType)
        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 = True
        self.Click()
    
    def initFeature(self, types, slctType):
        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)
        
        frm = ttk.Frame(self._c)
        frm.pack(pady=2, side=tk.TOP, fill=tk.X)
        self.drawTypeDim = DrawType(frm, types, slctType)
        self.drawTypeDim.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 getDrawType(self):
        return self.drawTypeDim.getType()
    
    def getDrawDim(self):
        return self.drawTypeDim.getDim()

    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 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]:
                return
            self.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.collapsed

    def setData(self, flag, data=None, **options):
        return self.afs[flag].setData(data, **options)
    
    def setOneMode(self, flag, mode):
        self.afs[flag].setMode(mode)

# 绘图类型和维度
class DrawType(ttk.Frame):
    # ws为两个combobox的宽
    def __init__(self, master, types, slctType, 
        slctDim="3", ws=None, **options):
        super().__init__(master, **options)
        self.pack()
        self.types = types  # 绘图类型
        self.dims = ("1", "2", "3", "1+1", "2+1", "3+1")    # 绘图维度
        
        self.initVar(slctType, slctDim)
        self.initWidgets(ws)

    def initVar(self, slctType, slctDim):
        self.drawType = tk.StringVar()
        self.drawType.set(slctType)
        
        self.drawDim = tk.StringVar()
        if type(slctDim) != str:
            slctDim = self.dims[int(slctDim)]
        self.drawDim.set(slctDim)

    def initWidgets(self, ws):
        if ws==None: ws = [8, 3]
        vs = [self.drawType, self.drawDim]
        slcts = [self.types, self.dims]
        for i in range(2):
            slct = ttk.Combobox(self, width=ws[i], textvariable=vs[i])
            slct['value'] = slcts[i]
            slct.pack(side=tk.LEFT)
    
    def getType(self):
        return self.drawType.get()
    
    def getDim(self):
        dim = self.drawDim.get()
        dimDct = {"1"  :  "x", "2"  :  "xy", "3"  : "xyz", 
                  "1+1": "tx", "2+1": "txy", "3+1":  "txyz"}
        return dimDct[dim]

class DarwSystem():
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("数据展示工具")
        self.data = {}
        self.als = []

        self.initConst()
        self.setFrmCtrl()

        frmFig = ttk.Frame(self.root)
        frmFig.pack(side=tk.LEFT,fill=tk.BOTH,expand=tk.YES)
        self.setFrmFig(frmFig)
        self.root.mainloop()
    
    def initConst(self):
        self.TYPES = ("点线图", "散点图", "条形图")


    def setFrmCtrl(self):
        frmCtrl = ttk.Frame(self.root,width=320)
        frmCtrl.pack(side=tk.RIGHT, fill=tk.Y)
        frm = ttk.Frame(frmCtrl, width=320)
        frm.pack(side=tk.TOP, fill=tk.X)
        self.setCtrlButtons(frm)
        self.frmAxis = ttk.Frame(frmCtrl)
        self.frmAxis.pack(side=tk.TOP, fill=tk.X)
        self.addLast(None)

    # ! 工具栏
    def setCtrlButtons(self, frm):
        self.drawTypeDim = DrawType(frm, self.TYPES, "点线图")
        self.drawTypeDim.pack(side=tk.LEFT)

        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)
        btn = ttk.Button(frm, text="+", width=3)
        btn.pack(side=tk.LEFT)
        btn.bind("<Button-1>", self.addLast)

        btn = ttk.Button(frm, text="-", width=3)
        btn.pack(side=tk.LEFT)
        btn.bind("<Button-1>", self.deleteLast)

    def addLast(self, evt):
        title = f"坐标{len(self.als)}"
        al = AxisList(self.frmAxis, title, 1, [5,10,20], 
            self.TYPES, self.drawTypeDim.getType())
        al.pack(side=tk.TOP, fill=tk.X)
        self.als.append(al)

    def deleteLast(self, evt):
        self.als[-1].pack_forget()
        del self.als[-1]


    def btnLoadData(self):
        name = askopenfilename()
        data = np.genfromtxt(name)
        for i, flag in enumerate('xyz'):
            if i >= data.shape[1]:
                return
            self.AL.setOneMode(flag, "外部导入")
            self.data[flag] = self.AL.setData(flag, data[:,i])
    
    def readDatas(self, al):
        dct = {}
        data = {}
        for flag in 'xyz':
            data[flag] = al.setData(flag, **dct)
            dct[flag] = data[flag]
        return data

    def btnDrawImg(self):
        drawDct = {
            "点线图" : self.drawPlot,
            "散点图" : self.drawScatter,
            "条形图" : self.drawBar
        }
        self.fig.clf()
        keys = self.drawTypeDim.getDim()
        p = '3d' if 'z' in keys else None
        ax = self.fig.add_subplot(projection=p)
        for al in self.als:
            data = self.readDatas(al)
            draw = drawDct[al.getDrawType()]
            draw(ax, data, keys)
        self.fig.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.08)
        self.canvas.draw()

    def drawBar(self, ax, data, keys):
        ax.bar(data['x'], data['y'])

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

    def drawScatter(self, ax, data, keys):
        ax.scatter(*[data[key] for key in keys])


    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()

到了这里,关于Python绘图系统9:新建绘图类型控件,实现混合类型图表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 3D科研绘图与学术图表绘制:从入门到精通

    💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】 🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】 💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 3D科研绘图和学术图表绘制是科研和学术领域中不可或缺的一部分,可以帮助研究

    2024年02月08日
    浏览(38)
  • c# winform实现控件类型、数量的动态更新

    在系统开发的过程中,往往会遇到需要动态的控制控件内部显示的控件数量、控件类型的情况,比如这样的。 1、问题描述:如何自定义的控制控件中数据显示的类型呢? 首先面对这个问题,我们得先了解winform的控制工具中有哪些控件是可以用来承载其他控件工具的,例如以

    2024年02月16日
    浏览(30)
  • 《MATLAB科研绘图与学术图表绘制从入门到精通》

    解锁MATLAB科研绘图魅力,让数据可视化成为你的科研利器! 1.零基础快速入门:软件操作+实战案例+图文、代码结合讲解,从入门到精通快速高效。 2.多种科研绘图方法:科研绘图基础+变量图形+极坐标图形+3D图形+地理信息可视化等,绘图技巧全面掌握。 3.实用性和艺术性兼

    2024年04月13日
    浏览(54)
  • Origin:科研绘图与学术图表绘制从入门到精通

    Origin是一款功能强大的数据分析和科学绘图软件,广泛应用于科研、工程和技术领域。它提供了丰富的数据可视化工具,可以帮助用户轻松创建各种类型的图表,如折线图、柱状图、散点图、饼图等。本文将介绍Origin科研绘图与学术图表绘制从入门到精通的步骤和方法,帮助

    2024年02月04日
    浏览(89)
  • TeeChart图表控件许可常见问题解答

    Steema是全球领先的图表类控件公司,总部设在西班牙的巴塞罗那附近,Steema公司的VCL图表报表控件在全球拥有极高知名度。TeeChart可以在微软的Visual Studio、Office和.NET以及Java和PHP开发平台中使用,也可以作为本地Javascript-HTML5使用。 TeeChart for .NET是优秀的工业4.0 WinForm图表控件

    2024年02月09日
    浏览(31)
  • 删除桌面右键菜单新建中的新建Microsoft Access,坚果云绘图\.accdb等方法

    打开注册表 先到导出备份 得到文件的后缀,比如 .ngm 打开注册表regedit分别定位到 HKEY_CLASSES_ROOT.ngm(坚果云绘图的删除/新增快捷方式) 在ShellNew前加一个点 保存退出 右键新建已经没有坚果云绘图了 删除Microsoft Access Database的方式: HKEY_LOCAL_MACHINESOFTWAREClassesAccess.MDBFile (

    2024年02月04日
    浏览(21)
  • 【深度学习】 Python 和 NumPy 系列教程(十五):Matplotlib详解:2、3d绘图类型(1):线框图(Wireframe Plot)

    目录  一、前言 二、实验环境 三、Matplotlib详解  1、2d绘图类型 2、3d绘图类型 0. 设置中文字体 1. 线框图(Wireframe Plot)         Python是一种高级编程语言,由Guido van Rossum于1991年创建。它以简洁、易读的语法而闻名,并且具有强大的功能和广泛的应用领域。Python具有丰富

    2024年02月08日
    浏览(36)
  • VS2019 MFC Teechart V5.1曲线控件使用方法Teechart Activex V5.1控件绘图控件 动态绘图

    Teechart控件安装注册:          1. 将TeeChart5.ocx 复制到C:WindowsSysWOW64。         2. 找到同目录下的cmd.exe。         3. 右键 管理员身份 打开 ,此刻进入的是system32 (不是管理员打开cmd的话,用win + R的话,会提示模块已加载,但对DllRegisterServer的调用失败)。    

    2024年02月05日
    浏览(52)
  • Android开发——控件EditText, 2.获取EditText输入的数据,通过按钮点击实现,ImageView控件,缩放类型,控件ProgressBar,常用属性详解,进度条设置

    1. android : hint 输入提示 2. android : textColorHint  输入提示文字的颜色 3. android : inputType  输入类型 4. android : drawableXxxx 在输入框的指定方位添加图片 5. android : drawablePadding  设置图片与输入内容的间距 6. android : paddingxxxx  设置内容与边框的间距 7. android : backgrou

    2024年02月07日
    浏览(36)
  • 【深度学习】 Python 和 NumPy 系列教程(廿四):Matplotlib详解:2、3d绘图类型(10)3D箱线图(3D Box Plot)

    目录 一、前言 二、实验环境 三、Matplotlib详解 1、2d绘图类型 2、3d绘图类型 0. 设置中文字体 1. 3D线框图(3D Line Plot) 2. 3D散点图(3D Scatter Plot) 3. 3D条形图(3D Bar Plot) 4. 3D曲面图(3D Surface Plot) 5. 3D等高线图(3D Contour Plot) 6. 3D向量场图(3D Vector Field Plot) 7. 3D表面投影图

    2024年02月03日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包