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