I'm working on writing a script that will run through data and create a graph. That is easy and done. Unfortunately the graphing modules I am using only create the graphs in a pdf format. I would like to have the graphs displayed in an interactive window, though.
Is their any way to either add a graph created with PyX into a TKinter window or load the pdf into a frame or something?
You need to convert the PyX output into a bitmap to include it in your Tkinter application. While there is no convenience method to get the PyX output as a PIL image directly, you can use the pipeGS method to prepare the bitmap and load it using the PIL. Here comes a rather minimal example:
import tempfile, os
from pyx import *
import Tkinter
import Image, ImageTk
# first we create some pyx graphics
c = canvas.canvas()
c.text(0, 0, "Hello, world!")
c.stroke(path.line(0, 0, 2, 0))
# now we use pipeGS (ghostscript) to create a bitmap graphics
fd, fname = tempfile.mkstemp()
f = os.fdopen(fd, "wb")
f.close()
c.pipeGS(fname, device="pngalpha", resolution=100)
# and load with PIL
i = Image.open(fname)
i.load()
# now we can already remove the temporary file
os.unlink(fname)
# finally we can use this image in Tkinter
root = Tkinter.Tk()
root.geometry('%dx%d' % (i.size[0],i.size[1]))
tkpi = ImageTk.PhotoImage(i)
label_image = Tkinter.Label(root, image=tkpi)
label_image.place(x=0,y=0,width=i.size[0],height=i.size[1])
root.mainloop()
Related
With the following code I want to display images from a relative path .\Datasets\image_datasets\problem_datasets within my project, I am unable to do so with tkinter, Instead it displays all the images in same UI window, I want these images to be displayed like a stream of frames as a video, can you help me understand why I don't get the expected ouput.
code :
import tkinter as tk
from PIL import ImageTk, Image
from matplotlib import image
from numpy import imag
import matplotlib.pyplot as plt
import glob
root = tk.Tk()
root.title("Test app")
images = [file for file in glob.glob('.\\Datasets\\image_datasets\\problem_datasets\\*.jpg')]
for path in images:
img = ImageTk.PhotoImage(Image.open(path))
lab = tk.Label(root,image=img)
lab.photo = img
lab.pack()
root.mainloop()
A couple of points:
you dont need lab.photo = img
you need to define and pack the label outside of your loop and just overwrite the image property inside, otherwise you create new labels each iteration
i recommend using os.sep instead of hardcoded folder separators \\ to be OS-independent
to actually see the transition, you need time.sleep or similar
my example will freeze the GUI, if you want it to be reactive after launching your image-transitions/"video", you will have to implement Threads
import tkinter as tk
from PIL import ImageTk, Image
from matplotlib import image
from numpy import imag
import matplotlib.pyplot as plt
import glob
import os
import time
root = tk.Tk()
root.title("Test app")
images = [file for file in glob.glob('.' + os.sep + 'Datasets' + os.sep + 'image_datasets' + os.sep + 'problem_datasets' + os.sep + '*.jpg')]
lab = tk.Label(root)
lab.pack()
for path in images:
_img = ImageTk.PhotoImage(Image.open(path))
lab.config(image=_img)
root.update() # to update the GUI
time.sleep(0.25) # to see the transition
root.mainloop()
You created new label in each iteration of the for loop. Instead you should create the label once before the for loop and update its image inside it.
However using loop and time.sleep() is not recommended in a tkinter application, suggest to use .after() instead:
import tkinter as tk
from PIL import ImageTk, Image
import glob
root = tk.Tk()
root.title("Test app")
images = glob.glob('./Datasets/image_datasets/problem_datasets/*.jpg')
# create the label for showing the images
lab = tk.Label(root)
lab.pack()
def show_image(i=0):
if i < len(images):
img = ImageTk.PhotoImage(file=images[i])
# update image
lab.config(image=img)
lab.photo = img # save reference of image to avoid garbage collection
# can change 10(ms) to other value to suit your case
root.after(10, show_image, i+1)
show_image() # start showing the images
root.mainloop()
from tkinter import *
from PIL import Image, ImageTk
import glob, os
root = Tk()
root.geometry("800x600")
# Function to display image
def displayImg(img):
image = Image.open(img)
photo = ImageTk.PhotoImage(image)
newPhoto_label = Label(image=photo)
newPhoto_label.pack()
# gta_images = []
os.chdir("gta")
for file in glob.glob("*.jpg"):
# gta_images.append(str(file))
displayImg(file)
print(file)
# print(gta_images)
root.mainloop()
I am trying to load images from a folder called "gta" and then display those game logos on my app. Program has no error but I think its a logical error. I am new to Python I don't know maybe there is some scoping logic problem in my displayImg funcion.
Note: When a PhotoImage object is garbage-collected by Python (e.g.
when you return from a function which stored an image in a local
variable), the image is cleared even if it’s being displayed by a
Tkinter widget.
For more.
from tkinter import *
from PIL import Image, ImageTk
import glob, os
root = Tk()
root.geometry("800x600")
photos = []
def displayImg(img):
image = Image.open(img)
photo = ImageTk.PhotoImage(image)
photos.append(photo)#keep references!
newPhoto_label = Label(image=photo)
newPhoto_label.pack()
for file in glob.glob("*.jpg"):
displayImg(file)
print(file)
root.mainloop()
Not sure if it will work but try using the path of the gta folder you are getting the images from, instead of its name simply - replace the name with the path.
I am trying to pass the path of an image and then opening it but i get this error for this line image = Image.open(path):
AttributeError: type object 'Image' has no attribute 'open'
from PIL import Image
from tkinter import *
class Menu:
def __init__(self,root):
self.root = root
self.root.title("Image")
self.image_entry = Entry(root)
self.image_entry.grid(row=0,column=1)
image_label = Label(root,text = "Enter the path of the image").grid(row=0)
images = Button(root,text="Show",command=lambda:[self.show(self.image_entry)]).grid(row=1,column=1)
root.mainloop()
def show(self,image_entry):
path=image_entry.get()
image = Image.open(path)
image.show()
The variable Image imported from PIL is being overwritten by the variable Image imported from Tkinter.
Possible solutions, in descending order of best-practice-ness:
Don't import things from tkinter using import *. Try importing only the names you need, for example from tkinter import Entry, Label, Button, Tk.
Choose an alias for PIL's Image that doesn't conflict with Tkinter's Image. For example, from PIL import Image as PILImage.
Switch the order of your imports so PIL's Image overwrites Tkinter's Image, instead of the other way around.
I have an image that is saved in a file test.bmp and this file is overwritten 2 times per second
(I want to show 2 images per second).
Here is what I have so far:
import tkinter as tk
from PIL import Image, ImageTk
root = tk.Tk()
img_path = 'test.bmp'
img = ImageTk.PhotoImage(Image.open(img_path), Image.ANTIALIAS))
canvas = tk.Canvas(root, height=400, width=400)
canvas.create_image(200, 200, image=img)
canvas.pack()
root.mainloop()
But I don't know how can I refresh the image every ½ second?
I'm using Python3 and Tkinter.
Gee, the code in your question looks very familiar...
Coming up with an answer comprised of tested code was complicated by the need to have the image file be updated by some mysterious unspecified process. This is done in the code below by creating a separate thread that periodically overwrites the image file independent of the main process. I tried to delineate this code from the rest with comments because I felt it was somewhat distracting and makes things seem more complex than they are really.
The main takeaway is that you'll need to use the universal tkinter widget after() method to schedule the image to be refreshed at some future time. Care also needs to be taken to first create a place-holder canvas image object so it can be updated in-place later. This is needed because there may be other canvas objects present, and otherwise the updated image could cover them up depending on relative placement if a place-holder had not been created (so the image object id that's returned can be saved and used later to change it).
from PIL import Image, ImageTk
import tkinter as tk
#------------------------------------------------------------------------------
# Code to simulate background process periodically updating the image file.
# Note:
# It's important that this code *not* interact directly with tkinter
# stuff in the main process since it doesn't support multi-threading.
import itertools
import os
import shutil
import threading
import time
def update_image_file(dst):
""" Overwrite (or create) destination file by copying successive image
files to the destination path. Runs indefinitely.
"""
TEST_IMAGES = 'test_image1.png', 'test_image2.png', 'test_image3.png'
for src in itertools.cycle(TEST_IMAGES):
shutil.copy(src, dst)
time.sleep(.5) # pause between updates
#------------------------------------------------------------------------------
def refresh_image(canvas, img, image_path, image_id):
try:
pil_img = Image.open(image_path).resize((400,400), Image.ANTIALIAS)
img = ImageTk.PhotoImage(pil_img)
canvas.itemconfigure(image_id, image=img)
except IOError: # missing or corrupt image file
img = None
# repeat every half sec
canvas.after(500, refresh_image, canvas, img, image_path, image_id)
root = tk.Tk()
image_path = 'test.png'
#------------------------------------------------------------------------------
# More code to simulate background process periodically updating the image file.
th = threading.Thread(target=update_image_file, args=(image_path,))
th.daemon = True # terminates whenever main thread does
th.start()
while not os.path.exists(image_path): # let it run until image file exists
time.sleep(.1)
#------------------------------------------------------------------------------
canvas = tk.Canvas(root, height=400, width=400)
img = None # initially only need a canvas image place-holder
image_id = canvas.create_image(200, 200, image=img)
canvas.pack()
refresh_image(canvas, img, image_path, image_id)
root.mainloop()
I have several images which I would like to show the user with Python. The user should enter some description and then the next image should be shown.
This is my code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, glob
from PIL import Image
path = '/home/moose/my/path/'
for infile in glob.glob( os.path.join(path, '*.png') ):
im = Image.open(infile)
im.show()
value = raw_input("Description: ")
# store and do some other stuff. Now the image-window should get closed
It is working, but the user has to close the image himself. Could I get python to close the image after the description has been entered?
I don't need PIL. If you have another idea with another library / bash-program (with subprocess), it'll be also fine.
psutil can get the pid of the display process created by im.show() and kill the process with that pid on every operating system:
import time
import psutil
from PIL import Image
# open and show image
im = Image.open('myImageFile.jpg')
im.show()
# display image for 10 seconds
time.sleep(10)
# hide image
for proc in psutil.process_iter():
if proc.name() == "display":
proc.kill()
The show method "is mainly intended for debugging purposes" and spawns an external process for which you don't get a handle, so you can't kill it in a proper way.
With PIL, you may want to use one of its GUI modules , such as ImageTk, ImageQt or ImageWin.
Otherwise, just manually spawn an image viewer from Python with the subprocess module:
for infile in glob.glob( os.path.join(path, '*.png')):
viewer = subprocess.Popen(['some_viewer', infile])
viewer.terminate()
viewer.kill() # make sure the viewer is gone; not needed on Windows
I've modified this recipe before to do some image work in Python. It uses Tkinter, so it doesn't require any modules besides PIL.
'''This will simply go through each file in the current directory and
try to display it. If the file is not an image then it will be skipped.
Click on the image display window to go to the next image.
Noah Spurrier 2007'''
import os, sys
import Tkinter
import Image, ImageTk
def button_click_exit_mainloop (event):
event.widget.quit() # this will cause mainloop to unblock.
root = Tkinter.Tk()
root.bind("<Button>", button_click_exit_mainloop)
root.geometry('+%d+%d' % (100,100))
dirlist = os.listdir('.')
old_label_image = None
for f in dirlist:
try:
image1 = Image.open(f)
root.geometry('%dx%d' % (image1.size[0],image1.size[1]))
tkpi = ImageTk.PhotoImage(image1)
label_image = Tkinter.Label(root, image=tkpi)
label_image.place(x=0,y=0,width=image1.size[0],height=image1.size[1])
root.title(f)
if old_label_image is not None:
old_label_image.destroy()
old_label_image = label_image
root.mainloop() # wait until user clicks the window
except Exception, e:
# This is used to skip anything not an image.
# Warning, this will hide other errors as well.
pass