Matplotlib在tkinter中起作用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Matplotlib在tkinter中起作用相关的知识,希望对你有一定的参考价值。

这是我的第一个python项目,所以我明白这个问题可能看起来有点愚蠢。 我正在尝试创建一个Mandelbrot渲染器。我正在从我理解的教程和代码中拼凑代码来制作一些东西。 所以基本上我有渲染器的GUI的所有数学和基本功能,但我无法让matplotlib图实际在tkinter GUI中绘图。 matplolib显示部分实际上是一个需要运行mandelbrot_image(-0.8,-0.7,0,0.1,cmap='hot')的函数。如果引入了该代码,则绘制Mandelbrot集,但是在不同的matplotlib窗口中。

这是我的所有代码,我提前感谢你,我再一次道歉。

   #big thanks and credit goes to to Jean Puget from IBM, SentDex from pythonprogramming.net, and stackoverflow 
   #for teaching me how to use python and inspiring much of this following code


import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg,    NavigationToolbar2TkAgg
from matplotlib.figure import Figure

import tkinter as tk
from tkinter import ttk

import numpy as np
from numba import jit

from matplotlib import pyplot as plt
from matplotlib import colors



#maths and display code derived/inspired from Jean Francois Puget 
#https://www.ibm.com/developerworks/community/blogs/jfp/entry/My_Christmas_Gift?lang=en
@jit
def mandelbrot(z,maxiter,horizon,log_horizon):
    c = z
    for n in range(maxiter):
        az = abs(z)
        if az > horizon:
            return n - np.log(np.log(az))/np.log(2) + log_horizon
        z = z*z + c
    return 0

 @jit
 def mandelbrot_set(xmin,xmax,ymin,ymax,width,height,maxiter):
    horizon = 2.0 ** 40
    log_horizon = np.log(np.log(horizon))/np.log(2)
    r1 = np.linspace(xmin, xmax, width)
    r2 = np.linspace(ymin, ymax, height)
    n3 = np.empty((width,height))
    for i in range(width):
        for j in range(height):
            n3[i,j] = mandelbrot(r1[i] + 1j*r2[j],maxiter,horizon, log_horizon)
    return (r1,r2,n3)


#Display setup
fig = Figure()
ax = fig.add_subplot(111)
xmin = -2.0
xmax = 0.5
ymin = -1.25
ymax = 1.25
cmap='hot'
# width=20
# height=20
# maxiter=1000
# gamma=0.3

def mandelbrot_image(xmin,xmax,ymin,ymax,width=10,height=10,
                 maxiter=1000,cmap='jet',gamma=0.3):
    dpi = 80
    img_width = dpi * width
    img_height = dpi * height
    x,y,z = mandelbrot_set(xmin,xmax,ymin,ymax,img_width,img_height,maxiter)

    fig, ax = plt.subplots(figsize=(width, height),dpi=72)
    ticks = np.arange(0,img_width,3*dpi)
    x_ticks = xmin + (xmax-xmin)*ticks/img_width
    plt.xticks(ticks, x_ticks)
    y_ticks = ymin + (ymax-ymin)*ticks/img_width
    plt.yticks(ticks, y_ticks)
    ax.set_title(cmap)
    norm = colors.PowerNorm(gamma)
    ax.figshow(z.T,cmap=cmap,origin='lower',norm=norm)


LARGE_FONT= ("Verdana", 12)


class base(tk.Tk):

    def __init__(self, *args, **kwargs):

        tk.Tk.__init__(self, *args, **kwargs)

        tk.Tk.iconbitmap(self, "iconz.ico")
        tk.Tk.wm_title(self, "Mandelbrot Renderer")


        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        menubar = tk.Menu(container)
        filemenu = tk.Menu(menubar, tearoff=0)

        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=quit)
        menubar.add_cascade(label="File", menu=filemenu)

        self.frames = {}

        for F in (StartPage, MainPage, Donate):

            frame = F(container, self)

            self.frames[F] = frame

            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        label = tk.Label(self, text="Start Page", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        button = ttk.Button(self, text="Lets Begin",
                        command=lambda: controller.show_frame(MainPage))
        button.pack()




class Donate(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Donate", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        button1 = ttk.Button(self, text="Back",
                            command=lambda: controller.show_frame(MainPage))
        button1.pack()






class MainPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Graph Page!", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        button1 = ttk.Button(self, text="Back to Home",
                            command=lambda: controller.show_frame(StartPage))
        button1.pack()

        button2 = ttk.Button(self, text="Donate",
                            command=lambda: controller.show_frame(Donate))
        button2.pack()


        canvas = FigureCanvasTkAgg(fig, self)
        canvas.show()
        canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)

        toolbar = NavigationToolbar2TkAgg(canvas, self)
        toolbar.update()
        canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)  




app = base()
app.geometry ("800x600")
app.mainloop()
答案

这里的主要问题是你创建了两个不同的数字。生活在Tk框架中的那个不是你绘制mandelbrot图像的那个。 因此,您需要在整个代码中使用相同的数字。 一种选择是让mandelbrot_image创建数字并将其返回以便以后能够将其提供给FigureCanvas。请参阅下面的完整解决方案。

另一个问题是matplotlib没有figshow方法。你可能想要imshow()instead。

import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure

import Tkinter as tk

import numpy as np
from numba import jit

from matplotlib import pyplot as plt
from matplotlib import colors

#maths and display code derived/inspired from Jean Francois Puget 
#https://www.ibm.com/developerworks/community/blogs/jfp/entry/My_Christmas_Gift?lang=en
@jit
def mandelbrot(z,maxiter,horizon,log_horizon):
    c = z
    for n in range(maxiter):
        az = abs(z)
        if az > horizon:
            return n - np.log(np.log(az))/np.log(2) + log_horizon
        z = z*z + c
    return 0

@jit
def mandelbrot_set(xmin,xmax,ymin,ymax,width,height,maxiter):
    horizon = 2.0 ** 40
    log_horizon = np.log(np.log(horizon))/np.log(2)
    r1 = np.linspace(xmin, xmax, width)
    r2 = np.linspace(ymin, ymax, height)
    n3 = np.empty((width,height))
    for i in range(width):
        for j in range(height):
            n3[i,j] = mandelbrot(r1[i] + 1j*r2[j],maxiter,horizon, log_horizon)
    return (r1,r2,n3)


def mandelbrot_image(xmin=-2.,xmax=0.5,ymin=-1.25,ymax=1.25,width=10,height=10,
                 maxiter=1000,cmap='jet',gamma=0.3):

    dpi = 80
    img_width = dpi * width
    img_height = dpi * height
    x,y,z = mandelbrot_set(xmin,xmax,ymin,ymax,img_width,img_height,maxiter)

    fig = Figure(figsize=(width, height))
    ax = fig.add_subplot(111)

    ticks = np.arange(0,img_width,3*dpi)
    x_ticks = xmin + (xmax-xmin)*ticks/img_width
    plt.xticks(ticks, x_ticks)
    y_ticks = ymin + (ymax-ymin)*ticks/img_width
    plt.yticks(ticks, y_ticks)
    ax.set_title(cmap)
    norm = colors.PowerNorm(gamma)
    ax.imshow(z.T,cmap=cmap,origin='lower',norm=norm)
    return fig

LARGE_FONT= ("Verdana", 12)

class base(tk.Tk):

    def __init__(self, *args, **kwargs):

        tk.Tk.__init__(self, *args, **kwargs)

        #tk.Tk.iconbitmap(self, "iconz.ico")
        tk.Tk.wm_title(self, "Mandelbrot Renderer")


        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        menubar = tk.Menu(container)
        filemenu = tk.Menu(menubar, tearoff=0)

        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=quit)
        menubar.add_cascade(label="File", menu=filemenu)

        self.frames = {}

        for F in (StartPage, MainPage):

            frame = F(container, self)

            self.frames[F] = frame

            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        label = tk.Label(self, text="Start Page", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        button = tk.Button(self, text="Lets Begin",
                        command=lambda: controller.show_frame(MainPage))
        button.pack()


class MainPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Graph Page!", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        button1 = tk.Button(self, text="Back to Home",
                            command=lambda: controller.show_frame(StartPage))
        button1.pack()

        # create a figure with the mandelbrot plot inside
        fig = mandelbrot_image()
        # attach this figure to the TK canvas
        canvas = FigureCanvasTkAgg(fig, self)
        canvas.show()
        canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)

        toolbar = NavigationToolbar2TkAgg(canvas, self)
        toolbar.update()
        canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)  


app = base()
app.geometry ("800x600")
app.mainloop()

注意:在较新版本的matplotlib中,您应该使用NavigationToolbar2Tk而不是NavigationToolbar2TkAgg

以上是关于Matplotlib在tkinter中起作用的主要内容,如果未能解决你的问题,请参考以下文章

Matplotlib 崩溃 tkinter 应用程序

将matplotlib嵌入到tkinter应用程序中

在 tkinter GUI 中更新 matplotlib 图

需要帮助使用matplotlib在tkinter中绘制图形[重复]

如何将 Seaborn 绘图集成到 Tkinter GUI

将 matplotlib 动画嵌入到 tkinter 帧中