##// END OF EJS Templates
uncompress compressed data
Ian Castleden -
Show More
@@ -1,1504 +1,1513 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 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 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 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 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 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 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 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 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 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 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 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 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.url = url
619 619 self.filename = filename
620 620 # because of @data.setter methods in
621 621 # subclasses ensure url and filename are set
622 622 # before assigning to self.data
623 623 self.data = data
624 624
625 625 if metadata is not None:
626 626 self.metadata = metadata
627 627 elif self.metadata is None:
628 628 self.metadata = {}
629 629
630 630 self.reload()
631 631 self._check_data()
632 632
633 633 def __repr__(self):
634 634 if not self._show_mem_addr:
635 635 cls = self.__class__
636 636 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
637 637 else:
638 638 r = super(DisplayObject, self).__repr__()
639 639 return r
640 640
641 641 def _check_data(self):
642 642 """Override in subclasses if there's something to check."""
643 643 pass
644 644
645 645 def _data_and_metadata(self):
646 646 """shortcut for returning metadata with shape information, if defined"""
647 647 if self.metadata:
648 648 return self.data, deepcopy(self.metadata)
649 649 else:
650 650 return self.data
651 651
652 652 def reload(self):
653 653 """Reload the raw data from file or URL."""
654 654 if self.filename is not None:
655 655 with open(self.filename, self._read_flags) as f:
656 656 self.data = f.read()
657 657 elif self.url is not None:
658 658 # Deferred import
659 659 from urllib.request import urlopen
660 660 response = urlopen(self.url)
661 661 data = response.read()
662 662 # extract encoding from header, if there is one:
663 663 encoding = None
664 if "content-type" in response.headers:
664 if 'content-type' in response.headers:
665 665 for sub in response.headers['content-type'].split(';'):
666 666 sub = sub.strip()
667 667 if sub.startswith('charset'):
668 668 encoding = sub.split('=')[-1].strip()
669 669 break
670 if 'content-encoding' in response.headers:
671 # TODO: do deflate?
672 if 'gzip' in response.headers['content-encoding']:
673 import gzip
674 from io import BytesIO
675 with gzip.open(BytesIO(data), 'rt', encoding=encoding) as fp:
676 encoding = None
677 data = fp.read()
678
670 679 # decode data, if an encoding was specified
671 680 # We only touch self.data once since
672 681 # subclasses such as SVG have @data.setter methods
673 682 # that transform self.data into ... well svg.
674 683 if encoding:
675 684 self.data = data.decode(encoding, 'replace')
676 685 else:
677 686 self.data = data
678 687
679 688
680 689 class TextDisplayObject(DisplayObject):
681 690 """Validate that display data is text"""
682 691 def _check_data(self):
683 692 if self.data is not None and not isinstance(self.data, str):
684 693 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
685 694
686 695 class Pretty(TextDisplayObject):
687 696
688 697 def _repr_pretty_(self, pp, cycle):
689 698 return pp.text(self.data)
690 699
691 700
692 701 class HTML(TextDisplayObject):
693 702
694 703 def __init__(self, data=None, url=None, filename=None, metadata=None):
695 704 def warn():
696 705 if not data:
697 706 return False
698 707
699 708 #
700 709 # Avoid calling lower() on the entire data, because it could be a
701 710 # long string and we're only interested in its beginning and end.
702 711 #
703 712 prefix = data[:10].lower()
704 713 suffix = data[-10:].lower()
705 714 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
706 715
707 716 if warn():
708 717 warnings.warn("Consider using IPython.display.IFrame instead")
709 718 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
710 719
711 720 def _repr_html_(self):
712 721 return self._data_and_metadata()
713 722
714 723 def __html__(self):
715 724 """
716 725 This method exists to inform other HTML-using modules (e.g. Markupsafe,
717 726 htmltag, etc) that this object is HTML and does not need things like
718 727 special characters (<>&) escaped.
719 728 """
720 729 return self._repr_html_()
721 730
722 731
723 732 class Markdown(TextDisplayObject):
724 733
725 734 def _repr_markdown_(self):
726 735 return self._data_and_metadata()
727 736
728 737
729 738 class Math(TextDisplayObject):
730 739
731 740 def _repr_latex_(self):
732 741 s = r"$\displaystyle %s$" % self.data.strip('$')
733 742 if self.metadata:
734 743 return s, deepcopy(self.metadata)
735 744 else:
736 745 return s
737 746
738 747
739 748 class Latex(TextDisplayObject):
740 749
741 750 def _repr_latex_(self):
742 751 return self._data_and_metadata()
743 752
744 753
745 754 class SVG(DisplayObject):
746 755
747 756 _read_flags = 'rb'
748 757 # wrap data in a property, which extracts the <svg> tag, discarding
749 758 # document headers
750 759 _data = None
751 760
752 761 @property
753 762 def data(self):
754 763 return self._data
755 764
756 765 @data.setter
757 766 def data(self, svg):
758 767 if svg is None:
759 768 self._data = None
760 769 return
761 770 # parse into dom object
762 771 from xml.dom import minidom
763 772 x = minidom.parseString(svg)
764 773 # get svg tag (should be 1)
765 774 found_svg = x.getElementsByTagName('svg')
766 775 if found_svg:
767 776 svg = found_svg[0].toxml()
768 777 else:
769 778 # fallback on the input, trust the user
770 779 # but this is probably an error.
771 780 pass
772 781 svg = cast_unicode(svg)
773 782 self._data = svg
774 783
775 784 def _repr_svg_(self):
776 785 return self._data_and_metadata()
777 786
778 787 class ProgressBar(DisplayObject):
779 788 """Progressbar supports displaying a progressbar like element
780 789 """
781 790 def __init__(self, total):
782 791 """Creates a new progressbar
783 792
784 793 Parameters
785 794 ----------
786 795 total : int
787 796 maximum size of the progressbar
788 797 """
789 798 self.total = total
790 799 self._progress = 0
791 800 self.html_width = '60ex'
792 801 self.text_width = 60
793 802 self._display_id = hexlify(os.urandom(8)).decode('ascii')
794 803
795 804 def __repr__(self):
796 805 fraction = self.progress / self.total
797 806 filled = '=' * int(fraction * self.text_width)
798 807 rest = ' ' * (self.text_width - len(filled))
799 808 return '[{}{}] {}/{}'.format(
800 809 filled, rest,
801 810 self.progress, self.total,
802 811 )
803 812
804 813 def _repr_html_(self):
805 814 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
806 815 self.html_width, self.total, self.progress)
807 816
808 817 def display(self):
809 818 display(self, display_id=self._display_id)
810 819
811 820 def update(self):
812 821 display(self, display_id=self._display_id, update=True)
813 822
814 823 @property
815 824 def progress(self):
816 825 return self._progress
817 826
818 827 @progress.setter
819 828 def progress(self, value):
820 829 self._progress = value
821 830 self.update()
822 831
823 832 def __iter__(self):
824 833 self.display()
825 834 self._progress = -1 # First iteration is 0
826 835 return self
827 836
828 837 def __next__(self):
829 838 """Returns current value and increments display by one."""
830 839 self.progress += 1
831 840 if self.progress < self.total:
832 841 return self.progress
833 842 else:
834 843 raise StopIteration()
835 844
836 845 class JSON(DisplayObject):
837 846 """JSON expects a JSON-able dict or list
838 847
839 848 not an already-serialized JSON string.
840 849
841 850 Scalar types (None, number, string) are not allowed, only dict or list containers.
842 851 """
843 852 # wrap data in a property, which warns about passing already-serialized JSON
844 853 _data = None
845 854 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
846 855 """Create a JSON display object given raw data.
847 856
848 857 Parameters
849 858 ----------
850 859 data : dict or list
851 860 JSON data to display. Not an already-serialized JSON string.
852 861 Scalar types (None, number, string) are not allowed, only dict
853 862 or list containers.
854 863 url : unicode
855 864 A URL to download the data from.
856 865 filename : unicode
857 866 Path to a local file to load the data from.
858 867 expanded : boolean
859 868 Metadata to control whether a JSON display component is expanded.
860 869 metadata: dict
861 870 Specify extra metadata to attach to the json display object.
862 871 root : str
863 872 The name of the root element of the JSON tree
864 873 """
865 874 self.metadata = {
866 875 'expanded': expanded,
867 876 'root': root,
868 877 }
869 878 if metadata:
870 879 self.metadata.update(metadata)
871 880 if kwargs:
872 881 self.metadata.update(kwargs)
873 882 super(JSON, self).__init__(data=data, url=url, filename=filename)
874 883
875 884 def _check_data(self):
876 885 if self.data is not None and not isinstance(self.data, (dict, list)):
877 886 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
878 887
879 888 @property
880 889 def data(self):
881 890 return self._data
882 891
883 892 @data.setter
884 893 def data(self, data):
885 894 if isinstance(data, (Path, PurePath)):
886 895 data = str(data)
887 896
888 897 if isinstance(data, str):
889 898 if self.filename is None and self.url is None:
890 899 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
891 900 data = json.loads(data)
892 901 self._data = data
893 902
894 903 def _data_and_metadata(self):
895 904 return self.data, self.metadata
896 905
897 906 def _repr_json_(self):
898 907 return self._data_and_metadata()
899 908
900 909 _css_t = """var link = document.createElement("link");
901 910 link.ref = "stylesheet";
902 911 link.type = "text/css";
903 912 link.href = "%s";
904 913 document.head.appendChild(link);
905 914 """
906 915
907 916 _lib_t1 = """new Promise(function(resolve, reject) {
908 917 var script = document.createElement("script");
909 918 script.onload = resolve;
910 919 script.onerror = reject;
911 920 script.src = "%s";
912 921 document.head.appendChild(script);
913 922 }).then(() => {
914 923 """
915 924
916 925 _lib_t2 = """
917 926 });"""
918 927
919 928 class GeoJSON(JSON):
920 929 """GeoJSON expects JSON-able dict
921 930
922 931 not an already-serialized JSON string.
923 932
924 933 Scalar types (None, number, string) are not allowed, only dict containers.
925 934 """
926 935
927 936 def __init__(self, *args, **kwargs):
928 937 """Create a GeoJSON display object given raw data.
929 938
930 939 Parameters
931 940 ----------
932 941 data : dict or list
933 942 VegaLite data. Not an already-serialized JSON string.
934 943 Scalar types (None, number, string) are not allowed, only dict
935 944 or list containers.
936 945 url_template : string
937 946 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
938 947 layer_options : dict
939 948 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
940 949 url : unicode
941 950 A URL to download the data from.
942 951 filename : unicode
943 952 Path to a local file to load the data from.
944 953 metadata: dict
945 954 Specify extra metadata to attach to the json display object.
946 955
947 956 Examples
948 957 --------
949 958
950 959 The following will display an interactive map of Mars with a point of
951 960 interest on frontend that do support GeoJSON display.
952 961
953 962 >>> from IPython.display import GeoJSON
954 963
955 964 >>> GeoJSON(data={
956 965 ... "type": "Feature",
957 966 ... "geometry": {
958 967 ... "type": "Point",
959 968 ... "coordinates": [-81.327, 296.038]
960 969 ... }
961 970 ... },
962 971 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
963 972 ... layer_options={
964 973 ... "basemap_id": "celestia_mars-shaded-16k_global",
965 974 ... "attribution" : "Celestia/praesepe",
966 975 ... "minZoom" : 0,
967 976 ... "maxZoom" : 18,
968 977 ... })
969 978 <IPython.core.display.GeoJSON object>
970 979
971 980 In the terminal IPython, you will only see the text representation of
972 981 the GeoJSON object.
973 982
974 983 """
975 984
976 985 super(GeoJSON, self).__init__(*args, **kwargs)
977 986
978 987
979 988 def _ipython_display_(self):
980 989 bundle = {
981 990 'application/geo+json': self.data,
982 991 'text/plain': '<IPython.display.GeoJSON object>'
983 992 }
984 993 metadata = {
985 994 'application/geo+json': self.metadata
986 995 }
987 996 display(bundle, metadata=metadata, raw=True)
988 997
989 998 class Javascript(TextDisplayObject):
990 999
991 1000 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
992 1001 """Create a Javascript display object given raw data.
993 1002
994 1003 When this object is returned by an expression or passed to the
995 1004 display function, it will result in the data being displayed
996 1005 in the frontend. If the data is a URL, the data will first be
997 1006 downloaded and then displayed.
998 1007
999 1008 In the Notebook, the containing element will be available as `element`,
1000 1009 and jQuery will be available. Content appended to `element` will be
1001 1010 visible in the output area.
1002 1011
1003 1012 Parameters
1004 1013 ----------
1005 1014 data : unicode, str or bytes
1006 1015 The Javascript source code or a URL to download it from.
1007 1016 url : unicode
1008 1017 A URL to download the data from.
1009 1018 filename : unicode
1010 1019 Path to a local file to load the data from.
1011 1020 lib : list or str
1012 1021 A sequence of Javascript library URLs to load asynchronously before
1013 1022 running the source code. The full URLs of the libraries should
1014 1023 be given. A single Javascript library URL can also be given as a
1015 1024 string.
1016 1025 css: : list or str
1017 1026 A sequence of css files to load before running the source code.
1018 1027 The full URLs of the css files should be given. A single css URL
1019 1028 can also be given as a string.
1020 1029 """
1021 1030 if isinstance(lib, str):
1022 1031 lib = [lib]
1023 1032 elif lib is None:
1024 1033 lib = []
1025 1034 if isinstance(css, str):
1026 1035 css = [css]
1027 1036 elif css is None:
1028 1037 css = []
1029 1038 if not isinstance(lib, (list,tuple)):
1030 1039 raise TypeError('expected sequence, got: %r' % lib)
1031 1040 if not isinstance(css, (list,tuple)):
1032 1041 raise TypeError('expected sequence, got: %r' % css)
1033 1042 self.lib = lib
1034 1043 self.css = css
1035 1044 super(Javascript, self).__init__(data=data, url=url, filename=filename)
1036 1045
1037 1046 def _repr_javascript_(self):
1038 1047 r = ''
1039 1048 for c in self.css:
1040 1049 r += _css_t % c
1041 1050 for l in self.lib:
1042 1051 r += _lib_t1 % l
1043 1052 r += self.data
1044 1053 r += _lib_t2*len(self.lib)
1045 1054 return r
1046 1055
1047 1056 # constants for identifying png/jpeg data
1048 1057 _PNG = b'\x89PNG\r\n\x1a\n'
1049 1058 _JPEG = b'\xff\xd8'
1050 1059
1051 1060 def _pngxy(data):
1052 1061 """read the (width, height) from a PNG header"""
1053 1062 ihdr = data.index(b'IHDR')
1054 1063 # next 8 bytes are width/height
1055 1064 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
1056 1065
1057 1066 def _jpegxy(data):
1058 1067 """read the (width, height) from a JPEG header"""
1059 1068 # adapted from http://www.64lines.com/jpeg-width-height
1060 1069
1061 1070 idx = 4
1062 1071 while True:
1063 1072 block_size = struct.unpack('>H', data[idx:idx+2])[0]
1064 1073 idx = idx + block_size
1065 1074 if data[idx:idx+2] == b'\xFF\xC0':
1066 1075 # found Start of Frame
1067 1076 iSOF = idx
1068 1077 break
1069 1078 else:
1070 1079 # read another block
1071 1080 idx += 2
1072 1081
1073 1082 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
1074 1083 return w, h
1075 1084
1076 1085 def _gifxy(data):
1077 1086 """read the (width, height) from a GIF header"""
1078 1087 return struct.unpack('<HH', data[6:10])
1079 1088
1080 1089
1081 1090 class Image(DisplayObject):
1082 1091
1083 1092 _read_flags = 'rb'
1084 1093 _FMT_JPEG = u'jpeg'
1085 1094 _FMT_PNG = u'png'
1086 1095 _FMT_GIF = u'gif'
1087 1096 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
1088 1097 _MIMETYPES = {
1089 1098 _FMT_PNG: 'image/png',
1090 1099 _FMT_JPEG: 'image/jpeg',
1091 1100 _FMT_GIF: 'image/gif',
1092 1101 }
1093 1102
1094 1103 def __init__(self, data=None, url=None, filename=None, format=None,
1095 1104 embed=None, width=None, height=None, retina=False,
1096 1105 unconfined=False, metadata=None):
1097 1106 """Create a PNG/JPEG/GIF image object given raw data.
1098 1107
1099 1108 When this object is returned by an input cell or passed to the
1100 1109 display function, it will result in the image being displayed
1101 1110 in the frontend.
1102 1111
1103 1112 Parameters
1104 1113 ----------
1105 1114 data : unicode, str or bytes
1106 1115 The raw image data or a URL or filename to load the data from.
1107 1116 This always results in embedded image data.
1108 1117 url : unicode
1109 1118 A URL to download the data from. If you specify `url=`,
1110 1119 the image data will not be embedded unless you also specify `embed=True`.
1111 1120 filename : unicode
1112 1121 Path to a local file to load the data from.
1113 1122 Images from a file are always embedded.
1114 1123 format : unicode
1115 1124 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
1116 1125 for format will be inferred from the filename extension.
1117 1126 embed : bool
1118 1127 Should the image data be embedded using a data URI (True) or be
1119 1128 loaded using an <img> tag. Set this to True if you want the image
1120 1129 to be viewable later with no internet connection in the notebook.
1121 1130
1122 1131 Default is `True`, unless the keyword argument `url` is set, then
1123 1132 default value is `False`.
1124 1133
1125 1134 Note that QtConsole is not able to display images if `embed` is set to `False`
1126 1135 width : int
1127 1136 Width in pixels to which to constrain the image in html
1128 1137 height : int
1129 1138 Height in pixels to which to constrain the image in html
1130 1139 retina : bool
1131 1140 Automatically set the width and height to half of the measured
1132 1141 width and height.
1133 1142 This only works for embedded images because it reads the width/height
1134 1143 from image data.
1135 1144 For non-embedded images, you can just set the desired display width
1136 1145 and height directly.
1137 1146 unconfined: bool
1138 1147 Set unconfined=True to disable max-width confinement of the image.
1139 1148 metadata: dict
1140 1149 Specify extra metadata to attach to the image.
1141 1150
1142 1151 Examples
1143 1152 --------
1144 1153 # embedded image data, works in qtconsole and notebook
1145 1154 # when passed positionally, the first arg can be any of raw image data,
1146 1155 # a URL, or a filename from which to load image data.
1147 1156 # The result is always embedding image data for inline images.
1148 1157 Image('http://www.google.fr/images/srpr/logo3w.png')
1149 1158 Image('/path/to/image.jpg')
1150 1159 Image(b'RAW_PNG_DATA...')
1151 1160
1152 1161 # Specifying Image(url=...) does not embed the image data,
1153 1162 # it only generates `<img>` tag with a link to the source.
1154 1163 # This will not work in the qtconsole or offline.
1155 1164 Image(url='http://www.google.fr/images/srpr/logo3w.png')
1156 1165
1157 1166 """
1158 1167 if isinstance(data, (Path, PurePath)):
1159 1168 data = str(data)
1160 1169
1161 1170 if filename is not None:
1162 1171 ext = self._find_ext(filename)
1163 1172 elif url is not None:
1164 1173 ext = self._find_ext(url)
1165 1174 elif data is None:
1166 1175 raise ValueError("No image data found. Expecting filename, url, or data.")
1167 1176 elif isinstance(data, str) and (
1168 1177 data.startswith('http') or _safe_exists(data)
1169 1178 ):
1170 1179 ext = self._find_ext(data)
1171 1180 else:
1172 1181 ext = None
1173 1182
1174 1183 if format is None:
1175 1184 if ext is not None:
1176 1185 if ext == u'jpg' or ext == u'jpeg':
1177 1186 format = self._FMT_JPEG
1178 1187 elif ext == u'png':
1179 1188 format = self._FMT_PNG
1180 1189 elif ext == u'gif':
1181 1190 format = self._FMT_GIF
1182 1191 else:
1183 1192 format = ext.lower()
1184 1193 elif isinstance(data, bytes):
1185 1194 # infer image type from image data header,
1186 1195 # only if format has not been specified.
1187 1196 if data[:2] == _JPEG:
1188 1197 format = self._FMT_JPEG
1189 1198
1190 1199 # failed to detect format, default png
1191 1200 if format is None:
1192 1201 format = self._FMT_PNG
1193 1202
1194 1203 if format.lower() == 'jpg':
1195 1204 # jpg->jpeg
1196 1205 format = self._FMT_JPEG
1197 1206
1198 1207 self.format = format.lower()
1199 1208 self.embed = embed if embed is not None else (url is None)
1200 1209
1201 1210 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
1202 1211 raise ValueError("Cannot embed the '%s' image format" % (self.format))
1203 1212 if self.embed:
1204 1213 self._mimetype = self._MIMETYPES.get(self.format)
1205 1214
1206 1215 self.width = width
1207 1216 self.height = height
1208 1217 self.retina = retina
1209 1218 self.unconfined = unconfined
1210 1219 super(Image, self).__init__(data=data, url=url, filename=filename,
1211 1220 metadata=metadata)
1212 1221
1213 1222 if self.width is None and self.metadata.get('width', {}):
1214 1223 self.width = metadata['width']
1215 1224
1216 1225 if self.height is None and self.metadata.get('height', {}):
1217 1226 self.height = metadata['height']
1218 1227
1219 1228 if retina:
1220 1229 self._retina_shape()
1221 1230
1222 1231
1223 1232 def _retina_shape(self):
1224 1233 """load pixel-doubled width and height from image data"""
1225 1234 if not self.embed:
1226 1235 return
1227 1236 if self.format == self._FMT_PNG:
1228 1237 w, h = _pngxy(self.data)
1229 1238 elif self.format == self._FMT_JPEG:
1230 1239 w, h = _jpegxy(self.data)
1231 1240 elif self.format == self._FMT_GIF:
1232 1241 w, h = _gifxy(self.data)
1233 1242 else:
1234 1243 # retina only supports png
1235 1244 return
1236 1245 self.width = w // 2
1237 1246 self.height = h // 2
1238 1247
1239 1248 def reload(self):
1240 1249 """Reload the raw data from file or URL."""
1241 1250 if self.embed:
1242 1251 super(Image,self).reload()
1243 1252 if self.retina:
1244 1253 self._retina_shape()
1245 1254
1246 1255 def _repr_html_(self):
1247 1256 if not self.embed:
1248 1257 width = height = klass = ''
1249 1258 if self.width:
1250 1259 width = ' width="%d"' % self.width
1251 1260 if self.height:
1252 1261 height = ' height="%d"' % self.height
1253 1262 if self.unconfined:
1254 1263 klass = ' class="unconfined"'
1255 1264 return u'<img src="{url}"{width}{height}{klass}/>'.format(
1256 1265 url=self.url,
1257 1266 width=width,
1258 1267 height=height,
1259 1268 klass=klass,
1260 1269 )
1261 1270
1262 1271 def _repr_mimebundle_(self, include=None, exclude=None):
1263 1272 """Return the image as a mimebundle
1264 1273
1265 1274 Any new mimetype support should be implemented here.
1266 1275 """
1267 1276 if self.embed:
1268 1277 mimetype = self._mimetype
1269 1278 data, metadata = self._data_and_metadata(always_both=True)
1270 1279 if metadata:
1271 1280 metadata = {mimetype: metadata}
1272 1281 return {mimetype: data}, metadata
1273 1282 else:
1274 1283 return {'text/html': self._repr_html_()}
1275 1284
1276 1285 def _data_and_metadata(self, always_both=False):
1277 1286 """shortcut for returning metadata with shape information, if defined"""
1278 1287 try:
1279 1288 b64_data = b2a_base64(self.data).decode('ascii')
1280 1289 except TypeError:
1281 1290 raise FileNotFoundError(
1282 1291 "No such file or directory: '%s'" % (self.data))
1283 1292 md = {}
1284 1293 if self.metadata:
1285 1294 md.update(self.metadata)
1286 1295 if self.width:
1287 1296 md['width'] = self.width
1288 1297 if self.height:
1289 1298 md['height'] = self.height
1290 1299 if self.unconfined:
1291 1300 md['unconfined'] = self.unconfined
1292 1301 if md or always_both:
1293 1302 return b64_data, md
1294 1303 else:
1295 1304 return b64_data
1296 1305
1297 1306 def _repr_png_(self):
1298 1307 if self.embed and self.format == self._FMT_PNG:
1299 1308 return self._data_and_metadata()
1300 1309
1301 1310 def _repr_jpeg_(self):
1302 1311 if self.embed and self.format == self._FMT_JPEG:
1303 1312 return self._data_and_metadata()
1304 1313
1305 1314 def _find_ext(self, s):
1306 1315 base, ext = splitext(s)
1307 1316
1308 1317 if not ext:
1309 1318 return base
1310 1319
1311 1320 # `splitext` includes leading period, so we skip it
1312 1321 return ext[1:].lower()
1313 1322
1314 1323
1315 1324 class Video(DisplayObject):
1316 1325
1317 1326 def __init__(self, data=None, url=None, filename=None, embed=False,
1318 1327 mimetype=None, width=None, height=None):
1319 1328 """Create a video object given raw data or an URL.
1320 1329
1321 1330 When this object is returned by an input cell or passed to the
1322 1331 display function, it will result in the video being displayed
1323 1332 in the frontend.
1324 1333
1325 1334 Parameters
1326 1335 ----------
1327 1336 data : unicode, str or bytes
1328 1337 The raw video data or a URL or filename to load the data from.
1329 1338 Raw data will require passing `embed=True`.
1330 1339 url : unicode
1331 1340 A URL for the video. If you specify `url=`,
1332 1341 the image data will not be embedded.
1333 1342 filename : unicode
1334 1343 Path to a local file containing the video.
1335 1344 Will be interpreted as a local URL unless `embed=True`.
1336 1345 embed : bool
1337 1346 Should the video be embedded using a data URI (True) or be
1338 1347 loaded using a <video> tag (False).
1339 1348
1340 1349 Since videos are large, embedding them should be avoided, if possible.
1341 1350 You must confirm embedding as your intention by passing `embed=True`.
1342 1351
1343 1352 Local files can be displayed with URLs without embedding the content, via::
1344 1353
1345 1354 Video('./video.mp4')
1346 1355
1347 1356 mimetype: unicode
1348 1357 Specify the mimetype for embedded videos.
1349 1358 Default will be guessed from file extension, if available.
1350 1359 width : int
1351 1360 Width in pixels to which to constrain the video in HTML.
1352 1361 If not supplied, defaults to the width of the video.
1353 1362 height : int
1354 1363 Height in pixels to which to constrain the video in html.
1355 1364 If not supplied, defaults to the height of the video.
1356 1365
1357 1366 Examples
1358 1367 --------
1359 1368
1360 1369 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1361 1370 Video('path/to/video.mp4')
1362 1371 Video('path/to/video.mp4', embed=True)
1363 1372 Video(b'raw-videodata', embed=True)
1364 1373 """
1365 1374 if isinstance(data, (Path, PurePath)):
1366 1375 data = str(data)
1367 1376
1368 1377 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1369 1378 url = data
1370 1379 data = None
1371 1380 elif os.path.exists(data):
1372 1381 filename = data
1373 1382 data = None
1374 1383
1375 1384 if data and not embed:
1376 1385 msg = ''.join([
1377 1386 "To embed videos, you must pass embed=True ",
1378 1387 "(this may make your notebook files huge)\n",
1379 1388 "Consider passing Video(url='...')",
1380 1389 ])
1381 1390 raise ValueError(msg)
1382 1391
1383 1392 self.mimetype = mimetype
1384 1393 self.embed = embed
1385 1394 self.width = width
1386 1395 self.height = height
1387 1396 super(Video, self).__init__(data=data, url=url, filename=filename)
1388 1397
1389 1398 def _repr_html_(self):
1390 1399 width = height = ''
1391 1400 if self.width:
1392 1401 width = ' width="%d"' % self.width
1393 1402 if self.height:
1394 1403 height = ' height="%d"' % self.height
1395 1404
1396 1405 # External URLs and potentially local files are not embedded into the
1397 1406 # notebook output.
1398 1407 if not self.embed:
1399 1408 url = self.url if self.url is not None else self.filename
1400 1409 output = """<video src="{0}" controls {1} {2}>
1401 1410 Your browser does not support the <code>video</code> element.
1402 1411 </video>""".format(url, width, height)
1403 1412 return output
1404 1413
1405 1414 # Embedded videos are base64-encoded.
1406 1415 mimetype = self.mimetype
1407 1416 if self.filename is not None:
1408 1417 if not mimetype:
1409 1418 mimetype, _ = mimetypes.guess_type(self.filename)
1410 1419
1411 1420 with open(self.filename, 'rb') as f:
1412 1421 video = f.read()
1413 1422 else:
1414 1423 video = self.data
1415 1424 if isinstance(video, str):
1416 1425 # unicode input is already b64-encoded
1417 1426 b64_video = video
1418 1427 else:
1419 1428 b64_video = b2a_base64(video).decode('ascii').rstrip()
1420 1429
1421 1430 output = """<video controls {0} {1}>
1422 1431 <source src="data:{2};base64,{3}" type="{2}">
1423 1432 Your browser does not support the video tag.
1424 1433 </video>""".format(width, height, mimetype, b64_video)
1425 1434 return output
1426 1435
1427 1436 def reload(self):
1428 1437 # TODO
1429 1438 pass
1430 1439
1431 1440
1432 1441 def clear_output(wait=False):
1433 1442 """Clear the output of the current cell receiving output.
1434 1443
1435 1444 Parameters
1436 1445 ----------
1437 1446 wait : bool [default: false]
1438 1447 Wait to clear the output until new output is available to replace it."""
1439 1448 from IPython.core.interactiveshell import InteractiveShell
1440 1449 if InteractiveShell.initialized():
1441 1450 InteractiveShell.instance().display_pub.clear_output(wait)
1442 1451 else:
1443 1452 print('\033[2K\r', end='')
1444 1453 sys.stdout.flush()
1445 1454 print('\033[2K\r', end='')
1446 1455 sys.stderr.flush()
1447 1456
1448 1457
1449 1458 @skip_doctest
1450 1459 def set_matplotlib_formats(*formats, **kwargs):
1451 1460 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1452 1461
1453 1462 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1454 1463
1455 1464 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1456 1465
1457 1466 To set this in your config files use the following::
1458 1467
1459 1468 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1460 1469 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1461 1470
1462 1471 Parameters
1463 1472 ----------
1464 1473 *formats : strs
1465 1474 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1466 1475 **kwargs :
1467 1476 Keyword args will be relayed to ``figure.canvas.print_figure``.
1468 1477 """
1469 1478 from IPython.core.interactiveshell import InteractiveShell
1470 1479 from IPython.core.pylabtools import select_figure_formats
1471 1480 # build kwargs, starting with InlineBackend config
1472 1481 kw = {}
1473 1482 from ipykernel.pylab.config import InlineBackend
1474 1483 cfg = InlineBackend.instance()
1475 1484 kw.update(cfg.print_figure_kwargs)
1476 1485 kw.update(**kwargs)
1477 1486 shell = InteractiveShell.instance()
1478 1487 select_figure_formats(shell, formats, **kw)
1479 1488
1480 1489 @skip_doctest
1481 1490 def set_matplotlib_close(close=True):
1482 1491 """Set whether the inline backend closes all figures automatically or not.
1483 1492
1484 1493 By default, the inline backend used in the IPython Notebook will close all
1485 1494 matplotlib figures automatically after each cell is run. This means that
1486 1495 plots in different cells won't interfere. Sometimes, you may want to make
1487 1496 a plot in one cell and then refine it in later cells. This can be accomplished
1488 1497 by::
1489 1498
1490 1499 In [1]: set_matplotlib_close(False)
1491 1500
1492 1501 To set this in your config files use the following::
1493 1502
1494 1503 c.InlineBackend.close_figures = False
1495 1504
1496 1505 Parameters
1497 1506 ----------
1498 1507 close : bool
1499 1508 Should all matplotlib figures be automatically closed after each cell is
1500 1509 run?
1501 1510 """
1502 1511 from ipykernel.pylab.config import InlineBackend
1503 1512 cfg = InlineBackend.instance()
1504 1513 cfg.close_figures = close
General Comments 0
You need to be logged in to leave comments. Login now