tkinter內(nèi)嵌Matplotlib系列(二)之函數(shù)曲線繪制

目錄

[TOC]

前言

前一章節(jié),我們解讀了tkinter內(nèi)嵌Matplotlib的教程,了解其內(nèi)嵌的原理,就是在tkinter創(chuàng)建matplotlib的畫布控件,再利用其返回的畫布對象進(jìn)行繪圖,其他附加功能,使用tkinter控件實現(xiàn)。

(一)對matplotlib畫布的封裝:

(1)說明:

我們希望對官方的實例代碼進(jìn)行封裝成一個函數(shù),并返回一個畫布對象,外部再調(diào)用該函數(shù),并獲取畫布對象,進(jìn)行繪制操作。

(2)封裝后的代碼:

"""
    畫布文件,實現(xiàn)繪圖區(qū)域的顯示,并返回畫布的對象。
"""
import tkinter as tk

# 創(chuàng)建畫布需要的庫
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# 創(chuàng)建工具欄需要的庫
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
# 快捷鍵需要的庫
from matplotlib.backend_bases import key_press_handler
# 導(dǎo)入畫圖常用的庫
from matplotlib.figure import Figure

def plot_fun(root):
    """
        該函數(shù)實現(xiàn)的是內(nèi)嵌畫布,不負(fù)責(zé)畫圖,返回畫布對象。
    :param root:父親控件對象, 一般是容器控件或者窗體
    :return: 畫布對象
    """
    # 畫布的大小和分別率
    fig = Figure(dpi=100)
    axs = fig.add_subplot(111)

    # 創(chuàng)建畫布
    canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
    canvas.draw()
    # 顯示畫布
    canvas.get_tk_widget().pack()

    # 創(chuàng)建工具條
    toolbar = NavigationToolbar2Tk(canvas, root)
    toolbar.update()
    # 顯示工具條
    canvas.get_tk_widget().pack()

    # 調(diào)用快捷鍵
    def on_key_press(event):
        key_press_handler(event, canvas, toolbar)

    canvas.mpl_connect("key_press_event", on_key_press)

    # 返回畫布的對象
    return axs

(二)思路分析:

1.需求說明:

(1)背景:

作為學(xué)生的我們,你是否有那么一個場景,唉……,這個數(shù)學(xué)函數(shù)好難求哦,要是知道它的圖像這么畫就好了。

(2)需求:

給出數(shù)學(xué)表達(dá)式,繪制出該數(shù)學(xué)表達(dá)式的函數(shù)曲線,一來可以觀察函數(shù)的變化趨勢,二來可以根據(jù)兩條曲線的交點(diǎn),來求解出方程的大致結(jié)果。

2.框架的設(shè)置:

(1)說明:

分模塊編程,向來是眾人所提倡的,再python里更是很好的實現(xiàn)。

再動手敲代碼之前,我們先來大致的設(shè)置一下,小項目的框架。

(2)框架圖解:

01.png

3.文件說明:

(1)main.py

主程序文件,負(fù)責(zé)程序的啟動與結(jié)束和窗體的大致設(shè)置。

(2)widget.py

控件文件,負(fù)責(zé)程序控件的創(chuàng)建與布局

(3)figure.py

畫布文件,實現(xiàn)繪圖區(qū)域的顯示,并返回畫布的對象。

(4)plot.py

繪圖文件,負(fù)責(zé)函數(shù)曲線的繪制

(三)各文件的源代碼

1.main.py

"""
    主程序文件,負(fù)責(zé)程序的啟動與結(jié)束和窗體的大致設(shè)置。
"""

import tkinter as tk
import widget


def win_w_h(root):
    """
        控制窗口的大小和出現(xiàn)的位置
    :param root:
    :return: 窗口的大小和出現(xiàn)的位置
    """
    # 設(shè)置標(biāo)題:
    win.title("數(shù)學(xué)函數(shù)繪圖")

    # 繪圖區(qū)標(biāo)簽
    label_plot = tk.Label(root, text="繪     圖       區(qū)",
                          font=("微軟雅黑", 10), fg="blue")
    label_plot.place(relx=0.26, rely=0)

    label_func = tk.Label(root, text="功     能       區(qū)",
                          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
    # 窗體出現(xiàn)的位置:控制的是左上角的坐標(biāo)
    show_width = (screen_width - win_width) / 2
    show_height = (screen_height - win_height) / 2

    # 返回窗體 坐標(biāo)
    return win_width, win_height, show_width, show_height


win = tk.Tk()
# 大小 位置
win.geometry("%dx%d+%d+%d" % (win_w_h(win)))


# 創(chuàng)建一個容器, 沒有畫布時的背景
frame1 = tk.Frame(win, bg="#c0c0c0")
frame1.place(relx=0.00, rely=0.05, relwidth=0.62, relheight=0.89)


# 控件區(qū)
frame2 = tk.Frame(win, bg="#808080")
frame2.place(relx=0.62, rely=0.05, relwidth=0.38, relheight=0.89)

# 調(diào)用控件模塊
widget.widget_main(win, frame2)
win.mainloop()

2.widget.py

"""
    控件文件,負(fù)責(zé)程序控件的創(chuàng)建與布局
"""
import tkinter as tk
# 對話框所需的庫
import tkinter.messagebox as mb
# 畫布文件
import figure
# 繪圖文件
import plot


def widget_main(win, root):
    """
        負(fù)責(zé)程序控件的創(chuàng)建與布局
    :param win: 主窗體的對象。
    :param root: 繪圖區(qū)的容器對象。
    :return: 無
    """
    # 控件區(qū)的容器對象
    frame1 = None


# ===========功能區(qū)============================
    # 繪圖的功能函數(shù)
    def plot_f():
        string = entry.get()
        # 判斷輸入框是否為空
        if string == "":
            mb.showerror("提示", "沒有輸入值,請重新輸入:")
        else:
            # 判斷是否已經(jīng)創(chuàng)建畫布
            if frame1==None:
                mb.showerror("提示", "沒有創(chuàng)建畫布,不能畫圖,請先創(chuàng)建畫布")
            else:
                axs = figure.plot_fun(frame1)
                plot.plot_main(string, axs)

    # 清除的功能函數(shù)
    def clear():
        nonlocal frame1
        entry.delete(0, "end")
        if frame1==None:
            mb.showerror("提示", "已經(jīng)沒有畫布,無法清除畫布")
        else:
            frame1.destroy()
            frame1 = None

    # 創(chuàng)建畫布的功能函數(shù)
    def create():
        nonlocal frame1
        if frame1 != None:
            mb.showerror("提示", "畫布已經(jīng)存在,請不要重復(fù)創(chuàng)建畫布")
        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)


# =============控件區(qū)======================
    #  標(biāo)簽控件
    label = tk.Label(root,
                     text="請輸入含x的數(shù)學(xué)公式:",
                     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)

    # 創(chuàng)建畫布區(qū)
    btn_draw = tk.Button(root,
                         text="創(chuàng)建",
                         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

"""
    畫布文件,實現(xiàn)繪圖區(qū)域的顯示,并返回畫布的對象。
"""
import tkinter as tk

# 創(chuàng)建畫布需要的庫
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# 創(chuàng)建工具欄需要的庫
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
# 快捷鍵需要的庫
from matplotlib.backend_bases import key_press_handler
# 導(dǎo)入畫圖常用的庫
from matplotlib.figure import Figure

def plot_fun(root):
    """
        該函數(shù)實現(xiàn)的是內(nèi)嵌畫布,不負(fù)責(zé)畫圖,返回畫布對象。
    :param root:父親控件對象, 一般是容器控件或者窗體
    :return: 畫布對象
    """
    # 畫布的大小和分別率
    fig = Figure(dpi=100)
    axs = fig.add_subplot(111)

    # 創(chuàng)建畫布
    canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.
    canvas.draw()
    # 顯示畫布
    canvas.get_tk_widget().pack()

    # 創(chuàng)建工具條
    toolbar = NavigationToolbar2Tk(canvas, root)
    toolbar.update()
    # 顯示工具條
    canvas.get_tk_widget().pack()

    # 調(diào)用快捷鍵
    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

"""
    繪圖文件,負(fù)責(zé)函數(shù)曲線的繪制
"""
import numpy as np


def plot_main(string, plt):
    """
        負(fù)責(zé)函數(shù)曲線的繪制
    :param string: 數(shù)學(xué)表達(dá)式
    :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)

(四)文件結(jié)構(gòu)

四個文件均處于同一個文件夾下,用main.py來運(yùn)行。

02.png

(五)項目下載:

百度網(wǎng)盤下載

鏈接:https://pan.baidu.com/s/13G_hWqagxqHRkdHaYcxiQQ
提取碼:codq

作者:Mark

日期:2019/02/15 周五

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內(nèi)容