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, e |
|
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 | """ | |
@@ -157,14 +175,17 b' def select_figure_format(shell, fmt):' | |||||
157 | svg_formatter = shell.display_formatter.formatters['image/svg+xml'] |
|
175 | svg_formatter = shell.display_formatter.formatters['image/svg+xml'] | |
158 | png_formatter = shell.display_formatter.formatters['image/png'] |
|
176 | png_formatter = shell.display_formatter.formatters['image/png'] | |
159 |
|
177 | |||
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')) | |
163 | elif fmt=='svg': |
|
181 | elif fmt in ('png2x', 'retina'): | |
|
182 | svg_formatter.type_printers.pop(Figure, None) | |||
|
183 | png_formatter.for_type(Figure, retina_figure) | |||
|
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, |
|
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 = |
|
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