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