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