##// END OF EJS Templates
Move testing for PIL[low] in the _figure_format_changed(...) function instead...
Daniel B. Vasquez -
Show More
@@ -1,346 +1,344 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities.
2 """Pylab (matplotlib) support utilities.
3
3
4 Authors
4 Authors
5 -------
5 -------
6
6
7 * Fernando Perez.
7 * Fernando Perez.
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10 from __future__ import print_function
10 from __future__ import print_function
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2009 The IPython Development Team
13 # Copyright (C) 2009 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import sys
23 import sys
24 from io import BytesIO
24 from io import BytesIO
25
25
26 from IPython.core.display import _pngxy
26 from IPython.core.display import _pngxy
27 from IPython.utils.decorators import flag_calls
27 from IPython.utils.decorators import flag_calls
28
28
29 # If user specifies a GUI, that dictates the backend, otherwise we read the
29 # If user specifies a GUI, that dictates the backend, otherwise we read the
30 # user's mpl default from the mpl rc structure
30 # user's mpl default from the mpl rc structure
31 backends = {'tk': 'TkAgg',
31 backends = {'tk': 'TkAgg',
32 'gtk': 'GTKAgg',
32 'gtk': 'GTKAgg',
33 'gtk3': 'GTK3Agg',
33 'gtk3': 'GTK3Agg',
34 'wx': 'WXAgg',
34 'wx': 'WXAgg',
35 'qt': 'Qt4Agg', # qt3 not supported
35 'qt': 'Qt4Agg', # qt3 not supported
36 'qt4': 'Qt4Agg',
36 'qt4': 'Qt4Agg',
37 'osx': 'MacOSX',
37 'osx': 'MacOSX',
38 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
38 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
39
39
40 # We also need a reverse backends2guis mapping that will properly choose which
40 # We also need a reverse backends2guis mapping that will properly choose which
41 # GUI support to activate based on the desired matplotlib backend. For the
41 # GUI support to activate based on the desired matplotlib backend. For the
42 # most part it's just a reverse of the above dict, but we also need to add a
42 # most part it's just a reverse of the above dict, but we also need to add a
43 # few others that map to the same GUI manually:
43 # few others that map to the same GUI manually:
44 backend2gui = dict(zip(backends.values(), backends.keys()))
44 backend2gui = dict(zip(backends.values(), backends.keys()))
45 # Our tests expect backend2gui to just return 'qt'
45 # Our tests expect backend2gui to just return 'qt'
46 backend2gui['Qt4Agg'] = 'qt'
46 backend2gui['Qt4Agg'] = 'qt'
47 # In the reverse mapping, there are a few extra valid matplotlib backends that
47 # In the reverse mapping, there are a few extra valid matplotlib backends that
48 # map to the same GUI support
48 # map to the same GUI support
49 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
49 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
50 backend2gui['GTK3Cairo'] = 'gtk3'
50 backend2gui['GTK3Cairo'] = 'gtk3'
51 backend2gui['WX'] = 'wx'
51 backend2gui['WX'] = 'wx'
52 backend2gui['CocoaAgg'] = 'osx'
52 backend2gui['CocoaAgg'] = 'osx'
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Matplotlib utilities
55 # Matplotlib utilities
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57
57
58
58
59 def getfigs(*fig_nums):
59 def getfigs(*fig_nums):
60 """Get a list of matplotlib figures by figure numbers.
60 """Get a list of matplotlib figures by figure numbers.
61
61
62 If no arguments are given, all available figures are returned. If the
62 If no arguments are given, all available figures are returned. If the
63 argument list contains references to invalid figures, a warning is printed
63 argument list contains references to invalid figures, a warning is printed
64 but the function continues pasting further figures.
64 but the function continues pasting further figures.
65
65
66 Parameters
66 Parameters
67 ----------
67 ----------
68 figs : tuple
68 figs : tuple
69 A tuple of ints giving the figure numbers of the figures to return.
69 A tuple of ints giving the figure numbers of the figures to return.
70 """
70 """
71 from matplotlib._pylab_helpers import Gcf
71 from matplotlib._pylab_helpers import Gcf
72 if not fig_nums:
72 if not fig_nums:
73 fig_managers = Gcf.get_all_fig_managers()
73 fig_managers = Gcf.get_all_fig_managers()
74 return [fm.canvas.figure for fm in fig_managers]
74 return [fm.canvas.figure for fm in fig_managers]
75 else:
75 else:
76 figs = []
76 figs = []
77 for num in fig_nums:
77 for num in fig_nums:
78 f = Gcf.figs.get(num)
78 f = Gcf.figs.get(num)
79 if f is None:
79 if f is None:
80 print('Warning: figure %s not available.' % num)
80 print('Warning: figure %s not available.' % num)
81 else:
81 else:
82 figs.append(f.canvas.figure)
82 figs.append(f.canvas.figure)
83 return figs
83 return figs
84
84
85
85
86 def figsize(sizex, sizey):
86 def figsize(sizex, sizey):
87 """Set the default figure size to be [sizex, sizey].
87 """Set the default figure size to be [sizex, sizey].
88
88
89 This is just an easy to remember, convenience wrapper that sets::
89 This is just an easy to remember, convenience wrapper that sets::
90
90
91 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
91 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
92 """
92 """
93 import matplotlib
93 import matplotlib
94 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
94 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
95
95
96
96
97 def print_figure(fig, fmt='png', quality=90):
97 def print_figure(fig, fmt='png', quality=90):
98 """Convert a figure to svg, jpg (if PIL is installed) or png for inline display."""
98 """Convert a figure to svg, png or jpg for inline display."""
99 from matplotlib import rcParams
99 from matplotlib import rcParams
100 # When there's an empty figure, we shouldn't return anything, otherwise we
100 # When there's an empty figure, we shouldn't return anything, otherwise we
101 # get big blank areas in the qt console.
101 # get big blank areas in the qt console.
102 if not fig.axes and not fig.lines:
102 if not fig.axes and not fig.lines:
103 return
103 return
104
104
105 fc = fig.get_facecolor()
105 fc = fig.get_facecolor()
106 ec = fig.get_edgecolor()
106 ec = fig.get_edgecolor()
107 bytes_io = BytesIO()
107 bytes_io = BytesIO()
108 dpi = rcParams['savefig.dpi']
108 dpi = rcParams['savefig.dpi']
109 if fmt == 'retina':
109 if fmt == 'retina':
110 dpi = dpi * 2
110 dpi = dpi * 2
111 fmt = 'png'
111 fmt = 'png'
112 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
112 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
113 facecolor=fc, edgecolor=ec, dpi=dpi, quality=quality)
113 facecolor=fc, edgecolor=ec, dpi=dpi, quality=quality)
114 data = bytes_io.getvalue()
114 data = bytes_io.getvalue()
115 return data
115 return data
116
116
117 def retina_figure(fig):
117 def retina_figure(fig):
118 """format a figure as a pixel-doubled (retina) PNG"""
118 """format a figure as a pixel-doubled (retina) PNG"""
119 pngdata = print_figure(fig, fmt='retina')
119 pngdata = print_figure(fig, fmt='retina')
120 w, h = _pngxy(pngdata)
120 w, h = _pngxy(pngdata)
121 metadata = dict(width=w//2, height=h//2)
121 metadata = dict(width=w//2, height=h//2)
122 return pngdata, metadata
122 return pngdata, metadata
123
123
124 # We need a little factory function here to create the closure where
124 # We need a little factory function here to create the closure where
125 # safe_execfile can live.
125 # safe_execfile can live.
126 def mpl_runner(safe_execfile):
126 def mpl_runner(safe_execfile):
127 """Factory to return a matplotlib-enabled runner for %run.
127 """Factory to return a matplotlib-enabled runner for %run.
128
128
129 Parameters
129 Parameters
130 ----------
130 ----------
131 safe_execfile : function
131 safe_execfile : function
132 This must be a function with the same interface as the
132 This must be a function with the same interface as the
133 :meth:`safe_execfile` method of IPython.
133 :meth:`safe_execfile` method of IPython.
134
134
135 Returns
135 Returns
136 -------
136 -------
137 A function suitable for use as the ``runner`` argument of the %run magic
137 A function suitable for use as the ``runner`` argument of the %run magic
138 function.
138 function.
139 """
139 """
140
140
141 def mpl_execfile(fname,*where,**kw):
141 def mpl_execfile(fname,*where,**kw):
142 """matplotlib-aware wrapper around safe_execfile.
142 """matplotlib-aware wrapper around safe_execfile.
143
143
144 Its interface is identical to that of the :func:`execfile` builtin.
144 Its interface is identical to that of the :func:`execfile` builtin.
145
145
146 This is ultimately a call to execfile(), but wrapped in safeties to
146 This is ultimately a call to execfile(), but wrapped in safeties to
147 properly handle interactive rendering."""
147 properly handle interactive rendering."""
148
148
149 import matplotlib
149 import matplotlib
150 import matplotlib.pylab as pylab
150 import matplotlib.pylab as pylab
151
151
152 #print '*** Matplotlib runner ***' # dbg
152 #print '*** Matplotlib runner ***' # dbg
153 # turn off rendering until end of script
153 # turn off rendering until end of script
154 is_interactive = matplotlib.rcParams['interactive']
154 is_interactive = matplotlib.rcParams['interactive']
155 matplotlib.interactive(False)
155 matplotlib.interactive(False)
156 safe_execfile(fname,*where,**kw)
156 safe_execfile(fname,*where,**kw)
157 matplotlib.interactive(is_interactive)
157 matplotlib.interactive(is_interactive)
158 # make rendering call now, if the user tried to do it
158 # make rendering call now, if the user tried to do it
159 if pylab.draw_if_interactive.called:
159 if pylab.draw_if_interactive.called:
160 pylab.draw()
160 pylab.draw()
161 pylab.draw_if_interactive.called = False
161 pylab.draw_if_interactive.called = False
162
162
163 return mpl_execfile
163 return mpl_execfile
164
164
165
165
166 def select_figure_format(shell, fmt, quality):
166 def select_figure_format(shell, fmt, quality):
167 """Select figure format for inline backend, can be 'png', 'retina', or 'svg'.
167 """Select figure format for inline backend, can be 'png', 'retina', 'jpg', or 'svg'.
168
168
169 Using this method ensures only one figure format is active at a time.
169 Using this method ensures only one figure format is active at a time.
170 """
170 """
171 from matplotlib.figure import Figure
171 from matplotlib.figure import Figure
172 from IPython.kernel.zmq.pylab import backend_inline
172 from IPython.kernel.zmq.pylab import backend_inline
173
173
174 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
174 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
175 png_formatter = shell.display_formatter.formatters['image/png']
175 png_formatter = shell.display_formatter.formatters['image/png']
176 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
176 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
177
177
178 [ f.type_printers.pop(Figure, None) for f in {svg_formatter, png_formatter, jpg_formatter} ]
179
178 if fmt == 'png':
180 if fmt == 'png':
179 svg_formatter.pop(Figure, None)
180 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
181 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
181 elif fmt in ('jpg', 'jpeg'):
182 svg_formatter.type_printers.pop(Figure, None)
183 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality))
184 elif fmt in ('png2x', 'retina'):
182 elif fmt in ('png2x', 'retina'):
185 svg_formatter.pop(Figure, None)
186 png_formatter.for_type(Figure, retina_figure)
183 png_formatter.for_type(Figure, retina_figure)
184 elif fmt in ('jpg', 'jpeg'):
185 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality))
187 elif fmt == 'svg':
186 elif fmt == 'svg':
188 png_formatter.pop(Figure, None)
189 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
187 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
190 else:
188 else:
191 raise ValueError("supported formats are: 'png', 'retina', 'svg', not %r" % fmt)
189 raise ValueError("supported formats are: 'png', 'retina', 'svg', 'jpg', not %r" % fmt)
192
190
193 # set the format to be used in the backend()
191 # set the format to be used in the backend()
194 backend_inline._figure_format = fmt
192 backend_inline._figure_format = fmt
195
193
196 #-----------------------------------------------------------------------------
194 #-----------------------------------------------------------------------------
197 # Code for initializing matplotlib and importing pylab
195 # Code for initializing matplotlib and importing pylab
198 #-----------------------------------------------------------------------------
196 #-----------------------------------------------------------------------------
199
197
200
198
201 def find_gui_and_backend(gui=None, gui_select=None):
199 def find_gui_and_backend(gui=None, gui_select=None):
202 """Given a gui string return the gui and mpl backend.
200 """Given a gui string return the gui and mpl backend.
203
201
204 Parameters
202 Parameters
205 ----------
203 ----------
206 gui : str
204 gui : str
207 Can be one of ('tk','gtk','wx','qt','qt4','inline').
205 Can be one of ('tk','gtk','wx','qt','qt4','inline').
208 gui_select : str
206 gui_select : str
209 Can be one of ('tk','gtk','wx','qt','qt4','inline').
207 Can be one of ('tk','gtk','wx','qt','qt4','inline').
210 This is any gui already selected by the shell.
208 This is any gui already selected by the shell.
211
209
212 Returns
210 Returns
213 -------
211 -------
214 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
212 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
215 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
213 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
216 """
214 """
217
215
218 import matplotlib
216 import matplotlib
219
217
220 if gui and gui != 'auto':
218 if gui and gui != 'auto':
221 # select backend based on requested gui
219 # select backend based on requested gui
222 backend = backends[gui]
220 backend = backends[gui]
223 else:
221 else:
224 # We need to read the backend from the original data structure, *not*
222 # We need to read the backend from the original data structure, *not*
225 # from mpl.rcParams, since a prior invocation of %matplotlib may have
223 # from mpl.rcParams, since a prior invocation of %matplotlib may have
226 # overwritten that.
224 # overwritten that.
227 # WARNING: this assumes matplotlib 1.1 or newer!!
225 # WARNING: this assumes matplotlib 1.1 or newer!!
228 backend = matplotlib.rcParamsOrig['backend']
226 backend = matplotlib.rcParamsOrig['backend']
229 # In this case, we need to find what the appropriate gui selection call
227 # In this case, we need to find what the appropriate gui selection call
230 # should be for IPython, so we can activate inputhook accordingly
228 # should be for IPython, so we can activate inputhook accordingly
231 gui = backend2gui.get(backend, None)
229 gui = backend2gui.get(backend, None)
232
230
233 # If we have already had a gui active, we need it and inline are the
231 # If we have already had a gui active, we need it and inline are the
234 # ones allowed.
232 # ones allowed.
235 if gui_select and gui != gui_select:
233 if gui_select and gui != gui_select:
236 gui = gui_select
234 gui = gui_select
237 backend = backends[gui]
235 backend = backends[gui]
238
236
239 return gui, backend
237 return gui, backend
240
238
241
239
242 def activate_matplotlib(backend):
240 def activate_matplotlib(backend):
243 """Activate the given backend and set interactive to True."""
241 """Activate the given backend and set interactive to True."""
244
242
245 import matplotlib
243 import matplotlib
246 matplotlib.interactive(True)
244 matplotlib.interactive(True)
247
245
248 # Matplotlib had a bug where even switch_backend could not force
246 # Matplotlib had a bug where even switch_backend could not force
249 # the rcParam to update. This needs to be set *before* the module
247 # the rcParam to update. This needs to be set *before* the module
250 # magic of switch_backend().
248 # magic of switch_backend().
251 matplotlib.rcParams['backend'] = backend
249 matplotlib.rcParams['backend'] = backend
252
250
253 import matplotlib.pyplot
251 import matplotlib.pyplot
254 matplotlib.pyplot.switch_backend(backend)
252 matplotlib.pyplot.switch_backend(backend)
255
253
256 # This must be imported last in the matplotlib series, after
254 # This must be imported last in the matplotlib series, after
257 # backend/interactivity choices have been made
255 # backend/interactivity choices have been made
258 import matplotlib.pylab as pylab
256 import matplotlib.pylab as pylab
259
257
260 pylab.show._needmain = False
258 pylab.show._needmain = False
261 # We need to detect at runtime whether show() is called by the user.
259 # We need to detect at runtime whether show() is called by the user.
262 # For this, we wrap it into a decorator which adds a 'called' flag.
260 # For this, we wrap it into a decorator which adds a 'called' flag.
263 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
261 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
264
262
265
263
266 def import_pylab(user_ns, import_all=True):
264 def import_pylab(user_ns, import_all=True):
267 """Populate the namespace with pylab-related values.
265 """Populate the namespace with pylab-related values.
268
266
269 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
267 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
270
268
271 Also imports a few names from IPython (figsize, display, getfigs)
269 Also imports a few names from IPython (figsize, display, getfigs)
272
270
273 """
271 """
274
272
275 # Import numpy as np/pyplot as plt are conventions we're trying to
273 # Import numpy as np/pyplot as plt are conventions we're trying to
276 # somewhat standardize on. Making them available to users by default
274 # somewhat standardize on. Making them available to users by default
277 # will greatly help this.
275 # will greatly help this.
278 s = ("import numpy\n"
276 s = ("import numpy\n"
279 "import matplotlib\n"
277 "import matplotlib\n"
280 "from matplotlib import pylab, mlab, pyplot\n"
278 "from matplotlib import pylab, mlab, pyplot\n"
281 "np = numpy\n"
279 "np = numpy\n"
282 "plt = pyplot\n"
280 "plt = pyplot\n"
283 )
281 )
284 exec(s, user_ns)
282 exec(s, user_ns)
285
283
286 if import_all:
284 if import_all:
287 s = ("from matplotlib.pylab import *\n"
285 s = ("from matplotlib.pylab import *\n"
288 "from numpy import *\n")
286 "from numpy import *\n")
289 exec(s, user_ns)
287 exec(s, user_ns)
290
288
291 # IPython symbols to add
289 # IPython symbols to add
292 user_ns['figsize'] = figsize
290 user_ns['figsize'] = figsize
293 from IPython.core.display import display
291 from IPython.core.display import display
294 # Add display and getfigs to the user's namespace
292 # Add display and getfigs to the user's namespace
295 user_ns['display'] = display
293 user_ns['display'] = display
296 user_ns['getfigs'] = getfigs
294 user_ns['getfigs'] = getfigs
297
295
298
296
299 def configure_inline_support(shell, backend):
297 def configure_inline_support(shell, backend):
300 """Configure an IPython shell object for matplotlib use.
298 """Configure an IPython shell object for matplotlib use.
301
299
302 Parameters
300 Parameters
303 ----------
301 ----------
304 shell : InteractiveShell instance
302 shell : InteractiveShell instance
305
303
306 backend : matplotlib backend
304 backend : matplotlib backend
307 """
305 """
308 # If using our svg payload backend, register the post-execution
306 # If using our svg payload backend, register the post-execution
309 # function that will pick up the results for display. This can only be
307 # function that will pick up the results for display. This can only be
310 # done with access to the real shell object.
308 # done with access to the real shell object.
311
309
312 # Note: if we can't load the inline backend, then there's no point
310 # Note: if we can't load the inline backend, then there's no point
313 # continuing (such as in terminal-only shells in environments without
311 # continuing (such as in terminal-only shells in environments without
314 # zeromq available).
312 # zeromq available).
315 try:
313 try:
316 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
314 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
317 except ImportError:
315 except ImportError:
318 return
316 return
319 from matplotlib import pyplot
317 from matplotlib import pyplot
320
318
321 cfg = InlineBackend.instance(parent=shell)
319 cfg = InlineBackend.instance(parent=shell)
322 cfg.shell = shell
320 cfg.shell = shell
323 if cfg not in shell.configurables:
321 if cfg not in shell.configurables:
324 shell.configurables.append(cfg)
322 shell.configurables.append(cfg)
325
323
326 if backend == backends['inline']:
324 if backend == backends['inline']:
327 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
325 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
328 shell.register_post_execute(flush_figures)
326 shell.register_post_execute(flush_figures)
329
327
330 # Save rcParams that will be overwrittern
328 # Save rcParams that will be overwrittern
331 shell._saved_rcParams = dict()
329 shell._saved_rcParams = dict()
332 for k in cfg.rc:
330 for k in cfg.rc:
333 shell._saved_rcParams[k] = pyplot.rcParams[k]
331 shell._saved_rcParams[k] = pyplot.rcParams[k]
334 # load inline_rc
332 # load inline_rc
335 pyplot.rcParams.update(cfg.rc)
333 pyplot.rcParams.update(cfg.rc)
336 else:
334 else:
337 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
335 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
338 if flush_figures in shell._post_execute:
336 if flush_figures in shell._post_execute:
339 shell._post_execute.pop(flush_figures)
337 shell._post_execute.pop(flush_figures)
340 if hasattr(shell, '_saved_rcParams'):
338 if hasattr(shell, '_saved_rcParams'):
341 pyplot.rcParams.update(shell._saved_rcParams)
339 pyplot.rcParams.update(shell._saved_rcParams)
342 del shell._saved_rcParams
340 del shell._saved_rcParams
343
341
344 # Setup the default figure format
342 # Setup the default figure format
345 select_figure_format(shell, cfg.figure_format, cfg.quality)
343 select_figure_format(shell, cfg.figure_format, cfg.quality)
346
344
@@ -1,104 +1,108 b''
1 """Configurable for configuring the IPython inline backend
1 """Configurable for configuring the IPython inline backend
2
2
3 This module does not import anything from matplotlib.
3 This module does not import anything from matplotlib.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2011 The IPython Development Team
6 # Copyright (C) 2011 The IPython Development Team
7 #
7 #
8 # Distributed under the terms of the BSD License. The full license is in
8 # Distributed under the terms of the BSD License. The full license is in
9 # the file COPYING, distributed as part of this software.
9 # the file COPYING, distributed as part of this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 from IPython.config.configurable import SingletonConfigurable
16 from IPython.config.configurable import SingletonConfigurable
17 from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, Bool, Int
17 from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, Bool, Int
18 from IPython.utils.warn import warn
18 from IPython.utils.warn import warn
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Configurable for inline backend options
21 # Configurable for inline backend options
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 try:
24 def pil_available():
25 from PIL import Image
25 """Test if PIL/Pillow is available"""
26 has_pil = True
26 out = False
27 except:
27 try:
28 has_pil = False
28 from PIL import Image
29 out = True
30 except:
31 pass
32 return out
29
33
30 # inherit from InlineBackendConfig for deprecation purposes
34 # inherit from InlineBackendConfig for deprecation purposes
31 class InlineBackendConfig(SingletonConfigurable):
35 class InlineBackendConfig(SingletonConfigurable):
32 pass
36 pass
33
37
34 class InlineBackend(InlineBackendConfig):
38 class InlineBackend(InlineBackendConfig):
35 """An object to store configuration of the inline backend."""
39 """An object to store configuration of the inline backend."""
36
40
37 def _config_changed(self, name, old, new):
41 def _config_changed(self, name, old, new):
38 # warn on change of renamed config section
42 # warn on change of renamed config section
39 if new.InlineBackendConfig != old.InlineBackendConfig:
43 if new.InlineBackendConfig != old.InlineBackendConfig:
40 warn("InlineBackendConfig has been renamed to InlineBackend")
44 warn("InlineBackendConfig has been renamed to InlineBackend")
41 super(InlineBackend, self)._config_changed(name, old, new)
45 super(InlineBackend, self)._config_changed(name, old, new)
42
46
43 # The typical default figure size is too large for inline use,
47 # The typical default figure size is too large for inline use,
44 # so we shrink the figure size to 6x4, and tweak fonts to
48 # so we shrink the figure size to 6x4, and tweak fonts to
45 # make that fit.
49 # make that fit.
46 rc = Dict({'figure.figsize': (6.0,4.0),
50 rc = Dict({'figure.figsize': (6.0,4.0),
47 # play nicely with white background in the Qt and notebook frontend
51 # play nicely with white background in the Qt and notebook frontend
48 'figure.facecolor': (1,1,1,0),
52 'figure.facecolor': (1,1,1,0),
49 'figure.edgecolor': (1,1,1,0),
53 'figure.edgecolor': (1,1,1,0),
50 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
54 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
51 'font.size': 10,
55 'font.size': 10,
52 # 72 dpi matches SVG/qtconsole
56 # 72 dpi matches SVG/qtconsole
53 # this only affects PNG export, as SVG has no dpi setting
57 # this only affects PNG export, as SVG has no dpi setting
54 'savefig.dpi': 72,
58 'savefig.dpi': 72,
55 # 10pt still needs a little more room on the xlabel:
59 # 10pt still needs a little more room on the xlabel:
56 'figure.subplot.bottom' : .125
60 'figure.subplot.bottom' : .125
57 }, config=True,
61 }, config=True,
58 help="""Subset of matplotlib rcParams that should be different for the
62 help="""Subset of matplotlib rcParams that should be different for the
59 inline backend."""
63 inline backend."""
60 )
64 )
61
65
62 fmts = ['svg', 'png', 'retina']
63
66
64 if has_pil:
67 figure_format = CaselessStrEnum(['svg', 'png', 'retina', 'jpg'],
65 # If we have PIL using jpeg as inline image format can save some bytes.
68 default_value='png', config=True,
66 fmts.append('jpg')
69 help="""The image format for figures with the inline backend.
67
70 JPEG requires the PIL/Pillow library.""")
68 # Matplotlib's JPEG printer supports a quality option that can be tweaked.
69 # We expose it only if PIL is available so the user isn't confused. But it
70 # isn't guarded by "has_pil" test because core/pylabtools.py expects this
71 # field OR we need to propagate the has_pil test to that module too.
72 quality = Int(default_value=90, config=has_pil,
73 help="Quality of compression [0-100], currently for lossy JPEG only.")
74
75 figure_format = CaselessStrEnum(fmts, default_value='png', config=True,
76 help="The image format for figures with the inline backend.")
77
71
78 def _figure_format_changed(self, name, old, new):
72 def _figure_format_changed(self, name, old, new):
79 from IPython.core.pylabtools import select_figure_format
73 from IPython.core.pylabtools import select_figure_format
74 if new in {"jpg", "jpeg"}:
75 if not pil_available():
76 raise TraitError("Requires PIL/Pillow for JPG figures")
80 if self.shell is None:
77 if self.shell is None:
81 return
78 return
82 else:
79 else:
83 select_figure_format(self.shell, new)
80 select_figure_format(self.shell, new)
81
82 quality = Int(default_value=90, config=True,
83 help="Quality of compression [0-100], currently for lossy JPEG only.")
84
85 def _quality_changed(self, name, old, new):
86 if new < 0 or new > 100:
87 raise TraitError("figure quality must be in [0-100] range.")
84
88
85 close_figures = Bool(True, config=True,
89 close_figures = Bool(True, config=True,
86 help="""Close all figures at the end of each cell.
90 help="""Close all figures at the end of each cell.
87
91
88 When True, ensures that each cell starts with no active figures, but it
92 When True, ensures that each cell starts with no active figures, but it
89 also means that one must keep track of references in order to edit or
93 also means that one must keep track of references in order to edit or
90 redraw figures in subsequent cells. This mode is ideal for the notebook,
94 redraw figures in subsequent cells. This mode is ideal for the notebook,
91 where residual plots from other cells might be surprising.
95 where residual plots from other cells might be surprising.
92
96
93 When False, one must call figure() to create new figures. This means
97 When False, one must call figure() to create new figures. This means
94 that gcf() and getfigs() can reference figures created in other cells,
98 that gcf() and getfigs() can reference figures created in other cells,
95 and the active figure can continue to be edited with pylab/pyplot
99 and the active figure can continue to be edited with pylab/pyplot
96 methods that reference the current active figure. This mode facilitates
100 methods that reference the current active figure. This mode facilitates
97 iterative editing of figures, and behaves most consistently with
101 iterative editing of figures, and behaves most consistently with
98 other matplotlib backends, but figure barriers between cells must
102 other matplotlib backends, but figure barriers between cells must
99 be explicit.
103 be explicit.
100 """)
104 """)
101
105
102 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
106 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
103
107
104
108
General Comments 0
You need to be logged in to leave comments. Login now