Repository: ipython/ipython

Issue:
Turning off %matplotlib inline (feature request)
Apologies if I'm just missing it in the docs.

Currently, (IPython v4.2) it doesn't seem possible to undo calling `%matplotlib inline` if one doesn't want to revert to an interactive backend (one can only switch between different interactive backends). The reason why I believe it is useful to sometimes switch to a non-interactive backend is a combination of:
- Proliferation of using `pyplot` as the plotting interface used by libraries
- Lack of end-user control over which figures get plotted if the figures are created using `pyplot.figure`

If it was possible to have an IPython analog of `matplotlib.use('agg')`, the end user would always have control over which figures are plotted.



Discussion:
I don't think it's you, I think we just haven't thought of this. We could make `%matplotlib arg`, for instance. I'm not sure it would do anything other than call `matplotlib.use('agg')`, though.

Just calling `matplotlib.use('agg')` doesn't switch off the effects of `%matplotlib inline`. I didn't dive into the source, but I assume the inline backend is based on agg and adds some jupyter-specific post-processing (keeping track of created figures and showing them).

Indeed, there's a few specific hooks that get added.  If you dig a bit into the code, it should be easy to add a `%matplotlib off` call that unregisters the post-processing to leave things back the way they were before (other than obviously matplotlib having been imported).

It should be clear that this can't undo global actions like initializing a GUI event loop, but it could help some valid use cases...

Care to make a PR?

> Care to make a PR?

Looked at the code, and the amount of involved machinery is beyond something I can understand and modify within reasonable time, sorry.

Overall IPython here doesn't behave more irreversible than matplotlib itself, so obviously it's not an important issue.

You can kill off any existing event loops and de-register the `PyOS_INPUTHOOK`.


Resolving patch:
diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py
--- a/IPython/core/pylabtools.py
+++ b/IPython/core/pylabtools.py
@@ -23,6 +23,7 @@
             'osx': 'MacOSX',
             'nbagg': 'nbAgg',
             'notebook': 'nbAgg',
+            'agg': 'agg',
             'inline' : 'module://ipykernel.pylab.backend_inline'}
 
 # We also need a reverse backends2guis mapping that will properly choose which
@@ -245,7 +246,7 @@ def find_gui_and_backend(gui=None, gui_select=None):
     Parameters
     ----------
     gui : str
-        Can be one of ('tk','gtk','wx','qt','qt4','inline').
+        Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
     gui_select : str
         Can be one of ('tk','gtk','wx','qt','qt4','inline').
         This is any gui already selected by the shell.
@@ -253,7 +254,7 @@ def find_gui_and_backend(gui=None, gui_select=None):
     Returns
     -------
     A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
-    'WXAgg','Qt4Agg','module://ipykernel.pylab.backend_inline').
+    'WXAgg','Qt4Agg','module://ipykernel.pylab.backend_inline','agg').
     """
 
     import matplotlib
@@ -261,6 +262,8 @@ def find_gui_and_backend(gui=None, gui_select=None):
     if gui and gui != 'auto':
         # select backend based on requested gui
         backend = backends[gui]
+        if gui == 'agg':
+            gui = None
     else:
         # We need to read the backend from the original data structure, *not*
         # from mpl.rcParams, since a prior invocation of %matplotlib may have


Test patch: