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