##// END OF EJS Templates
Adding third party rich output.
Adding third party rich output.

File last commit:

r17504:b8e80c94
r17505:715c3da4
Show More
Rich Output.ipynb
1523 lines | 239.7 KiB | text/plain | TextLexer

IPython's Rich Display System

In Python, objects can declare their textual representation using the __repr__ method. IPython expands on this idea and allows objects to declare other, richer representations including:

  • HTML
  • JSON
  • PNG
  • JPEG
  • SVG
  • LaTeX

A single object can declare some or all of these representations; all are handled by IPython's display system. This Notebook shows how you can use this display system to incorporate a broad range of content into your Notebooks.

Basic display imports

The display function is a general purpose tool for displaying different representations of objects. Think of it as print for these rich representations.

In [1]:
from IPython.display import display

A few points:

  • Calling display on an object will send all possible representations to the Notebook.
  • These representations are stored in the Notebook document.
  • In general the Notebook will use the richest available representation.

If you want to display a particular representation, there are specific functions for that:

In [2]:
from IPython.display import display_pretty, display_html, display_jpeg, display_png, display_json, display_latex, display_svg

Images

To work with images (JPEG, PNG) use the Image class.

In [3]:
from IPython.display import Image
In [5]:
i = Image(filename='../images/ipython_logo.png')

Returning an Image object from an expression will automatically display it:

In [6]:
i
Out[6]:
No description has been provided for this image

Or you can pass it to display:

In [7]:
display(i)
No description has been provided for this image

An image can also be displayed from raw data or a url

In [8]:
Image(url='http://python.org/images/python-logo.gif')
Out[8]:
No description has been provided for this image

SVG images are also supported out of the box (since modern browsers do a good job of rendering them):

In [9]:
from IPython.display import SVG
SVG(filename='images/python_logo.svg')
Out[9]:
No description has been provided for this image

If we want to create a link to one of them, we can call use the FileLink object.

In [10]:
from IPython.display import FileLink, FileLinks
FileLink('Running Code.ipynb')

Alternatively, if we want to link to all of the files in a directory, we can use the FileLinks object, passing '.' to indicate that we want links generated for the current working directory. Note that if there were other directories under the current directory, FileLinks would work in a recursive manner creating links to files in all sub-directories as well.

Embedded vs Non-embedded Images

By default, image data is embedded in the Notebook document so that the images can be viewed offline. However it is also possible to tell the Image class to only store a link to the image. Let's see how this works using a webcam at Berkeley.

In [12]:
from IPython.display import Image
img_url = 'http://www.lawrencehallofscience.org/static/scienceview/scienceview.berkeley.edu/html/view/view_assets/images/newview.jpg'

# by default Image data are embedded
Embed      = Image(img_url)

# if kwarg `url` is given, the embedding is assumed to be false
SoftLinked = Image(url=img_url)

# In each case, embed can be specified explicitly with the `embed` kwarg
# ForceEmbed = Image(url=img_url, embed=True)

Here is the embedded version. Note that this image was pulled from the webcam when this code cell was originally run and stored in the Notebook. Unless we rerun this cell, this is not todays image.

In [13]:
Embed
Out[13]:
<IPython.core.display.Image at 0x1068d0a10>

Here is today's image from same webcam at Berkeley, (refreshed every minutes, if you reload the notebook), visible only with an active internet connection, that should be different from the previous one. Notebooks saved with this kind of image will be lighter and always reflect the current version of the source, but the image won't display offline.

In [14]:
SoftLinked
Out[14]:
No description has been provided for this image

Of course, if you re-run this Notebook, the two images will be the same again.

Audio

IPython makes it easy to work with sounds interactively. The Audio display class allows you to create an audio control that is embedded in the Notebook. The interface is analogous to the interface of the Image display class. All audio formats supported by the browser can be used. Note that no single format is presently supported in all browsers.

In [15]:
from IPython.display import Audio
Audio(url="http://www.nch.com.au/acm/8k16bitpcm.wav")
Out[15]:

A Numpy array can be auralized automatically. The Audio class normalizes and encodes the data and embed the result in the Notebook.

For instance, when two sine waves with almost the same frequency are superimposed a phenomena known as beats occur. This can be auralised as follows

In [16]:
import numpy as np
max_time = 3
f1 = 220.0
f2 = 224.0
rate = 8000.0
L = 3
times = np.linspace(0,L,rate*L)
signal = np.sin(2*np.pi*f1*times) + np.sin(2*np.pi*f2*times)

Audio(data=signal, rate=rate)
Out[16]:

Video

More exotic objects can also be displayed, as long as their representation supports the IPython display protocol. For example, videos hosted externally on YouTube are easy to load (and writing a similar wrapper for other hosted content is trivial):

In [20]:
from IPython.display import YouTubeVideo
YouTubeVideo('sjfsUzECqK0')
Out[20]:

Using the nascent video capabilities of modern browsers, you may also be able to display local videos. At the moment this doesn't work very well in all browsers, so it may or may not work for you; we will continue testing this and looking for ways to make it more robust.

The following cell loads a local file called animation.m4v, encodes the raw video as base64 for http transport, and uses the HTML5 video tag to load it. On Chrome 15 it works correctly, displaying a control bar at the bottom with a play/pause button and a location slider.

In [18]:
from IPython.display import HTML
from base64 import b64encode
video = open("images/animation.m4v", "rb").read()
video_encoded = b64encode(video).decode('ascii')
video_tag = '<video controls alt="test" src="data:video/x-m4v;base64,{0}">'.format(video_encoded)
HTML(data=video_tag)
Out[18]:

HTML

Python objects can declare HTML representations that will be displayed in the Notebook. If you have some HTML you want to display, simply use the HTML class.

In [19]:
from IPython.display import HTML
In [20]:
s = """<table>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
<tr>
<td>row 1, cell 1</td>
<td>row 1, cell 2</td>
</tr>
<tr>
<td>row 2, cell 1</td>
<td>row 2, cell 2</td>
</tr>
</table>"""
In [21]:
h = HTML(s); h
Out[21]:
Header 1 Header 2
row 1, cell 1 row 1, cell 2
row 2, cell 1 row 2, cell 2

If you want to write HTML or Javascript straight to the frontend, you can use %%html or %%javascript cell magics. These are exactly the same as writing display(HTML("""cell contents""")), etc.

In [1]:
%%html
<table>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
<tr>
<td>row 1, cell 1</td>
<td>row 1, cell 2</td>
</tr>
<tr>
<td>row 2, cell 1</td>
<td>row 2, cell 2</td>
</tr>
</table>
Header 1 Header 2
row 1, cell 1 row 1, cell 2
row 2, cell 1 row 2, cell 2

Pandas makes use of this capability to allow DataFrames to be represented as HTML tables.

JavaScript

In [2]:
from IPython.display import Javascript
In [8]:
Javascript(
    """$.getScript('//cdnjs.cloudflare.com/ajax/libs/d3/3.2.2/d3.v3.min.js')"""
)
Out[8]:
SandBoxed(IPython.core.display.Javascript object)
In [4]:
%%html
<style type="text/css">

circle {
  fill: rgb(31, 119, 180);
  fill-opacity: .25;
  stroke: rgb(31, 119, 180);
  stroke-width: 1px;
}

.leaf circle {
  fill: #ff7f0e;
  fill-opacity: 1;
}

text {
  font: 10px sans-serif;
}

</style>
In [7]:
%%javascript

// element is the jQuery element we will append to
var e = element.get(0);
    
var diameter = 600,
    format = d3.format(",d");

var pack = d3.layout.pack()
    .size([diameter - 4, diameter - 4])
    .value(function(d) { return d.size; });

var svg = d3.select(e).append("svg")
    .attr("width", diameter)
    .attr("height", diameter)
  .append("g")
    .attr("transform", "translate(2,2)");

d3.json("data/flare.json", function(error, root) {
  var node = svg.datum(root).selectAll(".node")
      .data(pack.nodes)
    .enter().append("g")
      .attr("class", function(d) { return d.children ? "node" : "leaf node"; })
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

  node.append("title")
      .text(function(d) { return d.name + (d.children ? "" : ": " + format(d.size)); });

  node.append("circle")
      .attr("r", function(d) { return d.r; });

  node.filter(function(d) { return !d.children; }).append("text")
      .attr("dy", ".3em")
      .style("text-anchor", "middle")
      .text(function(d) { return d.name.substring(0, d.r / 3); });
});

d3.select(self.frameElement).style("height", diameter + "px");
SandBoxed(IPython.core.display.Javascript object)

Pandas

In [9]:
import pandas

Here is a small amount of stock data for APPL:

In [10]:
%%writefile data.csv
Date,Open,High,Low,Close,Volume,Adj Close
2012-06-01,569.16,590.00,548.50,584.00,14077000,581.50
2012-05-01,584.90,596.76,522.18,577.73,18827900,575.26
2012-04-02,601.83,644.00,555.00,583.98,28759100,581.48
2012-03-01,548.17,621.45,516.22,599.55,26486000,596.99
2012-02-01,458.41,547.61,453.98,542.44,22001000,540.12
2012-01-03,409.40,458.24,409.00,456.48,12949100,454.53
Writing data.csv

Read this as into a DataFrame:

In [11]:
df = pandas.read_csv('data.csv')

And view the HTML representation:

In [12]:
df
Out[12]:
Date Open High Low Close Volume Adj Close
0 2012-06-01 569.16 590.00 548.50 584.00 14077000 581.50
1 2012-05-01 584.90 596.76 522.18 577.73 18827900 575.26
2 2012-04-02 601.83 644.00 555.00 583.98 28759100 581.48
3 2012-03-01 548.17 621.45 516.22 599.55 26486000 596.99
4 2012-02-01 458.41 547.61 453.98 542.44 22001000 540.12
5 2012-01-03 409.40 458.24 409.00 456.48 12949100 454.53

6 rows × 7 columns

SymPy

In [13]:
from sympy.interactive.printing import init_printing
init_printing(use_latex='mathjax')
In [14]:
from __future__ import division
import sympy as sym
from sympy import *
x, y, z = symbols("x y z")
k, m, n = symbols("k m n", integer=True)
f, g, h = map(Function, 'fgh')
In [15]:
Rational(3,2)*pi + exp(I*x) / (x**2 + y)
Out[15]:
$$\frac{3 \pi}{2} + \frac{e^{i x}}{x^{2} + y}$$
In [16]:
a = 1/x + (x*sin(x) - 1)/x
a
Out[16]:
$$\frac{1}{x} \left(x \sin{\left (x \right )} - 1\right) + \frac{1}{x}$$
In [17]:
(1/cos(x)).series(x, 0, 6)
Out[17]:
$$1 + \frac{x^{2}}{2} + \frac{5 x^{4}}{24} + \mathcal{O}\left(x^{6}\right)$$

External sites

You can even embed an entire page from another site in an iframe; for example this is today's Wikipedia page for mobile users:

In [19]:
from IPython.display import IFrame
IFrame('http://python.org', width='100%', height=350)
Out[19]:

LaTeX

And we also support the display of mathematical expressions typeset in LaTeX, which is rendered in the browser thanks to the MathJax library.

In [27]:
from IPython.display import Math
Math(r'F(k) = \int_{-\infty}^{\infty} f(x) e^{2\pi i k} dx')
Out[27]:
$$F(k) = \int_{-\infty}^{\infty} f(x) e^{2\pi i k} dx$$

With the Latex class, you have to include the delimiters yourself. This allows you to use other LaTeX modes such as eqnarray:

In [28]:
from IPython.display import Latex
Latex(r"""\begin{eqnarray}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\
\nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} & = 0 
\end{eqnarray}""")
Out[28]:
\begin{eqnarray} \nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\ \nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\ \nabla \cdot \vec{\mathbf{B}} & = 0 \end{eqnarray}

Or you can enter latex directly with the %%latex cell magic:

In [29]:
%%latex
\begin{align}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\
\nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} & = 0
\end{align}
\begin{align} \nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\ \nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\ \nabla \cdot \vec{\mathbf{B}} & = 0 \end{align}