Permalink
Browse files

allow toggle of svg/png figure format in inline backend

png is now the default, and select_figure_format(fmt) is added to user_ns for switching between the two.

This should address some of the discussion in gh-381
  • Loading branch information...
1 parent 58e216b commit 501b44b487b95621d669ff028ba97a744ebea801 @minrk committed Apr 18, 2011
Showing with 61 additions and 26 deletions.
  1. +46 −16 IPython/lib/pylabtools.py
  2. +15 −10 IPython/zmq/pylab/backend_inline.py
@@ -75,8 +75,8 @@ def figsize(sizex, sizey):
matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
-def figure_to_svg(fig):
- """Convert a figure to svg for inline display."""
+def print_figure(fig, fmt='png'):
+ """Convert a figure to svg or png for inline display."""
# When there's an empty figure, we shouldn't return anything, otherwise we
# get big blank areas in the qt console.
if not fig.axes:
@@ -88,12 +88,15 @@ def figure_to_svg(fig):
fig.set_edgecolor('white')
try:
string_io = StringIO()
- fig.canvas.print_figure(string_io, format='svg')
- svg = string_io.getvalue()
+ # use 72 dpi to match QTConsole's dpi
+ fig.canvas.print_figure(string_io, format=fmt, dpi=72)
+ data = string_io.getvalue()
finally:
fig.set_facecolor(fc)
fig.set_edgecolor(ec)
- return svg
+ if fmt == 'png':
+ data = data.encode('base64')
+ return data
# We need a little factory function here to create the closure where
@@ -199,6 +202,30 @@ def activate_matplotlib(backend):
pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
+def _select_figure_format(shell, fmt):
+ """Select figure format for inline backend, either 'png' or 'svg'.
+
+ Using this method ensures only one figure format is active at a time.
+ """
+ from matplotlib.figure import Figure
+ from IPython.zmq.pylab import backend_inline
+
+ svg_formatter = shell.display_formatter.formatters['image/svg+xml']
+ png_formatter = shell.display_formatter.formatters['image/png']
+
+ if fmt=='png':
+ svg_formatter.type_printers.pop(Figure, None)
+ png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
+ elif fmt=='svg':
+ png_formatter.type_printers.pop(Figure, None)
+ svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
+ else:
+ raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt)
+
+ # set the format to be used in the backend()
+ backend_inline._figure_format = fmt
+
+
def import_pylab(user_ns, backend, import_all=True, shell=None):
"""Import the standard pylab symbols into user_ns."""
@@ -219,9 +246,9 @@ def import_pylab(user_ns, backend, import_all=True, shell=None):
# function that will pick up the results for display. This can only be
# done with access to the real shell object.
if backend == backends['inline']:
- from IPython.zmq.pylab.backend_inline import flush_svg
+ from IPython.zmq.pylab.backend_inline import flush_figures
from matplotlib import pyplot
- shell.register_post_execute(flush_svg)
+ shell.register_post_execute(flush_figures)
# The typical default figure size is too large for inline use,
# so we shrink the figure size to 6x4, and tweak fonts to
# make that fit. This is configurable via Global.pylab_inline_rc,
@@ -242,19 +269,22 @@ def import_pylab(user_ns, backend, import_all=True, shell=None):
# Add 'figsize' to pyplot and to the user's namespace
user_ns['figsize'] = pyplot.figsize = figsize
shell.user_ns_hidden['figsize'] = figsize
+
+ # Setup the default figure format
+ fmt = getattr(shell.config.Global, 'inline_figure_format', 'png')
+ def select_figure_format(fmt):
+ """select the figure image format (png or svg)."""
+ return _select_figure_format(shell, fmt)
+ select_figure_format(fmt)
+ # add select_figure_format to user_ns
+ user_ns['select_figure_format'] = select_figure_format
+ shell.user_ns_hidden['select_figure_format'] = select_figure_format
# The old pastefig function has been replaced by display
- # Always add this svg formatter so display works.
- from IPython.core.display import display, display_svg
- svg_formatter = shell.display_formatter.formatters['image/svg+xml']
- svg_formatter.for_type_by_name(
- 'matplotlib.figure','Figure',figure_to_svg
- )
- # Add display and display_png to the user's namespace
+ from IPython.core.display import display
+ # Add display to the user's namespace
user_ns['display'] = display
shell.user_ns_hidden['display'] = display
- user_ns['display_svg'] = display_svg
- shell.user_ns_hidden['display_svg'] = display_svg
user_ns['getfigs'] = getfigs
shell.user_ns_hidden['getfigs'] = getfigs
@@ -10,12 +10,15 @@
# Third-party imports
import matplotlib
-from matplotlib.backends.backend_svg import new_figure_manager
+from matplotlib.backends.backend_agg import new_figure_manager
from matplotlib._pylab_helpers import Gcf
# Local imports.
from IPython.core.displaypub import publish_display_data
-from IPython.lib.pylabtools import figure_to_svg
+from IPython.lib.pylabtools import print_figure
+
+# global config:
+_figure_format='png'
#-----------------------------------------------------------------------------
# Functions
@@ -32,7 +35,7 @@ def show(close=True):
removed from the internal list of figures.
"""
for figure_manager in Gcf.get_all_fig_managers():
- send_svg_figure(figure_manager.canvas.figure)
+ send_figure(figure_manager.canvas.figure)
if close:
matplotlib.pyplot.close('all')
@@ -50,8 +53,8 @@ def draw_if_interactive():
show._draw_called = True
-def flush_svg():
- """Call show, close all open figures, sending all SVG images.
+def flush_figures():
+ """Call show, close all open figures, sending all figure images.
This is meant to be called automatically and will call show() if, during
prior code execution, there had been any calls to draw_if_interactive.
@@ -61,21 +64,23 @@ def flush_svg():
show._draw_called = False
-def send_svg_figure(fig):
- """Draw the current figure and send it as an SVG payload.
+def send_figure(fig):
+ """Draw the current figure and send it as a PNG payload.
"""
# For an empty figure, don't even bother calling figure_to_svg, to avoid
# big blank spaces in the qt console
if not fig.axes:
return
- svg = figure_to_svg(fig)
+ data = print_figure(fig, _figure_format)
+ mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
+ mime = mimetypes[_figure_format]
# flush text streams before sending figures, helps a little with output
# synchronization in the console (though it's a bandaid, not a real sln)
sys.stdout.flush(); sys.stderr.flush()
publish_display_data(
- 'IPython.zmq.pylab.backend_inline.send_svg_figure',
+ 'IPython.zmq.pylab.backend_inline.send_figure',
'Matplotlib Plot',
- {'image/svg+xml' : svg}
+ {mime : data}
)

0 comments on commit 501b44b

Please sign in to comment.