##// END OF EJS Templates
Merge pull request #10317 from gnestor/json-warn...
meeseeksdev[bot] -
r23435:6eb3859e merge
parent child Browse files
Show More
@@ -1,1230 +1,1233 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats."""
2 """Top-level display functions for displaying object in different formats."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 try:
8 try:
9 from base64 import encodebytes as base64_encode
9 from base64 import encodebytes as base64_encode
10 except ImportError:
10 except ImportError:
11 from base64 import encodestring as base64_encode
11 from base64 import encodestring as base64_encode
12
12
13 from binascii import b2a_hex
13 from binascii import b2a_hex
14 import json
14 import json
15 import mimetypes
15 import mimetypes
16 import os
16 import os
17 import struct
17 import struct
18 import sys
18 import sys
19 import warnings
19 import warnings
20
20
21 from IPython.utils.py3compat import cast_bytes_py2, cast_unicode
21 from IPython.utils.py3compat import cast_bytes_py2, cast_unicode
22 from IPython.testing.skipdoctest import skip_doctest
22 from IPython.testing.skipdoctest import skip_doctest
23
23
24 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
24 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'GeoJSON', 'Javascript',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'GeoJSON', 'Javascript',
28 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
28 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
29 'publish_display_data', 'update_display', 'DisplayHandle']
29 'publish_display_data', 'update_display', 'DisplayHandle']
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # utility functions
32 # utility functions
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 def _safe_exists(path):
35 def _safe_exists(path):
36 """Check path, but don't let exceptions raise"""
36 """Check path, but don't let exceptions raise"""
37 try:
37 try:
38 return os.path.exists(path)
38 return os.path.exists(path)
39 except Exception:
39 except Exception:
40 return False
40 return False
41
41
42 def _merge(d1, d2):
42 def _merge(d1, d2):
43 """Like update, but merges sub-dicts instead of clobbering at the top level.
43 """Like update, but merges sub-dicts instead of clobbering at the top level.
44
44
45 Updates d1 in-place
45 Updates d1 in-place
46 """
46 """
47
47
48 if not isinstance(d2, dict) or not isinstance(d1, dict):
48 if not isinstance(d2, dict) or not isinstance(d1, dict):
49 return d2
49 return d2
50 for key, value in d2.items():
50 for key, value in d2.items():
51 d1[key] = _merge(d1.get(key), value)
51 d1[key] = _merge(d1.get(key), value)
52 return d1
52 return d1
53
53
54 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
54 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
55 """internal implementation of all display_foo methods
55 """internal implementation of all display_foo methods
56
56
57 Parameters
57 Parameters
58 ----------
58 ----------
59 mimetype : str
59 mimetype : str
60 The mimetype to be published (e.g. 'image/png')
60 The mimetype to be published (e.g. 'image/png')
61 objs : tuple of objects
61 objs : tuple of objects
62 The Python objects to display, or if raw=True raw text data to
62 The Python objects to display, or if raw=True raw text data to
63 display.
63 display.
64 raw : bool
64 raw : bool
65 Are the data objects raw data or Python objects that need to be
65 Are the data objects raw data or Python objects that need to be
66 formatted before display? [default: False]
66 formatted before display? [default: False]
67 metadata : dict (optional)
67 metadata : dict (optional)
68 Metadata to be associated with the specific mimetype output.
68 Metadata to be associated with the specific mimetype output.
69 """
69 """
70 if metadata:
70 if metadata:
71 metadata = {mimetype: metadata}
71 metadata = {mimetype: metadata}
72 if raw:
72 if raw:
73 # turn list of pngdata into list of { 'image/png': pngdata }
73 # turn list of pngdata into list of { 'image/png': pngdata }
74 objs = [ {mimetype: obj} for obj in objs ]
74 objs = [ {mimetype: obj} for obj in objs ]
75 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
75 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
76
76
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78 # Main functions
78 # Main functions
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80
80
81 # use * to indicate transient is keyword-only
81 # use * to indicate transient is keyword-only
82 def publish_display_data(data, metadata=None, source=None, *, transient=None, **kwargs):
82 def publish_display_data(data, metadata=None, source=None, *, transient=None, **kwargs):
83 """Publish data and metadata to all frontends.
83 """Publish data and metadata to all frontends.
84
84
85 See the ``display_data`` message in the messaging documentation for
85 See the ``display_data`` message in the messaging documentation for
86 more details about this message type.
86 more details about this message type.
87
87
88 The following MIME types are currently implemented:
88 The following MIME types are currently implemented:
89
89
90 * text/plain
90 * text/plain
91 * text/html
91 * text/html
92 * text/markdown
92 * text/markdown
93 * text/latex
93 * text/latex
94 * application/json
94 * application/json
95 * application/javascript
95 * application/javascript
96 * image/png
96 * image/png
97 * image/jpeg
97 * image/jpeg
98 * image/svg+xml
98 * image/svg+xml
99
99
100 Parameters
100 Parameters
101 ----------
101 ----------
102 data : dict
102 data : dict
103 A dictionary having keys that are valid MIME types (like
103 A dictionary having keys that are valid MIME types (like
104 'text/plain' or 'image/svg+xml') and values that are the data for
104 'text/plain' or 'image/svg+xml') and values that are the data for
105 that MIME type. The data itself must be a JSON'able data
105 that MIME type. The data itself must be a JSON'able data
106 structure. Minimally all data should have the 'text/plain' data,
106 structure. Minimally all data should have the 'text/plain' data,
107 which can be displayed by all frontends. If more than the plain
107 which can be displayed by all frontends. If more than the plain
108 text is given, it is up to the frontend to decide which
108 text is given, it is up to the frontend to decide which
109 representation to use.
109 representation to use.
110 metadata : dict
110 metadata : dict
111 A dictionary for metadata related to the data. This can contain
111 A dictionary for metadata related to the data. This can contain
112 arbitrary key, value pairs that frontends can use to interpret
112 arbitrary key, value pairs that frontends can use to interpret
113 the data. mime-type keys matching those in data can be used
113 the data. mime-type keys matching those in data can be used
114 to specify metadata about particular representations.
114 to specify metadata about particular representations.
115 source : str, deprecated
115 source : str, deprecated
116 Unused.
116 Unused.
117 transient : dict, keyword-only
117 transient : dict, keyword-only
118 A dictionary of transient data, such as display_id.
118 A dictionary of transient data, such as display_id.
119 """
119 """
120 from IPython.core.interactiveshell import InteractiveShell
120 from IPython.core.interactiveshell import InteractiveShell
121
121
122 display_pub = InteractiveShell.instance().display_pub
122 display_pub = InteractiveShell.instance().display_pub
123
123
124 # only pass transient if supplied,
124 # only pass transient if supplied,
125 # to avoid errors with older ipykernel.
125 # to avoid errors with older ipykernel.
126 # TODO: We could check for ipykernel version and provide a detailed upgrade message.
126 # TODO: We could check for ipykernel version and provide a detailed upgrade message.
127 if transient:
127 if transient:
128 kwargs['transient'] = transient
128 kwargs['transient'] = transient
129
129
130 display_pub.publish(
130 display_pub.publish(
131 data=data,
131 data=data,
132 metadata=metadata,
132 metadata=metadata,
133 **kwargs
133 **kwargs
134 )
134 )
135
135
136
136
137 def _new_id():
137 def _new_id():
138 """Generate a new random text id with urandom"""
138 """Generate a new random text id with urandom"""
139 return b2a_hex(os.urandom(16)).decode('ascii')
139 return b2a_hex(os.urandom(16)).decode('ascii')
140
140
141
141
142 def display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, **kwargs):
142 def display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, **kwargs):
143 """Display a Python object in all frontends.
143 """Display a Python object in all frontends.
144
144
145 By default all representations will be computed and sent to the frontends.
145 By default all representations will be computed and sent to the frontends.
146 Frontends can decide which representation is used and how.
146 Frontends can decide which representation is used and how.
147
147
148 Parameters
148 Parameters
149 ----------
149 ----------
150 objs : tuple of objects
150 objs : tuple of objects
151 The Python objects to display.
151 The Python objects to display.
152 raw : bool, optional
152 raw : bool, optional
153 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
153 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
154 or Python objects that need to be formatted before display? [default: False]
154 or Python objects that need to be formatted before display? [default: False]
155 include : list or tuple, optional
155 include : list or tuple, optional
156 A list of format type strings (MIME types) to include in the
156 A list of format type strings (MIME types) to include in the
157 format data dict. If this is set *only* the format types included
157 format data dict. If this is set *only* the format types included
158 in this list will be computed.
158 in this list will be computed.
159 exclude : list or tuple, optional
159 exclude : list or tuple, optional
160 A list of format type strings (MIME types) to exclude in the format
160 A list of format type strings (MIME types) to exclude in the format
161 data dict. If this is set all format types will be computed,
161 data dict. If this is set all format types will be computed,
162 except for those included in this argument.
162 except for those included in this argument.
163 metadata : dict, optional
163 metadata : dict, optional
164 A dictionary of metadata to associate with the output.
164 A dictionary of metadata to associate with the output.
165 mime-type keys in this dictionary will be associated with the individual
165 mime-type keys in this dictionary will be associated with the individual
166 representation formats, if they exist.
166 representation formats, if they exist.
167 transient : dict, optional
167 transient : dict, optional
168 A dictionary of transient data to associate with the output.
168 A dictionary of transient data to associate with the output.
169 Data in this dict should not be persisted to files (e.g. notebooks).
169 Data in this dict should not be persisted to files (e.g. notebooks).
170 display_id : str, optional
170 display_id : str, optional
171 Set an id for the display.
171 Set an id for the display.
172 This id can be used for updating this display area later via update_display.
172 This id can be used for updating this display area later via update_display.
173 If given as True, generate a new display_id
173 If given as True, generate a new display_id
174 kwargs: additional keyword-args, optional
174 kwargs: additional keyword-args, optional
175 Additional keyword-arguments are passed through to the display publisher.
175 Additional keyword-arguments are passed through to the display publisher.
176
176
177 Returns
177 Returns
178 -------
178 -------
179
179
180 handle: DisplayHandle
180 handle: DisplayHandle
181 Returns a handle on updatable displays, if display_id is given.
181 Returns a handle on updatable displays, if display_id is given.
182 Returns None if no display_id is given (default).
182 Returns None if no display_id is given (default).
183 """
183 """
184 raw = kwargs.pop('raw', False)
184 raw = kwargs.pop('raw', False)
185 if transient is None:
185 if transient is None:
186 transient = {}
186 transient = {}
187 if display_id:
187 if display_id:
188 if display_id == True:
188 if display_id == True:
189 display_id = _new_id()
189 display_id = _new_id()
190 transient['display_id'] = display_id
190 transient['display_id'] = display_id
191 if kwargs.get('update') and 'display_id' not in transient:
191 if kwargs.get('update') and 'display_id' not in transient:
192 raise TypeError('display_id required for update_display')
192 raise TypeError('display_id required for update_display')
193 if transient:
193 if transient:
194 kwargs['transient'] = transient
194 kwargs['transient'] = transient
195
195
196 from IPython.core.interactiveshell import InteractiveShell
196 from IPython.core.interactiveshell import InteractiveShell
197
197
198 if not raw:
198 if not raw:
199 format = InteractiveShell.instance().display_formatter.format
199 format = InteractiveShell.instance().display_formatter.format
200
200
201 for obj in objs:
201 for obj in objs:
202 if raw:
202 if raw:
203 publish_display_data(data=obj, metadata=metadata, **kwargs)
203 publish_display_data(data=obj, metadata=metadata, **kwargs)
204 else:
204 else:
205 format_dict, md_dict = format(obj, include=include, exclude=exclude)
205 format_dict, md_dict = format(obj, include=include, exclude=exclude)
206 if not format_dict:
206 if not format_dict:
207 # nothing to display (e.g. _ipython_display_ took over)
207 # nothing to display (e.g. _ipython_display_ took over)
208 continue
208 continue
209 if metadata:
209 if metadata:
210 # kwarg-specified metadata gets precedence
210 # kwarg-specified metadata gets precedence
211 _merge(md_dict, metadata)
211 _merge(md_dict, metadata)
212 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
212 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
213 if display_id:
213 if display_id:
214 return DisplayHandle(display_id)
214 return DisplayHandle(display_id)
215
215
216
216
217 # use * for keyword-only display_id arg
217 # use * for keyword-only display_id arg
218 def update_display(obj, *, display_id, **kwargs):
218 def update_display(obj, *, display_id, **kwargs):
219 """Update an existing display by id
219 """Update an existing display by id
220
220
221 Parameters
221 Parameters
222 ----------
222 ----------
223
223
224 obj:
224 obj:
225 The object with which to update the display
225 The object with which to update the display
226 display_id: keyword-only
226 display_id: keyword-only
227 The id of the display to update
227 The id of the display to update
228 """
228 """
229 kwargs['update'] = True
229 kwargs['update'] = True
230 display(obj, display_id=display_id, **kwargs)
230 display(obj, display_id=display_id, **kwargs)
231
231
232
232
233 class DisplayHandle(object):
233 class DisplayHandle(object):
234 """A handle on an updatable display
234 """A handle on an updatable display
235
235
236 Call .update(obj) to display a new object.
236 Call .update(obj) to display a new object.
237
237
238 Call .display(obj) to add a new instance of this display,
238 Call .display(obj) to add a new instance of this display,
239 and update existing instances.
239 and update existing instances.
240 """
240 """
241
241
242 def __init__(self, display_id=None):
242 def __init__(self, display_id=None):
243 if display_id is None:
243 if display_id is None:
244 display_id = _new_id()
244 display_id = _new_id()
245 self.display_id = display_id
245 self.display_id = display_id
246
246
247 def __repr__(self):
247 def __repr__(self):
248 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
248 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
249
249
250 def display(self, obj, **kwargs):
250 def display(self, obj, **kwargs):
251 """Make a new display with my id, updating existing instances.
251 """Make a new display with my id, updating existing instances.
252
252
253 Parameters
253 Parameters
254 ----------
254 ----------
255
255
256 obj:
256 obj:
257 object to display
257 object to display
258 **kwargs:
258 **kwargs:
259 additional keyword arguments passed to display
259 additional keyword arguments passed to display
260 """
260 """
261 display(obj, display_id=self.display_id, **kwargs)
261 display(obj, display_id=self.display_id, **kwargs)
262
262
263 def update(self, obj, **kwargs):
263 def update(self, obj, **kwargs):
264 """Update existing displays with my id
264 """Update existing displays with my id
265
265
266 Parameters
266 Parameters
267 ----------
267 ----------
268
268
269 obj:
269 obj:
270 object to display
270 object to display
271 **kwargs:
271 **kwargs:
272 additional keyword arguments passed to update_display
272 additional keyword arguments passed to update_display
273 """
273 """
274 update_display(obj, display_id=self.display_id, **kwargs)
274 update_display(obj, display_id=self.display_id, **kwargs)
275
275
276
276
277 def display_pretty(*objs, **kwargs):
277 def display_pretty(*objs, **kwargs):
278 """Display the pretty (default) representation of an object.
278 """Display the pretty (default) representation of an object.
279
279
280 Parameters
280 Parameters
281 ----------
281 ----------
282 objs : tuple of objects
282 objs : tuple of objects
283 The Python objects to display, or if raw=True raw text data to
283 The Python objects to display, or if raw=True raw text data to
284 display.
284 display.
285 raw : bool
285 raw : bool
286 Are the data objects raw data or Python objects that need to be
286 Are the data objects raw data or Python objects that need to be
287 formatted before display? [default: False]
287 formatted before display? [default: False]
288 metadata : dict (optional)
288 metadata : dict (optional)
289 Metadata to be associated with the specific mimetype output.
289 Metadata to be associated with the specific mimetype output.
290 """
290 """
291 _display_mimetype('text/plain', objs, **kwargs)
291 _display_mimetype('text/plain', objs, **kwargs)
292
292
293
293
294 def display_html(*objs, **kwargs):
294 def display_html(*objs, **kwargs):
295 """Display the HTML representation of an object.
295 """Display the HTML representation of an object.
296
296
297 Note: If raw=False and the object does not have a HTML
297 Note: If raw=False and the object does not have a HTML
298 representation, no HTML will be shown.
298 representation, no HTML will be shown.
299
299
300 Parameters
300 Parameters
301 ----------
301 ----------
302 objs : tuple of objects
302 objs : tuple of objects
303 The Python objects to display, or if raw=True raw HTML data to
303 The Python objects to display, or if raw=True raw HTML data to
304 display.
304 display.
305 raw : bool
305 raw : bool
306 Are the data objects raw data or Python objects that need to be
306 Are the data objects raw data or Python objects that need to be
307 formatted before display? [default: False]
307 formatted before display? [default: False]
308 metadata : dict (optional)
308 metadata : dict (optional)
309 Metadata to be associated with the specific mimetype output.
309 Metadata to be associated with the specific mimetype output.
310 """
310 """
311 _display_mimetype('text/html', objs, **kwargs)
311 _display_mimetype('text/html', objs, **kwargs)
312
312
313
313
314 def display_markdown(*objs, **kwargs):
314 def display_markdown(*objs, **kwargs):
315 """Displays the Markdown representation of an object.
315 """Displays the Markdown representation of an object.
316
316
317 Parameters
317 Parameters
318 ----------
318 ----------
319 objs : tuple of objects
319 objs : tuple of objects
320 The Python objects to display, or if raw=True raw markdown data to
320 The Python objects to display, or if raw=True raw markdown data to
321 display.
321 display.
322 raw : bool
322 raw : bool
323 Are the data objects raw data or Python objects that need to be
323 Are the data objects raw data or Python objects that need to be
324 formatted before display? [default: False]
324 formatted before display? [default: False]
325 metadata : dict (optional)
325 metadata : dict (optional)
326 Metadata to be associated with the specific mimetype output.
326 Metadata to be associated with the specific mimetype output.
327 """
327 """
328
328
329 _display_mimetype('text/markdown', objs, **kwargs)
329 _display_mimetype('text/markdown', objs, **kwargs)
330
330
331
331
332 def display_svg(*objs, **kwargs):
332 def display_svg(*objs, **kwargs):
333 """Display the SVG representation of an object.
333 """Display the SVG representation of an object.
334
334
335 Parameters
335 Parameters
336 ----------
336 ----------
337 objs : tuple of objects
337 objs : tuple of objects
338 The Python objects to display, or if raw=True raw svg data to
338 The Python objects to display, or if raw=True raw svg data to
339 display.
339 display.
340 raw : bool
340 raw : bool
341 Are the data objects raw data or Python objects that need to be
341 Are the data objects raw data or Python objects that need to be
342 formatted before display? [default: False]
342 formatted before display? [default: False]
343 metadata : dict (optional)
343 metadata : dict (optional)
344 Metadata to be associated with the specific mimetype output.
344 Metadata to be associated with the specific mimetype output.
345 """
345 """
346 _display_mimetype('image/svg+xml', objs, **kwargs)
346 _display_mimetype('image/svg+xml', objs, **kwargs)
347
347
348
348
349 def display_png(*objs, **kwargs):
349 def display_png(*objs, **kwargs):
350 """Display the PNG representation of an object.
350 """Display the PNG representation of an object.
351
351
352 Parameters
352 Parameters
353 ----------
353 ----------
354 objs : tuple of objects
354 objs : tuple of objects
355 The Python objects to display, or if raw=True raw png data to
355 The Python objects to display, or if raw=True raw png data to
356 display.
356 display.
357 raw : bool
357 raw : bool
358 Are the data objects raw data or Python objects that need to be
358 Are the data objects raw data or Python objects that need to be
359 formatted before display? [default: False]
359 formatted before display? [default: False]
360 metadata : dict (optional)
360 metadata : dict (optional)
361 Metadata to be associated with the specific mimetype output.
361 Metadata to be associated with the specific mimetype output.
362 """
362 """
363 _display_mimetype('image/png', objs, **kwargs)
363 _display_mimetype('image/png', objs, **kwargs)
364
364
365
365
366 def display_jpeg(*objs, **kwargs):
366 def display_jpeg(*objs, **kwargs):
367 """Display the JPEG representation of an object.
367 """Display the JPEG representation of an object.
368
368
369 Parameters
369 Parameters
370 ----------
370 ----------
371 objs : tuple of objects
371 objs : tuple of objects
372 The Python objects to display, or if raw=True raw JPEG data to
372 The Python objects to display, or if raw=True raw JPEG data to
373 display.
373 display.
374 raw : bool
374 raw : bool
375 Are the data objects raw data or Python objects that need to be
375 Are the data objects raw data or Python objects that need to be
376 formatted before display? [default: False]
376 formatted before display? [default: False]
377 metadata : dict (optional)
377 metadata : dict (optional)
378 Metadata to be associated with the specific mimetype output.
378 Metadata to be associated with the specific mimetype output.
379 """
379 """
380 _display_mimetype('image/jpeg', objs, **kwargs)
380 _display_mimetype('image/jpeg', objs, **kwargs)
381
381
382
382
383 def display_latex(*objs, **kwargs):
383 def display_latex(*objs, **kwargs):
384 """Display the LaTeX representation of an object.
384 """Display the LaTeX representation of an object.
385
385
386 Parameters
386 Parameters
387 ----------
387 ----------
388 objs : tuple of objects
388 objs : tuple of objects
389 The Python objects to display, or if raw=True raw latex data to
389 The Python objects to display, or if raw=True raw latex data to
390 display.
390 display.
391 raw : bool
391 raw : bool
392 Are the data objects raw data or Python objects that need to be
392 Are the data objects raw data or Python objects that need to be
393 formatted before display? [default: False]
393 formatted before display? [default: False]
394 metadata : dict (optional)
394 metadata : dict (optional)
395 Metadata to be associated with the specific mimetype output.
395 Metadata to be associated with the specific mimetype output.
396 """
396 """
397 _display_mimetype('text/latex', objs, **kwargs)
397 _display_mimetype('text/latex', objs, **kwargs)
398
398
399
399
400 def display_json(*objs, **kwargs):
400 def display_json(*objs, **kwargs):
401 """Display the JSON representation of an object.
401 """Display the JSON representation of an object.
402
402
403 Note that not many frontends support displaying JSON.
403 Note that not many frontends support displaying JSON.
404
404
405 Parameters
405 Parameters
406 ----------
406 ----------
407 objs : tuple of objects
407 objs : tuple of objects
408 The Python objects to display, or if raw=True raw json data to
408 The Python objects to display, or if raw=True raw json data to
409 display.
409 display.
410 raw : bool
410 raw : bool
411 Are the data objects raw data or Python objects that need to be
411 Are the data objects raw data or Python objects that need to be
412 formatted before display? [default: False]
412 formatted before display? [default: False]
413 metadata : dict (optional)
413 metadata : dict (optional)
414 Metadata to be associated with the specific mimetype output.
414 Metadata to be associated with the specific mimetype output.
415 """
415 """
416 _display_mimetype('application/json', objs, **kwargs)
416 _display_mimetype('application/json', objs, **kwargs)
417
417
418
418
419 def display_javascript(*objs, **kwargs):
419 def display_javascript(*objs, **kwargs):
420 """Display the Javascript representation of an object.
420 """Display the Javascript representation of an object.
421
421
422 Parameters
422 Parameters
423 ----------
423 ----------
424 objs : tuple of objects
424 objs : tuple of objects
425 The Python objects to display, or if raw=True raw javascript data to
425 The Python objects to display, or if raw=True raw javascript data to
426 display.
426 display.
427 raw : bool
427 raw : bool
428 Are the data objects raw data or Python objects that need to be
428 Are the data objects raw data or Python objects that need to be
429 formatted before display? [default: False]
429 formatted before display? [default: False]
430 metadata : dict (optional)
430 metadata : dict (optional)
431 Metadata to be associated with the specific mimetype output.
431 Metadata to be associated with the specific mimetype output.
432 """
432 """
433 _display_mimetype('application/javascript', objs, **kwargs)
433 _display_mimetype('application/javascript', objs, **kwargs)
434
434
435
435
436 def display_pdf(*objs, **kwargs):
436 def display_pdf(*objs, **kwargs):
437 """Display the PDF representation of an object.
437 """Display the PDF representation of an object.
438
438
439 Parameters
439 Parameters
440 ----------
440 ----------
441 objs : tuple of objects
441 objs : tuple of objects
442 The Python objects to display, or if raw=True raw javascript data to
442 The Python objects to display, or if raw=True raw javascript data to
443 display.
443 display.
444 raw : bool
444 raw : bool
445 Are the data objects raw data or Python objects that need to be
445 Are the data objects raw data or Python objects that need to be
446 formatted before display? [default: False]
446 formatted before display? [default: False]
447 metadata : dict (optional)
447 metadata : dict (optional)
448 Metadata to be associated with the specific mimetype output.
448 Metadata to be associated with the specific mimetype output.
449 """
449 """
450 _display_mimetype('application/pdf', objs, **kwargs)
450 _display_mimetype('application/pdf', objs, **kwargs)
451
451
452
452
453 #-----------------------------------------------------------------------------
453 #-----------------------------------------------------------------------------
454 # Smart classes
454 # Smart classes
455 #-----------------------------------------------------------------------------
455 #-----------------------------------------------------------------------------
456
456
457
457
458 class DisplayObject(object):
458 class DisplayObject(object):
459 """An object that wraps data to be displayed."""
459 """An object that wraps data to be displayed."""
460
460
461 _read_flags = 'r'
461 _read_flags = 'r'
462 _show_mem_addr = False
462 _show_mem_addr = False
463
463
464 def __init__(self, data=None, url=None, filename=None):
464 def __init__(self, data=None, url=None, filename=None):
465 """Create a display object given raw data.
465 """Create a display object given raw data.
466
466
467 When this object is returned by an expression or passed to the
467 When this object is returned by an expression or passed to the
468 display function, it will result in the data being displayed
468 display function, it will result in the data being displayed
469 in the frontend. The MIME type of the data should match the
469 in the frontend. The MIME type of the data should match the
470 subclasses used, so the Png subclass should be used for 'image/png'
470 subclasses used, so the Png subclass should be used for 'image/png'
471 data. If the data is a URL, the data will first be downloaded
471 data. If the data is a URL, the data will first be downloaded
472 and then displayed. If
472 and then displayed. If
473
473
474 Parameters
474 Parameters
475 ----------
475 ----------
476 data : unicode, str or bytes
476 data : unicode, str or bytes
477 The raw data or a URL or file to load the data from
477 The raw data or a URL or file to load the data from
478 url : unicode
478 url : unicode
479 A URL to download the data from.
479 A URL to download the data from.
480 filename : unicode
480 filename : unicode
481 Path to a local file to load the data from.
481 Path to a local file to load the data from.
482 """
482 """
483 if data is not None and isinstance(data, str):
483 if data is not None and isinstance(data, str):
484 if data.startswith('http') and url is None:
484 if data.startswith('http') and url is None:
485 url = data
485 url = data
486 filename = None
486 filename = None
487 data = None
487 data = None
488 elif _safe_exists(data) and filename is None:
488 elif _safe_exists(data) and filename is None:
489 url = None
489 url = None
490 filename = data
490 filename = data
491 data = None
491 data = None
492
492
493 self.data = data
493 self.data = data
494 self.url = url
494 self.url = url
495 self.filename = filename
495 self.filename = filename
496
496
497 self.reload()
497 self.reload()
498 self._check_data()
498 self._check_data()
499
499
500 def __repr__(self):
500 def __repr__(self):
501 if not self._show_mem_addr:
501 if not self._show_mem_addr:
502 cls = self.__class__
502 cls = self.__class__
503 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
503 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
504 else:
504 else:
505 r = super(DisplayObject, self).__repr__()
505 r = super(DisplayObject, self).__repr__()
506 return r
506 return r
507
507
508 def _check_data(self):
508 def _check_data(self):
509 """Override in subclasses if there's something to check."""
509 """Override in subclasses if there's something to check."""
510 pass
510 pass
511
511
512 def reload(self):
512 def reload(self):
513 """Reload the raw data from file or URL."""
513 """Reload the raw data from file or URL."""
514 if self.filename is not None:
514 if self.filename is not None:
515 with open(self.filename, self._read_flags) as f:
515 with open(self.filename, self._read_flags) as f:
516 self.data = f.read()
516 self.data = f.read()
517 elif self.url is not None:
517 elif self.url is not None:
518 try:
518 try:
519 # Deferred import
519 # Deferred import
520 from urllib.request import urlopen
520 from urllib.request import urlopen
521 response = urlopen(self.url)
521 response = urlopen(self.url)
522 self.data = response.read()
522 self.data = response.read()
523 # extract encoding from header, if there is one:
523 # extract encoding from header, if there is one:
524 encoding = None
524 encoding = None
525 for sub in response.headers['content-type'].split(';'):
525 for sub in response.headers['content-type'].split(';'):
526 sub = sub.strip()
526 sub = sub.strip()
527 if sub.startswith('charset'):
527 if sub.startswith('charset'):
528 encoding = sub.split('=')[-1].strip()
528 encoding = sub.split('=')[-1].strip()
529 break
529 break
530 # decode data, if an encoding was specified
530 # decode data, if an encoding was specified
531 if encoding:
531 if encoding:
532 self.data = self.data.decode(encoding, 'replace')
532 self.data = self.data.decode(encoding, 'replace')
533 except:
533 except:
534 self.data = None
534 self.data = None
535
535
536 class TextDisplayObject(DisplayObject):
536 class TextDisplayObject(DisplayObject):
537 """Validate that display data is text"""
537 """Validate that display data is text"""
538 def _check_data(self):
538 def _check_data(self):
539 if self.data is not None and not isinstance(self.data, str):
539 if self.data is not None and not isinstance(self.data, str):
540 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
540 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
541
541
542 class Pretty(TextDisplayObject):
542 class Pretty(TextDisplayObject):
543
543
544 def _repr_pretty_(self):
544 def _repr_pretty_(self):
545 return self.data
545 return self.data
546
546
547
547
548 class HTML(TextDisplayObject):
548 class HTML(TextDisplayObject):
549
549
550 def _repr_html_(self):
550 def _repr_html_(self):
551 return self.data
551 return self.data
552
552
553 def __html__(self):
553 def __html__(self):
554 """
554 """
555 This method exists to inform other HTML-using modules (e.g. Markupsafe,
555 This method exists to inform other HTML-using modules (e.g. Markupsafe,
556 htmltag, etc) that this object is HTML and does not need things like
556 htmltag, etc) that this object is HTML and does not need things like
557 special characters (<>&) escaped.
557 special characters (<>&) escaped.
558 """
558 """
559 return self._repr_html_()
559 return self._repr_html_()
560
560
561
561
562 class Markdown(TextDisplayObject):
562 class Markdown(TextDisplayObject):
563
563
564 def _repr_markdown_(self):
564 def _repr_markdown_(self):
565 return self.data
565 return self.data
566
566
567
567
568 class Math(TextDisplayObject):
568 class Math(TextDisplayObject):
569
569
570 def _repr_latex_(self):
570 def _repr_latex_(self):
571 s = self.data.strip('$')
571 s = self.data.strip('$')
572 return "$$%s$$" % s
572 return "$$%s$$" % s
573
573
574
574
575 class Latex(TextDisplayObject):
575 class Latex(TextDisplayObject):
576
576
577 def _repr_latex_(self):
577 def _repr_latex_(self):
578 return self.data
578 return self.data
579
579
580
580
581 class SVG(DisplayObject):
581 class SVG(DisplayObject):
582
582
583 _read_flags = 'rb'
583 _read_flags = 'rb'
584 # wrap data in a property, which extracts the <svg> tag, discarding
584 # wrap data in a property, which extracts the <svg> tag, discarding
585 # document headers
585 # document headers
586 _data = None
586 _data = None
587
587
588 @property
588 @property
589 def data(self):
589 def data(self):
590 return self._data
590 return self._data
591
591
592 @data.setter
592 @data.setter
593 def data(self, svg):
593 def data(self, svg):
594 if svg is None:
594 if svg is None:
595 self._data = None
595 self._data = None
596 return
596 return
597 # parse into dom object
597 # parse into dom object
598 from xml.dom import minidom
598 from xml.dom import minidom
599 svg = cast_bytes_py2(svg)
599 svg = cast_bytes_py2(svg)
600 x = minidom.parseString(svg)
600 x = minidom.parseString(svg)
601 # get svg tag (should be 1)
601 # get svg tag (should be 1)
602 found_svg = x.getElementsByTagName('svg')
602 found_svg = x.getElementsByTagName('svg')
603 if found_svg:
603 if found_svg:
604 svg = found_svg[0].toxml()
604 svg = found_svg[0].toxml()
605 else:
605 else:
606 # fallback on the input, trust the user
606 # fallback on the input, trust the user
607 # but this is probably an error.
607 # but this is probably an error.
608 pass
608 pass
609 svg = cast_unicode(svg)
609 svg = cast_unicode(svg)
610 self._data = svg
610 self._data = svg
611
611
612 def _repr_svg_(self):
612 def _repr_svg_(self):
613 return self.data
613 return self.data
614
614
615
615
616 class JSON(DisplayObject):
616 class JSON(DisplayObject):
617 """JSON expects a JSON-able dict or list
617 """JSON expects a JSON-able dict or list
618
618
619 not an already-serialized JSON string.
619 not an already-serialized JSON string.
620
620
621 Scalar types (None, number, string) are not allowed, only dict or list containers.
621 Scalar types (None, number, string) are not allowed, only dict or list containers.
622 """
622 """
623 # wrap data in a property, which warns about passing already-serialized JSON
623 # wrap data in a property, which warns about passing already-serialized JSON
624 _data = None
624 _data = None
625 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None):
625 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None):
626 """Create a JSON display object given raw data.
626 """Create a JSON display object given raw data.
627
627
628 Parameters
628 Parameters
629 ----------
629 ----------
630 data : dict or list
630 data : dict or list
631 JSON data to display. Not an already-serialized JSON string.
631 JSON data to display. Not an already-serialized JSON string.
632 Scalar types (None, number, string) are not allowed, only dict
632 Scalar types (None, number, string) are not allowed, only dict
633 or list containers.
633 or list containers.
634 url : unicode
634 url : unicode
635 A URL to download the data from.
635 A URL to download the data from.
636 filename : unicode
636 filename : unicode
637 Path to a local file to load the data from.
637 Path to a local file to load the data from.
638 expanded : boolean
638 expanded : boolean
639 Metadata to control whether a JSON display component is expanded.
639 Metadata to control whether a JSON display component is expanded.
640 metadata: dict
640 metadata: dict
641 Specify extra metadata to attach to the json display object.
641 Specify extra metadata to attach to the json display object.
642 """
642 """
643 self.expanded = expanded
643 self.expanded = expanded
644 self.metadata = metadata
644 self.metadata = metadata
645 super(JSON, self).__init__(data=data, url=url, filename=filename)
645 super(JSON, self).__init__(data=data, url=url, filename=filename)
646
646
647 def _check_data(self):
647 def _check_data(self):
648 if self.data is not None and not isinstance(self.data, (dict, list)):
648 if self.data is not None and not isinstance(self.data, (dict, list)):
649 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
649 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
650
650
651 @property
651 @property
652 def data(self):
652 def data(self):
653 return self._data
653 return self._data
654
654
655 @data.setter
655 @data.setter
656 def data(self, data):
656 def data(self, data):
657 if isinstance(data, str):
657 if isinstance(data, str):
658 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
658 if getattr(self, 'filename', None) is None:
659 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
659 data = json.loads(data)
660 data = json.loads(data)
660 self._data = data
661 self._data = data
661
662
662 def _data_and_metadata(self):
663 def _data_and_metadata(self):
663 md = {'expanded': self.expanded}
664 md = {'expanded': self.expanded}
664 if self.metadata:
665 if self.metadata:
665 md.update(self.metadata)
666 md.update(self.metadata)
666 return self.data, md
667 return self.data, md
667
668
668 def _repr_json_(self):
669 def _repr_json_(self):
669 return self._data_and_metadata()
670 return self._data_and_metadata()
670
671
671 css_t = """$("head").append($("<link/>").attr({
672 css_t = """$("head").append($("<link/>").attr({
672 rel: "stylesheet",
673 rel: "stylesheet",
673 type: "text/css",
674 type: "text/css",
674 href: "%s"
675 href: "%s"
675 }));
676 }));
676 """
677 """
677
678
678 lib_t1 = """$.getScript("%s", function () {
679 lib_t1 = """$.getScript("%s", function () {
679 """
680 """
680 lib_t2 = """});
681 lib_t2 = """});
681 """
682 """
682
683
683 class GeoJSON(DisplayObject):
684 class GeoJSON(DisplayObject):
684 """GeoJSON expects JSON-able dict
685 """GeoJSON expects JSON-able dict
685
686
686 not an already-serialized JSON string.
687 not an already-serialized JSON string.
687
688
688 Scalar types (None, number, string) are not allowed, only dict containers.
689 Scalar types (None, number, string) are not allowed, only dict containers.
689 """
690 """
690 # wrap data in a property, which warns about passing already-serialized JSON
691 # wrap data in a property, which warns about passing already-serialized JSON
691 _data = None
692 _data = None
692
693
693 def __init__(self, data=None, url_template=None, layer_options=None, url=None, filename=None, metadata=None):
694 def __init__(self, data=None, url_template=None, layer_options=None, url=None, filename=None, metadata=None):
694 """Create a GeoJSON display object given raw data.
695 """Create a GeoJSON display object given raw data.
695
696
696 Parameters
697 Parameters
697 ----------
698 ----------
698 data : dict or list
699 data : dict or list
699 VegaLite data. Not an already-serialized JSON string.
700 VegaLite data. Not an already-serialized JSON string.
700 Scalar types (None, number, string) are not allowed, only dict
701 Scalar types (None, number, string) are not allowed, only dict
701 or list containers.
702 or list containers.
702 url_template : string
703 url_template : string
703 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
704 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
704 layer_options : dict
705 layer_options : dict
705 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
706 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
706 url : unicode
707 url : unicode
707 A URL to download the data from.
708 A URL to download the data from.
708 filename : unicode
709 filename : unicode
709 Path to a local file to load the data from.
710 Path to a local file to load the data from.
710 metadata: dict
711 metadata: dict
711 Specify extra metadata to attach to the json display object.
712 Specify extra metadata to attach to the json display object.
712
713
713 Examples
714 Examples
714 --------
715 --------
715
716
716 The following will display an interactive map of Mars with a point of
717 The following will display an interactive map of Mars with a point of
717 interest on frontend that do support GeoJSON display.
718 interest on frontend that do support GeoJSON display.
718
719
719 >>> from IPython.display import GeoJSON
720 >>> from IPython.display import GeoJSON
720
721
721 >>> GeoJSON(data={
722 >>> GeoJSON(data={
722 ... "type": "Feature",
723 ... "type": "Feature",
723 ... "geometry": {
724 ... "geometry": {
724 ... "type": "Point",
725 ... "type": "Point",
725 ... "coordinates": [-81.327, 296.038]
726 ... "coordinates": [-81.327, 296.038]
726 ... },
727 ... },
727 ... "properties": {
728 ... "properties": {
728 ... "name": "Inca City"
729 ... "name": "Inca City"
729 ... }
730 ... }
730 ... },
731 ... },
731 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
732 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
732 ... layer_options={
733 ... layer_options={
733 ... "basemap_id": "celestia_mars-shaded-16k_global",
734 ... "basemap_id": "celestia_mars-shaded-16k_global",
734 ... "attribution" : "Celestia/praesepe",
735 ... "attribution" : "Celestia/praesepe",
735 ... "minZoom" : 0,
736 ... "minZoom" : 0,
736 ... "maxZoom" : 18,
737 ... "maxZoom" : 18,
737 ... })
738 ... })
738 <IPython.core.display.GeoJSON object>
739 <IPython.core.display.GeoJSON object>
739
740
740 In the terminal IPython, you will only see the text representation of
741 In the terminal IPython, you will only see the text representation of
741 the GeoJSON object.
742 the GeoJSON object.
742
743
743 """
744 """
744 self.url_template = url_template
745 self.url_template = url_template
745 self.layer_options = layer_options
746 self.layer_options = layer_options
746 self.metadata = metadata
747 self.metadata = metadata
747 super(GeoJSON, self).__init__(data=data, url=url, filename=filename)
748 super(GeoJSON, self).__init__(data=data, url=url, filename=filename)
748
749
749 def _check_data(self):
750 def _check_data(self):
750 if self.data is not None and not isinstance(self.data, dict):
751 if self.data is not None and not isinstance(self.data, dict):
751 raise TypeError("%s expects a JSONable dict, not %r" % (self.__class__.__name__, self.data))
752 raise TypeError("%s expects a JSONable dict, not %r" % (self.__class__.__name__, self.data))
752
753
753 @property
754 @property
754 def data(self):
755 def data(self):
755 return self._data
756 return self._data
756
757
757 @data.setter
758 @data.setter
758 def data(self, data):
759 def data(self, data):
759 if isinstance(data, str):
760 if isinstance(data, str):
761 if getattr(self, 'filename', None) is None:
762 warnings.warn("GeoJSON expects JSONable dict or list, not JSON strings")
760 data = json.loads(data)
763 data = json.loads(data)
761 self._data = data
764 self._data = data
762
765
763 def _ipython_display_(self):
766 def _ipython_display_(self):
764 md = {}
767 md = {}
765 if self.url_template:
768 if self.url_template:
766 md['tileUrlTemplate'] = self.url_template
769 md['tileUrlTemplate'] = self.url_template
767 if self.layer_options:
770 if self.layer_options:
768 md['tileLayerOptions'] = self.layer_options
771 md['tileLayerOptions'] = self.layer_options
769 if self.metadata:
772 if self.metadata:
770 md.update(self.metadata)
773 md.update(self.metadata)
771 bundle = {
774 bundle = {
772 'application/geo+json': self.data,
775 'application/geo+json': self.data,
773 'text/plain': '<jupyterlab_geojson.GeoJSON object>'
776 'text/plain': '<jupyterlab_geojson.GeoJSON object>'
774 }
777 }
775 metadata = {
778 metadata = {
776 'application/geo+json': md
779 'application/geo+json': md
777 }
780 }
778 display(bundle, metadata=metadata, raw=True)
781 display(bundle, metadata=metadata, raw=True)
779
782
780 class Javascript(TextDisplayObject):
783 class Javascript(TextDisplayObject):
781
784
782 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
785 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
783 """Create a Javascript display object given raw data.
786 """Create a Javascript display object given raw data.
784
787
785 When this object is returned by an expression or passed to the
788 When this object is returned by an expression or passed to the
786 display function, it will result in the data being displayed
789 display function, it will result in the data being displayed
787 in the frontend. If the data is a URL, the data will first be
790 in the frontend. If the data is a URL, the data will first be
788 downloaded and then displayed.
791 downloaded and then displayed.
789
792
790 In the Notebook, the containing element will be available as `element`,
793 In the Notebook, the containing element will be available as `element`,
791 and jQuery will be available. Content appended to `element` will be
794 and jQuery will be available. Content appended to `element` will be
792 visible in the output area.
795 visible in the output area.
793
796
794 Parameters
797 Parameters
795 ----------
798 ----------
796 data : unicode, str or bytes
799 data : unicode, str or bytes
797 The Javascript source code or a URL to download it from.
800 The Javascript source code or a URL to download it from.
798 url : unicode
801 url : unicode
799 A URL to download the data from.
802 A URL to download the data from.
800 filename : unicode
803 filename : unicode
801 Path to a local file to load the data from.
804 Path to a local file to load the data from.
802 lib : list or str
805 lib : list or str
803 A sequence of Javascript library URLs to load asynchronously before
806 A sequence of Javascript library URLs to load asynchronously before
804 running the source code. The full URLs of the libraries should
807 running the source code. The full URLs of the libraries should
805 be given. A single Javascript library URL can also be given as a
808 be given. A single Javascript library URL can also be given as a
806 string.
809 string.
807 css: : list or str
810 css: : list or str
808 A sequence of css files to load before running the source code.
811 A sequence of css files to load before running the source code.
809 The full URLs of the css files should be given. A single css URL
812 The full URLs of the css files should be given. A single css URL
810 can also be given as a string.
813 can also be given as a string.
811 """
814 """
812 if isinstance(lib, str):
815 if isinstance(lib, str):
813 lib = [lib]
816 lib = [lib]
814 elif lib is None:
817 elif lib is None:
815 lib = []
818 lib = []
816 if isinstance(css, str):
819 if isinstance(css, str):
817 css = [css]
820 css = [css]
818 elif css is None:
821 elif css is None:
819 css = []
822 css = []
820 if not isinstance(lib, (list,tuple)):
823 if not isinstance(lib, (list,tuple)):
821 raise TypeError('expected sequence, got: %r' % lib)
824 raise TypeError('expected sequence, got: %r' % lib)
822 if not isinstance(css, (list,tuple)):
825 if not isinstance(css, (list,tuple)):
823 raise TypeError('expected sequence, got: %r' % css)
826 raise TypeError('expected sequence, got: %r' % css)
824 self.lib = lib
827 self.lib = lib
825 self.css = css
828 self.css = css
826 super(Javascript, self).__init__(data=data, url=url, filename=filename)
829 super(Javascript, self).__init__(data=data, url=url, filename=filename)
827
830
828 def _repr_javascript_(self):
831 def _repr_javascript_(self):
829 r = ''
832 r = ''
830 for c in self.css:
833 for c in self.css:
831 r += css_t % c
834 r += css_t % c
832 for l in self.lib:
835 for l in self.lib:
833 r += lib_t1 % l
836 r += lib_t1 % l
834 r += self.data
837 r += self.data
835 r += lib_t2*len(self.lib)
838 r += lib_t2*len(self.lib)
836 return r
839 return r
837
840
838 # constants for identifying png/jpeg data
841 # constants for identifying png/jpeg data
839 _PNG = b'\x89PNG\r\n\x1a\n'
842 _PNG = b'\x89PNG\r\n\x1a\n'
840 _JPEG = b'\xff\xd8'
843 _JPEG = b'\xff\xd8'
841
844
842 def _pngxy(data):
845 def _pngxy(data):
843 """read the (width, height) from a PNG header"""
846 """read the (width, height) from a PNG header"""
844 ihdr = data.index(b'IHDR')
847 ihdr = data.index(b'IHDR')
845 # next 8 bytes are width/height
848 # next 8 bytes are width/height
846 w4h4 = data[ihdr+4:ihdr+12]
849 w4h4 = data[ihdr+4:ihdr+12]
847 return struct.unpack('>ii', w4h4)
850 return struct.unpack('>ii', w4h4)
848
851
849 def _jpegxy(data):
852 def _jpegxy(data):
850 """read the (width, height) from a JPEG header"""
853 """read the (width, height) from a JPEG header"""
851 # adapted from http://www.64lines.com/jpeg-width-height
854 # adapted from http://www.64lines.com/jpeg-width-height
852
855
853 idx = 4
856 idx = 4
854 while True:
857 while True:
855 block_size = struct.unpack('>H', data[idx:idx+2])[0]
858 block_size = struct.unpack('>H', data[idx:idx+2])[0]
856 idx = idx + block_size
859 idx = idx + block_size
857 if data[idx:idx+2] == b'\xFF\xC0':
860 if data[idx:idx+2] == b'\xFF\xC0':
858 # found Start of Frame
861 # found Start of Frame
859 iSOF = idx
862 iSOF = idx
860 break
863 break
861 else:
864 else:
862 # read another block
865 # read another block
863 idx += 2
866 idx += 2
864
867
865 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
868 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
866 return w, h
869 return w, h
867
870
868 class Image(DisplayObject):
871 class Image(DisplayObject):
869
872
870 _read_flags = 'rb'
873 _read_flags = 'rb'
871 _FMT_JPEG = u'jpeg'
874 _FMT_JPEG = u'jpeg'
872 _FMT_PNG = u'png'
875 _FMT_PNG = u'png'
873 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
876 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
874
877
875 def __init__(self, data=None, url=None, filename=None, format=None,
878 def __init__(self, data=None, url=None, filename=None, format=None,
876 embed=None, width=None, height=None, retina=False,
879 embed=None, width=None, height=None, retina=False,
877 unconfined=False, metadata=None):
880 unconfined=False, metadata=None):
878 """Create a PNG/JPEG image object given raw data.
881 """Create a PNG/JPEG image object given raw data.
879
882
880 When this object is returned by an input cell or passed to the
883 When this object is returned by an input cell or passed to the
881 display function, it will result in the image being displayed
884 display function, it will result in the image being displayed
882 in the frontend.
885 in the frontend.
883
886
884 Parameters
887 Parameters
885 ----------
888 ----------
886 data : unicode, str or bytes
889 data : unicode, str or bytes
887 The raw image data or a URL or filename to load the data from.
890 The raw image data or a URL or filename to load the data from.
888 This always results in embedded image data.
891 This always results in embedded image data.
889 url : unicode
892 url : unicode
890 A URL to download the data from. If you specify `url=`,
893 A URL to download the data from. If you specify `url=`,
891 the image data will not be embedded unless you also specify `embed=True`.
894 the image data will not be embedded unless you also specify `embed=True`.
892 filename : unicode
895 filename : unicode
893 Path to a local file to load the data from.
896 Path to a local file to load the data from.
894 Images from a file are always embedded.
897 Images from a file are always embedded.
895 format : unicode
898 format : unicode
896 The format of the image data (png/jpeg/jpg). If a filename or URL is given
899 The format of the image data (png/jpeg/jpg). If a filename or URL is given
897 for format will be inferred from the filename extension.
900 for format will be inferred from the filename extension.
898 embed : bool
901 embed : bool
899 Should the image data be embedded using a data URI (True) or be
902 Should the image data be embedded using a data URI (True) or be
900 loaded using an <img> tag. Set this to True if you want the image
903 loaded using an <img> tag. Set this to True if you want the image
901 to be viewable later with no internet connection in the notebook.
904 to be viewable later with no internet connection in the notebook.
902
905
903 Default is `True`, unless the keyword argument `url` is set, then
906 Default is `True`, unless the keyword argument `url` is set, then
904 default value is `False`.
907 default value is `False`.
905
908
906 Note that QtConsole is not able to display images if `embed` is set to `False`
909 Note that QtConsole is not able to display images if `embed` is set to `False`
907 width : int
910 width : int
908 Width in pixels to which to constrain the image in html
911 Width in pixels to which to constrain the image in html
909 height : int
912 height : int
910 Height in pixels to which to constrain the image in html
913 Height in pixels to which to constrain the image in html
911 retina : bool
914 retina : bool
912 Automatically set the width and height to half of the measured
915 Automatically set the width and height to half of the measured
913 width and height.
916 width and height.
914 This only works for embedded images because it reads the width/height
917 This only works for embedded images because it reads the width/height
915 from image data.
918 from image data.
916 For non-embedded images, you can just set the desired display width
919 For non-embedded images, you can just set the desired display width
917 and height directly.
920 and height directly.
918 unconfined: bool
921 unconfined: bool
919 Set unconfined=True to disable max-width confinement of the image.
922 Set unconfined=True to disable max-width confinement of the image.
920 metadata: dict
923 metadata: dict
921 Specify extra metadata to attach to the image.
924 Specify extra metadata to attach to the image.
922
925
923 Examples
926 Examples
924 --------
927 --------
925 # embedded image data, works in qtconsole and notebook
928 # embedded image data, works in qtconsole and notebook
926 # when passed positionally, the first arg can be any of raw image data,
929 # when passed positionally, the first arg can be any of raw image data,
927 # a URL, or a filename from which to load image data.
930 # a URL, or a filename from which to load image data.
928 # The result is always embedding image data for inline images.
931 # The result is always embedding image data for inline images.
929 Image('http://www.google.fr/images/srpr/logo3w.png')
932 Image('http://www.google.fr/images/srpr/logo3w.png')
930 Image('/path/to/image.jpg')
933 Image('/path/to/image.jpg')
931 Image(b'RAW_PNG_DATA...')
934 Image(b'RAW_PNG_DATA...')
932
935
933 # Specifying Image(url=...) does not embed the image data,
936 # Specifying Image(url=...) does not embed the image data,
934 # it only generates `<img>` tag with a link to the source.
937 # it only generates `<img>` tag with a link to the source.
935 # This will not work in the qtconsole or offline.
938 # This will not work in the qtconsole or offline.
936 Image(url='http://www.google.fr/images/srpr/logo3w.png')
939 Image(url='http://www.google.fr/images/srpr/logo3w.png')
937
940
938 """
941 """
939 if filename is not None:
942 if filename is not None:
940 ext = self._find_ext(filename)
943 ext = self._find_ext(filename)
941 elif url is not None:
944 elif url is not None:
942 ext = self._find_ext(url)
945 ext = self._find_ext(url)
943 elif data is None:
946 elif data is None:
944 raise ValueError("No image data found. Expecting filename, url, or data.")
947 raise ValueError("No image data found. Expecting filename, url, or data.")
945 elif isinstance(data, str) and (
948 elif isinstance(data, str) and (
946 data.startswith('http') or _safe_exists(data)
949 data.startswith('http') or _safe_exists(data)
947 ):
950 ):
948 ext = self._find_ext(data)
951 ext = self._find_ext(data)
949 else:
952 else:
950 ext = None
953 ext = None
951
954
952 if format is None:
955 if format is None:
953 if ext is not None:
956 if ext is not None:
954 if ext == u'jpg' or ext == u'jpeg':
957 if ext == u'jpg' or ext == u'jpeg':
955 format = self._FMT_JPEG
958 format = self._FMT_JPEG
956 if ext == u'png':
959 if ext == u'png':
957 format = self._FMT_PNG
960 format = self._FMT_PNG
958 else:
961 else:
959 format = ext.lower()
962 format = ext.lower()
960 elif isinstance(data, bytes):
963 elif isinstance(data, bytes):
961 # infer image type from image data header,
964 # infer image type from image data header,
962 # only if format has not been specified.
965 # only if format has not been specified.
963 if data[:2] == _JPEG:
966 if data[:2] == _JPEG:
964 format = self._FMT_JPEG
967 format = self._FMT_JPEG
965
968
966 # failed to detect format, default png
969 # failed to detect format, default png
967 if format is None:
970 if format is None:
968 format = 'png'
971 format = 'png'
969
972
970 if format.lower() == 'jpg':
973 if format.lower() == 'jpg':
971 # jpg->jpeg
974 # jpg->jpeg
972 format = self._FMT_JPEG
975 format = self._FMT_JPEG
973
976
974 self.format = format.lower()
977 self.format = format.lower()
975 self.embed = embed if embed is not None else (url is None)
978 self.embed = embed if embed is not None else (url is None)
976
979
977 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
980 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
978 raise ValueError("Cannot embed the '%s' image format" % (self.format))
981 raise ValueError("Cannot embed the '%s' image format" % (self.format))
979 self.width = width
982 self.width = width
980 self.height = height
983 self.height = height
981 self.retina = retina
984 self.retina = retina
982 self.unconfined = unconfined
985 self.unconfined = unconfined
983 self.metadata = metadata
986 self.metadata = metadata
984 super(Image, self).__init__(data=data, url=url, filename=filename)
987 super(Image, self).__init__(data=data, url=url, filename=filename)
985
988
986 if retina:
989 if retina:
987 self._retina_shape()
990 self._retina_shape()
988
991
989 def _retina_shape(self):
992 def _retina_shape(self):
990 """load pixel-doubled width and height from image data"""
993 """load pixel-doubled width and height from image data"""
991 if not self.embed:
994 if not self.embed:
992 return
995 return
993 if self.format == 'png':
996 if self.format == 'png':
994 w, h = _pngxy(self.data)
997 w, h = _pngxy(self.data)
995 elif self.format == 'jpeg':
998 elif self.format == 'jpeg':
996 w, h = _jpegxy(self.data)
999 w, h = _jpegxy(self.data)
997 else:
1000 else:
998 # retina only supports png
1001 # retina only supports png
999 return
1002 return
1000 self.width = w // 2
1003 self.width = w // 2
1001 self.height = h // 2
1004 self.height = h // 2
1002
1005
1003 def reload(self):
1006 def reload(self):
1004 """Reload the raw data from file or URL."""
1007 """Reload the raw data from file or URL."""
1005 if self.embed:
1008 if self.embed:
1006 super(Image,self).reload()
1009 super(Image,self).reload()
1007 if self.retina:
1010 if self.retina:
1008 self._retina_shape()
1011 self._retina_shape()
1009
1012
1010 def _repr_html_(self):
1013 def _repr_html_(self):
1011 if not self.embed:
1014 if not self.embed:
1012 width = height = klass = ''
1015 width = height = klass = ''
1013 if self.width:
1016 if self.width:
1014 width = ' width="%d"' % self.width
1017 width = ' width="%d"' % self.width
1015 if self.height:
1018 if self.height:
1016 height = ' height="%d"' % self.height
1019 height = ' height="%d"' % self.height
1017 if self.unconfined:
1020 if self.unconfined:
1018 klass = ' class="unconfined"'
1021 klass = ' class="unconfined"'
1019 return u'<img src="{url}"{width}{height}{klass}/>'.format(
1022 return u'<img src="{url}"{width}{height}{klass}/>'.format(
1020 url=self.url,
1023 url=self.url,
1021 width=width,
1024 width=width,
1022 height=height,
1025 height=height,
1023 klass=klass,
1026 klass=klass,
1024 )
1027 )
1025
1028
1026 def _data_and_metadata(self):
1029 def _data_and_metadata(self):
1027 """shortcut for returning metadata with shape information, if defined"""
1030 """shortcut for returning metadata with shape information, if defined"""
1028 md = {}
1031 md = {}
1029 if self.width:
1032 if self.width:
1030 md['width'] = self.width
1033 md['width'] = self.width
1031 if self.height:
1034 if self.height:
1032 md['height'] = self.height
1035 md['height'] = self.height
1033 if self.unconfined:
1036 if self.unconfined:
1034 md['unconfined'] = self.unconfined
1037 md['unconfined'] = self.unconfined
1035 if self.metadata:
1038 if self.metadata:
1036 md.update(self.metadata)
1039 md.update(self.metadata)
1037 if md:
1040 if md:
1038 return self.data, md
1041 return self.data, md
1039 else:
1042 else:
1040 return self.data
1043 return self.data
1041
1044
1042 def _repr_png_(self):
1045 def _repr_png_(self):
1043 if self.embed and self.format == u'png':
1046 if self.embed and self.format == u'png':
1044 return self._data_and_metadata()
1047 return self._data_and_metadata()
1045
1048
1046 def _repr_jpeg_(self):
1049 def _repr_jpeg_(self):
1047 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
1050 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
1048 return self._data_and_metadata()
1051 return self._data_and_metadata()
1049
1052
1050 def _find_ext(self, s):
1053 def _find_ext(self, s):
1051 return s.split('.')[-1].lower()
1054 return s.split('.')[-1].lower()
1052
1055
1053 class Video(DisplayObject):
1056 class Video(DisplayObject):
1054
1057
1055 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
1058 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
1056 """Create a video object given raw data or an URL.
1059 """Create a video object given raw data or an URL.
1057
1060
1058 When this object is returned by an input cell or passed to the
1061 When this object is returned by an input cell or passed to the
1059 display function, it will result in the video being displayed
1062 display function, it will result in the video being displayed
1060 in the frontend.
1063 in the frontend.
1061
1064
1062 Parameters
1065 Parameters
1063 ----------
1066 ----------
1064 data : unicode, str or bytes
1067 data : unicode, str or bytes
1065 The raw video data or a URL or filename to load the data from.
1068 The raw video data or a URL or filename to load the data from.
1066 Raw data will require passing `embed=True`.
1069 Raw data will require passing `embed=True`.
1067 url : unicode
1070 url : unicode
1068 A URL for the video. If you specify `url=`,
1071 A URL for the video. If you specify `url=`,
1069 the image data will not be embedded.
1072 the image data will not be embedded.
1070 filename : unicode
1073 filename : unicode
1071 Path to a local file containing the video.
1074 Path to a local file containing the video.
1072 Will be interpreted as a local URL unless `embed=True`.
1075 Will be interpreted as a local URL unless `embed=True`.
1073 embed : bool
1076 embed : bool
1074 Should the video be embedded using a data URI (True) or be
1077 Should the video be embedded using a data URI (True) or be
1075 loaded using a <video> tag (False).
1078 loaded using a <video> tag (False).
1076
1079
1077 Since videos are large, embedding them should be avoided, if possible.
1080 Since videos are large, embedding them should be avoided, if possible.
1078 You must confirm embedding as your intention by passing `embed=True`.
1081 You must confirm embedding as your intention by passing `embed=True`.
1079
1082
1080 Local files can be displayed with URLs without embedding the content, via::
1083 Local files can be displayed with URLs without embedding the content, via::
1081
1084
1082 Video('./video.mp4')
1085 Video('./video.mp4')
1083
1086
1084 mimetype: unicode
1087 mimetype: unicode
1085 Specify the mimetype for embedded videos.
1088 Specify the mimetype for embedded videos.
1086 Default will be guessed from file extension, if available.
1089 Default will be guessed from file extension, if available.
1087
1090
1088 Examples
1091 Examples
1089 --------
1092 --------
1090
1093
1091 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1094 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1092 Video('path/to/video.mp4')
1095 Video('path/to/video.mp4')
1093 Video('path/to/video.mp4', embed=True)
1096 Video('path/to/video.mp4', embed=True)
1094 Video(b'raw-videodata', embed=True)
1097 Video(b'raw-videodata', embed=True)
1095 """
1098 """
1096 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1099 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1097 url = data
1100 url = data
1098 data = None
1101 data = None
1099 elif os.path.exists(data):
1102 elif os.path.exists(data):
1100 filename = data
1103 filename = data
1101 data = None
1104 data = None
1102
1105
1103 if data and not embed:
1106 if data and not embed:
1104 msg = ''.join([
1107 msg = ''.join([
1105 "To embed videos, you must pass embed=True ",
1108 "To embed videos, you must pass embed=True ",
1106 "(this may make your notebook files huge)\n",
1109 "(this may make your notebook files huge)\n",
1107 "Consider passing Video(url='...')",
1110 "Consider passing Video(url='...')",
1108 ])
1111 ])
1109 raise ValueError(msg)
1112 raise ValueError(msg)
1110
1113
1111 self.mimetype = mimetype
1114 self.mimetype = mimetype
1112 self.embed = embed
1115 self.embed = embed
1113 super(Video, self).__init__(data=data, url=url, filename=filename)
1116 super(Video, self).__init__(data=data, url=url, filename=filename)
1114
1117
1115 def _repr_html_(self):
1118 def _repr_html_(self):
1116 # External URLs and potentially local files are not embedded into the
1119 # External URLs and potentially local files are not embedded into the
1117 # notebook output.
1120 # notebook output.
1118 if not self.embed:
1121 if not self.embed:
1119 url = self.url if self.url is not None else self.filename
1122 url = self.url if self.url is not None else self.filename
1120 output = """<video src="{0}" controls>
1123 output = """<video src="{0}" controls>
1121 Your browser does not support the <code>video</code> element.
1124 Your browser does not support the <code>video</code> element.
1122 </video>""".format(url)
1125 </video>""".format(url)
1123 return output
1126 return output
1124
1127
1125 # Embedded videos are base64-encoded.
1128 # Embedded videos are base64-encoded.
1126 mimetype = self.mimetype
1129 mimetype = self.mimetype
1127 if self.filename is not None:
1130 if self.filename is not None:
1128 if not mimetype:
1131 if not mimetype:
1129 mimetype, _ = mimetypes.guess_type(self.filename)
1132 mimetype, _ = mimetypes.guess_type(self.filename)
1130
1133
1131 with open(self.filename, 'rb') as f:
1134 with open(self.filename, 'rb') as f:
1132 video = f.read()
1135 video = f.read()
1133 else:
1136 else:
1134 video = self.data
1137 video = self.data
1135 if isinstance(video, str):
1138 if isinstance(video, str):
1136 # unicode input is already b64-encoded
1139 # unicode input is already b64-encoded
1137 b64_video = video
1140 b64_video = video
1138 else:
1141 else:
1139 b64_video = base64_encode(video).decode('ascii').rstrip()
1142 b64_video = base64_encode(video).decode('ascii').rstrip()
1140
1143
1141 output = """<video controls>
1144 output = """<video controls>
1142 <source src="data:{0};base64,{1}" type="{0}">
1145 <source src="data:{0};base64,{1}" type="{0}">
1143 Your browser does not support the video tag.
1146 Your browser does not support the video tag.
1144 </video>""".format(mimetype, b64_video)
1147 </video>""".format(mimetype, b64_video)
1145 return output
1148 return output
1146
1149
1147 def reload(self):
1150 def reload(self):
1148 # TODO
1151 # TODO
1149 pass
1152 pass
1150
1153
1151 def _repr_png_(self):
1154 def _repr_png_(self):
1152 # TODO
1155 # TODO
1153 pass
1156 pass
1154 def _repr_jpeg_(self):
1157 def _repr_jpeg_(self):
1155 # TODO
1158 # TODO
1156 pass
1159 pass
1157
1160
1158 def clear_output(wait=False):
1161 def clear_output(wait=False):
1159 """Clear the output of the current cell receiving output.
1162 """Clear the output of the current cell receiving output.
1160
1163
1161 Parameters
1164 Parameters
1162 ----------
1165 ----------
1163 wait : bool [default: false]
1166 wait : bool [default: false]
1164 Wait to clear the output until new output is available to replace it."""
1167 Wait to clear the output until new output is available to replace it."""
1165 from IPython.core.interactiveshell import InteractiveShell
1168 from IPython.core.interactiveshell import InteractiveShell
1166 if InteractiveShell.initialized():
1169 if InteractiveShell.initialized():
1167 InteractiveShell.instance().display_pub.clear_output(wait)
1170 InteractiveShell.instance().display_pub.clear_output(wait)
1168 else:
1171 else:
1169 print('\033[2K\r', end='')
1172 print('\033[2K\r', end='')
1170 sys.stdout.flush()
1173 sys.stdout.flush()
1171 print('\033[2K\r', end='')
1174 print('\033[2K\r', end='')
1172 sys.stderr.flush()
1175 sys.stderr.flush()
1173
1176
1174
1177
1175 @skip_doctest
1178 @skip_doctest
1176 def set_matplotlib_formats(*formats, **kwargs):
1179 def set_matplotlib_formats(*formats, **kwargs):
1177 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1180 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1178
1181
1179 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1182 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1180
1183
1181 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1184 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1182
1185
1183 To set this in your config files use the following::
1186 To set this in your config files use the following::
1184
1187
1185 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1188 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1186 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1189 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1187
1190
1188 Parameters
1191 Parameters
1189 ----------
1192 ----------
1190 *formats : strs
1193 *formats : strs
1191 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1194 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1192 **kwargs :
1195 **kwargs :
1193 Keyword args will be relayed to ``figure.canvas.print_figure``.
1196 Keyword args will be relayed to ``figure.canvas.print_figure``.
1194 """
1197 """
1195 from IPython.core.interactiveshell import InteractiveShell
1198 from IPython.core.interactiveshell import InteractiveShell
1196 from IPython.core.pylabtools import select_figure_formats
1199 from IPython.core.pylabtools import select_figure_formats
1197 # build kwargs, starting with InlineBackend config
1200 # build kwargs, starting with InlineBackend config
1198 kw = {}
1201 kw = {}
1199 from ipykernel.pylab.config import InlineBackend
1202 from ipykernel.pylab.config import InlineBackend
1200 cfg = InlineBackend.instance()
1203 cfg = InlineBackend.instance()
1201 kw.update(cfg.print_figure_kwargs)
1204 kw.update(cfg.print_figure_kwargs)
1202 kw.update(**kwargs)
1205 kw.update(**kwargs)
1203 shell = InteractiveShell.instance()
1206 shell = InteractiveShell.instance()
1204 select_figure_formats(shell, formats, **kw)
1207 select_figure_formats(shell, formats, **kw)
1205
1208
1206 @skip_doctest
1209 @skip_doctest
1207 def set_matplotlib_close(close=True):
1210 def set_matplotlib_close(close=True):
1208 """Set whether the inline backend closes all figures automatically or not.
1211 """Set whether the inline backend closes all figures automatically or not.
1209
1212
1210 By default, the inline backend used in the IPython Notebook will close all
1213 By default, the inline backend used in the IPython Notebook will close all
1211 matplotlib figures automatically after each cell is run. This means that
1214 matplotlib figures automatically after each cell is run. This means that
1212 plots in different cells won't interfere. Sometimes, you may want to make
1215 plots in different cells won't interfere. Sometimes, you may want to make
1213 a plot in one cell and then refine it in later cells. This can be accomplished
1216 a plot in one cell and then refine it in later cells. This can be accomplished
1214 by::
1217 by::
1215
1218
1216 In [1]: set_matplotlib_close(False)
1219 In [1]: set_matplotlib_close(False)
1217
1220
1218 To set this in your config files use the following::
1221 To set this in your config files use the following::
1219
1222
1220 c.InlineBackend.close_figures = False
1223 c.InlineBackend.close_figures = False
1221
1224
1222 Parameters
1225 Parameters
1223 ----------
1226 ----------
1224 close : bool
1227 close : bool
1225 Should all matplotlib figures be automatically closed after each cell is
1228 Should all matplotlib figures be automatically closed after each cell is
1226 run?
1229 run?
1227 """
1230 """
1228 from ipykernel.pylab.config import InlineBackend
1231 from ipykernel.pylab.config import InlineBackend
1229 cfg = InlineBackend.instance()
1232 cfg = InlineBackend.instance()
1230 cfg.close_figures = close
1233 cfg.close_figures = close
General Comments 0
You need to be logged in to leave comments. Login now