Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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...
commit 501b44b487b95621d669ff028ba97a744ebea801 1 parent 58e216b
Min RK authored

Showing 2 changed files with 61 additions and 26 deletions. Show diff stats Hide diff stats

  1. +46 16 IPython/lib/pylabtools.py
  2. +15 10 IPython/zmq/pylab/backend_inline.py
62 IPython/lib/pylabtools.py
@@ -75,8 +75,8 @@ def figsize(sizex, sizey):
75 75 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
76 76
77 77
78   -def figure_to_svg(fig):
79   - """Convert a figure to svg for inline display."""
  78 +def print_figure(fig, fmt='png'):
  79 + """Convert a figure to svg or png for inline display."""
80 80 # When there's an empty figure, we shouldn't return anything, otherwise we
81 81 # get big blank areas in the qt console.
82 82 if not fig.axes:
@@ -88,12 +88,15 @@ def figure_to_svg(fig):
88 88 fig.set_edgecolor('white')
89 89 try:
90 90 string_io = StringIO()
91   - fig.canvas.print_figure(string_io, format='svg')
92   - svg = string_io.getvalue()
  91 + # use 72 dpi to match QTConsole's dpi
  92 + fig.canvas.print_figure(string_io, format=fmt, dpi=72)
  93 + data = string_io.getvalue()
93 94 finally:
94 95 fig.set_facecolor(fc)
95 96 fig.set_edgecolor(ec)
96   - return svg
  97 + if fmt == 'png':
  98 + data = data.encode('base64')
  99 + return data
97 100
98 101
99 102 # We need a little factory function here to create the closure where
@@ -199,6 +202,30 @@ def activate_matplotlib(backend):
199 202 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
200 203
201 204
  205 +def _select_figure_format(shell, fmt):
  206 + """Select figure format for inline backend, either 'png' or 'svg'.
  207 +
  208 + Using this method ensures only one figure format is active at a time.
  209 + """
  210 + from matplotlib.figure import Figure
  211 + from IPython.zmq.pylab import backend_inline
  212 +
  213 + svg_formatter = shell.display_formatter.formatters['image/svg+xml']
  214 + png_formatter = shell.display_formatter.formatters['image/png']
  215 +
  216 + if fmt=='png':
  217 + svg_formatter.type_printers.pop(Figure, None)
  218 + png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
  219 + elif fmt=='svg':
  220 + png_formatter.type_printers.pop(Figure, None)
  221 + svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
  222 + else:
  223 + raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt)
  224 +
  225 + # set the format to be used in the backend()
  226 + backend_inline._figure_format = fmt
  227 +
  228 +
202 229 def import_pylab(user_ns, backend, import_all=True, shell=None):
203 230 """Import the standard pylab symbols into user_ns."""
204 231
@@ -219,9 +246,9 @@ def import_pylab(user_ns, backend, import_all=True, shell=None):
219 246 # function that will pick up the results for display. This can only be
220 247 # done with access to the real shell object.
221 248 if backend == backends['inline']:
222   - from IPython.zmq.pylab.backend_inline import flush_svg
  249 + from IPython.zmq.pylab.backend_inline import flush_figures
223 250 from matplotlib import pyplot
224   - shell.register_post_execute(flush_svg)
  251 + shell.register_post_execute(flush_figures)
225 252 # The typical default figure size is too large for inline use,
226 253 # so we shrink the figure size to 6x4, and tweak fonts to
227 254 # 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):
242 269 # Add 'figsize' to pyplot and to the user's namespace
243 270 user_ns['figsize'] = pyplot.figsize = figsize
244 271 shell.user_ns_hidden['figsize'] = figsize
  272 +
  273 + # Setup the default figure format
  274 + fmt = getattr(shell.config.Global, 'inline_figure_format', 'png')
  275 + def select_figure_format(fmt):
  276 + """select the figure image format (png or svg)."""
  277 + return _select_figure_format(shell, fmt)
  278 + select_figure_format(fmt)
  279 + # add select_figure_format to user_ns
  280 + user_ns['select_figure_format'] = select_figure_format
  281 + shell.user_ns_hidden['select_figure_format'] = select_figure_format
245 282
246 283 # The old pastefig function has been replaced by display
247   - # Always add this svg formatter so display works.
248   - from IPython.core.display import display, display_svg
249   - svg_formatter = shell.display_formatter.formatters['image/svg+xml']
250   - svg_formatter.for_type_by_name(
251   - 'matplotlib.figure','Figure',figure_to_svg
252   - )
253   - # Add display and display_png to the user's namespace
  284 + from IPython.core.display import display
  285 + # Add display to the user's namespace
254 286 user_ns['display'] = display
255 287 shell.user_ns_hidden['display'] = display
256   - user_ns['display_svg'] = display_svg
257   - shell.user_ns_hidden['display_svg'] = display_svg
258 288 user_ns['getfigs'] = getfigs
259 289 shell.user_ns_hidden['getfigs'] = getfigs
260 290
25 IPython/zmq/pylab/backend_inline.py
@@ -10,12 +10,15 @@
10 10
11 11 # Third-party imports
12 12 import matplotlib
13   -from matplotlib.backends.backend_svg import new_figure_manager
  13 +from matplotlib.backends.backend_agg import new_figure_manager
14 14 from matplotlib._pylab_helpers import Gcf
15 15
16 16 # Local imports.
17 17 from IPython.core.displaypub import publish_display_data
18   -from IPython.lib.pylabtools import figure_to_svg
  18 +from IPython.lib.pylabtools import print_figure
  19 +
  20 +# global config:
  21 +_figure_format='png'
19 22
20 23 #-----------------------------------------------------------------------------
21 24 # Functions
@@ -32,7 +35,7 @@ def show(close=True):
32 35 removed from the internal list of figures.
33 36 """
34 37 for figure_manager in Gcf.get_all_fig_managers():
35   - send_svg_figure(figure_manager.canvas.figure)
  38 + send_figure(figure_manager.canvas.figure)
36 39 if close:
37 40 matplotlib.pyplot.close('all')
38 41
@@ -50,8 +53,8 @@ def draw_if_interactive():
50 53 show._draw_called = True
51 54
52 55
53   -def flush_svg():
54   - """Call show, close all open figures, sending all SVG images.
  56 +def flush_figures():
  57 + """Call show, close all open figures, sending all figure images.
55 58
56 59 This is meant to be called automatically and will call show() if, during
57 60 prior code execution, there had been any calls to draw_if_interactive.
@@ -61,21 +64,23 @@ def flush_svg():
61 64 show._draw_called = False
62 65
63 66
64   -def send_svg_figure(fig):
65   - """Draw the current figure and send it as an SVG payload.
  67 +def send_figure(fig):
  68 + """Draw the current figure and send it as a PNG payload.
66 69 """
67 70 # For an empty figure, don't even bother calling figure_to_svg, to avoid
68 71 # big blank spaces in the qt console
69 72 if not fig.axes:
70 73 return
71 74
72   - svg = figure_to_svg(fig)
  75 + data = print_figure(fig, _figure_format)
  76 + mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
  77 + mime = mimetypes[_figure_format]
73 78 # flush text streams before sending figures, helps a little with output
74 79 # synchronization in the console (though it's a bandaid, not a real sln)
75 80 sys.stdout.flush(); sys.stderr.flush()
76 81 publish_display_data(
77   - 'IPython.zmq.pylab.backend_inline.send_svg_figure',
  82 + 'IPython.zmq.pylab.backend_inline.send_figure',
78 83 'Matplotlib Plot',
79   - {'image/svg+xml' : svg}
  84 + {mime : data}
80 85 )
81 86

0 comments on commit 501b44b

Please sign in to comment.
Something went wrong with that request. Please try again.