• tkinter内嵌Matplotlib系列(二)之函数曲线绘制


    目录

    前言

    前一章节,我们解读了tkinter内嵌Matplotlib的教程,了解其内嵌的原理,就是在tkinter创建matplotlib的画布控件,再利用其返回的画布对象进行绘图,其他附加功能,使用tkinter控件实现。

    (一)对matplotlib画布的封装:

    (1)说明:

    我们希望对官方的实例代码进行封装成一个函数,并返回一个画布对象,外部再调用该函数,并获取画布对象,进行绘制操作。

    (2)封装后的代码:

    """
        画布文件,实现绘图区域的显示,并返回画布的对象。
    """
    import tkinter as tk
    
    # 创建画布需要的库
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    # 创建工具栏需要的库
    from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
    # 快捷键需要的库
    from matplotlib.backend_bases import key_press_handler
    # 导入画图常用的库
    from matplotlib.figure import Figure
    
    def plot_fun(root):
        """
            该函数实现的是内嵌画布,不负责画图,返回画布对象。
        :param root:父亲控件对象, 一般是容器控件或者窗体
        :return: 画布对象
        """
        # 画布的大小和分别率
        fig = Figure(dpi=100)
        axs = fig.add_subplot(111)
    
        # 创建画布
        canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
        canvas.draw()
        # 显示画布
        canvas.get_tk_widget().pack()
    
        # 创建工具条
        toolbar = NavigationToolbar2Tk(canvas, root)
        toolbar.update()
        # 显示工具条
        canvas.get_tk_widget().pack()
    
        # 调用快捷键
        def on_key_press(event):
            key_press_handler(event, canvas, toolbar)
    
        canvas.mpl_connect("key_press_event", on_key_press)
    
        # 返回画布的对象
        return axs
    

    (二)思路分析:

    1.需求说明:

    (1)背景:

    作为学生的我们,你是否有那么一个场景,唉……,这个数学函数好难求哦,要是知道它的图像这么画就好了。

    (2)需求:

    给出数学表达式,绘制出该数学表达式的函数曲线,一来可以观察函数的变化趋势,二来可以根据两条曲线的交点,来求解出方程的大致结果。

    2.框架的设置:

    (1)说明:

    分模块编程,向来是众人所提倡的,再python里更是很好的实现。

    再动手敲代码之前,我们先来大致的设置一下,小项目的框架。

    (2)框架图解:

    01.png

    3.文件说明:

    (1)main.py

    主程序文件,负责程序的启动与结束和窗体的大致设置。

    (2)widget.py

    控件文件,负责程序控件的创建与布局

    (3)figure.py

    画布文件,实现绘图区域的显示,并返回画布的对象。

    (4)plot.py

    绘图文件,负责函数曲线的绘制

    (三)各文件的源代码

    1.main.py

    """
        主程序文件,负责程序的启动与结束和窗体的大致设置。
    """
    
    import tkinter as tk
    import widget
    
    
    def win_w_h(root):
        """
            控制窗口的大小和出现的位置
        :param root:
        :return: 窗口的大小和出现的位置
        """
        # 设置标题:
        win.title("数学函数绘图")
    
        # 绘图区标签
        label_plot = tk.Label(root, text="绘     图       区",
                              font=("微软雅黑", 10), fg="blue")
        label_plot.place(relx=0.26, rely=0)
    
        label_func = tk.Label(root, text="功     能       区",
                              font=("微软雅黑", 10), fg="blue")
        label_func.place(relx=0.75, rely=0)
        # 获取屏幕的大小;
        screen_height = root.winfo_screenheight()
        screen_width = root.winfo_screenwidth()
        # 窗体的大小
        win_width = 0.8 * screen_width
        win_height = 0.8 * screen_height
        # 窗体出现的位置:控制的是左上角的坐标
        show_width = (screen_width - win_width) / 2
        show_height = (screen_height - win_height) / 2
    
        # 返回窗体 坐标
        return win_width, win_height, show_width, show_height
    
    
    win = tk.Tk()
    # 大小 位置
    win.geometry("%dx%d+%d+%d" % (win_w_h(win)))
    
    
    # 创建一个容器, 没有画布时的背景
    frame1 = tk.Frame(win, bg="#c0c0c0")
    frame1.place(relx=0.00, rely=0.05, relwidth=0.62, relheight=0.89)
    
    
    # 控件区
    frame2 = tk.Frame(win, bg="#808080")
    frame2.place(relx=0.62, rely=0.05, relwidth=0.38, relheight=0.89)
    
    # 调用控件模块
    widget.widget_main(win, frame2)
    win.mainloop()
    

    2.widget.py

    """
        控件文件,负责程序控件的创建与布局
    """
    import tkinter as tk
    # 对话框所需的库
    import tkinter.messagebox as mb
    # 画布文件
    import figure
    # 绘图文件
    import plot
    
    
    def widget_main(win, root):
        """
            负责程序控件的创建与布局
        :param win: 主窗体的对象。
        :param root: 绘图区的容器对象。
        :return: 无
        """
        # 控件区的容器对象
        frame1 = None
    
    
    # ===========功能区============================
        # 绘图的功能函数
        def plot_f():
            string = entry.get()
            # 判断输入框是否为空
            if string == "":
                mb.showerror("提示", "没有输入值,请重新输入:")
            else:
                # 判断是否已经创建画布
                if frame1==None:
                    mb.showerror("提示", "没有创建画布,不能画图,请先创建画布")
                else:
                    axs = figure.plot_fun(frame1)
                    plot.plot_main(string, axs)
    
        # 清除的功能函数
        def clear():
            nonlocal frame1
            entry.delete(0, "end")
            if frame1==None:
                mb.showerror("提示", "已经没有画布,无法清除画布")
            else:
                frame1.destroy()
                frame1 = None
    
        # 创建画布的功能函数
        def create():
            nonlocal frame1
            if frame1 != None:
                mb.showerror("提示", "画布已经存在,请不要重复创建画布")
            else:
                frame1 = tk.LabelFrame(win, bg="#80ff80", text="画-----布", labelanchor="n", fg="green")
                frame1.place(relx=0.00, rely=0.05, relwidth=0.62, relheight=0.95)
    
    
    # =============控件区======================
        #  标签控件
        label = tk.Label(root,
                         text="请输入含x的数学公式:",
                         font=("微软雅黑", 18),
                         fg="blue")
        label.place(relx=0.2, rely=0.1)
    
        # 输入框
        entry = tk.Entry(root, font=("华文楷体", 15))
        entry.place(relx=0.1, rely=0.2, relwidth=0.8)
    
        # 创建画布区
        btn_draw = tk.Button(root,
                             text="创建",
                             cursor="hand2",
                             width=10,
                             bg="orange",
                             relief="raised",
                             command=create
                             )
        btn_draw.place(relx=0.1, rely=0.3)
    
        # 绘图按钮
        btn_draw = tk.Button(root,
                             text="绘图",
                             cursor="hand2",
                             width=10,
                             bg="green",
                             relief="raised",
                             command=plot_f
                             )
        btn_draw.place(relx=0.4, rely=0.3)
    
        # 清除按钮
        btn_clear = tk.Button(root,
                              text="清除",
                              cursor="hand2",
                              width=10,
                              bg="yellow",
                              relief="raised",
                              command=clear
                              )
        btn_clear.place(relx=0.7, rely=0.3)
    

    3.figure.py

    """
        画布文件,实现绘图区域的显示,并返回画布的对象。
    """
    import tkinter as tk
    
    # 创建画布需要的库
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    # 创建工具栏需要的库
    from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
    # 快捷键需要的库
    from matplotlib.backend_bases import key_press_handler
    # 导入画图常用的库
    from matplotlib.figure import Figure
    
    def plot_fun(root):
        """
            该函数实现的是内嵌画布,不负责画图,返回画布对象。
        :param root:父亲控件对象, 一般是容器控件或者窗体
        :return: 画布对象
        """
        # 画布的大小和分别率
        fig = Figure(dpi=100)
        axs = fig.add_subplot(111)
    
        # 创建画布
        canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
        canvas.draw()
        # 显示画布
        canvas.get_tk_widget().pack()
    
        # 创建工具条
        toolbar = NavigationToolbar2Tk(canvas, root)
        toolbar.update()
        # 显示工具条
        canvas.get_tk_widget().pack()
    
        # 调用快捷键
        def on_key_press(event):
            key_press_handler(event, canvas, toolbar)
    
        canvas.mpl_connect("key_press_event", on_key_press)
    
        # 返回画布的对象
        return axs
    

    4.plot.py

    """
        绘图文件,负责函数曲线的绘制
    """
    import numpy as np
    
    
    def plot_main(string, plt):
        """
            负责函数曲线的绘制
        :param string: 数学表达式
        :param plt: 画布的对象
        :return: 无
        """
        list_expr = []
        list_expr = string.split(",")
        string1 = []
        for sub_expr in list_expr:
            string1.append(sub_expr)
        x = np.linspace(-10, 10, 100)
        y = []
        num = string.count('x')
        for i in x:
            t = (i, ) * num
            string = string.replace("x", "(%f)")
            i = eval(string % t)
            y.append(i)
        plt.plot(x, y)
        plt.grid(True)
        plt.legend(labels=string1)
    

    (四)文件结构

    四个文件均处于同一个文件夹下,用main.py来运行。

    02.png

    (五)项目下载:

    百度网盘下载

    链接:https://pan.baidu.com/s/13G_hWqagxqHRkdHaYcxiQQ
    提取码:codq

    作者:Mark

    日期:2019/02/15 周五

  • 相关阅读:
    Microsoft Biztalk Server 2000简介
    BizTalk学习笔记系列之二:实例说明如何使用BizTalk
    BizTalk学习笔记系列之三:企业集成应用和BizTalk
    简单状态机Workflow基于Web应用【转】
    C#类、接口、虚方法和抽象方法
    多表查询语句写法、数据库数字如何转化为汉子、Sql语句拼接
    IsPostBack用法
    Net前台页面如何调用后台cs变量
    aspx页面中写if else 语句的方法,
    查询数据库最大的索引、静态类与非静态类的区别、后台操作DIV样式的方法、C#操作TreeView组件中的一些常用方法及具体实现
  • 原文地址:https://www.cnblogs.com/zyg123/p/10385517.html
Copyright © 2020-2023  润新知