Show More
@@ -19,6 +19,7 b' Authors' | |||
|
19 | 19 | # Imports |
|
20 | 20 | #----------------------------------------------------------------------------- |
|
21 | 21 | |
|
22 | import struct | |
|
22 | 23 | import sys |
|
23 | 24 | from io import BytesIO |
|
24 | 25 | |
@@ -90,6 +91,7 b' def figsize(sizex, sizey):' | |||
|
90 | 91 | |
|
91 | 92 | def print_figure(fig, fmt='png'): |
|
92 | 93 | """Convert a figure to svg or png for inline display.""" |
|
94 | from matplotlib import rcParams | |
|
93 | 95 | # When there's an empty figure, we shouldn't return anything, otherwise we |
|
94 | 96 | # get big blank areas in the qt console. |
|
95 | 97 | if not fig.axes and not fig.lines: |
@@ -98,11 +100,27 b" def print_figure(fig, fmt='png'):" | |||
|
98 | 100 | fc = fig.get_facecolor() |
|
99 | 101 | ec = fig.get_edgecolor() |
|
100 | 102 | bytes_io = BytesIO() |
|
103 | dpi = rcParams['savefig.dpi'] | |
|
104 | if fmt == 'retina': | |
|
105 | dpi = dpi * 2 | |
|
101 | 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 | 108 | data = bytes_io.getvalue() |
|
104 | 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 | 125 | # We need a little factory function here to create the closure where |
|
108 | 126 | # safe_execfile can live. |
@@ -147,7 +165,7 b' def mpl_runner(safe_execfile):' | |||
|
147 | 165 | |
|
148 | 166 | |
|
149 | 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 | 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 | 175 | svg_formatter = shell.display_formatter.formatters['image/svg+xml'] |
|
158 | 176 | png_formatter = shell.display_formatter.formatters['image/png'] |
|
159 | 177 | |
|
160 | if fmt=='png': | |
|
178 | if fmt == 'png': | |
|
161 | 179 | svg_formatter.type_printers.pop(Figure, None) |
|
162 | 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 | 185 | png_formatter.type_printers.pop(Figure, None) |
|
165 | 186 | svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg')) |
|
166 | 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 | 190 | # set the format to be used in the backend() |
|
170 | 191 | backend_inline._figure_format = fmt |
@@ -18,7 +18,7 b' from IPython.config.configurable import SingletonConfigurable' | |||
|
18 | 18 | from IPython.core.display import display |
|
19 | 19 | from IPython.core.displaypub import publish_display_data |
|
20 | 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 | 22 | from IPython.utils.warn import warn |
|
23 | 23 | |
|
24 | 24 | #----------------------------------------------------------------------------- |
@@ -56,7 +56,7 b' class InlineBackend(InlineBackendConfig):' | |||
|
56 | 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 | 60 | help="The image format for figures with the inline backend.") |
|
61 | 61 | |
|
62 | 62 | def _figure_format_changed(self, name, old, new): |
@@ -65,7 +65,7 b' class InlineBackend(InlineBackendConfig):' | |||
|
65 | 65 | else: |
|
66 | 66 | select_figure_format(self.shell, new) |
|
67 | 67 | |
|
68 |
close_figures = |
|
|
68 | close_figures = Bool(True, config=True, | |
|
69 | 69 | help="""Close all figures at the end of each cell. |
|
70 | 70 | |
|
71 | 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