tk windows in Jupyter - python

I'm trying to get a tk window to display inline in Jupyter -- similar to the effect that %matplotlib inline has, but for a non-matplotlib tk window. Specifically, I'm trying to get graphics.py windows to display inline. Here would be a minimal working example:
# Some kind of replacement for %matplotlib inline:
%gui tk # <--- doesn't solve the problem, only connects the event loops?
# minimal graphics.py working example:
from graphics import *
c = Circle(Point(50,50), 10)
c.draw(win)
win.getMouse() # Pause to view result
win.close() # Close window when done
Is this possible/feasible? If it's not already implemented, is this something I could attempt to make myself?

Related

Disable pyqtgraph plot window

As a continuation of this question of mine:
pyqtgraph for plotting multiple data lists
I managed to use pyqtgraph to export my plot to a file. But i still get the window that pyqtgraph spawns in order to try to create the plot there. This window now shows nothing, it is empty and white. When i use regular python console, after a while this window disappears, but if i use Ipython, the window says "Not responding" and when i close it Ipython says "Kernel died, restarting".
Is there a way to completely disable this pyqtgraph window and only use the output file to create the plot, in order for it to work correctly without errors?
I used to do this with matplotlib (which had the same window popping up, but if you used command matplotlib.use('Agg'), to change the backend, then the window stopped popping.
Oh my... i just figured it out! My first answer on SO, don't be too harsh on me.
First, make sure you are creating your pyqtgraph graph in a constructor(init function) of a class. Call it there once and immediately hide it (that was the complicated part for me).
Here is an example code:
import numpy as np
import pyqtgraph as pg
import pyqtgraph.exporters
class MyPlotClass():
def __init__(self):
self.windowplt = pg.plot()
self.windowplt.win.hide()
def savePlots(self):
x = np.arange(0, 256)
y = np.arange(0, 256)
self.windowplt.plot(x, y)
exporter = pg.exporters.ImageExporter(self.windowplt.plotItem)
exporter.params.param('width').setValue(256, blockSignal=exporter.widthChanged)
exporter.params.param('height').setValue(256, blockSignal=exporter.heightChanged)
for i in np.arange(0,10):
exporter.export('./fileName' + str(i) + '.png')
print(i)
if __name__ == "__main__":
saveMyFiles = MyPlotClass()
saveMyFiles.savePlots()
Only one window WILL appear for a shot duration and hide itself immediately.
I know your Question is old, but it might help anyone in the future. I was searching for the solution for the whole day now.
As mentioned in your previous thread pyqtgraph for plotting multiple data lists the ImageExporter.py bug still exists. Insted of changing the code of the pyqtgraph library you can work around it by setting both width and height yourself (as in the code above).
exporter.params.param('width').setValue(256, blockSignal=exporter.widthChanged)
exporter.params.param('height').setValue(256, blockSignal=exporter.heightChanged)

Repeated dialog window with Tkinter and Matplotlib on Mac OS X

I'm newbie in Tkinter. I try to use next code to open a file using tkFileDialog.askopenfilename and then plot something with Matplotlib:
import matplotlib.pyplot as plt
import Tkinter, tkFileDialog
root = Tkinter.Tk()
root.withdraw()
file_path = tkFileDialog.askopenfilename()
x = range(10)
plt.plot(x)
plt.show()
After running the above script I get dialog window to open my file. After file selection I get repeated dialog window to open the file and a new window at the bottom of my screen. I know that the problem is because of plt.show(). What happens and how to avoid dialog window reopening? Should I set a Matplotlib backend for my task?
My versions:
Tcl/Tk 8.5.9
Matplotlib 1.3.1
Tkinter $Revision: 81008 $
OS X 10.9.4
I have found two related stackoverflow questions:
pyplot-show-reopens-old-tkinter-dialog and
matplotlib-figures-not-working-after-tkinter-file-dialog
but no answers. It seems that root.destroy() is not working for me.
When run with python test.py, the following seems to work for me:
import matplotlib.pyplot as plt
import Tkinter, tkFileDialog
root = Tkinter.Tk()
root.withdraw()
file_path = tkFileDialog.askopenfilename()
root.destroy()
print file_path
x = range(10)
plt.plot(x)
plt.show()
I think it works because the Tk instance for the file dialog is destroyed before matplotlib fires up its own. Interestingly, it also works for me when run from
ipython --pylab=tk
where I would have expected a problem with starting the event loop twice. The canonical solution in this case would be to check if Tk is already running before firing it up (again).
I'm on MacOSX 10.7.5, custom built matplotlib (shouldn't matter).
The only thing I noticed was that after experimenting with this, the touchpad swipe gestures on my Mac no longer work... Looking into this.
Edit
Here is a breakdown of the Tk commands executed by tkFileDialog.askopenfilename():
# breakdown of tkFileDialog.askopenfilename()
import Tkinter as Tk
window = Tk.Tk()
window.withdraw()
w = Tk.Frame(window)
s = w.tk.call('tk_getOpenFile', *w._options({}))
print s
w.destroy()
window.destroy()
When I run this (with python test.py), I get the file open dialog, where I can choose a file. Upon "OK" it prints the file name and exits. This works every time on my system. However, sometimes the 3-finger gestures on my touchpad stop working while running this program! And they don't come back after the program exits!! Not even after I kill the terminal the program was running in!!!
The only way I found to bring them back is to add the following matplotlib code to test.py:
import matplotlib
matplotlib.use('tkagg')
import matplotlib.pyplot as plt
plt.figure() # simplified from plt.plot(range(10))
plt.show()
and then click on the title bar of "Figure 1". This instantly brings back the 3-finger gestures. I suspect this is simply a bug in Tkinter. (I'm on Tcl/Tk 8.5, by the way)
I cannot reproduce the behavior that the file open dialog is constantly relaunched on my system.
Could you please describe what happens on your system if you launch test.py, without any matplotlib commands?
Alternatively, since Tkinter is old and apparently buggy, may I suggest to use Qt instead? Not only does it look much nicer, it is also snappier and I didn't have any problems with bugs.
Edit 2
I have broken down the Tk actions that matplotlib takes when executing the above commands in a non-interactive environment (i.e. with python test.py and not from iPython). These are the essential backend calls:
import matplotlib.backends.backend_tkagg as backend
figManager = backend.new_figure_manager(1)
figManager.show()
backend.show.mainloop()
These are still backend independent. I.e., for a Qt figure, simply use:
import matplotlib.backends.backend_qt4agg as backend
If we break this down further to the backend-specific layer, we have:
import matplotlib.backends.backend_tkagg as backend
import Tkinter as Tk
window = Tk.Tk()
window.withdraw()
# uncomment this to use the same Tk instance for tkFileDialog and matplotlib
#import tkFileDialog
#fname = tkFileDialog.askopenfilename(master=window)
#print fname
# figManager = backend.new_figure_manager(1)
from matplotlib.figure import Figure
figure = Figure()
canvas = backend.FigureCanvasTkAgg(figure, master=window)
figManager = backend.FigureManagerTkAgg(canvas, 1, window)
# figManager.show()
window.deiconify()
# backend.show.mainloop()
Tk.mainloop()
First, run with the tkFileDialog calls commented out and check if the matplotlib figure appears and behaves correctly. Then uncomment the tkFileDialog calls and see if you finally get the expected behavior.
If not, one has to continue breaking down FigureCanvasTkAgg and FigureManagerTkAgg to understand what is going on...
Edit 3
OK, since the problem persisted, let's break down matplotlib's Tk calls even further. The following code completely isolates all of matplotlib's Tk actions that I consider essential (so it is no longer necessary to import anything from matplotlib!). Note that I left out generating the toolbar and assigning lots of callbacks and keypress events. If the code below works now, then the problem lies with these. If it doesn't work, we can conclude that it is purely a Tk problem, and most likely a bug that should be reported. Here is the code:
import Tkinter as Tk
window = Tk.Tk()
window.withdraw()
# uncomment this to use the same Tk instance for tkFileDialog and matplotlib
#w = Tk.Frame(window)
#fname = w.tk.call('tk_getOpenFile', *w._options({}))
#print fname
#w.destroy()
# canvas = backend.FigureCanvasTkAgg(figure, master=window)
_tkcanvas = Tk.Canvas(master=window, width=640, height=480, borderwidth=4)
_tkphoto = Tk.PhotoImage(master=_tkcanvas, width=640, height=480)
_tkcanvas.create_image(320, 240, image=_tkphoto)
_tkcanvas.focus_set()
# figManager = backend.FigureManagerTkAgg(canvas, 1, window)
window.wm_title("Figure 1")
window.minsize(480, 360)
_tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
# figManager.show()
window.deiconify()
# backend.show.mainloop()
Tk.mainloop()
Please play around with commenting out some lines and see if you can get it working correctly. If not, I would conclude that this is a bug in Tkinter, which should be reported.

Tkinter / pylab conflict?

I'm very new to Python but have started writing a few small scripts this week. I'm currently trying to write a simple program to plot some data. I'd like to do the following:
ask the user to choose the data directory using a GUI
for each file in the directory, make a plot
close each plot with a mouse click and advance to the next plot
I've mostly gotten the program to work - I can choose the directory using tkFileDialog.askdirectory, then read in the data, make the plots and advance though them using a mouse click.
My problem is with the TK root window that opens with the tkFileDialog. If I use withdraw() the extra window doesn't open, but only the first plot will appear (a mouse click closes that plot but doesn't show the next one). If I don't use withdraw(), the extra window must be manually closed after the first plot to advance to the second.
I'm wondering if there is a way to choose the directory that will avoid displaying the extra window?
I'm attaching some sample code to show my thought process. This doesn't call the actual data but still reproduces the problem (you'll need to change the .D to some file type that you have in a directory):
import numpy as np
from pylab import *
import glob
import os
import Tkinter, tkFileDialog
##################################################
#define the mouse click event
##################################################
def moveon(event):
close()
##################################################
#ask for the directory
##################################################
root = Tkinter.Tk()
#root.withdraw()
direc = tkFileDialog.askdirectory(parent=root,initialdir="/",title='Please select a directory')
os.chdir(direc)
for files in glob.glob("*.D*"):
##################################################
#Read in the data
##################################################
#assume this reads x and y from each file
x = [1, 2]
y = [3, 4]
##################################################
#loop though the plots
##################################################
fig = figure(1)
plot(x,y)
cid = fig.canvas.mpl_connect('button_press_event',moveon)
show()
Since you don't seem to be using Tkinter after your file dialog, you could do root.destroy()
to close the Tk root window right after you have the user select a file.

Python Tkinter Flashing Standard Window

I am building an Interface with TKinter and I have the problem, that whenever create a new window the standardized tkinter window of 200x200 pixel with nothing in it flashes up for a fraction of a second and AFTER that all my modifications (widgets ect.) are made. This happens before AND after calling the mainloop.
The Main-Interface is created.
Mainloop stats
Flashing window
Main-Interface appears
Also after Mainloop was called this happens with newly created windows.
Main-Interface appears--> Push a button, that creates a new window
Flashing window
new window appears
Sadly I cannot give you a sample code... If I try to do a minimal example, this doesn't happen. Maybe the standard window is created, but it is changed so fast, that it doesn't appear on screen. I don't even know what to look up in this case... searching "tkinter flashing window" yields nothing.
EDIT: I found the source of the problem. It seems to be caused by wm_iconbitmap, FigureCanvasTkAgg and tkinter.Toplevel. If you remove the the icon out of the code, it works fine, no flashing. But if I use it together with one of the other, the window flashes when created. Try it out with the code below. You have to put the icon in the working directory of course.
Here is a code sample and the link to the icon I am using, but I suppose any icon will do.
# coding=utf-8
import numpy as np
import matplotlib as mpl
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
import os
class INTERFACE(object):
def __init__(self):
self.root = tk.Tk()
self.root.protocol("WM_DELETE_WINDOW", self.EXIT)
self.root.wm_iconbitmap( os.path.abspath("icon.ico")) #<---- !!!!!!
self.root.geometry("1024x768")
canvas = FigureCanvasTkAgg(self.testfigure(), master=self.root) #<---- !!!!!!
canvas.get_tk_widget().grid(sticky=tk.N+tk.W+tk.E+tk.S)
self.root.rowconfigure(0, weight=1)
self.root.columnconfigure(0, weight=1)
def testfigure(self):
x=np.linspace(0, 2*np.pi,100)
y=np.sin(x)
fig = mpl.figure.Figure()
sub = fig.add_subplot(111)
sub.plot(x,y)
return fig
def EXIT(self):
Top = tk.Toplevel(master=self.root)
Top.wm_iconbitmap( os.path.abspath("icon.ico")) #<---- !!!!!!
Top.transient(self.root)
Top.resizable(width=False, height=False)
Top.title("Exit")
tk.Message(Top,text="Do you really want to quit?", justify=tk.CENTER, width=300).grid(row=0,columnspan=3)
tk.Button(Top,text="YES",command=self.root.destroy).grid(row=1,column=0)
tk.Button(Top,text="No",command=self.root.destroy).grid(row=1,column=1)
tk.Button(Top,text="Maybe",command=self.root.destroy).grid(row=1,column=2)
def start(self):
self.root.mainloop()
if __name__ == '__main__':
INTERFACE().start()
I know this is an old question, but I've experienced a similar situation and have found a solution.
In my case, I've isolated the issue to the use of iconbitmap. I've managed to solve it by calling iconbitmap with the after method just before calling root.mainloop().
Example:
from tkinter import *
root = Tk()
w = Label(root, text="Hello, world!")
w.pack()
root.geometry('300x300+500+500')
root.after(50, root.iconbitmap('icon.ico'))
root.mainloop()
This method has worked on Toplevel() windows with icons as well.
Tested on Win 8.1 with Python 3.5.0.
Edit: Upon further inspection I've noticed that the behavior changes relative to root.geometry's presence as well. My initial example didn't have it and I only noticed after a few tries that it still had the same issue. The time delay in the after method doesn't seem to change anything.
Moving root.geometry below the after method yields the same issue for some reason.
Most likely, somewhere in your initialization code you're calling update or update_idletasks, which causes the current state of the GUI to be drawn on the screen.
Another possible source of the problem is if you're creating multiple instances of Tk rather than Toplevel.
Without seeing your code, though, all we can do is guess.
Your best route to solving this problem is to create a small example that has the same behavior. Not because we need it to help you, but because the effort you put into recreating the bug will likely teach you what is causing the bug.
This should work but it requires win32gui
import win32gui
def FlashMyWindow(title):
ID = win32gui.FindWindow(None, title)
win32gui.FlashWindow(ID,True)

Using TCL extensions to set native window style in Tkinter

pythonware.com/library/tkinter/introduction/…
documents a overrideredirect method
that will remove thetitlebar and
borders, if that is not enough you
must set the native window style, I'm
not sure if Tkinter gives you that
kind of low-level access, if not, try
the something like
twapi.magicsplat.com/ui.html#set_window_style
TCL extension
In an earlier post I got this as a reply on how to get a border in Tkinter similar to the one pictured below. I am not familiar with Tcl and it's extensions. So how would go about doing this? The end goal is basicaly to get the border below on a Tkinter window.
Edit :
I used the following on Windows 7 and it didn't seem to change the style. It's probably missing something. Any help would be appreciated, this could be really cool!
import string, win32ui, win32con
import Tkinter as tk
root = tk.Tk()
frame = win32ui.CreateWindowFromHandle(string.atoi(root.wm_frame(), 0))
frame.ModifyStyle(win32con.WS_CAPTION, 0, win32con.SWP_FRAMECHANGED)
root.mainloop()
You can do this using a combination of the Python win32 api packages and Tkinter. What you need to know is that a Tk window is the client section of a Win32 window. The window manager interactions are handled using a wrapper that is the parent of Tk window itself. If you have a Tkinter window 'w' then you can create a PyWin32 window for the frame or just manipulate it directly. You can get the frame hwnd using w.wm_frame() and parsing the hex string returned or by using GetParent on the winfo_id value from the Tk window (although wm_frame is likely to be more reliable).
import string, win32ui, win32con
from Tkinter import *
w = Tk()
frame = win32ui.CreateWindowFromHandle(string.atoi(w.wm_frame(), 0))
frame.ModifyStyle(win32con.WS_CAPTION, 0, win32con.SWP_FRAMECHANGED)
This removes the WS_CAPTION style and notifies the window that its frame is modified which forces a geometry recalculation so that the change propagates to the Tk child window.
EDIT ---
The following arranges to ensure we modify the window style after the window has been fully created and mapped to the display.
import string, win32ui, win32con
from Tkinter import *
def decaption(event):
w = event.widget
frame = win32ui.CreateWindowFromHandle(string.atoi(w.wm_frame(), 0))
frame.ModifyStyle(win32con.WS_CAPTION, 0, win32con.SWP_FRAMECHANGED)
w.bind("<Map>", None)
root = Tk()
root.bind("<Map>", decaption)
root.mainloop()
One solution is to draw your own border. Use overrideredirect to remove all decorations, grid/pack/place a canvas that fills the window, then draw or use bitmaps to get the visual effect you want. You'll have to add your own bindings for moving and resizing tne window, but that's not too difficult.

Categories

Resources