display.py 42 KB

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