6

I am trying to update the data in a matplotlib imshow window within a Tkinter gui, an example of my code is as follows:

#minimal example...

import matplotlib, sys
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import pylab as plt
from scipy import ndimage

if sys.version_info[0] < 3:
    import Tkinter as Tk
else:
    import tkinter as Tk

root = Tk.Tk()
root.wm_title("minimal example")

image = plt.imread('test.jpg')
fig = plt.figure(figsize=(5,4))
im = plt.imshow(image) # later use a.set_data(new_data)
ax = plt.gca()
ax.set_xticklabels([]) 
ax.set_yticklabels([]) 

# a tk.DrawingArea
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

def rotate(*args):
    print 'rotate button press...'
    theta = 90
    rotated = ndimage.rotate(image, theta)
    im.set_data(rotated)
    root.update()

def quit(*args):
    print 'quit button press...'
    root.quit()     
    root.destroy() 

button_rotate = Tk.Button(master = root, text = 'Rotate', command = rotate)
button_quit = Tk.Button(master = root, text = 'Quit', command = quit)

button_quit.pack(side=Tk.LEFT)
button_rotate.pack()

Tk.mainloop()

As you can see, I load an image using imshow(), and then try updating the image's data using set_data(), and then want to update the root window of the gui using root.update(). When executed, the print 'rotate button press...' line is executed, but the rest is seemingly not. Do I need to pass the image handle to the rotate function some how, or return the rotated image?

not link
  • 858
  • 1
  • 16
  • 29

1 Answers1

3

The canvas needs to be redrawn, try this:

def rotate(*args):
    print 'rotate button press...'
    theta = 90
    rotated = ndimage.rotate(image, theta)
    im.set_data(rotated)
    canvas.draw()

Update to keep rotating

Note this is saving image as an attribute of root. Maybe not the best approach but it works for the example.

root = Tk.Tk()
root.wm_title("minimal example")

root.image = plt.imread('test.jpg')
fig = plt.figure(figsize=(5,4))
im = plt.imshow(root.image) # later use a.set_data(new_data)
ax = plt.gca()
ax.set_xticklabels([]) 
ax.set_yticklabels([])

# a tk.DrawingArea
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

def rotate(*args):
    print 'rotate button press...'
    root.image = ndimage.rotate(root.image, 90)
    im.set_data(root.image)
    canvas.draw()
Fiver
  • 9,909
  • 9
  • 43
  • 63
  • That seems to work, but only once. If I press the rotate button again, it doesn't seem to do anything. (Do I need to somehow save the new state of the image?) And on a potentially unrelated note, it seems to mirror the image, not rotate it 90 as desired. – not link Oct 26 '13 at 23:07
  • Yep, this is because you are always rotating the original `image` 90 degrees. I'll update with another fix, but you'd be better off refactoring to make your own subclass of Tkinter.Frame so you can save your application's attributes...but that's for another question. – Fiver Oct 26 '13 at 23:22
  • You should not import `pyplot` while embedding. – tacaswell Oct 27 '13 at 01:28