##// END OF EJS Templates
Move imports into methods and fix docstring typo
David Österberg -
Show More
@@ -1,487 +1,487 b''
1 1 """Various display related classes.
2 2
3 3 Authors : MinRK, gregcaporaso, dannystaple
4 4 """
5 5 from os.path import exists, isfile, splitext, abspath, join, isdir
6 6 from os import walk, sep
7 import base64
8 import struct
9 from io import BytesIO
10 import wave
11 import mimetypes
12 7
13 8 from IPython.core.display import DisplayObject
14 9
15 10
16 11 class Audio(DisplayObject):
17 12 """Create an audio object.
18 13
19 14 When this object is returned by an input cell or passed to the
20 15 display function, it will result in Audio controls being displayed
21 16 in the frontend (only works in the notebook).
22 17
23 18 Parameters
24 19 ----------
25 20 data : numpy array, unicode, str or bytes
26 21 Can be a
27 22 * Numpy array containing the desired waveform,
28 * String containingvthe filename
23 * String containing the filename
29 24 * Bytestring containing raw PCM data or
30 25 * URL pointing to a file on the web.
31 26
32 27 If the array option is used the waveform will be normalized.
33 28
34 29 If a filename or url is used the format support will be browser
35 30 dependent.
36 31 url : unicode
37 32 A URL to download the data from.
38 33 filename : unicode
39 34 Path to a local file to load the data from.
40 35 embed : boolean
41 36 Should the image data be embedded using a data URI (True) or be
42 37 loaded using an <img> tag. Set this to True if you want the image
43 38 to be viewable later with no internet connection in the notebook.
44 39
45 40 Default is `True`, unless the keyword argument `url` is set, then
46 41 default value is `False`.
47 42 rate : integer
48 43 The sampling rate of the raw data.
49 44 Only required when data parameter is being used as an array
50 45 autoplay : bool
51 46 Set to True if the audio should immediately start playing.
52 47 Default is `False`.
53 48
54 49 Examples
55 50 --------
56 51
57 52 # Generate a sound
58 53 import numpy as np
59 54 framerate = 44100
60 55 t = np.linspace(0,5,framerate*5)
61 56 data = np.sin(2*np.pi*440*np.sin(10*t**2))
62 57 Audio(data,rate=framerate)
63 58
64 59 Audio("http://www.nch.com.au/acm/8k16bitpcm.wav")
65 60 Audio(url="http://media.bradsucks.net/albums/ooi-128/01_-_Brad_Sucks_-_Dropping_out_of_School.mp3")
66 61 Audio(url="http://www.w3schools.com/html/horse.ogg", embed=True)
67 62
68 63 Audio('/path/to/sound.wav')
69 64 Audio(filename='/path/to/sound.ogg')
70 65
71 66 Audio(b'RAW_WAV_DATA..)
72 67 Audio(data=b'RAW_WAV_DATA..)
73 68
74 69 """
75 70
76 71 def __init__(self, data=None, filename=None, url=None, embed=None, rate=None, autoplay=False):
77 72 if filename is None and url is None and data is None:
78 73 raise ValueError("No image data found. Expecting filename, url, or data.")
79 74 if embed is False and url is None:
80 75 raise ValueError("No url found. Expecting url when embed=False")
81 76
82 77 if url is not None and embed is not True:
83 78 self.embed = False
84 79 else:
85 80 self.embed = True
86 81 self.autoplay = autoplay
87 82 super(Audio, self).__init__(data=data, url=url, filename=filename)
88 83
89 84 if self.data is not None and not isinstance(self.data, bytes):
90 85 self.data = self._make_wav(data,rate)
91 86
92 87 def reload(self):
93 88 """Reload the raw data from file or URL."""
89 import mimetypes
94 90 if self.embed:
95 91 super(Audio, self).reload()
96 92
97 93 if self.filename is not None:
98 94 self.mimetype = mimetypes.guess_type(self.filename)[0]
99 95 elif self.url is not None:
100 96 self.mimetype = mimetypes.guess_type(self.url)[0]
101 97 else:
102 98 self.mimetype = "audio/wav"
103 99
104 100
105 101 def _make_wav(self,data,rate):
106 102 """ Transform a numpy array to a PCM bytestring """
103 import struct
104 from io import BytesIO
105 import wave
107 106 maxabsvalue = max(map(abs,data))
108 107 scaled = map(lambda x: int(x/maxabsvalue*32767), data)
109 108 fp = BytesIO()
110 109 waveobj = wave.open(fp,mode='wb')
111 110 waveobj.setnchannels(1)
112 111 waveobj.setframerate(rate)
113 112 waveobj.setsampwidth(2)
114 113 waveobj.setcomptype('NONE','NONE')
115 114 waveobj.writeframes(b''.join([struct.pack('<h',x) for x in scaled]))
116 115 val = fp.getvalue()
117 116 waveobj.close()
118 117 return val
119 118
120 119 def _data_and_metadata(self):
121 120 """shortcut for returning metadata with url information, if defined"""
122 121 md = {}
123 122 if self.url:
124 123 md['url'] = self.url
125 124 if md:
126 125 return self.data, md
127 126 else:
128 127 return self.data
129 128
130 129 def _repr_html_(self):
131 130 src = """
132 131 <audio controls="controls" {autoplay}>
133 132 <source src="{src}" type="{type}" />
134 133 Your browser does not support the audio element.
135 134 </audio>
136 135 """
137 136 return src.format(src=self.src_attr(),type=self.mimetype, autoplay=self.autoplay_attr())
138 137
139 138 def src_attr(self):
139 import base64
140 140 if self.embed and (self.data is not None):
141 141 return """data:{type};base64,{base64}""".format(type=self.mimetype, base64=base64.encodestring(self.data))
142 142 elif self.url is not None:
143 143 return self.url
144 144 else:
145 145 return ""
146 146
147 147 def autoplay_attr(self):
148 148 if(self.autoplay):
149 149 return 'autoplay="autoplay"'
150 150 else:
151 151 return ''
152 152
153 153 class IFrame(object):
154 154 """
155 155 Generic class to embed an iframe in an IPython notebook
156 156 """
157 157
158 158 iframe = """
159 159 <iframe
160 160 width="{width}"
161 161 height={height}"
162 162 src="{src}{params}"
163 163 frameborder="0"
164 164 allowfullscreen
165 165 ></iframe>
166 166 """
167 167
168 168 def __init__(self, src, width, height, **kwargs):
169 169 self.src = src
170 170 self.width = width
171 171 self.height = height
172 172 self.params = kwargs
173 173
174 174 def _repr_html_(self):
175 175 """return the embed iframe"""
176 176 if self.params:
177 177 from urllib import urlencode
178 178 params = "?" + urlencode(self.params)
179 179 else:
180 180 params = ""
181 181 return self.iframe.format(src=self.src,
182 182 width=self.width,
183 183 height=self.height,
184 184 params=params)
185 185
186 186 class YouTubeVideo(IFrame):
187 187 """Class for embedding a YouTube Video in an IPython session, based on its video id.
188 188
189 189 e.g. to embed the video on this page:
190 190
191 191 http://www.youtube.com/watch?v=foo
192 192
193 193 you would do:
194 194
195 195 vid = YouTubeVideo("foo")
196 196 display(vid)
197 197
198 198 To start from 30 seconds:
199 199
200 200 vid = YouTubeVideo("abc", start=30)
201 201 display(vid)
202 202
203 203 To calculate seconds from time as hours, minutes, seconds use:
204 204 start=int(timedelta(hours=1, minutes=46, seconds=40).total_seconds())
205 205
206 206 Other parameters can be provided as documented at
207 207 https://developers.google.com/youtube/player_parameters#parameter-subheader
208 208 """
209 209
210 210 def __init__(self, id, width=400, height=300, **kwargs):
211 211 src = "http://www.youtube.com/embed/{0}".format(id)
212 212 super(YouTubeVideo, self).__init__(src, width, height, **kwargs)
213 213
214 214 class VimeoVideo(IFrame):
215 215 """
216 216 Class for embedding a Vimeo video in an IPython session, based on its video id.
217 217 """
218 218
219 219 def __init__(self, id, width=400, height=300, **kwargs):
220 220 src="http://player.vimeo.com/video/{0}".format(id)
221 221 super(VimeoVideo, self).__init__(src, width, height, **kwargs)
222 222
223 223 class ScribdDocument(IFrame):
224 224 """
225 225 Class for embedding a Scribd document in an IPython session
226 226
227 227 Use the start_page params to specify a starting point in the document
228 228 Use the view_mode params to specify display type one off scroll | slideshow | book
229 229
230 230 e.g to Display Wes' foundational paper about PANDAS in book mode from page 3
231 231
232 232 ScribdDocument(71048089, width=800, height=400, start_page=3, view_mode="book")
233 233 """
234 234
235 235 def __init__(self, id, width=400, height=300, **kwargs):
236 236 src="http://www.scribd.com/embeds/{0}/content".format(id)
237 237 super(ScribdDocument, self).__init__(src, width, height, **kwargs)
238 238
239 239 class FileLink(object):
240 240 """Class for embedding a local file link in an IPython session, based on path
241 241
242 242 e.g. to embed a link that was generated in the IPython notebook as my/data.txt
243 243
244 244 you would do::
245 245
246 246 local_file = FileLink("my/data.txt")
247 247 display(local_file)
248 248
249 249 or in the HTML notebook, just::
250 250
251 251 FileLink("my/data.txt")
252 252 """
253 253
254 254 html_link_str = "<a href='%s' target='_blank'>%s</a>"
255 255
256 256 def __init__(self,
257 257 path,
258 258 url_prefix='files/',
259 259 result_html_prefix='',
260 260 result_html_suffix='<br>'):
261 261 """
262 262 Parameters
263 263 ----------
264 264 path : str
265 265 path to the file or directory that should be formatted
266 266 directory_prefix : str
267 267 prefix to be prepended to all files to form a working link [default:
268 268 'files']
269 269 result_html_prefix : str
270 270 text to append to beginning to link [default: none]
271 271 result_html_suffix : str
272 272 text to append at the end of link [default: '<br>']
273 273 """
274 274 if isdir(path):
275 275 raise ValueError,\
276 276 ("Cannot display a directory using FileLink. "
277 277 "Use FileLinks to display '%s'." % path)
278 278 self.path = path
279 279 self.url_prefix = url_prefix
280 280 self.result_html_prefix = result_html_prefix
281 281 self.result_html_suffix = result_html_suffix
282 282
283 283 def _format_path(self):
284 284 fp = ''.join([self.url_prefix,self.path])
285 285 return ''.join([self.result_html_prefix,
286 286 self.html_link_str % (fp, self.path),
287 287 self.result_html_suffix])
288 288
289 289 def _repr_html_(self):
290 290 """return html link to file
291 291 """
292 292 if not exists(self.path):
293 293 return ("Path (<tt>%s</tt>) doesn't exist. "
294 294 "It may still be in the process of "
295 295 "being generated, or you may have the "
296 296 "incorrect path." % self.path)
297 297
298 298 return self._format_path()
299 299
300 300 def __repr__(self):
301 301 """return absolute path to file
302 302 """
303 303 return abspath(self.path)
304 304
305 305 class FileLinks(FileLink):
306 306 """Class for embedding local file links in an IPython session, based on path
307 307
308 308 e.g. to embed links to files that were generated in the IPython notebook under my/data
309 309
310 310 you would do:
311 311
312 312 local_files = FileLinks("my/data")
313 313 display(local_files)
314 314
315 315 or in the HTML notebook, just
316 316
317 317 FileLinks("my/data")
318 318
319 319 """
320 320 def __init__(self,
321 321 path,
322 322 url_prefix='files/',
323 323 included_suffixes=None,
324 324 result_html_prefix='',
325 325 result_html_suffix='<br>',
326 326 notebook_display_formatter=None,
327 327 terminal_display_formatter=None):
328 328 """
329 329 included_suffixes : list of filename suffixes to include when
330 330 formatting output [default: include all files]
331 331
332 332 See the FileLink (baseclass of LocalDirectory) docstring for
333 333 information on additional parameters.
334 334
335 335 notebook_display_formatter : func used to format links for display
336 336 in the notebook. See discussion of formatter function below.
337 337
338 338 terminal_display_formatter : func used to format links for display
339 339 in the terminal. See discussion of formatter function below.
340 340
341 341
342 342 Passing custom formatter functions
343 343 ----------------------------------
344 344 Formatter functions must be of the form:
345 345 f(dirname, fnames, included_suffixes)
346 346 dirname : the name of a directory (a string),
347 347 fnames : a list of the files in that directory
348 348 included_suffixes : a list of the file suffixes that should be
349 349 included in the output (passing None means
350 350 to include all suffixes in the output in
351 351 the built-in formatters)
352 352
353 353 returns a list of lines that should will be print in the
354 354 notebook (if passing notebook_display_formatter) or the terminal
355 355 (if passing terminal_display_formatter). This function is iterated
356 356 over for each directory in self.path. Default formatters are in
357 357 place, can be passed here to support alternative formatting.
358 358
359 359 """
360 360 if isfile(path):
361 361 raise ValueError,\
362 362 ("Cannot display a file using FileLinks. "
363 363 "Use FileLink to display '%s'." % path)
364 364 self.included_suffixes = included_suffixes
365 365 # remove trailing slashs for more consistent output formatting
366 366 path = path.rstrip('/')
367 367
368 368 self.path = path
369 369 self.url_prefix = url_prefix
370 370 self.result_html_prefix = result_html_prefix
371 371 self.result_html_suffix = result_html_suffix
372 372
373 373 self.notebook_display_formatter = \
374 374 notebook_display_formatter or self._get_notebook_display_formatter()
375 375 self.terminal_display_formatter = \
376 376 terminal_display_formatter or self._get_terminal_display_formatter()
377 377
378 378 def _get_display_formatter(self,
379 379 dirname_output_format,
380 380 fname_output_format,
381 381 fp_format,
382 382 fp_cleaner=None):
383 383 """ generate built-in formatter function
384 384
385 385 this is used to define both the notebook and terminal built-in
386 386 formatters as they only differ by some wrapper text for each entry
387 387
388 388 dirname_output_format: string to use for formatting directory
389 389 names, dirname will be substituted for a single "%s" which
390 390 must appear in this string
391 391 fname_output_format: string to use for formatting file names,
392 392 if a single "%s" appears in the string, fname will be substituted
393 393 if two "%s" appear in the string, the path to fname will be
394 394 substituted for the first and fname will be substituted for the
395 395 second
396 396 fp_format: string to use for formatting filepaths, must contain
397 397 exactly two "%s" and the dirname will be subsituted for the first
398 398 and fname will be substituted for the second
399 399 """
400 400 def f(dirname, fnames, included_suffixes=None):
401 401 result = []
402 402 # begin by figuring out which filenames, if any,
403 403 # are going to be displayed
404 404 display_fnames = []
405 405 for fname in fnames:
406 406 if (isfile(join(dirname,fname)) and
407 407 (included_suffixes == None or
408 408 splitext(fname)[1] in included_suffixes)):
409 409 display_fnames.append(fname)
410 410
411 411 if len(display_fnames) == 0:
412 412 # if there are no filenames to display, don't print anything
413 413 # (not even the directory name)
414 414 pass
415 415 else:
416 416 # otherwise print the formatted directory name followed by
417 417 # the formatted filenames
418 418 dirname_output_line = dirname_output_format % dirname
419 419 result.append(dirname_output_line)
420 420 for fname in display_fnames:
421 421 fp = fp_format % (dirname,fname)
422 422 if fp_cleaner is not None:
423 423 fp = fp_cleaner(fp)
424 424 try:
425 425 # output can include both a filepath and a filename...
426 426 fname_output_line = fname_output_format % (fp, fname)
427 427 except TypeError:
428 428 # ... or just a single filepath
429 429 fname_output_line = fname_output_format % fname
430 430 result.append(fname_output_line)
431 431 return result
432 432 return f
433 433
434 434 def _get_notebook_display_formatter(self,
435 435 spacer="&nbsp;&nbsp;"):
436 436 """ generate function to use for notebook formatting
437 437 """
438 438 dirname_output_format = \
439 439 self.result_html_prefix + "%s/" + self.result_html_suffix
440 440 fname_output_format = \
441 441 self.result_html_prefix + spacer + self.html_link_str + self.result_html_suffix
442 442 fp_format = self.url_prefix + '%s/%s'
443 443 if sep == "\\":
444 444 # Working on a platform where the path separator is "\", so
445 445 # must convert these to "/" for generating a URI
446 446 def fp_cleaner(fp):
447 447 # Replace all occurences of backslash ("\") with a forward
448 448 # slash ("/") - this is necessary on windows when a path is
449 449 # provided as input, but we must link to a URI
450 450 return fp.replace('\\','/')
451 451 else:
452 452 fp_cleaner = None
453 453
454 454 return self._get_display_formatter(dirname_output_format,
455 455 fname_output_format,
456 456 fp_format,
457 457 fp_cleaner)
458 458
459 459 def _get_terminal_display_formatter(self,
460 460 spacer=" "):
461 461 """ generate function to use for terminal formatting
462 462 """
463 463 dirname_output_format = "%s/"
464 464 fname_output_format = spacer + "%s"
465 465 fp_format = '%s/%s'
466 466
467 467 return self._get_display_formatter(dirname_output_format,
468 468 fname_output_format,
469 469 fp_format)
470 470
471 471 def _format_path(self):
472 472 result_lines = []
473 473 walked_dir = list(walk(self.path))
474 474 walked_dir.sort()
475 475 for dirname, subdirs, fnames in walked_dir:
476 476 result_lines += self.notebook_display_formatter(dirname, fnames, self.included_suffixes)
477 477 return '\n'.join(result_lines)
478 478
479 479 def __repr__(self):
480 480 """return newline-separated absolute paths
481 481 """
482 482 result_lines = []
483 483 walked_dir = list(walk(self.path))
484 484 walked_dir.sort()
485 485 for dirname, subdirs, fnames in walked_dir:
486 486 result_lines += self.terminal_display_formatter(dirname, fnames, self.included_suffixes)
487 487 return '\n'.join(result_lines)
General Comments 0
You need to be logged in to leave comments. Login now