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