##// END OF EJS Templates
Issue 2053:...
Jerry Fowler -
Show More
@@ -0,0 +1,38 b''
1 #-----------------------------------------------------------------------------
2 # Copyright (C) 2010-2011 The IPython Development Team.
3 #
4 # Distributed under the terms of the BSD License.
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
8 import os
9
10 import nose.tools as nt
11
12 from IPython.core import display
13 from IPython.utils import path as ipath
14
15 def test_image_size():
16 """Simple test for display.Image(args, width=x,height=y)"""
17 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
18 img = display.Image(url=thisurl, width=200, height=200)
19 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
20 img = display.Image(url=thisurl, width=200)
21 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
22 img = display.Image(url=thisurl)
23 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
24
25 def test_image_filename_defaults():
26 '''test format constraint, and validity of jpeg and png'''
27 tpath = ipath.get_ipython_package_dir()
28 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.gif'),
29 embed=True)
30 nt.assert_raises(ValueError, display.Image)
31 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
32 imgfile = os.path.join(tpath, 'frontend/html/notebook/static/ipynblogo.png')
33 img = display.Image(filename=imgfile)
34 nt.assert_equal('png', img.format)
35 nt.assert_is_not_none(img._repr_png_())
36 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
37 nt.assert_equal('jpeg', img.format)
38 nt.assert_is_none(img._repr_jpeg_())
@@ -1,532 +1,554 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Top-level display functions for displaying object in different formats.
3 3
4 4 Authors:
5 5
6 6 * Brian Granger
7 7 """
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2008-2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 from __future__ import print_function
21 21
22 22 from xml.dom import minidom
23 23
24 24 from .displaypub import (
25 25 publish_pretty, publish_html,
26 26 publish_latex, publish_svg,
27 27 publish_png, publish_json,
28 28 publish_javascript, publish_jpeg
29 29 )
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Main functions
33 33 #-----------------------------------------------------------------------------
34 34
35 35 def display(*objs, **kwargs):
36 36 """Display a Python object in all frontends.
37 37
38 38 By default all representations will be computed and sent to the frontends.
39 39 Frontends can decide which representation is used and how.
40 40
41 41 Parameters
42 42 ----------
43 43 objs : tuple of objects
44 44 The Python objects to display.
45 45 include : list or tuple, optional
46 46 A list of format type strings (MIME types) to include in the
47 47 format data dict. If this is set *only* the format types included
48 48 in this list will be computed.
49 49 exclude : list or tuple, optional
50 50 A list of format type string (MIME types) to exclue in the format
51 51 data dict. If this is set all format types will be computed,
52 52 except for those included in this argument.
53 53 """
54 54 include = kwargs.get('include')
55 55 exclude = kwargs.get('exclude')
56 56
57 57 from IPython.core.interactiveshell import InteractiveShell
58 58 inst = InteractiveShell.instance()
59 59 format = inst.display_formatter.format
60 60 publish = inst.display_pub.publish
61 61
62 62 for obj in objs:
63 63 format_dict = format(obj, include=include, exclude=exclude)
64 64 publish('IPython.core.display.display', format_dict)
65 65
66 66
67 67 def display_pretty(*objs, **kwargs):
68 68 """Display the pretty (default) representation of an object.
69 69
70 70 Parameters
71 71 ----------
72 72 objs : tuple of objects
73 73 The Python objects to display, or if raw=True raw text data to
74 74 display.
75 75 raw : bool
76 76 Are the data objects raw data or Python objects that need to be
77 77 formatted before display? [default: False]
78 78 """
79 79 raw = kwargs.pop('raw',False)
80 80 if raw:
81 81 for obj in objs:
82 82 publish_pretty(obj)
83 83 else:
84 84 display(*objs, include=['text/plain'])
85 85
86 86
87 87 def display_html(*objs, **kwargs):
88 88 """Display the HTML representation of an object.
89 89
90 90 Parameters
91 91 ----------
92 92 objs : tuple of objects
93 93 The Python objects to display, or if raw=True raw HTML data to
94 94 display.
95 95 raw : bool
96 96 Are the data objects raw data or Python objects that need to be
97 97 formatted before display? [default: False]
98 98 """
99 99 raw = kwargs.pop('raw',False)
100 100 if raw:
101 101 for obj in objs:
102 102 publish_html(obj)
103 103 else:
104 104 display(*objs, include=['text/plain','text/html'])
105 105
106 106
107 107 def display_svg(*objs, **kwargs):
108 108 """Display the SVG representation of an object.
109 109
110 110 Parameters
111 111 ----------
112 112 objs : tuple of objects
113 113 The Python objects to display, or if raw=True raw svg data to
114 114 display.
115 115 raw : bool
116 116 Are the data objects raw data or Python objects that need to be
117 117 formatted before display? [default: False]
118 118 """
119 119 raw = kwargs.pop('raw',False)
120 120 if raw:
121 121 for obj in objs:
122 122 publish_svg(obj)
123 123 else:
124 124 display(*objs, include=['text/plain','image/svg+xml'])
125 125
126 126
127 127 def display_png(*objs, **kwargs):
128 128 """Display the PNG representation of an object.
129 129
130 130 Parameters
131 131 ----------
132 132 objs : tuple of objects
133 133 The Python objects to display, or if raw=True raw png data to
134 134 display.
135 135 raw : bool
136 136 Are the data objects raw data or Python objects that need to be
137 137 formatted before display? [default: False]
138 138 """
139 139 raw = kwargs.pop('raw',False)
140 140 if raw:
141 141 for obj in objs:
142 142 publish_png(obj)
143 143 else:
144 144 display(*objs, include=['text/plain','image/png'])
145 145
146 146
147 147 def display_jpeg(*objs, **kwargs):
148 148 """Display the JPEG representation of an object.
149 149
150 150 Parameters
151 151 ----------
152 152 objs : tuple of objects
153 153 The Python objects to display, or if raw=True raw JPEG data to
154 154 display.
155 155 raw : bool
156 156 Are the data objects raw data or Python objects that need to be
157 157 formatted before display? [default: False]
158 158 """
159 159 raw = kwargs.pop('raw',False)
160 160 if raw:
161 161 for obj in objs:
162 162 publish_jpeg(obj)
163 163 else:
164 164 display(*objs, include=['text/plain','image/jpeg'])
165 165
166 166
167 167 def display_latex(*objs, **kwargs):
168 168 """Display the LaTeX representation of an object.
169 169
170 170 Parameters
171 171 ----------
172 172 objs : tuple of objects
173 173 The Python objects to display, or if raw=True raw latex data to
174 174 display.
175 175 raw : bool
176 176 Are the data objects raw data or Python objects that need to be
177 177 formatted before display? [default: False]
178 178 """
179 179 raw = kwargs.pop('raw',False)
180 180 if raw:
181 181 for obj in objs:
182 182 publish_latex(obj)
183 183 else:
184 184 display(*objs, include=['text/plain','text/latex'])
185 185
186 186
187 187 def display_json(*objs, **kwargs):
188 188 """Display the JSON representation of an object.
189 189
190 190 Parameters
191 191 ----------
192 192 objs : tuple of objects
193 193 The Python objects to display, or if raw=True raw json data to
194 194 display.
195 195 raw : bool
196 196 Are the data objects raw data or Python objects that need to be
197 197 formatted before display? [default: False]
198 198 """
199 199 raw = kwargs.pop('raw',False)
200 200 if raw:
201 201 for obj in objs:
202 202 publish_json(obj)
203 203 else:
204 204 display(*objs, include=['text/plain','application/json'])
205 205
206 206
207 207 def display_javascript(*objs, **kwargs):
208 208 """Display the Javascript representation of an object.
209 209
210 210 Parameters
211 211 ----------
212 212 objs : tuple of objects
213 213 The Python objects to display, or if raw=True raw javascript data to
214 214 display.
215 215 raw : bool
216 216 Are the data objects raw data or Python objects that need to be
217 217 formatted before display? [default: False]
218 218 """
219 219 raw = kwargs.pop('raw',False)
220 220 if raw:
221 221 for obj in objs:
222 222 publish_javascript(obj)
223 223 else:
224 224 display(*objs, include=['text/plain','application/javascript'])
225 225
226 226 #-----------------------------------------------------------------------------
227 227 # Smart classes
228 228 #-----------------------------------------------------------------------------
229 229
230 230
231 231 class DisplayObject(object):
232 232 """An object that wraps data to be displayed."""
233 233
234 234 _read_flags = 'r'
235 235
236 236 def __init__(self, data=None, url=None, filename=None):
237 237 """Create a display object given raw data.
238 238
239 239 When this object is returned by an expression or passed to the
240 240 display function, it will result in the data being displayed
241 241 in the frontend. The MIME type of the data should match the
242 242 subclasses used, so the Png subclass should be used for 'image/png'
243 243 data. If the data is a URL, the data will first be downloaded
244 244 and then displayed. If
245 245
246 246 Parameters
247 247 ----------
248 248 data : unicode, str or bytes
249 249 The raw data or a URL to download the data from.
250 250 url : unicode
251 251 A URL to download the data from.
252 252 filename : unicode
253 253 Path to a local file to load the data from.
254 254 """
255 255 if data is not None and data.startswith('http'):
256 256 self.url = data
257 257 self.filename = None
258 258 self.data = None
259 259 else:
260 260 self.data = data
261 261 self.url = url
262 262 self.filename = None if filename is None else unicode(filename)
263 263 self.reload()
264 264
265 265 def reload(self):
266 266 """Reload the raw data from file or URL."""
267 267 if self.filename is not None:
268 268 with open(self.filename, self._read_flags) as f:
269 269 self.data = f.read()
270 270 elif self.url is not None:
271 271 try:
272 272 import urllib2
273 273 response = urllib2.urlopen(self.url)
274 274 self.data = response.read()
275 275 # extract encoding from header, if there is one:
276 276 encoding = None
277 277 for sub in response.headers['content-type'].split(';'):
278 278 sub = sub.strip()
279 279 if sub.startswith('charset'):
280 280 encoding = sub.split('=')[-1].strip()
281 281 break
282 282 # decode data, if an encoding was specified
283 283 if encoding:
284 284 self.data = self.data.decode(encoding, 'replace')
285 285 except:
286 286 self.data = None
287 287
288 288 class Pretty(DisplayObject):
289 289
290 290 def _repr_pretty_(self):
291 291 return self.data
292 292
293 293
294 294 class HTML(DisplayObject):
295 295
296 296 def _repr_html_(self):
297 297 return self.data
298 298
299 299
300 300 class Math(DisplayObject):
301 301
302 302 def _repr_latex_(self):
303 303 s = self.data.strip('$')
304 304 return "$$%s$$" % s
305 305
306 306
307 307 class Latex(DisplayObject):
308 308
309 309 def _repr_latex_(self):
310 310 return self.data
311 311
312 312
313 313 class SVG(DisplayObject):
314 314
315 315 # wrap data in a property, which extracts the <svg> tag, discarding
316 316 # document headers
317 317 _data = None
318 318
319 319 @property
320 320 def data(self):
321 321 return self._data
322 322
323 323 @data.setter
324 324 def data(self, svg):
325 325 if svg is None:
326 326 self._data = None
327 327 return
328 328 # parse into dom object
329 329 x = minidom.parseString(svg)
330 330 # get svg tag (should be 1)
331 331 found_svg = x.getElementsByTagName('svg')
332 332 if found_svg:
333 333 svg = found_svg[0].toxml()
334 334 else:
335 335 # fallback on the input, trust the user
336 336 # but this is probably an error.
337 337 pass
338 338 self._data = svg
339 339
340 340 def _repr_svg_(self):
341 341 return self.data
342 342
343 343
344 344 class JSON(DisplayObject):
345 345
346 346 def _repr_json_(self):
347 347 return self.data
348 348
349 349 css_t = """$("head").append($("<link/>").attr({
350 350 rel: "stylesheet",
351 351 type: "text/css",
352 352 href: "%s"
353 353 }));
354 354 """
355 355
356 356 lib_t1 = """$.getScript("%s", function () {
357 357 """
358 358 lib_t2 = """});
359 359 """
360 360
361 361 class Javascript(DisplayObject):
362 362
363 363 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
364 364 """Create a Javascript display object given raw data.
365 365
366 366 When this object is returned by an expression or passed to the
367 367 display function, it will result in the data being displayed
368 368 in the frontend. If the data is a URL, the data will first be
369 369 downloaded and then displayed.
370 370
371 371 In the Notebook, the containing element will be available as `element`,
372 372 and jQuery will be available. The output area starts hidden, so if
373 373 the js appends content to `element` that should be visible, then
374 374 it must call `container.show()` to unhide the area.
375 375
376 376 Parameters
377 377 ----------
378 378 data : unicode, str or bytes
379 379 The Javascript source code or a URL to download it from.
380 380 url : unicode
381 381 A URL to download the data from.
382 382 filename : unicode
383 383 Path to a local file to load the data from.
384 384 lib : list or str
385 385 A sequence of Javascript library URLs to load asynchronously before
386 386 running the source code. The full URLs of the libraries should
387 387 be given. A single Javascript library URL can also be given as a
388 388 string.
389 389 css: : list or str
390 390 A sequence of css files to load before running the source code.
391 391 The full URLs of the css files should be give. A single css URL
392 392 can also be given as a string.
393 393 """
394 394 if isinstance(lib, basestring):
395 395 lib = [lib]
396 396 elif lib is None:
397 397 lib = []
398 398 if isinstance(css, basestring):
399 399 css = [css]
400 400 elif css is None:
401 401 css = []
402 402 if not isinstance(lib, (list,tuple)):
403 403 raise TypeError('expected sequence, got: %r' % lib)
404 404 if not isinstance(css, (list,tuple)):
405 405 raise TypeError('expected sequence, got: %r' % css)
406 406 self.lib = lib
407 407 self.css = css
408 408 super(Javascript, self).__init__(data=data, url=url, filename=filename)
409 409
410 410 def _repr_javascript_(self):
411 411 r = ''
412 412 for c in self.css:
413 413 r += css_t % c
414 414 for l in self.lib:
415 415 r += lib_t1 % l
416 416 r += self.data
417 417 r += lib_t2*len(self.lib)
418 418 return r
419 419
420 420
421 421 class Image(DisplayObject):
422 422
423 423 _read_flags = 'rb'
424 _FMT_JPEG = u'jpeg'
425 _FMT_PNG = u'png'
426 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
424 427
425 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None):
428 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None):
426 429 """Create a display an PNG/JPEG image given raw data.
427 430
428 431 When this object is returned by an expression or passed to the
429 432 display function, it will result in the image being displayed
430 433 in the frontend.
431 434
432 435 Parameters
433 436 ----------
434 437 data : unicode, str or bytes
435 438 The raw data or a URL to download the data from.
436 439 url : unicode
437 440 A URL to download the data from.
438 441 filename : unicode
439 442 Path to a local file to load the data from.
440 443 format : unicode
441 444 The format of the image data (png/jpeg/jpg). If a filename or URL is given
442 445 for format will be inferred from the filename extension.
443 446 embed : bool
444 447 Should the image data be embedded using a data URI (True) or be
445 448 loaded using an <img> tag. Set this to True if you want the image
446 449 to be viewable later with no internet connection in the notebook.
447 450
448 451 Default is `True`, unless the keyword argument `url` is set, then
449 452 default value is `False`.
450 453
451 454 Note that QtConsole is not able to display images if `embed` is set to `False`
455 width : int
456 Width to which to constrain the image in html
457 height : int
458 Height to which to constrain the image in html
452 459
453 460 Examples
454 461 --------
455 462 # embed implicitly True, works in qtconsole and notebook
456 463 Image('http://www.google.fr/images/srpr/logo3w.png')
457 464
458 465 # embed implicitly False, does not works in qtconsole but works in notebook if
459 466 # internet connection available
460 467 Image(url='http://www.google.fr/images/srpr/logo3w.png')
461 468
462 469 """
463 470 if filename is not None:
464 471 ext = self._find_ext(filename)
465 472 elif url is not None:
466 473 ext = self._find_ext(url)
474 elif data is None:
475 raise ValueError("No image data found. Expecting filename, url, or data.")
467 476 elif data.startswith('http'):
468 477 ext = self._find_ext(data)
469 478 else:
470 479 ext = None
480
471 481 if ext is not None:
482 format = ext.lower()
472 483 if ext == u'jpg' or ext == u'jpeg':
473 format = u'jpeg'
484 format = self._FMT_JPEG
474 485 if ext == u'png':
475 format = u'png'
486 format = self._FMT_PNG
487
476 488 self.format = unicode(format).lower()
477 489 self.embed = embed if embed is not None else (url is None)
490
491 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
492 raise ValueError("Cannot embed the '%s' image format" % (self.format))
493 self.width = width
494 self.height = height
478 495 super(Image, self).__init__(data=data, url=url, filename=filename)
479 496
480 497 def reload(self):
481 498 """Reload the raw data from file or URL."""
482 499 if self.embed:
483 500 super(Image,self).reload()
484 501
485 502 def _repr_html_(self):
486 503 if not self.embed:
487 return u'<img src="%s" />' % self.url
504 width = height = ''
505 if self.width:
506 width = ' width="%d"' % self.width
507 if self.height:
508 height = ' height="%d"' % self.height
509 return u'<img src="%s"%s%s/>' % (self.url, width, height)
488 510
489 511 def _repr_png_(self):
490 512 if self.embed and self.format == u'png':
491 513 return self.data
492 514
493 515 def _repr_jpeg_(self):
494 516 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
495 517 return self.data
496 518
497 519 def _find_ext(self, s):
498 520 return unicode(s.split('.')[-1].lower())
499 521
500 522
501 523 def clear_output(stdout=True, stderr=True, other=True):
502 524 """Clear the output of the current cell receiving output.
503 525
504 526 Optionally, each of stdout/stderr or other non-stream data (e.g. anything
505 527 produced by display()) can be excluded from the clear event.
506 528
507 529 By default, everything is cleared.
508 530
509 531 Parameters
510 532 ----------
511 533 stdout : bool [default: True]
512 534 Whether to clear stdout.
513 535 stderr : bool [default: True]
514 536 Whether to clear stderr.
515 537 other : bool [default: True]
516 538 Whether to clear everything else that is not stdout/stderr
517 539 (e.g. figures,images,HTML, any result of display()).
518 540 """
519 541 from IPython.core.interactiveshell import InteractiveShell
520 542 if InteractiveShell.initialized():
521 543 InteractiveShell.instance().display_pub.clear_output(
522 544 stdout=stdout, stderr=stderr, other=other,
523 545 )
524 546 else:
525 547 from IPython.utils import io
526 548 if stdout:
527 549 print('\033[2K\r', file=io.stdout, end='')
528 550 io.stdout.flush()
529 551 if stderr:
530 552 print('\033[2K\r', file=io.stderr, end='')
531 553 io.stderr.flush()
532 554
General Comments 0
You need to be logged in to leave comments. Login now