display.py 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373
  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 binascii import b2a_base64, hexlify
  6. import html
  7. import json
  8. import mimetypes
  9. import os
  10. import struct
  11. import warnings
  12. from copy import deepcopy
  13. from os.path import splitext
  14. from pathlib import Path, PurePath
  15. from typing import Optional
  16. from IPython.testing.skipdoctest import skip_doctest
  17. from . import display_functions
  18. __all__ = [
  19. "display_pretty",
  20. "display_html",
  21. "display_markdown",
  22. "display_svg",
  23. "display_png",
  24. "display_jpeg",
  25. "display_webp",
  26. "display_latex",
  27. "display_json",
  28. "display_javascript",
  29. "display_pdf",
  30. "DisplayObject",
  31. "TextDisplayObject",
  32. "Pretty",
  33. "HTML",
  34. "Markdown",
  35. "Math",
  36. "Latex",
  37. "SVG",
  38. "ProgressBar",
  39. "JSON",
  40. "GeoJSON",
  41. "Javascript",
  42. "Image",
  43. "set_matplotlib_formats",
  44. "set_matplotlib_close",
  45. "Video",
  46. ]
  47. _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
  48. __all__ = __all__ + _deprecated_names
  49. # ----- warn to import from IPython.display -----
  50. from warnings import warn
  51. def __getattr__(name):
  52. if name in _deprecated_names:
  53. warn(
  54. f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython.display",
  55. DeprecationWarning,
  56. stacklevel=2,
  57. )
  58. return getattr(display_functions, name)
  59. if name in globals().keys():
  60. return globals()[name]
  61. else:
  62. raise AttributeError(f"module {__name__} has no attribute {name}")
  63. #-----------------------------------------------------------------------------
  64. # utility functions
  65. #-----------------------------------------------------------------------------
  66. def _safe_exists(path):
  67. """Check path, but don't let exceptions raise"""
  68. try:
  69. return os.path.exists(path)
  70. except Exception:
  71. return False
  72. def _display_mimetype(mimetype, objs, raw=False, metadata=None):
  73. """internal implementation of all display_foo methods
  74. Parameters
  75. ----------
  76. mimetype : str
  77. The mimetype to be published (e.g. 'image/png')
  78. *objs : object
  79. The Python objects to display, or if raw=True raw text data to
  80. display.
  81. raw : bool
  82. Are the data objects raw data or Python objects that need to be
  83. formatted before display? [default: False]
  84. metadata : dict (optional)
  85. Metadata to be associated with the specific mimetype output.
  86. """
  87. if metadata:
  88. metadata = {mimetype: metadata}
  89. if raw:
  90. # turn list of pngdata into list of { 'image/png': pngdata }
  91. objs = [ {mimetype: obj} for obj in objs ]
  92. display_functions.display(*objs, raw=raw, metadata=metadata, include=[mimetype])
  93. #-----------------------------------------------------------------------------
  94. # Main functions
  95. #-----------------------------------------------------------------------------
  96. def display_pretty(*objs, **kwargs):
  97. """Display the pretty (default) representation of an object.
  98. Parameters
  99. ----------
  100. *objs : object
  101. The Python objects to display, or if raw=True raw text data to
  102. display.
  103. raw : bool
  104. Are the data objects raw data or Python objects that need to be
  105. formatted before display? [default: False]
  106. metadata : dict (optional)
  107. Metadata to be associated with the specific mimetype output.
  108. """
  109. _display_mimetype('text/plain', objs, **kwargs)
  110. def display_html(*objs, **kwargs):
  111. """Display the HTML representation of an object.
  112. Note: If raw=False and the object does not have a HTML
  113. representation, no HTML will be shown.
  114. Parameters
  115. ----------
  116. *objs : object
  117. The Python objects to display, or if raw=True raw HTML data to
  118. display.
  119. raw : bool
  120. Are the data objects raw data or Python objects that need to be
  121. formatted before display? [default: False]
  122. metadata : dict (optional)
  123. Metadata to be associated with the specific mimetype output.
  124. """
  125. _display_mimetype('text/html', objs, **kwargs)
  126. def display_markdown(*objs, **kwargs):
  127. """Displays the Markdown representation of an object.
  128. Parameters
  129. ----------
  130. *objs : object
  131. The Python objects to display, or if raw=True raw markdown data to
  132. display.
  133. raw : bool
  134. Are the data objects raw data or Python objects that need to be
  135. formatted before display? [default: False]
  136. metadata : dict (optional)
  137. Metadata to be associated with the specific mimetype output.
  138. """
  139. _display_mimetype('text/markdown', objs, **kwargs)
  140. def display_svg(*objs, **kwargs):
  141. """Display the SVG representation of an object.
  142. Parameters
  143. ----------
  144. *objs : object
  145. The Python objects to display, or if raw=True raw svg data to
  146. display.
  147. raw : bool
  148. Are the data objects raw data or Python objects that need to be
  149. formatted before display? [default: False]
  150. metadata : dict (optional)
  151. Metadata to be associated with the specific mimetype output.
  152. """
  153. _display_mimetype('image/svg+xml', objs, **kwargs)
  154. def display_png(*objs, **kwargs):
  155. """Display the PNG representation of an object.
  156. Parameters
  157. ----------
  158. *objs : object
  159. The Python objects to display, or if raw=True raw png data to
  160. display.
  161. raw : bool
  162. Are the data objects raw data or Python objects that need to be
  163. formatted before display? [default: False]
  164. metadata : dict (optional)
  165. Metadata to be associated with the specific mimetype output.
  166. """
  167. _display_mimetype('image/png', objs, **kwargs)
  168. def display_jpeg(*objs, **kwargs):
  169. """Display the JPEG representation of an object.
  170. Parameters
  171. ----------
  172. *objs : object
  173. The Python objects to display, or if raw=True raw JPEG data to
  174. display.
  175. raw : bool
  176. Are the data objects raw data or Python objects that need to be
  177. formatted before display? [default: False]
  178. metadata : dict (optional)
  179. Metadata to be associated with the specific mimetype output.
  180. """
  181. _display_mimetype('image/jpeg', objs, **kwargs)
  182. def display_webp(*objs, **kwargs):
  183. """Display the WEBP representation of an object.
  184. Parameters
  185. ----------
  186. *objs : object
  187. The Python objects to display, or if raw=True raw JPEG data to
  188. display.
  189. raw : bool
  190. Are the data objects raw data or Python objects that need to be
  191. formatted before display? [default: False]
  192. metadata : dict (optional)
  193. Metadata to be associated with the specific mimetype output.
  194. """
  195. _display_mimetype("image/webp", objs, **kwargs)
  196. def display_latex(*objs, **kwargs):
  197. """Display the LaTeX representation of an object.
  198. Parameters
  199. ----------
  200. *objs : object
  201. The Python objects to display, or if raw=True raw latex data to
  202. display.
  203. raw : bool
  204. Are the data objects raw data or Python objects that need to be
  205. formatted before display? [default: False]
  206. metadata : dict (optional)
  207. Metadata to be associated with the specific mimetype output.
  208. """
  209. _display_mimetype('text/latex', objs, **kwargs)
  210. def display_json(*objs, **kwargs):
  211. """Display the JSON representation of an object.
  212. Note that not many frontends support displaying JSON.
  213. Parameters
  214. ----------
  215. *objs : object
  216. The Python objects to display, or if raw=True raw json data to
  217. display.
  218. raw : bool
  219. Are the data objects raw data or Python objects that need to be
  220. formatted before display? [default: False]
  221. metadata : dict (optional)
  222. Metadata to be associated with the specific mimetype output.
  223. """
  224. _display_mimetype('application/json', objs, **kwargs)
  225. def display_javascript(*objs, **kwargs):
  226. """Display the Javascript representation of an object.
  227. Parameters
  228. ----------
  229. *objs : object
  230. The Python objects to display, or if raw=True raw javascript data to
  231. display.
  232. raw : bool
  233. Are the data objects raw data or Python objects that need to be
  234. formatted before display? [default: False]
  235. metadata : dict (optional)
  236. Metadata to be associated with the specific mimetype output.
  237. """
  238. _display_mimetype('application/javascript', objs, **kwargs)
  239. def display_pdf(*objs, **kwargs):
  240. """Display the PDF representation of an object.
  241. Parameters
  242. ----------
  243. *objs : object
  244. The Python objects to display, or if raw=True raw javascript data to
  245. display.
  246. raw : bool
  247. Are the data objects raw data or Python objects that need to be
  248. formatted before display? [default: False]
  249. metadata : dict (optional)
  250. Metadata to be associated with the specific mimetype output.
  251. """
  252. _display_mimetype('application/pdf', objs, **kwargs)
  253. #-----------------------------------------------------------------------------
  254. # Smart classes
  255. #-----------------------------------------------------------------------------
  256. class DisplayObject(object):
  257. """An object that wraps data to be displayed."""
  258. _read_flags = 'r'
  259. _show_mem_addr = False
  260. metadata = None
  261. def __init__(self, data=None, url=None, filename=None, metadata=None):
  262. """Create a display object given raw data.
  263. When this object is returned by an expression or passed to the
  264. display function, it will result in the data being displayed
  265. in the frontend. The MIME type of the data should match the
  266. subclasses used, so the Png subclass should be used for 'image/png'
  267. data. If the data is a URL, the data will first be downloaded
  268. and then displayed.
  269. Parameters
  270. ----------
  271. data : unicode, str or bytes
  272. The raw data or a URL or file to load the data from
  273. url : unicode
  274. A URL to download the data from.
  275. filename : unicode
  276. Path to a local file to load the data from.
  277. metadata : dict
  278. Dict of metadata associated to be the object when displayed
  279. """
  280. if isinstance(data, (Path, PurePath)):
  281. data = str(data)
  282. if data is not None and isinstance(data, str):
  283. if data.startswith('http') and url is None:
  284. url = data
  285. filename = None
  286. data = None
  287. elif _safe_exists(data) and filename is None:
  288. url = None
  289. filename = data
  290. data = None
  291. self.url = url
  292. self.filename = filename
  293. # because of @data.setter methods in
  294. # subclasses ensure url and filename are set
  295. # before assigning to self.data
  296. self.data = data
  297. if metadata is not None:
  298. self.metadata = metadata
  299. elif self.metadata is None:
  300. self.metadata = {}
  301. self.reload()
  302. self._check_data()
  303. def __repr__(self):
  304. if not self._show_mem_addr:
  305. cls = self.__class__
  306. r = "<%s.%s object>" % (cls.__module__, cls.__name__)
  307. else:
  308. r = super(DisplayObject, self).__repr__()
  309. return r
  310. def _check_data(self):
  311. """Override in subclasses if there's something to check."""
  312. pass
  313. def _data_and_metadata(self):
  314. """shortcut for returning metadata with shape information, if defined"""
  315. if self.metadata:
  316. return self.data, deepcopy(self.metadata)
  317. else:
  318. return self.data
  319. def reload(self):
  320. """Reload the raw data from file or URL."""
  321. if self.filename is not None:
  322. encoding = None if "b" in self._read_flags else "utf-8"
  323. with open(self.filename, self._read_flags, encoding=encoding) as f:
  324. self.data = f.read()
  325. elif self.url is not None:
  326. # Deferred import
  327. from urllib.request import urlopen
  328. response = urlopen(self.url)
  329. data = response.read()
  330. # extract encoding from header, if there is one:
  331. encoding = None
  332. if 'content-type' in response.headers:
  333. for sub in response.headers['content-type'].split(';'):
  334. sub = sub.strip()
  335. if sub.startswith('charset'):
  336. encoding = sub.split('=')[-1].strip()
  337. break
  338. if 'content-encoding' in response.headers:
  339. # TODO: do deflate?
  340. if 'gzip' in response.headers['content-encoding']:
  341. import gzip
  342. from io import BytesIO
  343. # assume utf-8 if encoding is not specified
  344. with gzip.open(
  345. BytesIO(data), "rt", encoding=encoding or "utf-8"
  346. ) as fp:
  347. encoding = None
  348. data = fp.read()
  349. # decode data, if an encoding was specified
  350. # We only touch self.data once since
  351. # subclasses such as SVG have @data.setter methods
  352. # that transform self.data into ... well svg.
  353. if encoding:
  354. self.data = data.decode(encoding, 'replace')
  355. else:
  356. self.data = data
  357. class TextDisplayObject(DisplayObject):
  358. """Create a text display object given raw data.
  359. Parameters
  360. ----------
  361. data : str or unicode
  362. The raw data or a URL or file to load the data from.
  363. url : unicode
  364. A URL to download the data from.
  365. filename : unicode
  366. Path to a local file to load the data from.
  367. metadata : dict
  368. Dict of metadata associated to be the object when displayed
  369. """
  370. def _check_data(self):
  371. if self.data is not None and not isinstance(self.data, str):
  372. raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
  373. class Pretty(TextDisplayObject):
  374. def _repr_pretty_(self, pp, cycle):
  375. return pp.text(self.data)
  376. class HTML(TextDisplayObject):
  377. def __init__(self, data=None, url=None, filename=None, metadata=None):
  378. def warn():
  379. if not data:
  380. return False
  381. #
  382. # Avoid calling lower() on the entire data, because it could be a
  383. # long string and we're only interested in its beginning and end.
  384. #
  385. prefix = data[:10].lower()
  386. suffix = data[-10:].lower()
  387. return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
  388. if warn():
  389. warnings.warn("Consider using IPython.display.IFrame instead")
  390. super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
  391. def _repr_html_(self):
  392. return self._data_and_metadata()
  393. def __html__(self):
  394. """
  395. This method exists to inform other HTML-using modules (e.g. Markupsafe,
  396. htmltag, etc) that this object is HTML and does not need things like
  397. special characters (<>&) escaped.
  398. """
  399. return self._repr_html_()
  400. class Markdown(TextDisplayObject):
  401. def _repr_markdown_(self):
  402. return self._data_and_metadata()
  403. class Math(TextDisplayObject):
  404. def _repr_latex_(self):
  405. s = r"$\displaystyle %s$" % self.data.strip('$')
  406. if self.metadata:
  407. return s, deepcopy(self.metadata)
  408. else:
  409. return s
  410. class Latex(TextDisplayObject):
  411. def _repr_latex_(self):
  412. return self._data_and_metadata()
  413. class SVG(DisplayObject):
  414. """Embed an SVG into the display.
  415. Note if you just want to view a svg image via a URL use `:class:Image` with
  416. a url=URL keyword argument.
  417. """
  418. _read_flags = 'rb'
  419. # wrap data in a property, which extracts the <svg> tag, discarding
  420. # document headers
  421. _data: Optional[str] = None
  422. @property
  423. def data(self):
  424. return self._data
  425. @data.setter
  426. def data(self, svg):
  427. if svg is None:
  428. self._data = None
  429. return
  430. # parse into dom object
  431. from xml.dom import minidom
  432. x = minidom.parseString(svg)
  433. # get svg tag (should be 1)
  434. found_svg = x.getElementsByTagName('svg')
  435. if found_svg:
  436. svg = found_svg[0].toxml()
  437. else:
  438. # fallback on the input, trust the user
  439. # but this is probably an error.
  440. pass
  441. if isinstance(svg, bytes):
  442. self._data = svg.decode(errors="replace")
  443. else:
  444. self._data = svg
  445. def _repr_svg_(self):
  446. return self._data_and_metadata()
  447. class ProgressBar(DisplayObject):
  448. """Progressbar supports displaying a progressbar like element
  449. """
  450. def __init__(self, total):
  451. """Creates a new progressbar
  452. Parameters
  453. ----------
  454. total : int
  455. maximum size of the progressbar
  456. """
  457. self.total = total
  458. self._progress = 0
  459. self.html_width = '60ex'
  460. self.text_width = 60
  461. self._display_id = hexlify(os.urandom(8)).decode('ascii')
  462. def __repr__(self):
  463. fraction = self.progress / self.total
  464. filled = '=' * int(fraction * self.text_width)
  465. rest = ' ' * (self.text_width - len(filled))
  466. return '[{}{}] {}/{}'.format(
  467. filled, rest,
  468. self.progress, self.total,
  469. )
  470. def _repr_html_(self):
  471. return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
  472. self.html_width, self.total, self.progress)
  473. def display(self):
  474. display_functions.display(self, display_id=self._display_id)
  475. def update(self):
  476. display_functions.display(self, display_id=self._display_id, update=True)
  477. @property
  478. def progress(self):
  479. return self._progress
  480. @progress.setter
  481. def progress(self, value):
  482. self._progress = value
  483. self.update()
  484. def __iter__(self):
  485. self.display()
  486. self._progress = -1 # First iteration is 0
  487. return self
  488. def __next__(self):
  489. """Returns current value and increments display by one."""
  490. self.progress += 1
  491. if self.progress < self.total:
  492. return self.progress
  493. else:
  494. raise StopIteration()
  495. class JSON(DisplayObject):
  496. """JSON expects a JSON-able dict or list
  497. not an already-serialized JSON string.
  498. Scalar types (None, number, string) are not allowed, only dict or list containers.
  499. """
  500. # wrap data in a property, which warns about passing already-serialized JSON
  501. _data = None
  502. def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
  503. """Create a JSON display object given raw data.
  504. Parameters
  505. ----------
  506. data : dict or list
  507. JSON data to display. Not an already-serialized JSON string.
  508. Scalar types (None, number, string) are not allowed, only dict
  509. or list containers.
  510. url : unicode
  511. A URL to download the data from.
  512. filename : unicode
  513. Path to a local file to load the data from.
  514. expanded : boolean
  515. Metadata to control whether a JSON display component is expanded.
  516. metadata : dict
  517. Specify extra metadata to attach to the json display object.
  518. root : str
  519. The name of the root element of the JSON tree
  520. """
  521. self.metadata = {
  522. 'expanded': expanded,
  523. 'root': root,
  524. }
  525. if metadata:
  526. self.metadata.update(metadata)
  527. if kwargs:
  528. self.metadata.update(kwargs)
  529. super(JSON, self).__init__(data=data, url=url, filename=filename)
  530. def _check_data(self):
  531. if self.data is not None and not isinstance(self.data, (dict, list)):
  532. raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
  533. @property
  534. def data(self):
  535. return self._data
  536. @data.setter
  537. def data(self, data):
  538. if isinstance(data, (Path, PurePath)):
  539. data = str(data)
  540. if isinstance(data, str):
  541. if self.filename is None and self.url is None:
  542. warnings.warn("JSON expects JSONable dict or list, not JSON strings")
  543. data = json.loads(data)
  544. self._data = data
  545. def _data_and_metadata(self):
  546. return self.data, self.metadata
  547. def _repr_json_(self):
  548. return self._data_and_metadata()
  549. _css_t = """var link = document.createElement("link");
  550. link.rel = "stylesheet";
  551. link.type = "text/css";
  552. link.href = "%s";
  553. document.head.appendChild(link);
  554. """
  555. _lib_t1 = """new Promise(function(resolve, reject) {
  556. var script = document.createElement("script");
  557. script.onload = resolve;
  558. script.onerror = reject;
  559. script.src = "%s";
  560. document.head.appendChild(script);
  561. }).then(() => {
  562. """
  563. _lib_t2 = """
  564. });"""
  565. class GeoJSON(JSON):
  566. """GeoJSON expects JSON-able dict
  567. not an already-serialized JSON string.
  568. Scalar types (None, number, string) are not allowed, only dict containers.
  569. """
  570. def __init__(self, *args, **kwargs):
  571. """Create a GeoJSON display object given raw data.
  572. Parameters
  573. ----------
  574. data : dict or list
  575. VegaLite data. Not an already-serialized JSON string.
  576. Scalar types (None, number, string) are not allowed, only dict
  577. or list containers.
  578. url_template : string
  579. Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
  580. layer_options : dict
  581. Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
  582. url : unicode
  583. A URL to download the data from.
  584. filename : unicode
  585. Path to a local file to load the data from.
  586. metadata : dict
  587. Specify extra metadata to attach to the json display object.
  588. Examples
  589. --------
  590. The following will display an interactive map of Mars with a point of
  591. interest on frontend that do support GeoJSON display.
  592. >>> from IPython.display import GeoJSON
  593. >>> GeoJSON(data={
  594. ... "type": "Feature",
  595. ... "geometry": {
  596. ... "type": "Point",
  597. ... "coordinates": [-81.327, 296.038]
  598. ... }
  599. ... },
  600. ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
  601. ... layer_options={
  602. ... "basemap_id": "celestia_mars-shaded-16k_global",
  603. ... "attribution" : "Celestia/praesepe",
  604. ... "minZoom" : 0,
  605. ... "maxZoom" : 18,
  606. ... })
  607. <IPython.core.display.GeoJSON object>
  608. In the terminal IPython, you will only see the text representation of
  609. the GeoJSON object.
  610. """
  611. super(GeoJSON, self).__init__(*args, **kwargs)
  612. def _ipython_display_(self):
  613. bundle = {
  614. 'application/geo+json': self.data,
  615. 'text/plain': '<IPython.display.GeoJSON object>'
  616. }
  617. metadata = {
  618. 'application/geo+json': self.metadata
  619. }
  620. display_functions.display(bundle, metadata=metadata, raw=True)
  621. class Javascript(TextDisplayObject):
  622. def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
  623. """Create a Javascript display object given raw data.
  624. When this object is returned by an expression or passed to the
  625. display function, it will result in the data being displayed
  626. in the frontend. If the data is a URL, the data will first be
  627. downloaded and then displayed.
  628. In the Notebook, the containing element will be available as `element`,
  629. and jQuery will be available. Content appended to `element` will be
  630. visible in the output area.
  631. Parameters
  632. ----------
  633. data : unicode, str or bytes
  634. The Javascript source code or a URL to download it from.
  635. url : unicode
  636. A URL to download the data from.
  637. filename : unicode
  638. Path to a local file to load the data from.
  639. lib : list or str
  640. A sequence of Javascript library URLs to load asynchronously before
  641. running the source code. The full URLs of the libraries should
  642. be given. A single Javascript library URL can also be given as a
  643. string.
  644. css : list or str
  645. A sequence of css files to load before running the source code.
  646. The full URLs of the css files should be given. A single css URL
  647. can also be given as a string.
  648. """
  649. if isinstance(lib, str):
  650. lib = [lib]
  651. elif lib is None:
  652. lib = []
  653. if isinstance(css, str):
  654. css = [css]
  655. elif css is None:
  656. css = []
  657. if not isinstance(lib, (list,tuple)):
  658. raise TypeError('expected sequence, got: %r' % lib)
  659. if not isinstance(css, (list,tuple)):
  660. raise TypeError('expected sequence, got: %r' % css)
  661. self.lib = lib
  662. self.css = css
  663. super(Javascript, self).__init__(data=data, url=url, filename=filename)
  664. def _repr_javascript_(self):
  665. r = ''
  666. for c in self.css:
  667. r += _css_t % c
  668. for l in self.lib:
  669. r += _lib_t1 % l
  670. r += self.data
  671. r += _lib_t2*len(self.lib)
  672. return r
  673. # constants for identifying png/jpeg/gif/webp data
  674. _PNG = b"\x89PNG\r\n\x1a\n"
  675. _JPEG = b"\xff\xd8"
  676. _GIF1 = b"GIF87a"
  677. _GIF2 = b"GIF89a"
  678. _WEBP = b"WEBP"
  679. def _pngxy(data):
  680. """read the (width, height) from a PNG header"""
  681. ihdr = data.index(b'IHDR')
  682. # next 8 bytes are width/height
  683. return struct.unpack('>ii', data[ihdr+4:ihdr+12])
  684. def _jpegxy(data):
  685. """read the (width, height) from a JPEG header"""
  686. # adapted from http://www.64lines.com/jpeg-width-height
  687. idx = 4
  688. while True:
  689. block_size = struct.unpack('>H', data[idx:idx+2])[0]
  690. idx = idx + block_size
  691. if data[idx:idx+2] == b'\xFF\xC0':
  692. # found Start of Frame
  693. iSOF = idx
  694. break
  695. else:
  696. # read another block
  697. idx += 2
  698. h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
  699. return w, h
  700. def _gifxy(data):
  701. """read the (width, height) from a GIF header"""
  702. return struct.unpack('<HH', data[6:10])
  703. def _webpxy(data):
  704. """read the (width, height) from a WEBP header"""
  705. if data[12:16] == b"VP8 ":
  706. width, height = struct.unpack("<HH", data[24:30])
  707. width = width & 0x3FFF
  708. height = height & 0x3FFF
  709. return (width, height)
  710. elif data[12:16] == b"VP8L":
  711. size_info = struct.unpack("<I", data[21:25])[0]
  712. width = 1 + ((size_info & 0x3F) << 8) | (size_info >> 24)
  713. height = 1 + (
  714. (((size_info >> 8) & 0xF) << 10)
  715. | (((size_info >> 14) & 0x3FC) << 2)
  716. | ((size_info >> 22) & 0x3)
  717. )
  718. return (width, height)
  719. else:
  720. raise ValueError("Not a valid WEBP header")
  721. class Image(DisplayObject):
  722. _read_flags = "rb"
  723. _FMT_JPEG = "jpeg"
  724. _FMT_PNG = "png"
  725. _FMT_GIF = "gif"
  726. _FMT_WEBP = "webp"
  727. _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF, _FMT_WEBP]
  728. _MIMETYPES = {
  729. _FMT_PNG: "image/png",
  730. _FMT_JPEG: "image/jpeg",
  731. _FMT_GIF: "image/gif",
  732. _FMT_WEBP: "image/webp",
  733. }
  734. def __init__(
  735. self,
  736. data=None,
  737. url=None,
  738. filename=None,
  739. format=None,
  740. embed=None,
  741. width=None,
  742. height=None,
  743. retina=False,
  744. unconfined=False,
  745. metadata=None,
  746. alt=None,
  747. ):
  748. """Create a PNG/JPEG/GIF/WEBP image object given raw data.
  749. When this object is returned by an input cell or passed to the
  750. display function, it will result in the image being displayed
  751. in the frontend.
  752. Parameters
  753. ----------
  754. data : unicode, str or bytes
  755. The raw image data or a URL or filename to load the data from.
  756. This always results in embedded image data.
  757. url : unicode
  758. A URL to download the data from. If you specify `url=`,
  759. the image data will not be embedded unless you also specify `embed=True`.
  760. filename : unicode
  761. Path to a local file to load the data from.
  762. Images from a file are always embedded.
  763. format : unicode
  764. The format of the image data (png/jpeg/jpg/gif/webp). If a filename or URL is given
  765. for format will be inferred from the filename extension.
  766. embed : bool
  767. Should the image data be embedded using a data URI (True) or be
  768. loaded using an <img> tag. Set this to True if you want the image
  769. to be viewable later with no internet connection in the notebook.
  770. Default is `True`, unless the keyword argument `url` is set, then
  771. default value is `False`.
  772. Note that QtConsole is not able to display images if `embed` is set to `False`
  773. width : int
  774. Width in pixels to which to constrain the image in html
  775. height : int
  776. Height in pixels to which to constrain the image in html
  777. retina : bool
  778. Automatically set the width and height to half of the measured
  779. width and height.
  780. This only works for embedded images because it reads the width/height
  781. from image data.
  782. For non-embedded images, you can just set the desired display width
  783. and height directly.
  784. unconfined : bool
  785. Set unconfined=True to disable max-width confinement of the image.
  786. metadata : dict
  787. Specify extra metadata to attach to the image.
  788. alt : unicode
  789. Alternative text for the image, for use by screen readers.
  790. Examples
  791. --------
  792. embedded image data, works in qtconsole and notebook
  793. when passed positionally, the first arg can be any of raw image data,
  794. a URL, or a filename from which to load image data.
  795. The result is always embedding image data for inline images.
  796. >>> Image('https://www.google.fr/images/srpr/logo3w.png') # doctest: +SKIP
  797. <IPython.core.display.Image object>
  798. >>> Image('/path/to/image.jpg')
  799. <IPython.core.display.Image object>
  800. >>> Image(b'RAW_PNG_DATA...')
  801. <IPython.core.display.Image object>
  802. Specifying Image(url=...) does not embed the image data,
  803. it only generates ``<img>`` tag with a link to the source.
  804. This will not work in the qtconsole or offline.
  805. >>> Image(url='https://www.google.fr/images/srpr/logo3w.png')
  806. <IPython.core.display.Image object>
  807. """
  808. if isinstance(data, (Path, PurePath)):
  809. data = str(data)
  810. if filename is not None:
  811. ext = self._find_ext(filename)
  812. elif url is not None:
  813. ext = self._find_ext(url)
  814. elif data is None:
  815. raise ValueError("No image data found. Expecting filename, url, or data.")
  816. elif isinstance(data, str) and (
  817. data.startswith('http') or _safe_exists(data)
  818. ):
  819. ext = self._find_ext(data)
  820. else:
  821. ext = None
  822. if format is None:
  823. if ext is not None:
  824. if ext == u'jpg' or ext == u'jpeg':
  825. format = self._FMT_JPEG
  826. elif ext == u'png':
  827. format = self._FMT_PNG
  828. elif ext == u'gif':
  829. format = self._FMT_GIF
  830. elif ext == "webp":
  831. format = self._FMT_WEBP
  832. else:
  833. format = ext.lower()
  834. elif isinstance(data, bytes):
  835. # infer image type from image data header,
  836. # only if format has not been specified.
  837. if data[:2] == _JPEG:
  838. format = self._FMT_JPEG
  839. elif data[:8] == _PNG:
  840. format = self._FMT_PNG
  841. elif data[8:12] == _WEBP:
  842. format = self._FMT_WEBP
  843. elif data[:6] == _GIF1 or data[:6] == _GIF2:
  844. format = self._FMT_GIF
  845. # failed to detect format, default png
  846. if format is None:
  847. format = self._FMT_PNG
  848. if format.lower() == 'jpg':
  849. # jpg->jpeg
  850. format = self._FMT_JPEG
  851. self.format = format.lower()
  852. self.embed = embed if embed is not None else (url is None)
  853. if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
  854. raise ValueError("Cannot embed the '%s' image format" % (self.format))
  855. if self.embed:
  856. self._mimetype = self._MIMETYPES.get(self.format)
  857. self.width = width
  858. self.height = height
  859. self.retina = retina
  860. self.unconfined = unconfined
  861. self.alt = alt
  862. super(Image, self).__init__(data=data, url=url, filename=filename,
  863. metadata=metadata)
  864. if self.width is None and self.metadata.get('width', {}):
  865. self.width = metadata['width']
  866. if self.height is None and self.metadata.get('height', {}):
  867. self.height = metadata['height']
  868. if self.alt is None and self.metadata.get("alt", {}):
  869. self.alt = metadata["alt"]
  870. if retina:
  871. self._retina_shape()
  872. def _retina_shape(self):
  873. """load pixel-doubled width and height from image data"""
  874. if not self.embed:
  875. return
  876. if self.format == self._FMT_PNG:
  877. w, h = _pngxy(self.data)
  878. elif self.format == self._FMT_JPEG:
  879. w, h = _jpegxy(self.data)
  880. elif self.format == self._FMT_GIF:
  881. w, h = _gifxy(self.data)
  882. else:
  883. # retina only supports png
  884. return
  885. self.width = w // 2
  886. self.height = h // 2
  887. def reload(self):
  888. """Reload the raw data from file or URL."""
  889. if self.embed:
  890. super(Image,self).reload()
  891. if self.retina:
  892. self._retina_shape()
  893. def _repr_html_(self):
  894. if not self.embed:
  895. width = height = klass = alt = ""
  896. if self.width:
  897. width = ' width="%d"' % self.width
  898. if self.height:
  899. height = ' height="%d"' % self.height
  900. if self.unconfined:
  901. klass = ' class="unconfined"'
  902. if self.alt:
  903. alt = ' alt="%s"' % html.escape(self.alt)
  904. return '<img src="{url}"{width}{height}{klass}{alt}/>'.format(
  905. url=self.url,
  906. width=width,
  907. height=height,
  908. klass=klass,
  909. alt=alt,
  910. )
  911. def _repr_mimebundle_(self, include=None, exclude=None):
  912. """Return the image as a mimebundle
  913. Any new mimetype support should be implemented here.
  914. """
  915. if self.embed:
  916. mimetype = self._mimetype
  917. data, metadata = self._data_and_metadata(always_both=True)
  918. if metadata:
  919. metadata = {mimetype: metadata}
  920. return {mimetype: data}, metadata
  921. else:
  922. return {'text/html': self._repr_html_()}
  923. def _data_and_metadata(self, always_both=False):
  924. """shortcut for returning metadata with shape information, if defined"""
  925. try:
  926. b64_data = b2a_base64(self.data, newline=False).decode("ascii")
  927. except TypeError as e:
  928. raise FileNotFoundError(
  929. "No such file or directory: '%s'" % (self.data)) from e
  930. md = {}
  931. if self.metadata:
  932. md.update(self.metadata)
  933. if self.width:
  934. md['width'] = self.width
  935. if self.height:
  936. md['height'] = self.height
  937. if self.unconfined:
  938. md['unconfined'] = self.unconfined
  939. if self.alt:
  940. md["alt"] = self.alt
  941. if md or always_both:
  942. return b64_data, md
  943. else:
  944. return b64_data
  945. def _repr_png_(self):
  946. if self.embed and self.format == self._FMT_PNG:
  947. return self._data_and_metadata()
  948. def _repr_jpeg_(self):
  949. if self.embed and self.format == self._FMT_JPEG:
  950. return self._data_and_metadata()
  951. def _find_ext(self, s):
  952. base, ext = splitext(s)
  953. if not ext:
  954. return base
  955. # `splitext` includes leading period, so we skip it
  956. return ext[1:].lower()
  957. class Video(DisplayObject):
  958. def __init__(self, data=None, url=None, filename=None, embed=False,
  959. mimetype=None, width=None, height=None, html_attributes="controls"):
  960. """Create a video object given raw data or an URL.
  961. When this object is returned by an input cell or passed to the
  962. display function, it will result in the video being displayed
  963. in the frontend.
  964. Parameters
  965. ----------
  966. data : unicode, str or bytes
  967. The raw video data or a URL or filename to load the data from.
  968. Raw data will require passing ``embed=True``.
  969. url : unicode
  970. A URL for the video. If you specify ``url=``,
  971. the image data will not be embedded.
  972. filename : unicode
  973. Path to a local file containing the video.
  974. Will be interpreted as a local URL unless ``embed=True``.
  975. embed : bool
  976. Should the video be embedded using a data URI (True) or be
  977. loaded using a <video> tag (False).
  978. Since videos are large, embedding them should be avoided, if possible.
  979. You must confirm embedding as your intention by passing ``embed=True``.
  980. Local files can be displayed with URLs without embedding the content, via::
  981. Video('./video.mp4')
  982. mimetype : unicode
  983. Specify the mimetype for embedded videos.
  984. Default will be guessed from file extension, if available.
  985. width : int
  986. Width in pixels to which to constrain the video in HTML.
  987. If not supplied, defaults to the width of the video.
  988. height : int
  989. Height in pixels to which to constrain the video in html.
  990. If not supplied, defaults to the height of the video.
  991. html_attributes : str
  992. Attributes for the HTML ``<video>`` block.
  993. Default: ``"controls"`` to get video controls.
  994. Other examples: ``"controls muted"`` for muted video with controls,
  995. ``"loop autoplay"`` for looping autoplaying video without controls.
  996. Examples
  997. --------
  998. ::
  999. Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
  1000. Video('path/to/video.mp4')
  1001. Video('path/to/video.mp4', embed=True)
  1002. Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
  1003. Video(b'raw-videodata', embed=True)
  1004. """
  1005. if isinstance(data, (Path, PurePath)):
  1006. data = str(data)
  1007. if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
  1008. url = data
  1009. data = None
  1010. elif data is not None and os.path.exists(data):
  1011. filename = data
  1012. data = None
  1013. if data and not embed:
  1014. msg = ''.join([
  1015. "To embed videos, you must pass embed=True ",
  1016. "(this may make your notebook files huge)\n",
  1017. "Consider passing Video(url='...')",
  1018. ])
  1019. raise ValueError(msg)
  1020. self.mimetype = mimetype
  1021. self.embed = embed
  1022. self.width = width
  1023. self.height = height
  1024. self.html_attributes = html_attributes
  1025. super(Video, self).__init__(data=data, url=url, filename=filename)
  1026. def _repr_html_(self):
  1027. width = height = ''
  1028. if self.width:
  1029. width = ' width="%d"' % self.width
  1030. if self.height:
  1031. height = ' height="%d"' % self.height
  1032. # External URLs and potentially local files are not embedded into the
  1033. # notebook output.
  1034. if not self.embed:
  1035. url = self.url if self.url is not None else self.filename
  1036. output = """<video src="{0}" {1} {2} {3}>
  1037. Your browser does not support the <code>video</code> element.
  1038. </video>""".format(url, self.html_attributes, width, height)
  1039. return output
  1040. # Embedded videos are base64-encoded.
  1041. mimetype = self.mimetype
  1042. if self.filename is not None:
  1043. if not mimetype:
  1044. mimetype, _ = mimetypes.guess_type(self.filename)
  1045. with open(self.filename, 'rb') as f:
  1046. video = f.read()
  1047. else:
  1048. video = self.data
  1049. if isinstance(video, str):
  1050. # unicode input is already b64-encoded
  1051. b64_video = video
  1052. else:
  1053. b64_video = b2a_base64(video, newline=False).decode("ascii").rstrip()
  1054. output = """<video {0} {1} {2}>
  1055. <source src="data:{3};base64,{4}" type="{3}">
  1056. Your browser does not support the video tag.
  1057. </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
  1058. return output
  1059. def reload(self):
  1060. # TODO
  1061. pass
  1062. @skip_doctest
  1063. def set_matplotlib_formats(*formats, **kwargs):
  1064. """
  1065. .. deprecated:: 7.23
  1066. use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
  1067. Select figure formats for the inline backend. Optionally pass quality for JPEG.
  1068. For example, this enables PNG and JPEG output with a JPEG quality of 90%::
  1069. In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
  1070. To set this in your config files use the following::
  1071. c.InlineBackend.figure_formats = {'png', 'jpeg'}
  1072. c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
  1073. Parameters
  1074. ----------
  1075. *formats : strs
  1076. One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
  1077. **kwargs
  1078. Keyword args will be relayed to ``figure.canvas.print_figure``.
  1079. """
  1080. warnings.warn(
  1081. "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
  1082. "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
  1083. DeprecationWarning,
  1084. stacklevel=2,
  1085. )
  1086. from matplotlib_inline.backend_inline import (
  1087. set_matplotlib_formats as set_matplotlib_formats_orig,
  1088. )
  1089. set_matplotlib_formats_orig(*formats, **kwargs)
  1090. @skip_doctest
  1091. def set_matplotlib_close(close=True):
  1092. """
  1093. .. deprecated:: 7.23
  1094. use `matplotlib_inline.backend_inline.set_matplotlib_close()`
  1095. Set whether the inline backend closes all figures automatically or not.
  1096. By default, the inline backend used in the IPython Notebook will close all
  1097. matplotlib figures automatically after each cell is run. This means that
  1098. plots in different cells won't interfere. Sometimes, you may want to make
  1099. a plot in one cell and then refine it in later cells. This can be accomplished
  1100. by::
  1101. In [1]: set_matplotlib_close(False)
  1102. To set this in your config files use the following::
  1103. c.InlineBackend.close_figures = False
  1104. Parameters
  1105. ----------
  1106. close : bool
  1107. Should all matplotlib figures be automatically closed after each cell is
  1108. run?
  1109. """
  1110. warnings.warn(
  1111. "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
  1112. "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
  1113. DeprecationWarning,
  1114. stacklevel=2,
  1115. )
  1116. from matplotlib_inline.backend_inline import (
  1117. set_matplotlib_close as set_matplotlib_close_orig,
  1118. )
  1119. set_matplotlib_close_orig(close)