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