##// END OF EJS Templates
unicode fixes in SVG...
MinRK -
Show More
@@ -1,689 +1,691 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats.
2 """Top-level display functions for displaying object in different formats.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2013 The IPython Development Team
10 # Copyright (C) 2013 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 from __future__ import print_function
20 from __future__ import print_function
21
21
22 import os
22 import os
23 import struct
23 import struct
24
24
25 from IPython.utils.py3compat import string_types
25 from IPython.utils.py3compat import string_types, cast_bytes_py2, cast_unicode
26
26
27 from .displaypub import publish_display_data
27 from .displaypub import publish_display_data
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # utility functions
30 # utility functions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 def _safe_exists(path):
33 def _safe_exists(path):
34 """Check path, but don't let exceptions raise"""
34 """Check path, but don't let exceptions raise"""
35 try:
35 try:
36 return os.path.exists(path)
36 return os.path.exists(path)
37 except Exception:
37 except Exception:
38 return False
38 return False
39
39
40 def _merge(d1, d2):
40 def _merge(d1, d2):
41 """Like update, but merges sub-dicts instead of clobbering at the top level.
41 """Like update, but merges sub-dicts instead of clobbering at the top level.
42
42
43 Updates d1 in-place
43 Updates d1 in-place
44 """
44 """
45
45
46 if not isinstance(d2, dict) or not isinstance(d1, dict):
46 if not isinstance(d2, dict) or not isinstance(d1, dict):
47 return d2
47 return d2
48 for key, value in d2.items():
48 for key, value in d2.items():
49 d1[key] = _merge(d1.get(key), value)
49 d1[key] = _merge(d1.get(key), value)
50 return d1
50 return d1
51
51
52 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
52 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
53 """internal implementation of all display_foo methods
53 """internal implementation of all display_foo methods
54
54
55 Parameters
55 Parameters
56 ----------
56 ----------
57 mimetype : str
57 mimetype : str
58 The mimetype to be published (e.g. 'image/png')
58 The mimetype to be published (e.g. 'image/png')
59 objs : tuple of objects
59 objs : tuple of objects
60 The Python objects to display, or if raw=True raw text data to
60 The Python objects to display, or if raw=True raw text data to
61 display.
61 display.
62 raw : bool
62 raw : bool
63 Are the data objects raw data or Python objects that need to be
63 Are the data objects raw data or Python objects that need to be
64 formatted before display? [default: False]
64 formatted before display? [default: False]
65 metadata : dict (optional)
65 metadata : dict (optional)
66 Metadata to be associated with the specific mimetype output.
66 Metadata to be associated with the specific mimetype output.
67 """
67 """
68 if metadata:
68 if metadata:
69 metadata = {mimetype: metadata}
69 metadata = {mimetype: metadata}
70 if raw:
70 if raw:
71 # turn list of pngdata into list of { 'image/png': pngdata }
71 # turn list of pngdata into list of { 'image/png': pngdata }
72 objs = [ {mimetype: obj} for obj in objs ]
72 objs = [ {mimetype: obj} for obj in objs ]
73 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
73 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
74
74
75 #-----------------------------------------------------------------------------
75 #-----------------------------------------------------------------------------
76 # Main functions
76 # Main functions
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78
78
79 def display(*objs, **kwargs):
79 def display(*objs, **kwargs):
80 """Display a Python object in all frontends.
80 """Display a Python object in all frontends.
81
81
82 By default all representations will be computed and sent to the frontends.
82 By default all representations will be computed and sent to the frontends.
83 Frontends can decide which representation is used and how.
83 Frontends can decide which representation is used and how.
84
84
85 Parameters
85 Parameters
86 ----------
86 ----------
87 objs : tuple of objects
87 objs : tuple of objects
88 The Python objects to display.
88 The Python objects to display.
89 raw : bool, optional
89 raw : bool, optional
90 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
90 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
91 or Python objects that need to be formatted before display? [default: False]
91 or Python objects that need to be formatted before display? [default: False]
92 include : list or tuple, optional
92 include : list or tuple, optional
93 A list of format type strings (MIME types) to include in the
93 A list of format type strings (MIME types) to include in the
94 format data dict. If this is set *only* the format types included
94 format data dict. If this is set *only* the format types included
95 in this list will be computed.
95 in this list will be computed.
96 exclude : list or tuple, optional
96 exclude : list or tuple, optional
97 A list of format type strings (MIME types) to exclude in the format
97 A list of format type strings (MIME types) to exclude in the format
98 data dict. If this is set all format types will be computed,
98 data dict. If this is set all format types will be computed,
99 except for those included in this argument.
99 except for those included in this argument.
100 metadata : dict, optional
100 metadata : dict, optional
101 A dictionary of metadata to associate with the output.
101 A dictionary of metadata to associate with the output.
102 mime-type keys in this dictionary will be associated with the individual
102 mime-type keys in this dictionary will be associated with the individual
103 representation formats, if they exist.
103 representation formats, if they exist.
104 """
104 """
105 raw = kwargs.get('raw', False)
105 raw = kwargs.get('raw', False)
106 include = kwargs.get('include')
106 include = kwargs.get('include')
107 exclude = kwargs.get('exclude')
107 exclude = kwargs.get('exclude')
108 metadata = kwargs.get('metadata')
108 metadata = kwargs.get('metadata')
109
109
110 from IPython.core.interactiveshell import InteractiveShell
110 from IPython.core.interactiveshell import InteractiveShell
111
111
112 if raw:
112 if raw:
113 for obj in objs:
113 for obj in objs:
114 publish_display_data('display', obj, metadata)
114 publish_display_data('display', obj, metadata)
115 else:
115 else:
116 format = InteractiveShell.instance().display_formatter.format
116 format = InteractiveShell.instance().display_formatter.format
117 for obj in objs:
117 for obj in objs:
118 format_dict, md_dict = format(obj, include=include, exclude=exclude)
118 format_dict, md_dict = format(obj, include=include, exclude=exclude)
119 if metadata:
119 if metadata:
120 # kwarg-specified metadata gets precedence
120 # kwarg-specified metadata gets precedence
121 _merge(md_dict, metadata)
121 _merge(md_dict, metadata)
122 publish_display_data('display', format_dict, md_dict)
122 publish_display_data('display', format_dict, md_dict)
123
123
124
124
125 def display_pretty(*objs, **kwargs):
125 def display_pretty(*objs, **kwargs):
126 """Display the pretty (default) representation of an object.
126 """Display the pretty (default) representation of an object.
127
127
128 Parameters
128 Parameters
129 ----------
129 ----------
130 objs : tuple of objects
130 objs : tuple of objects
131 The Python objects to display, or if raw=True raw text data to
131 The Python objects to display, or if raw=True raw text data to
132 display.
132 display.
133 raw : bool
133 raw : bool
134 Are the data objects raw data or Python objects that need to be
134 Are the data objects raw data or Python objects that need to be
135 formatted before display? [default: False]
135 formatted before display? [default: False]
136 metadata : dict (optional)
136 metadata : dict (optional)
137 Metadata to be associated with the specific mimetype output.
137 Metadata to be associated with the specific mimetype output.
138 """
138 """
139 _display_mimetype('text/plain', objs, **kwargs)
139 _display_mimetype('text/plain', objs, **kwargs)
140
140
141
141
142 def display_html(*objs, **kwargs):
142 def display_html(*objs, **kwargs):
143 """Display the HTML representation of an object.
143 """Display the HTML representation of an object.
144
144
145 Parameters
145 Parameters
146 ----------
146 ----------
147 objs : tuple of objects
147 objs : tuple of objects
148 The Python objects to display, or if raw=True raw HTML data to
148 The Python objects to display, or if raw=True raw HTML data to
149 display.
149 display.
150 raw : bool
150 raw : bool
151 Are the data objects raw data or Python objects that need to be
151 Are the data objects raw data or Python objects that need to be
152 formatted before display? [default: False]
152 formatted before display? [default: False]
153 metadata : dict (optional)
153 metadata : dict (optional)
154 Metadata to be associated with the specific mimetype output.
154 Metadata to be associated with the specific mimetype output.
155 """
155 """
156 _display_mimetype('text/html', objs, **kwargs)
156 _display_mimetype('text/html', objs, **kwargs)
157
157
158
158
159 def display_svg(*objs, **kwargs):
159 def display_svg(*objs, **kwargs):
160 """Display the SVG representation of an object.
160 """Display the SVG representation of an object.
161
161
162 Parameters
162 Parameters
163 ----------
163 ----------
164 objs : tuple of objects
164 objs : tuple of objects
165 The Python objects to display, or if raw=True raw svg data to
165 The Python objects to display, or if raw=True raw svg data to
166 display.
166 display.
167 raw : bool
167 raw : bool
168 Are the data objects raw data or Python objects that need to be
168 Are the data objects raw data or Python objects that need to be
169 formatted before display? [default: False]
169 formatted before display? [default: False]
170 metadata : dict (optional)
170 metadata : dict (optional)
171 Metadata to be associated with the specific mimetype output.
171 Metadata to be associated with the specific mimetype output.
172 """
172 """
173 _display_mimetype('image/svg+xml', objs, **kwargs)
173 _display_mimetype('image/svg+xml', objs, **kwargs)
174
174
175
175
176 def display_png(*objs, **kwargs):
176 def display_png(*objs, **kwargs):
177 """Display the PNG representation of an object.
177 """Display the PNG representation of an object.
178
178
179 Parameters
179 Parameters
180 ----------
180 ----------
181 objs : tuple of objects
181 objs : tuple of objects
182 The Python objects to display, or if raw=True raw png data to
182 The Python objects to display, or if raw=True raw png data to
183 display.
183 display.
184 raw : bool
184 raw : bool
185 Are the data objects raw data or Python objects that need to be
185 Are the data objects raw data or Python objects that need to be
186 formatted before display? [default: False]
186 formatted before display? [default: False]
187 metadata : dict (optional)
187 metadata : dict (optional)
188 Metadata to be associated with the specific mimetype output.
188 Metadata to be associated with the specific mimetype output.
189 """
189 """
190 _display_mimetype('image/png', objs, **kwargs)
190 _display_mimetype('image/png', objs, **kwargs)
191
191
192
192
193 def display_jpeg(*objs, **kwargs):
193 def display_jpeg(*objs, **kwargs):
194 """Display the JPEG representation of an object.
194 """Display the JPEG representation of an object.
195
195
196 Parameters
196 Parameters
197 ----------
197 ----------
198 objs : tuple of objects
198 objs : tuple of objects
199 The Python objects to display, or if raw=True raw JPEG data to
199 The Python objects to display, or if raw=True raw JPEG data to
200 display.
200 display.
201 raw : bool
201 raw : bool
202 Are the data objects raw data or Python objects that need to be
202 Are the data objects raw data or Python objects that need to be
203 formatted before display? [default: False]
203 formatted before display? [default: False]
204 metadata : dict (optional)
204 metadata : dict (optional)
205 Metadata to be associated with the specific mimetype output.
205 Metadata to be associated with the specific mimetype output.
206 """
206 """
207 _display_mimetype('image/jpeg', objs, **kwargs)
207 _display_mimetype('image/jpeg', objs, **kwargs)
208
208
209
209
210 def display_latex(*objs, **kwargs):
210 def display_latex(*objs, **kwargs):
211 """Display the LaTeX representation of an object.
211 """Display the LaTeX representation of an object.
212
212
213 Parameters
213 Parameters
214 ----------
214 ----------
215 objs : tuple of objects
215 objs : tuple of objects
216 The Python objects to display, or if raw=True raw latex data to
216 The Python objects to display, or if raw=True raw latex data to
217 display.
217 display.
218 raw : bool
218 raw : bool
219 Are the data objects raw data or Python objects that need to be
219 Are the data objects raw data or Python objects that need to be
220 formatted before display? [default: False]
220 formatted before display? [default: False]
221 metadata : dict (optional)
221 metadata : dict (optional)
222 Metadata to be associated with the specific mimetype output.
222 Metadata to be associated with the specific mimetype output.
223 """
223 """
224 _display_mimetype('text/latex', objs, **kwargs)
224 _display_mimetype('text/latex', objs, **kwargs)
225
225
226
226
227 def display_json(*objs, **kwargs):
227 def display_json(*objs, **kwargs):
228 """Display the JSON representation of an object.
228 """Display the JSON representation of an object.
229
229
230 Note that not many frontends support displaying JSON.
230 Note that not many frontends support displaying JSON.
231
231
232 Parameters
232 Parameters
233 ----------
233 ----------
234 objs : tuple of objects
234 objs : tuple of objects
235 The Python objects to display, or if raw=True raw json data to
235 The Python objects to display, or if raw=True raw json data to
236 display.
236 display.
237 raw : bool
237 raw : bool
238 Are the data objects raw data or Python objects that need to be
238 Are the data objects raw data or Python objects that need to be
239 formatted before display? [default: False]
239 formatted before display? [default: False]
240 metadata : dict (optional)
240 metadata : dict (optional)
241 Metadata to be associated with the specific mimetype output.
241 Metadata to be associated with the specific mimetype output.
242 """
242 """
243 _display_mimetype('application/json', objs, **kwargs)
243 _display_mimetype('application/json', objs, **kwargs)
244
244
245
245
246 def display_javascript(*objs, **kwargs):
246 def display_javascript(*objs, **kwargs):
247 """Display the Javascript representation of an object.
247 """Display the Javascript representation of an object.
248
248
249 Parameters
249 Parameters
250 ----------
250 ----------
251 objs : tuple of objects
251 objs : tuple of objects
252 The Python objects to display, or if raw=True raw javascript data to
252 The Python objects to display, or if raw=True raw javascript data to
253 display.
253 display.
254 raw : bool
254 raw : bool
255 Are the data objects raw data or Python objects that need to be
255 Are the data objects raw data or Python objects that need to be
256 formatted before display? [default: False]
256 formatted before display? [default: False]
257 metadata : dict (optional)
257 metadata : dict (optional)
258 Metadata to be associated with the specific mimetype output.
258 Metadata to be associated with the specific mimetype output.
259 """
259 """
260 _display_mimetype('application/javascript', objs, **kwargs)
260 _display_mimetype('application/javascript', objs, **kwargs)
261
261
262 #-----------------------------------------------------------------------------
262 #-----------------------------------------------------------------------------
263 # Smart classes
263 # Smart classes
264 #-----------------------------------------------------------------------------
264 #-----------------------------------------------------------------------------
265
265
266
266
267 class DisplayObject(object):
267 class DisplayObject(object):
268 """An object that wraps data to be displayed."""
268 """An object that wraps data to be displayed."""
269
269
270 _read_flags = 'r'
270 _read_flags = 'r'
271
271
272 def __init__(self, data=None, url=None, filename=None):
272 def __init__(self, data=None, url=None, filename=None):
273 """Create a display object given raw data.
273 """Create a display object given raw data.
274
274
275 When this object is returned by an expression or passed to the
275 When this object is returned by an expression or passed to the
276 display function, it will result in the data being displayed
276 display function, it will result in the data being displayed
277 in the frontend. The MIME type of the data should match the
277 in the frontend. The MIME type of the data should match the
278 subclasses used, so the Png subclass should be used for 'image/png'
278 subclasses used, so the Png subclass should be used for 'image/png'
279 data. If the data is a URL, the data will first be downloaded
279 data. If the data is a URL, the data will first be downloaded
280 and then displayed. If
280 and then displayed. If
281
281
282 Parameters
282 Parameters
283 ----------
283 ----------
284 data : unicode, str or bytes
284 data : unicode, str or bytes
285 The raw data or a URL or file to load the data from
285 The raw data or a URL or file to load the data from
286 url : unicode
286 url : unicode
287 A URL to download the data from.
287 A URL to download the data from.
288 filename : unicode
288 filename : unicode
289 Path to a local file to load the data from.
289 Path to a local file to load the data from.
290 """
290 """
291 if data is not None and isinstance(data, string_types):
291 if data is not None and isinstance(data, string_types):
292 if data.startswith('http') and url is None:
292 if data.startswith('http') and url is None:
293 url = data
293 url = data
294 filename = None
294 filename = None
295 data = None
295 data = None
296 elif _safe_exists(data) and filename is None:
296 elif _safe_exists(data) and filename is None:
297 url = None
297 url = None
298 filename = data
298 filename = data
299 data = None
299 data = None
300
300
301 self.data = data
301 self.data = data
302 self.url = url
302 self.url = url
303 self.filename = None if filename is None else unicode(filename)
303 self.filename = None if filename is None else unicode(filename)
304
304
305 self.reload()
305 self.reload()
306
306
307 def reload(self):
307 def reload(self):
308 """Reload the raw data from file or URL."""
308 """Reload the raw data from file or URL."""
309 if self.filename is not None:
309 if self.filename is not None:
310 with open(self.filename, self._read_flags) as f:
310 with open(self.filename, self._read_flags) as f:
311 self.data = f.read()
311 self.data = f.read()
312 elif self.url is not None:
312 elif self.url is not None:
313 try:
313 try:
314 import urllib2
314 import urllib2
315 response = urllib2.urlopen(self.url)
315 response = urllib2.urlopen(self.url)
316 self.data = response.read()
316 self.data = response.read()
317 # extract encoding from header, if there is one:
317 # extract encoding from header, if there is one:
318 encoding = None
318 encoding = None
319 for sub in response.headers['content-type'].split(';'):
319 for sub in response.headers['content-type'].split(';'):
320 sub = sub.strip()
320 sub = sub.strip()
321 if sub.startswith('charset'):
321 if sub.startswith('charset'):
322 encoding = sub.split('=')[-1].strip()
322 encoding = sub.split('=')[-1].strip()
323 break
323 break
324 # decode data, if an encoding was specified
324 # decode data, if an encoding was specified
325 if encoding:
325 if encoding:
326 self.data = self.data.decode(encoding, 'replace')
326 self.data = self.data.decode(encoding, 'replace')
327 except:
327 except:
328 self.data = None
328 self.data = None
329
329
330 class Pretty(DisplayObject):
330 class Pretty(DisplayObject):
331
331
332 def _repr_pretty_(self):
332 def _repr_pretty_(self):
333 return self.data
333 return self.data
334
334
335
335
336 class HTML(DisplayObject):
336 class HTML(DisplayObject):
337
337
338 def _repr_html_(self):
338 def _repr_html_(self):
339 return self.data
339 return self.data
340
340
341 def __html__(self):
341 def __html__(self):
342 """
342 """
343 This method exists to inform other HTML-using modules (e.g. Markupsafe,
343 This method exists to inform other HTML-using modules (e.g. Markupsafe,
344 htmltag, etc) that this object is HTML and does not need things like
344 htmltag, etc) that this object is HTML and does not need things like
345 special characters (<>&) escaped.
345 special characters (<>&) escaped.
346 """
346 """
347 return self._repr_html_()
347 return self._repr_html_()
348
348
349
349
350 class Math(DisplayObject):
350 class Math(DisplayObject):
351
351
352 def _repr_latex_(self):
352 def _repr_latex_(self):
353 s = self.data.strip('$')
353 s = self.data.strip('$')
354 return "$$%s$$" % s
354 return "$$%s$$" % s
355
355
356
356
357 class Latex(DisplayObject):
357 class Latex(DisplayObject):
358
358
359 def _repr_latex_(self):
359 def _repr_latex_(self):
360 return self.data
360 return self.data
361
361
362
362
363 class SVG(DisplayObject):
363 class SVG(DisplayObject):
364
364
365 # wrap data in a property, which extracts the <svg> tag, discarding
365 # wrap data in a property, which extracts the <svg> tag, discarding
366 # document headers
366 # document headers
367 _data = None
367 _data = None
368
368
369 @property
369 @property
370 def data(self):
370 def data(self):
371 return self._data
371 return self._data
372
372
373 @data.setter
373 @data.setter
374 def data(self, svg):
374 def data(self, svg):
375 if svg is None:
375 if svg is None:
376 self._data = None
376 self._data = None
377 return
377 return
378 # parse into dom object
378 # parse into dom object
379 from xml.dom import minidom
379 from xml.dom import minidom
380 svg = cast_bytes_py2(svg)
380 x = minidom.parseString(svg)
381 x = minidom.parseString(svg)
381 # get svg tag (should be 1)
382 # get svg tag (should be 1)
382 found_svg = x.getElementsByTagName('svg')
383 found_svg = x.getElementsByTagName('svg')
383 if found_svg:
384 if found_svg:
384 svg = found_svg[0].toxml()
385 svg = found_svg[0].toxml()
385 else:
386 else:
386 # fallback on the input, trust the user
387 # fallback on the input, trust the user
387 # but this is probably an error.
388 # but this is probably an error.
388 pass
389 pass
390 svg = cast_unicode(svg)
389 self._data = svg
391 self._data = svg
390
392
391 def _repr_svg_(self):
393 def _repr_svg_(self):
392 return self.data
394 return self.data
393
395
394
396
395 class JSON(DisplayObject):
397 class JSON(DisplayObject):
396
398
397 def _repr_json_(self):
399 def _repr_json_(self):
398 return self.data
400 return self.data
399
401
400 css_t = """$("head").append($("<link/>").attr({
402 css_t = """$("head").append($("<link/>").attr({
401 rel: "stylesheet",
403 rel: "stylesheet",
402 type: "text/css",
404 type: "text/css",
403 href: "%s"
405 href: "%s"
404 }));
406 }));
405 """
407 """
406
408
407 lib_t1 = """$.getScript("%s", function () {
409 lib_t1 = """$.getScript("%s", function () {
408 """
410 """
409 lib_t2 = """});
411 lib_t2 = """});
410 """
412 """
411
413
412 class Javascript(DisplayObject):
414 class Javascript(DisplayObject):
413
415
414 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
416 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
415 """Create a Javascript display object given raw data.
417 """Create a Javascript display object given raw data.
416
418
417 When this object is returned by an expression or passed to the
419 When this object is returned by an expression or passed to the
418 display function, it will result in the data being displayed
420 display function, it will result in the data being displayed
419 in the frontend. If the data is a URL, the data will first be
421 in the frontend. If the data is a URL, the data will first be
420 downloaded and then displayed.
422 downloaded and then displayed.
421
423
422 In the Notebook, the containing element will be available as `element`,
424 In the Notebook, the containing element will be available as `element`,
423 and jQuery will be available. The output area starts hidden, so if
425 and jQuery will be available. The output area starts hidden, so if
424 the js appends content to `element` that should be visible, then
426 the js appends content to `element` that should be visible, then
425 it must call `container.show()` to unhide the area.
427 it must call `container.show()` to unhide the area.
426
428
427 Parameters
429 Parameters
428 ----------
430 ----------
429 data : unicode, str or bytes
431 data : unicode, str or bytes
430 The Javascript source code or a URL to download it from.
432 The Javascript source code or a URL to download it from.
431 url : unicode
433 url : unicode
432 A URL to download the data from.
434 A URL to download the data from.
433 filename : unicode
435 filename : unicode
434 Path to a local file to load the data from.
436 Path to a local file to load the data from.
435 lib : list or str
437 lib : list or str
436 A sequence of Javascript library URLs to load asynchronously before
438 A sequence of Javascript library URLs to load asynchronously before
437 running the source code. The full URLs of the libraries should
439 running the source code. The full URLs of the libraries should
438 be given. A single Javascript library URL can also be given as a
440 be given. A single Javascript library URL can also be given as a
439 string.
441 string.
440 css: : list or str
442 css: : list or str
441 A sequence of css files to load before running the source code.
443 A sequence of css files to load before running the source code.
442 The full URLs of the css files should be given. A single css URL
444 The full URLs of the css files should be given. A single css URL
443 can also be given as a string.
445 can also be given as a string.
444 """
446 """
445 if isinstance(lib, basestring):
447 if isinstance(lib, basestring):
446 lib = [lib]
448 lib = [lib]
447 elif lib is None:
449 elif lib is None:
448 lib = []
450 lib = []
449 if isinstance(css, basestring):
451 if isinstance(css, basestring):
450 css = [css]
452 css = [css]
451 elif css is None:
453 elif css is None:
452 css = []
454 css = []
453 if not isinstance(lib, (list,tuple)):
455 if not isinstance(lib, (list,tuple)):
454 raise TypeError('expected sequence, got: %r' % lib)
456 raise TypeError('expected sequence, got: %r' % lib)
455 if not isinstance(css, (list,tuple)):
457 if not isinstance(css, (list,tuple)):
456 raise TypeError('expected sequence, got: %r' % css)
458 raise TypeError('expected sequence, got: %r' % css)
457 self.lib = lib
459 self.lib = lib
458 self.css = css
460 self.css = css
459 super(Javascript, self).__init__(data=data, url=url, filename=filename)
461 super(Javascript, self).__init__(data=data, url=url, filename=filename)
460
462
461 def _repr_javascript_(self):
463 def _repr_javascript_(self):
462 r = ''
464 r = ''
463 for c in self.css:
465 for c in self.css:
464 r += css_t % c
466 r += css_t % c
465 for l in self.lib:
467 for l in self.lib:
466 r += lib_t1 % l
468 r += lib_t1 % l
467 r += self.data
469 r += self.data
468 r += lib_t2*len(self.lib)
470 r += lib_t2*len(self.lib)
469 return r
471 return r
470
472
471 # constants for identifying png/jpeg data
473 # constants for identifying png/jpeg data
472 _PNG = b'\x89PNG\r\n\x1a\n'
474 _PNG = b'\x89PNG\r\n\x1a\n'
473 _JPEG = b'\xff\xd8'
475 _JPEG = b'\xff\xd8'
474
476
475 def _pngxy(data):
477 def _pngxy(data):
476 """read the (width, height) from a PNG header"""
478 """read the (width, height) from a PNG header"""
477 ihdr = data.index(b'IHDR')
479 ihdr = data.index(b'IHDR')
478 # next 8 bytes are width/height
480 # next 8 bytes are width/height
479 w4h4 = data[ihdr+4:ihdr+12]
481 w4h4 = data[ihdr+4:ihdr+12]
480 return struct.unpack('>ii', w4h4)
482 return struct.unpack('>ii', w4h4)
481
483
482 def _jpegxy(data):
484 def _jpegxy(data):
483 """read the (width, height) from a JPEG header"""
485 """read the (width, height) from a JPEG header"""
484 # adapted from http://www.64lines.com/jpeg-width-height
486 # adapted from http://www.64lines.com/jpeg-width-height
485
487
486 idx = 4
488 idx = 4
487 while True:
489 while True:
488 block_size = struct.unpack('>H', data[idx:idx+2])[0]
490 block_size = struct.unpack('>H', data[idx:idx+2])[0]
489 idx = idx + block_size
491 idx = idx + block_size
490 if data[idx:idx+2] == b'\xFF\xC0':
492 if data[idx:idx+2] == b'\xFF\xC0':
491 # found Start of Frame
493 # found Start of Frame
492 iSOF = idx
494 iSOF = idx
493 break
495 break
494 else:
496 else:
495 # read another block
497 # read another block
496 idx += 2
498 idx += 2
497
499
498 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
500 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
499 return w, h
501 return w, h
500
502
501 class Image(DisplayObject):
503 class Image(DisplayObject):
502
504
503 _read_flags = 'rb'
505 _read_flags = 'rb'
504 _FMT_JPEG = u'jpeg'
506 _FMT_JPEG = u'jpeg'
505 _FMT_PNG = u'png'
507 _FMT_PNG = u'png'
506 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
508 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
507
509
508 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None, retina=False):
510 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None, retina=False):
509 """Create a display an PNG/JPEG image given raw data.
511 """Create a display an PNG/JPEG image given raw data.
510
512
511 When this object is returned by an expression or passed to the
513 When this object is returned by an expression or passed to the
512 display function, it will result in the image being displayed
514 display function, it will result in the image being displayed
513 in the frontend.
515 in the frontend.
514
516
515 Parameters
517 Parameters
516 ----------
518 ----------
517 data : unicode, str or bytes
519 data : unicode, str or bytes
518 The raw image data or a URL or filename to load the data from.
520 The raw image data or a URL or filename to load the data from.
519 This always results in embedded image data.
521 This always results in embedded image data.
520 url : unicode
522 url : unicode
521 A URL to download the data from. If you specify `url=`,
523 A URL to download the data from. If you specify `url=`,
522 the image data will not be embedded unless you also specify `embed=True`.
524 the image data will not be embedded unless you also specify `embed=True`.
523 filename : unicode
525 filename : unicode
524 Path to a local file to load the data from.
526 Path to a local file to load the data from.
525 Images from a file are always embedded.
527 Images from a file are always embedded.
526 format : unicode
528 format : unicode
527 The format of the image data (png/jpeg/jpg). If a filename or URL is given
529 The format of the image data (png/jpeg/jpg). If a filename or URL is given
528 for format will be inferred from the filename extension.
530 for format will be inferred from the filename extension.
529 embed : bool
531 embed : bool
530 Should the image data be embedded using a data URI (True) or be
532 Should the image data be embedded using a data URI (True) or be
531 loaded using an <img> tag. Set this to True if you want the image
533 loaded using an <img> tag. Set this to True if you want the image
532 to be viewable later with no internet connection in the notebook.
534 to be viewable later with no internet connection in the notebook.
533
535
534 Default is `True`, unless the keyword argument `url` is set, then
536 Default is `True`, unless the keyword argument `url` is set, then
535 default value is `False`.
537 default value is `False`.
536
538
537 Note that QtConsole is not able to display images if `embed` is set to `False`
539 Note that QtConsole is not able to display images if `embed` is set to `False`
538 width : int
540 width : int
539 Width to which to constrain the image in html
541 Width to which to constrain the image in html
540 height : int
542 height : int
541 Height to which to constrain the image in html
543 Height to which to constrain the image in html
542 retina : bool
544 retina : bool
543 Automatically set the width and height to half of the measured
545 Automatically set the width and height to half of the measured
544 width and height.
546 width and height.
545 This only works for embedded images because it reads the width/height
547 This only works for embedded images because it reads the width/height
546 from image data.
548 from image data.
547 For non-embedded images, you can just set the desired display width
549 For non-embedded images, you can just set the desired display width
548 and height directly.
550 and height directly.
549
551
550 Examples
552 Examples
551 --------
553 --------
552 # embedded image data, works in qtconsole and notebook
554 # embedded image data, works in qtconsole and notebook
553 # when passed positionally, the first arg can be any of raw image data,
555 # when passed positionally, the first arg can be any of raw image data,
554 # a URL, or a filename from which to load image data.
556 # a URL, or a filename from which to load image data.
555 # The result is always embedding image data for inline images.
557 # The result is always embedding image data for inline images.
556 Image('http://www.google.fr/images/srpr/logo3w.png')
558 Image('http://www.google.fr/images/srpr/logo3w.png')
557 Image('/path/to/image.jpg')
559 Image('/path/to/image.jpg')
558 Image(b'RAW_PNG_DATA...')
560 Image(b'RAW_PNG_DATA...')
559
561
560 # Specifying Image(url=...) does not embed the image data,
562 # Specifying Image(url=...) does not embed the image data,
561 # it only generates `<img>` tag with a link to the source.
563 # it only generates `<img>` tag with a link to the source.
562 # This will not work in the qtconsole or offline.
564 # This will not work in the qtconsole or offline.
563 Image(url='http://www.google.fr/images/srpr/logo3w.png')
565 Image(url='http://www.google.fr/images/srpr/logo3w.png')
564
566
565 """
567 """
566 if filename is not None:
568 if filename is not None:
567 ext = self._find_ext(filename)
569 ext = self._find_ext(filename)
568 elif url is not None:
570 elif url is not None:
569 ext = self._find_ext(url)
571 ext = self._find_ext(url)
570 elif data is None:
572 elif data is None:
571 raise ValueError("No image data found. Expecting filename, url, or data.")
573 raise ValueError("No image data found. Expecting filename, url, or data.")
572 elif isinstance(data, string_types) and (
574 elif isinstance(data, string_types) and (
573 data.startswith('http') or _safe_exists(data)
575 data.startswith('http') or _safe_exists(data)
574 ):
576 ):
575 ext = self._find_ext(data)
577 ext = self._find_ext(data)
576 else:
578 else:
577 ext = None
579 ext = None
578
580
579 if ext is not None:
581 if ext is not None:
580 format = ext.lower()
582 format = ext.lower()
581 if ext == u'jpg' or ext == u'jpeg':
583 if ext == u'jpg' or ext == u'jpeg':
582 format = self._FMT_JPEG
584 format = self._FMT_JPEG
583 if ext == u'png':
585 if ext == u'png':
584 format = self._FMT_PNG
586 format = self._FMT_PNG
585 elif isinstance(data, bytes) and format == 'png':
587 elif isinstance(data, bytes) and format == 'png':
586 # infer image type from image data header,
588 # infer image type from image data header,
587 # only if format might not have been specified.
589 # only if format might not have been specified.
588 if data[:2] == _JPEG:
590 if data[:2] == _JPEG:
589 format = 'jpeg'
591 format = 'jpeg'
590
592
591 self.format = unicode(format).lower()
593 self.format = unicode(format).lower()
592 self.embed = embed if embed is not None else (url is None)
594 self.embed = embed if embed is not None else (url is None)
593
595
594 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
596 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
595 raise ValueError("Cannot embed the '%s' image format" % (self.format))
597 raise ValueError("Cannot embed the '%s' image format" % (self.format))
596 self.width = width
598 self.width = width
597 self.height = height
599 self.height = height
598 self.retina = retina
600 self.retina = retina
599 super(Image, self).__init__(data=data, url=url, filename=filename)
601 super(Image, self).__init__(data=data, url=url, filename=filename)
600
602
601 if retina:
603 if retina:
602 self._retina_shape()
604 self._retina_shape()
603
605
604 def _retina_shape(self):
606 def _retina_shape(self):
605 """load pixel-doubled width and height from image data"""
607 """load pixel-doubled width and height from image data"""
606 if not self.embed:
608 if not self.embed:
607 return
609 return
608 if self.format == 'png':
610 if self.format == 'png':
609 w, h = _pngxy(self.data)
611 w, h = _pngxy(self.data)
610 elif self.format == 'jpeg':
612 elif self.format == 'jpeg':
611 w, h = _jpegxy(self.data)
613 w, h = _jpegxy(self.data)
612 else:
614 else:
613 # retina only supports png
615 # retina only supports png
614 return
616 return
615 self.width = w // 2
617 self.width = w // 2
616 self.height = h // 2
618 self.height = h // 2
617
619
618 def reload(self):
620 def reload(self):
619 """Reload the raw data from file or URL."""
621 """Reload the raw data from file or URL."""
620 if self.embed:
622 if self.embed:
621 super(Image,self).reload()
623 super(Image,self).reload()
622 if self.retina:
624 if self.retina:
623 self._retina_shape()
625 self._retina_shape()
624
626
625 def _repr_html_(self):
627 def _repr_html_(self):
626 if not self.embed:
628 if not self.embed:
627 width = height = ''
629 width = height = ''
628 if self.width:
630 if self.width:
629 width = ' width="%d"' % self.width
631 width = ' width="%d"' % self.width
630 if self.height:
632 if self.height:
631 height = ' height="%d"' % self.height
633 height = ' height="%d"' % self.height
632 return u'<img src="%s"%s%s/>' % (self.url, width, height)
634 return u'<img src="%s"%s%s/>' % (self.url, width, height)
633
635
634 def _data_and_metadata(self):
636 def _data_and_metadata(self):
635 """shortcut for returning metadata with shape information, if defined"""
637 """shortcut for returning metadata with shape information, if defined"""
636 md = {}
638 md = {}
637 if self.width:
639 if self.width:
638 md['width'] = self.width
640 md['width'] = self.width
639 if self.height:
641 if self.height:
640 md['height'] = self.height
642 md['height'] = self.height
641 if md:
643 if md:
642 return self.data, md
644 return self.data, md
643 else:
645 else:
644 return self.data
646 return self.data
645
647
646 def _repr_png_(self):
648 def _repr_png_(self):
647 if self.embed and self.format == u'png':
649 if self.embed and self.format == u'png':
648 return self._data_and_metadata()
650 return self._data_and_metadata()
649
651
650 def _repr_jpeg_(self):
652 def _repr_jpeg_(self):
651 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
653 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
652 return self._data_and_metadata()
654 return self._data_and_metadata()
653
655
654 def _find_ext(self, s):
656 def _find_ext(self, s):
655 return unicode(s.split('.')[-1].lower())
657 return unicode(s.split('.')[-1].lower())
656
658
657
659
658 def clear_output(stdout=True, stderr=True, other=True):
660 def clear_output(stdout=True, stderr=True, other=True):
659 """Clear the output of the current cell receiving output.
661 """Clear the output of the current cell receiving output.
660
662
661 Optionally, each of stdout/stderr or other non-stream data (e.g. anything
663 Optionally, each of stdout/stderr or other non-stream data (e.g. anything
662 produced by display()) can be excluded from the clear event.
664 produced by display()) can be excluded from the clear event.
663
665
664 By default, everything is cleared.
666 By default, everything is cleared.
665
667
666 Parameters
668 Parameters
667 ----------
669 ----------
668 stdout : bool [default: True]
670 stdout : bool [default: True]
669 Whether to clear stdout.
671 Whether to clear stdout.
670 stderr : bool [default: True]
672 stderr : bool [default: True]
671 Whether to clear stderr.
673 Whether to clear stderr.
672 other : bool [default: True]
674 other : bool [default: True]
673 Whether to clear everything else that is not stdout/stderr
675 Whether to clear everything else that is not stdout/stderr
674 (e.g. figures,images,HTML, any result of display()).
676 (e.g. figures,images,HTML, any result of display()).
675 """
677 """
676 from IPython.core.interactiveshell import InteractiveShell
678 from IPython.core.interactiveshell import InteractiveShell
677 if InteractiveShell.initialized():
679 if InteractiveShell.initialized():
678 InteractiveShell.instance().display_pub.clear_output(
680 InteractiveShell.instance().display_pub.clear_output(
679 stdout=stdout, stderr=stderr, other=other,
681 stdout=stdout, stderr=stderr, other=other,
680 )
682 )
681 else:
683 else:
682 from IPython.utils import io
684 from IPython.utils import io
683 if stdout:
685 if stdout:
684 print('\033[2K\r', file=io.stdout, end='')
686 print('\033[2K\r', file=io.stdout, end='')
685 io.stdout.flush()
687 io.stdout.flush()
686 if stderr:
688 if stderr:
687 print('\033[2K\r', file=io.stderr, end='')
689 print('\033[2K\r', file=io.stderr, end='')
688 io.stderr.flush()
690 io.stderr.flush()
689
691
General Comments 0
You need to be logged in to leave comments. Login now