1

I am trying to do the following:

  1. Create plot with imshow() using matplotlib package, which gives matplotlib.image.AxesImage
  2. Convert matplotlib.image.AxesImage to PIL.ImageTk.PhotoImage
  3. Use this PIL.ImageTk.PhotoImage as image on TkInter canvas

How can I accomplish the above without saving any image?

After referring a post I tried to directly color code my data with the following code:

from Tkinter import *
from PIL import ImageTk,Image
import numpy as np
from pylab import cm
root=Tk()
canvas = Canvas(root)
canvas.pack(expand = YES, fill = BOTH)    
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
myarray = np.sin(x) + np.cos(y)
image1 = Image.fromarray(np.uint8(cm.gist_earth(myarray)*255))
test = canvas.create_image(10,10,image = image1)
#canvas.itemconfig(test, image=nextimage)    
mainloop()

The above code gives the error

TclError: image "<PIL.Image.Image image mode=RGBA size=120x100 at 0x2DC01E8>" doesn't exist

What might be the problem?

Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
lokesh
  • 329
  • 1
  • 8
  • 18
  • -Could you avoid step 2 and 3 and directly use fig in canvas Tkinter? see [link1](http://stackoverflow.com/questions/12930143/matplotlib-plot-in-tkinter-every-update-adds-new-navigationtoolbar) -Else you can redirect output from savefig into a buffer, see:[link2](http://stackoverflow.com/questions/14869321/is-there-a-way-to-convert-pyplot-imshow-object-to-numpy-array) – Katsu Aug 31 '13 at 13:04
  • @Katsu Please refer my update – lokesh Aug 31 '13 at 13:49

1 Answers1

1

You have to create and empty ImageTk.PhotoImage instance, and then paste the content from your Image instance there.

If you are reading from an AxesImage object (returned by imshow), you can transfer its data to Image first, then paste to PhotoImage.

Here is an example (note that you actually need to compute myarray over a meshgrid):

from Tkinter import *
from PIL import Image, ImageTk
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
root=Tk()
canvas = Canvas(root)
canvas.pack(expand = YES, fill = BOTH)
x = np.linspace(0, 2*np.pi, 400)
y = np.linspace(0, 2*np.pi, 400)
X, Y = np.meshgrid(x, y, copy=False)
myarray = np.cos(X) + np.cos(Y)

im_plt = plt.imshow(myarray)

image1 = Image.fromarray(np.uint8( im_plt.get_cmap()(im_plt.get_array())*255))
im = ImageTk.PhotoImage('RGB', image1.size)
im.paste(image1)
test = canvas.create_image(0, 0, image=im)
mainloop()

Which will result in something like:

enter image description here

Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
  • Can i paste matplotlib.image.AxesImage generated by imshow on this PhotoImage as well? – lokesh Aug 31 '13 at 14:32
  • i can able to do that by using BytesIO like this `buf = io.BytesIO() plt.savefig(buf, format = 'png') buf.seek(0) image11 = Image.open(buf) im = ImageTk.PhotoImage('RGBA',(120,100)) im.paste(image11)` is there a way to paste directly?? – lokesh Aug 31 '13 at 14:43
  • @lokesh I've updated the answer... it is possible to pass directly the content from `imshow` to `Image`, then paste to `PhotoImage` – Saullo G. P. Castro Aug 31 '13 at 14:50
  • @lokesh I haven't played enough to tell you now... but I believe there is a shortcut in order to avoid this – Saullo G. P. Castro Aug 31 '13 at 14:59
  • the result is not matching. PhotoImage is different and imshow plot is different try to plot separately check the difference – lokesh Sep 01 '13 at 09:28
  • where the difference is coming? – lokesh Sep 01 '13 at 09:28