##// END OF EJS Templates
Merge pull request #4679 from dbarbeau/jpg-inline...
Min RK -
r14808:6def8ea0 merge
parent child Browse files
Show More
@@ -0,0 +1,3 b''
1 * The InlineBackend.figure_format flag now supports JPEG output if PIL/Pillow is available.
2 * The new ``InlineBackend.quality`` flag is a Integer in the range [10, 100] which controls
3 the quality of figures where higher values give nicer images (currently JPEG only).
@@ -94,8 +94,10 b' def figsize(sizex, sizey):'
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'):
97 def print_figure(fig, fmt='png', quality=90):
98 """Convert a figure to svg or png for inline display."""
98 """Convert a figure to svg, png or jpg for inline display.
99 Quality is only relevant for jpg.
100 """
99 from matplotlib import rcParams
101 from matplotlib import rcParams
100 # When there's an empty figure, we shouldn't return anything, otherwise we
102 # When there's an empty figure, we shouldn't return anything, otherwise we
101 # get big blank areas in the qt console.
103 # get big blank areas in the qt console.
@@ -110,7 +112,7 b" def print_figure(fig, fmt='png'):"
110 dpi = dpi * 2
112 dpi = dpi * 2
111 fmt = 'png'
113 fmt = 'png'
112 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
114 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
113 facecolor=fc, edgecolor=ec, dpi=dpi)
115 facecolor=fc, edgecolor=ec, dpi=dpi, quality=quality)
114 data = bytes_io.getvalue()
116 data = bytes_io.getvalue()
115 return data
117 return data
116
118
@@ -163,8 +165,8 b' def mpl_runner(safe_execfile):'
163 return mpl_execfile
165 return mpl_execfile
164
166
165
167
166 def select_figure_format(shell, fmt):
168 def select_figure_format(shell, fmt, quality=90):
167 """Select figure format for inline backend, can be 'png', 'retina', or 'svg'.
169 """Select figure format for inline backend, can be 'png', 'retina', 'jpg', or 'svg'.
168
170
169 Using this method ensures only one figure format is active at a time.
171 Using this method ensures only one figure format is active at a time.
170 """
172 """
@@ -173,18 +175,20 b' def select_figure_format(shell, fmt):'
173
175
174 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
176 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
175 png_formatter = shell.display_formatter.formatters['image/png']
177 png_formatter = shell.display_formatter.formatters['image/png']
178 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
179
180 [ f.type_printers.pop(Figure, None) for f in {svg_formatter, png_formatter, jpg_formatter} ]
176
181
177 if fmt == 'png':
182 if fmt == 'png':
178 svg_formatter.pop(Figure, None)
179 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
183 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
180 elif fmt in ('png2x', 'retina'):
184 elif fmt in ('png2x', 'retina'):
181 svg_formatter.pop(Figure, None)
182 png_formatter.for_type(Figure, retina_figure)
185 png_formatter.for_type(Figure, retina_figure)
186 elif fmt in ('jpg', 'jpeg'):
187 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality))
183 elif fmt == 'svg':
188 elif fmt == 'svg':
184 png_formatter.pop(Figure, None)
185 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
189 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
186 else:
190 else:
187 raise ValueError("supported formats are: 'png', 'retina', 'svg', not %r" % fmt)
191 raise ValueError("supported formats are: 'png', 'retina', 'svg', 'jpg', not %r" % fmt)
188
192
189 # set the format to be used in the backend()
193 # set the format to be used in the backend()
190 backend_inline._figure_format = fmt
194 backend_inline._figure_format = fmt
@@ -338,5 +342,5 b' def configure_inline_support(shell, backend):'
338 del shell._saved_rcParams
342 del shell._saved_rcParams
339
343
340 # Setup the default figure format
344 # Setup the default figure format
341 select_figure_format(shell, cfg.figure_format)
345 select_figure_format(shell, cfg.figure_format, cfg.quality)
342
346
@@ -26,6 +26,8 b' import numpy as np'
26 from IPython.core.interactiveshell import InteractiveShell
26 from IPython.core.interactiveshell import InteractiveShell
27 from .. import pylabtools as pt
27 from .. import pylabtools as pt
28
28
29 from IPython.testing import decorators as dec
30
29 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
30 # Globals and constants
32 # Globals and constants
31 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
@@ -53,6 +55,16 b' def test_figure_to_svg():'
53 svg = pt.print_figure(fig, 'svg')[:100].lower()
55 svg = pt.print_figure(fig, 'svg')[:100].lower()
54 nt.assert_in(b'doctype svg', svg)
56 nt.assert_in(b'doctype svg', svg)
55
57
58 @dec.skip_without("PIL.Image")
59 def test_figure_to_jpg():
60 # simple check for at least jpg-looking output
61 fig = plt.figure()
62 ax = fig.add_subplot(1,1,1)
63 ax.plot([1,2,3])
64 plt.draw()
65 jpg = pt.print_figure(fig, 'jpg')[:100].lower()
66 assert jpg.startswith(b'\xff\xd8')
67
56
68
57 def test_import_pylab():
69 def test_import_pylab():
58 ip = get_ipython()
70 ip = get_ipython()
@@ -14,13 +14,23 b' This module does not import anything from matplotlib.'
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
17 from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, Bool, Int, TraitError
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 def pil_available():
25 """Test if PIL/Pillow is available"""
26 out = False
27 try:
28 from PIL import Image
29 out = True
30 except:
31 pass
32 return out
33
24 # inherit from InlineBackendConfig for deprecation purposes
34 # inherit from InlineBackendConfig for deprecation purposes
25 class InlineBackendConfig(SingletonConfigurable):
35 class InlineBackendConfig(SingletonConfigurable):
26 pass
36 pass
@@ -53,15 +63,28 b' class InlineBackend(InlineBackendConfig):'
53 inline backend."""
63 inline backend."""
54 )
64 )
55
65
56 figure_format = CaselessStrEnum(['svg', 'png', 'retina'], default_value='png', config=True,
66
57 help="The image format for figures with the inline backend.")
67 figure_format = CaselessStrEnum(['svg', 'png', 'retina', 'jpg'],
68 default_value='png', config=True,
69 help="""The image format for figures with the inline
70 backend. JPEG requires the PIL/Pillow library.""")
58
71
59 def _figure_format_changed(self, name, old, new):
72 def _figure_format_changed(self, name, old, new):
60 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")
61 if self.shell is None:
77 if self.shell is None:
62 return
78 return
63 else:
79 else:
64 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 [10-100], currently for lossy JPEG only.")
84
85 def _quality_changed(self, name, old, new):
86 if new < 10 or new > 100:
87 raise TraitError("figure JPEG quality must be in [10-100] range.")
65
88
66 close_figures = Bool(True, config=True,
89 close_figures = Bool(True, config=True,
67 help="""Close all figures at the end of each cell.
90 help="""Close all figures at the end of each cell.
General Comments 0
You need to be logged in to leave comments. Login now