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