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