##// END OF EJS Templates
Fix small bug in display protocol example (numpy polynomials).
Fernando Perez -
Show More
This diff has been collapsed as it changes many lines, (751 lines changed) Show them Hide them
@@ -1,379 +1,378 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "name": "display_protocol"
3 "name": "display_protocol"
4 },
5 "nbformat": 2,
6 "worksheets": [
7 {
8 "cells": [
9 {
10 "cell_type": "markdown",
11 "source": [
12 "# Using the IPython display protocol for your own objects",
13 "",
14 "IPython extends the idea of the ``__repr__`` method in Python to support multiple representations for a given",
15 "object, which clients can use to display the object according to their capabilities. An object can return multiple",
16 "representations of itself by implementing special methods, and you can also define at runtime custom display ",
17 "functions for existing objects whose methods you can't or won't modify. In this notebook, we show how both approaches work.",
18 "",
19 "<br/>",
20 "**Note:** this notebook has had all output cells stripped out so we can include it in the IPython documentation with ",
21 "a minimal file size. You'll need to manually execute the cells to see the output (you can run all of them with the ",
22 "\"Run All\" button, or execute each individually). You must start this notebook with",
23 "<pre>",
24 "ipython notebook --pylab inline",
25 "</pre>",
26 "",
27 "to ensure pylab support is available for plots.",
28 "",
29 "## Custom-built classes with dedicated ``_repr_*_`` methods",
30 "",
31 "In our first example, we illustrate how objects can expose directly to IPython special representations of",
32 "themselves, by providing methods such as ``_repr_svg_``, ``_repr_png_``, ``_repr_latex_``, etc. For a full",
33 "list of the special ``_repr_*_`` methods supported, see the code in ``IPython.core.displaypub``.",
34 "",
35 "As an illustration, we build a class that holds data generated by sampling a Gaussian distribution with given mean ",
36 "and variance. The class can display itself in a variety of ways: as a LaTeX expression or as an image in PNG or SVG ",
37 "format. Each frontend can then decide which representation it can handle.",
38 "Further, we illustrate how to expose directly to the user the ability to directly access the various alternate ",
39 "representations (since by default displaying the object itself will only show one, and which is shown will depend on the ",
40 "required representations that even cache necessary data in cases where it may be expensive to compute.",
41 "",
42 "The next cell defines the Gaussian class:"
43 ]
4 },
44 },
5 "nbformat": 2,
45 {
6 "worksheets": [
46 "cell_type": "code",
7 {
47 "collapsed": true,
8 "cells": [
48 "input": [
9 {
49 "from IPython.lib.pylabtools import print_figure",
10 "cell_type": "markdown",
50 "from IPython.core.display import Image, SVG, Math",
11 "source": [
51 "",
12 "# Using the IPython display protocol for your own objects",
52 "class Gaussian(object):",
13 "",
53 " \"\"\"A simple object holding data sampled from a Gaussian distribution.",
14 "IPython extends the idea of the ``__repr__`` method in Python to support multiple representations for a given",
54 " \"\"\"",
15 "object, which clients can use to display the object according to their capabilities. An object can return multiple",
55 " def __init__(self, mean=0, std=1, size=1000):",
16 "representations of itself by implementing special methods, and you can also define at runtime custom display ",
56 " self.data = np.random.normal(mean, std, size)",
17 "functions for existing objects whose methods you can't or won't modify. In this notebook, we show how both approaches work.",
57 " self.mean = mean",
18 "",
58 " self.std = std",
19 "<br/>",
59 " self.size = size",
20 "**Note:** this notebook has had all output cells stripped out so we can include it in the IPython documentation with ",
60 " # For caching plots that may be expensive to compute",
21 "a minimal file size. You'll need to manually execute the cells to see the output (you can run all of them with the ",
61 " self._png_data = None",
22 "\"Run All\" button, or execute each individually). You must start this notebook with",
62 " self._svg_data = None",
23 "<pre>",
63 " ",
24 "ipython notebook --pylab inline",
64 " def _figure_data(self, format):",
25 "</pre>",
65 " fig, ax = plt.subplots()",
26 "",
66 " ax.plot(self.data, 'o')",
27 "to ensure pylab support is available for plots.",
67 " ax.set_title(self._repr_latex_())",
28 "",
68 " data = print_figure(fig, format)",
29 "## Custom-built classes with dedicated ``_repr_*_`` methods",
69 " # We MUST close the figure, otherwise IPython's display machinery",
30 "",
70 " # will pick it up and send it as output, resulting in a double display",
31 "In our first example, we illustrate how objects can expose directly to IPython special representations of",
71 " plt.close(fig)",
32 "themselves, by providing methods such as ``_repr_svg_``, ``_repr_png_``, ``_repr_latex_``, etc. For a full",
72 " return data",
33 "list of the special ``_repr_*_`` methods supported, see the code in ``IPython.core.displaypub``.",
73 " ",
34 "",
74 " # Here we define the special repr methods that provide the IPython display protocol",
35 "As an illustration, we build a class that holds data generated by sampling a Gaussian distribution with given mean ",
75 " # Note that for the two figures, we cache the figure data once computed.",
36 "and variance. The class can display itself in a variety of ways: as a LaTeX expression or as an image in PNG or SVG ",
76 " ",
37 "format. Each frontend can then decide which representation it can handle.",
77 " def _repr_png_(self):",
38 "Further, we illustrate how to expose directly to the user the ability to directly access the various alternate ",
78 " if self._png_data is None:",
39 "representations (since by default displaying the object itself will only show one, and which is shown will depend on the ",
79 " self._png_data = self._figure_data('png')",
40 "required representations that even cache necessary data in cases where it may be expensive to compute.",
80 " return self._png_data",
41 "",
81 "",
42 "The next cell defines the Gaussian class:"
82 "",
43 ]
83 " def _repr_svg_(self):",
44 },
84 " if self._svg_data is None:",
45 {
85 " self._svg_data = self._figure_data('svg')",
46 "cell_type": "code",
86 " return self._svg_data",
47 "collapsed": true,
87 " ",
48 "input": [
88 " def _repr_latex_(self):",
49 "from IPython.lib.pylabtools import print_figure",
89 " return r'$\\mathcal{N}(\\mu=%.2g, \\sigma=%.2g),\\ N=%d$' % (self.mean,",
50 "from IPython.core.display import Image, SVG, Math",
90 " self.std, self.size)",
51 "",
91 " ",
52 "class Gaussian(object):",
92 " # We expose as properties some of the above reprs, so that the user can see them",
53 " \"\"\"A simple object holding data sampled from a Gaussian distribution.",
93 " # directly (since otherwise the client dictates which one it shows by default)",
54 " \"\"\"",
94 " @property",
55 " def __init__(self, mean=0, std=1, size=1000):",
95 " def png(self):",
56 " self.data = np.random.normal(mean, std, size)",
96 " return Image(self._repr_png_(), embed=True)",
57 " self.mean = mean",
97 " ",
58 " self.std = std",
98 " @property",
59 " self.size = size",
99 " def svg(self):",
60 " # For caching plots that may be expensive to compute",
100 " return SVG(self._repr_svg_())",
61 " self._png_data = None",
101 " ",
62 " self._svg_data = None",
102 " @property",
63 " ",
103 " def latex(self):",
64 " def _figure_data(self, format):",
104 " return Math(self._repr_svg_())",
65 " fig, ax = plt.subplots()",
105 " ",
66 " ax.plot(self.data, 'o')",
106 " # An example of using a property to display rich information, in this case",
67 " ax.set_title(self._repr_latex_())",
107 " # the histogram of the distribution. We've hardcoded the format to be png",
68 " data = print_figure(fig, format)",
108 " # in this case, but in production code it would be trivial to make it an option",
69 " # We MUST close the figure, otherwise IPython's display machinery",
109 " @property",
70 " # will pick it up and send it as output, resulting in a double display",
110 " def hist(self):",
71 " plt.close(fig)",
111 " fig, ax = plt.subplots()",
72 " return data",
112 " ax.hist(self.data, bins=100)",
73 " ",
113 " ax.set_title(self._repr_latex_())",
74 " # Here we define the special repr methods that provide the IPython display protocol",
114 " data = print_figure(fig, 'png')",
75 " # Note that for the two figures, we cache the figure data once computed.",
115 " plt.close(fig)",
76 " ",
116 " return Image(data, embed=True)"
77 " def _repr_png_(self):",
117 ],
78 " if self._png_data is None:",
118 "language": "python",
79 " self._png_data = self._figure_data('png')",
119 "outputs": [],
80 " return self._png_data",
120 "prompt_number": 1
81 "",
121 },
82 "",
122 {
83 " def _repr_svg_(self):",
123 "cell_type": "markdown",
84 " if self._svg_data is None:",
124 "source": [
85 " self._svg_data = self._figure_data('svg')",
125 "Now, we create an instance of the Gaussian distribution, whose default representation will be its LaTeX form:"
86 " return self._svg_data",
126 ]
87 " ",
127 },
88 " def _repr_latex_(self):",
128 {
89 " return r'$\\mathcal{N}(\\mu=%.2g, \\sigma=%.2g),\\ N=%d$' % (self.mean,",
129 "cell_type": "code",
90 " self.std, self.size)",
130 "collapsed": false,
91 " ",
131 "input": [
92 " # We expose as properties some of the above reprs, so that the user can see them",
132 "x = Gaussian()",
93 " # directly (since otherwise the client dictates which one it shows by default)",
133 "x"
94 " @property",
134 ],
95 " def png(self):",
135 "language": "python",
96 " return Image(self._repr_png_(), embed=True)",
136 "outputs": [],
97 " ",
137 "prompt_number": 2
98 " @property",
138 },
99 " def svg(self):",
139 {
100 " return SVG(self._repr_svg_())",
140 "cell_type": "markdown",
101 " ",
141 "source": [
102 " @property",
142 "We can view the data in png or svg formats:"
103 " def latex(self):",
143 ]
104 " return Math(self._repr_svg_())",
144 },
105 " ",
145 {
106 " # An example of using a property to display rich information, in this case",
146 "cell_type": "code",
107 " # the histogram of the distribution. We've hardcoded the format to be png",
147 "collapsed": false,
108 " # in this case, but in production code it would be trivial to make it an option",
148 "input": [
109 " @property",
149 "x.png"
110 " def hist(self):",
150 ],
111 " fig, ax = plt.subplots()",
151 "language": "python",
112 " ax.hist(self.data, bins=100)",
152 "outputs": [],
113 " ax.set_title(self._repr_latex_())",
153 "prompt_number": 3
114 " data = print_figure(fig, 'png')",
154 },
115 " plt.close(fig)",
155 {
116 " return Image(data, embed=True)"
156 "cell_type": "code",
117 ],
157 "collapsed": false,
118 "language": "python",
158 "input": [
119 "outputs": [],
159 "x.svg"
120 "prompt_number": 1
160 ],
121 },
161 "language": "python",
122 {
162 "outputs": [],
123 "cell_type": "markdown",
163 "prompt_number": 4
124 "source": [
164 },
125 "Now, we create an instance of the Gaussian distribution, whose default representation will be its LaTeX form:"
165 {
126 ]
166 "cell_type": "markdown",
127 },
167 "source": [
128 {
168 "Since IPython only displays by default as an ``Out[]`` cell the result of the last computation, we can use the",
129 "cell_type": "code",
169 "``display()`` function to show more than one representation in a single cell:"
130 "collapsed": true,
170 ]
131 "input": [
171 },
132 "x = Gaussian()",
172 {
133 "x"
173 "cell_type": "code",
134 ],
174 "collapsed": false,
135 "language": "python",
175 "input": [
136 "outputs": [],
176 "display(x.png)",
137 "prompt_number": 2
177 "display(x.svg)"
138 },
178 ],
139 {
179 "language": "python",
140 "cell_type": "markdown",
180 "outputs": [],
141 "source": [
181 "prompt_number": 5
142 "We can view the data in png or svg formats:"
182 },
143 ]
183 {
144 },
184 "cell_type": "markdown",
145 {
185 "source": [
146 "cell_type": "code",
186 "Now let's create a new Gaussian with different parameters"
147 "collapsed": true,
187 ]
148 "input": [
188 },
149 "x.png"
189 {
150 ],
190 "cell_type": "code",
151 "language": "python",
191 "collapsed": false,
152 "outputs": [],
192 "input": [
153 "prompt_number": 3
193 "x2 = Gaussian(0.5, 0.2, 2000)",
154 },
194 "x2"
155 {
195 ],
156 "cell_type": "code",
196 "language": "python",
157 "collapsed": true,
197 "outputs": [],
158 "input": [
198 "prompt_number": 6
159 "x.svg"
199 },
160 ],
200 {
161 "language": "python",
201 "cell_type": "markdown",
162 "outputs": [],
202 "source": [
163 "prompt_number": 4
203 "We can easily compare them by displaying their histograms"
164 },
204 ]
165 {
205 },
166 "cell_type": "markdown",
206 {
167 "source": [
207 "cell_type": "code",
168 "Since IPython only displays by default as an ``Out[]`` cell the result of the last computation, we can use the",
208 "collapsed": false,
169 "``display()`` function to show more than one representation in a single cell:"
209 "input": [
170 ]
210 "display(x.hist)",
171 },
211 "display(x2.hist)"
172 {
212 ],
173 "cell_type": "code",
213 "language": "python",
174 "collapsed": true,
214 "outputs": [],
175 "input": [
215 "prompt_number": 7
176 "display(x.png)",
216 },
177 "display(x.svg)"
217 {
178 ],
218 "cell_type": "markdown",
179 "language": "python",
219 "source": [
180 "outputs": [],
220 "## Adding IPython display support to existing objects",
181 "prompt_number": 5
221 "",
182 },
222 "When you are directly writing your own classes, you can adapt them for display in IPython by ",
183 {
223 "following the above example. But in practice, we often need to work with existing code we",
184 "cell_type": "markdown",
224 "can't modify. ",
185 "source": [
225 "",
186 "Now let's create a new Gaussian with different parameters"
226 "We now illustrate how to add these kinds of extended display capabilities to existing objects.",
187 ]
227 "We will use the numpy polynomials and change their default representation to be a formatted",
188 },
228 "LaTeX expression.",
189 {
229 "",
190 "cell_type": "code",
230 "First, consider how a numpy polynomial object renders by default:"
191 "collapsed": true,
231 ]
192 "input": [
232 },
193 "x2 = Gaussian(0.5, 0.2, 2000)",
233 {
194 "x2"
234 "cell_type": "code",
195 ],
235 "collapsed": false,
196 "language": "python",
236 "input": [
197 "outputs": [],
237 "p = np.polynomial.Polynomial([1,2,3], [-10, 10])",
198 "prompt_number": 6
238 "p"
199 },
239 ],
200 {
240 "language": "python",
201 "cell_type": "markdown",
241 "outputs": [],
202 "source": [
242 "prompt_number": 8
203 "We can easily compare them by displaying their histograms"
243 },
204 ]
244 {
205 },
245 "cell_type": "markdown",
206 {
246 "source": [
207 "cell_type": "code",
247 "Next, we define a function that pretty-prints a polynomial as a LaTeX string:"
208 "collapsed": true,
248 ]
209 "input": [
249 },
210 "display(x.hist)",
250 {
211 "display(x2.hist)"
251 "cell_type": "code",
212 ],
252 "collapsed": true,
213 "language": "python",
253 "input": [
214 "outputs": [],
254 "def poly2latex(p):",
215 "prompt_number": 7
255 " terms = ['%.2g' % p.coef[0]]",
216 },
256 " if len(p) > 1:",
217 {
257 " term = 'x'",
218 "cell_type": "markdown",
258 " c = p.coef[1]",
219 "source": [
259 " if c!=1:",
220 "## Adding IPython display support to existing objects",
260 " term = ('%.2g ' % c) + term",
221 "",
261 " terms.append(term)",
222 "When you are directly writing your own classes, you can adapt them for display in IPython by ",
262 " if len(p) > 2:",
223 "following the above example. But in practice, we often need to work with existing code we",
263 " for i in range(2, len(p)):",
224 "can't modify. ",
264 " term = 'x^%d' % i",
225 "",
265 " c = p.coef[i]",
226 "We now illustrate how to add these kinds of extended display capabilities to existing objects.",
266 " if c!=1:",
227 "We will use the numpy polynomials and change their default representation to be a formatted",
267 " term = ('%.2g ' % c) + term",
228 "LaTeX expression.",
268 " terms.append(term)",
229 "",
269 " px = '$P(x)=%s$' % '+'.join(terms)",
230 "First, consider how a numpy polynomial object renders by default:"
270 " dom = r', domain: $[%.2g,\\ %.2g]$' % tuple(p.domain)",
231 ]
271 " return px+dom"
232 },
272 ],
233 {
273 "language": "python",
234 "cell_type": "code",
274 "outputs": [],
235 "collapsed": true,
275 "prompt_number": 11
236 "input": [
276 },
237 "p = np.polynomial.Polynomial([1,2,3], [-10, 10])",
277 {
238 "p"
278 "cell_type": "markdown",
239 ],
279 "source": [
240 "language": "python",
280 "This produces, on our polynomial ``p``, the following:"
241 "outputs": [],
281 ]
242 "prompt_number": 8
282 },
243 },
283 {
244 {
284 "cell_type": "code",
245 "cell_type": "markdown",
285 "collapsed": false,
246 "source": [
286 "input": [
247 "Next, we define a function that pretty-prints a polynomial as a LaTeX string:"
287 "poly2latex(p)"
248 ]
288 ],
249 },
289 "language": "python",
250 {
290 "outputs": [],
251 "cell_type": "code",
291 "prompt_number": 12
252 "collapsed": true,
292 },
253 "input": [
293 {
254 "def poly2latex(p):",
294 "cell_type": "markdown",
255 " terms = ['%.2g' % p.coef[0]]",
295 "source": [
256 " if len(p) > 1:",
296 "Note that this did *not* produce a formated LaTeX object, because it is simply a string ",
257 " term = 'x'",
297 "with LaTeX code. In order for this to be interpreted as a mathematical expression, it",
258 " c = p.coef[1]",
298 "must be properly wrapped into a Math object:"
259 " if c!=1:",
299 ]
260 " term = ('%.2g ' % c) + term",
300 },
261 " terms.append(term)",
301 {
262 " if len(p) > 2:",
302 "cell_type": "code",
263 " for i in range(2, len(p)):",
303 "collapsed": false,
264 " term = 'x^%d' % i",
304 "input": [
265 " c = p.coef[i]",
305 "from IPython.core.display import Math",
266 " if c!=1:",
306 "Math(poly2latex(p))"
267 " term = ('%.2g ' % c) + term",
307 ],
268 " terms.append(term)",
308 "language": "python",
269 " px = '$P(x)=%s$' % '+'.join(terms)",
309 "outputs": [],
270 " dom = r', domain: $[%.2g,\\ %.2g]$' % tuple(p.domain)",
310 "prompt_number": 13
271 " win = r', window: $[%.2g,\\ %.2g]$' % tuple(p.window)",
311 },
272 " return px+dom+win"
312 {
273 ],
313 "cell_type": "markdown",
274 "language": "python",
314 "source": [
275 "outputs": [],
315 "But we can configure IPython to do this automatically for us as follows. We hook into the",
276 "prompt_number": 9
316 "IPython display system and instruct it to use ``poly2latex`` for the latex mimetype, when",
277 },
317 "encountering objects of the ``Polynomial`` type defined in the",
278 {
318 "``numpy.polynomial.polynomial`` module:"
279 "cell_type": "markdown",
319 ]
280 "source": [
320 },
281 "This produces, on our polynomial ``p``, the following:"
321 {
282 ]
322 "cell_type": "code",
283 },
323 "collapsed": true,
284 {
324 "input": [
285 "cell_type": "code",
325 "ip = get_ipython()",
286 "collapsed": true,
326 "latex_formatter = ip.display_formatter.formatters['text/latex']",
287 "input": [
327 "latex_formatter.for_type_by_name('numpy.polynomial.polynomial',",
288 "poly2latex(p)"
328 " 'Polynomial', poly2latex)"
289 ],
329 ],
290 "language": "python",
330 "language": "python",
291 "outputs": [],
331 "outputs": [],
292 "prompt_number": 10
332 "prompt_number": 14
293 },
333 },
294 {
334 {
295 "cell_type": "markdown",
335 "cell_type": "markdown",
296 "source": [
336 "source": [
297 "Note that this did *not* produce a formated LaTeX object, because it is simply a string ",
337 "For more examples on how to use the above system, and how to bundle similar print functions",
298 "with LaTeX code. In order for this to be interpreted as a mathematical expression, it",
338 "into a convenient IPython extension, see the ``IPython/extensions/sympyprinting.py`` file. ",
299 "must be properly wrapped into a Math object:"
339 "The machinery that defines the display system is in the ``display.py`` and ``displaypub.py`` ",
300 ]
340 "files in ``IPython/core``.",
301 },
341 "",
302 {
342 "Once our special printer has been loaded, all polynomials will be represented by their ",
303 "cell_type": "code",
343 "mathematical form instead:"
304 "collapsed": true,
344 ]
305 "input": [
345 },
306 "from IPython.core.display import Math",
346 {
307 "Math(poly2latex(p))"
347 "cell_type": "code",
308 ],
348 "collapsed": false,
309 "language": "python",
349 "input": [
310 "outputs": [],
350 "p"
311 "prompt_number": 11
351 ],
312 },
352 "language": "python",
313 {
353 "outputs": [],
314 "cell_type": "markdown",
354 "prompt_number": 15
315 "source": [
355 },
316 "But we can configure IPython to do this automatically for us as follows. We hook into the",
356 {
317 "IPython display system and instruct it to use ``poly2latex`` for the latex mimetype, when",
357 "cell_type": "code",
318 "encountering objects of the ``Polynomial`` type defined in the",
358 "collapsed": false,
319 "``numpy.polynomial.polynomial`` module:"
359 "input": [
320 ]
360 "p2 = np.polynomial.Polynomial([-20, 71, -15, 1])",
321 },
361 "p2"
322 {
362 ],
323 "cell_type": "code",
363 "language": "python",
324 "collapsed": true,
364 "outputs": [],
325 "input": [
365 "prompt_number": 16
326 "ip = get_ipython()",
366 },
327 "latex_formatter = ip.display_formatter.formatters['text/latex']",
367 {
328 "latex_formatter.for_type_by_name('numpy.polynomial.polynomial',",
368 "cell_type": "code",
329 " 'Polynomial', poly2latex)"
369 "collapsed": true,
330 ],
370 "input": [],
331 "language": "python",
371 "language": "python",
332 "outputs": [],
372 "outputs": [],
333 "prompt_number": 12
373 "prompt_number": 14
334 },
374 }
335 {
375 ]
336 "cell_type": "markdown",
376 }
337 "source": [
377 ]
338 "For more examples on how to use the above system, and how to bundle similar print functions",
339 "into a convenient IPython extension, see the ``IPython/extensions/sympyprinting.py`` file. ",
340 "The machinery that defines the display system is in the ``display.py`` and ``displaypub.py`` ",
341 "files in ``IPython/core``.",
342 "",
343 "Once our special printer has been loaded, all polynomials will be represented by their ",
344 "mathematical form instead:"
345 ]
346 },
347 {
348 "cell_type": "code",
349 "collapsed": true,
350 "input": [
351 "p"
352 ],
353 "language": "python",
354 "outputs": [],
355 "prompt_number": 13
356 },
357 {
358 "cell_type": "code",
359 "collapsed": true,
360 "input": [
361 "p2 = np.polynomial.Polynomial([-20, 71, -15, 1])",
362 "p2"
363 ],
364 "language": "python",
365 "outputs": [],
366 "prompt_number": 14
367 },
368 {
369 "cell_type": "code",
370 "collapsed": true,
371 "input": [],
372 "language": "python",
373 "outputs": [],
374 "prompt_number": 14
375 }
376 ]
377 }
378 ]
379 } No newline at end of file
378 }
General Comments 0
You need to be logged in to leave comments. Login now