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