Skip to main content

Introduction

  • Chapter
  • First Online:
Book cover Python for Signal Processing
  • 11k Accesses

Abstract

Python went mainstream years ago. It is well-established in web programming and is the platform for high-traffic sites like YouTube. Less well known is Python for scientific applications, what we are calling “Scientific Python” here. Scientific Python has been used in government, academia, and industry for at least a decade. NASA’s Jet Propulsion Laboratory uses it for interfacing Fortran/C++ libraries for planning and visualization of spacecraft trajectories. The Lawrence Livermore National Laboratory uses scientific Python for a wide variety of computing tasks, some involving routine text processing, and others involving advanced visualization of vast data sets (e.g. VISIT [CBB+05]). Shell Research, Boeing, Industrial Light and Magic, Sony Entertainment, and Procter & Gamble use scientific Python on a daily basis for similar tasks. Python is well-established and continues to extend into many different fields.

This is a preview of subscription content, log in via an institution to check access.

Access this chapter

Chapter
USD 29.95
Price excludes VAT (USA)
  • Available as PDF
  • Read on any device
  • Instant download
  • Own it forever
eBook
USD 84.99
Price excludes VAT (USA)
  • Available as EPUB and PDF
  • Read on any device
  • Instant download
  • Own it forever
Softcover Book
USD 109.99
Price excludes VAT (USA)
  • Compact, lightweight edition
  • Dispatched in 3 to 5 business days
  • Free shipping worldwide - see info
Hardcover Book
USD 159.99
Price excludes VAT (USA)
  • Durable hardcover edition
  • Dispatched in 3 to 5 business days
  • Free shipping worldwide - see info

Tax calculation will be finalised at checkout

Purchases are for personal use only

Institutional subscriptions

Notes

  1. 1.

    See arrayobject.h

References

  1. H. Childs, E.S. Brugger, K.S. Bonnell, J.S. Meredith, M. Miller, B.J. Whitlock, N. Max, A contract-based system for large data visualization, in Proceedings of IEEE Visualization 2005, Minneapolis, 2005, pp. 190–198

    Google Scholar 

  2. H.P. Langtangen, Python Scripting for Computational Science, vol. 3 (Springer, Berlin, 2009)

    Google Scholar 

  3. T.E. Oliphant, A Guide to Numpy, vol. 1 (Trelgol Publishing, USA, 2006)

    Google Scholar 

Download references

Author information

Authors and Affiliations

Authors

Appendix

Appendix

Listing 1.1: Line 1 imports Numpy as np, which is the recommended convention. The next line creates an array of 32 bit floating point numbers. The itemize property shows the number of bytes per item.

1 >>> import numpy as np # recommended convention

2 >>> x = np.array([1,1,1],dtype=np.float32)

3 >>> x

4 array([ 1.,  1.,  1.], dtype=float32)

5 >>> x.itemsize

6 4

Listing 1.2: This computes the sine of the input array of all ones, using Numpy’s unary function, np.sin. There is another sine function in the built-in math module, but the Numpy version is faster because it does not require explicit looping (i.e. using a for loop) over each of the elements in the array. That looping happens in np.sin function itself.

1 >>> np.sin(np.array([1,1,1],dtype=np.float32) )

2 array([ 0.84147096,  0.84147096,  0.84147096], dtype=float32)

Listing 1.3: Numpy arrays can have different shapes and number of dimensions.

1 >>> x=np.array([ [1,2,3],[4,5,6] ])

2 >>> x.shape

3 (2, 3)

Listing 1.4: Numpy slicing rules extend Python’s natural slicing syntax. Note the colon “:” character selects all elements in the corresponding row or column.

1 >>> x=np.array([ [1,2,3],[4,5,6] ])

2 >>> x[:,0] # 0th column

3 array([1, 4])

4 >>> x[:,1] # 1st column

5 array([2, 5])

6 >>> x[0,:] # 0th row

7 array([1, 2, 3])

8 >>> x[1,:] # 1st row

9 array([4, 5, 6])

Listing 1.5: Numpy slicing can select sections of an array as shown.

 1 >>> x=np.array([ [1,2,3],[4,5,6] ])

 2 >>> x

 3 array([[1, 2, 3],

 4        [4, 5, 6]])

 5 >>> x[:,1:] # all rows, 1st thru last column

 6 array([[2, 3],

 7        [5, 6]])

 8 >>> x[:,::2] # all rows, every other column

 9 array([[1, 3],

10        [4, 6]])

Listing 1.6: MATLAB employs pass-by-value semantics meaning that slice operations like this automatically generate copies.

 >> x=ones(3,3)

x =

     1     1     1

     1     1     1

     1     1     1

>> x(:,4)=ones(3,1) % tack on extra dimension

x =

     1     1     1     1

     1     1     1     1

     1     1     1     1

>> size(x)

ans =

     3     4

Listing 1.7: In contrast with MATLAB, Numpy uses pass-by-reference semantics so it creates views into the existing array, without implicit copying. This is particularly helpful with very large arrays because copying can be slow.

 1 >>> x = np.ones((3,3))

 2 >>> x

 3 array([[ 1.,  1.,  1.],

 4        [ 1.,  1.,  1.],

 5        [ 1.,  1.,  1.]])

 6 >>> x[:,[0,1,2,2]] # notice duplicated last dimension

 7 array([[ 1.,  1.,  1.,  1.],

 8        [ 1.,  1.,  1.,  1.],

 9        [ 1.,  1.,  1.,  1.]])

10 >>> y=x[:,[0,1,2,2]] # same as above, but do assign it

Listing 1.8: Because we made a copy in Listing 1.7, changing the individual elements of x does not affect y.

1 >>> x[0,0]=999 # change element in x

2 >>> x                         # changed

3 array([[ 999.,    1.,    1.],

4        [   1.,    1.,    1.],

5        [   1.,    1.,    1.]])

6 >>> y                         # not changed!

7 array([[ 1.,  1.,  1.,  1.],

8        [ 1.,  1.,  1.,  1.],

9        [ 1.,  1.,  1.,  1.]])

Listing 1.9: As a consequence of the pass-by-reference semantics, Numpy views point at the same memory as their parents, so changing an element in x updates the corresponding element in y. This is because a view is just a window into the same memory.

 1 >>> x = np.ones((3,3))

 2 >>> y = x[:2,:2] # upper left piece

 3 >>> x[0,0] = 999 # change value

 4 >>> x

 5 array([[ 999.,    1.,    1.], # see the change?

 6        [   1.,    1.,    1.],

 7        [   1.,    1.,    1.]])

 8 >>> y

 9 array([[ 999.,    1.], # changed y also!

10        [   1.,    1.]])

Listing 1.10: Indexing can also create copies as we saw before in Listing 1.7. Here, y is a copy, not a view, because it was created using indexing whereas z was created using slicing. Thus, even though y and z have the same entries, only z is affected by changes to x.

 1 >>> x = np.arange(5) # create array

 2 >>> x

 3 array([0, 1, 2, 3, 4])

 4 >>> y=x[[0,1,2]] # index by integer list

 5 >>> y

 6 array([0, 1, 2])

 7 >>> z=x[:3]      # slice

 8 >>> z            # note y and z have same entries?

 9 array([0, 1, 2])

10 >>> x[0]=999     # change element of x

11 >>> x

12 array([999,   1,   2,   3,   4])

13 >>> y            # note y is unaffected,

14 array([0, 1, 2])

15 >>> z            # but z is (it’s a view).

16 array([999,   1,   2])

Listing 1.11: Numpy arrays have a built-in flags.owndata property that can help keep track of views until you get the hang of them.

1 >>> x.flags.owndata

2 True

3 >>> y.flags.owndata

4 True

5 >>> z.flags.owndata # as a view, z does not own the data!

6 False

Listing 1.12: Numpy arrays support elementwise multiplication, not row-column multiplication. You must use Numpy matrices for this kind of multiplication.

1 >>> import numpy as np

2 >>> A=np.matrix([[1,2,3],[4,5,6],[7,8,9]])

3 >>> x=np.matrix([[1],[0],[0]])

4 >>> A*x

5 matrix([[1],

6         [4],

7         [7]])

Listing 1.13: It is easy and fast to convert between Numpy arrays and matrices because doing so need not imply any memory copying (recall the pass-by-value semantics). In the last line, we did not have to bother converting x because the left-to-right evaluation automatically handles that.

 1 >>> A=np.ones((3,3))

 2 >>> type(A) # array not matrix

 3 <type ’numpy.ndarray’>

 4 >>> x=np.ones((3,1)) # array not matrix

 5 >>> A*x

 6 array([[ 1.,  1.,  1.],

 7        [ 1.,  1.,  1.],

 8        [ 1.,  1.,  1.]])

 9 >>> np.matrix(A)*x # row-column multiplication

10 matrix([[ 3.],

11         [ 3.],

12         [ 3.]])

Listing 1.14: Numpy’s meshgrid creates two-dimensional grids.

1 >>> X,Y=np.meshgrid(np.arange(2),np.arange(2))

2 >>> X

3 array([[0, 1],

4        [0, 1]])

5 >>> Y

6 array([[0, 0],

7        [1, 1]])

Listing 1.15: Because the two arrays have compatible shapes, they can be added together element-wise.

1 >>> X+Y

2 array([[0, 1],

3        [1, 2]])

Listing 1.16: Using Numpy broadcasting, we can skip creating compatible arrays using meshgrid and instead accomplish the same thing automatically by using the None singleton to inject an additional compatible dimension.

 1 >>> x = np.array([0,1])

 2 >>> y = np.array([0,1])

 3 >>> x

 4 array([0, 1])

 5 >>> y

 6 array([0, 1])

 7 >>> x + y[:,None] # add broadcast dimension

 8 array([[0, 1],

 9        [1, 2]])

10 >>> X+Y

11 array([[0, 1],

12        [1, 2]])

Listing 1.17: In this example, the array shapes are different, so the addition of x and y is not possible without Numpy broadcasting. The last line shows that broadcasting generates the same output as using the compatible array generated by meshgrid.

 1 >>> x = np.array([0,1])

 2 >>> y = np.array([0,1,2])

 3 >>> X,Y = np.meshgrid(x,y)

 4 >>> X

 5 array([[0, 1], # duplicate by row

 6        [0, 1],

 7        [0, 1]])

 8 >>> Y

 9 array([[0, 0], # duplicate by column

10        [1, 1],

11        [2, 2]])

12 >>> X+Y

13 array([[0, 1],

14        [1, 2],

15        [2, 3]])

16 >>> x+y[:,None] # same as w/ meshgrid

17 array([[0, 1],

18        [1, 2],

19        [2, 3]])

Listing 1.18: Numpy broadcasting also works in multiple dimensions. We start here with three one-dimensional arrays and create a three-dimensional output using broadcasting. The x+y[:None] part creates a conforming two-dimensional array as in Listing 1.17, and due to the left-to-right evaluation order, this two-dimensional intermediate product is broadcast against the z variable, whose two None dimensions create an output three-dimensional array.

 1 >>> x = np.array([0,1])

 2 >>> y = np.array([0,1,2])

 3 >>> z = np.array([0,1,2,3])

 4 >>> x+y[:,None]+z[:,None,None]

 5 array([[[0, 1],

 6         [1, 2],

 7         [2, 3]],

 8        [[1, 2],

 9         [2, 3],

10         [3, 4]],

11        [[2, 3],

12         [3, 4],

13         [4, 5]],

14        [[3, 4],

15         [4, 5],

16         [5, 6]]])

Listing 1.19: The first line imports the Matplotlib module following the recommended naming convention. The next plots a range of numbers. The last line actually forces the plot to render. Because this example assumes you are in the plain Python interpreter, this last step is necessary. Otherwise, IPython (discussed later) makes this step unnecessary.

1 >>> import matplotlib.pyplot as plt

2 >>> plt.plot(range(10))

3 [<matplotlib.lines.Line2D object at 0x00CB9770>]

4 >>> plt.show() # unnecessary in IPython (discussed later)

Rights and permissions

Reprints and permissions

Copyright information

© 2014 Springer International Publishing Switzerland

About this chapter

Cite this chapter

Unpingco, J. (2014). Introduction. In: Python for Signal Processing. Springer, Cham. https://doi.org/10.1007/978-3-319-01342-8_1

Download citation

  • DOI: https://doi.org/10.1007/978-3-319-01342-8_1

  • Published:

  • Publisher Name: Springer, Cham

  • Print ISBN: 978-3-319-01341-1

  • Online ISBN: 978-3-319-01342-8

  • eBook Packages: EngineeringEngineering (R0)

Publish with us

Policies and ethics