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