0

I am trying to embed a matplotlib window inside a tkinter GUI, but I am having trouble getting the "slider" widget to show up. In fact, the code below does show an embedded image, but the image itself is behaving like a slider, if you click on it!

I have tried using the ideas from this question

Placing plot on Tkinter main window in Python

import matplotlib
matplotlib.use('TkAgg')
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from matplotlib.widgets import Slider
import Tkinter as tk


class Embed:

    def __init__(self, root):

        self.root = root
        self.plot = Plotting(self.root)
        self.a = np.array([[1,2,3],[2,3,4],[3,4,5]])
        self.b = np.array([[1,2,3],[4,5,6],[7,8,9]])
        self.ctuple = (self.a,self.b)
        self.cube = np.dstack(self.ctuple)
        self.button = tk.Button(root, text="check", command=lambda: self.plot.plot(self.cube))
        self.button.pack()

class Plotting:

    def __init__(self, root):

        self.root = root

    def plot(self, cube, axis=2, **kwargs):

        fig = Figure(figsize=(6,6))
        ax = fig.add_subplot(111)
        s = [slice(0,1) if i == axis else slice(None) for i in xrange(3)]
        im = cube[s].squeeze()

        l = ax.imshow(im, **kwargs)
        canvas = FigureCanvasTkAgg(fig, self.root)
        canvas.get_tk_widget().pack()
        canvas.draw()
        slider = Slider(ax, 'Axis %i index' % axis, 0, cube.shape[axis] - 1,
                    valinit=0, valfmt='%i')

        def update(val):
            ind = int(slider.val)
            s = [slice(ind, ind + 1) if i == axis else slice(None)
             for i in xrange(3)]
            im = cube[s].squeeze()
            l.set_data(im, **kwargs)
            canvas.draw()

        slider.on_changed(update)

if __name__ == '__main__':

    root = tk.Tk()
    app = Embed(root)
    root.mainloop()
    root.destroy()

any help is much appreciated!

Community
  • 1
  • 1
jm22b
  • 377
  • 1
  • 3
  • 16

1 Answers1

0

I don't know what your code does. I tried to change it as little as I can:

import matplotlib
matplotlib.use('TkAgg')
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import Tkinter as Tk
import matplotlib.pyplot as plt


class Embed:

    def __init__(self, root_):
        self.root = root_
        self.a = np.array([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
        self.b = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
        self.c = np.array([[1, 4, 7], [4, 7, 10], [7, 10, 13]])
        self.ctuple = (self.a, self.b)
        self.cube = np.dstack(self.ctuple)
        self.cube = np.dstack([self.cube, self.c])
        self.plot = Plotting(self.root, self.cube)
        self.button = Tk.Button(root, text="check", command=lambda: self.plot.plot())
        self.button.pack()


class Plotting:
    def __init__(self, root, cube):
        self.root = root
        self.fig = Figure(figsize=(6, 6))
        self.ax = self.fig.add_subplot(111)
        self.cube = cube
        self.slider = Tk.Scale(
            self.root, from_=0, to=cube.shape[2] - 1, resolution=0.01, orient=Tk.HORIZONTAL, command=self.update
        )
        # self.slider.on_changed(self.update)
        self.slider.pack()
        self.plotted = False
        self.l = None
        self.canvas = None
        plt.show()

    def plot(self, **kwargs):
        self.plotted = True
        s = [slice(0, 1) if i == 2 else slice(None) for i in xrange(3)]
        im = self.cube[s].squeeze()
        self.l = self.ax.imshow(im, **kwargs)
        self.canvas = FigureCanvasTkAgg(self.fig, self.root)
        self.canvas.get_tk_widget().pack()
        self.canvas.draw()

    def update(self, val):
        ind = int(self.slider.get())
        s = [slice(ind, ind + 1) if i == 2 else slice(None) for i in xrange(3)]
        if self.plotted:
            im = self.cube[s].squeeze()
            self.l.set_data(im)
            self.canvas.draw()


if __name__ == '__main__':
    root = Tk.Tk()
    app = Embed(root)
    root.mainloop()
    root.destroy()
Ophir Carmi
  • 2,701
  • 1
  • 23
  • 42
  • Thank you for the response, I am trying to embed a mpl window in my tkinter gui that uses a slider to move through a 3d array. This code illustrates what I would like to embed http://pastebin.com/AxnUZ7EJ That produces a new window upon a button click, with a slider bar to scroll through the arrays. There's just two dummy arrays at the moment – jm22b Aug 01 '16 at 08:07
  • so what is the problem? http://pastebin.com/AxnUZ7EJ is working for me. did you check my code? – Ophir Carmi Aug 01 '16 at 08:42
  • My apologies, I did check your code and thought that it didn't show a slider, but upon checking again I can see that it does. Not sure what I did the first time... Thank you for your help What is the significance of the underscore in "root_" ? – jm22b Aug 01 '16 at 08:50
  • I use PyCharm IDE. I recommend it (community version). It has a feature of inspection of the code. When you write the same variable name for global `root = Tk.Tk()` and inside the function, PyCharm says that it can shadow the global. Underscore after the name says it's "private" or inner variable. see: https://www.python.org/dev/peps/pep-0008/#descriptive-naming-styles – Ophir Carmi Aug 01 '16 at 08:56