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