##// END OF EJS Templates
enable retina matplotlib figures
MinRK -
Show More
@@ -19,6 +19,7 b' Authors'
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import struct
22 import sys
23 import sys
23 from io import BytesIO
24 from io import BytesIO
24
25
@@ -90,6 +91,7 b' def figsize(sizex, sizey):'
90
91
91 def print_figure(fig, fmt='png'):
92 def print_figure(fig, fmt='png'):
92 """Convert a figure to svg or png for inline display."""
93 """Convert a figure to svg or png for inline display."""
94 from matplotlib import rcParams
93 # When there's an empty figure, we shouldn't return anything, otherwise we
95 # When there's an empty figure, we shouldn't return anything, otherwise we
94 # get big blank areas in the qt console.
96 # get big blank areas in the qt console.
95 if not fig.axes and not fig.lines:
97 if not fig.axes and not fig.lines:
@@ -98,11 +100,27 b" def print_figure(fig, fmt='png'):"
98 fc = fig.get_facecolor()
100 fc = fig.get_facecolor()
99 ec = fig.get_edgecolor()
101 ec = fig.get_edgecolor()
100 bytes_io = BytesIO()
102 bytes_io = BytesIO()
103 dpi = rcParams['savefig.dpi']
104 if fmt == 'retina':
105 dpi = dpi * 2
101 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
106 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
102 facecolor=fc, edgecolor=ec)
107 facecolor=fc, edgecolor=ec, dpi=dpi)
103 data = bytes_io.getvalue()
108 data = bytes_io.getvalue()
104 return data
109 return data
105
110
111 def pngxy(data):
112 """read the width/height from a PNG header"""
113 ihdr = data.index(b'IHDR')
114 # next 8 bytes are width/height
115 w4h4 = data[ihdr+4:ihdr+12]
116 return struct.unpack('>ii', w4h4)
117
118 def retina_figure(fig):
119 """format a figure as a pixel-doubled (retina) PNG"""
120 pngdata = print_figure(fig, fmt='retina')
121 w, h = pngxy(pngdata)
122 metadata = dict(width=w//2, height=h//2)
123 return pngdata, metadata
106
124
107 # We need a little factory function here to create the closure where
125 # We need a little factory function here to create the closure where
108 # safe_execfile can live.
126 # safe_execfile can live.
@@ -147,7 +165,7 b' def mpl_runner(safe_execfile):'
147
165
148
166
149 def select_figure_format(shell, fmt):
167 def select_figure_format(shell, fmt):
150 """Select figure format for inline backend, either 'png' or 'svg'.
168 """Select figure format for inline backend, can be 'png', 'retina', or 'svg'.
151
169
152 Using this method ensures only one figure format is active at a time.
170 Using this method ensures only one figure format is active at a time.
153 """
171 """
@@ -160,11 +178,14 b' def select_figure_format(shell, fmt):'
160 if fmt=='png':
178 if fmt == 'png':
161 svg_formatter.type_printers.pop(Figure, None)
179 svg_formatter.type_printers.pop(Figure, None)
162 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
180 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
181 elif fmt in ('png2x', 'retina'):
182 svg_formatter.type_printers.pop(Figure, None)
183 png_formatter.for_type(Figure, retina_figure)
163 elif fmt=='svg':
184 elif fmt == 'svg':
164 png_formatter.type_printers.pop(Figure, None)
185 png_formatter.type_printers.pop(Figure, None)
165 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
186 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
166 else:
187 else:
167 raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt)
188 raise ValueError("supported formats are: 'png', 'retina', 'svg', not %r" % fmt)
168
189
169 # set the format to be used in the backend()
190 # set the format to be used in the backend()
170 backend_inline._figure_format = fmt
191 backend_inline._figure_format = fmt
@@ -18,7 +18,7 b' from IPython.config.configurable import SingletonConfigurable'
18 from IPython.core.display import display
18 from IPython.core.display import display
19 from IPython.core.displaypub import publish_display_data
19 from IPython.core.displaypub import publish_display_data
20 from IPython.core.pylabtools import print_figure, select_figure_format
20 from IPython.core.pylabtools import print_figure, select_figure_format
21 from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, CBool
21 from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, Bool
22 from IPython.utils.warn import warn
22 from IPython.utils.warn import warn
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
@@ -56,7 +56,7 b' class InlineBackend(InlineBackendConfig):'
56 inline backend."""
56 inline backend."""
57 )
57 )
58
58
59 figure_format = CaselessStrEnum(['svg', 'png'], default_value='png', config=True,
59 figure_format = CaselessStrEnum(['svg', 'png', 'retina'], default_value='png', config=True,
60 help="The image format for figures with the inline backend.")
60 help="The image format for figures with the inline backend.")
61
61
62 def _figure_format_changed(self, name, old, new):
62 def _figure_format_changed(self, name, old, new):
@@ -65,7 +65,7 b' class InlineBackend(InlineBackendConfig):'
65 else:
65 else:
66 select_figure_format(self.shell, new)
66 select_figure_format(self.shell, new)
67
67
68 close_figures = CBool(True, config=True,
68 close_figures = Bool(True, config=True,
69 help="""Close all figures at the end of each cell.
69 help="""Close all figures at the end of each cell.
70
70
71 When True, ensures that each cell starts with no active figures, but it
71 When True, ensures that each cell starts with no active figures, but it
General Comments 0
You need to be logged in to leave comments. Login now