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