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