1

This is my first python project and I am trying to plot the Mandelbrot set in Matplotlib and place it into a tkinter frame. This has already been accomplished however a extraneous empty figure appears along with the GUI. This empty plot has the correct amount of tick marks while the plot in the GUI has the incorrect amount of tick marks on the plot (I cant figure out where the tick values are coming from either, but I suspect pixels). I have also searched for quite some time now on how to solve this problem to no avail. I have tried canvas.draw, messing with the methods and classes and I still cannot figure it out... The following is an excerpt of the code that will run. code specifying the display are in the method named mandelbrot_image and the MainPage class Thank you in advance.

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




LARGE_FONT= ("Verdana", 12)

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("The Mandelbrot set")
    norm = colors.PowerNorm(gamma)
    ax.imshow(z.T,cmap=cmap,origin='lower',norm=norm)


    return fig

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)

        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 getcheckvalue(self):
        print (self.mvar.get())

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




        fig = mandelbrot_image()
        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()
8
  • (not related to accepting answer) I was also wondering how I could add the standard toolbar to the plot. Like I tried adding it in but it only shows up in the extraneous matplotlib figure, not the plot in the GUI Commented Feb 28, 2017 at 12:07
  • Didn't already provide you with an answer which solved the problem of two figures appearing? What did you change in between? Commented Feb 28, 2017 at 18:44
  • The answer you provided inserted the plot into the tkinter canvas (which I am thankful for). The second figure accompanied the solution. Commented Feb 28, 2017 at 18:49
  • Are you saying that my previous answer did not solve the problem of two figures appearing? Commented Feb 28, 2017 at 18:56
  • no you did answer my previous question (which was how to embed a matplotlib plot into the tkinter canvas | thank you for the help) this is a different problem Commented Feb 28, 2017 at 19:00

1 Answer 1

1

So apparently a new figure is created because of a call to pyplot.xticks(). While this behaviour is not reproducible in python 2.7 and I'm uncertain about the reasons for it, a solution is to use the API commands of the axes:

ticks = np.arange(0,img_width,3*dpi)
x_ticks = xmin + (xmax-xmin)*ticks/img_width
y_ticks = ymin + (ymax-ymin)*ticks/img_width
ax.set_xticks(ticks)
ax.set_xticklabels(x_ticks)
ax.set_yticks(ticks)
ax.set_yticklabels(y_ticks)
ax.set_title("The Mandelbrot set")

In order to prevent further complications, it may be sensible to use the matplotlib API througout the code, getting rid of pyplot (plt) entirely.

Concering the Navigationbar, I was able to obtain it using the following inside the MainPage's __init__ function:

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

Note: In newer versions of matplotlib you should use NavigationToolbar2Tk instead of NavigationToolbar2TkAgg.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.