Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pylab import adjustments #3568

Merged
merged 13 commits into from
Jul 17, 2013
79 changes: 62 additions & 17 deletions IPython/core/interactiveshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
from IPython.core.payload import PayloadManager
from IPython.core.prefilter import PrefilterManager
from IPython.core.profiledir import ProfileDir
from IPython.core.pylabtools import pylab_activate
from IPython.core.prompts import PromptManager
from IPython.lib.latextools import LaTeXTool
from IPython.testing.skipdoctest import skip_doctest
Expand Down Expand Up @@ -2832,6 +2831,51 @@ def run_code(self, code_obj):

def enable_gui(self, gui=None):
raise NotImplementedError('Implement enable_gui in a subclass')

def enable_matplotlib(self, gui=None):
"""Enable interactive matplotlib and inline figure support.

This takes the following steps:

1. select the appropriate eventloop and matplotlib backend
2. set up matplotlib for interactive use with that backend
3. configure formatters for inline figure display
4. enable the selected gui eventloop

Parameters
----------
gui : optional, string
If given, dictates the choice of matplotlib GUI backend to use
(should be one of IPython's supported backends, 'qt', 'osx', 'tk',
'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
matplotlib (as dictated by the matplotlib build-time options plus the
user's matplotlibrc configuration file). Note that not all backends
make sense in all contexts, for example a terminal ipython can't
display figures inline.
"""
from IPython.core import pylabtools as pt
gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)

if gui != 'inline':
# If we have our first gui selection, store it
if self.pylab_gui_select is None:
self.pylab_gui_select = gui
# Otherwise if they are different
elif gui != self.pylab_gui_select:
print ('Warning: Cannot change to a different GUI toolkit: %s.'
' Using %s instead.' % (gui, self.pylab_gui_select))
gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)

pt.activate_matplotlib(backend)
pt.configure_inline_support(self, backend)

# Now we must activate the gui pylab wants to use, and fix %run to take
# plot updates into account
self.enable_gui(gui)
self.magics_manager.registry['ExecutionMagics'].default_runner = \
pt.mpl_runner(self.safe_execfile)

return gui, backend

def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
"""Activate pylab support at runtime.
Expand All @@ -2840,6 +2884,8 @@ def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
namespace all of numpy and pylab, and configures IPython to correctly
interact with the GUI event loop. The GUI backend to be used can be
optionally selected with the optional ``gui`` argument.

This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.

Parameters
----------
Expand All @@ -2851,30 +2897,29 @@ def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
user's matplotlibrc configuration file). Note that not all backends
make sense in all contexts, for example a terminal ipython can't
display figures inline.
import_all : optional, bool, default: True
Whether to do `from numpy import *` and `from pylab import *`
in addition to module imports.
welcome_message : deprecated
This argument is ignored, no welcome message will be displayed.
"""
from IPython.core.pylabtools import mpl_runner, backends
from IPython.core.pylabtools import import_pylab

gui, backend = self.enable_matplotlib(gui)

# We want to prevent the loading of pylab to pollute the user's
# namespace as shown by the %who* magics, so we execute the activation
# code in an empty namespace, and we update *both* user_ns and
# user_ns_hidden with this information.
ns = {}
try:
gui = pylab_activate(ns, gui, import_all, self, welcome_message=welcome_message)
except KeyError:
error("Backend '%s' not supported. Supported backends are: %s"
% (gui, " ".join(sorted(backends.keys()))))
return
except ImportError:
error("pylab mode doesn't work as matplotlib could not be found." + \
"\nIs it installed on the system?")
return
import_pylab(ns, import_all)
# warn about clobbered names
ignored = set(["__builtins__"])
both = set(ns).intersection(self.user_ns).difference(ignored)
clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ]
self.user_ns.update(ns)
self.user_ns_hidden.update(ns)
# Now we must activate the gui pylab wants to use, and fix %run to take
# plot updates into account
self.enable_gui(gui)
self.magics_manager.registry['ExecutionMagics'].default_runner = \
mpl_runner(self.safe_execfile)
return gui, backend, clobbered

#-------------------------------------------------------------------------
# Utilities
Expand Down
129 changes: 91 additions & 38 deletions IPython/core/magics/pylab.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,41 @@

# Our own packages
from IPython.config.application import Application
from IPython.core import magic_arguments
from IPython.core.magic import Magics, magics_class, line_magic
from IPython.testing.skipdoctest import skip_doctest
from IPython.utils.warn import warn
from IPython.core.pylabtools import backends

#-----------------------------------------------------------------------------
# Magic implementation classes
#-----------------------------------------------------------------------------

magic_gui_arg = magic_arguments.argument(
'gui', nargs='?',
help="""Name of the matplotlib backend to use %s.
If given, the corresponding matplotlib backend is used,
otherwise it will be matplotlib's default
(which you can set in your matplotlib config file).
""" % str(tuple(sorted(backends.keys())))
)


@magics_class
class PylabMagics(Magics):
"""Magics related to matplotlib's pylab support"""

@skip_doctest
@line_magic
def pylab(self, parameter_s=''):
"""Load numpy and matplotlib to work interactively.

%pylab [GUINAME]

This function lets you activate pylab (matplotlib, numpy and
interactive support) at any point during an IPython session.

It will import at the top level numpy as np, pyplot as plt, matplotlib,
pylab and mlab, as well as all names from numpy and pylab.

@magic_arguments.magic_arguments()
@magic_gui_arg
def matplotlib(self, line=''):
"""Set up matplotlib to work interactively.

This function lets you activate matplotlib interactive support
at any point during an IPython session.
It does not import anything into the interactive namespace.

If you are using the inline matplotlib backend for embedded figures,
you can adjust its behavior via the %config magic::

Expand All @@ -49,40 +60,82 @@ def pylab(self, parameter_s=''):
# cells:
In [2]: %config InlineBackend.close_figures = False

Parameters
----------
guiname : optional
One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk',
'osx' or 'tk'). If given, the corresponding Matplotlib backend is
used, otherwise matplotlib's default (which you can override in your
matplotlib config file) is used.

Examples
--------
In this case, where the MPL default is TkAgg::

In [2]: %pylab

Welcome to pylab, a matplotlib-based Python environment.
Backend in use: TkAgg
For more information, type 'help(pylab)'.
In [2]: %matplotlib
Using matplotlib backend: TkAgg

But you can explicitly request a different backend::

In [3]: %pylab qt
In [3]: %matplotlib qt
"""
args = magic_arguments.parse_argstring(self.matplotlib, line)
gui, backend = self.shell.enable_matplotlib(args.gui)
self._show_matplotlib_backend(args.gui, backend)

Welcome to pylab, a matplotlib-based Python environment.
Backend in use: Qt4Agg
For more information, type 'help(pylab)'.
@skip_doctest
@line_magic
@magic_arguments.magic_arguments()
@magic_arguments.argument(
'--no-import-all', action='store_true', default=None,
help="""Prevent IPython from performing ``import *`` into the interactive namespace.

The names that will still be added to the namespace if this flag is given::

numpy
matplotlib
np (numpy alias)
plt (matplotlib.pyplot alias)
pylab (from matplotlib)
pyplot (from matplotlib)
mlab (from matplotlib)
display (from IPython)
figsize (from IPython)
getfigs (from IPython)

You can govern the default behavior with the
InteractiveShellApp.pylab_import_all configurable.
"""
)
@magic_gui_arg
def pylab(self, line=''):
"""Load numpy and matplotlib to work interactively.

if Application.initialized():
app = Application.instance()
try:
import_all_status = app.pylab_import_all
except AttributeError:
import_all_status = True
else:
import_all_status = True
This function lets you activate pylab (matplotlib, numpy and
interactive support) at any point during an IPython session.

self.shell.enable_pylab(parameter_s, import_all=import_all_status, welcome_message=True)
It will import at the top level numpy as np, pyplot as plt, matplotlib,
pylab and mlab, as well as all names from numpy and pylab.

See the %matplotlib magic for more details.
"""
args = magic_arguments.parse_argstring(self.pylab, line)
if args.no_import_all is None:
# get default from Application
if Application.initialized():
app = Application.instance()
try:
import_all = app.pylab_import_all
except AttributeError:
import_all = True
else:
# nothing specified, no app - default True
import_all = True
else:
# invert no-import flag
import_all = not args.no_import_all

gui, backend, clobbered = self.shell.enable_pylab(args.gui, import_all=import_all)
self._show_matplotlib_backend(args.gui, backend)
if clobbered:
warn("pylab import has clobbered these variables: %s" % clobbered +
"\n`%pylab --no-import-all` prevents importing * from pylab and numpy"
)

def _show_matplotlib_backend(self, gui, backend):
"""show matplotlib message backend message"""
if not gui or gui == 'auto':
print ("using matplotlib backend: %s" % backend)