diff --git a/docs/examples/notebooks/display_protocol.ipynb b/docs/examples/notebooks/display_protocol.ipynb index 92560da..1779fda 100644 --- a/docs/examples/notebooks/display_protocol.ipynb +++ b/docs/examples/notebooks/display_protocol.ipynb @@ -1,379 +1,378 @@ { - "metadata": { - "name": "display_protocol" + "metadata": { + "name": "display_protocol" + }, + "nbformat": 2, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Using the IPython display protocol for your own objects", + "", + "IPython extends the idea of the ``__repr__`` method in Python to support multiple representations for a given", + "object, which clients can use to display the object according to their capabilities. An object can return multiple", + "representations of itself by implementing special methods, and you can also define at runtime custom display ", + "functions for existing objects whose methods you can't or won't modify. In this notebook, we show how both approaches work.", + "", + "
", + "**Note:** this notebook has had all output cells stripped out so we can include it in the IPython documentation with ", + "a minimal file size. You'll need to manually execute the cells to see the output (you can run all of them with the ", + "\"Run All\" button, or execute each individually). You must start this notebook with", + "
", 
+      "ipython notebook --pylab inline", 
+      "
", + "", + "to ensure pylab support is available for plots.", + "", + "## Custom-built classes with dedicated ``_repr_*_`` methods", + "", + "In our first example, we illustrate how objects can expose directly to IPython special representations of", + "themselves, by providing methods such as ``_repr_svg_``, ``_repr_png_``, ``_repr_latex_``, etc. For a full", + "list of the special ``_repr_*_`` methods supported, see the code in ``IPython.core.displaypub``.", + "", + "As an illustration, we build a class that holds data generated by sampling a Gaussian distribution with given mean ", + "and variance. The class can display itself in a variety of ways: as a LaTeX expression or as an image in PNG or SVG ", + "format. Each frontend can then decide which representation it can handle.", + "Further, we illustrate how to expose directly to the user the ability to directly access the various alternate ", + "representations (since by default displaying the object itself will only show one, and which is shown will depend on the ", + "required representations that even cache necessary data in cases where it may be expensive to compute.", + "", + "The next cell defines the Gaussian class:" + ] }, - "nbformat": 2, - "worksheets": [ - { - "cells": [ - { - "cell_type": "markdown", - "source": [ - "# Using the IPython display protocol for your own objects", - "", - "IPython extends the idea of the ``__repr__`` method in Python to support multiple representations for a given", - "object, which clients can use to display the object according to their capabilities. An object can return multiple", - "representations of itself by implementing special methods, and you can also define at runtime custom display ", - "functions for existing objects whose methods you can't or won't modify. In this notebook, we show how both approaches work.", - "", - "
", - "**Note:** this notebook has had all output cells stripped out so we can include it in the IPython documentation with ", - "a minimal file size. You'll need to manually execute the cells to see the output (you can run all of them with the ", - "\"Run All\" button, or execute each individually). You must start this notebook with", - "
", 
-                        "ipython notebook --pylab inline", 
-                        "
", - "", - "to ensure pylab support is available for plots.", - "", - "## Custom-built classes with dedicated ``_repr_*_`` methods", - "", - "In our first example, we illustrate how objects can expose directly to IPython special representations of", - "themselves, by providing methods such as ``_repr_svg_``, ``_repr_png_``, ``_repr_latex_``, etc. For a full", - "list of the special ``_repr_*_`` methods supported, see the code in ``IPython.core.displaypub``.", - "", - "As an illustration, we build a class that holds data generated by sampling a Gaussian distribution with given mean ", - "and variance. The class can display itself in a variety of ways: as a LaTeX expression or as an image in PNG or SVG ", - "format. Each frontend can then decide which representation it can handle.", - "Further, we illustrate how to expose directly to the user the ability to directly access the various alternate ", - "representations (since by default displaying the object itself will only show one, and which is shown will depend on the ", - "required representations that even cache necessary data in cases where it may be expensive to compute.", - "", - "The next cell defines the Gaussian class:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "from IPython.lib.pylabtools import print_figure", - "from IPython.core.display import Image, SVG, Math", - "", - "class Gaussian(object):", - " \"\"\"A simple object holding data sampled from a Gaussian distribution.", - " \"\"\"", - " def __init__(self, mean=0, std=1, size=1000):", - " self.data = np.random.normal(mean, std, size)", - " self.mean = mean", - " self.std = std", - " self.size = size", - " # For caching plots that may be expensive to compute", - " self._png_data = None", - " self._svg_data = None", - " ", - " def _figure_data(self, format):", - " fig, ax = plt.subplots()", - " ax.plot(self.data, 'o')", - " ax.set_title(self._repr_latex_())", - " data = print_figure(fig, format)", - " # We MUST close the figure, otherwise IPython's display machinery", - " # will pick it up and send it as output, resulting in a double display", - " plt.close(fig)", - " return data", - " ", - " # Here we define the special repr methods that provide the IPython display protocol", - " # Note that for the two figures, we cache the figure data once computed.", - " ", - " def _repr_png_(self):", - " if self._png_data is None:", - " self._png_data = self._figure_data('png')", - " return self._png_data", - "", - "", - " def _repr_svg_(self):", - " if self._svg_data is None:", - " self._svg_data = self._figure_data('svg')", - " return self._svg_data", - " ", - " def _repr_latex_(self):", - " return r'$\\mathcal{N}(\\mu=%.2g, \\sigma=%.2g),\\ N=%d$' % (self.mean,", - " self.std, self.size)", - " ", - " # We expose as properties some of the above reprs, so that the user can see them", - " # directly (since otherwise the client dictates which one it shows by default)", - " @property", - " def png(self):", - " return Image(self._repr_png_(), embed=True)", - " ", - " @property", - " def svg(self):", - " return SVG(self._repr_svg_())", - " ", - " @property", - " def latex(self):", - " return Math(self._repr_svg_())", - " ", - " # An example of using a property to display rich information, in this case", - " # the histogram of the distribution. We've hardcoded the format to be png", - " # in this case, but in production code it would be trivial to make it an option", - " @property", - " def hist(self):", - " fig, ax = plt.subplots()", - " ax.hist(self.data, bins=100)", - " ax.set_title(self._repr_latex_())", - " data = print_figure(fig, 'png')", - " plt.close(fig)", - " return Image(data, embed=True)" - ], - "language": "python", - "outputs": [], - "prompt_number": 1 - }, - { - "cell_type": "markdown", - "source": [ - "Now, we create an instance of the Gaussian distribution, whose default representation will be its LaTeX form:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "x = Gaussian()", - "x" - ], - "language": "python", - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "markdown", - "source": [ - "We can view the data in png or svg formats:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "x.png" - ], - "language": "python", - "outputs": [], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "x.svg" - ], - "language": "python", - "outputs": [], - "prompt_number": 4 - }, - { - "cell_type": "markdown", - "source": [ - "Since IPython only displays by default as an ``Out[]`` cell the result of the last computation, we can use the", - "``display()`` function to show more than one representation in a single cell:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "display(x.png)", - "display(x.svg)" - ], - "language": "python", - "outputs": [], - "prompt_number": 5 - }, - { - "cell_type": "markdown", - "source": [ - "Now let's create a new Gaussian with different parameters" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "x2 = Gaussian(0.5, 0.2, 2000)", - "x2" - ], - "language": "python", - "outputs": [], - "prompt_number": 6 - }, - { - "cell_type": "markdown", - "source": [ - "We can easily compare them by displaying their histograms" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "display(x.hist)", - "display(x2.hist)" - ], - "language": "python", - "outputs": [], - "prompt_number": 7 - }, - { - "cell_type": "markdown", - "source": [ - "## Adding IPython display support to existing objects", - "", - "When you are directly writing your own classes, you can adapt them for display in IPython by ", - "following the above example. But in practice, we often need to work with existing code we", - "can't modify. ", - "", - "We now illustrate how to add these kinds of extended display capabilities to existing objects.", - "We will use the numpy polynomials and change their default representation to be a formatted", - "LaTeX expression.", - "", - "First, consider how a numpy polynomial object renders by default:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "p = np.polynomial.Polynomial([1,2,3], [-10, 10])", - "p" - ], - "language": "python", - "outputs": [], - "prompt_number": 8 - }, - { - "cell_type": "markdown", - "source": [ - "Next, we define a function that pretty-prints a polynomial as a LaTeX string:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "def poly2latex(p):", - " terms = ['%.2g' % p.coef[0]]", - " if len(p) > 1:", - " term = 'x'", - " c = p.coef[1]", - " if c!=1:", - " term = ('%.2g ' % c) + term", - " terms.append(term)", - " if len(p) > 2:", - " for i in range(2, len(p)):", - " term = 'x^%d' % i", - " c = p.coef[i]", - " if c!=1:", - " term = ('%.2g ' % c) + term", - " terms.append(term)", - " px = '$P(x)=%s$' % '+'.join(terms)", - " dom = r', domain: $[%.2g,\\ %.2g]$' % tuple(p.domain)", - " win = r', window: $[%.2g,\\ %.2g]$' % tuple(p.window)", - " return px+dom+win" - ], - "language": "python", - "outputs": [], - "prompt_number": 9 - }, - { - "cell_type": "markdown", - "source": [ - "This produces, on our polynomial ``p``, the following:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "poly2latex(p)" - ], - "language": "python", - "outputs": [], - "prompt_number": 10 - }, - { - "cell_type": "markdown", - "source": [ - "Note that this did *not* produce a formated LaTeX object, because it is simply a string ", - "with LaTeX code. In order for this to be interpreted as a mathematical expression, it", - "must be properly wrapped into a Math object:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "from IPython.core.display import Math", - "Math(poly2latex(p))" - ], - "language": "python", - "outputs": [], - "prompt_number": 11 - }, - { - "cell_type": "markdown", - "source": [ - "But we can configure IPython to do this automatically for us as follows. We hook into the", - "IPython display system and instruct it to use ``poly2latex`` for the latex mimetype, when", - "encountering objects of the ``Polynomial`` type defined in the", - "``numpy.polynomial.polynomial`` module:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "ip = get_ipython()", - "latex_formatter = ip.display_formatter.formatters['text/latex']", - "latex_formatter.for_type_by_name('numpy.polynomial.polynomial',", - " 'Polynomial', poly2latex)" - ], - "language": "python", - "outputs": [], - "prompt_number": 12 - }, - { - "cell_type": "markdown", - "source": [ - "For more examples on how to use the above system, and how to bundle similar print functions", - "into a convenient IPython extension, see the ``IPython/extensions/sympyprinting.py`` file. ", - "The machinery that defines the display system is in the ``display.py`` and ``displaypub.py`` ", - "files in ``IPython/core``.", - "", - "Once our special printer has been loaded, all polynomials will be represented by their ", - "mathematical form instead:" - ] - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "p" - ], - "language": "python", - "outputs": [], - "prompt_number": 13 - }, - { - "cell_type": "code", - "collapsed": true, - "input": [ - "p2 = np.polynomial.Polynomial([-20, 71, -15, 1])", - "p2" - ], - "language": "python", - "outputs": [], - "prompt_number": 14 - }, - { - "cell_type": "code", - "collapsed": true, - "input": [], - "language": "python", - "outputs": [], - "prompt_number": 14 - } - ] - } - ] + { + "cell_type": "code", + "collapsed": true, + "input": [ + "from IPython.lib.pylabtools import print_figure", + "from IPython.core.display import Image, SVG, Math", + "", + "class Gaussian(object):", + " \"\"\"A simple object holding data sampled from a Gaussian distribution.", + " \"\"\"", + " def __init__(self, mean=0, std=1, size=1000):", + " self.data = np.random.normal(mean, std, size)", + " self.mean = mean", + " self.std = std", + " self.size = size", + " # For caching plots that may be expensive to compute", + " self._png_data = None", + " self._svg_data = None", + " ", + " def _figure_data(self, format):", + " fig, ax = plt.subplots()", + " ax.plot(self.data, 'o')", + " ax.set_title(self._repr_latex_())", + " data = print_figure(fig, format)", + " # We MUST close the figure, otherwise IPython's display machinery", + " # will pick it up and send it as output, resulting in a double display", + " plt.close(fig)", + " return data", + " ", + " # Here we define the special repr methods that provide the IPython display protocol", + " # Note that for the two figures, we cache the figure data once computed.", + " ", + " def _repr_png_(self):", + " if self._png_data is None:", + " self._png_data = self._figure_data('png')", + " return self._png_data", + "", + "", + " def _repr_svg_(self):", + " if self._svg_data is None:", + " self._svg_data = self._figure_data('svg')", + " return self._svg_data", + " ", + " def _repr_latex_(self):", + " return r'$\\mathcal{N}(\\mu=%.2g, \\sigma=%.2g),\\ N=%d$' % (self.mean,", + " self.std, self.size)", + " ", + " # We expose as properties some of the above reprs, so that the user can see them", + " # directly (since otherwise the client dictates which one it shows by default)", + " @property", + " def png(self):", + " return Image(self._repr_png_(), embed=True)", + " ", + " @property", + " def svg(self):", + " return SVG(self._repr_svg_())", + " ", + " @property", + " def latex(self):", + " return Math(self._repr_svg_())", + " ", + " # An example of using a property to display rich information, in this case", + " # the histogram of the distribution. We've hardcoded the format to be png", + " # in this case, but in production code it would be trivial to make it an option", + " @property", + " def hist(self):", + " fig, ax = plt.subplots()", + " ax.hist(self.data, bins=100)", + " ax.set_title(self._repr_latex_())", + " data = print_figure(fig, 'png')", + " plt.close(fig)", + " return Image(data, embed=True)" + ], + "language": "python", + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "markdown", + "source": [ + "Now, we create an instance of the Gaussian distribution, whose default representation will be its LaTeX form:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x = Gaussian()", + "x" + ], + "language": "python", + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "source": [ + "We can view the data in png or svg formats:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x.png" + ], + "language": "python", + "outputs": [], + "prompt_number": 3 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x.svg" + ], + "language": "python", + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "source": [ + "Since IPython only displays by default as an ``Out[]`` cell the result of the last computation, we can use the", + "``display()`` function to show more than one representation in a single cell:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "display(x.png)", + "display(x.svg)" + ], + "language": "python", + "outputs": [], + "prompt_number": 5 + }, + { + "cell_type": "markdown", + "source": [ + "Now let's create a new Gaussian with different parameters" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x2 = Gaussian(0.5, 0.2, 2000)", + "x2" + ], + "language": "python", + "outputs": [], + "prompt_number": 6 + }, + { + "cell_type": "markdown", + "source": [ + "We can easily compare them by displaying their histograms" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "display(x.hist)", + "display(x2.hist)" + ], + "language": "python", + "outputs": [], + "prompt_number": 7 + }, + { + "cell_type": "markdown", + "source": [ + "## Adding IPython display support to existing objects", + "", + "When you are directly writing your own classes, you can adapt them for display in IPython by ", + "following the above example. But in practice, we often need to work with existing code we", + "can't modify. ", + "", + "We now illustrate how to add these kinds of extended display capabilities to existing objects.", + "We will use the numpy polynomials and change their default representation to be a formatted", + "LaTeX expression.", + "", + "First, consider how a numpy polynomial object renders by default:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "p = np.polynomial.Polynomial([1,2,3], [-10, 10])", + "p" + ], + "language": "python", + "outputs": [], + "prompt_number": 8 + }, + { + "cell_type": "markdown", + "source": [ + "Next, we define a function that pretty-prints a polynomial as a LaTeX string:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "def poly2latex(p):", + " terms = ['%.2g' % p.coef[0]]", + " if len(p) > 1:", + " term = 'x'", + " c = p.coef[1]", + " if c!=1:", + " term = ('%.2g ' % c) + term", + " terms.append(term)", + " if len(p) > 2:", + " for i in range(2, len(p)):", + " term = 'x^%d' % i", + " c = p.coef[i]", + " if c!=1:", + " term = ('%.2g ' % c) + term", + " terms.append(term)", + " px = '$P(x)=%s$' % '+'.join(terms)", + " dom = r', domain: $[%.2g,\\ %.2g]$' % tuple(p.domain)", + " return px+dom" + ], + "language": "python", + "outputs": [], + "prompt_number": 11 + }, + { + "cell_type": "markdown", + "source": [ + "This produces, on our polynomial ``p``, the following:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "poly2latex(p)" + ], + "language": "python", + "outputs": [], + "prompt_number": 12 + }, + { + "cell_type": "markdown", + "source": [ + "Note that this did *not* produce a formated LaTeX object, because it is simply a string ", + "with LaTeX code. In order for this to be interpreted as a mathematical expression, it", + "must be properly wrapped into a Math object:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from IPython.core.display import Math", + "Math(poly2latex(p))" + ], + "language": "python", + "outputs": [], + "prompt_number": 13 + }, + { + "cell_type": "markdown", + "source": [ + "But we can configure IPython to do this automatically for us as follows. We hook into the", + "IPython display system and instruct it to use ``poly2latex`` for the latex mimetype, when", + "encountering objects of the ``Polynomial`` type defined in the", + "``numpy.polynomial.polynomial`` module:" + ] + }, + { + "cell_type": "code", + "collapsed": true, + "input": [ + "ip = get_ipython()", + "latex_formatter = ip.display_formatter.formatters['text/latex']", + "latex_formatter.for_type_by_name('numpy.polynomial.polynomial',", + " 'Polynomial', poly2latex)" + ], + "language": "python", + "outputs": [], + "prompt_number": 14 + }, + { + "cell_type": "markdown", + "source": [ + "For more examples on how to use the above system, and how to bundle similar print functions", + "into a convenient IPython extension, see the ``IPython/extensions/sympyprinting.py`` file. ", + "The machinery that defines the display system is in the ``display.py`` and ``displaypub.py`` ", + "files in ``IPython/core``.", + "", + "Once our special printer has been loaded, all polynomials will be represented by their ", + "mathematical form instead:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "p" + ], + "language": "python", + "outputs": [], + "prompt_number": 15 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "p2 = np.polynomial.Polynomial([-20, 71, -15, 1])", + "p2" + ], + "language": "python", + "outputs": [], + "prompt_number": 16 + }, + { + "cell_type": "code", + "collapsed": true, + "input": [], + "language": "python", + "outputs": [], + "prompt_number": 14 + } + ] + } + ] } \ No newline at end of file