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