Search code examples
pythontkintermayavitkinter-canvasmayavi.mlab

Tkinter canvas containg a mayavi.mlab plot


I have been working on visualising a 3D plot generated using mayavi.mlab and then generating a GUI window using Tkinter to vary some parameters (2 to be exact) of my 3D plot. My problem is I cannot connect the canvas from Tkinter to host my mayavi plot. More specific: I have created a class for my 3D calculations and a class for the GUI.

import numpy as np
from mayavi import mlab
from Tkinter import *
import tkMessageBox as msg
class 3Dplot_calc:

    x,y,z = np.mgrid[-10:10:150j,-10:10:150j,-10:10:150j]

    def __init__(self, R, I):
      self.R = R
      self.I = I

There is a series of methods in between to help calculate the useful part

class GUI:    

    def __init__(self,master):    
        frame = Frame(master)
        frame.pack()
        self.Set_Figure(frame)
        self.Inputs(frame)

    def Set_Figure(self,frame):
        self.fig = mlab.figure(1, size=(500,500))
        ### i need to attach it to the canvas somehow and make it upgrade

Here is where I am stuck!!! GUI class goes on defining sliders for R and I ,some other buttons, a plot button and defining their place in the frame. The relevant parts are:

    def Inputs(self,frame):
        input_frame = Frame(frame)
        input_frame.grid(column=0, row=0)

        #Add Sliders
        self.slR = Scale(input_frame, from_=1.0, to=5.0, orient=HORIZONTAL)
        self.slR.set(1.0)

        self.slI = Scale(input_frame, from_=-5.0, to=5.0, orient=HORIZONTAL)
        self.slI.set(1.0)

        #Add Plot Button
        self.plot_button = Button(input_frame, text='PLOT', command = self.Generate_Values)

    def Generate_Values(self):    
        R = int(self.slR.get())
        I = float(self.slI.get())

        a = 3Dplot_calc(R,I)
        Bx,By,Bz = a.Bx, a.By, a.Bz #Those are the useful methods 
        field = mlab.pipeline.vector_field(Bx, By, Bz)
        magnitude = mlab.pipeline.extract_vector_norm(field)
        contours = mlab.pipeline.iso_surface(magnitude,contours=3)

        field_lines = mlab.pipeline.streamline(magnitude, seedtype='line',
                                    integration_direction='both')       
        self.canvas.show()
root = Tk()
gui = GUI(root)
root.mainloop() 

The 3Dplot class works fine on its own. The error that I get is: GUI instance has no attribute 'canvas'. I could edit the post and put my full code if it is needed.


Solution

  • I don't think that this is possible, for fundamental reasons. A program can only have one GUI backend running the event loop, and IIUC, current versions of Mayavi only support Qt (well) and Wx (somewhat) backends, not Tkinter. I would suggest using TraitsUI, with a Qt backend, to vary your parameters rather than TKinter. E.g. see http://docs.enthought.com/mayavi/mayavi/auto/example_mayavi_traits_ui.html