##// END OF EJS Templates
Added GTK support to ZeroMQ kernel....
Added GTK support to ZeroMQ kernel. We use an approach which is a combination of an gtk timer callback into our execution loop, like we do for Qt and Wx, I've run as tests several GTK examples found on the net, as well as multiple matplotlib scripts, and so far everything works as expected. The only catch is that we silently trap gtk.main_quit(), so examples that call it with a 'close' button or similar seem to not do anything. But their windows close normally and no other problems have been found. This solution uses code taken from an old bug report of ours: https://bugs.launchpad.net/ipython/+bug/270856 specifically the attachment in this comment: https://bugs.launchpad.net/ipython/+bug/270856/comments/6 along with the changes suggested by Michiel de Hoon there. Thanks to Ville and Michiel for that old discussion, which put me on the right track to figure out the details of the logic needed for GTK.

File last commit:

r2918:d0abfbea
r2949:13751b1c
Show More
pylabtools.py
182 lines | 5.9 KiB | text/x-python | PythonLexer
# -*- coding: utf-8 -*-
"""Pylab (matplotlib) support utilities.
Authors
-------
* Fernando Perez.
* Brian Granger
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2009 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from IPython.utils.decorators import flag_calls
#-----------------------------------------------------------------------------
# Main classes and functions
#-----------------------------------------------------------------------------
def find_gui_and_backend(gui=None):
"""Given a gui string return the gui and mpl backend.
Parameters
----------
gui : str
Can be one of ('tk','gtk','wx','qt','qt4','payload-svg').
Returns
-------
A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_payload_svg').
"""
import matplotlib
# If user specifies a GUI, that dictates the backend, otherwise we read the
# user's mpl default from the mpl rc structure
g2b = {'tk': 'TkAgg',
'gtk': 'GTKAgg',
'wx': 'WXAgg',
'qt': 'Qt4Agg', # qt3 not supported
'qt4': 'Qt4Agg',
'payload-svg' : \
'module://IPython.zmq.pylab.backend_payload_svg'}
if gui:
# select backend based on requested gui
backend = g2b[gui]
else:
backend = matplotlib.rcParams['backend']
# In this case, we need to find what the appropriate gui selection call
# should be for IPython, so we can activate inputhook accordingly
b2g = dict(zip(g2b.values(),g2b.keys()))
gui = b2g.get(backend, None)
return gui, backend
def activate_matplotlib(backend):
"""Activate the given backend and set interactive to True."""
import matplotlib
if backend.startswith('module://'):
# Work around bug in matplotlib: matplotlib.use converts the
# backend_id to lowercase even if a module name is specified!
matplotlib.rcParams['backend'] = backend
else:
matplotlib.use(backend)
matplotlib.interactive(True)
# This must be imported last in the matplotlib series, after
# backend/interactivity choices have been made
import matplotlib.pylab as pylab
# XXX For now leave this commented out, but depending on discussions with
# mpl-dev, we may be able to allow interactive switching...
#import matplotlib.pyplot
#matplotlib.pyplot.switch_backend(backend)
pylab.show._needmain = False
# We need to detect at runtime whether show() is called by the user.
# For this, we wrap it into a decorator which adds a 'called' flag.
pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
def import_pylab(user_ns, import_all=True):
"""Import the standard pylab symbols into user_ns."""
# Import numpy as np/pyplot as plt are conventions we're trying to
# somewhat standardize on. Making them available to users by default
# will greatly help this.
exec ("import numpy\n"
"import matplotlib\n"
"from matplotlib import pylab, mlab, pyplot\n"
"np = numpy\n"
"plt = pyplot\n"
) in user_ns
if import_all:
exec("from matplotlib.pylab import *\n"
"from numpy import *\n") in user_ns
def pylab_activate(user_ns, gui=None, import_all=True):
"""Activate pylab mode in the user's namespace.
Loads and initializes numpy, matplotlib and friends for interactive use.
Parameters
----------
user_ns : dict
Namespace where the imports will occur.
gui : optional, string
A valid gui name following the conventions of the %gui magic.
import_all : optional, boolean
If true, an 'import *' is done from numpy and pylab.
Returns
-------
The actual gui used (if not given as input, it was obtained from matplotlib
itself, and will be needed next to configure IPython's gui integration.
"""
gui, backend = find_gui_and_backend(gui)
activate_matplotlib(backend)
import_pylab(user_ns)
print """
Welcome to pylab, a matplotlib-based Python environment [backend: %s].
For more information, type 'help(pylab)'.""" % backend
return gui
# We need a little factory function here to create the closure where
# safe_execfile can live.
def mpl_runner(safe_execfile):
"""Factory to return a matplotlib-enabled runner for %run.
Parameters
----------
safe_execfile : function
This must be a function with the same interface as the
:meth:`safe_execfile` method of IPython.
Returns
-------
A function suitable for use as the ``runner`` argument of the %run magic
function.
"""
def mpl_execfile(fname,*where,**kw):
"""matplotlib-aware wrapper around safe_execfile.
Its interface is identical to that of the :func:`execfile` builtin.
This is ultimately a call to execfile(), but wrapped in safeties to
properly handle interactive rendering."""
import matplotlib
import matplotlib.pylab as pylab
#print '*** Matplotlib runner ***' # dbg
# turn off rendering until end of script
is_interactive = matplotlib.rcParams['interactive']
matplotlib.interactive(False)
safe_execfile(fname,*where,**kw)
matplotlib.interactive(is_interactive)
# make rendering call now, if the user tried to do it
if pylab.draw_if_interactive.called:
pylab.draw()
pylab.draw_if_interactive.called = False
return mpl_execfile