2017-03-01 64 views
1

我再次需要幫助... 我對python非常陌生,我試圖在GUI中繪製Mandelbrot集。目前我正在研究一個函數,在該函數中我可以更改分形的渲染顏色。問題是我無法弄清楚如何用新的替換舊的繪圖。一切都需要重新繪製陰謀才行(終端甚至暫停,好像它正在重新計算,但不會產生任何東西)。我曾嘗試在互聯網上提出的所有不同的地方插入fig.clf(),但我仍然無法弄清楚。附件是代碼將運行的摘錄。此代碼的特定位置位於名爲mandelbrot_image和類MainPage的函數中。先謝謝你。用戶輸入更新Matplotlib圖

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 
from tkinter import * 
#import tkinter.messagebox 
from tkinter import messagebox 
import numpy as np 
from numba import jit 


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='hot',gamma=0.3): #the coords and cmap are essentially a filler for the imput in the plot() function at the bottom of the code 


    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 
    ax.set_xticks(ticks); ax.set_xticklabels(x_ticks) 
    y_ticks = ymin + (ymax-ymin)*ticks/img_width 
    ax.set_yticks(ticks); ax.set_yticklabels(y_ticks) 
    ax.set_title("The Mandelbrot set") 
    norm = colors.PowerNorm(gamma) 
    #fig.clf() 
    ax.imshow(z.T,cmap=cmap,origin='lower',norm=norm) 

    return fig 

LARGE_FONT= ("Verdana", 12) 
NORM_FONT= ("Verdana", 10) 

class base(tk.Tk): 

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

     tk.Tk.__init__(self, *args, **kwargs) 
     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) 


     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 = ttk.Button(self, text="Lets Begin", 
         command=lambda: controller.show_frame(MainPage)) 
     button.pack() 



class MainPage(tk.Frame): 

    def var_states(self): #this is supposed to send code to run plot() again but it doesnt do it 
     print (self.combobox.get()) 
     print (self.colr) 
     self.plot() 


    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) 

     values = ['jet', 'rainbow', 'ocean', 'hot', 'cubehelix','gnuplot','terrain','prism', 'pink'] 
     button1 = ttk.Button(self, text="Back to Home", 
          command=lambda: controller.show_frame(StartPage)) 
     button1.pack() 

     button2 = ttk.Button(self, text="Re-Render", 
          command=self.plot) 
     button2.pack() 
     self.mvar = IntVar() 
     self.cbutton = ttk.Checkbutton(self, text="shadow",onvalue=0, offvalue=1, variable=self.mvar) 
     self.cbutton.pack() 

     self.combobox = ttk.Combobox(self, values=values) 
     self.combobox.current(0) 
     self.combobox.pack(side = RIGHT) 

     global colr 
     self.colr = self.combobox.get() 
     self.plot() 

    def plot (self): 
     colr = self.combobox.get() 
     print (colr) 
     #fig.clf() this does nothing and crashes 
     fig = mandelbrot_image(-0.8,-0.7,0,0.1,cmap=colr) #this is calling the method with the coordinates of the plot and the color scheme 
     #fig.clf()this works but just leaves the screen completely blank 
     canvas = FigureCanvasTkAgg(fig, self) 
     #fig.clf()this works but just leaves the screen completely blank 
     canvas.show() 
     #canvas.clf() 
     #fig.clf() this works but just leaves the screen completely blank 
     canvas.get_tk_widget().pack(side = BOTTOM, fill=tk.BOTH, expand=True) 

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

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

回答

1

如果要更新圖形,則不應在多次調用的函數中創建該圖形。相反,您可以在MainPage的init函數中創建圖形,並僅更新其子圖的內容。因此,繪圖功能只能清除座標軸(不是圖形!),並調用要繪製的座標軸作爲參數傳送到的函數mandelbrot_image。最後,必須使用canvas.draw()重新繪製畫布,以使新圖出現在GUI中。

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

import Tkinter as tk #replace with tkinter for python 3 
import ttk 
import numpy as np 
from numba import jit 
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(ax, xmin=-2.,xmax=0.5,ymin=-1.25,ymax=1.25,width=10,height=10,\ 
      maxiter=1000,cmap='hot',gamma=0.3): #the coords and cmap are essentially a filler for the imput in the plot() function at the bottom of the code 


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

    ticks = np.arange(0,img_width,3*dpi) 
    x_ticks = xmin + (xmax-xmin)*ticks/img_width 
    ax.set_xticks(ticks); ax.set_xticklabels(x_ticks) 
    y_ticks = ymin + (ymax-ymin)*ticks/img_width 
    ax.set_yticks(ticks); ax.set_yticklabels(y_ticks) 
    ax.set_title("The Mandelbrot set") 
    norm = colors.PowerNorm(gamma) 
    ax.imshow(z.T,cmap=cmap,origin='lower',norm=norm) 


LARGE_FONT= ("Verdana", 12) 
NORM_FONT= ("Verdana", 10) 

class base(tk.Tk): 

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

     tk.Tk.__init__(self, *args, **kwargs) 
     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) 


     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 var_states(self): #this is supposed to send code to run plot() again but it doesnt do it 
     print (self.combobox.get()) 
     print (self.colr) 
     self.plot() 


    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) 

     values = ['jet', 'rainbow', 'ocean', 'hot', 'cubehelix','gnuplot','terrain','prism', 'pink'] 
     button1 = tk.Button(self, text="Back to Home", 
          command=lambda: controller.show_frame(StartPage)) 
     button1.pack() 

     button2 = tk.Button(self, text="Re-Render", 
          command=self.plot) 
     button2.pack() 
     self.mvar = tk.IntVar() 
     self.cbutton = tk.Checkbutton(self, text="shadow",onvalue=0, offvalue=1, variable=self.mvar) 
     self.cbutton.pack() 

     self.combobox = ttk.Combobox(self, values=values) 
     self.combobox.current(0) 
     self.combobox.pack(side = tk.TOP) 

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

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

     self.plot() 

    def plot (self): 
     colr = self.combobox.get() 
     print (colr) 
     self.ax.clear() 
     mandelbrot_image(self.ax, -0.8,-0.7,0,0.1,cmap=colr) 
     self.canvas.draw() 


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

你是上帝。感謝您再次幫助我,我誠實地仍然會被一個沒有您的幾個按鈕的tkinter窗口卡住。有了這個幫助,我應該可以完成一些我需要添加的東西,然後完成這個程序(我將把它放在我的github上,以及我未來的python項目,現在可以感謝你了)你的幫助肯定有幫助幫助我在matplotlib,tkinter和Python中獲得更好的理解。我不能要求更好的資產/導師。 (感謝您直接寫這段代碼) – Simon

+0

您可以通過[upvoting](http://meta.stackexchange.com/questions/173399/how-to-upvote-on-stack-overflow)來顯示您的感謝問題和在嘗試解決問題時對您有用的答案,當然包括您自己的問題的答案。請注意,SO不是一種代碼編寫服務,您不能總是找到有時間回答這些問題的人。對於未來,我建議(重新)閱讀[問]以及如何提供[mcve]。創建這樣的最小示例還將幫助您自己找到解決方案。 – ImportanceOfBeingErnest

+0

謝謝,下次我會問我會縮短我的代碼。我也提出了你的答案,但是因爲我有不到15的聲望,他們沒有公開展示(然而他們應該被記錄下來)。 – Simon