Repository: ipython/ipython

Issue:
use js version of nbagg figures for display
The display system shows a png of figure objects, even if they are live nbagg figures and can have a live display.

This may require changes on the mpl side as well.

attn @pelson



Discussion:
I think this is a question of priority between:
1. the `_repr_foo_` methods on an object vs formatters set in our global registry.
2. different mimetypes in the same display message

@minrk will probably know more about this.

`%matplotlib anything` will register the figure formatters for inline display when a figure is displayed explicitly or via the displayhook. Perhaps that's inappropriate with the nbagg backend. @tacaswell Can you display an nbagg figure multiple times on one page?

I don't know enough about how coms work to answer that question.

On Thu, Jul 9, 2015, 12:14 AM Min RK notifications@github.com wrote:

> %matplotlib anything will register the figure formatters for inline
> display when a figure is displayed explicitly or via the displayhook.
> Perhaps that's inappropriate with the nbagg backend. @tacaswell
> https://github.com/tacaswell Can you display an nbagg figure multiple
> times on one page?
> 
> —
> Reply to this email directly or view it on GitHub
> https://github.com/ipython/ipython/issues/8617#issuecomment-119821023.

What would you like to happen if a figure is passed to `display` or the displayhook? Text representation? Or another instance of the figure on the page?

> Can you display an nbagg figure multiple times on one page?

Yes.

A second instance in the page, the use case i have in mind is if you some
how over write the out put cell that has your plot and i would like to do

Display(plt.figure(5))

And get the figure back on the page.

On Thu, Jul 9, 2015, 12:34 PM Phil Elson notifications@github.com wrote:

> Can you display an nbagg figure multiple times on one page?
> 
> Yes.
> 
> —
> Reply to this email directly or view it on GitHub
> https://github.com/ipython/ipython/issues/8617#issuecomment-120081042.

ok. In that case, we should register a formatter for figures with:

``` python
ipython_formatter = get_ipython().display_formatter.ipython_formatter
ipython_formatter.for_type(Figure, func_that_shows_figure)
```

That should take higher priority than any png/etc. formatters that we register.

What's the MPL call that would redisplay the figure?

`fig.canvas.manager.reshow()`

or I guess `lambda fig: fig.canvas.manager.reshow()`

[this notebook](http://nbviewer.ipython.org/gist/minrk/fec86818f69029766991) should illustrate it (not that you can really tell that the two plots were interactive). It seems like this is something we should be doing in IPython, so I'll add it to the matplotlib enable bits.

That works, but now we have a pathological case where if you put

``` python
fig, ax = plt.subplots()
fig
```

in a cell you get the figure twice (once from the implicit `show` call that is part of setting the figure manager up and once from the reshow called by the implicit display).


Resolving patch:
diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py
--- a/IPython/core/pylabtools.py
+++ b/IPython/core/pylabtools.py
@@ -173,6 +173,16 @@ def mpl_execfile(fname,*where,**kw):
     return mpl_execfile
 
 
+def _reshow_nbagg_figure(fig):
+    """reshow an nbagg figure"""
+    try:
+        reshow = fig.canvas.manager.reshow
+    except AttributeError:
+        raise NotImplementedError()
+    else:
+        reshow()
+
+
 def select_figure_formats(shell, formats, **kwargs):
     """Select figure formats for the inline backend.
 
@@ -185,6 +195,7 @@ def select_figure_formats(shell, formats, **kwargs):
     **kwargs : any
         Extra keyword arguments to be passed to fig.canvas.print_figure.
     """
+    import matplotlib
     from matplotlib.figure import Figure
     from ipykernel.pylab import backend_inline
 
@@ -199,7 +210,11 @@ def select_figure_formats(shell, formats, **kwargs):
     formats = set(formats)
 
     [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
-    
+
+    if matplotlib.backends.backend.lower() == 'nbagg':
+        formatter = shell.display_formatter.ipython_display_formatter
+        formatter.for_type(Figure, _reshow_nbagg_figure)
+
     supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
     bad = formats.difference(supported)
     if bad:


Test patch: