aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/ipython/py3/IPython/core/display.py
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-02-10 16:44:30 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:30 +0300
commit2598ef1d0aee359b4b6d5fdd1758916d5907d04f (patch)
tree012bb94d777798f1f56ac1cec429509766d05181 /contrib/python/ipython/py3/IPython/core/display.py
parent6751af0b0c1b952fede40b19b71da8025b5d8bcf (diff)
downloadydb-2598ef1d0aee359b4b6d5fdd1758916d5907d04f.tar.gz
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/ipython/py3/IPython/core/display.py')
-rw-r--r--contrib/python/ipython/py3/IPython/core/display.py3112
1 files changed, 1556 insertions, 1556 deletions
diff --git a/contrib/python/ipython/py3/IPython/core/display.py b/contrib/python/ipython/py3/IPython/core/display.py
index f45e7599c9..f5a5a90e4a 100644
--- a/contrib/python/ipython/py3/IPython/core/display.py
+++ b/contrib/python/ipython/py3/IPython/core/display.py
@@ -1,1556 +1,1556 @@
-# -*- coding: utf-8 -*-
-"""Top-level display functions for displaying object in different formats."""
-
-# Copyright (c) IPython Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-
-from binascii import b2a_hex, b2a_base64, hexlify
-import json
-import mimetypes
-import os
-import struct
-import sys
-import warnings
-from copy import deepcopy
-from os.path import splitext
-from pathlib import Path, PurePath
-
-from IPython.utils.py3compat import cast_unicode
-from IPython.testing.skipdoctest import skip_doctest
-
-__all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
-'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
-'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
-'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
-'GeoJSON', 'Javascript', 'Image', 'clear_output', 'set_matplotlib_formats',
-'set_matplotlib_close', 'publish_display_data', 'update_display', 'DisplayHandle',
-'Video']
-
-#-----------------------------------------------------------------------------
-# utility functions
-#-----------------------------------------------------------------------------
-
-def _safe_exists(path):
- """Check path, but don't let exceptions raise"""
- try:
- return os.path.exists(path)
- except Exception:
- return False
-
-def _merge(d1, d2):
- """Like update, but merges sub-dicts instead of clobbering at the top level.
-
- Updates d1 in-place
- """
-
- if not isinstance(d2, dict) or not isinstance(d1, dict):
- return d2
- for key, value in d2.items():
- d1[key] = _merge(d1.get(key), value)
- return d1
-
-def _display_mimetype(mimetype, objs, raw=False, metadata=None):
- """internal implementation of all display_foo methods
-
- Parameters
- ----------
- mimetype : str
- The mimetype to be published (e.g. 'image/png')
- *objs : object
- The Python objects to display, or if raw=True raw text data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
- if metadata:
- metadata = {mimetype: metadata}
- if raw:
- # turn list of pngdata into list of { 'image/png': pngdata }
- objs = [ {mimetype: obj} for obj in objs ]
- display(*objs, raw=raw, metadata=metadata, include=[mimetype])
-
-#-----------------------------------------------------------------------------
-# Main functions
-#-----------------------------------------------------------------------------
-
-# use * to indicate transient is keyword-only
-def publish_display_data(data, metadata=None, source=None, *, transient=None, **kwargs):
- """Publish data and metadata to all frontends.
-
- See the ``display_data`` message in the messaging documentation for
- more details about this message type.
-
- Keys of data and metadata can be any mime-type.
-
- Parameters
- ----------
- data : dict
- A dictionary having keys that are valid MIME types (like
- 'text/plain' or 'image/svg+xml') and values that are the data for
- that MIME type. The data itself must be a JSON'able data
- structure. Minimally all data should have the 'text/plain' data,
- which can be displayed by all frontends. If more than the plain
- text is given, it is up to the frontend to decide which
- representation to use.
- metadata : dict
- A dictionary for metadata related to the data. This can contain
- arbitrary key, value pairs that frontends can use to interpret
- the data. mime-type keys matching those in data can be used
- to specify metadata about particular representations.
- source : str, deprecated
- Unused.
- transient : dict, keyword-only
- A dictionary of transient data, such as display_id.
- """
- from IPython.core.interactiveshell import InteractiveShell
-
- display_pub = InteractiveShell.instance().display_pub
-
- # only pass transient if supplied,
- # to avoid errors with older ipykernel.
- # TODO: We could check for ipykernel version and provide a detailed upgrade message.
- if transient:
- kwargs['transient'] = transient
-
- display_pub.publish(
- data=data,
- metadata=metadata,
- **kwargs
- )
-
-
-def _new_id():
- """Generate a new random text id with urandom"""
- return b2a_hex(os.urandom(16)).decode('ascii')
-
-
-def display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, **kwargs):
- """Display a Python object in all frontends.
-
- By default all representations will be computed and sent to the frontends.
- Frontends can decide which representation is used and how.
-
- In terminal IPython this will be similar to using :func:`print`, for use in richer
- frontends see Jupyter notebook examples with rich display logic.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display.
- raw : bool, optional
- Are the objects to be displayed already mimetype-keyed dicts of raw display data,
- or Python objects that need to be formatted before display? [default: False]
- include : list, tuple or set, optional
- A list of format type strings (MIME types) to include in the
- format data dict. If this is set *only* the format types included
- in this list will be computed.
- exclude : list, tuple or set, optional
- A list of format type strings (MIME types) to exclude in the format
- data dict. If this is set all format types will be computed,
- except for those included in this argument.
- metadata : dict, optional
- A dictionary of metadata to associate with the output.
- mime-type keys in this dictionary will be associated with the individual
- representation formats, if they exist.
- transient : dict, optional
- A dictionary of transient data to associate with the output.
- Data in this dict should not be persisted to files (e.g. notebooks).
- display_id : str, bool optional
- Set an id for the display.
- This id can be used for updating this display area later via update_display.
- If given as `True`, generate a new `display_id`
- clear : bool, optional
- Should the output area be cleared before displaying anything? If True,
- this will wait for additional output before clearing. [default: False]
- kwargs: additional keyword-args, optional
- Additional keyword-arguments are passed through to the display publisher.
-
- Returns
- -------
-
- handle: DisplayHandle
- Returns a handle on updatable displays for use with :func:`update_display`,
- if `display_id` is given. Returns :any:`None` if no `display_id` is given
- (default).
-
- Examples
- --------
-
- >>> class Json(object):
- ... def __init__(self, json):
- ... self.json = json
- ... def _repr_pretty_(self, pp, cycle):
- ... import json
- ... pp.text(json.dumps(self.json, indent=2))
- ... def __repr__(self):
- ... return str(self.json)
- ...
-
- >>> d = Json({1:2, 3: {4:5}})
-
- >>> print(d)
- {1: 2, 3: {4: 5}}
-
- >>> display(d)
- {
- "1": 2,
- "3": {
- "4": 5
- }
- }
-
- >>> def int_formatter(integer, pp, cycle):
- ... pp.text('I'*integer)
-
- >>> plain = get_ipython().display_formatter.formatters['text/plain']
- >>> plain.for_type(int, int_formatter)
- <function _repr_pprint at 0x...>
- >>> display(7-5)
- II
-
- >>> del plain.type_printers[int]
- >>> display(7-5)
- 2
-
- See Also
- --------
-
- :func:`update_display`
-
- Notes
- -----
-
- In Python, objects can declare their textual representation using the
- `__repr__` method. IPython expands on this idea and allows objects to declare
- other, rich representations including:
-
- - HTML
- - JSON
- - PNG
- - JPEG
- - SVG
- - LaTeX
-
- A single object can declare some or all of these representations; all are
- handled by IPython's display system.
-
- The main idea of the first approach is that you have to implement special
- display methods when you define your class, one for each representation you
- want to use. Here is a list of the names of the special methods and the
- values they must return:
-
- - `_repr_html_`: return raw HTML as a string, or a tuple (see below).
- - `_repr_json_`: return a JSONable dict, or a tuple (see below).
- - `_repr_jpeg_`: return raw JPEG data, or a tuple (see below).
- - `_repr_png_`: return raw PNG data, or a tuple (see below).
- - `_repr_svg_`: return raw SVG data as a string, or a tuple (see below).
- - `_repr_latex_`: return LaTeX commands in a string surrounded by "$",
- or a tuple (see below).
- - `_repr_mimebundle_`: return a full mimebundle containing the mapping
- from all mimetypes to data.
- Use this for any mime-type not listed above.
-
- The above functions may also return the object's metadata alonside the
- data. If the metadata is available, the functions will return a tuple
- containing the data and metadata, in that order. If there is no metadata
- available, then the functions will return the data only.
-
- When you are directly writing your own classes, you can adapt them for
- display in IPython by following the above approach. But in practice, you
- often need to work with existing classes that you can't easily modify.
-
- You can refer to the documentation on integrating with the display system in
- order to register custom formatters for already existing types
- (:ref:`integrating_rich_display`).
-
- .. versionadded:: 5.4 display available without import
- .. versionadded:: 6.1 display available without import
-
- Since IPython 5.4 and 6.1 :func:`display` is automatically made available to
- the user without import. If you are using display in a document that might
- be used in a pure python context or with older version of IPython, use the
- following import at the top of your file::
-
- from IPython.display import display
-
- """
- from IPython.core.interactiveshell import InteractiveShell
-
- if not InteractiveShell.initialized():
- # Directly print objects.
- print(*objs)
- return
-
- raw = kwargs.pop("raw", False)
- clear = kwargs.pop("clear", False)
- if transient is None:
- transient = {}
- if metadata is None:
- metadata={}
- if display_id:
- if display_id is True:
- display_id = _new_id()
- transient['display_id'] = display_id
- if kwargs.get('update') and 'display_id' not in transient:
- raise TypeError('display_id required for update_display')
- if transient:
- kwargs['transient'] = transient
-
- if not objs and display_id:
- # if given no objects, but still a request for a display_id,
- # we assume the user wants to insert an empty output that
- # can be updated later
- objs = [{}]
- raw = True
-
- if not raw:
- format = InteractiveShell.instance().display_formatter.format
-
- if clear:
- clear_output(wait=True)
-
- for obj in objs:
- if raw:
- publish_display_data(data=obj, metadata=metadata, **kwargs)
- else:
- format_dict, md_dict = format(obj, include=include, exclude=exclude)
- if not format_dict:
- # nothing to display (e.g. _ipython_display_ took over)
- continue
- if metadata:
- # kwarg-specified metadata gets precedence
- _merge(md_dict, metadata)
- publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
- if display_id:
- return DisplayHandle(display_id)
-
-
-# use * for keyword-only display_id arg
-def update_display(obj, *, display_id, **kwargs):
- """Update an existing display by id
-
- Parameters
- ----------
-
- obj:
- The object with which to update the display
- display_id: keyword-only
- The id of the display to update
-
- See Also
- --------
-
- :func:`display`
- """
- kwargs['update'] = True
- display(obj, display_id=display_id, **kwargs)
-
-
-class DisplayHandle(object):
- """A handle on an updatable display
-
- Call `.update(obj)` to display a new object.
-
- Call `.display(obj`) to add a new instance of this display,
- and update existing instances.
-
- See Also
- --------
-
- :func:`display`, :func:`update_display`
-
- """
-
- def __init__(self, display_id=None):
- if display_id is None:
- display_id = _new_id()
- self.display_id = display_id
-
- def __repr__(self):
- return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
-
- def display(self, obj, **kwargs):
- """Make a new display with my id, updating existing instances.
-
- Parameters
- ----------
-
- obj:
- object to display
- **kwargs:
- additional keyword arguments passed to display
- """
- display(obj, display_id=self.display_id, **kwargs)
-
- def update(self, obj, **kwargs):
- """Update existing displays with my id
-
- Parameters
- ----------
-
- obj:
- object to display
- **kwargs:
- additional keyword arguments passed to update_display
- """
- update_display(obj, display_id=self.display_id, **kwargs)
-
-
-def display_pretty(*objs, **kwargs):
- """Display the pretty (default) representation of an object.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display, or if raw=True raw text data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
- _display_mimetype('text/plain', objs, **kwargs)
-
-
-def display_html(*objs, **kwargs):
- """Display the HTML representation of an object.
-
- Note: If raw=False and the object does not have a HTML
- representation, no HTML will be shown.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display, or if raw=True raw HTML data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
- _display_mimetype('text/html', objs, **kwargs)
-
-
-def display_markdown(*objs, **kwargs):
- """Displays the Markdown representation of an object.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display, or if raw=True raw markdown data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
-
- _display_mimetype('text/markdown', objs, **kwargs)
-
-
-def display_svg(*objs, **kwargs):
- """Display the SVG representation of an object.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display, or if raw=True raw svg data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
- _display_mimetype('image/svg+xml', objs, **kwargs)
-
-
-def display_png(*objs, **kwargs):
- """Display the PNG representation of an object.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display, or if raw=True raw png data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
- _display_mimetype('image/png', objs, **kwargs)
-
-
-def display_jpeg(*objs, **kwargs):
- """Display the JPEG representation of an object.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display, or if raw=True raw JPEG data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
- _display_mimetype('image/jpeg', objs, **kwargs)
-
-
-def display_latex(*objs, **kwargs):
- """Display the LaTeX representation of an object.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display, or if raw=True raw latex data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
- _display_mimetype('text/latex', objs, **kwargs)
-
-
-def display_json(*objs, **kwargs):
- """Display the JSON representation of an object.
-
- Note that not many frontends support displaying JSON.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display, or if raw=True raw json data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
- _display_mimetype('application/json', objs, **kwargs)
-
-
-def display_javascript(*objs, **kwargs):
- """Display the Javascript representation of an object.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display, or if raw=True raw javascript data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
- _display_mimetype('application/javascript', objs, **kwargs)
-
-
-def display_pdf(*objs, **kwargs):
- """Display the PDF representation of an object.
-
- Parameters
- ----------
- *objs : object
- The Python objects to display, or if raw=True raw javascript data to
- display.
- raw : bool
- Are the data objects raw data or Python objects that need to be
- formatted before display? [default: False]
- metadata : dict (optional)
- Metadata to be associated with the specific mimetype output.
- """
- _display_mimetype('application/pdf', objs, **kwargs)
-
-
-#-----------------------------------------------------------------------------
-# Smart classes
-#-----------------------------------------------------------------------------
-
-
-class DisplayObject(object):
- """An object that wraps data to be displayed."""
-
- _read_flags = 'r'
- _show_mem_addr = False
- metadata = None
-
- def __init__(self, data=None, url=None, filename=None, metadata=None):
- """Create a display object given raw data.
-
- When this object is returned by an expression or passed to the
- display function, it will result in the data being displayed
- in the frontend. The MIME type of the data should match the
- subclasses used, so the Png subclass should be used for 'image/png'
- data. If the data is a URL, the data will first be downloaded
- and then displayed. If
-
- Parameters
- ----------
- data : unicode, str or bytes
- The raw data or a URL or file to load the data from
- url : unicode
- A URL to download the data from.
- filename : unicode
- Path to a local file to load the data from.
- metadata : dict
- Dict of metadata associated to be the object when displayed
- """
- if isinstance(data, (Path, PurePath)):
- data = str(data)
-
- if data is not None and isinstance(data, str):
- if data.startswith('http') and url is None:
- url = data
- filename = None
- data = None
- elif _safe_exists(data) and filename is None:
- url = None
- filename = data
- data = None
-
- self.url = url
- self.filename = filename
- # because of @data.setter methods in
- # subclasses ensure url and filename are set
- # before assigning to self.data
- self.data = data
-
- if metadata is not None:
- self.metadata = metadata
- elif self.metadata is None:
- self.metadata = {}
-
- self.reload()
- self._check_data()
-
- def __repr__(self):
- if not self._show_mem_addr:
- cls = self.__class__
- r = "<%s.%s object>" % (cls.__module__, cls.__name__)
- else:
- r = super(DisplayObject, self).__repr__()
- return r
-
- def _check_data(self):
- """Override in subclasses if there's something to check."""
- pass
-
- def _data_and_metadata(self):
- """shortcut for returning metadata with shape information, if defined"""
- if self.metadata:
- return self.data, deepcopy(self.metadata)
- else:
- return self.data
-
- def reload(self):
- """Reload the raw data from file or URL."""
- if self.filename is not None:
- with open(self.filename, self._read_flags) as f:
- self.data = f.read()
- elif self.url is not None:
- # Deferred import
- from urllib.request import urlopen
- response = urlopen(self.url)
- data = response.read()
- # extract encoding from header, if there is one:
- encoding = None
- if 'content-type' in response.headers:
- for sub in response.headers['content-type'].split(';'):
- sub = sub.strip()
- if sub.startswith('charset'):
- encoding = sub.split('=')[-1].strip()
- break
- if 'content-encoding' in response.headers:
- # TODO: do deflate?
- if 'gzip' in response.headers['content-encoding']:
- import gzip
- from io import BytesIO
- with gzip.open(BytesIO(data), 'rt', encoding=encoding) as fp:
- encoding = None
- data = fp.read()
-
- # decode data, if an encoding was specified
- # We only touch self.data once since
- # subclasses such as SVG have @data.setter methods
- # that transform self.data into ... well svg.
- if encoding:
- self.data = data.decode(encoding, 'replace')
- else:
- self.data = data
-
-
-class TextDisplayObject(DisplayObject):
- """Validate that display data is text"""
- def _check_data(self):
- if self.data is not None and not isinstance(self.data, str):
- raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
-
-class Pretty(TextDisplayObject):
-
- def _repr_pretty_(self, pp, cycle):
- return pp.text(self.data)
-
-
-class HTML(TextDisplayObject):
-
- def __init__(self, data=None, url=None, filename=None, metadata=None):
- def warn():
- if not data:
- return False
-
- #
- # Avoid calling lower() on the entire data, because it could be a
- # long string and we're only interested in its beginning and end.
- #
- prefix = data[:10].lower()
- suffix = data[-10:].lower()
- return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
-
- if warn():
- warnings.warn("Consider using IPython.display.IFrame instead")
- super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
-
- def _repr_html_(self):
- return self._data_and_metadata()
-
- def __html__(self):
- """
- This method exists to inform other HTML-using modules (e.g. Markupsafe,
- htmltag, etc) that this object is HTML and does not need things like
- special characters (<>&) escaped.
- """
- return self._repr_html_()
-
-
-class Markdown(TextDisplayObject):
-
- def _repr_markdown_(self):
- return self._data_and_metadata()
-
-
-class Math(TextDisplayObject):
-
- def _repr_latex_(self):
- s = r"$\displaystyle %s$" % self.data.strip('$')
- if self.metadata:
- return s, deepcopy(self.metadata)
- else:
- return s
-
-
-class Latex(TextDisplayObject):
-
- def _repr_latex_(self):
- return self._data_and_metadata()
-
-
-class SVG(DisplayObject):
- """Embed an SVG into the display.
-
- Note if you just want to view a svg image via a URL use `:class:Image` with
- a url=URL keyword argument.
- """
-
- _read_flags = 'rb'
- # wrap data in a property, which extracts the <svg> tag, discarding
- # document headers
- _data = None
-
- @property
- def data(self):
- return self._data
-
- @data.setter
- def data(self, svg):
- if svg is None:
- self._data = None
- return
- # parse into dom object
- from xml.dom import minidom
- x = minidom.parseString(svg)
- # get svg tag (should be 1)
- found_svg = x.getElementsByTagName('svg')
- if found_svg:
- svg = found_svg[0].toxml()
- else:
- # fallback on the input, trust the user
- # but this is probably an error.
- pass
- svg = cast_unicode(svg)
- self._data = svg
-
- def _repr_svg_(self):
- return self._data_and_metadata()
-
-class ProgressBar(DisplayObject):
- """Progressbar supports displaying a progressbar like element
- """
- def __init__(self, total):
- """Creates a new progressbar
-
- Parameters
- ----------
- total : int
- maximum size of the progressbar
- """
- self.total = total
- self._progress = 0
- self.html_width = '60ex'
- self.text_width = 60
- self._display_id = hexlify(os.urandom(8)).decode('ascii')
-
- def __repr__(self):
- fraction = self.progress / self.total
- filled = '=' * int(fraction * self.text_width)
- rest = ' ' * (self.text_width - len(filled))
- return '[{}{}] {}/{}'.format(
- filled, rest,
- self.progress, self.total,
- )
-
- def _repr_html_(self):
- return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
- self.html_width, self.total, self.progress)
-
- def display(self):
- display(self, display_id=self._display_id)
-
- def update(self):
- display(self, display_id=self._display_id, update=True)
-
- @property
- def progress(self):
- return self._progress
-
- @progress.setter
- def progress(self, value):
- self._progress = value
- self.update()
-
- def __iter__(self):
- self.display()
- self._progress = -1 # First iteration is 0
- return self
-
- def __next__(self):
- """Returns current value and increments display by one."""
- self.progress += 1
- if self.progress < self.total:
- return self.progress
- else:
- raise StopIteration()
-
-class JSON(DisplayObject):
- """JSON expects a JSON-able dict or list
-
- not an already-serialized JSON string.
-
- Scalar types (None, number, string) are not allowed, only dict or list containers.
- """
- # wrap data in a property, which warns about passing already-serialized JSON
- _data = None
- def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
- """Create a JSON display object given raw data.
-
- Parameters
- ----------
- data : dict or list
- JSON data to display. Not an already-serialized JSON string.
- Scalar types (None, number, string) are not allowed, only dict
- or list containers.
- url : unicode
- A URL to download the data from.
- filename : unicode
- Path to a local file to load the data from.
- expanded : boolean
- Metadata to control whether a JSON display component is expanded.
- metadata: dict
- Specify extra metadata to attach to the json display object.
- root : str
- The name of the root element of the JSON tree
- """
- self.metadata = {
- 'expanded': expanded,
- 'root': root,
- }
- if metadata:
- self.metadata.update(metadata)
- if kwargs:
- self.metadata.update(kwargs)
- super(JSON, self).__init__(data=data, url=url, filename=filename)
-
- def _check_data(self):
- if self.data is not None and not isinstance(self.data, (dict, list)):
- raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
-
- @property
- def data(self):
- return self._data
-
- @data.setter
- def data(self, data):
- if isinstance(data, (Path, PurePath)):
- data = str(data)
-
- if isinstance(data, str):
- if self.filename is None and self.url is None:
- warnings.warn("JSON expects JSONable dict or list, not JSON strings")
- data = json.loads(data)
- self._data = data
-
- def _data_and_metadata(self):
- return self.data, self.metadata
-
- def _repr_json_(self):
- return self._data_and_metadata()
-
-_css_t = """var link = document.createElement("link");
- link.ref = "stylesheet";
- link.type = "text/css";
- link.href = "%s";
- document.head.appendChild(link);
-"""
-
-_lib_t1 = """new Promise(function(resolve, reject) {
- var script = document.createElement("script");
- script.onload = resolve;
- script.onerror = reject;
- script.src = "%s";
- document.head.appendChild(script);
-}).then(() => {
-"""
-
-_lib_t2 = """
-});"""
-
-class GeoJSON(JSON):
- """GeoJSON expects JSON-able dict
-
- not an already-serialized JSON string.
-
- Scalar types (None, number, string) are not allowed, only dict containers.
- """
-
- def __init__(self, *args, **kwargs):
- """Create a GeoJSON display object given raw data.
-
- Parameters
- ----------
- data : dict or list
- VegaLite data. Not an already-serialized JSON string.
- Scalar types (None, number, string) are not allowed, only dict
- or list containers.
- url_template : string
- Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
- layer_options : dict
- Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
- url : unicode
- A URL to download the data from.
- filename : unicode
- Path to a local file to load the data from.
- metadata: dict
- Specify extra metadata to attach to the json display object.
-
- Examples
- --------
-
- The following will display an interactive map of Mars with a point of
- interest on frontend that do support GeoJSON display.
-
- >>> from IPython.display import GeoJSON
-
- >>> GeoJSON(data={
- ... "type": "Feature",
- ... "geometry": {
- ... "type": "Point",
- ... "coordinates": [-81.327, 296.038]
- ... }
- ... },
- ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
- ... layer_options={
- ... "basemap_id": "celestia_mars-shaded-16k_global",
- ... "attribution" : "Celestia/praesepe",
- ... "minZoom" : 0,
- ... "maxZoom" : 18,
- ... })
- <IPython.core.display.GeoJSON object>
-
- In the terminal IPython, you will only see the text representation of
- the GeoJSON object.
-
- """
-
- super(GeoJSON, self).__init__(*args, **kwargs)
-
-
- def _ipython_display_(self):
- bundle = {
- 'application/geo+json': self.data,
- 'text/plain': '<IPython.display.GeoJSON object>'
- }
- metadata = {
- 'application/geo+json': self.metadata
- }
- display(bundle, metadata=metadata, raw=True)
-
-class Javascript(TextDisplayObject):
-
- def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
- """Create a Javascript display object given raw data.
-
- When this object is returned by an expression or passed to the
- display function, it will result in the data being displayed
- in the frontend. If the data is a URL, the data will first be
- downloaded and then displayed.
-
- In the Notebook, the containing element will be available as `element`,
- and jQuery will be available. Content appended to `element` will be
- visible in the output area.
-
- Parameters
- ----------
- data : unicode, str or bytes
- The Javascript source code or a URL to download it from.
- url : unicode
- A URL to download the data from.
- filename : unicode
- Path to a local file to load the data from.
- lib : list or str
- A sequence of Javascript library URLs to load asynchronously before
- running the source code. The full URLs of the libraries should
- be given. A single Javascript library URL can also be given as a
- string.
- css: : list or str
- A sequence of css files to load before running the source code.
- The full URLs of the css files should be given. A single css URL
- can also be given as a string.
- """
- if isinstance(lib, str):
- lib = [lib]
- elif lib is None:
- lib = []
- if isinstance(css, str):
- css = [css]
- elif css is None:
- css = []
- if not isinstance(lib, (list,tuple)):
- raise TypeError('expected sequence, got: %r' % lib)
- if not isinstance(css, (list,tuple)):
- raise TypeError('expected sequence, got: %r' % css)
- self.lib = lib
- self.css = css
- super(Javascript, self).__init__(data=data, url=url, filename=filename)
-
- def _repr_javascript_(self):
- r = ''
- for c in self.css:
- r += _css_t % c
- for l in self.lib:
- r += _lib_t1 % l
- r += self.data
- r += _lib_t2*len(self.lib)
- return r
-
-# constants for identifying png/jpeg data
-_PNG = b'\x89PNG\r\n\x1a\n'
-_JPEG = b'\xff\xd8'
-
-def _pngxy(data):
- """read the (width, height) from a PNG header"""
- ihdr = data.index(b'IHDR')
- # next 8 bytes are width/height
- return struct.unpack('>ii', data[ihdr+4:ihdr+12])
-
-def _jpegxy(data):
- """read the (width, height) from a JPEG header"""
- # adapted from http://www.64lines.com/jpeg-width-height
-
- idx = 4
- while True:
- block_size = struct.unpack('>H', data[idx:idx+2])[0]
- idx = idx + block_size
- if data[idx:idx+2] == b'\xFF\xC0':
- # found Start of Frame
- iSOF = idx
- break
- else:
- # read another block
- idx += 2
-
- h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
- return w, h
-
-def _gifxy(data):
- """read the (width, height) from a GIF header"""
- return struct.unpack('<HH', data[6:10])
-
-
-class Image(DisplayObject):
-
- _read_flags = 'rb'
- _FMT_JPEG = u'jpeg'
- _FMT_PNG = u'png'
- _FMT_GIF = u'gif'
- _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
- _MIMETYPES = {
- _FMT_PNG: 'image/png',
- _FMT_JPEG: 'image/jpeg',
- _FMT_GIF: 'image/gif',
- }
-
- def __init__(self, data=None, url=None, filename=None, format=None,
- embed=None, width=None, height=None, retina=False,
- unconfined=False, metadata=None):
- """Create a PNG/JPEG/GIF image object given raw data.
-
- When this object is returned by an input cell or passed to the
- display function, it will result in the image being displayed
- in the frontend.
-
- Parameters
- ----------
- data : unicode, str or bytes
- The raw image data or a URL or filename to load the data from.
- This always results in embedded image data.
- url : unicode
- A URL to download the data from. If you specify `url=`,
- the image data will not be embedded unless you also specify `embed=True`.
- filename : unicode
- Path to a local file to load the data from.
- Images from a file are always embedded.
- format : unicode
- The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
- for format will be inferred from the filename extension.
- embed : bool
- Should the image data be embedded using a data URI (True) or be
- loaded using an <img> tag. Set this to True if you want the image
- to be viewable later with no internet connection in the notebook.
-
- Default is `True`, unless the keyword argument `url` is set, then
- default value is `False`.
-
- Note that QtConsole is not able to display images if `embed` is set to `False`
- width : int
- Width in pixels to which to constrain the image in html
- height : int
- Height in pixels to which to constrain the image in html
- retina : bool
- Automatically set the width and height to half of the measured
- width and height.
- This only works for embedded images because it reads the width/height
- from image data.
- For non-embedded images, you can just set the desired display width
- and height directly.
- unconfined: bool
- Set unconfined=True to disable max-width confinement of the image.
- metadata: dict
- Specify extra metadata to attach to the image.
-
- Examples
- --------
- # embedded image data, works in qtconsole and notebook
- # when passed positionally, the first arg can be any of raw image data,
- # a URL, or a filename from which to load image data.
- # The result is always embedding image data for inline images.
- Image('http://www.google.fr/images/srpr/logo3w.png')
- Image('/path/to/image.jpg')
- Image(b'RAW_PNG_DATA...')
-
- # Specifying Image(url=...) does not embed the image data,
- # it only generates `<img>` tag with a link to the source.
- # This will not work in the qtconsole or offline.
- Image(url='http://www.google.fr/images/srpr/logo3w.png')
-
- """
- if isinstance(data, (Path, PurePath)):
- data = str(data)
-
- if filename is not None:
- ext = self._find_ext(filename)
- elif url is not None:
- ext = self._find_ext(url)
- elif data is None:
- raise ValueError("No image data found. Expecting filename, url, or data.")
- elif isinstance(data, str) and (
- data.startswith('http') or _safe_exists(data)
- ):
- ext = self._find_ext(data)
- else:
- ext = None
-
- if format is None:
- if ext is not None:
- if ext == u'jpg' or ext == u'jpeg':
- format = self._FMT_JPEG
- elif ext == u'png':
- format = self._FMT_PNG
- elif ext == u'gif':
- format = self._FMT_GIF
- else:
- format = ext.lower()
- elif isinstance(data, bytes):
- # infer image type from image data header,
- # only if format has not been specified.
- if data[:2] == _JPEG:
- format = self._FMT_JPEG
-
- # failed to detect format, default png
- if format is None:
- format = self._FMT_PNG
-
- if format.lower() == 'jpg':
- # jpg->jpeg
- format = self._FMT_JPEG
-
- self.format = format.lower()
- self.embed = embed if embed is not None else (url is None)
-
- if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
- raise ValueError("Cannot embed the '%s' image format" % (self.format))
- if self.embed:
- self._mimetype = self._MIMETYPES.get(self.format)
-
- self.width = width
- self.height = height
- self.retina = retina
- self.unconfined = unconfined
- super(Image, self).__init__(data=data, url=url, filename=filename,
- metadata=metadata)
-
- if self.width is None and self.metadata.get('width', {}):
- self.width = metadata['width']
-
- if self.height is None and self.metadata.get('height', {}):
- self.height = metadata['height']
-
- if retina:
- self._retina_shape()
-
-
- def _retina_shape(self):
- """load pixel-doubled width and height from image data"""
- if not self.embed:
- return
- if self.format == self._FMT_PNG:
- w, h = _pngxy(self.data)
- elif self.format == self._FMT_JPEG:
- w, h = _jpegxy(self.data)
- elif self.format == self._FMT_GIF:
- w, h = _gifxy(self.data)
- else:
- # retina only supports png
- return
- self.width = w // 2
- self.height = h // 2
-
- def reload(self):
- """Reload the raw data from file or URL."""
- if self.embed:
- super(Image,self).reload()
- if self.retina:
- self._retina_shape()
-
- def _repr_html_(self):
- if not self.embed:
- width = height = klass = ''
- if self.width:
- width = ' width="%d"' % self.width
- if self.height:
- height = ' height="%d"' % self.height
- if self.unconfined:
- klass = ' class="unconfined"'
- return u'<img src="{url}"{width}{height}{klass}/>'.format(
- url=self.url,
- width=width,
- height=height,
- klass=klass,
- )
-
- def _repr_mimebundle_(self, include=None, exclude=None):
- """Return the image as a mimebundle
-
- Any new mimetype support should be implemented here.
- """
- if self.embed:
- mimetype = self._mimetype
- data, metadata = self._data_and_metadata(always_both=True)
- if metadata:
- metadata = {mimetype: metadata}
- return {mimetype: data}, metadata
- else:
- return {'text/html': self._repr_html_()}
-
- def _data_and_metadata(self, always_both=False):
- """shortcut for returning metadata with shape information, if defined"""
- try:
- b64_data = b2a_base64(self.data).decode('ascii')
- except TypeError:
- raise FileNotFoundError(
- "No such file or directory: '%s'" % (self.data))
- md = {}
- if self.metadata:
- md.update(self.metadata)
- if self.width:
- md['width'] = self.width
- if self.height:
- md['height'] = self.height
- if self.unconfined:
- md['unconfined'] = self.unconfined
- if md or always_both:
- return b64_data, md
- else:
- return b64_data
-
- def _repr_png_(self):
- if self.embed and self.format == self._FMT_PNG:
- return self._data_and_metadata()
-
- def _repr_jpeg_(self):
- if self.embed and self.format == self._FMT_JPEG:
- return self._data_and_metadata()
-
- def _find_ext(self, s):
- base, ext = splitext(s)
-
- if not ext:
- return base
-
- # `splitext` includes leading period, so we skip it
- return ext[1:].lower()
-
-
-class Video(DisplayObject):
-
- def __init__(self, data=None, url=None, filename=None, embed=False,
- mimetype=None, width=None, height=None, html_attributes="controls"):
- """Create a video object given raw data or an URL.
-
- When this object is returned by an input cell or passed to the
- display function, it will result in the video being displayed
- in the frontend.
-
- Parameters
- ----------
- data : unicode, str or bytes
- The raw video data or a URL or filename to load the data from.
- Raw data will require passing ``embed=True``.
- url : unicode
- A URL for the video. If you specify ``url=``,
- the image data will not be embedded.
- filename : unicode
- Path to a local file containing the video.
- Will be interpreted as a local URL unless ``embed=True``.
- embed : bool
- Should the video be embedded using a data URI (True) or be
- loaded using a <video> tag (False).
-
- Since videos are large, embedding them should be avoided, if possible.
- You must confirm embedding as your intention by passing ``embed=True``.
-
- Local files can be displayed with URLs without embedding the content, via::
-
- Video('./video.mp4')
-
- mimetype: unicode
- Specify the mimetype for embedded videos.
- Default will be guessed from file extension, if available.
- width : int
- Width in pixels to which to constrain the video in HTML.
- If not supplied, defaults to the width of the video.
- height : int
- Height in pixels to which to constrain the video in html.
- If not supplied, defaults to the height of the video.
- html_attributes : str
- Attributes for the HTML ``<video>`` block.
- Default: ``"controls"`` to get video controls.
- Other examples: ``"controls muted"`` for muted video with controls,
- ``"loop autoplay"`` for looping autoplaying video without controls.
-
- Examples
- --------
-
- ::
-
- Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
- Video('path/to/video.mp4')
- Video('path/to/video.mp4', embed=True)
- Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
- Video(b'raw-videodata', embed=True)
- """
- if isinstance(data, (Path, PurePath)):
- data = str(data)
-
- if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
- url = data
- data = None
- elif os.path.exists(data):
- filename = data
- data = None
-
- if data and not embed:
- msg = ''.join([
- "To embed videos, you must pass embed=True ",
- "(this may make your notebook files huge)\n",
- "Consider passing Video(url='...')",
- ])
- raise ValueError(msg)
-
- self.mimetype = mimetype
- self.embed = embed
- self.width = width
- self.height = height
- self.html_attributes = html_attributes
- super(Video, self).__init__(data=data, url=url, filename=filename)
-
- def _repr_html_(self):
- width = height = ''
- if self.width:
- width = ' width="%d"' % self.width
- if self.height:
- height = ' height="%d"' % self.height
-
- # External URLs and potentially local files are not embedded into the
- # notebook output.
- if not self.embed:
- url = self.url if self.url is not None else self.filename
- output = """<video src="{0}" {1} {2} {3}>
- Your browser does not support the <code>video</code> element.
- </video>""".format(url, self.html_attributes, width, height)
- return output
-
- # Embedded videos are base64-encoded.
- mimetype = self.mimetype
- if self.filename is not None:
- if not mimetype:
- mimetype, _ = mimetypes.guess_type(self.filename)
-
- with open(self.filename, 'rb') as f:
- video = f.read()
- else:
- video = self.data
- if isinstance(video, str):
- # unicode input is already b64-encoded
- b64_video = video
- else:
- b64_video = b2a_base64(video).decode('ascii').rstrip()
-
- output = """<video {0} {1} {2}>
- <source src="data:{3};base64,{4}" type="{3}">
- Your browser does not support the video tag.
- </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
- return output
-
- def reload(self):
- # TODO
- pass
-
-
-def clear_output(wait=False):
- """Clear the output of the current cell receiving output.
-
- Parameters
- ----------
- wait : bool [default: false]
- Wait to clear the output until new output is available to replace it."""
- from IPython.core.interactiveshell import InteractiveShell
- if InteractiveShell.initialized():
- InteractiveShell.instance().display_pub.clear_output(wait)
- else:
- print('\033[2K\r', end='')
- sys.stdout.flush()
- print('\033[2K\r', end='')
- sys.stderr.flush()
-
-
-@skip_doctest
-def set_matplotlib_formats(*formats, **kwargs):
- """
- .. deprecated:: 7.23
-
- use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
-
- Select figure formats for the inline backend. Optionally pass quality for JPEG.
-
- For example, this enables PNG and JPEG output with a JPEG quality of 90%::
-
- In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
-
- To set this in your config files use the following::
-
- c.InlineBackend.figure_formats = {'png', 'jpeg'}
- c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
-
- Parameters
- ----------
- *formats : strs
- One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
- **kwargs :
- Keyword args will be relayed to ``figure.canvas.print_figure``.
- """
- warnings.warn(
- "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
- "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
- DeprecationWarning,
- stacklevel=2,
- )
-
- from matplotlib_inline.backend_inline import (
- set_matplotlib_formats as set_matplotlib_formats_orig,
- )
-
- set_matplotlib_formats_orig(*formats, **kwargs)
-
-@skip_doctest
-def set_matplotlib_close(close=True):
- """
- .. deprecated:: 7.23
-
- use `matplotlib_inline.backend_inline.set_matplotlib_close()`
-
-
- Set whether the inline backend closes all figures automatically or not.
-
- By default, the inline backend used in the IPython Notebook will close all
- matplotlib figures automatically after each cell is run. This means that
- plots in different cells won't interfere. Sometimes, you may want to make
- a plot in one cell and then refine it in later cells. This can be accomplished
- by::
-
- In [1]: set_matplotlib_close(False)
-
- To set this in your config files use the following::
-
- c.InlineBackend.close_figures = False
-
- Parameters
- ----------
- close : bool
- Should all matplotlib figures be automatically closed after each cell is
- run?
- """
- warnings.warn(
- "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
- "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
- DeprecationWarning,
- stacklevel=2,
- )
-
- from matplotlib_inline.backend_inline import (
- set_matplotlib_close as set_matplotlib_close_orig,
- )
-
- set_matplotlib_close_orig(close)
+# -*- coding: utf-8 -*-
+"""Top-level display functions for displaying object in different formats."""
+
+# Copyright (c) IPython Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+
+from binascii import b2a_hex, b2a_base64, hexlify
+import json
+import mimetypes
+import os
+import struct
+import sys
+import warnings
+from copy import deepcopy
+from os.path import splitext
+from pathlib import Path, PurePath
+
+from IPython.utils.py3compat import cast_unicode
+from IPython.testing.skipdoctest import skip_doctest
+
+__all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
+'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
+'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
+'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
+'GeoJSON', 'Javascript', 'Image', 'clear_output', 'set_matplotlib_formats',
+'set_matplotlib_close', 'publish_display_data', 'update_display', 'DisplayHandle',
+'Video']
+
+#-----------------------------------------------------------------------------
+# utility functions
+#-----------------------------------------------------------------------------
+
+def _safe_exists(path):
+ """Check path, but don't let exceptions raise"""
+ try:
+ return os.path.exists(path)
+ except Exception:
+ return False
+
+def _merge(d1, d2):
+ """Like update, but merges sub-dicts instead of clobbering at the top level.
+
+ Updates d1 in-place
+ """
+
+ if not isinstance(d2, dict) or not isinstance(d1, dict):
+ return d2
+ for key, value in d2.items():
+ d1[key] = _merge(d1.get(key), value)
+ return d1
+
+def _display_mimetype(mimetype, objs, raw=False, metadata=None):
+ """internal implementation of all display_foo methods
+
+ Parameters
+ ----------
+ mimetype : str
+ The mimetype to be published (e.g. 'image/png')
+ *objs : object
+ The Python objects to display, or if raw=True raw text data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+ if metadata:
+ metadata = {mimetype: metadata}
+ if raw:
+ # turn list of pngdata into list of { 'image/png': pngdata }
+ objs = [ {mimetype: obj} for obj in objs ]
+ display(*objs, raw=raw, metadata=metadata, include=[mimetype])
+
+#-----------------------------------------------------------------------------
+# Main functions
+#-----------------------------------------------------------------------------
+
+# use * to indicate transient is keyword-only
+def publish_display_data(data, metadata=None, source=None, *, transient=None, **kwargs):
+ """Publish data and metadata to all frontends.
+
+ See the ``display_data`` message in the messaging documentation for
+ more details about this message type.
+
+ Keys of data and metadata can be any mime-type.
+
+ Parameters
+ ----------
+ data : dict
+ A dictionary having keys that are valid MIME types (like
+ 'text/plain' or 'image/svg+xml') and values that are the data for
+ that MIME type. The data itself must be a JSON'able data
+ structure. Minimally all data should have the 'text/plain' data,
+ which can be displayed by all frontends. If more than the plain
+ text is given, it is up to the frontend to decide which
+ representation to use.
+ metadata : dict
+ A dictionary for metadata related to the data. This can contain
+ arbitrary key, value pairs that frontends can use to interpret
+ the data. mime-type keys matching those in data can be used
+ to specify metadata about particular representations.
+ source : str, deprecated
+ Unused.
+ transient : dict, keyword-only
+ A dictionary of transient data, such as display_id.
+ """
+ from IPython.core.interactiveshell import InteractiveShell
+
+ display_pub = InteractiveShell.instance().display_pub
+
+ # only pass transient if supplied,
+ # to avoid errors with older ipykernel.
+ # TODO: We could check for ipykernel version and provide a detailed upgrade message.
+ if transient:
+ kwargs['transient'] = transient
+
+ display_pub.publish(
+ data=data,
+ metadata=metadata,
+ **kwargs
+ )
+
+
+def _new_id():
+ """Generate a new random text id with urandom"""
+ return b2a_hex(os.urandom(16)).decode('ascii')
+
+
+def display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, **kwargs):
+ """Display a Python object in all frontends.
+
+ By default all representations will be computed and sent to the frontends.
+ Frontends can decide which representation is used and how.
+
+ In terminal IPython this will be similar to using :func:`print`, for use in richer
+ frontends see Jupyter notebook examples with rich display logic.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display.
+ raw : bool, optional
+ Are the objects to be displayed already mimetype-keyed dicts of raw display data,
+ or Python objects that need to be formatted before display? [default: False]
+ include : list, tuple or set, optional
+ A list of format type strings (MIME types) to include in the
+ format data dict. If this is set *only* the format types included
+ in this list will be computed.
+ exclude : list, tuple or set, optional
+ A list of format type strings (MIME types) to exclude in the format
+ data dict. If this is set all format types will be computed,
+ except for those included in this argument.
+ metadata : dict, optional
+ A dictionary of metadata to associate with the output.
+ mime-type keys in this dictionary will be associated with the individual
+ representation formats, if they exist.
+ transient : dict, optional
+ A dictionary of transient data to associate with the output.
+ Data in this dict should not be persisted to files (e.g. notebooks).
+ display_id : str, bool optional
+ Set an id for the display.
+ This id can be used for updating this display area later via update_display.
+ If given as `True`, generate a new `display_id`
+ clear : bool, optional
+ Should the output area be cleared before displaying anything? If True,
+ this will wait for additional output before clearing. [default: False]
+ kwargs: additional keyword-args, optional
+ Additional keyword-arguments are passed through to the display publisher.
+
+ Returns
+ -------
+
+ handle: DisplayHandle
+ Returns a handle on updatable displays for use with :func:`update_display`,
+ if `display_id` is given. Returns :any:`None` if no `display_id` is given
+ (default).
+
+ Examples
+ --------
+
+ >>> class Json(object):
+ ... def __init__(self, json):
+ ... self.json = json
+ ... def _repr_pretty_(self, pp, cycle):
+ ... import json
+ ... pp.text(json.dumps(self.json, indent=2))
+ ... def __repr__(self):
+ ... return str(self.json)
+ ...
+
+ >>> d = Json({1:2, 3: {4:5}})
+
+ >>> print(d)
+ {1: 2, 3: {4: 5}}
+
+ >>> display(d)
+ {
+ "1": 2,
+ "3": {
+ "4": 5
+ }
+ }
+
+ >>> def int_formatter(integer, pp, cycle):
+ ... pp.text('I'*integer)
+
+ >>> plain = get_ipython().display_formatter.formatters['text/plain']
+ >>> plain.for_type(int, int_formatter)
+ <function _repr_pprint at 0x...>
+ >>> display(7-5)
+ II
+
+ >>> del plain.type_printers[int]
+ >>> display(7-5)
+ 2
+
+ See Also
+ --------
+
+ :func:`update_display`
+
+ Notes
+ -----
+
+ In Python, objects can declare their textual representation using the
+ `__repr__` method. IPython expands on this idea and allows objects to declare
+ other, rich representations including:
+
+ - HTML
+ - JSON
+ - PNG
+ - JPEG
+ - SVG
+ - LaTeX
+
+ A single object can declare some or all of these representations; all are
+ handled by IPython's display system.
+
+ The main idea of the first approach is that you have to implement special
+ display methods when you define your class, one for each representation you
+ want to use. Here is a list of the names of the special methods and the
+ values they must return:
+
+ - `_repr_html_`: return raw HTML as a string, or a tuple (see below).
+ - `_repr_json_`: return a JSONable dict, or a tuple (see below).
+ - `_repr_jpeg_`: return raw JPEG data, or a tuple (see below).
+ - `_repr_png_`: return raw PNG data, or a tuple (see below).
+ - `_repr_svg_`: return raw SVG data as a string, or a tuple (see below).
+ - `_repr_latex_`: return LaTeX commands in a string surrounded by "$",
+ or a tuple (see below).
+ - `_repr_mimebundle_`: return a full mimebundle containing the mapping
+ from all mimetypes to data.
+ Use this for any mime-type not listed above.
+
+ The above functions may also return the object's metadata alonside the
+ data. If the metadata is available, the functions will return a tuple
+ containing the data and metadata, in that order. If there is no metadata
+ available, then the functions will return the data only.
+
+ When you are directly writing your own classes, you can adapt them for
+ display in IPython by following the above approach. But in practice, you
+ often need to work with existing classes that you can't easily modify.
+
+ You can refer to the documentation on integrating with the display system in
+ order to register custom formatters for already existing types
+ (:ref:`integrating_rich_display`).
+
+ .. versionadded:: 5.4 display available without import
+ .. versionadded:: 6.1 display available without import
+
+ Since IPython 5.4 and 6.1 :func:`display` is automatically made available to
+ the user without import. If you are using display in a document that might
+ be used in a pure python context or with older version of IPython, use the
+ following import at the top of your file::
+
+ from IPython.display import display
+
+ """
+ from IPython.core.interactiveshell import InteractiveShell
+
+ if not InteractiveShell.initialized():
+ # Directly print objects.
+ print(*objs)
+ return
+
+ raw = kwargs.pop("raw", False)
+ clear = kwargs.pop("clear", False)
+ if transient is None:
+ transient = {}
+ if metadata is None:
+ metadata={}
+ if display_id:
+ if display_id is True:
+ display_id = _new_id()
+ transient['display_id'] = display_id
+ if kwargs.get('update') and 'display_id' not in transient:
+ raise TypeError('display_id required for update_display')
+ if transient:
+ kwargs['transient'] = transient
+
+ if not objs and display_id:
+ # if given no objects, but still a request for a display_id,
+ # we assume the user wants to insert an empty output that
+ # can be updated later
+ objs = [{}]
+ raw = True
+
+ if not raw:
+ format = InteractiveShell.instance().display_formatter.format
+
+ if clear:
+ clear_output(wait=True)
+
+ for obj in objs:
+ if raw:
+ publish_display_data(data=obj, metadata=metadata, **kwargs)
+ else:
+ format_dict, md_dict = format(obj, include=include, exclude=exclude)
+ if not format_dict:
+ # nothing to display (e.g. _ipython_display_ took over)
+ continue
+ if metadata:
+ # kwarg-specified metadata gets precedence
+ _merge(md_dict, metadata)
+ publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
+ if display_id:
+ return DisplayHandle(display_id)
+
+
+# use * for keyword-only display_id arg
+def update_display(obj, *, display_id, **kwargs):
+ """Update an existing display by id
+
+ Parameters
+ ----------
+
+ obj:
+ The object with which to update the display
+ display_id: keyword-only
+ The id of the display to update
+
+ See Also
+ --------
+
+ :func:`display`
+ """
+ kwargs['update'] = True
+ display(obj, display_id=display_id, **kwargs)
+
+
+class DisplayHandle(object):
+ """A handle on an updatable display
+
+ Call `.update(obj)` to display a new object.
+
+ Call `.display(obj`) to add a new instance of this display,
+ and update existing instances.
+
+ See Also
+ --------
+
+ :func:`display`, :func:`update_display`
+
+ """
+
+ def __init__(self, display_id=None):
+ if display_id is None:
+ display_id = _new_id()
+ self.display_id = display_id
+
+ def __repr__(self):
+ return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
+
+ def display(self, obj, **kwargs):
+ """Make a new display with my id, updating existing instances.
+
+ Parameters
+ ----------
+
+ obj:
+ object to display
+ **kwargs:
+ additional keyword arguments passed to display
+ """
+ display(obj, display_id=self.display_id, **kwargs)
+
+ def update(self, obj, **kwargs):
+ """Update existing displays with my id
+
+ Parameters
+ ----------
+
+ obj:
+ object to display
+ **kwargs:
+ additional keyword arguments passed to update_display
+ """
+ update_display(obj, display_id=self.display_id, **kwargs)
+
+
+def display_pretty(*objs, **kwargs):
+ """Display the pretty (default) representation of an object.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display, or if raw=True raw text data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+ _display_mimetype('text/plain', objs, **kwargs)
+
+
+def display_html(*objs, **kwargs):
+ """Display the HTML representation of an object.
+
+ Note: If raw=False and the object does not have a HTML
+ representation, no HTML will be shown.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display, or if raw=True raw HTML data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+ _display_mimetype('text/html', objs, **kwargs)
+
+
+def display_markdown(*objs, **kwargs):
+ """Displays the Markdown representation of an object.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display, or if raw=True raw markdown data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+
+ _display_mimetype('text/markdown', objs, **kwargs)
+
+
+def display_svg(*objs, **kwargs):
+ """Display the SVG representation of an object.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display, or if raw=True raw svg data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+ _display_mimetype('image/svg+xml', objs, **kwargs)
+
+
+def display_png(*objs, **kwargs):
+ """Display the PNG representation of an object.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display, or if raw=True raw png data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+ _display_mimetype('image/png', objs, **kwargs)
+
+
+def display_jpeg(*objs, **kwargs):
+ """Display the JPEG representation of an object.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display, or if raw=True raw JPEG data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+ _display_mimetype('image/jpeg', objs, **kwargs)
+
+
+def display_latex(*objs, **kwargs):
+ """Display the LaTeX representation of an object.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display, or if raw=True raw latex data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+ _display_mimetype('text/latex', objs, **kwargs)
+
+
+def display_json(*objs, **kwargs):
+ """Display the JSON representation of an object.
+
+ Note that not many frontends support displaying JSON.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display, or if raw=True raw json data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+ _display_mimetype('application/json', objs, **kwargs)
+
+
+def display_javascript(*objs, **kwargs):
+ """Display the Javascript representation of an object.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display, or if raw=True raw javascript data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+ _display_mimetype('application/javascript', objs, **kwargs)
+
+
+def display_pdf(*objs, **kwargs):
+ """Display the PDF representation of an object.
+
+ Parameters
+ ----------
+ *objs : object
+ The Python objects to display, or if raw=True raw javascript data to
+ display.
+ raw : bool
+ Are the data objects raw data or Python objects that need to be
+ formatted before display? [default: False]
+ metadata : dict (optional)
+ Metadata to be associated with the specific mimetype output.
+ """
+ _display_mimetype('application/pdf', objs, **kwargs)
+
+
+#-----------------------------------------------------------------------------
+# Smart classes
+#-----------------------------------------------------------------------------
+
+
+class DisplayObject(object):
+ """An object that wraps data to be displayed."""
+
+ _read_flags = 'r'
+ _show_mem_addr = False
+ metadata = None
+
+ def __init__(self, data=None, url=None, filename=None, metadata=None):
+ """Create a display object given raw data.
+
+ When this object is returned by an expression or passed to the
+ display function, it will result in the data being displayed
+ in the frontend. The MIME type of the data should match the
+ subclasses used, so the Png subclass should be used for 'image/png'
+ data. If the data is a URL, the data will first be downloaded
+ and then displayed. If
+
+ Parameters
+ ----------
+ data : unicode, str or bytes
+ The raw data or a URL or file to load the data from
+ url : unicode
+ A URL to download the data from.
+ filename : unicode
+ Path to a local file to load the data from.
+ metadata : dict
+ Dict of metadata associated to be the object when displayed
+ """
+ if isinstance(data, (Path, PurePath)):
+ data = str(data)
+
+ if data is not None and isinstance(data, str):
+ if data.startswith('http') and url is None:
+ url = data
+ filename = None
+ data = None
+ elif _safe_exists(data) and filename is None:
+ url = None
+ filename = data
+ data = None
+
+ self.url = url
+ self.filename = filename
+ # because of @data.setter methods in
+ # subclasses ensure url and filename are set
+ # before assigning to self.data
+ self.data = data
+
+ if metadata is not None:
+ self.metadata = metadata
+ elif self.metadata is None:
+ self.metadata = {}
+
+ self.reload()
+ self._check_data()
+
+ def __repr__(self):
+ if not self._show_mem_addr:
+ cls = self.__class__
+ r = "<%s.%s object>" % (cls.__module__, cls.__name__)
+ else:
+ r = super(DisplayObject, self).__repr__()
+ return r
+
+ def _check_data(self):
+ """Override in subclasses if there's something to check."""
+ pass
+
+ def _data_and_metadata(self):
+ """shortcut for returning metadata with shape information, if defined"""
+ if self.metadata:
+ return self.data, deepcopy(self.metadata)
+ else:
+ return self.data
+
+ def reload(self):
+ """Reload the raw data from file or URL."""
+ if self.filename is not None:
+ with open(self.filename, self._read_flags) as f:
+ self.data = f.read()
+ elif self.url is not None:
+ # Deferred import
+ from urllib.request import urlopen
+ response = urlopen(self.url)
+ data = response.read()
+ # extract encoding from header, if there is one:
+ encoding = None
+ if 'content-type' in response.headers:
+ for sub in response.headers['content-type'].split(';'):
+ sub = sub.strip()
+ if sub.startswith('charset'):
+ encoding = sub.split('=')[-1].strip()
+ break
+ if 'content-encoding' in response.headers:
+ # TODO: do deflate?
+ if 'gzip' in response.headers['content-encoding']:
+ import gzip
+ from io import BytesIO
+ with gzip.open(BytesIO(data), 'rt', encoding=encoding) as fp:
+ encoding = None
+ data = fp.read()
+
+ # decode data, if an encoding was specified
+ # We only touch self.data once since
+ # subclasses such as SVG have @data.setter methods
+ # that transform self.data into ... well svg.
+ if encoding:
+ self.data = data.decode(encoding, 'replace')
+ else:
+ self.data = data
+
+
+class TextDisplayObject(DisplayObject):
+ """Validate that display data is text"""
+ def _check_data(self):
+ if self.data is not None and not isinstance(self.data, str):
+ raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
+
+class Pretty(TextDisplayObject):
+
+ def _repr_pretty_(self, pp, cycle):
+ return pp.text(self.data)
+
+
+class HTML(TextDisplayObject):
+
+ def __init__(self, data=None, url=None, filename=None, metadata=None):
+ def warn():
+ if not data:
+ return False
+
+ #
+ # Avoid calling lower() on the entire data, because it could be a
+ # long string and we're only interested in its beginning and end.
+ #
+ prefix = data[:10].lower()
+ suffix = data[-10:].lower()
+ return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
+
+ if warn():
+ warnings.warn("Consider using IPython.display.IFrame instead")
+ super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
+
+ def _repr_html_(self):
+ return self._data_and_metadata()
+
+ def __html__(self):
+ """
+ This method exists to inform other HTML-using modules (e.g. Markupsafe,
+ htmltag, etc) that this object is HTML and does not need things like
+ special characters (<>&) escaped.
+ """
+ return self._repr_html_()
+
+
+class Markdown(TextDisplayObject):
+
+ def _repr_markdown_(self):
+ return self._data_and_metadata()
+
+
+class Math(TextDisplayObject):
+
+ def _repr_latex_(self):
+ s = r"$\displaystyle %s$" % self.data.strip('$')
+ if self.metadata:
+ return s, deepcopy(self.metadata)
+ else:
+ return s
+
+
+class Latex(TextDisplayObject):
+
+ def _repr_latex_(self):
+ return self._data_and_metadata()
+
+
+class SVG(DisplayObject):
+ """Embed an SVG into the display.
+
+ Note if you just want to view a svg image via a URL use `:class:Image` with
+ a url=URL keyword argument.
+ """
+
+ _read_flags = 'rb'
+ # wrap data in a property, which extracts the <svg> tag, discarding
+ # document headers
+ _data = None
+
+ @property
+ def data(self):
+ return self._data
+
+ @data.setter
+ def data(self, svg):
+ if svg is None:
+ self._data = None
+ return
+ # parse into dom object
+ from xml.dom import minidom
+ x = minidom.parseString(svg)
+ # get svg tag (should be 1)
+ found_svg = x.getElementsByTagName('svg')
+ if found_svg:
+ svg = found_svg[0].toxml()
+ else:
+ # fallback on the input, trust the user
+ # but this is probably an error.
+ pass
+ svg = cast_unicode(svg)
+ self._data = svg
+
+ def _repr_svg_(self):
+ return self._data_and_metadata()
+
+class ProgressBar(DisplayObject):
+ """Progressbar supports displaying a progressbar like element
+ """
+ def __init__(self, total):
+ """Creates a new progressbar
+
+ Parameters
+ ----------
+ total : int
+ maximum size of the progressbar
+ """
+ self.total = total
+ self._progress = 0
+ self.html_width = '60ex'
+ self.text_width = 60
+ self._display_id = hexlify(os.urandom(8)).decode('ascii')
+
+ def __repr__(self):
+ fraction = self.progress / self.total
+ filled = '=' * int(fraction * self.text_width)
+ rest = ' ' * (self.text_width - len(filled))
+ return '[{}{}] {}/{}'.format(
+ filled, rest,
+ self.progress, self.total,
+ )
+
+ def _repr_html_(self):
+ return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
+ self.html_width, self.total, self.progress)
+
+ def display(self):
+ display(self, display_id=self._display_id)
+
+ def update(self):
+ display(self, display_id=self._display_id, update=True)
+
+ @property
+ def progress(self):
+ return self._progress
+
+ @progress.setter
+ def progress(self, value):
+ self._progress = value
+ self.update()
+
+ def __iter__(self):
+ self.display()
+ self._progress = -1 # First iteration is 0
+ return self
+
+ def __next__(self):
+ """Returns current value and increments display by one."""
+ self.progress += 1
+ if self.progress < self.total:
+ return self.progress
+ else:
+ raise StopIteration()
+
+class JSON(DisplayObject):
+ """JSON expects a JSON-able dict or list
+
+ not an already-serialized JSON string.
+
+ Scalar types (None, number, string) are not allowed, only dict or list containers.
+ """
+ # wrap data in a property, which warns about passing already-serialized JSON
+ _data = None
+ def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
+ """Create a JSON display object given raw data.
+
+ Parameters
+ ----------
+ data : dict or list
+ JSON data to display. Not an already-serialized JSON string.
+ Scalar types (None, number, string) are not allowed, only dict
+ or list containers.
+ url : unicode
+ A URL to download the data from.
+ filename : unicode
+ Path to a local file to load the data from.
+ expanded : boolean
+ Metadata to control whether a JSON display component is expanded.
+ metadata: dict
+ Specify extra metadata to attach to the json display object.
+ root : str
+ The name of the root element of the JSON tree
+ """
+ self.metadata = {
+ 'expanded': expanded,
+ 'root': root,
+ }
+ if metadata:
+ self.metadata.update(metadata)
+ if kwargs:
+ self.metadata.update(kwargs)
+ super(JSON, self).__init__(data=data, url=url, filename=filename)
+
+ def _check_data(self):
+ if self.data is not None and not isinstance(self.data, (dict, list)):
+ raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
+
+ @property
+ def data(self):
+ return self._data
+
+ @data.setter
+ def data(self, data):
+ if isinstance(data, (Path, PurePath)):
+ data = str(data)
+
+ if isinstance(data, str):
+ if self.filename is None and self.url is None:
+ warnings.warn("JSON expects JSONable dict or list, not JSON strings")
+ data = json.loads(data)
+ self._data = data
+
+ def _data_and_metadata(self):
+ return self.data, self.metadata
+
+ def _repr_json_(self):
+ return self._data_and_metadata()
+
+_css_t = """var link = document.createElement("link");
+ link.ref = "stylesheet";
+ link.type = "text/css";
+ link.href = "%s";
+ document.head.appendChild(link);
+"""
+
+_lib_t1 = """new Promise(function(resolve, reject) {
+ var script = document.createElement("script");
+ script.onload = resolve;
+ script.onerror = reject;
+ script.src = "%s";
+ document.head.appendChild(script);
+}).then(() => {
+"""
+
+_lib_t2 = """
+});"""
+
+class GeoJSON(JSON):
+ """GeoJSON expects JSON-able dict
+
+ not an already-serialized JSON string.
+
+ Scalar types (None, number, string) are not allowed, only dict containers.
+ """
+
+ def __init__(self, *args, **kwargs):
+ """Create a GeoJSON display object given raw data.
+
+ Parameters
+ ----------
+ data : dict or list
+ VegaLite data. Not an already-serialized JSON string.
+ Scalar types (None, number, string) are not allowed, only dict
+ or list containers.
+ url_template : string
+ Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
+ layer_options : dict
+ Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
+ url : unicode
+ A URL to download the data from.
+ filename : unicode
+ Path to a local file to load the data from.
+ metadata: dict
+ Specify extra metadata to attach to the json display object.
+
+ Examples
+ --------
+
+ The following will display an interactive map of Mars with a point of
+ interest on frontend that do support GeoJSON display.
+
+ >>> from IPython.display import GeoJSON
+
+ >>> GeoJSON(data={
+ ... "type": "Feature",
+ ... "geometry": {
+ ... "type": "Point",
+ ... "coordinates": [-81.327, 296.038]
+ ... }
+ ... },
+ ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
+ ... layer_options={
+ ... "basemap_id": "celestia_mars-shaded-16k_global",
+ ... "attribution" : "Celestia/praesepe",
+ ... "minZoom" : 0,
+ ... "maxZoom" : 18,
+ ... })
+ <IPython.core.display.GeoJSON object>
+
+ In the terminal IPython, you will only see the text representation of
+ the GeoJSON object.
+
+ """
+
+ super(GeoJSON, self).__init__(*args, **kwargs)
+
+
+ def _ipython_display_(self):
+ bundle = {
+ 'application/geo+json': self.data,
+ 'text/plain': '<IPython.display.GeoJSON object>'
+ }
+ metadata = {
+ 'application/geo+json': self.metadata
+ }
+ display(bundle, metadata=metadata, raw=True)
+
+class Javascript(TextDisplayObject):
+
+ def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
+ """Create a Javascript display object given raw data.
+
+ When this object is returned by an expression or passed to the
+ display function, it will result in the data being displayed
+ in the frontend. If the data is a URL, the data will first be
+ downloaded and then displayed.
+
+ In the Notebook, the containing element will be available as `element`,
+ and jQuery will be available. Content appended to `element` will be
+ visible in the output area.
+
+ Parameters
+ ----------
+ data : unicode, str or bytes
+ The Javascript source code or a URL to download it from.
+ url : unicode
+ A URL to download the data from.
+ filename : unicode
+ Path to a local file to load the data from.
+ lib : list or str
+ A sequence of Javascript library URLs to load asynchronously before
+ running the source code. The full URLs of the libraries should
+ be given. A single Javascript library URL can also be given as a
+ string.
+ css: : list or str
+ A sequence of css files to load before running the source code.
+ The full URLs of the css files should be given. A single css URL
+ can also be given as a string.
+ """
+ if isinstance(lib, str):
+ lib = [lib]
+ elif lib is None:
+ lib = []
+ if isinstance(css, str):
+ css = [css]
+ elif css is None:
+ css = []
+ if not isinstance(lib, (list,tuple)):
+ raise TypeError('expected sequence, got: %r' % lib)
+ if not isinstance(css, (list,tuple)):
+ raise TypeError('expected sequence, got: %r' % css)
+ self.lib = lib
+ self.css = css
+ super(Javascript, self).__init__(data=data, url=url, filename=filename)
+
+ def _repr_javascript_(self):
+ r = ''
+ for c in self.css:
+ r += _css_t % c
+ for l in self.lib:
+ r += _lib_t1 % l
+ r += self.data
+ r += _lib_t2*len(self.lib)
+ return r
+
+# constants for identifying png/jpeg data
+_PNG = b'\x89PNG\r\n\x1a\n'
+_JPEG = b'\xff\xd8'
+
+def _pngxy(data):
+ """read the (width, height) from a PNG header"""
+ ihdr = data.index(b'IHDR')
+ # next 8 bytes are width/height
+ return struct.unpack('>ii', data[ihdr+4:ihdr+12])
+
+def _jpegxy(data):
+ """read the (width, height) from a JPEG header"""
+ # adapted from http://www.64lines.com/jpeg-width-height
+
+ idx = 4
+ while True:
+ block_size = struct.unpack('>H', data[idx:idx+2])[0]
+ idx = idx + block_size
+ if data[idx:idx+2] == b'\xFF\xC0':
+ # found Start of Frame
+ iSOF = idx
+ break
+ else:
+ # read another block
+ idx += 2
+
+ h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
+ return w, h
+
+def _gifxy(data):
+ """read the (width, height) from a GIF header"""
+ return struct.unpack('<HH', data[6:10])
+
+
+class Image(DisplayObject):
+
+ _read_flags = 'rb'
+ _FMT_JPEG = u'jpeg'
+ _FMT_PNG = u'png'
+ _FMT_GIF = u'gif'
+ _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
+ _MIMETYPES = {
+ _FMT_PNG: 'image/png',
+ _FMT_JPEG: 'image/jpeg',
+ _FMT_GIF: 'image/gif',
+ }
+
+ def __init__(self, data=None, url=None, filename=None, format=None,
+ embed=None, width=None, height=None, retina=False,
+ unconfined=False, metadata=None):
+ """Create a PNG/JPEG/GIF image object given raw data.
+
+ When this object is returned by an input cell or passed to the
+ display function, it will result in the image being displayed
+ in the frontend.
+
+ Parameters
+ ----------
+ data : unicode, str or bytes
+ The raw image data or a URL or filename to load the data from.
+ This always results in embedded image data.
+ url : unicode
+ A URL to download the data from. If you specify `url=`,
+ the image data will not be embedded unless you also specify `embed=True`.
+ filename : unicode
+ Path to a local file to load the data from.
+ Images from a file are always embedded.
+ format : unicode
+ The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
+ for format will be inferred from the filename extension.
+ embed : bool
+ Should the image data be embedded using a data URI (True) or be
+ loaded using an <img> tag. Set this to True if you want the image
+ to be viewable later with no internet connection in the notebook.
+
+ Default is `True`, unless the keyword argument `url` is set, then
+ default value is `False`.
+
+ Note that QtConsole is not able to display images if `embed` is set to `False`
+ width : int
+ Width in pixels to which to constrain the image in html
+ height : int
+ Height in pixels to which to constrain the image in html
+ retina : bool
+ Automatically set the width and height to half of the measured
+ width and height.
+ This only works for embedded images because it reads the width/height
+ from image data.
+ For non-embedded images, you can just set the desired display width
+ and height directly.
+ unconfined: bool
+ Set unconfined=True to disable max-width confinement of the image.
+ metadata: dict
+ Specify extra metadata to attach to the image.
+
+ Examples
+ --------
+ # embedded image data, works in qtconsole and notebook
+ # when passed positionally, the first arg can be any of raw image data,
+ # a URL, or a filename from which to load image data.
+ # The result is always embedding image data for inline images.
+ Image('http://www.google.fr/images/srpr/logo3w.png')
+ Image('/path/to/image.jpg')
+ Image(b'RAW_PNG_DATA...')
+
+ # Specifying Image(url=...) does not embed the image data,
+ # it only generates `<img>` tag with a link to the source.
+ # This will not work in the qtconsole or offline.
+ Image(url='http://www.google.fr/images/srpr/logo3w.png')
+
+ """
+ if isinstance(data, (Path, PurePath)):
+ data = str(data)
+
+ if filename is not None:
+ ext = self._find_ext(filename)
+ elif url is not None:
+ ext = self._find_ext(url)
+ elif data is None:
+ raise ValueError("No image data found. Expecting filename, url, or data.")
+ elif isinstance(data, str) and (
+ data.startswith('http') or _safe_exists(data)
+ ):
+ ext = self._find_ext(data)
+ else:
+ ext = None
+
+ if format is None:
+ if ext is not None:
+ if ext == u'jpg' or ext == u'jpeg':
+ format = self._FMT_JPEG
+ elif ext == u'png':
+ format = self._FMT_PNG
+ elif ext == u'gif':
+ format = self._FMT_GIF
+ else:
+ format = ext.lower()
+ elif isinstance(data, bytes):
+ # infer image type from image data header,
+ # only if format has not been specified.
+ if data[:2] == _JPEG:
+ format = self._FMT_JPEG
+
+ # failed to detect format, default png
+ if format is None:
+ format = self._FMT_PNG
+
+ if format.lower() == 'jpg':
+ # jpg->jpeg
+ format = self._FMT_JPEG
+
+ self.format = format.lower()
+ self.embed = embed if embed is not None else (url is None)
+
+ if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
+ raise ValueError("Cannot embed the '%s' image format" % (self.format))
+ if self.embed:
+ self._mimetype = self._MIMETYPES.get(self.format)
+
+ self.width = width
+ self.height = height
+ self.retina = retina
+ self.unconfined = unconfined
+ super(Image, self).__init__(data=data, url=url, filename=filename,
+ metadata=metadata)
+
+ if self.width is None and self.metadata.get('width', {}):
+ self.width = metadata['width']
+
+ if self.height is None and self.metadata.get('height', {}):
+ self.height = metadata['height']
+
+ if retina:
+ self._retina_shape()
+
+
+ def _retina_shape(self):
+ """load pixel-doubled width and height from image data"""
+ if not self.embed:
+ return
+ if self.format == self._FMT_PNG:
+ w, h = _pngxy(self.data)
+ elif self.format == self._FMT_JPEG:
+ w, h = _jpegxy(self.data)
+ elif self.format == self._FMT_GIF:
+ w, h = _gifxy(self.data)
+ else:
+ # retina only supports png
+ return
+ self.width = w // 2
+ self.height = h // 2
+
+ def reload(self):
+ """Reload the raw data from file or URL."""
+ if self.embed:
+ super(Image,self).reload()
+ if self.retina:
+ self._retina_shape()
+
+ def _repr_html_(self):
+ if not self.embed:
+ width = height = klass = ''
+ if self.width:
+ width = ' width="%d"' % self.width
+ if self.height:
+ height = ' height="%d"' % self.height
+ if self.unconfined:
+ klass = ' class="unconfined"'
+ return u'<img src="{url}"{width}{height}{klass}/>'.format(
+ url=self.url,
+ width=width,
+ height=height,
+ klass=klass,
+ )
+
+ def _repr_mimebundle_(self, include=None, exclude=None):
+ """Return the image as a mimebundle
+
+ Any new mimetype support should be implemented here.
+ """
+ if self.embed:
+ mimetype = self._mimetype
+ data, metadata = self._data_and_metadata(always_both=True)
+ if metadata:
+ metadata = {mimetype: metadata}
+ return {mimetype: data}, metadata
+ else:
+ return {'text/html': self._repr_html_()}
+
+ def _data_and_metadata(self, always_both=False):
+ """shortcut for returning metadata with shape information, if defined"""
+ try:
+ b64_data = b2a_base64(self.data).decode('ascii')
+ except TypeError:
+ raise FileNotFoundError(
+ "No such file or directory: '%s'" % (self.data))
+ md = {}
+ if self.metadata:
+ md.update(self.metadata)
+ if self.width:
+ md['width'] = self.width
+ if self.height:
+ md['height'] = self.height
+ if self.unconfined:
+ md['unconfined'] = self.unconfined
+ if md or always_both:
+ return b64_data, md
+ else:
+ return b64_data
+
+ def _repr_png_(self):
+ if self.embed and self.format == self._FMT_PNG:
+ return self._data_and_metadata()
+
+ def _repr_jpeg_(self):
+ if self.embed and self.format == self._FMT_JPEG:
+ return self._data_and_metadata()
+
+ def _find_ext(self, s):
+ base, ext = splitext(s)
+
+ if not ext:
+ return base
+
+ # `splitext` includes leading period, so we skip it
+ return ext[1:].lower()
+
+
+class Video(DisplayObject):
+
+ def __init__(self, data=None, url=None, filename=None, embed=False,
+ mimetype=None, width=None, height=None, html_attributes="controls"):
+ """Create a video object given raw data or an URL.
+
+ When this object is returned by an input cell or passed to the
+ display function, it will result in the video being displayed
+ in the frontend.
+
+ Parameters
+ ----------
+ data : unicode, str or bytes
+ The raw video data or a URL or filename to load the data from.
+ Raw data will require passing ``embed=True``.
+ url : unicode
+ A URL for the video. If you specify ``url=``,
+ the image data will not be embedded.
+ filename : unicode
+ Path to a local file containing the video.
+ Will be interpreted as a local URL unless ``embed=True``.
+ embed : bool
+ Should the video be embedded using a data URI (True) or be
+ loaded using a <video> tag (False).
+
+ Since videos are large, embedding them should be avoided, if possible.
+ You must confirm embedding as your intention by passing ``embed=True``.
+
+ Local files can be displayed with URLs without embedding the content, via::
+
+ Video('./video.mp4')
+
+ mimetype: unicode
+ Specify the mimetype for embedded videos.
+ Default will be guessed from file extension, if available.
+ width : int
+ Width in pixels to which to constrain the video in HTML.
+ If not supplied, defaults to the width of the video.
+ height : int
+ Height in pixels to which to constrain the video in html.
+ If not supplied, defaults to the height of the video.
+ html_attributes : str
+ Attributes for the HTML ``<video>`` block.
+ Default: ``"controls"`` to get video controls.
+ Other examples: ``"controls muted"`` for muted video with controls,
+ ``"loop autoplay"`` for looping autoplaying video without controls.
+
+ Examples
+ --------
+
+ ::
+
+ Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
+ Video('path/to/video.mp4')
+ Video('path/to/video.mp4', embed=True)
+ Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
+ Video(b'raw-videodata', embed=True)
+ """
+ if isinstance(data, (Path, PurePath)):
+ data = str(data)
+
+ if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
+ url = data
+ data = None
+ elif os.path.exists(data):
+ filename = data
+ data = None
+
+ if data and not embed:
+ msg = ''.join([
+ "To embed videos, you must pass embed=True ",
+ "(this may make your notebook files huge)\n",
+ "Consider passing Video(url='...')",
+ ])
+ raise ValueError(msg)
+
+ self.mimetype = mimetype
+ self.embed = embed
+ self.width = width
+ self.height = height
+ self.html_attributes = html_attributes
+ super(Video, self).__init__(data=data, url=url, filename=filename)
+
+ def _repr_html_(self):
+ width = height = ''
+ if self.width:
+ width = ' width="%d"' % self.width
+ if self.height:
+ height = ' height="%d"' % self.height
+
+ # External URLs and potentially local files are not embedded into the
+ # notebook output.
+ if not self.embed:
+ url = self.url if self.url is not None else self.filename
+ output = """<video src="{0}" {1} {2} {3}>
+ Your browser does not support the <code>video</code> element.
+ </video>""".format(url, self.html_attributes, width, height)
+ return output
+
+ # Embedded videos are base64-encoded.
+ mimetype = self.mimetype
+ if self.filename is not None:
+ if not mimetype:
+ mimetype, _ = mimetypes.guess_type(self.filename)
+
+ with open(self.filename, 'rb') as f:
+ video = f.read()
+ else:
+ video = self.data
+ if isinstance(video, str):
+ # unicode input is already b64-encoded
+ b64_video = video
+ else:
+ b64_video = b2a_base64(video).decode('ascii').rstrip()
+
+ output = """<video {0} {1} {2}>
+ <source src="data:{3};base64,{4}" type="{3}">
+ Your browser does not support the video tag.
+ </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
+ return output
+
+ def reload(self):
+ # TODO
+ pass
+
+
+def clear_output(wait=False):
+ """Clear the output of the current cell receiving output.
+
+ Parameters
+ ----------
+ wait : bool [default: false]
+ Wait to clear the output until new output is available to replace it."""
+ from IPython.core.interactiveshell import InteractiveShell
+ if InteractiveShell.initialized():
+ InteractiveShell.instance().display_pub.clear_output(wait)
+ else:
+ print('\033[2K\r', end='')
+ sys.stdout.flush()
+ print('\033[2K\r', end='')
+ sys.stderr.flush()
+
+
+@skip_doctest
+def set_matplotlib_formats(*formats, **kwargs):
+ """
+ .. deprecated:: 7.23
+
+ use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
+
+ Select figure formats for the inline backend. Optionally pass quality for JPEG.
+
+ For example, this enables PNG and JPEG output with a JPEG quality of 90%::
+
+ In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
+
+ To set this in your config files use the following::
+
+ c.InlineBackend.figure_formats = {'png', 'jpeg'}
+ c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
+
+ Parameters
+ ----------
+ *formats : strs
+ One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
+ **kwargs :
+ Keyword args will be relayed to ``figure.canvas.print_figure``.
+ """
+ warnings.warn(
+ "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
+ "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+
+ from matplotlib_inline.backend_inline import (
+ set_matplotlib_formats as set_matplotlib_formats_orig,
+ )
+
+ set_matplotlib_formats_orig(*formats, **kwargs)
+
+@skip_doctest
+def set_matplotlib_close(close=True):
+ """
+ .. deprecated:: 7.23
+
+ use `matplotlib_inline.backend_inline.set_matplotlib_close()`
+
+
+ Set whether the inline backend closes all figures automatically or not.
+
+ By default, the inline backend used in the IPython Notebook will close all
+ matplotlib figures automatically after each cell is run. This means that
+ plots in different cells won't interfere. Sometimes, you may want to make
+ a plot in one cell and then refine it in later cells. This can be accomplished
+ by::
+
+ In [1]: set_matplotlib_close(False)
+
+ To set this in your config files use the following::
+
+ c.InlineBackend.close_figures = False
+
+ Parameters
+ ----------
+ close : bool
+ Should all matplotlib figures be automatically closed after each cell is
+ run?
+ """
+ warnings.warn(
+ "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
+ "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+
+ from matplotlib_inline.backend_inline import (
+ set_matplotlib_close as set_matplotlib_close_orig,
+ )
+
+ set_matplotlib_close_orig(close)