Skip to content

Commit 0ca7f18

Browse files
author
Matthias Bussonnier
committed
custom display objects
1 parent 4ad68d5 commit 0ca7f18

File tree

4 files changed

+412
-0
lines changed

4 files changed

+412
-0
lines changed
Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Custom Display Logic Exercises"
8+
]
9+
},
10+
{
11+
"cell_type": "code",
12+
"execution_count": null,
13+
"metadata": {
14+
"collapsed": false
15+
},
16+
"outputs": [],
17+
"source": [
18+
"from IPython.display import display\n",
19+
"from IPython.display import (\n",
20+
" display_png, display_html, display_latex,\n",
21+
" display_javascript, display_svg\n",
22+
")"
23+
]
24+
},
25+
{
26+
"cell_type": "markdown",
27+
"metadata": {},
28+
"source": [
29+
"## Circle class with custom display methods"
30+
]
31+
},
32+
{
33+
"cell_type": "markdown",
34+
"metadata": {},
35+
"source": [
36+
"Write a simple `MyCircle` Python class. Here is a skeleton to get you started:\n",
37+
"\n",
38+
"```python\n",
39+
"class MyCircle(object):\n",
40+
" def __init__(self, center=(0.0,0.0), radius=1.0, color='blue'):\n",
41+
" self.center = center\n",
42+
" self.radius = radius\n",
43+
" self.color = color\n",
44+
"```\n",
45+
"\n",
46+
"Now add special display methods to this class for the following representations (remember to wrap them in Python strings):\n",
47+
"\n",
48+
"For HTML:\n",
49+
"\n",
50+
" ○\n",
51+
"\n",
52+
"For SVG:\n",
53+
"\n",
54+
" <svg width=\"100px\" height=\"100px\">\n",
55+
" <circle cx=\"50\" cy=\"50\" r=\"20\" stroke=\"black\" stroke-width=\"1\" fill=\"white\"/>\n",
56+
" </svg>\n",
57+
"\n",
58+
"For LaTeX (wrap with `$` and use a raw Python string):\n",
59+
"\n",
60+
" \\bigcirc\n",
61+
"\n",
62+
"For JavaScript:\n",
63+
"\n",
64+
" alert('I am a circle!');\n",
65+
"\n",
66+
"After you write the class, create an instance and then use `display_html`, `display_svg`, `display_latex` and `display_javascript` to display those representations."
67+
]
68+
},
69+
{
70+
"cell_type": "markdown",
71+
"metadata": {},
72+
"source": [
73+
"### Solution"
74+
]
75+
},
76+
{
77+
"cell_type": "markdown",
78+
"metadata": {},
79+
"source": [
80+
"Here is the solution to the simple `MyCircle` class:"
81+
]
82+
},
83+
{
84+
"cell_type": "code",
85+
"execution_count": null,
86+
"metadata": {
87+
"collapsed": false
88+
},
89+
"outputs": [],
90+
"source": [
91+
"%load soln/mycircle.py"
92+
]
93+
},
94+
{
95+
"cell_type": "markdown",
96+
"metadata": {},
97+
"source": [
98+
"Now create an instance and use the display methods:"
99+
]
100+
},
101+
{
102+
"cell_type": "code",
103+
"execution_count": null,
104+
"metadata": {
105+
"collapsed": false
106+
},
107+
"outputs": [],
108+
"source": [
109+
"c = MyCircle()"
110+
]
111+
},
112+
{
113+
"cell_type": "code",
114+
"execution_count": null,
115+
"metadata": {
116+
"collapsed": false
117+
},
118+
"outputs": [],
119+
"source": [
120+
"display(c)"
121+
]
122+
},
123+
{
124+
"cell_type": "code",
125+
"execution_count": null,
126+
"metadata": {
127+
"collapsed": false
128+
},
129+
"outputs": [],
130+
"source": [
131+
"display_html(c)"
132+
]
133+
},
134+
{
135+
"cell_type": "code",
136+
"execution_count": null,
137+
"metadata": {
138+
"collapsed": false
139+
},
140+
"outputs": [],
141+
"source": [
142+
"display_svg(c)"
143+
]
144+
},
145+
{
146+
"cell_type": "code",
147+
"execution_count": null,
148+
"metadata": {
149+
"collapsed": false
150+
},
151+
"outputs": [],
152+
"source": [
153+
"display_latex(c)"
154+
]
155+
},
156+
{
157+
"cell_type": "code",
158+
"execution_count": null,
159+
"metadata": {
160+
"collapsed": false
161+
},
162+
"outputs": [],
163+
"source": [
164+
"display_javascript(c)"
165+
]
166+
},
167+
{
168+
"cell_type": "markdown",
169+
"metadata": {},
170+
"source": [
171+
"## PNG formatter for `MyCircle`"
172+
]
173+
},
174+
{
175+
"cell_type": "code",
176+
"execution_count": null,
177+
"metadata": {
178+
"collapsed": false
179+
},
180+
"outputs": [],
181+
"source": [
182+
"%matplotlib inline\n",
183+
"from matplotlib import pyplot as plt"
184+
]
185+
},
186+
{
187+
"cell_type": "markdown",
188+
"metadata": {},
189+
"source": [
190+
"Now let's assume that the `MyCircle` class has already been defined and add a PNG representation using a formatter display function. Here is a function that converts a `MyCircle` instance to raw PNG data."
191+
]
192+
},
193+
{
194+
"cell_type": "code",
195+
"execution_count": null,
196+
"metadata": {
197+
"collapsed": false
198+
},
199+
"outputs": [],
200+
"source": [
201+
"from IPython.core.pylabtools import print_figure\n",
202+
"\n",
203+
"def circle_to_png(circle):\n",
204+
" \"\"\"Render AnotherCircle to png data using matplotlib\"\"\"\n",
205+
" fig, ax = plt.subplots()\n",
206+
" patch = plt.Circle(circle.center,\n",
207+
" radius=circle.radius,\n",
208+
" fc=circle.color,\n",
209+
" )\n",
210+
" ax.add_patch(patch)\n",
211+
" plt.axis('scaled')\n",
212+
" data = print_figure(fig, 'png')\n",
213+
" # We MUST close the figure, otherwise IPython's display machinery\n",
214+
" # will pick it up and send it as output, resulting in a double display\n",
215+
" plt.close(fig)\n",
216+
" return data"
217+
]
218+
},
219+
{
220+
"cell_type": "markdown",
221+
"metadata": {},
222+
"source": [
223+
"Now use the IPython API to get the PNG formatter (`image/png`) and call the `for_type` method to register `circle_to_png` as the display function for `MyCircle`."
224+
]
225+
},
226+
{
227+
"cell_type": "code",
228+
"execution_count": null,
229+
"metadata": {
230+
"collapsed": false
231+
},
232+
"outputs": [],
233+
"source": [
234+
"%load soln/mycircle_png.py"
235+
]
236+
},
237+
{
238+
"cell_type": "code",
239+
"execution_count": null,
240+
"metadata": {
241+
"collapsed": false
242+
},
243+
"outputs": [],
244+
"source": [
245+
"display_png(c)"
246+
]
247+
},
248+
{
249+
"cell_type": "markdown",
250+
"metadata": {},
251+
"source": [
252+
"## PNG formatter for NumPy arrays"
253+
]
254+
},
255+
{
256+
"cell_type": "markdown",
257+
"metadata": {},
258+
"source": [
259+
"In this exercise, you will register a display formatter function that generates a PNG representation of a 2d NumPy array. Here is the function that uses the [Python Imaging Library (PIL)](http://www.pythonware.com/products/pil/) to generate the raw PNG data:"
260+
]
261+
},
262+
{
263+
"cell_type": "code",
264+
"execution_count": null,
265+
"metadata": {
266+
"collapsed": false
267+
},
268+
"outputs": [],
269+
"source": [
270+
"from PIL import Image\n",
271+
"from io import BytesIO\n",
272+
"import numpy as np\n",
273+
"\n",
274+
"def ndarray_to_png(x):\n",
275+
" if len(x.shape) != 2: return\n",
276+
" x = np.asarray(Image.fromarray(x).resize((500, 500)))\n",
277+
" x = (x - x.min()) / (x.max() - x.min())\n",
278+
" img = Image.fromarray((x*256).astype('uint8'))\n",
279+
" img_buffer = BytesIO()\n",
280+
" img.save(img_buffer, format='png')\n",
281+
" return img_buffer.getvalue()"
282+
]
283+
},
284+
{
285+
"cell_type": "markdown",
286+
"metadata": {},
287+
"source": [
288+
"Use the `for_type` method of the PNG formatter to register `ndarray_to_png` as the display function for `np.ndarray`."
289+
]
290+
},
291+
{
292+
"cell_type": "code",
293+
"execution_count": null,
294+
"metadata": {
295+
"collapsed": false
296+
},
297+
"outputs": [],
298+
"source": [
299+
"%load soln/ndarray_png.py"
300+
]
301+
},
302+
{
303+
"cell_type": "markdown",
304+
"metadata": {},
305+
"source": [
306+
"Now create a few NumPy arrays and display them. Notice that their default representation in the Notebook is PNG rather than text."
307+
]
308+
},
309+
{
310+
"cell_type": "code",
311+
"execution_count": null,
312+
"metadata": {
313+
"collapsed": false
314+
},
315+
"outputs": [],
316+
"source": [
317+
"a = np.random.rand(100,100)"
318+
]
319+
},
320+
{
321+
"cell_type": "code",
322+
"execution_count": null,
323+
"metadata": {
324+
"collapsed": false
325+
},
326+
"outputs": [],
327+
"source": [
328+
"a"
329+
]
330+
},
331+
{
332+
"cell_type": "markdown",
333+
"metadata": {},
334+
"source": [
335+
"You can still display the plain text representation using the `display_pretty` function."
336+
]
337+
},
338+
{
339+
"cell_type": "code",
340+
"execution_count": null,
341+
"metadata": {
342+
"collapsed": false
343+
},
344+
"outputs": [],
345+
"source": [
346+
"from IPython.display import display_pretty"
347+
]
348+
},
349+
{
350+
"cell_type": "code",
351+
"execution_count": null,
352+
"metadata": {
353+
"collapsed": false
354+
},
355+
"outputs": [],
356+
"source": [
357+
"display_pretty(a)"
358+
]
359+
},
360+
{
361+
"cell_type": "code",
362+
"execution_count": null,
363+
"metadata": {
364+
"collapsed": false
365+
},
366+
"outputs": [],
367+
"source": [
368+
"b = np.linspace(0,100.0, 100**2).reshape((100,100))"
369+
]
370+
},
371+
{
372+
"cell_type": "code",
373+
"execution_count": null,
374+
"metadata": {
375+
"collapsed": false
376+
},
377+
"outputs": [],
378+
"source": [
379+
"b"
380+
]
381+
}
382+
],
383+
"metadata": {},
384+
"nbformat": 4,
385+
"nbformat_minor": 0
386+
}

0 commit comments

Comments
 (0)