##// END OF EJS Templates
Merge pull request #11907 from vidartf/empty_display...
Matthias Bussonnier -
r25201:d262f0c4 merge
parent child Browse files
Show More
@@ -1,1490 +1,1497 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 : tuple of objects
60 objs : tuple of objects
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 : tuple of objects
142 objs : tuple of objects
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:
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
302 # can be updated later
303 objs = [{}]
304 raw = True
305
299 if not raw:
306 if not raw:
300 format = InteractiveShell.instance().display_formatter.format
307 format = InteractiveShell.instance().display_formatter.format
301
308
302 for obj in objs:
309 for obj in objs:
303 if raw:
310 if raw:
304 publish_display_data(data=obj, metadata=metadata, **kwargs)
311 publish_display_data(data=obj, metadata=metadata, **kwargs)
305 else:
312 else:
306 format_dict, md_dict = format(obj, include=include, exclude=exclude)
313 format_dict, md_dict = format(obj, include=include, exclude=exclude)
307 if not format_dict:
314 if not format_dict:
308 # nothing to display (e.g. _ipython_display_ took over)
315 # nothing to display (e.g. _ipython_display_ took over)
309 continue
316 continue
310 if metadata:
317 if metadata:
311 # kwarg-specified metadata gets precedence
318 # kwarg-specified metadata gets precedence
312 _merge(md_dict, metadata)
319 _merge(md_dict, metadata)
313 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
320 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
314 if display_id:
321 if display_id:
315 return DisplayHandle(display_id)
322 return DisplayHandle(display_id)
316
323
317
324
318 # use * for keyword-only display_id arg
325 # use * for keyword-only display_id arg
319 def update_display(obj, *, display_id, **kwargs):
326 def update_display(obj, *, display_id, **kwargs):
320 """Update an existing display by id
327 """Update an existing display by id
321
328
322 Parameters
329 Parameters
323 ----------
330 ----------
324
331
325 obj:
332 obj:
326 The object with which to update the display
333 The object with which to update the display
327 display_id: keyword-only
334 display_id: keyword-only
328 The id of the display to update
335 The id of the display to update
329
336
330 See Also
337 See Also
331 --------
338 --------
332
339
333 :func:`display`
340 :func:`display`
334 """
341 """
335 kwargs['update'] = True
342 kwargs['update'] = True
336 display(obj, display_id=display_id, **kwargs)
343 display(obj, display_id=display_id, **kwargs)
337
344
338
345
339 class DisplayHandle(object):
346 class DisplayHandle(object):
340 """A handle on an updatable display
347 """A handle on an updatable display
341
348
342 Call `.update(obj)` to display a new object.
349 Call `.update(obj)` to display a new object.
343
350
344 Call `.display(obj`) to add a new instance of this display,
351 Call `.display(obj`) to add a new instance of this display,
345 and update existing instances.
352 and update existing instances.
346
353
347 See Also
354 See Also
348 --------
355 --------
349
356
350 :func:`display`, :func:`update_display`
357 :func:`display`, :func:`update_display`
351
358
352 """
359 """
353
360
354 def __init__(self, display_id=None):
361 def __init__(self, display_id=None):
355 if display_id is None:
362 if display_id is None:
356 display_id = _new_id()
363 display_id = _new_id()
357 self.display_id = display_id
364 self.display_id = display_id
358
365
359 def __repr__(self):
366 def __repr__(self):
360 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
367 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
361
368
362 def display(self, obj, **kwargs):
369 def display(self, obj, **kwargs):
363 """Make a new display with my id, updating existing instances.
370 """Make a new display with my id, updating existing instances.
364
371
365 Parameters
372 Parameters
366 ----------
373 ----------
367
374
368 obj:
375 obj:
369 object to display
376 object to display
370 **kwargs:
377 **kwargs:
371 additional keyword arguments passed to display
378 additional keyword arguments passed to display
372 """
379 """
373 display(obj, display_id=self.display_id, **kwargs)
380 display(obj, display_id=self.display_id, **kwargs)
374
381
375 def update(self, obj, **kwargs):
382 def update(self, obj, **kwargs):
376 """Update existing displays with my id
383 """Update existing displays with my id
377
384
378 Parameters
385 Parameters
379 ----------
386 ----------
380
387
381 obj:
388 obj:
382 object to display
389 object to display
383 **kwargs:
390 **kwargs:
384 additional keyword arguments passed to update_display
391 additional keyword arguments passed to update_display
385 """
392 """
386 update_display(obj, display_id=self.display_id, **kwargs)
393 update_display(obj, display_id=self.display_id, **kwargs)
387
394
388
395
389 def display_pretty(*objs, **kwargs):
396 def display_pretty(*objs, **kwargs):
390 """Display the pretty (default) representation of an object.
397 """Display the pretty (default) representation of an object.
391
398
392 Parameters
399 Parameters
393 ----------
400 ----------
394 objs : tuple of objects
401 objs : tuple of objects
395 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
396 display.
403 display.
397 raw : bool
404 raw : bool
398 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
399 formatted before display? [default: False]
406 formatted before display? [default: False]
400 metadata : dict (optional)
407 metadata : dict (optional)
401 Metadata to be associated with the specific mimetype output.
408 Metadata to be associated with the specific mimetype output.
402 """
409 """
403 _display_mimetype('text/plain', objs, **kwargs)
410 _display_mimetype('text/plain', objs, **kwargs)
404
411
405
412
406 def display_html(*objs, **kwargs):
413 def display_html(*objs, **kwargs):
407 """Display the HTML representation of an object.
414 """Display the HTML representation of an object.
408
415
409 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
410 representation, no HTML will be shown.
417 representation, no HTML will be shown.
411
418
412 Parameters
419 Parameters
413 ----------
420 ----------
414 objs : tuple of objects
421 objs : tuple of objects
415 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
416 display.
423 display.
417 raw : bool
424 raw : bool
418 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
419 formatted before display? [default: False]
426 formatted before display? [default: False]
420 metadata : dict (optional)
427 metadata : dict (optional)
421 Metadata to be associated with the specific mimetype output.
428 Metadata to be associated with the specific mimetype output.
422 """
429 """
423 _display_mimetype('text/html', objs, **kwargs)
430 _display_mimetype('text/html', objs, **kwargs)
424
431
425
432
426 def display_markdown(*objs, **kwargs):
433 def display_markdown(*objs, **kwargs):
427 """Displays the Markdown representation of an object.
434 """Displays the Markdown representation of an object.
428
435
429 Parameters
436 Parameters
430 ----------
437 ----------
431 objs : tuple of objects
438 objs : tuple of objects
432 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
433 display.
440 display.
434 raw : bool
441 raw : bool
435 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
436 formatted before display? [default: False]
443 formatted before display? [default: False]
437 metadata : dict (optional)
444 metadata : dict (optional)
438 Metadata to be associated with the specific mimetype output.
445 Metadata to be associated with the specific mimetype output.
439 """
446 """
440
447
441 _display_mimetype('text/markdown', objs, **kwargs)
448 _display_mimetype('text/markdown', objs, **kwargs)
442
449
443
450
444 def display_svg(*objs, **kwargs):
451 def display_svg(*objs, **kwargs):
445 """Display the SVG representation of an object.
452 """Display the SVG representation of an object.
446
453
447 Parameters
454 Parameters
448 ----------
455 ----------
449 objs : tuple of objects
456 objs : tuple of objects
450 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
451 display.
458 display.
452 raw : bool
459 raw : bool
453 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
454 formatted before display? [default: False]
461 formatted before display? [default: False]
455 metadata : dict (optional)
462 metadata : dict (optional)
456 Metadata to be associated with the specific mimetype output.
463 Metadata to be associated with the specific mimetype output.
457 """
464 """
458 _display_mimetype('image/svg+xml', objs, **kwargs)
465 _display_mimetype('image/svg+xml', objs, **kwargs)
459
466
460
467
461 def display_png(*objs, **kwargs):
468 def display_png(*objs, **kwargs):
462 """Display the PNG representation of an object.
469 """Display the PNG representation of an object.
463
470
464 Parameters
471 Parameters
465 ----------
472 ----------
466 objs : tuple of objects
473 objs : tuple of objects
467 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
468 display.
475 display.
469 raw : bool
476 raw : bool
470 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
471 formatted before display? [default: False]
478 formatted before display? [default: False]
472 metadata : dict (optional)
479 metadata : dict (optional)
473 Metadata to be associated with the specific mimetype output.
480 Metadata to be associated with the specific mimetype output.
474 """
481 """
475 _display_mimetype('image/png', objs, **kwargs)
482 _display_mimetype('image/png', objs, **kwargs)
476
483
477
484
478 def display_jpeg(*objs, **kwargs):
485 def display_jpeg(*objs, **kwargs):
479 """Display the JPEG representation of an object.
486 """Display the JPEG representation of an object.
480
487
481 Parameters
488 Parameters
482 ----------
489 ----------
483 objs : tuple of objects
490 objs : tuple of objects
484 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
485 display.
492 display.
486 raw : bool
493 raw : bool
487 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
488 formatted before display? [default: False]
495 formatted before display? [default: False]
489 metadata : dict (optional)
496 metadata : dict (optional)
490 Metadata to be associated with the specific mimetype output.
497 Metadata to be associated with the specific mimetype output.
491 """
498 """
492 _display_mimetype('image/jpeg', objs, **kwargs)
499 _display_mimetype('image/jpeg', objs, **kwargs)
493
500
494
501
495 def display_latex(*objs, **kwargs):
502 def display_latex(*objs, **kwargs):
496 """Display the LaTeX representation of an object.
503 """Display the LaTeX representation of an object.
497
504
498 Parameters
505 Parameters
499 ----------
506 ----------
500 objs : tuple of objects
507 objs : tuple of objects
501 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
502 display.
509 display.
503 raw : bool
510 raw : bool
504 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
505 formatted before display? [default: False]
512 formatted before display? [default: False]
506 metadata : dict (optional)
513 metadata : dict (optional)
507 Metadata to be associated with the specific mimetype output.
514 Metadata to be associated with the specific mimetype output.
508 """
515 """
509 _display_mimetype('text/latex', objs, **kwargs)
516 _display_mimetype('text/latex', objs, **kwargs)
510
517
511
518
512 def display_json(*objs, **kwargs):
519 def display_json(*objs, **kwargs):
513 """Display the JSON representation of an object.
520 """Display the JSON representation of an object.
514
521
515 Note that not many frontends support displaying JSON.
522 Note that not many frontends support displaying JSON.
516
523
517 Parameters
524 Parameters
518 ----------
525 ----------
519 objs : tuple of objects
526 objs : tuple of objects
520 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
521 display.
528 display.
522 raw : bool
529 raw : bool
523 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
524 formatted before display? [default: False]
531 formatted before display? [default: False]
525 metadata : dict (optional)
532 metadata : dict (optional)
526 Metadata to be associated with the specific mimetype output.
533 Metadata to be associated with the specific mimetype output.
527 """
534 """
528 _display_mimetype('application/json', objs, **kwargs)
535 _display_mimetype('application/json', objs, **kwargs)
529
536
530
537
531 def display_javascript(*objs, **kwargs):
538 def display_javascript(*objs, **kwargs):
532 """Display the Javascript representation of an object.
539 """Display the Javascript representation of an object.
533
540
534 Parameters
541 Parameters
535 ----------
542 ----------
536 objs : tuple of objects
543 objs : tuple of objects
537 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
538 display.
545 display.
539 raw : bool
546 raw : bool
540 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
541 formatted before display? [default: False]
548 formatted before display? [default: False]
542 metadata : dict (optional)
549 metadata : dict (optional)
543 Metadata to be associated with the specific mimetype output.
550 Metadata to be associated with the specific mimetype output.
544 """
551 """
545 _display_mimetype('application/javascript', objs, **kwargs)
552 _display_mimetype('application/javascript', objs, **kwargs)
546
553
547
554
548 def display_pdf(*objs, **kwargs):
555 def display_pdf(*objs, **kwargs):
549 """Display the PDF representation of an object.
556 """Display the PDF representation of an object.
550
557
551 Parameters
558 Parameters
552 ----------
559 ----------
553 objs : tuple of objects
560 objs : tuple of objects
554 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
555 display.
562 display.
556 raw : bool
563 raw : bool
557 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
558 formatted before display? [default: False]
565 formatted before display? [default: False]
559 metadata : dict (optional)
566 metadata : dict (optional)
560 Metadata to be associated with the specific mimetype output.
567 Metadata to be associated with the specific mimetype output.
561 """
568 """
562 _display_mimetype('application/pdf', objs, **kwargs)
569 _display_mimetype('application/pdf', objs, **kwargs)
563
570
564
571
565 #-----------------------------------------------------------------------------
572 #-----------------------------------------------------------------------------
566 # Smart classes
573 # Smart classes
567 #-----------------------------------------------------------------------------
574 #-----------------------------------------------------------------------------
568
575
569
576
570 class DisplayObject(object):
577 class DisplayObject(object):
571 """An object that wraps data to be displayed."""
578 """An object that wraps data to be displayed."""
572
579
573 _read_flags = 'r'
580 _read_flags = 'r'
574 _show_mem_addr = False
581 _show_mem_addr = False
575 metadata = None
582 metadata = None
576
583
577 def __init__(self, data=None, url=None, filename=None, metadata=None):
584 def __init__(self, data=None, url=None, filename=None, metadata=None):
578 """Create a display object given raw data.
585 """Create a display object given raw data.
579
586
580 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
581 display function, it will result in the data being displayed
588 display function, it will result in the data being displayed
582 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
583 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'
584 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
585 and then displayed. If
592 and then displayed. If
586
593
587 Parameters
594 Parameters
588 ----------
595 ----------
589 data : unicode, str or bytes
596 data : unicode, str or bytes
590 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
591 url : unicode
598 url : unicode
592 A URL to download the data from.
599 A URL to download the data from.
593 filename : unicode
600 filename : unicode
594 Path to a local file to load the data from.
601 Path to a local file to load the data from.
595 metadata : dict
602 metadata : dict
596 Dict of metadata associated to be the object when displayed
603 Dict of metadata associated to be the object when displayed
597 """
604 """
598 if isinstance(data, (Path, PurePath)):
605 if isinstance(data, (Path, PurePath)):
599 data = str(data)
606 data = str(data)
600
607
601 if data is not None and isinstance(data, str):
608 if data is not None and isinstance(data, str):
602 if data.startswith('http') and url is None:
609 if data.startswith('http') and url is None:
603 url = data
610 url = data
604 filename = None
611 filename = None
605 data = None
612 data = None
606 elif _safe_exists(data) and filename is None:
613 elif _safe_exists(data) and filename is None:
607 url = None
614 url = None
608 filename = data
615 filename = data
609 data = None
616 data = None
610
617
611 self.data = data
618 self.data = data
612 self.url = url
619 self.url = url
613 self.filename = filename
620 self.filename = filename
614
621
615 if metadata is not None:
622 if metadata is not None:
616 self.metadata = metadata
623 self.metadata = metadata
617 elif self.metadata is None:
624 elif self.metadata is None:
618 self.metadata = {}
625 self.metadata = {}
619
626
620 self.reload()
627 self.reload()
621 self._check_data()
628 self._check_data()
622
629
623 def __repr__(self):
630 def __repr__(self):
624 if not self._show_mem_addr:
631 if not self._show_mem_addr:
625 cls = self.__class__
632 cls = self.__class__
626 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
633 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
627 else:
634 else:
628 r = super(DisplayObject, self).__repr__()
635 r = super(DisplayObject, self).__repr__()
629 return r
636 return r
630
637
631 def _check_data(self):
638 def _check_data(self):
632 """Override in subclasses if there's something to check."""
639 """Override in subclasses if there's something to check."""
633 pass
640 pass
634
641
635 def _data_and_metadata(self):
642 def _data_and_metadata(self):
636 """shortcut for returning metadata with shape information, if defined"""
643 """shortcut for returning metadata with shape information, if defined"""
637 if self.metadata:
644 if self.metadata:
638 return self.data, deepcopy(self.metadata)
645 return self.data, deepcopy(self.metadata)
639 else:
646 else:
640 return self.data
647 return self.data
641
648
642 def reload(self):
649 def reload(self):
643 """Reload the raw data from file or URL."""
650 """Reload the raw data from file or URL."""
644 if self.filename is not None:
651 if self.filename is not None:
645 with open(self.filename, self._read_flags) as f:
652 with open(self.filename, self._read_flags) as f:
646 self.data = f.read()
653 self.data = f.read()
647 elif self.url is not None:
654 elif self.url is not None:
648 try:
655 try:
649 # Deferred import
656 # Deferred import
650 from urllib.request import urlopen
657 from urllib.request import urlopen
651 response = urlopen(self.url)
658 response = urlopen(self.url)
652 self.data = response.read()
659 self.data = response.read()
653 # extract encoding from header, if there is one:
660 # extract encoding from header, if there is one:
654 encoding = None
661 encoding = None
655 for sub in response.headers['content-type'].split(';'):
662 for sub in response.headers['content-type'].split(';'):
656 sub = sub.strip()
663 sub = sub.strip()
657 if sub.startswith('charset'):
664 if sub.startswith('charset'):
658 encoding = sub.split('=')[-1].strip()
665 encoding = sub.split('=')[-1].strip()
659 break
666 break
660 # decode data, if an encoding was specified
667 # decode data, if an encoding was specified
661 if encoding:
668 if encoding:
662 self.data = self.data.decode(encoding, 'replace')
669 self.data = self.data.decode(encoding, 'replace')
663 except:
670 except:
664 self.data = None
671 self.data = None
665
672
666 class TextDisplayObject(DisplayObject):
673 class TextDisplayObject(DisplayObject):
667 """Validate that display data is text"""
674 """Validate that display data is text"""
668 def _check_data(self):
675 def _check_data(self):
669 if self.data is not None and not isinstance(self.data, str):
676 if self.data is not None and not isinstance(self.data, str):
670 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
677 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
671
678
672 class Pretty(TextDisplayObject):
679 class Pretty(TextDisplayObject):
673
680
674 def _repr_pretty_(self, pp, cycle):
681 def _repr_pretty_(self, pp, cycle):
675 return pp.text(self.data)
682 return pp.text(self.data)
676
683
677
684
678 class HTML(TextDisplayObject):
685 class HTML(TextDisplayObject):
679
686
680 def __init__(self, data=None, url=None, filename=None, metadata=None):
687 def __init__(self, data=None, url=None, filename=None, metadata=None):
681 def warn():
688 def warn():
682 if not data:
689 if not data:
683 return False
690 return False
684
691
685 #
692 #
686 # Avoid calling lower() on the entire data, because it could be a
693 # Avoid calling lower() on the entire data, because it could be a
687 # long string and we're only interested in its beginning and end.
694 # long string and we're only interested in its beginning and end.
688 #
695 #
689 prefix = data[:10].lower()
696 prefix = data[:10].lower()
690 suffix = data[-10:].lower()
697 suffix = data[-10:].lower()
691 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
698 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
692
699
693 if warn():
700 if warn():
694 warnings.warn("Consider using IPython.display.IFrame instead")
701 warnings.warn("Consider using IPython.display.IFrame instead")
695 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
702 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
696
703
697 def _repr_html_(self):
704 def _repr_html_(self):
698 return self._data_and_metadata()
705 return self._data_and_metadata()
699
706
700 def __html__(self):
707 def __html__(self):
701 """
708 """
702 This method exists to inform other HTML-using modules (e.g. Markupsafe,
709 This method exists to inform other HTML-using modules (e.g. Markupsafe,
703 htmltag, etc) that this object is HTML and does not need things like
710 htmltag, etc) that this object is HTML and does not need things like
704 special characters (<>&) escaped.
711 special characters (<>&) escaped.
705 """
712 """
706 return self._repr_html_()
713 return self._repr_html_()
707
714
708
715
709 class Markdown(TextDisplayObject):
716 class Markdown(TextDisplayObject):
710
717
711 def _repr_markdown_(self):
718 def _repr_markdown_(self):
712 return self._data_and_metadata()
719 return self._data_and_metadata()
713
720
714
721
715 class Math(TextDisplayObject):
722 class Math(TextDisplayObject):
716
723
717 def _repr_latex_(self):
724 def _repr_latex_(self):
718 s = r"$\displaystyle %s$" % self.data.strip('$')
725 s = r"$\displaystyle %s$" % self.data.strip('$')
719 if self.metadata:
726 if self.metadata:
720 return s, deepcopy(self.metadata)
727 return s, deepcopy(self.metadata)
721 else:
728 else:
722 return s
729 return s
723
730
724
731
725 class Latex(TextDisplayObject):
732 class Latex(TextDisplayObject):
726
733
727 def _repr_latex_(self):
734 def _repr_latex_(self):
728 return self._data_and_metadata()
735 return self._data_and_metadata()
729
736
730
737
731 class SVG(DisplayObject):
738 class SVG(DisplayObject):
732
739
733 _read_flags = 'rb'
740 _read_flags = 'rb'
734 # wrap data in a property, which extracts the <svg> tag, discarding
741 # wrap data in a property, which extracts the <svg> tag, discarding
735 # document headers
742 # document headers
736 _data = None
743 _data = None
737
744
738 @property
745 @property
739 def data(self):
746 def data(self):
740 return self._data
747 return self._data
741
748
742 @data.setter
749 @data.setter
743 def data(self, svg):
750 def data(self, svg):
744 if svg is None:
751 if svg is None:
745 self._data = None
752 self._data = None
746 return
753 return
747 # parse into dom object
754 # parse into dom object
748 from xml.dom import minidom
755 from xml.dom import minidom
749 x = minidom.parseString(svg)
756 x = minidom.parseString(svg)
750 # get svg tag (should be 1)
757 # get svg tag (should be 1)
751 found_svg = x.getElementsByTagName('svg')
758 found_svg = x.getElementsByTagName('svg')
752 if found_svg:
759 if found_svg:
753 svg = found_svg[0].toxml()
760 svg = found_svg[0].toxml()
754 else:
761 else:
755 # fallback on the input, trust the user
762 # fallback on the input, trust the user
756 # but this is probably an error.
763 # but this is probably an error.
757 pass
764 pass
758 svg = cast_unicode(svg)
765 svg = cast_unicode(svg)
759 self._data = svg
766 self._data = svg
760
767
761 def _repr_svg_(self):
768 def _repr_svg_(self):
762 return self._data_and_metadata()
769 return self._data_and_metadata()
763
770
764 class ProgressBar(DisplayObject):
771 class ProgressBar(DisplayObject):
765 """Progressbar supports displaying a progressbar like element
772 """Progressbar supports displaying a progressbar like element
766 """
773 """
767 def __init__(self, total):
774 def __init__(self, total):
768 """Creates a new progressbar
775 """Creates a new progressbar
769
776
770 Parameters
777 Parameters
771 ----------
778 ----------
772 total : int
779 total : int
773 maximum size of the progressbar
780 maximum size of the progressbar
774 """
781 """
775 self.total = total
782 self.total = total
776 self._progress = 0
783 self._progress = 0
777 self.html_width = '60ex'
784 self.html_width = '60ex'
778 self.text_width = 60
785 self.text_width = 60
779 self._display_id = hexlify(os.urandom(8)).decode('ascii')
786 self._display_id = hexlify(os.urandom(8)).decode('ascii')
780
787
781 def __repr__(self):
788 def __repr__(self):
782 fraction = self.progress / self.total
789 fraction = self.progress / self.total
783 filled = '=' * int(fraction * self.text_width)
790 filled = '=' * int(fraction * self.text_width)
784 rest = ' ' * (self.text_width - len(filled))
791 rest = ' ' * (self.text_width - len(filled))
785 return '[{}{}] {}/{}'.format(
792 return '[{}{}] {}/{}'.format(
786 filled, rest,
793 filled, rest,
787 self.progress, self.total,
794 self.progress, self.total,
788 )
795 )
789
796
790 def _repr_html_(self):
797 def _repr_html_(self):
791 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
798 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
792 self.html_width, self.total, self.progress)
799 self.html_width, self.total, self.progress)
793
800
794 def display(self):
801 def display(self):
795 display(self, display_id=self._display_id)
802 display(self, display_id=self._display_id)
796
803
797 def update(self):
804 def update(self):
798 display(self, display_id=self._display_id, update=True)
805 display(self, display_id=self._display_id, update=True)
799
806
800 @property
807 @property
801 def progress(self):
808 def progress(self):
802 return self._progress
809 return self._progress
803
810
804 @progress.setter
811 @progress.setter
805 def progress(self, value):
812 def progress(self, value):
806 self._progress = value
813 self._progress = value
807 self.update()
814 self.update()
808
815
809 def __iter__(self):
816 def __iter__(self):
810 self.display()
817 self.display()
811 self._progress = -1 # First iteration is 0
818 self._progress = -1 # First iteration is 0
812 return self
819 return self
813
820
814 def __next__(self):
821 def __next__(self):
815 """Returns current value and increments display by one."""
822 """Returns current value and increments display by one."""
816 self.progress += 1
823 self.progress += 1
817 if self.progress < self.total:
824 if self.progress < self.total:
818 return self.progress
825 return self.progress
819 else:
826 else:
820 raise StopIteration()
827 raise StopIteration()
821
828
822 class JSON(DisplayObject):
829 class JSON(DisplayObject):
823 """JSON expects a JSON-able dict or list
830 """JSON expects a JSON-able dict or list
824
831
825 not an already-serialized JSON string.
832 not an already-serialized JSON string.
826
833
827 Scalar types (None, number, string) are not allowed, only dict or list containers.
834 Scalar types (None, number, string) are not allowed, only dict or list containers.
828 """
835 """
829 # wrap data in a property, which warns about passing already-serialized JSON
836 # wrap data in a property, which warns about passing already-serialized JSON
830 _data = None
837 _data = None
831 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
838 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
832 """Create a JSON display object given raw data.
839 """Create a JSON display object given raw data.
833
840
834 Parameters
841 Parameters
835 ----------
842 ----------
836 data : dict or list
843 data : dict or list
837 JSON data to display. Not an already-serialized JSON string.
844 JSON data to display. Not an already-serialized JSON string.
838 Scalar types (None, number, string) are not allowed, only dict
845 Scalar types (None, number, string) are not allowed, only dict
839 or list containers.
846 or list containers.
840 url : unicode
847 url : unicode
841 A URL to download the data from.
848 A URL to download the data from.
842 filename : unicode
849 filename : unicode
843 Path to a local file to load the data from.
850 Path to a local file to load the data from.
844 expanded : boolean
851 expanded : boolean
845 Metadata to control whether a JSON display component is expanded.
852 Metadata to control whether a JSON display component is expanded.
846 metadata: dict
853 metadata: dict
847 Specify extra metadata to attach to the json display object.
854 Specify extra metadata to attach to the json display object.
848 root : str
855 root : str
849 The name of the root element of the JSON tree
856 The name of the root element of the JSON tree
850 """
857 """
851 self.metadata = {
858 self.metadata = {
852 'expanded': expanded,
859 'expanded': expanded,
853 'root': root,
860 'root': root,
854 }
861 }
855 if metadata:
862 if metadata:
856 self.metadata.update(metadata)
863 self.metadata.update(metadata)
857 if kwargs:
864 if kwargs:
858 self.metadata.update(kwargs)
865 self.metadata.update(kwargs)
859 super(JSON, self).__init__(data=data, url=url, filename=filename)
866 super(JSON, self).__init__(data=data, url=url, filename=filename)
860
867
861 def _check_data(self):
868 def _check_data(self):
862 if self.data is not None and not isinstance(self.data, (dict, list)):
869 if self.data is not None and not isinstance(self.data, (dict, list)):
863 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
870 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
864
871
865 @property
872 @property
866 def data(self):
873 def data(self):
867 return self._data
874 return self._data
868
875
869 @data.setter
876 @data.setter
870 def data(self, data):
877 def data(self, data):
871 if isinstance(data, (Path, PurePath)):
878 if isinstance(data, (Path, PurePath)):
872 data = str(data)
879 data = str(data)
873
880
874 if isinstance(data, str):
881 if isinstance(data, str):
875 if getattr(self, 'filename', None) is None:
882 if getattr(self, 'filename', None) is None:
876 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
883 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
877 data = json.loads(data)
884 data = json.loads(data)
878 self._data = data
885 self._data = data
879
886
880 def _data_and_metadata(self):
887 def _data_and_metadata(self):
881 return self.data, self.metadata
888 return self.data, self.metadata
882
889
883 def _repr_json_(self):
890 def _repr_json_(self):
884 return self._data_and_metadata()
891 return self._data_and_metadata()
885
892
886 _css_t = """var link = document.createElement("link");
893 _css_t = """var link = document.createElement("link");
887 link.ref = "stylesheet";
894 link.ref = "stylesheet";
888 link.type = "text/css";
895 link.type = "text/css";
889 link.href = "%s";
896 link.href = "%s";
890 document.head.appendChild(link);
897 document.head.appendChild(link);
891 """
898 """
892
899
893 _lib_t1 = """new Promise(function(resolve, reject) {
900 _lib_t1 = """new Promise(function(resolve, reject) {
894 var script = document.createElement("script");
901 var script = document.createElement("script");
895 script.onload = resolve;
902 script.onload = resolve;
896 script.onerror = reject;
903 script.onerror = reject;
897 script.src = "%s";
904 script.src = "%s";
898 document.head.appendChild(script);
905 document.head.appendChild(script);
899 }).then(() => {
906 }).then(() => {
900 """
907 """
901
908
902 _lib_t2 = """
909 _lib_t2 = """
903 });"""
910 });"""
904
911
905 class GeoJSON(JSON):
912 class GeoJSON(JSON):
906 """GeoJSON expects JSON-able dict
913 """GeoJSON expects JSON-able dict
907
914
908 not an already-serialized JSON string.
915 not an already-serialized JSON string.
909
916
910 Scalar types (None, number, string) are not allowed, only dict containers.
917 Scalar types (None, number, string) are not allowed, only dict containers.
911 """
918 """
912
919
913 def __init__(self, *args, **kwargs):
920 def __init__(self, *args, **kwargs):
914 """Create a GeoJSON display object given raw data.
921 """Create a GeoJSON display object given raw data.
915
922
916 Parameters
923 Parameters
917 ----------
924 ----------
918 data : dict or list
925 data : dict or list
919 VegaLite data. Not an already-serialized JSON string.
926 VegaLite data. Not an already-serialized JSON string.
920 Scalar types (None, number, string) are not allowed, only dict
927 Scalar types (None, number, string) are not allowed, only dict
921 or list containers.
928 or list containers.
922 url_template : string
929 url_template : string
923 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
930 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
924 layer_options : dict
931 layer_options : dict
925 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
932 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
926 url : unicode
933 url : unicode
927 A URL to download the data from.
934 A URL to download the data from.
928 filename : unicode
935 filename : unicode
929 Path to a local file to load the data from.
936 Path to a local file to load the data from.
930 metadata: dict
937 metadata: dict
931 Specify extra metadata to attach to the json display object.
938 Specify extra metadata to attach to the json display object.
932
939
933 Examples
940 Examples
934 --------
941 --------
935
942
936 The following will display an interactive map of Mars with a point of
943 The following will display an interactive map of Mars with a point of
937 interest on frontend that do support GeoJSON display.
944 interest on frontend that do support GeoJSON display.
938
945
939 >>> from IPython.display import GeoJSON
946 >>> from IPython.display import GeoJSON
940
947
941 >>> GeoJSON(data={
948 >>> GeoJSON(data={
942 ... "type": "Feature",
949 ... "type": "Feature",
943 ... "geometry": {
950 ... "geometry": {
944 ... "type": "Point",
951 ... "type": "Point",
945 ... "coordinates": [-81.327, 296.038]
952 ... "coordinates": [-81.327, 296.038]
946 ... }
953 ... }
947 ... },
954 ... },
948 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
955 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
949 ... layer_options={
956 ... layer_options={
950 ... "basemap_id": "celestia_mars-shaded-16k_global",
957 ... "basemap_id": "celestia_mars-shaded-16k_global",
951 ... "attribution" : "Celestia/praesepe",
958 ... "attribution" : "Celestia/praesepe",
952 ... "minZoom" : 0,
959 ... "minZoom" : 0,
953 ... "maxZoom" : 18,
960 ... "maxZoom" : 18,
954 ... })
961 ... })
955 <IPython.core.display.GeoJSON object>
962 <IPython.core.display.GeoJSON object>
956
963
957 In the terminal IPython, you will only see the text representation of
964 In the terminal IPython, you will only see the text representation of
958 the GeoJSON object.
965 the GeoJSON object.
959
966
960 """
967 """
961
968
962 super(GeoJSON, self).__init__(*args, **kwargs)
969 super(GeoJSON, self).__init__(*args, **kwargs)
963
970
964
971
965 def _ipython_display_(self):
972 def _ipython_display_(self):
966 bundle = {
973 bundle = {
967 'application/geo+json': self.data,
974 'application/geo+json': self.data,
968 'text/plain': '<IPython.display.GeoJSON object>'
975 'text/plain': '<IPython.display.GeoJSON object>'
969 }
976 }
970 metadata = {
977 metadata = {
971 'application/geo+json': self.metadata
978 'application/geo+json': self.metadata
972 }
979 }
973 display(bundle, metadata=metadata, raw=True)
980 display(bundle, metadata=metadata, raw=True)
974
981
975 class Javascript(TextDisplayObject):
982 class Javascript(TextDisplayObject):
976
983
977 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
984 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
978 """Create a Javascript display object given raw data.
985 """Create a Javascript display object given raw data.
979
986
980 When this object is returned by an expression or passed to the
987 When this object is returned by an expression or passed to the
981 display function, it will result in the data being displayed
988 display function, it will result in the data being displayed
982 in the frontend. If the data is a URL, the data will first be
989 in the frontend. If the data is a URL, the data will first be
983 downloaded and then displayed.
990 downloaded and then displayed.
984
991
985 In the Notebook, the containing element will be available as `element`,
992 In the Notebook, the containing element will be available as `element`,
986 and jQuery will be available. Content appended to `element` will be
993 and jQuery will be available. Content appended to `element` will be
987 visible in the output area.
994 visible in the output area.
988
995
989 Parameters
996 Parameters
990 ----------
997 ----------
991 data : unicode, str or bytes
998 data : unicode, str or bytes
992 The Javascript source code or a URL to download it from.
999 The Javascript source code or a URL to download it from.
993 url : unicode
1000 url : unicode
994 A URL to download the data from.
1001 A URL to download the data from.
995 filename : unicode
1002 filename : unicode
996 Path to a local file to load the data from.
1003 Path to a local file to load the data from.
997 lib : list or str
1004 lib : list or str
998 A sequence of Javascript library URLs to load asynchronously before
1005 A sequence of Javascript library URLs to load asynchronously before
999 running the source code. The full URLs of the libraries should
1006 running the source code. The full URLs of the libraries should
1000 be given. A single Javascript library URL can also be given as a
1007 be given. A single Javascript library URL can also be given as a
1001 string.
1008 string.
1002 css: : list or str
1009 css: : list or str
1003 A sequence of css files to load before running the source code.
1010 A sequence of css files to load before running the source code.
1004 The full URLs of the css files should be given. A single css URL
1011 The full URLs of the css files should be given. A single css URL
1005 can also be given as a string.
1012 can also be given as a string.
1006 """
1013 """
1007 if isinstance(lib, str):
1014 if isinstance(lib, str):
1008 lib = [lib]
1015 lib = [lib]
1009 elif lib is None:
1016 elif lib is None:
1010 lib = []
1017 lib = []
1011 if isinstance(css, str):
1018 if isinstance(css, str):
1012 css = [css]
1019 css = [css]
1013 elif css is None:
1020 elif css is None:
1014 css = []
1021 css = []
1015 if not isinstance(lib, (list,tuple)):
1022 if not isinstance(lib, (list,tuple)):
1016 raise TypeError('expected sequence, got: %r' % lib)
1023 raise TypeError('expected sequence, got: %r' % lib)
1017 if not isinstance(css, (list,tuple)):
1024 if not isinstance(css, (list,tuple)):
1018 raise TypeError('expected sequence, got: %r' % css)
1025 raise TypeError('expected sequence, got: %r' % css)
1019 self.lib = lib
1026 self.lib = lib
1020 self.css = css
1027 self.css = css
1021 super(Javascript, self).__init__(data=data, url=url, filename=filename)
1028 super(Javascript, self).__init__(data=data, url=url, filename=filename)
1022
1029
1023 def _repr_javascript_(self):
1030 def _repr_javascript_(self):
1024 r = ''
1031 r = ''
1025 for c in self.css:
1032 for c in self.css:
1026 r += _css_t % c
1033 r += _css_t % c
1027 for l in self.lib:
1034 for l in self.lib:
1028 r += _lib_t1 % l
1035 r += _lib_t1 % l
1029 r += self.data
1036 r += self.data
1030 r += _lib_t2*len(self.lib)
1037 r += _lib_t2*len(self.lib)
1031 return r
1038 return r
1032
1039
1033 # constants for identifying png/jpeg data
1040 # constants for identifying png/jpeg data
1034 _PNG = b'\x89PNG\r\n\x1a\n'
1041 _PNG = b'\x89PNG\r\n\x1a\n'
1035 _JPEG = b'\xff\xd8'
1042 _JPEG = b'\xff\xd8'
1036
1043
1037 def _pngxy(data):
1044 def _pngxy(data):
1038 """read the (width, height) from a PNG header"""
1045 """read the (width, height) from a PNG header"""
1039 ihdr = data.index(b'IHDR')
1046 ihdr = data.index(b'IHDR')
1040 # next 8 bytes are width/height
1047 # next 8 bytes are width/height
1041 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
1048 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
1042
1049
1043 def _jpegxy(data):
1050 def _jpegxy(data):
1044 """read the (width, height) from a JPEG header"""
1051 """read the (width, height) from a JPEG header"""
1045 # adapted from http://www.64lines.com/jpeg-width-height
1052 # adapted from http://www.64lines.com/jpeg-width-height
1046
1053
1047 idx = 4
1054 idx = 4
1048 while True:
1055 while True:
1049 block_size = struct.unpack('>H', data[idx:idx+2])[0]
1056 block_size = struct.unpack('>H', data[idx:idx+2])[0]
1050 idx = idx + block_size
1057 idx = idx + block_size
1051 if data[idx:idx+2] == b'\xFF\xC0':
1058 if data[idx:idx+2] == b'\xFF\xC0':
1052 # found Start of Frame
1059 # found Start of Frame
1053 iSOF = idx
1060 iSOF = idx
1054 break
1061 break
1055 else:
1062 else:
1056 # read another block
1063 # read another block
1057 idx += 2
1064 idx += 2
1058
1065
1059 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
1066 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
1060 return w, h
1067 return w, h
1061
1068
1062 def _gifxy(data):
1069 def _gifxy(data):
1063 """read the (width, height) from a GIF header"""
1070 """read the (width, height) from a GIF header"""
1064 return struct.unpack('<HH', data[6:10])
1071 return struct.unpack('<HH', data[6:10])
1065
1072
1066
1073
1067 class Image(DisplayObject):
1074 class Image(DisplayObject):
1068
1075
1069 _read_flags = 'rb'
1076 _read_flags = 'rb'
1070 _FMT_JPEG = u'jpeg'
1077 _FMT_JPEG = u'jpeg'
1071 _FMT_PNG = u'png'
1078 _FMT_PNG = u'png'
1072 _FMT_GIF = u'gif'
1079 _FMT_GIF = u'gif'
1073 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
1080 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
1074 _MIMETYPES = {
1081 _MIMETYPES = {
1075 _FMT_PNG: 'image/png',
1082 _FMT_PNG: 'image/png',
1076 _FMT_JPEG: 'image/jpeg',
1083 _FMT_JPEG: 'image/jpeg',
1077 _FMT_GIF: 'image/gif',
1084 _FMT_GIF: 'image/gif',
1078 }
1085 }
1079
1086
1080 def __init__(self, data=None, url=None, filename=None, format=None,
1087 def __init__(self, data=None, url=None, filename=None, format=None,
1081 embed=None, width=None, height=None, retina=False,
1088 embed=None, width=None, height=None, retina=False,
1082 unconfined=False, metadata=None):
1089 unconfined=False, metadata=None):
1083 """Create a PNG/JPEG/GIF image object given raw data.
1090 """Create a PNG/JPEG/GIF image object given raw data.
1084
1091
1085 When this object is returned by an input cell or passed to the
1092 When this object is returned by an input cell or passed to the
1086 display function, it will result in the image being displayed
1093 display function, it will result in the image being displayed
1087 in the frontend.
1094 in the frontend.
1088
1095
1089 Parameters
1096 Parameters
1090 ----------
1097 ----------
1091 data : unicode, str or bytes
1098 data : unicode, str or bytes
1092 The raw image data or a URL or filename to load the data from.
1099 The raw image data or a URL or filename to load the data from.
1093 This always results in embedded image data.
1100 This always results in embedded image data.
1094 url : unicode
1101 url : unicode
1095 A URL to download the data from. If you specify `url=`,
1102 A URL to download the data from. If you specify `url=`,
1096 the image data will not be embedded unless you also specify `embed=True`.
1103 the image data will not be embedded unless you also specify `embed=True`.
1097 filename : unicode
1104 filename : unicode
1098 Path to a local file to load the data from.
1105 Path to a local file to load the data from.
1099 Images from a file are always embedded.
1106 Images from a file are always embedded.
1100 format : unicode
1107 format : unicode
1101 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
1108 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
1102 for format will be inferred from the filename extension.
1109 for format will be inferred from the filename extension.
1103 embed : bool
1110 embed : bool
1104 Should the image data be embedded using a data URI (True) or be
1111 Should the image data be embedded using a data URI (True) or be
1105 loaded using an <img> tag. Set this to True if you want the image
1112 loaded using an <img> tag. Set this to True if you want the image
1106 to be viewable later with no internet connection in the notebook.
1113 to be viewable later with no internet connection in the notebook.
1107
1114
1108 Default is `True`, unless the keyword argument `url` is set, then
1115 Default is `True`, unless the keyword argument `url` is set, then
1109 default value is `False`.
1116 default value is `False`.
1110
1117
1111 Note that QtConsole is not able to display images if `embed` is set to `False`
1118 Note that QtConsole is not able to display images if `embed` is set to `False`
1112 width : int
1119 width : int
1113 Width in pixels to which to constrain the image in html
1120 Width in pixels to which to constrain the image in html
1114 height : int
1121 height : int
1115 Height in pixels to which to constrain the image in html
1122 Height in pixels to which to constrain the image in html
1116 retina : bool
1123 retina : bool
1117 Automatically set the width and height to half of the measured
1124 Automatically set the width and height to half of the measured
1118 width and height.
1125 width and height.
1119 This only works for embedded images because it reads the width/height
1126 This only works for embedded images because it reads the width/height
1120 from image data.
1127 from image data.
1121 For non-embedded images, you can just set the desired display width
1128 For non-embedded images, you can just set the desired display width
1122 and height directly.
1129 and height directly.
1123 unconfined: bool
1130 unconfined: bool
1124 Set unconfined=True to disable max-width confinement of the image.
1131 Set unconfined=True to disable max-width confinement of the image.
1125 metadata: dict
1132 metadata: dict
1126 Specify extra metadata to attach to the image.
1133 Specify extra metadata to attach to the image.
1127
1134
1128 Examples
1135 Examples
1129 --------
1136 --------
1130 # embedded image data, works in qtconsole and notebook
1137 # embedded image data, works in qtconsole and notebook
1131 # when passed positionally, the first arg can be any of raw image data,
1138 # when passed positionally, the first arg can be any of raw image data,
1132 # a URL, or a filename from which to load image data.
1139 # a URL, or a filename from which to load image data.
1133 # The result is always embedding image data for inline images.
1140 # The result is always embedding image data for inline images.
1134 Image('http://www.google.fr/images/srpr/logo3w.png')
1141 Image('http://www.google.fr/images/srpr/logo3w.png')
1135 Image('/path/to/image.jpg')
1142 Image('/path/to/image.jpg')
1136 Image(b'RAW_PNG_DATA...')
1143 Image(b'RAW_PNG_DATA...')
1137
1144
1138 # Specifying Image(url=...) does not embed the image data,
1145 # Specifying Image(url=...) does not embed the image data,
1139 # it only generates `<img>` tag with a link to the source.
1146 # it only generates `<img>` tag with a link to the source.
1140 # This will not work in the qtconsole or offline.
1147 # This will not work in the qtconsole or offline.
1141 Image(url='http://www.google.fr/images/srpr/logo3w.png')
1148 Image(url='http://www.google.fr/images/srpr/logo3w.png')
1142
1149
1143 """
1150 """
1144 if isinstance(data, (Path, PurePath)):
1151 if isinstance(data, (Path, PurePath)):
1145 data = str(data)
1152 data = str(data)
1146
1153
1147 if filename is not None:
1154 if filename is not None:
1148 ext = self._find_ext(filename)
1155 ext = self._find_ext(filename)
1149 elif url is not None:
1156 elif url is not None:
1150 ext = self._find_ext(url)
1157 ext = self._find_ext(url)
1151 elif data is None:
1158 elif data is None:
1152 raise ValueError("No image data found. Expecting filename, url, or data.")
1159 raise ValueError("No image data found. Expecting filename, url, or data.")
1153 elif isinstance(data, str) and (
1160 elif isinstance(data, str) and (
1154 data.startswith('http') or _safe_exists(data)
1161 data.startswith('http') or _safe_exists(data)
1155 ):
1162 ):
1156 ext = self._find_ext(data)
1163 ext = self._find_ext(data)
1157 else:
1164 else:
1158 ext = None
1165 ext = None
1159
1166
1160 if format is None:
1167 if format is None:
1161 if ext is not None:
1168 if ext is not None:
1162 if ext == u'jpg' or ext == u'jpeg':
1169 if ext == u'jpg' or ext == u'jpeg':
1163 format = self._FMT_JPEG
1170 format = self._FMT_JPEG
1164 elif ext == u'png':
1171 elif ext == u'png':
1165 format = self._FMT_PNG
1172 format = self._FMT_PNG
1166 elif ext == u'gif':
1173 elif ext == u'gif':
1167 format = self._FMT_GIF
1174 format = self._FMT_GIF
1168 else:
1175 else:
1169 format = ext.lower()
1176 format = ext.lower()
1170 elif isinstance(data, bytes):
1177 elif isinstance(data, bytes):
1171 # infer image type from image data header,
1178 # infer image type from image data header,
1172 # only if format has not been specified.
1179 # only if format has not been specified.
1173 if data[:2] == _JPEG:
1180 if data[:2] == _JPEG:
1174 format = self._FMT_JPEG
1181 format = self._FMT_JPEG
1175
1182
1176 # failed to detect format, default png
1183 # failed to detect format, default png
1177 if format is None:
1184 if format is None:
1178 format = self._FMT_PNG
1185 format = self._FMT_PNG
1179
1186
1180 if format.lower() == 'jpg':
1187 if format.lower() == 'jpg':
1181 # jpg->jpeg
1188 # jpg->jpeg
1182 format = self._FMT_JPEG
1189 format = self._FMT_JPEG
1183
1190
1184 self.format = format.lower()
1191 self.format = format.lower()
1185 self.embed = embed if embed is not None else (url is None)
1192 self.embed = embed if embed is not None else (url is None)
1186
1193
1187 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
1194 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
1188 raise ValueError("Cannot embed the '%s' image format" % (self.format))
1195 raise ValueError("Cannot embed the '%s' image format" % (self.format))
1189 if self.embed:
1196 if self.embed:
1190 self._mimetype = self._MIMETYPES.get(self.format)
1197 self._mimetype = self._MIMETYPES.get(self.format)
1191
1198
1192 self.width = width
1199 self.width = width
1193 self.height = height
1200 self.height = height
1194 self.retina = retina
1201 self.retina = retina
1195 self.unconfined = unconfined
1202 self.unconfined = unconfined
1196 super(Image, self).__init__(data=data, url=url, filename=filename,
1203 super(Image, self).__init__(data=data, url=url, filename=filename,
1197 metadata=metadata)
1204 metadata=metadata)
1198
1205
1199 if self.width is None and self.metadata.get('width', {}):
1206 if self.width is None and self.metadata.get('width', {}):
1200 self.width = metadata['width']
1207 self.width = metadata['width']
1201
1208
1202 if self.height is None and self.metadata.get('height', {}):
1209 if self.height is None and self.metadata.get('height', {}):
1203 self.height = metadata['height']
1210 self.height = metadata['height']
1204
1211
1205 if retina:
1212 if retina:
1206 self._retina_shape()
1213 self._retina_shape()
1207
1214
1208
1215
1209 def _retina_shape(self):
1216 def _retina_shape(self):
1210 """load pixel-doubled width and height from image data"""
1217 """load pixel-doubled width and height from image data"""
1211 if not self.embed:
1218 if not self.embed:
1212 return
1219 return
1213 if self.format == self._FMT_PNG:
1220 if self.format == self._FMT_PNG:
1214 w, h = _pngxy(self.data)
1221 w, h = _pngxy(self.data)
1215 elif self.format == self._FMT_JPEG:
1222 elif self.format == self._FMT_JPEG:
1216 w, h = _jpegxy(self.data)
1223 w, h = _jpegxy(self.data)
1217 elif self.format == self._FMT_GIF:
1224 elif self.format == self._FMT_GIF:
1218 w, h = _gifxy(self.data)
1225 w, h = _gifxy(self.data)
1219 else:
1226 else:
1220 # retina only supports png
1227 # retina only supports png
1221 return
1228 return
1222 self.width = w // 2
1229 self.width = w // 2
1223 self.height = h // 2
1230 self.height = h // 2
1224
1231
1225 def reload(self):
1232 def reload(self):
1226 """Reload the raw data from file or URL."""
1233 """Reload the raw data from file or URL."""
1227 if self.embed:
1234 if self.embed:
1228 super(Image,self).reload()
1235 super(Image,self).reload()
1229 if self.retina:
1236 if self.retina:
1230 self._retina_shape()
1237 self._retina_shape()
1231
1238
1232 def _repr_html_(self):
1239 def _repr_html_(self):
1233 if not self.embed:
1240 if not self.embed:
1234 width = height = klass = ''
1241 width = height = klass = ''
1235 if self.width:
1242 if self.width:
1236 width = ' width="%d"' % self.width
1243 width = ' width="%d"' % self.width
1237 if self.height:
1244 if self.height:
1238 height = ' height="%d"' % self.height
1245 height = ' height="%d"' % self.height
1239 if self.unconfined:
1246 if self.unconfined:
1240 klass = ' class="unconfined"'
1247 klass = ' class="unconfined"'
1241 return u'<img src="{url}"{width}{height}{klass}/>'.format(
1248 return u'<img src="{url}"{width}{height}{klass}/>'.format(
1242 url=self.url,
1249 url=self.url,
1243 width=width,
1250 width=width,
1244 height=height,
1251 height=height,
1245 klass=klass,
1252 klass=klass,
1246 )
1253 )
1247
1254
1248 def _repr_mimebundle_(self, include=None, exclude=None):
1255 def _repr_mimebundle_(self, include=None, exclude=None):
1249 """Return the image as a mimebundle
1256 """Return the image as a mimebundle
1250
1257
1251 Any new mimetype support should be implemented here.
1258 Any new mimetype support should be implemented here.
1252 """
1259 """
1253 if self.embed:
1260 if self.embed:
1254 mimetype = self._mimetype
1261 mimetype = self._mimetype
1255 data, metadata = self._data_and_metadata(always_both=True)
1262 data, metadata = self._data_and_metadata(always_both=True)
1256 if metadata:
1263 if metadata:
1257 metadata = {mimetype: metadata}
1264 metadata = {mimetype: metadata}
1258 return {mimetype: data}, metadata
1265 return {mimetype: data}, metadata
1259 else:
1266 else:
1260 return {'text/html': self._repr_html_()}
1267 return {'text/html': self._repr_html_()}
1261
1268
1262 def _data_and_metadata(self, always_both=False):
1269 def _data_and_metadata(self, always_both=False):
1263 """shortcut for returning metadata with shape information, if defined"""
1270 """shortcut for returning metadata with shape information, if defined"""
1264 try:
1271 try:
1265 b64_data = b2a_base64(self.data).decode('ascii')
1272 b64_data = b2a_base64(self.data).decode('ascii')
1266 except TypeError:
1273 except TypeError:
1267 raise FileNotFoundError(
1274 raise FileNotFoundError(
1268 "No such file or directory: '%s'" % (self.data))
1275 "No such file or directory: '%s'" % (self.data))
1269 md = {}
1276 md = {}
1270 if self.metadata:
1277 if self.metadata:
1271 md.update(self.metadata)
1278 md.update(self.metadata)
1272 if self.width:
1279 if self.width:
1273 md['width'] = self.width
1280 md['width'] = self.width
1274 if self.height:
1281 if self.height:
1275 md['height'] = self.height
1282 md['height'] = self.height
1276 if self.unconfined:
1283 if self.unconfined:
1277 md['unconfined'] = self.unconfined
1284 md['unconfined'] = self.unconfined
1278 if md or always_both:
1285 if md or always_both:
1279 return b64_data, md
1286 return b64_data, md
1280 else:
1287 else:
1281 return b64_data
1288 return b64_data
1282
1289
1283 def _repr_png_(self):
1290 def _repr_png_(self):
1284 if self.embed and self.format == self._FMT_PNG:
1291 if self.embed and self.format == self._FMT_PNG:
1285 return self._data_and_metadata()
1292 return self._data_and_metadata()
1286
1293
1287 def _repr_jpeg_(self):
1294 def _repr_jpeg_(self):
1288 if self.embed and self.format == self._FMT_JPEG:
1295 if self.embed and self.format == self._FMT_JPEG:
1289 return self._data_and_metadata()
1296 return self._data_and_metadata()
1290
1297
1291 def _find_ext(self, s):
1298 def _find_ext(self, s):
1292 base, ext = splitext(s)
1299 base, ext = splitext(s)
1293
1300
1294 if not ext:
1301 if not ext:
1295 return base
1302 return base
1296
1303
1297 # `splitext` includes leading period, so we skip it
1304 # `splitext` includes leading period, so we skip it
1298 return ext[1:].lower()
1305 return ext[1:].lower()
1299
1306
1300
1307
1301 class Video(DisplayObject):
1308 class Video(DisplayObject):
1302
1309
1303 def __init__(self, data=None, url=None, filename=None, embed=False,
1310 def __init__(self, data=None, url=None, filename=None, embed=False,
1304 mimetype=None, width=None, height=None):
1311 mimetype=None, width=None, height=None):
1305 """Create a video object given raw data or an URL.
1312 """Create a video object given raw data or an URL.
1306
1313
1307 When this object is returned by an input cell or passed to the
1314 When this object is returned by an input cell or passed to the
1308 display function, it will result in the video being displayed
1315 display function, it will result in the video being displayed
1309 in the frontend.
1316 in the frontend.
1310
1317
1311 Parameters
1318 Parameters
1312 ----------
1319 ----------
1313 data : unicode, str or bytes
1320 data : unicode, str or bytes
1314 The raw video data or a URL or filename to load the data from.
1321 The raw video data or a URL or filename to load the data from.
1315 Raw data will require passing `embed=True`.
1322 Raw data will require passing `embed=True`.
1316 url : unicode
1323 url : unicode
1317 A URL for the video. If you specify `url=`,
1324 A URL for the video. If you specify `url=`,
1318 the image data will not be embedded.
1325 the image data will not be embedded.
1319 filename : unicode
1326 filename : unicode
1320 Path to a local file containing the video.
1327 Path to a local file containing the video.
1321 Will be interpreted as a local URL unless `embed=True`.
1328 Will be interpreted as a local URL unless `embed=True`.
1322 embed : bool
1329 embed : bool
1323 Should the video be embedded using a data URI (True) or be
1330 Should the video be embedded using a data URI (True) or be
1324 loaded using a <video> tag (False).
1331 loaded using a <video> tag (False).
1325
1332
1326 Since videos are large, embedding them should be avoided, if possible.
1333 Since videos are large, embedding them should be avoided, if possible.
1327 You must confirm embedding as your intention by passing `embed=True`.
1334 You must confirm embedding as your intention by passing `embed=True`.
1328
1335
1329 Local files can be displayed with URLs without embedding the content, via::
1336 Local files can be displayed with URLs without embedding the content, via::
1330
1337
1331 Video('./video.mp4')
1338 Video('./video.mp4')
1332
1339
1333 mimetype: unicode
1340 mimetype: unicode
1334 Specify the mimetype for embedded videos.
1341 Specify the mimetype for embedded videos.
1335 Default will be guessed from file extension, if available.
1342 Default will be guessed from file extension, if available.
1336 width : int
1343 width : int
1337 Width in pixels to which to constrain the video in HTML.
1344 Width in pixels to which to constrain the video in HTML.
1338 If not supplied, defaults to the width of the video.
1345 If not supplied, defaults to the width of the video.
1339 height : int
1346 height : int
1340 Height in pixels to which to constrain the video in html.
1347 Height in pixels to which to constrain the video in html.
1341 If not supplied, defaults to the height of the video.
1348 If not supplied, defaults to the height of the video.
1342
1349
1343 Examples
1350 Examples
1344 --------
1351 --------
1345
1352
1346 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1353 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1347 Video('path/to/video.mp4')
1354 Video('path/to/video.mp4')
1348 Video('path/to/video.mp4', embed=True)
1355 Video('path/to/video.mp4', embed=True)
1349 Video(b'raw-videodata', embed=True)
1356 Video(b'raw-videodata', embed=True)
1350 """
1357 """
1351 if isinstance(data, (Path, PurePath)):
1358 if isinstance(data, (Path, PurePath)):
1352 data = str(data)
1359 data = str(data)
1353
1360
1354 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1361 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1355 url = data
1362 url = data
1356 data = None
1363 data = None
1357 elif os.path.exists(data):
1364 elif os.path.exists(data):
1358 filename = data
1365 filename = data
1359 data = None
1366 data = None
1360
1367
1361 if data and not embed:
1368 if data and not embed:
1362 msg = ''.join([
1369 msg = ''.join([
1363 "To embed videos, you must pass embed=True ",
1370 "To embed videos, you must pass embed=True ",
1364 "(this may make your notebook files huge)\n",
1371 "(this may make your notebook files huge)\n",
1365 "Consider passing Video(url='...')",
1372 "Consider passing Video(url='...')",
1366 ])
1373 ])
1367 raise ValueError(msg)
1374 raise ValueError(msg)
1368
1375
1369 self.mimetype = mimetype
1376 self.mimetype = mimetype
1370 self.embed = embed
1377 self.embed = embed
1371 self.width = width
1378 self.width = width
1372 self.height = height
1379 self.height = height
1373 super(Video, self).__init__(data=data, url=url, filename=filename)
1380 super(Video, self).__init__(data=data, url=url, filename=filename)
1374
1381
1375 def _repr_html_(self):
1382 def _repr_html_(self):
1376 width = height = ''
1383 width = height = ''
1377 if self.width:
1384 if self.width:
1378 width = ' width="%d"' % self.width
1385 width = ' width="%d"' % self.width
1379 if self.height:
1386 if self.height:
1380 height = ' height="%d"' % self.height
1387 height = ' height="%d"' % self.height
1381
1388
1382 # External URLs and potentially local files are not embedded into the
1389 # External URLs and potentially local files are not embedded into the
1383 # notebook output.
1390 # notebook output.
1384 if not self.embed:
1391 if not self.embed:
1385 url = self.url if self.url is not None else self.filename
1392 url = self.url if self.url is not None else self.filename
1386 output = """<video src="{0}" controls {1} {2}>
1393 output = """<video src="{0}" controls {1} {2}>
1387 Your browser does not support the <code>video</code> element.
1394 Your browser does not support the <code>video</code> element.
1388 </video>""".format(url, width, height)
1395 </video>""".format(url, width, height)
1389 return output
1396 return output
1390
1397
1391 # Embedded videos are base64-encoded.
1398 # Embedded videos are base64-encoded.
1392 mimetype = self.mimetype
1399 mimetype = self.mimetype
1393 if self.filename is not None:
1400 if self.filename is not None:
1394 if not mimetype:
1401 if not mimetype:
1395 mimetype, _ = mimetypes.guess_type(self.filename)
1402 mimetype, _ = mimetypes.guess_type(self.filename)
1396
1403
1397 with open(self.filename, 'rb') as f:
1404 with open(self.filename, 'rb') as f:
1398 video = f.read()
1405 video = f.read()
1399 else:
1406 else:
1400 video = self.data
1407 video = self.data
1401 if isinstance(video, str):
1408 if isinstance(video, str):
1402 # unicode input is already b64-encoded
1409 # unicode input is already b64-encoded
1403 b64_video = video
1410 b64_video = video
1404 else:
1411 else:
1405 b64_video = b2a_base64(video).decode('ascii').rstrip()
1412 b64_video = b2a_base64(video).decode('ascii').rstrip()
1406
1413
1407 output = """<video controls {0} {1}>
1414 output = """<video controls {0} {1}>
1408 <source src="data:{2};base64,{3}" type="{2}">
1415 <source src="data:{2};base64,{3}" type="{2}">
1409 Your browser does not support the video tag.
1416 Your browser does not support the video tag.
1410 </video>""".format(width, height, mimetype, b64_video)
1417 </video>""".format(width, height, mimetype, b64_video)
1411 return output
1418 return output
1412
1419
1413 def reload(self):
1420 def reload(self):
1414 # TODO
1421 # TODO
1415 pass
1422 pass
1416
1423
1417
1424
1418 def clear_output(wait=False):
1425 def clear_output(wait=False):
1419 """Clear the output of the current cell receiving output.
1426 """Clear the output of the current cell receiving output.
1420
1427
1421 Parameters
1428 Parameters
1422 ----------
1429 ----------
1423 wait : bool [default: false]
1430 wait : bool [default: false]
1424 Wait to clear the output until new output is available to replace it."""
1431 Wait to clear the output until new output is available to replace it."""
1425 from IPython.core.interactiveshell import InteractiveShell
1432 from IPython.core.interactiveshell import InteractiveShell
1426 if InteractiveShell.initialized():
1433 if InteractiveShell.initialized():
1427 InteractiveShell.instance().display_pub.clear_output(wait)
1434 InteractiveShell.instance().display_pub.clear_output(wait)
1428 else:
1435 else:
1429 print('\033[2K\r', end='')
1436 print('\033[2K\r', end='')
1430 sys.stdout.flush()
1437 sys.stdout.flush()
1431 print('\033[2K\r', end='')
1438 print('\033[2K\r', end='')
1432 sys.stderr.flush()
1439 sys.stderr.flush()
1433
1440
1434
1441
1435 @skip_doctest
1442 @skip_doctest
1436 def set_matplotlib_formats(*formats, **kwargs):
1443 def set_matplotlib_formats(*formats, **kwargs):
1437 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1444 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1438
1445
1439 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1446 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1440
1447
1441 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1448 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1442
1449
1443 To set this in your config files use the following::
1450 To set this in your config files use the following::
1444
1451
1445 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1452 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1446 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1453 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1447
1454
1448 Parameters
1455 Parameters
1449 ----------
1456 ----------
1450 *formats : strs
1457 *formats : strs
1451 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1458 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1452 **kwargs :
1459 **kwargs :
1453 Keyword args will be relayed to ``figure.canvas.print_figure``.
1460 Keyword args will be relayed to ``figure.canvas.print_figure``.
1454 """
1461 """
1455 from IPython.core.interactiveshell import InteractiveShell
1462 from IPython.core.interactiveshell import InteractiveShell
1456 from IPython.core.pylabtools import select_figure_formats
1463 from IPython.core.pylabtools import select_figure_formats
1457 # build kwargs, starting with InlineBackend config
1464 # build kwargs, starting with InlineBackend config
1458 kw = {}
1465 kw = {}
1459 from ipykernel.pylab.config import InlineBackend
1466 from ipykernel.pylab.config import InlineBackend
1460 cfg = InlineBackend.instance()
1467 cfg = InlineBackend.instance()
1461 kw.update(cfg.print_figure_kwargs)
1468 kw.update(cfg.print_figure_kwargs)
1462 kw.update(**kwargs)
1469 kw.update(**kwargs)
1463 shell = InteractiveShell.instance()
1470 shell = InteractiveShell.instance()
1464 select_figure_formats(shell, formats, **kw)
1471 select_figure_formats(shell, formats, **kw)
1465
1472
1466 @skip_doctest
1473 @skip_doctest
1467 def set_matplotlib_close(close=True):
1474 def set_matplotlib_close(close=True):
1468 """Set whether the inline backend closes all figures automatically or not.
1475 """Set whether the inline backend closes all figures automatically or not.
1469
1476
1470 By default, the inline backend used in the IPython Notebook will close all
1477 By default, the inline backend used in the IPython Notebook will close all
1471 matplotlib figures automatically after each cell is run. This means that
1478 matplotlib figures automatically after each cell is run. This means that
1472 plots in different cells won't interfere. Sometimes, you may want to make
1479 plots in different cells won't interfere. Sometimes, you may want to make
1473 a plot in one cell and then refine it in later cells. This can be accomplished
1480 a plot in one cell and then refine it in later cells. This can be accomplished
1474 by::
1481 by::
1475
1482
1476 In [1]: set_matplotlib_close(False)
1483 In [1]: set_matplotlib_close(False)
1477
1484
1478 To set this in your config files use the following::
1485 To set this in your config files use the following::
1479
1486
1480 c.InlineBackend.close_figures = False
1487 c.InlineBackend.close_figures = False
1481
1488
1482 Parameters
1489 Parameters
1483 ----------
1490 ----------
1484 close : bool
1491 close : bool
1485 Should all matplotlib figures be automatically closed after each cell is
1492 Should all matplotlib figures be automatically closed after each cell is
1486 run?
1493 run?
1487 """
1494 """
1488 from ipykernel.pylab.config import InlineBackend
1495 from ipykernel.pylab.config import InlineBackend
1489 cfg = InlineBackend.instance()
1496 cfg = InlineBackend.instance()
1490 cfg.close_figures = close
1497 cfg.close_figures = close
General Comments 0
You need to be logged in to leave comments. Login now