diff options
author | Hardik Ghaghada | 2014-06-12 13:22:13 +0530 |
---|---|---|
committer | Hardik Ghaghada | 2014-06-12 13:22:13 +0530 |
commit | 1f7318ca9553270899537d98d75e9f4fced85ed4 (patch) | |
tree | 7d149f9203f7eb122e749696e570d10086275ce4 /lecture-notes/advanced-python | |
parent | 985adfa4f8a8b9cfba2b0a573dadc77283651957 (diff) | |
download | sees-1f7318ca9553270899537d98d75e9f4fced85ed4.tar.gz sees-1f7318ca9553270899537d98d75e9f4fced85ed4.tar.bz2 sees-1f7318ca9553270899537d98d75e9f4fced85ed4.zip |
restructring repo
Diffstat (limited to 'lecture-notes/advanced-python')
47 files changed, 6482 insertions, 0 deletions
diff --git a/lecture-notes/advanced-python/advanced_py.tex b/lecture-notes/advanced-python/advanced_py.tex new file mode 100644 index 0000000..b15419e --- /dev/null +++ b/lecture-notes/advanced-python/advanced_py.tex @@ -0,0 +1,53 @@ +\documentclass[12pt,presentation]{beamer} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{fixltx2e} +\usepackage{graphicx} +\usepackage{longtable} +\usepackage{float} +\usepackage{wrapfig} +\usepackage{soul} +\usepackage{textcomp} +\usepackage{marvosym} +\usepackage{wasysym} +\usepackage{latexsym} +\usepackage{amssymb} +\usepackage{hyperref} +\tolerance=1000 +\usepackage[english]{babel} \usepackage{ae,aecompl} +\usepackage{mathpazo,courier,euler} \usepackage[scaled=.95]{helvet} +\usepackage{listings} +\lstset{language=Python, basicstyle=\ttfamily\bfseries, +commentstyle=\color{red}\itshape, stringstyle=\color{green}, +showstringspaces=false, keywordstyle=\color{blue}\bfseries} +\providecommand{\alert}[1]{\textbf{#1}} + +\title{Advanced Python} +\author{FOSSEE} + +\usetheme{Warsaw}\usecolortheme{default}\useoutertheme{infolines}\setbeamercovered{transparent} + +\AtBeginSection[] +{ + \begin{frame}<beamer> + \frametitle{Outline} + \tableofcontents[currentsection] + \end{frame} +} + +\begin{document} + +\maketitle + +\begin{frame} +\frametitle{Outline} +\setcounter{tocdepth}{3} +\tableofcontents +\end{frame} + +\include{slides/plotting} +\include{slides/arrays} +\include{slides/scipy} +\include{slides/modules} + +\end{document} diff --git a/lecture-notes/advanced-python/arrays.rst b/lecture-notes/advanced-python/arrays.rst new file mode 100644 index 0000000..d5699ce --- /dev/null +++ b/lecture-notes/advanced-python/arrays.rst @@ -0,0 +1,736 @@ +Arrays +====== + +In this section, we shall learn about a very powerful data structure, +specially useful for scientific computations, the array. We shall look at +initialization of arrays, operations on arrays and a brief comparison with +lists. + +Arrays are homogeneous data structures, unlike lists which can be +heterogeneous. They can have only one type of data as their entries. + +Arrays of a given length are comparatively much faster in mathematical +operations than lists of the same length, because of the fact that they are +homogeneous. + +Now let us see how to create arrays. + +To create an array we will use the function ``array()``, + +:: + + a1 = array([1,2,3,4]) + +Notice that we created a one dimensional array here. Also notice that we +passed a list as an argument, to create the array. + +We create two dimensional array by converting a list of lists to an array + +:: + + a2 = array([[1,2,3,4],[5,6,7,8]]) + +A two dimensional array has been created by passing a list of lists to the +array function. + +Now let us use ``arange()`` function to create the same arrays as before. + +:: + + ar1 = arange(1, 5) + +The ``arange`` function is similar to the range function that we have already +looked at, in the basic Python section. + +To create the two dimensional array, we first obtain a 1D array with the +elements from 1 to 8 and then convert it to a 2D array. + +To obtain the 1D array, we use the ``arange`` function + +:: + ar2 = arange(1, 9) + print ar2 + +We use the shape method to change the shape of the array, into a 2D array. + +:: + + ar2.shape = 2, 4 + print ar2 + +This gives us the required array. + +Instead of passing a list to the array function, we could also pass a list +variable. For, instance + +:: + + l1 = [1,2,3,4] + a3 = array(l1) + +We used the shape method to change the shape of the array. But it can also +be used to find out the shape of an array that we have. + +:: + a1.shape + a2.shape + +As, already stated, arrays are homogeneous. Let us try to create a new +array with a mix of elements and see what happens. + +:: + + a4 = array([1,2,3,'a string']) + +We expect an error, but there wasn't one. What happened? Let's see what a4 +has. + +:: + + a4 + +There you go! The data type of the array has been set to a string of +length 8. All the elements have been implicitly type-casted as strings, +though our first three elements were meant to be integers. The dtype +specifies the data-type of the array. + +There some other special methods as well, to create special types of +arrays. We can create an 2 dimensional identity array, using the function +``identity()``. The function ``identity()`` takes an integer argument which +specifies the size of the diagonal of the array. + +:: + + identity(3) + +As you can see the identity function returned a three by three array, with +all the diagonal elements as ones and the rest of the elements as zeros. + +``zeros()`` function accepts a tuple, which is the shape of the array that +we want to create, and it generates an array with all elements as zeros. + +Let us creates an array of the order four by five with all the elements +zero. We can do it using the method zeros, :: + + zeros((4,5)) + +Notice that we passed a tuple to the function zeros. Similarly, ``ones()`` +gives us an array with all elements as ones. + +Also, ``zeros_like`` gives us an array with all elements as zeros, with a +shape similar to the array passed as the argument and the same data-type as +the argument array. + +:: + + a = zeros_like([1.5, 1, 2, 3] + print a, a.dtype + +Similarly, the function ``ones_like``. + +Let us try out some basic operations with arrays, before we end this +section. + +Let's check the value of a1, by typing it out on the interpreter. + +:: + + a1 + +``a1`` is a single dimensional array, array([1,2,3,4]). Now, try + +:: + + a1 * 2 + +We get back a new array, with all the elements multiplied by 2. Note that +the value of elements of ``a1`` remains the same. + +:: + + a1 + +Similarly we can perform addition or subtraction or division. + +:: + + a1 + 3 + a1 - 7 + a1 / 2.0 + +We can change the array, by simply assigning the newly returned array to +the old array. + +:: + + a1 = a1 + 2 + +Notice the change in elements of a1, + +:: + + a1 + +We could also do the augmented assignment, but there's a small nuance here. +For instance, + +:: + + a = arange(1, 5) + b = arange(1, 5) + + print a, a.dtype + print b, b.dtype + + a = a/2.0 + b /= 2.0 + + print a, a.dtype + print b, b.dtype + +As you can see, ``b`` doesn't have the expected result because the +augmented assignment that we are doing, is an inplace operation. Given that +arrays are optimized to be very fast, by fixing their datatype and hence +the amount of memory they can occupy, the division by a float, when +performed inplace, fails to change the dtype of the array. So, be cautious, +when using in-place assignments. + +Now let us try operations between two arrays. + +:: + + a1 + a1 + a1 * a2 + +Note that both the addition and the multiplication are element-wise. + +Accessing pieces of arrays +========================== + +Now, that we know how to create arrays, let's see how to access individual +elements of arrays, get rows and columns and other chunks of arrays using +slicing and striding. + +Let us have two arrays, A and C, as the sample arrays that we will use to +learn how to access parts of arrays. + +:: + + A = array([12, 23, 34, 45, 56]) + + C = array([[11, 12, 13, 14, 15], + [21, 22, 23, 24, 25], + [31, 32, 33, 34, 35], + [41, 42, 43, 44, 45], + [51, 52, 53, 54, 55]]) + +Let us begin with the most elementary thing, accessing individual elements. +Also, let us first do it with the one-dimensional array A, and then do the +same thing with the two-dimensional array. + +To access, the element 34 in A, we say, + +:: + + A[2] + +A of 2, note that we are using square brackets. + +Like lists, indexing starts from 0 in arrays, too. So, 34, the third +element has the index 2. + +Now, let us access the element 34 from C. To do this, we say + +:: + + C[2, 3] + +C of 2,3. + +34 is in the third row and the fourth column, and since indexing begins +from zero, the row index is 2 and column index is 3. + +Now, that we have accessed one element of the array, let us change it. We +shall change the 34 to -34 in both A and C. To do this, we simply assign +the new value after accessing the element. + +:: + + A[2] = -34 + C[2, 3] = -34 + +Now that we have accessed and changed a single element, let us access and +change more than one element at a time; first rows and then columns. + +Let us access one row of C, say the third row. We do it by saying, + +:: + + C[2] + +How do we access the last row of C? We could say, + +:: + + C[4] + +for the fifth row, or as with lists, use negative indexing and say + +:: + + C[-1] + +Now, we could change the last row into all zeros, using either + +:: + + C[-1] = [0, 0, 0, 0, 0] + +or + +:: + + C[-1] = 0 + +Now, how do we access one column of C? As with accessing individual +elements, the column is the second parameter to be specified (after the +comma). The first parameter, is replaced with a ``:``. This specifies that +we want all the elements of that dimension, instead of just one particular +element. We access the third column by + +:: + + C[:, 2] + +So, we can change the last column of C to zeroes, by + +:: + + C[:, -1] = 0 + +Since A is one dimensional, rows and columns of A don't make much sense. It +has just one row and + +:: + + A[:] + +gives the whole of A. + +Now, that we know how to access, rows and columns of an array, we shall +learn how to access other, larger pieces of an array. For this purpose, we +will be using image arrays. + +To read an image into an array, we use the ``imread`` command. We shall use +the image ``squares.png``. We shall first navigate to that path in the OS +and see what the image contains. + +Let us now read the data in ``squares.png`` into the array ``I``. + +:: + + I = imread('squares.png') + +We can see the contents of the image, using the command ``imshow``. We say, + +:: + + imshow(I) + +to see what has been read into ``I``. We do not see white and black +because, ``pylab`` has mapped white and black to different colors. This can +be changed by using a different colormap. + +To see that ``I`` is really, just an array, we say, + +:: + + I + +at the prompt, and see that an array is displayed. + +To check the dimensions of any array, we can use ``.shape``. We say + +:: + + I.shape + +to get the dimensions of the image. As we can see, ``squares.png`` has the +dimensions of 300x300. + +Our goal for now, is be to get the top-left quadrant of the image. To do +this, we need to access, a few of the rows and a few of the columns of the +array. + +To access, the third column of C, we said, ``C[:, 2]``. Essentially, we are +accessing all the rows in column three of C. Now, let us modify this to +access only the first three rows, of column three of C. +We say, + +:: + + C[0:3, 2] + +to get the elements of rows indexed from 0 to 3, 3 not included and column +indexed 2. Note that, the index before the colon is included and the index +after it is not included in the slice that we have obtained. This is very +similar to the ``range`` function, where ``range`` returns a list, in which +the upper limit or stop value is not included. + +Now, if we wish to access the elements of row with index 2, and in +columns indexed 0 to 2 (included), we say, + +:: + + C[2, 0:3] + +Note that when specifying ranges, if you are starting from the beginning or +going up-to the end, the corresponding element may be dropped. + +:: + + C[2, :3] + +also gives us the same elements, [31, 32, 33] + +Now, we are ready to obtain the top left quarter of the image. How do we go +about doing it? Since, we know the shape of the image to be 300, we know +that we need to get the first 150 rows and first 150 columns. + +:: + + I[:150, :150] + +gives us the top-left corner of the image. + +We use the ``imshow`` command to see the slice we obtained in the +form of an image and confirm. + +:: + + imshow(I[:150, :150]) + +How would we obtain the square in the center of the image? + +:: + + imshow(I[75:225, 75:225]) + +Our next goal is to compress the image, using a very simple technique to +reduce the space that the image takes on disk while not compromising too +heavily on the image quality. The idea is to drop alternate rows and +columns of the image and save it. This way we will be reducing the data to +a fourth of the original data but losing only so much of visual +information. + +We shall first learn the idea of striding using the smaller array C. +Suppose we wish to access only the odd rows and columns (first, third, +fifth). We do this by, + +:: + + C[0:5:2, 0:5:2] + +if we wish to be explicit, or simply, +:: + + C[::2, ::2] + +This is very similar to the step specified to the ``range`` function. It +specifies, the jump or step in which to move, while accessing the elements. +If no step is specified, a default value of 1 is assumed. + +:: + + C[1::2, ::2] + +gives the elements, [[21, 23, 0], [41, 43, 0]] + +Now, that we know how to stride over an array, we can drop alternate rows +and columns out of the image in I. + +:: + + I[::2, ::2] + +To see this image, we say, +:: + + imshow(I[::2, ::2]) + +This does not have much data to notice any real difference, but notice that +the scale has reduced to show that we have dropped alternate rows and +columns. If you notice carefully, you will be able to observe some blurring +near the edges. To notice this effect more clearly, increase the step to 4. + +:: + + imshow(I[::4, ::4]) + +That brings us to our discussion on accessing pieces of arrays. We shall +look at matrices, next. + +Matrices +======== + +In this course, we shall perform all matrix operations using the array +data-structure. We shall create a 2D array and treat it as a matrix. + +:: + + m1 = array([[1,2,3,4]]) + m1.shape + +As we already know, we can get a 2D array from a list of lists as well. + +:: + + l1 = [[1,2,3,4],[5,6,7,8]] + m2 = array(l1) + m3 = array([[5,6,7,8],[9,10,11,12]]) + +We can do matrix addition and subtraction as, + +:: + + m3 + m2 + +does element by element addition, thus matrix addition. + +Similarly, + +:: + + m3 - m2 + +it does matrix subtraction, that is element by element +subtraction. Now let us try, + +:: + + m3 * m2 + +Note that in arrays ``m3 * m2`` does element wise multiplication and not +matrix multiplication, + +And matrix multiplication in matrices are done using the function ``dot()`` + +:: + + dot(m3, m2) + +but for matrix multiplication, we need arrays of compatible sizes and hence +the multiplication fails, in this case. + +To see an example of matrix multiplication, we choose a proper pair. + +:: + + m1.shape + +m1 is of the shape one by four, let us create an array of the shape four by +two, + +:: + + m4 = array([[1,2],[3,4],[5,6],[7,8]]) + dot(m1, m4) + +Thus, the function ``dot()`` can be used for matrix multiplication. + +We have already seen the special functions like ``identity()``, +``zeros()``, ``ones()``, etc. to create special arrays. + +Let us now look at some Matrix specific operations. + +To find out the transpose, we use the ``.T`` method. + +:: + + print m4 + print m4.T + +Now let us try to find out the Frobenius norm of inverse of a 4 by 4 +matrix, the matrix being, + +:: + + m5 = arange(1,17).reshape(4,4) + print m5 + +The inverse of a matrix A, A raise to minus one is also called the +reciprocal matrix such that A multiplied by A inverse will give 1. + +:: + + im5 = inv(m5) + +The Frobenius norm of a matrix is defined as square root of sum of squares +of elements in the matrix. The Frobenius norm of ``im5`` can be found by, + +:: + + sqrt(sum(im5 * im5)) + +Now try to find out the infinity norm of the matrix im5. The infinity norm +is defined as the maximum value of sum of the absolute of elements in each +row. + +The solution for the problem is, + +:: + + max(sum(abs(im5), axis=1)) + +Well! to find the Frobenius norm and Infinity norm we have an even easier +method, and let us see that now. + +The norm of a matrix can be found out using the method ``norm()``. In order +to find out the Frobenius norm of the im5, we do, + +:: + + norm(im5) + +And to find out the Infinity norm of the matrix im5, we do, +:: + + norm(im5,ord=inf) + + +The determinant of a square matrix can be obtained using the function +``det()`` and the determinant of m5 by, + +:: + + det(m5) + +The eigen values and eigen vector of a square matrix can be computed +using the function ``eig()`` and ``eigvals()``. + +Let us find out the eigen values and eigen vectors of the matrix +m5. We can do it as, + +:: + + eig(m5) + + +Note that it returned a tuple of two matrices. The first element in +the tuple are the eigen values and the second element in the tuple are +the eigen vectors. Thus the eigen values are, +:: + + eig(m5)[0] + +and the eigen vectors are, + +:: + + eig(m5)[1] + +The eigen values can also be computed using the function ``eigvals()`` as, + +:: + + eigvals(m5) + + +We can also find the singular value decomposition or S V D of a matrix. + +The SVD of ``m5`` can be found by + +:: + + svd(m5) + +Notice that it returned a tuple of 3 elements. The first one U the +next one Sigma and the third one V star. + +That brings us to our discussion of matrices and operations on them. But we +shall continue to use them in the next section on Least square fit. + +Least square fit +================ + +First let us have a look at the problem. + +We have an input file generated from a simple pendulum experiment, which we +have already looked at. We shall find the least square fit of the plot +obtained by plotting l vs. t^2, where l is the length of the pendulum and t +is the corresponding time-period. + +:: + + l, t = loadtxt("/home/fossee/pendulum.txt", unpack=True) + l + t + +We can see that l and t are two sequences containing length and time values +correspondingly. + +Let us first plot l vs t^2. Type +:: + + tsq = t * t + plot(l, tsq, 'bo') + +We can see that there is a visible linear trend, but we do not get a +straight line connecting them. We shall, therefore, generate a least square +fit line. + +We are first going to generate the two matrices ``tsq`` and A, the vander +monde matrix. Then we are going to use the ``lstsq`` function to find the +values of m and c. + +Let us now generate the A matrix with l values. We shall first generate a 2 +x 90 matrix with the first row as l values and the second row as ones. Then +take the transpose of it. Type + +:: + + A = array((l, ones_like(l))) + A + +We see that we have intermediate matrix. Now we need the transpose. Type + +:: + + A = A.T + A + +Now we have both the matrices A and tsq. We only need to use the ``lstsq`` + +:: + + result = lstsq(A, tsq) + +The result is a sequence of values. The first item in this sequence, is the +matrix p i.e., the values of m and c. Hence, + +:: + + m, c = result[0] + m + c + +Now that we have m and c, we need to generate the fitted values of t^2. Type + +:: + + tsq_fit = m * l + c + plot(l, tsq, 'bo') + plot(l, tsq_fit, 'r') + +We get the least square fit of l vs t^2 + +That brings us to the end of our discussion on least square fit curve and +also our discussion of arrays. + +.. + Local Variables: + mode: rst + indent-tabs-mode: nil + sentence-end-double-space: nil + fill-column: 75 + End: diff --git a/lecture-notes/advanced-python/data/L-TSq-limited.png b/lecture-notes/advanced-python/data/L-TSq-limited.png Binary files differnew file mode 100644 index 0000000..c6e280e --- /dev/null +++ b/lecture-notes/advanced-python/data/L-TSq-limited.png diff --git a/lecture-notes/advanced-python/data/L-Tsq-Line.png b/lecture-notes/advanced-python/data/L-Tsq-Line.png Binary files differnew file mode 100644 index 0000000..5535eff --- /dev/null +++ b/lecture-notes/advanced-python/data/L-Tsq-Line.png diff --git a/lecture-notes/advanced-python/data/L-Tsq-points.png b/lecture-notes/advanced-python/data/L-Tsq-points.png Binary files differnew file mode 100644 index 0000000..3b8f2a3 --- /dev/null +++ b/lecture-notes/advanced-python/data/L-Tsq-points.png diff --git a/lecture-notes/advanced-python/data/L-Tsq.png b/lecture-notes/advanced-python/data/L-Tsq.png Binary files differnew file mode 100644 index 0000000..75f2c70 --- /dev/null +++ b/lecture-notes/advanced-python/data/L-Tsq.png diff --git a/lecture-notes/advanced-python/data/company-a-data.txt b/lecture-notes/advanced-python/data/company-a-data.txt new file mode 100644 index 0000000..06f4ca4 --- /dev/null +++ b/lecture-notes/advanced-python/data/company-a-data.txt @@ -0,0 +1,2 @@ +2.000000000000000000e+03 2.001000000000000000e+03 2.002000000000000000e+03 2.003000000000000000e+03 2.004000000000000000e+03 2.005000000000000000e+03 2.006000000000000000e+03 2.007000000000000000e+03 2.008000000000000000e+03 2.009000000000000000e+03 2.010000000000000000e+03 +2.300000000000000000e+01 5.500000000000000000e+01 3.200000000000000000e+01 6.500000000000000000e+01 8.800000000000000000e+01 5.000000000000000000e+00 1.400000000000000000e+01 6.700000000000000000e+01 2.300000000000000000e+01 2.300000000000000000e+01 1.200000000000000000e+01 diff --git a/lecture-notes/advanced-python/data/error-bar.png b/lecture-notes/advanced-python/data/error-bar.png Binary files differnew file mode 100644 index 0000000..cc1a454 --- /dev/null +++ b/lecture-notes/advanced-python/data/error-bar.png diff --git a/lecture-notes/advanced-python/data/least-sq-fit.png b/lecture-notes/advanced-python/data/least-sq-fit.png Binary files differnew file mode 100644 index 0000000..dba2afb --- /dev/null +++ b/lecture-notes/advanced-python/data/least-sq-fit.png diff --git a/lecture-notes/advanced-python/data/pendulum.txt b/lecture-notes/advanced-python/data/pendulum.txt new file mode 100644 index 0000000..01da9b8 --- /dev/null +++ b/lecture-notes/advanced-python/data/pendulum.txt @@ -0,0 +1,90 @@ +1.0000e-01 6.9004e-01 +1.1000e-01 6.9497e-01 +1.2000e-01 7.4252e-01 +1.3000e-01 7.5360e-01 +1.4000e-01 8.3568e-01 +1.5000e-01 8.6789e-01 +1.6000e-01 8.4182e-01 +1.7000e-01 8.5379e-01 +1.8000e-01 8.5762e-01 +1.9000e-01 8.8390e-01 +2.0000e-01 8.9985e-01 +2.1000e-01 9.8436e-01 +2.2000e-01 1.0244e+00 +2.3000e-01 1.0572e+00 +2.4000e-01 9.9077e-01 +2.5000e-01 1.0058e+00 +2.6000e-01 1.0727e+00 +2.7000e-01 1.0943e+00 +2.8000e-01 1.1432e+00 +2.9000e-01 1.1045e+00 +3.0000e-01 1.1867e+00 +3.1000e-01 1.1385e+00 +3.2000e-01 1.2245e+00 +3.3000e-01 1.2406e+00 +3.4000e-01 1.2071e+00 +3.5000e-01 1.2658e+00 +3.6000e-01 1.2995e+00 +3.7000e-01 1.3142e+00 +3.8000e-01 1.2663e+00 +3.9000e-01 1.2578e+00 +4.0000e-01 1.2991e+00 +4.1000e-01 1.3058e+00 +4.2000e-01 1.3478e+00 +4.3000e-01 1.3506e+00 +4.4000e-01 1.4044e+00 +4.5000e-01 1.3948e+00 +4.6000e-01 1.3800e+00 +4.7000e-01 1.4480e+00 +4.8000e-01 1.4168e+00 +4.9000e-01 1.4719e+00 +5.0000e-01 1.4656e+00 +5.1000e-01 1.4399e+00 +5.2000e-01 1.5174e+00 +5.3000e-01 1.4988e+00 +5.4000e-01 1.4751e+00 +5.5000e-01 1.5326e+00 +5.6000e-01 1.5297e+00 +5.7000e-01 1.5372e+00 +5.8000e-01 1.6094e+00 +5.9000e-01 1.6352e+00 +6.0000e-01 1.5843e+00 +6.1000e-01 1.6643e+00 +6.2000e-01 1.5987e+00 +6.3000e-01 1.6585e+00 +6.4000e-01 1.6317e+00 +6.5000e-01 1.7074e+00 +6.6000e-01 1.6654e+00 +6.7000e-01 1.6551e+00 +6.8000e-01 1.6964e+00 +6.9000e-01 1.7143e+00 +7.0000e-01 1.7706e+00 +7.1000e-01 1.7622e+00 +7.2000e-01 1.7260e+00 +7.3000e-01 1.8089e+00 +7.4000e-01 1.7905e+00 +7.5000e-01 1.7428e+00 +7.6000e-01 1.8381e+00 +7.7000e-01 1.8182e+00 +7.8000e-01 1.7865e+00 +7.9000e-01 1.7995e+00 +8.0000e-01 1.8296e+00 +8.1000e-01 1.8625e+00 +8.2000e-01 1.8623e+00 +8.3000e-01 1.8383e+00 +8.4000e-01 1.8593e+00 +8.5000e-01 1.8944e+00 +8.6000e-01 1.9598e+00 +8.7000e-01 1.9000e+00 +8.8000e-01 1.9244e+00 +8.9000e-01 1.9397e+00 +9.0000e-01 1.9440e+00 +9.1000e-01 1.9718e+00 +9.2000e-01 1.9383e+00 +9.3000e-01 1.9555e+00 +9.4000e-01 2.0006e+00 +9.5000e-01 1.9841e+00 +9.6000e-01 2.0066e+00 +9.7000e-01 2.0493e+00 +9.8000e-01 2.0503e+00 +9.9000e-01 2.0214e+00 diff --git a/lecture-notes/advanced-python/data/pendulum_error.txt b/lecture-notes/advanced-python/data/pendulum_error.txt new file mode 100644 index 0000000..5cf2194 --- /dev/null +++ b/lecture-notes/advanced-python/data/pendulum_error.txt @@ -0,0 +1,90 @@ +1.0000e-01 6.9004e-01 0.03 0.02 +1.1000e-01 6.9497e-01 0.05 0.03 +1.2000e-01 7.4252e-01 0.02 0.01 +1.3000e-01 7.5360e-01 0.02 0.04 +1.4000e-01 8.3568e-01 0.04 0.00 +1.5000e-01 8.6789e-01 0.01 0.03 +1.6000e-01 8.4182e-01 0.01 0.02 +1.7000e-01 8.5379e-01 0.04 0.02 +1.8000e-01 8.5762e-01 0.02 0.02 +1.9000e-01 8.8390e-01 0.03 0.02 +2.0000e-01 8.9985e-01 0.00 0.03 +2.1000e-01 9.8436e-01 0.04 0.00 +2.2000e-01 1.0244e+00 0.01 0.01 +2.3000e-01 1.0572e+00 0.05 0.04 +2.4000e-01 9.9077e-01 0.05 0.04 +2.5000e-01 1.0058e+00 0.01 0.02 +2.6000e-01 1.0727e+00 0.03 0.02 +2.7000e-01 1.0943e+00 0.03 0.03 +2.8000e-01 1.1432e+00 0.04 0.02 +2.9000e-01 1.1045e+00 0.01 0.02 +3.0000e-01 1.1867e+00 0.00 0.01 +3.1000e-01 1.1385e+00 0.04 0.00 +3.2000e-01 1.2245e+00 0.04 0.04 +3.3000e-01 1.2406e+00 0.00 0.03 +3.4000e-01 1.2071e+00 0.03 0.03 +3.5000e-01 1.2658e+00 0.05 0.03 +3.6000e-01 1.2995e+00 0.03 0.02 +3.7000e-01 1.3142e+00 0.05 0.03 +3.8000e-01 1.2663e+00 0.00 0.00 +3.9000e-01 1.2578e+00 0.03 0.03 +4.0000e-01 1.2991e+00 0.00 0.03 +4.1000e-01 1.3058e+00 0.03 0.04 +4.2000e-01 1.3478e+00 0.05 0.03 +4.3000e-01 1.3506e+00 0.01 0.01 +4.4000e-01 1.4044e+00 0.02 0.02 +4.5000e-01 1.3948e+00 0.03 0.01 +4.6000e-01 1.3800e+00 0.05 0.02 +4.7000e-01 1.4480e+00 0.03 0.03 +4.8000e-01 1.4168e+00 0.04 0.01 +4.9000e-01 1.4719e+00 0.02 0.04 +5.0000e-01 1.4656e+00 0.03 0.04 +5.1000e-01 1.4399e+00 0.01 0.01 +5.2000e-01 1.5174e+00 0.03 0.02 +5.3000e-01 1.4988e+00 0.00 0.00 +5.4000e-01 1.4751e+00 0.05 0.01 +5.5000e-01 1.5326e+00 0.05 0.02 +5.6000e-01 1.5297e+00 0.05 0.00 +5.7000e-01 1.5372e+00 0.00 0.02 +5.8000e-01 1.6094e+00 0.02 0.03 +5.9000e-01 1.6352e+00 0.02 0.03 +6.0000e-01 1.5843e+00 0.04 0.00 +6.1000e-01 1.6643e+00 0.05 0.01 +6.2000e-01 1.5987e+00 0.01 0.02 +6.3000e-01 1.6585e+00 0.01 0.03 +6.4000e-01 1.6317e+00 0.04 0.00 +6.5000e-01 1.7074e+00 0.03 0.00 +6.6000e-01 1.6654e+00 0.03 0.01 +6.7000e-01 1.6551e+00 0.04 0.03 +6.8000e-01 1.6964e+00 0.01 0.02 +6.9000e-01 1.7143e+00 0.01 0.02 +7.0000e-01 1.7706e+00 0.01 0.03 +7.1000e-01 1.7622e+00 0.02 0.03 +7.2000e-01 1.7260e+00 0.04 0.03 +7.3000e-01 1.8089e+00 0.05 0.01 +7.4000e-01 1.7905e+00 0.04 0.03 +7.5000e-01 1.7428e+00 0.01 0.01 +7.6000e-01 1.8381e+00 0.01 0.03 +7.7000e-01 1.8182e+00 0.00 0.03 +7.8000e-01 1.7865e+00 0.04 0.02 +7.9000e-01 1.7995e+00 0.04 0.02 +8.0000e-01 1.8296e+00 0.04 0.02 +8.1000e-01 1.8625e+00 0.02 0.04 +8.2000e-01 1.8623e+00 0.02 0.03 +8.3000e-01 1.8383e+00 0.04 0.02 +8.4000e-01 1.8593e+00 0.04 0.00 +8.5000e-01 1.8944e+00 0.03 0.02 +8.6000e-01 1.9598e+00 0.00 0.03 +8.7000e-01 1.9000e+00 0.04 0.01 +8.8000e-01 1.9244e+00 0.01 0.00 +8.9000e-01 1.9397e+00 0.03 0.02 +9.0000e-01 1.9440e+00 0.03 0.02 +9.1000e-01 1.9718e+00 0.05 0.02 +9.2000e-01 1.9383e+00 0.02 0.02 +9.3000e-01 1.9555e+00 0.05 0.04 +9.4000e-01 2.0006e+00 0.00 0.02 +9.5000e-01 1.9841e+00 0.00 0.02 +9.6000e-01 2.0066e+00 0.02 0.01 +9.7000e-01 2.0493e+00 0.05 0.03 +9.8000e-01 2.0503e+00 0.03 0.03 +9.9000e-01 2.0214e+00 0.03 0.04 diff --git a/lecture-notes/advanced-python/exercises.rst b/lecture-notes/advanced-python/exercises.rst new file mode 100644 index 0000000..eeaa323 --- /dev/null +++ b/lecture-notes/advanced-python/exercises.rst @@ -0,0 +1,56 @@ +Exercises +========= + +#. Consider the iteration :math:`$x_{n+1} = f(x_n)$` where + :math:`$f(x) = kx(1-x)$`. Plot the successive iterates of this + process. + +#. Plot this using a cobweb plot as follows: + + #. Start at :math:`$(x_0, 0)$` + #. Draw line to :math:`$(x_i, f(x_i))$`; + #. Set :math:`$x_{i+1} = f(x_i)$` + #. Draw line to :math:`$(x_i, x_i)$` + #. Repeat from 2 for as long as you want + +#. Plot the Koch snowflake. Write a function to generate the necessary + points given the two points constituting a line. + + #. Split the line into 4 segments. + #. The first and last segments are trivial. + #. To rotate the point you can use complex numbers, recall that + :math:`$z e^{j \theta}$` rotates a point :math:`$z$` in 2D by + :math:`$\theta$`. + #. Do this for all line segments till everything is done. + +#. Show rate of convergence for a first and second order finite + difference of sin(x) + +#. Given, the position of a projectile in in ``pos.txt``, plot it's + trajectory. + + - Label both the axes. + - What kind of motion is this? + - Title the graph accordingly. + - Annotate the position where vertical velocity is zero. + +#. Write a Program that plots a regular n-gon(Let n = 5). + +#. Create a sequence of images in which the damped oscillator + (:math:`$e^{-x/10}sin(x)$`) slowly evolves over time. + +#. Given a list of numbers, find all the indices at which 1 is present. + numbers = [1, 1, 3, 4, 3, 6, 7, 8, 1, 2, 4, 1] + +#. Given a list of numbers, find all the indices at which 1 is present. + numbers = [1, 1, 3, 4, 3, 6, 7, 8, 1, 2, 4, 1]. Solve the problem using a + functional approach. + +.. + Local Variables: + mode: rst + indent-tabs-mode: nil + sentence-end-double-space: nil + fill-column: 77 + End: + diff --git a/lecture-notes/advanced-python/handOut.rst b/lecture-notes/advanced-python/handOut.rst new file mode 100644 index 0000000..2cd3618 --- /dev/null +++ b/lecture-notes/advanced-python/handOut.rst @@ -0,0 +1,14 @@ +================= + Advanced Python +================= + +.. include :: plotting.rst +.. include :: arrays.rst +.. include :: scipy.rst +.. include :: modules.rst +.. include :: oop.rst +.. include :: lambda.rst +.. include :: sage.rst +.. include :: rst.rst + + diff --git a/lecture-notes/advanced-python/images/L-Tsq.png b/lecture-notes/advanced-python/images/L-Tsq.png Binary files differnew file mode 100644 index 0000000..cc1a454 --- /dev/null +++ b/lecture-notes/advanced-python/images/L-Tsq.png diff --git a/lecture-notes/advanced-python/images/bar.png b/lecture-notes/advanced-python/images/bar.png Binary files differnew file mode 100644 index 0000000..cee54fb --- /dev/null +++ b/lecture-notes/advanced-python/images/bar.png diff --git a/lecture-notes/advanced-python/images/cosine.png b/lecture-notes/advanced-python/images/cosine.png Binary files differnew file mode 100644 index 0000000..2b15a32 --- /dev/null +++ b/lecture-notes/advanced-python/images/cosine.png diff --git a/lecture-notes/advanced-python/images/epid.png b/lecture-notes/advanced-python/images/epid.png Binary files differnew file mode 100644 index 0000000..e1c7e08 --- /dev/null +++ b/lecture-notes/advanced-python/images/epid.png diff --git a/lecture-notes/advanced-python/images/fsolve.png b/lecture-notes/advanced-python/images/fsolve.png Binary files differnew file mode 100644 index 0000000..0108215 --- /dev/null +++ b/lecture-notes/advanced-python/images/fsolve.png diff --git a/lecture-notes/advanced-python/images/loglog.png b/lecture-notes/advanced-python/images/loglog.png Binary files differnew file mode 100644 index 0000000..824b9f1 --- /dev/null +++ b/lecture-notes/advanced-python/images/loglog.png diff --git a/lecture-notes/advanced-python/images/lst-sq-fit.png b/lecture-notes/advanced-python/images/lst-sq-fit.png Binary files differnew file mode 100644 index 0000000..7e9dfe2 --- /dev/null +++ b/lecture-notes/advanced-python/images/lst-sq-fit.png diff --git a/lecture-notes/advanced-python/images/ode.png b/lecture-notes/advanced-python/images/ode.png Binary files differnew file mode 100644 index 0000000..c76a483 --- /dev/null +++ b/lecture-notes/advanced-python/images/ode.png diff --git a/lecture-notes/advanced-python/images/overlaid.png b/lecture-notes/advanced-python/images/overlaid.png Binary files differnew file mode 100644 index 0000000..41e1891 --- /dev/null +++ b/lecture-notes/advanced-python/images/overlaid.png diff --git a/lecture-notes/advanced-python/images/pie.png b/lecture-notes/advanced-python/images/pie.png Binary files differnew file mode 100644 index 0000000..7791e54 --- /dev/null +++ b/lecture-notes/advanced-python/images/pie.png diff --git a/lecture-notes/advanced-python/images/plot.png b/lecture-notes/advanced-python/images/plot.png Binary files differnew file mode 100644 index 0000000..89cbc46 --- /dev/null +++ b/lecture-notes/advanced-python/images/plot.png diff --git a/lecture-notes/advanced-python/images/roots.png b/lecture-notes/advanced-python/images/roots.png Binary files differnew file mode 100644 index 0000000..c13a1a4 --- /dev/null +++ b/lecture-notes/advanced-python/images/roots.png diff --git a/lecture-notes/advanced-python/images/scatter.png b/lecture-notes/advanced-python/images/scatter.png Binary files differnew file mode 100644 index 0000000..66bd5d8 --- /dev/null +++ b/lecture-notes/advanced-python/images/scatter.png diff --git a/lecture-notes/advanced-python/images/sine.png b/lecture-notes/advanced-python/images/sine.png Binary files differnew file mode 100644 index 0000000..7667886 --- /dev/null +++ b/lecture-notes/advanced-python/images/sine.png diff --git a/lecture-notes/advanced-python/images/slice.png b/lecture-notes/advanced-python/images/slice.png Binary files differnew file mode 100644 index 0000000..7f53d2a --- /dev/null +++ b/lecture-notes/advanced-python/images/slice.png diff --git a/lecture-notes/advanced-python/images/squares.png b/lecture-notes/advanced-python/images/squares.png Binary files differnew file mode 100644 index 0000000..ee102e6 --- /dev/null +++ b/lecture-notes/advanced-python/images/squares.png diff --git a/lecture-notes/advanced-python/images/subplot.png b/lecture-notes/advanced-python/images/subplot.png Binary files differnew file mode 100644 index 0000000..2c1a662 --- /dev/null +++ b/lecture-notes/advanced-python/images/subplot.png diff --git a/lecture-notes/advanced-python/lambda.rst b/lecture-notes/advanced-python/lambda.rst new file mode 100644 index 0000000..4660300 --- /dev/null +++ b/lecture-notes/advanced-python/lambda.rst @@ -0,0 +1,225 @@ +Functional programming +====================== + +In this section, we shall look at a different style of programming called +Functional programming, which is supported by Python. + +The fundamental idea behind functional programming is that the output of a +function, should not depend on the state of the program. It should only +depend on the inputs to the program and should return the same output, +whenever the function is called with the same arguments. Essentially, the +functions of our code, behave like mathematical functions, where the output +is dependent only on the variables on which the function depends. There is +no "state" associated with the program. + +Let's look at some of the functionality that Python provides for writing +code in the Functional approach. + +List Comprehensions +------------------- + +Let's take a very simple problem to illustrate how list comprehensions +work. Let's say, we are given a list of weights of people, and we need to +calculate the corresponding weights on the moon. Essentially, return a new +list, with each of the values divided by 6.0. + +It's a simple problem, and let's first solve it using a ``for`` loop. We +shall initialize a new empty, list and keep appending the new weights +calculated + +:: + + weights = [30, 45.5, 78, 81, 55.5, 62.5] + + weights_moon = [] + + for w in weights: + weights_moon.append(w/6.0) + + print weights_moon + +We had to initialize an empty list, and write a ``for`` loop that appends +each of the values to the new list. List comprehensions provide a way of +writing a one liner, that does the same thing, without resorting to +initializing a new empty list. Here's how we would do it, using list +comprehensions + +:: + + [ w/6.0 for w in weights ] + +As we can see, we have the same list, that we obtained previously, using +the ``for`` loop. + +Let's now look at a slightly more complex example, where we wish to +calculate the weights on the moon, only if the weight on the earth is +greater than 50. + +:: + + weights = [30, 45.5, 78, 81, 55.5, 62.5] + weights_moon = [] + for w in weights: + if w > 50: + weights_moon.append(w/6.0) + + print weights_moon + +The ``for`` loop above can be translated to a list comprehension as shown + +:: + + [ w/6.0 for w in weights if w>50 ] + +Now, let's change the problem again. Say, we wish to give the weight on the +moon (divide by 6), when the weight is greater than 50, otherwise triple +the weight. + +:: + + weights = [30, 45.5, 78, 81, 55.5, 62.5] + weights_migrate = [] + for w in weights: + if w > 50: + weights_migrate.append(w/6.0) + else: + weights_migrate.append(w * 3.0) + + print weights_migrate + +This problem, however, cannot be translated into a list comprehension. We +shall use the ``map`` built-in, to solve the problem in a functional +style. + +``map`` +------- + +But before getting to the more complex problem, let's solve the easier +problem of returning the weight on moon for all the weights. + +The ``map`` function essentially allows us to apply a function to all the +elements of a list, and returns a new list that consists of the outputs +from each of the call. So, to use ``map`` we need to define a function, +that takes an input and returns a sixth of it. + +:: + + def moonize(weight): + return weight/6.0 + +Now, that we have our ``moonize`` function, we can pass the function and the +list of weights as an argument to ``map`` and get the required list. + +:: + + map(moonize, weights) + +Let's define a new function, that compares the weight value with 50 and +returns a new value based on the condition. + +:: + + def migrate(weight): + if weight < 50: + return weight*3.0 + else: + return weight/6.0 + +Now, we can use ``map`` to obtain the new weight values + +:: + + map(migrate, weights) + +As you can see, we obtained the result, that we obtained before. + +But, defining such functions each time, is slightly inconvenient. We are +not going to use these functions at any later point, in our code. So, it is +slightly wasteful to define functions for this. Wouldn't it be nice to +write them, without actually defining functions? Enter ``lambda``! + +``lambda`` +---------- + +Essentially, lambda allows us to define small functions anonymously. The +first example that uses the ``moonize`` function can now be re-written as +below, using the lambda function. + +:: + + map(lambda x: x/6.0, weights) + +``lambda`` above is defining a function, which takes one argument ``x`` and +returns a sixth of that argument. The ``lambda`` actually returns a +function object which we could in fact assign to a name and use later. + +:: + + l_moonize = lambda x: x/6.0 + +The ``l_moonize`` function, now behaves similarly to the ``moonize`` +function. + +The ``migrate`` function can be written using a lambda function as below + +:: + + l_migrate = lambda x: x*3.0 if x < 50 else x/6.0 + + +If you observed, we have carefully avoided the discussion of the example +where only the weights that were above 50 were calculated and returned. +This is because, this cannot be done using ``map``. We may return ``None`` +instead of calculating a sixth of the element, but we cannot ensure that +the element is not present in the new list. + +This can be done using ``filter`` and ``map`` in conjunction. + +``filter`` +---------- + +The ``filter`` function, like the ``map`` takes two arguments, a function +and a sequence and calls the function for each element of the sequence. The +output of ``filter`` is a sequence consisting of elements for which the +function returned ``True`` + +The problem of returning a sixth of only those weights which are more than +50, can be solved as below + +:: + + map(lambda x: x/6.0, filter(lambda x: x > 50, weights)) + +The ``filter`` function returns a list containing only the values which are +greater than 50. + +:: + + filter(lambda x: x > 50, weights) + + +``reduce`` +---------- + +As, the name suggests, ``reduce`` reduces a sequence to a single object. +``reduce`` takes two arguments, a function and a sequence, but the function +should take two arguments as input. + +``reduce`` initially passes the first two elements as arguments, and +continues iterating of the sequence and passes the output of the previous +call with the current element, as the arguments to the function. The final +result therefore, is just a single element. + +:: + + reduce(lambda x,y: x*y, [1, 2, 3, 4]) + +multiplies all the elements of the list and returns ``24``. + +.. + Local Variables: + mode: rst + indent-tabs-mode: nil + sentence-end-double-space: nil + fill-column: 75 + End: diff --git a/lecture-notes/advanced-python/module_plan.rst b/lecture-notes/advanced-python/module_plan.rst new file mode 100644 index 0000000..2ee4925 --- /dev/null +++ b/lecture-notes/advanced-python/module_plan.rst @@ -0,0 +1,79 @@ +Advanced Python +=============== + +Module Objectives +----------------- + +After successfully completing this module a participant will be able to: + +* generate 2D plots {Ap} +* Work with arrays and use them effectively {Ap} +* Solve linear, polynomial and other non-linear equations {Ap} +* Solve ODEs {Ap} +* Write mid-sized programs that carry out typical {Ap} + engineering/numerical computations such as those that involve + (basic) manipulation of large arrays in an efficient manner + ++---------+-----------------------------------+----------+ +| Session | Topic | Duration | ++---------+-----------------------------------+----------+ +| | Interactive Plottin | 5 min | +| | - -pylab | | +| | - plot, linspace | | +| | | | +| | Embellishing plots | 10 min | +| | - clf | | +| | - title | | +| | - xlabel, ylabel | | +| | - annotate | | +| | - xlim, ylim | | +| | | | +| | Saving to scripts | 10 min | +| | - %hist | | +| | - %save | | +| | - %run | | +| | | | +| | Saving plots | | +| | | | +| | Multiple plots | 15 min | +| | - legend | | +| | - *figure* | | +| | - subplot | | +| | | | +| | Plotting data | 10 min | +| | - loadtxt | | +| | | | +| | Other plots | 10 min | +| | - bar, | | +| | - pie | | +| | - scatter | | +| | - loglog | | ++---------+-----------------------------------+----------+ +| | Arrays - Introduction | 15 min | +| | - creating from lists | | +| | - special methods | | +| | - operations on arrays | | +| | | | +| | Accessing pieces of arrays | 15 min | +| | - accessing and changing elements | | +| | - rows and columns | | +| | - slicing and striding | | +| | | | +| | Matrix operations | 10 min | +| | | | +| | Least square fit | 15 min | ++---------+-----------------------------------+----------+ +| | Solving equations | 15 min | +| | - solve | | +| | - roots | | +| | - fsolve | | +| | | | +| | ODEs | 20 min | +| | - 1st order | | +| | - 2nd order | | +| | | | +| | python modules | 20 min | +| | - imports | | +| | - sys.path | | +| | - writing own modules | | ++---------+-----------------------------------+----------+ diff --git a/lecture-notes/advanced-python/modules.rst b/lecture-notes/advanced-python/modules.rst new file mode 100644 index 0000000..f3df676 --- /dev/null +++ b/lecture-notes/advanced-python/modules.rst @@ -0,0 +1,278 @@ +Using Python modules +==================== + +We shall, in this section, see how to run Python scripts from the command +line, and more details about importing modules. + +Let us create a simple python script to print hello world. Open your text +editor and type the following, and save the script as ``hello.py``. + +:: + + print "Hello world!" + +Until now we have been running scripts from inside IPython, using + +:: + + %run -i hello.py + +But, as we know, IPython is just an advanced interpreter and it is not +mandatory that every one who wants to run your program has IPython +installed. + +So, the right method to run the script, would be to run it using the Python +interpreter. Open the terminal and navigate to the directory where +``hello.py`` is saved. + +Then run the script by saying, +:: + + python hello.py + +The script is executed and the string ``Hello World!`` has been printed. + +Now let us run a script that plots a simple sine curve in the range -2pi to +2pi, using Python, instead of running it from within IPython. + +Type the following lines and save it in ``sine_plot.py`` file. + +:: + + x = linspace(-2*pi, 2*pi, 100) + plot(x, sin(x)) + show() + +Now let us run sine_plot.py as a python script. + +:: + + python sine_plot.py + +Do we get the plot? No! All we get is error messages. Python complains that +``linspace`` isn't defined. What happened? Let us try to run the same +script from within IPython. Start IPython, with the ``-pylab`` argument and +run the script. It works! + +What is going on, here? IPython when started with the ``-pylab`` option, is +importing a whole set of functionality for us to work with, without +bothering about importing etc. + +Let us now try to fix the problem by importing ``linspace``. + +Let's add the following line as the first line in the script. + +:: + + from scipy import * + +Now let us run the script again, + +:: + + python sine_plot.py + +Now we get an error, that says ``plot`` is not defined. Let's edit the file +and import this from pylab. Let's add the following line, as the second +line of our script. + +:: + + from pylab import * + +And run the script, + +:: + + python sine_plot.py + +Yes! it worked. So what did we do? + +We actually imported the required functions and keywords, using ``import``. +By using the * , we are asking python to import everything from the +``scipy`` and ``pylab`` modules. This isn't a good practice, as +1. it imports a lot of unnecessary things +2. the two modules may have functions with the same name, which would + cause a conflict. + +One of the ways out is to import only the stuff that we need, explicitly. + +Let us modify sine_plot.py by replacing the import statements with the +following lines. + +:: + + from scipy import linspace, pi, sin + from pylab import plot, show + +Now let us try running the code again as, + +:: + + python show_plot.py + +As expected, this works. But, once the number of functions that you need to +import increases, this is slightly inconvenient. Also, you cannot use +functions with the same name, from different modules. To overcome this, +there's another method. + +We could just import the modules as it is, and use the functions or other +objects as a part of those modules. Change the import lines, to the +following. + +:: + + import scipy + import pylab + +Now, replace ``pi`` with ``scipy.pi``. Similarly, for ``sin`` and +``linspace``. Replace ``plot`` and ``show`` with ``pylab.plot`` and +``pylab.show``, respectively. + +Now, run the file and see that we get the output, as expected. + +We have learned how to import from modules, but what exactly is a module? +How is one written? + +A module is simply a Python script containing the definitions and +statements, which can be imported. So, it is very easy to create your own +modules. You just need to stick in all your definitions into your python +file and put the file in your current directory. + +When importing, Python searches the locations present in a variable called +the Python path. So, our module file should be present in one of the +locations in the Python path. The first location to be searched is the +current directory of the script being run. So, having our module file in +the current working directory, is the simplest way to allow it to be used +as a module and import things from it. + +Python has a very rich standard library of modules. It is very extensive, +offering a wide range of facilities. Some of the standard modules are, + +for Math: math, random +for Internet access: urllib2, smtplib +for System, Command line arguments: sys +for Operating system interface: os +for regular expressions: re +for compression: gzip, zipfile, tarfile +And there are lot more. + +Find more information at Python Library reference, +``http://docs.python.org/library/`` + +There are a lot of other modules like pylab, scipy, Mayavi, etc which +are not part of the standard Python library. + +This brings us to the end of our discussion on modules and running scripts +from the command line. + +Writing modules +=============== + +In this section we shall look at writing modules, in some more detail. +Often we will have to reuse the code that we have previously written. We do +that by writing functions. Functions can then be put into modules, and +imported as and when required. + +Let us first write a function that computes the gcd of two numbers and save it in a script. + +:: + + def gcd(a, b): + while b: + a, b = b, a%b + return a + +Now, we shall write a test function in the script that tests the gcd function, to see if it works. + +:: + + if gcd(40, 12) == 4 and gcd(12, 13) == 1: + print "Everything OK" + else: + print "The GCD function is wrong" + +Let us save the file as gcd_script.py in ``/home/fossee/gcd_script.py`` and +run it. + +:: + + $ python /home/fossee/gcd_script.py + +We can see that the script is executed and everything is fine. + +What if we want to use the gcd function in some of our other scripts. This +is also possible since every python file can be used as a module. + +But first, we shall understand what happens when you import a module. + +Open IPython and type + +:: + + import sys + sys.path + +This is a list of locations where python searches for a module when it +encounters an import statement. Hence, when we just did ``import sys``, +python searches for a file named ``sys.py`` or a folder named ``sys`` in +all these locations one by one, until it finds one. We can place our script +in any one of these locations and import it. + +The first item in the list is an empty string which means the current +working directory is also searched. + +Alternatively, we can also import the module if we are working in same +directory where the script exists. + +Since we are in /home/fossee, we can simply do + +:: + + import gcd_script + +We can see that the gcd_script is imported. But the test code that we added +at the end of the file is also executed. + +But we want the test code to be executed only when the file is run as a +python script and not when it is imported. + +This is possible by using ``__name__`` variable. + + +Go to the file and add + +:: + + if __name__ == "__main__": + +before the test code and indent the test code. + +Let us first run the code. + +:: + + $ python gcd_script.py + +We can see that the test runs successfully. + +Now we shall import the file + +:: + + import gcd_script + +We see that now the test code is not executed. + +The ``__name__`` variable is local to every module and it is equal to +``__main__`` only when the file is run as a script. Hence, all the code +that goes in to the if block, ``if __name__ == "__main__":`` is executed +only when the file is run as a python script. + +.. + Local Variables: + mode: rst + indent-tabs-mode: nil + sentence-end-double-space: nil + fill-column: 75 + End: diff --git a/lecture-notes/advanced-python/more_arrays.rst b/lecture-notes/advanced-python/more_arrays.rst new file mode 100644 index 0000000..c562edd --- /dev/null +++ b/lecture-notes/advanced-python/more_arrays.rst @@ -0,0 +1,310 @@ +More Arrays +=========== + +In this section, we shall explore arrays a bit more, since they are the +fundamental building block of all the computation work we wish to do. + +Arrays were introduced, stating that they are very fast as compared to +lists, owing to their homogeneity. They are definitely a lot more +convenient than a list of lists for doing element-wise operations. Let's +now look at the speed difference, quantitatively. + +Arrays vs. Lists +---------------- + +Let us create a large array with, say a million elements and see how long +it takes to get a new sequence that contains the ``sin`` of each of these +elements. + +:: + + a = linspace(0, 2*pi, 1000000) + + sin(a) + + b = [] + for i in a: b.append(sin(i)) + +There is a visible difference in the run-time of the two ways of doing it. +But, let's look at it quantitatively using the ``%timeit`` magic command of +IPython to get a quantitative difference between doing is using a ``for`` +loop and using the array way of doing it. + +:: + + %timeit sin(a) + + b = [] + %timeit for i in a: b.append(sin(i)) + +The first method turns out to be around 70 times faster on my machine. So, +as you can see, the homogeneity. The speed gains due to homogeneity are +because, the loops are run in C, rather than in Python and Python loops are +comparatively much slower than C loops. + +Fancy Indexing +-------------- + +We have looked at slicing and striding to get pieces of arrays. But they +only allow us to do so much. + +For instance, let's say, we have an array a of length 40 with some random +elements. We wish to get a new array which is obtained by dropping every +element that is at a position that is a multiple of 8, i.e., we wish to +drop the elements 0, 8, 16, 24, 32. How do we go about doing this? +Essentially, we wish to drop the elements a[::8]. We shall use something +called Boolean arrays to solve this problem. + +Let's look at a small example before solving this problem. + +:: + + p = array([1, 2, 3]) + q = array([True, False, True]) + + p[q] + +``q`` is called a Boolean array and can be used to index another array. +Only the elements at positions corresponding to ``True`` values in q, will +be returned. + +Now, to solve the problem of dropping the elements a[::8] from a, we need +to create a Boolean array, with those elements as ``False`` and the rest as +``True``. There could be multiple ways of doing that. Here's one + +:: + + b = arange(len(a)) + b%8!=0 + + a[b%8!=0] + +Checking if the elements of ``b`` are not multiples of 8, returns a Boolean +array, which we are then using to index ``a``. + +Numpy arrays can also be indexed using arrays of indices. Let's solve the +same problem using arrays with indices. Let's look at the same small +example that we looked at, for Boolean arrays, before solving the actual +problem. + +:: + + p = array([1, 2, 3]) + q = array([0, 2]) + + p[q] + +The array ``q`` has the indices of the elements that we wish to pick out of +the array ``p``. The order in which the indices are present, doesn't +matter. The returned array, will contain the elements of ``p`` in the order +in which they have been indexed. They can even be repeated, if we wish to +get the same element out of ``p``. + +:: + + r = array([2, 0]) + p[r] + + s = array([1, 1]) + p[s] + +Now, to solve the problem of dropping all the elements of ``p`` whose +indices are a multiple of 8, we need to generate an array, which doesn't +have these elements. + +:: + + q = array([i for i in range(40) if i%8]) + p[q] + +Copies and Views +---------------- + +Simple assignment of mutable objects, do not make copies in Python. For +instance, + +:: + + a = array([1, 2, 3]) + b = a + +Here, ``b`` and ``a`` are not copies of each other, but different names for +the same object. If one of them is changed, it reflects in the other one, +as well. By the way, if you recall, this behaviour is similar with lists as +well. + +:: + + a[0] = 1 + print a, b + + +Slicing an array, returns a view of it. Assigning the slice of an object to +a new variable, means the new variable references a portion of the data of +the original object. Hence, changing the data of the new variable, changes +the original variable, as well. + +:: + + a = arange(10) + b = a[5:] + + b[:] = 5 + print b, a + +If we require a complete (or deep) copy of the data of an array, we should +use the ``copy()`` method. + +:: + + a = arange(10) + b = a[5:].copy() + + b[:] = 5 + print b, a + +Broadcasting +------------ + +Let's now look at a more advanced concept called Broadcasting. The +broadcasting rules help us understand how Numpy deals with arrays of +different dimensions. + +We know that array operations are element-wise, and for them to work, the +two arrays should be of the same shape. + +For instance, + +:: + + a = array([1, 2, 3, 4]) + b = array([2, 4, 6, 8]) + + a * b + +works, but, + +:: + + a = array([1, 2, 3, 4]) + c = array([6, 8, 10]) + + a * c + +does not work, which is expected. But, surprisingly (or may be not so +surprisingly, since we have seen it before) multiplication of a vector with +a scalar works. + +:: + + a = array([1, 2, 3, 4]) + c = 6 + + a * c + +The above multiplication works, thanks to Broadcasting. Let us look at +another example of Broadcasting before looking at the general rules of +broadcasting. + +:: + + x = array([1, 2, 3]) + y = array([4, 5, 6]) + x+y + + y.shape = 3, 1 + print x, y + x+y + +When we are operating on two arrays, Numpy broadcasts the arrays, so that +the shape of the two arrays becomes the same. Then the required operation +is performed on the two arrays. + +The procedure of broadcasting is as follows. + +1. When operating on two arrays, the arrays with the smaller number of + dimensions, has 1s prepended to it's shape, so that the number of + dimensions of both the arrays becomes the same. +2. The size in each dimension of the output shape is the maximum of all the + input shapes in that dimension. +3. An input can be used in the calculation if its shape in a particular + dimension either matches the output shape or has value exactly 1. +4. If an input has a dimension size of 1 in its shape, the first data entry + in that dimension will be used for all + +Let's look at the example of adding ``x`` and ``y`` to each other, step by +step. + +:: + + x.shape + y.shape + +``x.shape`` is (3,) and ``y.shape`` is (3,1). Now, ``x`` has the smaller +dimensions of the two. 1 is prepended to the shape of x, until both the +arrays have the same dimension. ``x.shape`` becomes (1, 3). + +Now, by rule 2, we know that the output shape is the maximum of all the +input shapes, in each of the dimensions. So, the shape of the output is +expect to be (3, 3) + +The condition 3 satisfies, for both ``x`` and ``y``. So, this is a valid +operation on ``x`` and ``y``. + +To see how the last step works, we use the ``broadcast_arrays`` command. + +:: + + broadcast_arrays(x, y) + +The values of ``x`` are broadcasted or copied, in the dimension where it's +size was 1. Similarly, for ``y``. + +Let's look at another example, before ending our discussion on +Broadcasting. Let's say we have the co-ordinates of a set of points, and we +wish to calculate the distance of a new point from each of these points. + +:: + + x = array([[ 2., 2.], + [ 6., 9.], + [ 6., 6.], + [ 9., 0.]]) + + y = array([4., 3.]) + +We shall use broadcasting to calculate the difference between ``y`` and each of +the points in ``x``. + +:: + + x - y + +The array ``y`` has been broadcast and the difference has been obtained. +The following commands, will now give us the required distances. + +:: + + (x-y)**2 + sqrt(sum((x-y)**2, axis=1)) + +As you can see, broadcasting makes the code much simpler. Also, the +operation of subtracting ``y`` from each of the elements of ``x`` is +performed using iterations in the underlying C language, rather than us +writing ``for`` loops in Python. This turns out to be much faster, as long +as the array sizes are small. + +But this may turn out to be slower, when the number of objects gets larger. +This discussion is not in the scope of this course. Look at +`EricsBroadcastingDoc <http://www.scipy.org/EricsBroadcastingDoc>`_ for more +detail. + + + +.. + Local Variables: + mode: rst + indent-tabs-mode: nil + sentence-end-double-space: nil + fill-column: 75 + End: diff --git a/lecture-notes/advanced-python/more_py.tex b/lecture-notes/advanced-python/more_py.tex new file mode 100644 index 0000000..8b50ec4 --- /dev/null +++ b/lecture-notes/advanced-python/more_py.tex @@ -0,0 +1,51 @@ +\documentclass[12pt,presentation]{beamer} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{fixltx2e} +\usepackage{graphicx} +\usepackage{longtable} +\usepackage{float} +\usepackage{wrapfig} +\usepackage{soul} +\usepackage{textcomp} +\usepackage{marvosym} +\usepackage{wasysym} +\usepackage{latexsym} +\usepackage{amssymb} +\usepackage{hyperref} +\tolerance=1000 +\usepackage[english]{babel} \usepackage{ae,aecompl} +\usepackage{mathpazo,courier,euler} \usepackage[scaled=.95]{helvet} +\usepackage{listings} +\lstset{language=Python, basicstyle=\ttfamily\bfseries, +commentstyle=\color{red}\itshape, stringstyle=\color{green}, +showstringspaces=false, keywordstyle=\color{blue}\bfseries} +\providecommand{\alert}[1]{\textbf{#1}} + +\title{SEES: Advanced Python(2)} +\author{FOSSEE} + +\usetheme{Warsaw}\usecolortheme{default}\useoutertheme{infolines}\setbeamercovered{transparent} + +\AtBeginSection[] +{ + \begin{frame}<beamer> + \frametitle{Outline} + \tableofcontents[currentsection] + \end{frame} +} + +\begin{document} + +\maketitle + +\begin{frame} +\frametitle{Outline} +\setcounter{tocdepth}{3} +\tableofcontents +\end{frame} + +\include{slides/lambda} +\include{slides/oop} + +\end{document} diff --git a/lecture-notes/advanced-python/oop.rst b/lecture-notes/advanced-python/oop.rst new file mode 100644 index 0000000..b1ecbe8 --- /dev/null +++ b/lecture-notes/advanced-python/oop.rst @@ -0,0 +1,230 @@ +Object Oriented Programming +=========================== + +At the end of this section, you will be able to - + +- Understand the differences between Object Oriented Programming and + Procedural Programming +- Appreciate the need for Object Oriented Programming +- Read and understand Object Oriented Programs +- Write simple Object Oriented Programs + +Suppose we have a list of talks, to be presented at a conference. How would +we store the details of the talks? We could possibly have a dictionary for +each talk, that contains keys and values for Speaker, Title and Tags of the +talk. Also, say we would like to get the first name of the speaker and the +tags of the talk as a list, when required. We could do it, as below. + +:: + + talk = {'Speaker': 'Guido van Rossum', + 'Title': 'The History of Python' + 'Tags': 'python,history,C,advanced'} + + def get_first_name(talk): + return talk['Speaker'].split()[0] + + def get_tags(talk): + return talk['Tags'].split(',') + +This is fine, when we have a small number of talks and a small number of +operations that we wish to perform. But, as the number of talks increases, +this gets inconvenient. Say, you are writing another function in some other +module, that uses this ``talk`` dictionary, you will also need to pass the +functions that act on ``talk`` to that function. This gets quite messy, +when you have a lot of functions and objects. + +This is where Objects come in handy. Objects, essentially, group data with +the methods that act on the data into a single block/object. + +Objects and Methods +------------------- + +The idea of objects and object oriented programming is being introduced, +now, but this doesn't mean that we haven't come across objects. Everything +in Python is an object. We have been dealing with objects all the while. +Strings, lists, functions and even modules are objects in Python. As we +have seen, objects combine data along with functions that act upon the +data and we have been seeing this since the beginning. The functions that +are tied to an object are called methods. We have seen various methods, +until now. + +:: + + s = "Hello World" + s.lower() + + l = [1, 2, 3, 4, 5] + l.append(6) + +``lower`` is a string method and is being called upon ``s``, which is a +string object. Similarly, ``append`` is a list method, which is being +called on the list object ``l``. + +Functions are also objects and they can be passed to and returned from +functions, as we have seen in the SciPy section. + +Objects are also useful, because the provide a similar interface, without +us needing to bother about which exact type of object we are dealing with. +For example, we can iterate over the items in a sequence, as shown below +without really worrying about whether it's a list or a dictionary or a +file-object. + +:: + + for element in (1, 2, 3): + print element + for key in {'one':1, 'two':2}: + print key + for char in "123": + print char + for line in open("myfile.txt"): + print line + for line in urllib2.urlopen('http://site.com'): + print line + +All objects providing a similar inteface can be used the same way. + +Classes +------- + +When we created a string ``s``, we obtained an object of ``type`` string. + +:: + + s = "Hello World" + type(s) + +``s`` already comes with all the methods of strings. So, it suggests that +there should be some template, based on which the object ``s`` is built. +This template or blueprint to build an object is the Class. The class +definition gives the blueprint for building objects of that kind, and each +``object`` is an *instance* of that ``class``. + +As you would've expected, we can define our own classes in Python. Let us +define a simple Talk class for the example that we started this section +with. + +:: + + class Talk: + """A class for the Talks.""" + + def __init__(self, speaker, title, tags): + self.speaker = speaker + self.title = title + self.tags = tags + + def get_speaker_firstname(self): + return self.speaker.split()[0] + + def get_tags(self): + return self.tags.split(',') + +The above example introduces a lot of new things. Let us look at it, piece +by piece. + +A class is defined using a ``class`` block -- the keyword ``class`` +followed by the class name, in turn followed by a semicolon. All the +statements within the ``class`` are enclosed in it's block. Here, we have +defined a class named ``Talk``. + +Our class has the same two functions that we had defined before, to get the +speaker firstname and the tags. But along with that, we have a new function +``__init__``. We will see, what it is, in a short while. By the way, the +functions inside a class are called methods, as you already know. By +design, each method of a class requires to have the same instance of the +class, (i.e., the object) from which it was called as the first argument. +This argument is generally defined using ``self``. + +``self.speaker``, ``self.title`` and ``self.tags`` are variables that +contain the respective data. So, as you can see, we have combined the data +and the methods operating on it, into a single entity, an object. + +Let's now initialize a ``Talk`` which is equivalent to the example of the +talk, that we started with. Initializing an object is similar to calling a +function. + +:: + + bdfl = Talk('Guido van Rossum', + 'The History of Python', + 'python,history,C,advanced') + +We pass the arguments of the ``__init__`` function to the class name. We +are creating an object ``bdfl``, that is an instance of the class ``Talk`` +and represents the talk by Guido van Rossum on the History of Python. We +can now use the methods of the class, using the dot notation, that we have +been doing all the while. + +:: + + bdfl.get_tags() + bdfl.get_speaker_firstname() + +The ``__init__`` method is a special method, that is called, each time an +object is created from a class, i.e., an instance of a class is created. + +:: + + print bdfl.speaker + print bdfl.tags + print bdfl.title + +As you can see, the ``__init__`` method was called and the variables of the +``bdfl`` object have been set. object have been set. Also notice that, the +``__init__`` function takes 4 arguments, but we have passed only three. The +first argument ``self`` as we have already seen, is a reference to the +object itself. + + +Inheritance +----------- + +Now assume that we have a different category for Tutorials. They are almost +like talks, except that they can be hands-on or not. Now, we do not wish to +re-write the whole code that we wrote for the ``Talk`` class. Here, the +idea of inheritance comes in handy. We "inherit" the ``Talk`` class and +modify it to suit our needs. + +:: + + class Tutorial(Talk): + """A class for the tutorials.""" + + def __init__(self, speaker, title, tags, handson=True): + Talk.__init__(self, speaker, title, tags) + self.handson = handson + + def is_handson(self): + return self.handson + +We have now derived the ``Tutorial`` class from the ``Talk`` class. The +``Tutorial`` class, has a different ``__init__`` method, and a new +``is_handson`` method. But, since it is derived from the ``Talk`` method it +also has the methods, ``get_tags`` and ``get_speaker_firstname``. This +concept of inheriting methods and values is called inheritance. + +:: + + numpy = Tutorial('Travis Oliphant', 'Numpy Basics', 'numpy,python,beginner') + numpy.is_handson() + numpy.get_speaker_firstname() + +As you can see, it has saved a lot of code duplication and effort. + +That brings us to the end of the section on Object Oriented Programming. In +this section we have learnt, + +- the fundamental difference in paradigm, between Object Oriented + Programming and Procedural Programming +- to write our own classes +- to write new classes that inherit from existing classes + +.. + Local Variables: + mode: rst + indent-tabs-mode: nil + sentence-end-double-space: nil + fill-column: 75 + End: diff --git a/lecture-notes/advanced-python/plotting.rst b/lecture-notes/advanced-python/plotting.rst new file mode 100644 index 0000000..ad246d4 --- /dev/null +++ b/lecture-notes/advanced-python/plotting.rst @@ -0,0 +1,816 @@ +Interactive Plotting +==================== + +We have looked at the basics of Python. In this section we shall look at the +basics of plotting. + +Lets start our IPython interpreter, by + +:: + + $ ipython -pylab + +Pylab is a python library which provides plotting functionality. It also +provides many other important mathematical and scientific functions. After +running ``ipython -pylab`` in your shell if at the top of the output, you see +something like + +:: + + `ERROR: matplotlib could NOT be imported! Starting normal IPython.` + + +Then you have to install ``python-matplotlib`` and run this command again. + +Let us get started directly and try plotting a cosine curve in the range -pi +to pi. + +:: + + p = linspace(-pi,pi,100) + plot(p, cos(p)) + +As you can see we have obtained a cosine curve in the required range. Let's +try and understand what we have done here. + +The variable ``p`` has a hundred points in the range -pi to pi. To see this, +check the documentation of the linspace command. + +:: + + linspace? + +As you can see, it returns ``num`` evenly spaced samples, calculated over the +interval start and stop. + +You can verify this, by looking at the first and last points of ``p`` and the +length of ``p`` + +:: + + print p[0], p[-1], len(p) + +Now, let's clear the plot we obtained and plot a sine curve in the same +range. + +:: + + clf() + plot(p, sin(p)) + +``clf`` command clears the plot, and the plot command following it, plots the +required curve. + +Let's briefly explore the plot window and look at what features it has. + +Firstly, note that moving the mouse around gives us the point where mouse +points at. + +Also we have some buttons the right most among them is for saving the file. + +Left to the save button is the slider button to specify the margins. + +Left to this is zoom button to zoom into the plot. Just specify the region to +zoom into. + +The button left to it can be used to move the axes of the plot. + +The next two buttons with a left and right arrow icons change the state of +the plot and take it to the previous state it was in. It more or less acts +like a back and forward button in the browser. + +The last one is 'home', which returns the plot to the original view. + +Embellishing Plots +================== + +Now that we know how to make simple plots, let us look at embellishing the +plots. We shall look at how to modify the colour, thickness and line-style of +a plot. We shall then learn how to add title to a plot and then look at +adding labels to x and y axes. We shall also look at adding annotations to the plot and setting the limits on the axes. + +Let us decorate the sine curve that we have already plotted. If you have closed that window or your IPython terminal, redo the plot. + +:: + + p = linspace(-pi,pi,100) + plot(p, sin(p)) + + +As we can see, the default colour and the default thickness of the line is as +decided by pylab. Wouldn't it be nice if we could control these parameters in +the plot? This is possible by passing additional arguments to the plot +command. + +The additional argument that we shall be passing in here now is the color +argument. We shall first clear the figure and plot the same in red color. + +:: + + clf() + plot(p, sin(p), 'r') + +As we can see we have the same plot but now in red color. + +To alter the thickness of the line, we use the ``linewidth`` argument +in the plot command. + +:: + + plot(p, cos(p), linewidth=2) + +produces a plot with a thicker line, to be more precise plot with line +thickness 2. + +Occasionally we would also want to alter the style of line. Sometimes all we +want is just a bunch of points not joined. This is possible by passing the +linestyle argument along with or instead of the colour argument. + +:: + + clf() + plot(p, sin(p), '.') + +produces a plot with only points. + +To produce the same plot but now in blue colour, we do + +:: + + clf() + plot(p, sin(p), 'b.') + +Other available options can be seen in the documentation of plot. + +:: + + plot? + +Now that we know how to produce a bare minimum plot with colour, style and +thickness of our interest, we shall look at decorating the plot. + +Let us start with a plot of the function -x^2 + 4x - 5 in the range -2 to 4. + +:: + + x = linspace(-2, 4, 50) + plot(x, -x*x + 4*x - 5, 'r', linewidth=2) + +We now have the plot in a colour and linewidth of our interest. As you can +see, the figure does not have any description describing the plot. + +We will now add a title to the plot by using the ``title`` command. + +:: + + title("Parabolic function -x^2+4x-5") + +The figure now has a title which describes what the plot is. The ``title`` +command as you can see, takes a string as an argument and sets the title +accordingly. + +The formatting in title is messed and it does not look clean. You can imagine +what would be the situation if there were fractions and more complex +functions like log and exp. Wouldn't it be good if there was LaTeX like +formatting? + +That is also possible by adding a $ sign before and after the part of the +string that should be in LaTeX style. For instance, + +:: + + title("Parabolic function $-x^2+4x-5$") + +gives us the polynomial formatted properly. + +Although we have title, the plot is not complete without labelling x and y +axes. Hence we shall label x-axis to "x" and y-axis to "f(x)" :: + + xlabel("x") + +As you can see, ``xlabel`` command takes a string as an argument, +similar to the ``title`` command and sets it as the label to x-axis. + +.. #[See the diff] + +Similarly, + +:: + + ylabel("f(x)") + +sets the name of the y-axis as "f(x)" + +Let us now see how to name or annotate a point on the plot. For example the +point (2, -1) is the local maxima. We would like to name the point +accordingly. We can do this by using + +:: + + annotate("local maxima", xy=(2, -1)) + +As you can see, the first argument to ``annotate`` command is the name we +would like to mark the point as and the second argument is the co-ordinates +of the point at which the name should appear. It is a sequence containing two +numbers. The first is x co-ordinate and second is y co-ordinate. + +As we can see, every annotate command makes a new annotation on the figure. + +Now we have everything we need to decorate a plot. But, it would be nice to +change the limits of the plot area, so that it looks better. + +We shall look at how to get and set them from the script. We shall first get +the existing limits and then change them as required. + +:: + + xlim() + ylim() + +We see that ``xlim`` function returns the current x axis limits and ylim +function returns the current y-axis limits. + +Let us look at how to set the limits. + +:: + + xlim(-4, 5) + +We see the limits of x-axis are now set to -4 and 5. + +Similarly + +:: + + ylim(-15, 2) + +sets the limits of y-axis appropriately. + +Saving to Scripts +================= + +While we are at it, let's look at how to save all the things we typed into +our interpreter into scripts that can be used anytime we like. + +Let's now look at the history of the commands we have typed. The history can +be retreived by using ``%hist`` command. + +:: + + %hist + + +As you can see, it displays a list of recent commands that we typed. Every +command has a number in front, to specify in which order and when it was +typed. + +Please note that there is a % sign before the hist command. This implies that +``%hist`` is a command that is specific to IPython and not available in the +vanilla Python interpreter. These type of commands are called as magic +commands. + +Also note that, the ``%hist`` itself is a command and is displayed as the +most recent command. We should note that anything we type in is stored as +history, irrespective of whether it is a valid command or an error or an +IPython magic command. + +If we want only the recent 5 commands to be displayed, we pass the number as +an argument to ``%hist`` command. + +:: + + %hist 5 + +displays the recent 5 commands, inclusive of the ``%hist`` command. The +default number is 40. + +To list all the commands between 5 and 10, type + +:: + + %hist 5-10 + +Now that we have the history, we would like to save the required lines of +code from history to reproduce the plot of the parabolic function. This is +possible by using the ``%save`` command. + +Before we do that, let us first look at history and identify what lines of +code we require. + +:: + + %hist + +The first command is linspace. But second command is a command that gave us +an error. Hence we do not need second command. The commands from third to +sixth and eighth are required. + +:: + + %save plot_script.py 1 3-6 8 + +The command saves first and then third to sixth and eighth lines of code into +the specified file. + +The first argument to %save is the path of file to save the commands and the +arguments there after are the commands to be saved in the given order. + +Now that we have the required lines of code in a file, let us learn how to +run the file as a python script. We use the IPython magic command ``%run`` to +do this. + +:: + + %run -i plot_script.py + +The script runs but we do not see the plot. This happens because when we are +running a script and we are not in interactive mode anymore. + +Hence on your IPython terminal type + +:: + + show() + +to show the plot. + +The reason for including a ``-i`` after ``run`` is to tell the interpreter +that if any name is not found in script, search for it in the interpreter. +Hence all these ``sin``, ``plot``, ``pi`` and ``show`` which are not +available in script, are taken from the interpreter and used to run the +script. + +Saving Plots +============ + +Let us now learn to save the plots, from the command line, in different +formats. + +Let us plot a sine curve from minus 3pi to 3pi. + +:: + + x = linspace(-3*pi,3*pi,100) + plot(x,sin(x)) + +As, you can see we now have a sine curve. Let's now see how to save the plot. + +For saving the plot, we will use ``savefig()`` function, and it has to be +done with the plot window open. The statement is, :: + + savefig('sine.png') + +Notice that ``savefig`` function takes one argument which is the filename. +The last 3 characters after the ``.`` in the filename is the extension or +type of the file which determines the format in which you want to save. + +Also, note that we gave the full path or the absolute path to which we +want to save the file. + +Here we have used an extension ``.png`` which means the plot gets saved as a +PNG image. + +You can check file which has been saved as ``sine.png`` + +``savefig`` can save the plot in many formats, such as pdf, ps, eps, svg and +png. + + + +Multiple Plots +============== + +Let us now learn, how to draw more than one plot, how to add legends to each +plot to indicate what each plot represents. We will also learn how to switch +between the plots and create multiple plots with different regular axes which +are also called as subplots. + +Let us first create set of points for our plot. For this we will use the +command called linspace:: + + x = linspace(0, 50, 10) + +As we know, x has 10 points in the interval between 0 and 50 both inclusive. + +Now let us draw a plot simple sine plot using these points + +:: + + plot(x, sin(x)) + +This should give us a nice sine plot. + +Oh! wait! It isn't as nice, as we expected. The curve isn't very smooth, why? +In the ``linspace`` command, we chose too few points in a large interval +between 0 and 50 for the curve to be smooth. So now let us use linspace again +to get 500 points between 0 and 50 and draw the sine plot + +:: + + y = linspace(0, 50, 500) + plot(y, sin(y)) + +Now we see a smooth curve. We can also see that, we have two plots, one +overlaid upon another. Pylab overlays plots by default. + +Since, we have two plots now overlaid upon each other we would like to have a +way to indicate what each plot represents to distinguish between them. This +is accomplished using legends. Equivalently, the legend command does this for +us + +:: + + legend(['sine-10 points', 'sine-500 points']) + +Now we can see the legends being displayed for the respective plots. The +legend command takes a single list of parameters where each parameter is the +text indicating the plots in the order of their serial number. + +Additionally, we could give the ``legend`` command an additional argument to +choose the location of the placement, manually. By default, ``pylab`` places +it in the location it thinks is the best. The example below, places it in the +center of the plot. Look at the doc-string of ``legend`` for other locations. + +:: + + legend(['sine-10 points', 'sine-500 points'], loc='center') + +We now know how to draw multiple plots and use legends to indicate which plot +represents what function, but we would like to have more control over the +plots we draw. Like plot them in different windows, switch between them, +perform some operations or labeling on them individually and so on. Let us +see how to accomplish this. Before we move on, let us clear our screen. + +:: + + clf() + +To accomplishing this, we use the figure command + +:: + + x = linspace(0, 50, 500) + figure(1) + plot(x, sin(x), 'b') + figure(2) + plot(x, cos(x), 'g') + +Now we have two plots, a sine plot and a cosine plot in two different +figures. + +The figure command takes an integer as an argument which is the serial number +of the plot. This selects the corresponding plot. All the plot commands we +run after this are applied to the selected plot. In this example figure 1 is +the sine plot and figure 2 is the cosine plot. We can, for example, save each +plot separately + +:: + + savefig('cosine.png') + figure(1) + title('sin(y)') + savefig('sine.png') + +We also titled our first plot as 'sin(y)' which we did not do for the second +plot. + +Let us now do the following. Draw a line of the form y = x as one figure and +another line of the form y = 2x + 3. Switch back to the first figure, +annotate the x and y intercepts. Now switch to the second figure and annotate +its x and y intercepts. Save each of them. + +To solve this problem we should first create the first figure using +the figure command. Before that, let us first run clf command to make +sure all the previous plots are cleared + +:: + + clf() + figure(1) + x = linspace(-5, 5, 100) + plot(x, x) + +Now we can use figure command to create second plotting area and plot +the figure + +:: + + figure(2) + plot(x, ((2 * x) + 3)) + +Now to switch between the figures we can use figure command. So let us +switch to figure 1. We are asked to annotate x and y intercepts of the +figure 1 but since figure 1 passes through origin we will have to +annotate the origin. We will annotate the intercepts for the second +figure and save them as follows + +:: + + figure(1) + annotate('Origin', xy=(0.0, 0.0) + figure(2) + annotate('x-intercept', xy=(0, 3)) + annotate('y-intercept', xy=(0, -1.5)) + savefig('plot2.png') + figure(1) + savefig('plot1.png') + +We can close the figures from the terminal by using the ``close()`` command. + +:: + + close() + close() + +The first ``close`` command closes figure 1, and the second one closes the +figure 2. We could have also use the ``close`` command with an argument +'all', to close all the figures. + +:: + + close('all') + +At times we run into situations where we want to compare two plots and in +such cases we want to draw both the plots in the same plotting area. The +situation is such that the two plots have different regular axes which means +we cannot draw overlaid plots. In such cases we can draw subplots. + +We use subplot command to accomplish this + +:: + + subplot(2, 1, 1) + +``subplot`` command takes three arguments, number of rows, number of columns +and the plot number, which specifies what subplot must be created now in the +order of the serial number. In this case we passed 1 as the argument, so the +first subplot that is top half is created. If we execute the subplot command +as + +:: + + subplot(2, 1, 2) + +the lower subplot is created. Now we can draw plots in each of the subplot +area using the plot command. + +:: + + x = linspace(0, 50, 500) + plot(x, cos(x)) + + subplot(2, 1, 1) + y = linspace(0, 5, 100) + plot(y, y ** 2) + +This created two plots one in each of the subplot area. The top subplot holds +a parabola and the bottom subplot holds a cosine curve. + +As seen here we can use subplot command to switch between the subplot +as well, but we have to use the same arguments as we used to create +that subplot, otherwise the previous subplot at that place will be +automatically erased. It is clear from the two subplots that both have +different regular axes. For the cosine plot x-axis varies from 0 to +100 and y-axis varies from 0 to 1 where as for the parabolic plot the +x-axis varies from 0 to 10 and y-axis varies from 0 to 100 + +Plotting Data +============= + +We often require to plot points obtained from experimental observations, +instead of the analytic functions that we have been plotting, until now. We +shall now learn to read data from files and read it into sequences that can +later be used to plot. + +We shall use the ``loadtxt`` command to load data from files. We will be +looking at how to read a file with multiple columns of data and load each +column of data into a sequence. + +Now, Let us begin with reading the file ``primes.txt``, which contains just a +list of primes listed in a column, using the loadtxt command. The file, in +our case, is present in ``primes.txt``. + +Now let us read this list into the variable ``primes``. + +:: + + primes = loadtxt('primes.txt') + +``primes`` is now a sequence of primes, that was listed in the file, +``primes.txt``. + +We now type, ``print primes`` to see the sequence printed. + +We observe that all of the numbers end with a period. This is so, because +these numbers are actually read as ``floats``. + +Now, let us use the ``loadtxt`` command to read a file that contains two +columns of data, ``pendulum.txt``. This file contains the length of the +pendulum in the first column and the corresponding time period in the second. +Note that ``loadtxt`` needs both the columns to have equal number of rows. + +Let us, now, read the data into the variable ``pend``. Again, it is +assumed that the file is in our current working directory. + +:: + + pend = loadtxt('pendulum.txt') + +Let us now print the variable ``pend`` and see what's in it. + +:: + + print pend + +Notice that ``pend`` is not a simple sequence like ``primes``. It has a +sequence of items in which each item contains two values. Let us use an +additional argument of the ``loadtxt`` command, to read it into two separate, +simple sequences. We add the argument ``unpack=True`` to the ``loadtxt`` +command. + +:: + + L, T = loadtxt('pendulum.txt', unpack=True) + +Let us now, print the variables L and T, to see what they contain. + +:: + + print L + print T + +Notice, that L and T now contain the first and second columns of data +from the data file, ``pendulum.txt``, and they are both simple +sequences. ``unpack=True`` has given us the two columns into two +separate sequences instead of one complex sequence. + +Now that we have the required data in sequences, let us see how to plot it. + +Since we already have the values of L and T as two different sequences, we +now need to calculate T squared. We shall be plotting L vs. T^2 values. + +To obtain the square of sequence T we will use the function ``square`` + +:: + + Tsq = square(T) + +Now to plot L vs T^2 we will simply type + +:: + + plot(L, Tsq, '.') + +For any experimental data, there is always an error in measurements due to +instrumental and human constraints. Now we shall try and take into account +error into our plots. + +We shall read the read the error values from the file ``pendulum_error.txt`` +along with the L and T values. + +:: + + L, T, L_err, T_err = loadtxt('pendulum_error.txt', unpack=True) + + +Now to plot L vs T^2 with an error bar we use the function ``errorbar()`` + +:: + + errorbar(L, Tsq , xerr=L_err, yerr=T_err, fmt='b.') + +This gives a plot with error bar for x and y axis. The dots are of blue +color. The parameters ``xerr`` and ``yerr`` are error on x and y axis and +``fmt`` is the format of the plot. + + +You can explore other options of ``errorbar`` by looking at it's +documentation. + +:: + + errorbar? + + +Other kinds of Plots +==================== + +We shall now briefly look at a few other kinds of plots, namely, the scatter +plot, the pie chart, the bar chart and the log-log plot. + +Let us start with scatter plot. + +In a scatter plot, the data is displayed as a collection of points, each +having the value of one variable determining the position on the horizontal +axis and the value of the other variable determining the position on the +vertical axis. This kind of plot is also called a scatter chart, a scatter +diagram or a scatter graph. + +Now, let us plot a scatter plot showing the percentage profit of a company A +from the year 2000-2010. The data for the same is available in the file +``company-a-data.txt``. + +The data file has two lines with a set of values in each line, the first line +representing years and the second line representing the profit percentages. + +To produce the scatter plot, we first need to load the data from the file +using ``loadtxt``. + +:: + + year,profit = loadtxt('company-a-data.txt', dtype=int) + +By default loadtxt converts the value to float. The ``dtype=type(int())`` +argument in loadtxt converts the value to integer as we require the data as +integers. + +In-order to generate the scatter graph we will use the function ``scatter()`` + +:: + + scatter(year, profit) + +Notice that we passed two arguments to ``scatter()`` function, first one the +values in x-coordinate, year, and the other the values in y-coordinate, the +profit percentage. + +Now let plot a pie chart for the same data. A pie chart or a circle graph is +a circular chart divided into sectors, illustrating proportion. + +Plot a pie chart representing the profit percentage of company A, with the +same data from file ``company-a-data.txt``. We shall reuse the data we have +already read from the file. + +We can plot the pie chart using the function ``pie()``. + +:: + + pie(profit, labels=year) + +Notice that we passed two arguments to the function ``pie()``. First one the +values and the next one the set of labels to be used in the pie chart. + +Now let us move on to the bar charts. A bar chart or bar graph is a chart +with rectangular bars with lengths proportional to the values that they +represent. + +Plot a bar chart representing the profit percentage of company A, with the +same data from file ``company-a-data.txt``. + +We can plot the bar chart using the function ``bar()``. + +:: + + bar(year, profit) + +Note that the function ``bar()`` needs at least two arguments one the values +in x-coordinate and the other values in y-coordinate which is used to +determine the height of the bars. + +Now let us move on to the log-log plot. A log-log graph or a log-log plot is +a two-dimensional graph of numerical data that uses logarithmic scales on +both the horizontal and vertical axes. + +Due to the nonlinear scaling of the axes, a function of the form y = ax^b +will appear as a straight line on a log-log graph. + +Plot a ``log-log`` chart of y=5*x^3 for x from 1-20. + +Before we actually plot let us calculate the points needed for that. + +:: + + x = linspace(1,20,100) + y = 5*x**3 + +Now we can plot the log-log chart using ``loglog()`` function, + +:: + + loglog(x, y) + +For the sake of clarity, let us make a linear plot of x vs. y. + +:: + + plot(x, y) + +Observing the two plots together should give you some clarity about the +``loglog`` plot. + +Help about matplotlib can be obtained from +http://matplotlib.sourceforge.net/contents.html + +That brings us to the end of the discussion on plots and matplotlib. We have +looked a making simple plots, embellishing plots, saving plots, making +multiple plots, plotting data from files, and a few varieties of plots. + +.. + Local Variables: + mode: rst + indent-tabs-mode: nil + sentence-end-double-space: nil + fill-column: 77 + End: + + diff --git a/lecture-notes/advanced-python/rst.rst b/lecture-notes/advanced-python/rst.rst new file mode 100644 index 0000000..fcbd986 --- /dev/null +++ b/lecture-notes/advanced-python/rst.rst @@ -0,0 +1,277 @@ +ReST +---- + +---------------------------- +The Pythonic way to Document +---------------------------- + +.. author: FOSSEE +.. date: 2010-07-22 Thu + + +What is ReST? +------------- + + + Sage Docs - Linear Algebra | Sources + + ReST is a lightweight markup language. + + Developed by the Python community + + Heavily used in documentation of Python code + +Why ReST? +--------- + + + Highly readable source format. + + Easy to learn and write. + + Simple yet Powerful markup that can produce html/LaTeX output. + +Tools used +---------- + + + You will need python-docutils to compile your ReST documents +:: + + sudo apt-get install python-docutils + + + To build websites, look at Sphinx, rest2web, etc. + + rst2html doesn't support math. We shall use Sphinx to see how math works +:: + + sudo apt-get install python-sphinx + +Generating output +----------------- + + + html:: + + rst2html source.rst destination.html + + + LaTeX :: + + rst2latex source.rst destination.tex + + + Slide shows :: + + rst2s5 source.rst destination.html + +Paragraph +--------- + + + The most basic structural element + + Just a chunk of text separated by blank lines. + + Must begin at the left edge margin. + + Indented paragraphs are output as quoted text. + + Example :: + + Sage provides standard constructions from linear algebra, + e.g., the characteristic polynomial, echelon form, trace, + decomposition, etc., of a matrix. + +Section Headings +---------------- + + + Single line of text with adornment + + Adornment is underline alone or an over- and underline + + ``- = ` : ' " ~ ^ _ * + # < >`` can be used for adornment + + All headings with same adornment are at same level + + **NOTE**- The over/under line should be at least as long as the heading + :: + + Linear Algebra + ============== + + Matrix spaces + ------------- + + Sparse Linear Algebra + --------------------- + + +Text Styles +----------- + + ======================= ==================== + Markup text Resulting text + ======================= ==================== + ``*italics*`` *italics* + ``**strong**`` **strong** + ````inline literal```` ``inline literal`` + ======================= ==================== + + + +Code Samples +------------ + + + To include code, end the prior paragraph with =::= + + Code needs to be indented one level + + The code block ends, when text falls back to the previous indentation + + For instance :: + + For example, each of the following is legal :: + + plot(x, y) # plot x and y using default line style and color + plot(x, y, 'bo') # plot x and y using blue circle markers + plot(y) # plot y using x as index array 0..N-1 + plot(y, 'r+') # ditto, but with red plusses + +Math +---- + + + ReST in itself doesn't support math + + Sphinx has support for math using ~jsmath~ or ~pngmath~ + :: + + :math: `3 \times 3` + + .. math:: + + \sum_{n=0}^N x_n = y + +Lists +----- + + + Three flavors - Enumerated, Bulleted, Definition + + Always start as a new paragraph --- preceeded by a new line + + Enumerated + + Number or Letter followed by a =.=, =)= or surrounded by =( )=. + + :: + + 1) Numbers + #) auto numbered + A. Upper case letters + a) lower case letters + i) roman numerals + (I) more roman numerals + + +Lists ... +--------- + + + Bulleted lists + + Start a line with -, + or * + + :: + + * a bullet point using "*" + + - a sub-list using "-" + + + yet another sub-list + + - another item + +Lists ... +--------- + + + Definition Lists + + * Consist of Term, and it's definition. + * Term is one line phrase; Definition is one or more paragraphs + * Definition is indented relative to the term + * Blank lines are not allowed between term and it's definition + + what + Definition lists associate a term with a definition. + +Tables +------ + + + Simple Tables + + * Each line is a row. + * The table ends with ~=~ + * Column Header is specified by using ~=~ + * Cells may span columns; ~-~ is used to specify cells spanning columns. + +:: + + ============ ============ =========== + Header 1 Header 2 Header 3 + ============ ============ =========== + body row 1 column 2 column 3 + body row 2 Cells may span columns. + ------------ ------------------------ + body row 3 column 2 column 3 + ============ ============ =========== + + +Tables... +--------- + +Grid Tables +----------- + +:: + + +------------+------------+-----------+ + | Header 1 | Header 2 | Header 3 | + +============+============+===========+ + body row 1 column 2 column 3 + +------------+------------+-----------+ + body row 2 Cells may span columns. + +------------+------------+-----------+ + body row 3 Cells may - Cells + +------------+ span rows. - contain + body row 4 - blocks. + +------------+------------+-----------+ + +Links +----- + + + External links + + Python_ is my favorite programming language. + +.. _Python: http://www.python.org/ + + + Internal links + + * To generate a link target, add a label to the location + +.. _example: + * Titles & Section headings automatically produce link targets (in ReST) + * Linking to Target + + in ReST :: + + This is an example_ link. + A Title + ======= + + `A Title`_ automatically generates hyperlink targets. + + + in Sphinx :: + + :ref: `This is an example <example>` link. + This is an :ref: `example` link. + + +Footnotes +--------- +:: + + This[#]_ gives auto-numbered[#]_ footnotes. + + This[*]_ gives auto-symbol footnotes[*]_. + + .. [#] First auto numbered footnote + .. [#] Second auto numbered footnote + .. [*] First auto symbol footnote + .. [*] Second auto symbol footnote + + + +References +---------- + + + An Introduction to reStructured Text -- David Goodger + + Quick reStructuredText + + reStructuredText-- Bits and Pieces -- Christoph Reller + + +.. `An Introduction to reStructured Text`: http://docutils.sourceforge.net/docs/ref/rst/introduction.html +.. `Quick reStructuredText`: http://docutils.sourceforge.net/docs/user/rst/quickref.html +.. `reStructuredText-- Bits and Pieces`: http://people.ee.ethz.ch/~creller/web/tricks/reST.html + diff --git a/lecture-notes/advanced-python/sage.rst b/lecture-notes/advanced-python/sage.rst new file mode 100644 index 0000000..46fcef4 --- /dev/null +++ b/lecture-notes/advanced-python/sage.rst @@ -0,0 +1,947 @@ +Sage notebook +============= + +In this section, we will learn what Sage is, what is Sage notebook, how to +start and use the sage notebook. In the notebook we will be specifically +learning how to execute our code, how to write annotations and other +content, typesetting the content and how to use the offline help available. + +To start with, What is Sage? Sage is a free, open-source mathematical +software. Sage can do a lot of math stuff for you including, but not +limited to, algebra, calculus, geometry, cryptography, graph theory among +other things. It can also be used as aid in teaching and research in any of +the areas that Sage supports. So let us start Sage now + +We are assuming that you have Sage installed on your computer now. If not +please visit the page +http://sagemath.org/doc/tutorial/introduction.html#installation for the +tutorial on how to install Sage. + + +Let us now learn how to start Sage. On the terminal type + +:: + + sage + +This should start a new Sage shell with the prompt sage: which looks like +this + +:: + + sage: + +So now we can type all the commands that Sage supports here. But Sage comes +bundled with a much more elegant tool called Sage Notebook. It provides a +web based user interface to use Sage. So once we have a Sage notebook +server up and running, all we need is a browser to access the Sage +functionality. + +We could also use a server run by somebody, else like the official instance +of the Sage server at http://sagenb.org. So all we need is just a browser, +a modern browser, to use Sage and nothing else! The Sage notebook also +provides a convenient way of sharing and publishing our work, which is very +handy for research and teaching. + +However we can also run our own instances of Sage notebook servers on all +the computers we have a local installation of Sage. To start the notebook +server just type + +:: + + notebook() + +on the Sage prompt. This will start the Sage Notebook server. If we are +starting the notebook server for the first time, we are prompted to enter +the password for the admin. Type the password and make a note of it. After +this Sage automatically starts a browser page, with the notebook opened. + +If it doesn't automatically start a browser page check if the Notebook +server started and there were no problems. If so open your browser and in +the address bar type the URL shown in the instructions upon running the +notebook command on the sage prompt. + +If you are not logged in yet, it shows the Notebook home page and textboxes +to type the username and the password. You can use the username 'admin' and +the password you gave while starting the notebook server for the first +time. There are also links to recover forgotten password and to create new +accounts. + +Once we are logged in with the admin account we can see the notebook admin +page. A notebook can contain a collection of Sage Notebook worksheets. + +Worksheet is basically a working area. This is where we enter all the Sage +commands on the notebook. + +The admin page lists all the worksheets created. On the topmost part of +this page we have the links to various pages. + +The home link takes us to the admin home page. The published link takes us +to the page which lists all the published worksheets. The log link has the +complete log of all the actions we did on the notebook. We have the +settings link where we can configure our notebook, the notebook server, +create and mangage accounts. We have a link to help upon clicking opens a +new window with the complete help of Sage. The entire documentation of Sage +is supplied with Sage for offline reference and the help link is the way to +get into it. Then we can report bugs about Sage by clicking on Report a +Problem link and there is a link to sign out of the notebook. + +We can create a new worksheet by clicking New Worksheet link + +Sage prompts you for a name for the worksheet. Let us name the worksheet as +nbtutorial. Now we have our first worksheet which is empty. + +A worksheet will contain a collection of cells. Every Sage command must be +entered in this cell. Cell is equivalent to the prompt on console. When we +create a new worksheet, to start with we will have one empty cell. Let us +try out some math here + +:: + + 2 + 2 + 57.1 ^ 100 + +The hat operator is used for exponentiation. We can observe that only the +output of the last command is displayed. By default each cell displays the +result of only the last operation. We have to use print statement to +display all the results we want to be displayed. + +Now to perform more operations we want more cells. So how do we create a +new cell? It is very simple. As we hover our mouse above or below the +existing cells we see a blue line, by clicking on this new line we can +create a new cell. + +We have a cell, we have typed some commands in it, but how do we evaluate +that cell? Pressing Shift along with Enter evaluates the cell. +Alternatively we can also click on the evaluate link to evaluate the cell + +:: + + matrix([[1,2], [3,4]])^(-1) + +After we create many cells, we may want to move between the cells. To move +between the cells use Up and Down arrow keys. Also clicking on the cell +will let you edit that particular cell. + +To delete a cell, clear the contents of the cell and hit backspace. + +If you want to add annotations in the worksheet itself on the blue line +that appears on hovering the mouse around the cell, Hold Shift and click on +the line. This creates a *What You See Is What You Get* cell. + +We can make our text here rich text. We can make it bold, Italics, we can +create bulleted and enumerated lists in this area + +:: + + This text contains both the **bold** text and also *italicised* + text. + It also contains bulleted list: + * Item 1 + * Item 2 + It also contains enumerate list: + 1. Item 1 + 2. Item 2 + +In the same cell we can display typeset math using the LaTeX like syntax + +:: + + $\int_0^\infty e^{-x} \, dx$ + +We enclose the math to be typeset within $ and $ or $$ and $$ as in LaTeX. + +We can also obtain help for a particular Sage command or function within +the worksheet itself by using a question mark following the command + +:: + + sin? + +Evaluating this cell gives me the entire help for the sin function inline +on the worksheet itself. Similarly we can also look at the source code of +each command or function using double question mark + +:: + + matrix?? + +Sage notebook also provides the feature for autocompletion. To auto-complete +a command type first few unique characters and hit tab key + +:: + + sudo<tab> + +To see all the commands starting with a specific name type those characters +and hit tab + +:: + + plo<tab> + +To list all the methods that are available for a certain variable or a +data-type we can use the variable name followed by the dot to access the +methods available on it and then hit tab + +:: + + s = 'Hello' + s.rep<tab> + +The output produced by each cell can be one of the three states. It can be +either the full output, or truncated output or hidden output. The output +area will display the error if the Sage code we wrote in the cell did not +successfully execute + +:: + + a, b = 10 + +The default output we obtained now is a truncated output. Clicking at the +left of the output area when the mouse pointer turns to hand gives us the +full output, clicking again makes the output hidden and it cycles. + +Lastly, Sage supports a variety of languages and each cell on the worksheet +can contain code written in a specific language. It is possible to instruct +Sage to interpret the code in the language we have written. This can be +done by putting percentage sign(%) followed by the name of the language. +For example, to interpret the cell as Python code we put + +:: + + %python + +as the first line in the cell. Similarly we have: %sh for shell scripting, +%fortran for Fortran, %gap for GAP and so on. Let us see how this works. +Say we have an integer. The type of the integer in default Sage mode is + +:: + + a = 1 + type(a) + + Output: <type 'sage.rings.integer.Integer'> + +We see that Integers are Sage Integers. Now let us put %python as the first +line of the cell and execute the same code snippet + +:: + + %python + a = 1 + type(a) + + Output: <type 'int'> + +Now we see that the integer is a Python integer. Why? Because now we +instructed Sage to interpret that cell as Python code. + +This brings us to the end of the section on using Sage. + +Symbolics +========= + +In this section, we shall learn to define symbolic expressions in Sage, use +built-in constants and functions, perform integration and differentiation +using Sage, define matrices and symbolic functions and simplify and solve +them. + +In addtion to a lot of other things, Sage can do Symbolic Math and we shall +start with defining symbolic expressions in Sage. + +On the sage notebook type + +:: + + sin(y) + +It raises a name error saying that ``y`` is not defined. We need to declare +``y`` as a symbol. We do it using the ``var`` function. + +:: + + var('y') + +Now if you type + +:: + + sin(y) + +Sage simply returns the expression. + +Sage treats ``sin(y)`` as a symbolic expression. We can use this to do +symbolic math using Sage's built-in constants and expressions. + +Let us try out a few examples. + +:: + + var('x, alpha, y, beta') + (x^2/alpha^2)+(y^2/beta^2) + +We have defined 4 variables, ``x``, ``y``, ``alpha`` and ``beta`` and +have defined a symbolic expression using them. + +Here is an expression in ``theta`` + +:: + + var('theta') + sin(theta)*sin(theta)+cos(theta)*cos(theta) + +Sage also provides built-in constants which are commonly used in +mathematics, for instance pi, e, infinity. The function ``n`` gives the +numerical values of all these constants. + +:: + + n(pi) + n(e) + n(oo) + +If you look into the documentation of function ``n`` by doing + +:: + + n? + +You will see what all arguments it takes and what it returns. It will be +very helpful if you look at the documentation of all functions introduced, +in this section. + +Also we can define the number of digits we wish to have in the constants. +For this we have to pass an argument -- digits. + +:: + + n(pi, digits = 10) + +Apart from the constants Sage also has a lot of built-in functions like +``sin``, ``cos``, ``log``, ``factorial``, ``gamma``, ``exp``, ``arcsin`` +etc ... + +Lets try some of them out on the Sage notebook. + +:: + + sin(pi/2) + + arctan(oo) + + log(e,e) + +Given that we have defined variables like x, y etc., we can define an +arbitrary function with desired name + +:: + + var('x') + function('f',x) + +Here f is the name of the function and x is the independent variable . +Now we can define f(x) to be + +:: + + f(x) = x/2 + sin(x) + +Evaluating this function f for the value x=pi returns pi/2. + +:: + + f(pi) + +We can also define functions that are not continuous but defined piece-wise. +Let us define a function which is a parabola between 0 to 1 and a constant +from 1 to 2 . + +:: + + + var('x') + h(x)=x^2 + g(x)=1 + + f=Piecewise([[(0,1),h(x)],[(1,2),g(x)]],x) + f + +We can also define functions convergent series and other series. + +We first define a function f(n) in the way discussed above. + +:: + + var('n') + function('f', n) + + +To sum the function for a range of discrete values of n, we use the +sage function sum. + +For a convergent series , f(n)=1/n^2 we can say + +:: + + var('n') + function('f', n) + f(n) = 1/n^2 + sum(f(n), n, 1, oo) + + +Lets us now try another series + +:: + + + f(n) = (-1)^(n-1)*1/(2*n - 1) + sum(f(n), n, 1, oo) + +This series converges to pi/4. + +Let's now look at some calculus. + +:: + + diff(x**2 + sin(x), x) + +The diff function differentiates an expression or a function. It's first +argument is expression or function and second argument is the independent +variable. + +We have already tried an expression now lets try a function + +:: + + f = exp(x^2) + arcsin(x) + diff(f(x), x) + +To get a higher order differential we need to add an extra third argument +for order + +:: + + diff(f(x), x, 3) + +in this case it is 3. + +Just like differentiation of expression you can also integrate them + +:: + + x = var('x') + s = integral(1/(1 + (tan(x))**2),x) + s + +Many a times we need to find factors of an expression, we can use the +"factor" function + +:: + + y = (x^100 - x^70)*(cos(x)^2 + cos(x)^2*tan(x)^2) + f = factor(y) + +One can simplify complicated expression + +:: + + f.simplify_full() + +This simplifies the expression fully. We can also do simplification of +just the algebraic part and the trigonometric part + +:: + + f.simplify_exp() + f.simplify_trig() + +One can also find roots of an equation by using ``find_root`` function + +:: + + phi = var('phi') + find_root(cos(phi)==sin(phi),0,pi/2) + +Let's substitute this solution into the equation and see we were +correct + +:: + + var('phi') + f(phi)=cos(phi)-sin(phi) + root=find_root(f(phi)==0,0,pi/2) + f.substitute(phi=root) + +as we can see when we substitute the value the answer is almost = 0 showing +the solution we got was correct. + +Lets us now try some matrix algebra symbolically :: + + var('a,b,c,d') + A=matrix([[a,1,0],[0,b,0],[0,c,d]]) + A + +Now lets do some of the matrix operations on this matrix + +:: + A.det() + A.inverse() + + +That brings us to the end of our discussion on symbolics. + +Plotting using Sage +=================== + +In this section we shall look at + + * 2D plotting in SAGE + * 3D plotting in SAGE + +We shall first create a symbolic variable ``x`` + +:: + + x = var('x') + +We shall plot the function ``sin(x) - cos(x) ^ 2`` in the range (-5, 5). + +:: + + plot(sin(x) - cos(x) ^ 2, (x, -5, 5)) + +As we can see, the plot is shown. + +``plot`` command takes the symbolic function as the first argument and the +range as the second argument. + +We have seen that plot command plots the given function on a linear range. + +What if the x and y values are functions of another variable. For instance, +lets plot the trajectory of a projectile. + +A projectile was thrown at 50 m/s^2 and at an angle of 45 degrees from the +ground. We shall plot the trajectory of the particle for 5 seconds. + +These types of plots can be drawn using the parametric_plot function. We +first define the time variable. + +:: + + t = var('t') + +Then we define the x and y as functions of t. + +:: + + f_x = 50 * cos(pi/4) + f_y = 50 * sin(pi/4) * t - 1/2 * 9.81 * t^2 ) + +We then call the ``parametric_plot`` function as + +:: + + parametric_plot((f_x, f_y), (t, 0, 5)) + +And we can see the trajectory of the projectile. + +The ``parametric_plot`` funciton takes a tuple of two functions as the +first argument and the range over which the independent variable varies as +the second argument. + +Now we shall look at how to plot a set of points. + +We have the ``line`` function to achieve this. + +We shall plot sin(x) at few points and join them. + +First we need the set of points. + +:: + + points = [ (x, sin(x)) for x in srange(-2*float(pi), 2*float(pi), 0.75) ] + +``srange`` takes a start, a stop and a step argument and returns a list of +point. We generate list of tuples in which the first value is ``x`` and +second is ``sin(x)``. + +:: + + line(points) + +plots the points and joins them with a line. + +The ``line`` function behaves like the plot command in matplotlib. The +difference is that ``plot`` command takes two sequences while line command +expects a sequence of co-ordinates. + +As we can see, the axes limits are set by SAGE. Often we would want to set +them ourselves. Moreover, the plot is shown here since the last command +that is executed produces a plot. + +Let us try this example + +:: + + plot(cos(x), (x,0,2*pi)) + # Does the plot show up?? + +As we can see here, the plot is not shown since the last command does not +produce a plot. + +The actual way of showing a plot is to use the ``show`` command. + +:: + + p1 = plot(cos(x), (x,0,2*pi)) + show(p1) + # What happens now?? + +As we can see the plot is shown since we used it with ``show`` command. + +``show`` command is also used set the axes limits. + +:: + + p1 = plot(cos(x), (x,0,2*pi)) + show(p1, xmin=0, xmax=2*pi, ymin=-1.2, ymax=1.2) + +As we can see, we just have to pass the right keyword arguments to the +``show`` command to set the axes limits. + +The ``show`` command can also be used to show multiple plots. + +:: + + p1 = plot(cos(x), (x, 0, 2*pi)) + p2 = plot(sin(x), (x, 0, 2*pi)) + show(p1+p2) + +As we can see, we can add the plots and use them in the ``show`` command. + +Now we shall look at 3D plotting in SAGE. + +We have the ``plot3d`` function that takes a function in terms of two +independent variables and the range over which they vary. + +:: + + x, y = var('x y') + plot3d(x^2 + y^2, (x, 0, 2), (y, 0, 2)) + +We get a 3D plot which can be rotated and zoomed using the mouse. + +``parametric_plot3d`` function plots the surface in which x, y and z are +functions of another variable. + +:: + + u, v = var("u v") + f_x = u + f_y = v + f_z = u^2 + v^2 + parametric_plot3d((f_x, f_y, f_z), (u, 0, 2), (v, 0, 2)) + +Using Sage +========== + +In this section we shall quickly look at a few examples of using Sage for +Linear Algebra, Calculus, Graph Theory and Number theory. + +Let us begin with Calculus. We shall be looking at limits, differentiation, +integration, and Taylor polynomial. + +To find the limit of the function x*sin(1/x), at x=0, we say + +:: + + lim(x*sin(1/x), x=0) + +We get the limit to be 0, as expected. + +It is also possible to the limit at a point from one direction. For +example, let us find the limit of 1/x at x=0, when approaching from the +positive side. + +:: + + lim(1/x, x=0, dir='above') + +To find the limit from the negative side, we say, + +:: + + lim(1/x, x=0, dir='below') + +Let us now see how to differentiate, using Sage. We shall find the +differential of the expression ``exp(sin(x^2))/x`` w.r.t ``x``. We shall +first define the expression, and then use the ``diff`` function to obtain +the differential of the expression. + +:: + + var('x') + f = exp(sin(x^2))/x + + diff(f, x) + +We can also obtain the partial differentiation of an expression w.r.t one +of the variables. Let us differentiate the expression ``exp(sin(y - +x^2))/x`` w.r.t x and y. + +:: + + var('x y') + f = exp(sin(y - x^2))/x + + diff(f, x) + + diff(f, y) + +Now, let us look at integration. We shall use the expression obtained from +the differentiation that we did before, ``diff(f, y)`` --- ``e^(sin(-x^2 + +y))*cos(-x^2 + y)/x``. The ``integrate`` command is used to obtain the +integral of an expression or function. + +:: + + integrate(e^(sin(-x^2 + y))*cos(-x^2 + y)/x, y) + +We get back the correct expression. The minus sign being inside or outside +the ``sin`` function doesn't change much. + +Now, let us find the value of the integral between the limits 0 and pi/2. + +:: + + integral(e^(sin(-x^2 + y))*cos(-x^2 + y)/x, y, 0, pi/2) + +Let us now see how to obtain the Taylor expansion of an expression using +sage. Let us obtain the Taylor expansion of ``(x + 1)^n`` up to degree 4 +about 0. + +:: + + var('x n') + taylor((x+1)^n, x, 0, 4) + +This brings us to the end of the features of Sage for Calculus, that we +will be looking at. For more, look at the Calculus quick-ref from the Sage +Wiki. + +Next let us move on to Matrix Algebra. + +Let us begin with solving the equation ``Ax = v``, where A is the matrix +``matrix([[1,2],[3,4]])`` and v is the vector ``vector([1,2])``. + +To solve the equation, ``Ax = v`` we simply say + +:: + + x = solve_right(A, v) + +To solve the equation, ``xA = v`` we simply say + +:: + + x = solve_left(A, v) + +The left and right here, denote the position of ``A``, relative to x. + +Now, let us look at Graph Theory in Sage. + +We shall look at some ways to create graphs and some of the graph families +available in Sage. + +The simplest way to define an arbitrary graph is to use a dictionary of +lists. We create a simple graph by + +:: + + G = Graph({0:[1,2,3], 2:[4]}) + +We say + +:: + + G.show() + +to view the visualization of the graph. + +Similarly, we can obtain a directed graph using the ``DiGraph`` function. + +:: + + G = DiGraph({0:[1,2,3], 2:[4]}) + + +Sage also provides a lot of graph families which can be viewed by typing +``graph.<tab>``. Let us obtain a complete graph with 5 vertices and then +show the graph. + +:: + + G = graphs.CompleteGraph(5) + + G.show() + +Sage provides other functions for Number theory and Combinatorics. Let's +have a glimpse of a few of them. + +:: + + prime_range(100, 200) + +gives primes in the range 100 to 200. + +:: + + is_prime(1999) + +checks if 1999 is a prime number or not. + +:: + + factor(2001) + +gives the factorized form of 2001. + +:: + + C = Permutations([1, 2, 3, 4]) + C.list() + +gives the permutations of ``[1, 2, 3, 4]`` + +:: + + C = Combinations([1, 2, 3, 4]) + C.list() + +gives all the combinations of ``[1, 2, 3, 4]`` + +That brings us to the end of this session showing various features +available in Sage. + +Using Sage to Teach +=================== + +In this section, we shall look at + + * How to use the "@interact" feature of SAGE for better demonstration + * How to use SAGE for collaborative learning + +Let us look at a typical example of demonstrating a damped oscillation. + +:: + + t = var('t') + p1 = plot( e^(-t) * sin(2*t), (t, 0, 15)) + show(p1) + +Now let us reduce the damping factor + +:: + + t = var('t') + p1 = plot(e^(-t/2) * sin(2*t), (t, 0, 15)) + show(p1) + +Now if we want to reduce the damping factor even more, we would be using +e^(-t/3). We can observe that every time we have to change, all we do is +change something very small and re evaluate the cell. + +This process can be simplified, using the ``@interact`` feature of SAGE. + +:: + + @interact + def plot_damped(n=1): + t = var('t') + p1 = plot( e^(-t/n) * sin(2*t), (t, 0, 20)) + show(p1) + +We can see that the function is evaluated and the plot is shown. We can +also see that there is a field to enter the value of ``n`` and it is +currently set to ``1``. Let us change it to 2 and hit enter. + +We see that the new plot with reduced damping factor is shown. Similarly we +can change ``n`` to any desired value and hit enter and the function will +be evaluated. + +This is a very handy tool while demonstrating or teaching. + +Often we would want to vary a parameter over range instead of taking it as +an input from the user. For instance we do not want the user to give ``n`` +as 0 for the damping oscillation we discussed. In such cases we use a range +of values as the default argument. + +:: + + @interact + def plot_damped(n=(1..10)): + t = var('t') + p1 = plot( e^(-t/n) * sin(2*t), (t, 0, 20)) + show(p1) + +We get similar plot but the only difference is the input widget. Here it is +a slider unlike an input field. We can see that as the slider is moved, the +function is evaluated and plotted accordingly. + +Sometimes we want the user to have only a given set of options. We use a +list of items as the default argument in such situations. + +:: + + @interact + def str_shift(s="STRING", shift=(0..8), direction=["Left", "Right"]): + shift_len = shift % len(s) + chars = list(s) + if direction == "Right": + shifted_chars = chars[-shift_len:] + chars[:-shift_len] + else: + shifted_chars = chars[shift_len:] + chars[:shift_len] + print "Actual String:", s + print "Shifted String:", "".join(shifted_chars) + +We can see that buttons are displayed which enables us to select from a +given set of options. + +We have learnt how to use the ``@interact`` feature of SAGE for better +demonstration. We shall look at how to use SAGE worksheets for +collaborative learning. + +The first feature we shall see is the ``publish`` feature. Open a worksheet +and in the top right, we can see a button called ``publish``. Click on that +and we get a confirmation page with an option for re publishing. + +For now lets forget that option and simply publish by clicking ``yes``. The +worksheet is now published. + +Now lets sign out and go to the sage notebook home. We see link to browse +published worksheets. Lets click on it and we can see the worksheet. This +does not require login and anyone can view the worksheet. + +Alternatively, if one wants to edit the sheet, there is a link on top left +corner that enables the user to download a copy of the sheet onto their +home. This way they can edit a copy of the worksheet. + +We have learnt how to publish the worksheets to enable users to edit a +copy. Next, we shall look at how to enable users to edit the actual +worksheet itself. + +Let us open the worksheet and we see a link called ``share`` on the top +right corner of the worksheet. Click the link and we get a box where we can +type the usernames of users whom we want to share the worksheet with. We +can even specify multiple users by seperating their names using commas. +Once we have shared the worksheet, the worksheet appears on the home of +shared users. + +.. + Local Variables: + mode: rst + indent-tabs-mode: nil + sentence-end-double-space: nil + fill-column: 75 + End: diff --git a/lecture-notes/advanced-python/scipy.rst b/lecture-notes/advanced-python/scipy.rst new file mode 100644 index 0000000..fd0508a --- /dev/null +++ b/lecture-notes/advanced-python/scipy.rst @@ -0,0 +1,270 @@ +In this section we shall look at using scipy to do various common +scientific computation tasks. We shall be looking at solving equations +(linear and non-linear) and solving ODEs. We shall also briefly look at +FFTs. + +Solving Equations +================= + +Let us begin with solving equations, specifically linear equations. + +Consider the set of equations, +:: + + 3x + 2y -z = 1, + 2x-2y + 4z = -2, + -x+ 1/2 y-z = 0 + +We shall use the ``solve`` function, to solve the given system of linear +equations. ``solve`` requires the coefficients and the constants to be in +the form of matrices, of the form ``Ax = b`` to solve the system. + +We begin by entering the coefficients and the constants as matrices. + +:: + + A = array([[3,2,-1], + [2,-2,4], + [-1, 0.5, -1]]) + +A is a 3X3 matrix of the coefficients of x, y and z + +:: + + b = array([1, -2, 0]) + +Now, we can use the solve function to solve the given system. + +:: + + x = solve(A, b) + +Type x, to look at the solution obtained. + +The equation is of the form ``Ax = b``, so we verify the solution by +obtaining a matrix product of ``A`` and ``x``, and comparing it with ``b``. +As we have seen earlier, we should use the dot function, for a matrix +product and not the * operator. + +:: + + Ax = dot(A, x) + Ax + +The result ``Ax``, doesn't look exactly like ``b``, but if we carefully +observe, we will see that it is the same as ``b``. To save ourself all this +trouble, we can use the ``allclose`` function. + +``allclose`` checks if two matrices are close enough to each other (with-in +the specified tolerance level). Here we shall use the default tolerance +level of the function. + +:: + allclose(Ax, b) + +The function returns ``True``, which implies that the product of ``A`` & +``x`` is very close to the value of ``b``. This validates our solution. + +Let's move to finding the roots of a polynomial. We shall use the ``roots`` +function for this. + +The function requires an array of the coefficients of the polynomial in the +descending order of powers. Consider the polynomial x^2-5x+6 = 0 + +:: + + coeffs = [1, -5, 6] + roots(coeffs) + +As we can see, roots returns the result in an array. It even works for +polynomials with imaginary roots. + +:: + + roots([1, 1, 1]) + +As you can see, the roots of that equation are complex. + +What if, we want the solution of non linear equations? + +For that we shall use the ``fsolve`` function. We shall use the equation +sin(x)+cos^2(x), as an example. ``fsolve`` is not part of the pylab package +which we imported at the beginning, so we will have to import it. It is +part of ``scipy`` package. Let's import it, + +:: + + from scipy.optimize import fsolve + +We shall look at the details of importing, later. + +Now, let's look at the documentation of fsolve by typing fsolve? + +:: + + fsolve? + +As mentioned in documentation the first argument, ``func``, is a python +function that takes atleast one argument. The second argument, ``x0``, is +the initial estimate of the roots of the function. Based on this initial +guess, ``fsolve`` returns a root. + +Let's define a function called f, that returns the value of +``(sin(x)+cos^2(x))`` evaluated at the input value ``x``. + +:: + + def f(x): + return sin(x)+cos(x)*cos(x) + +We can test our function, by calling it with an argument for which the +output value is known, say x = 0. We can see that + +Let's check our function definition, by calling it with 0 as an argument. + +:: + + f(0) + + +We can see that the output is 1 as expected, since sin(x) + cos^2(x) has a +value of 1, when x = 0. + +Now, that we have our function, we can use ``fsolve`` to obtain a root of +the expression sin(x)+cos^2(x). Let's use 0 as our initial guess. + +:: + + fsolve(f, 0) + +fsolve has returned a root of sin(x)+cos^2(x) that is close to 0. + +That brings us to the end of our discussion on solving equations. We +discussed solution of linear equations, finding roots of polynomials and +non-linear equations. + + +ODEs +==== + +Let's see how to solve Ordinary Differential Equations (ODEs), using +Python. Let's consider the classic problem of the spread of an epidemic in +a population, as an example. + +This is given by the ordinary differential equation ``dy/dt = ky(L-y)`` +where L is the total population and k is an arbitrary constant. + +For our problem, let us use L=250000, k=0.00003. Let the boundary condition +be y(0)=250. + +We shall use the ``odeint`` function to solve this ODE. As before, this +function resides in a submodule of SciPy and doesn't come along with Pylab. +We import it, +:: + + from scipy.integrate import odeint + +We can represent the given ODE as a Python function. This function takes +the dependent variable y and the independent variable t as arguments and +returns the ODE. + +:: + + def epid(y, t): + k = 0.00003 + L = 250000 + return k*y*(L-y) + +Independent variable t can be assigned the values in the interval of 0 and +12 with 60 points using linspace: + + In []: t = linspace(0, 12, 60) + +Now obtaining the solution of the ode we defined, is as simple as calling +the Python's ``odeint`` function which we just imported + +:: + + y = odeint(epid, 250, t) + +We can plot the the values of y against t to get a graphical picture our ODE. + +:: + + plot(y, t) + +Let's now try and solve an ODE of second order. Let's take the example of a +simple pendulum. + +The equations can be written as a system of two first order ODEs + + d(theta)/dt = omega + +and + + d(omega)/dt = - g/L sin(theta) + +Let us define the boundary conditions as: at t = 0, theta = theta-naught = +10 degrees and omega = 0 + +Let us first define our system of equations as a Python function, +``pend_int``. As in the earlier case of single ODE we shall use ``odeint`` +function to solve this system of equations. + +:: + + def pend_int(initial, t): + theta = initial[0] + omega = initial[1] + g = 9.81 + L = 0.2 + f=[omega, -(g/L)*sin(theta)] + return f + +It takes two arguments. The first argument itself containing two dependent +variables in the system, theta and omega. The second argument is the +independent variable t. + +In the function we assign the first and second values of the initial +argument to theta and omega respectively. Acceleration due to gravity, as +we know is 9.81 meter per second sqaure. Let the length of the the pendulum +be 0.2 meter. + +We create a list, f, of two equations which corresponds to our two ODEs, +that is ``d(theta)/dt = omega`` and ``d(omega)/dt = - g/L sin(theta)``. We +return this list of equations f. + +Now we can create a set of values for our time variable t over which we need +to integrate our system of ODEs. Let us say, + +:: + + t = linspace(0, 20, 100) + +We shall assign the boundary conditions to the variable initial. + +:: + + initial = [10*2*pi/360, 0] + +Now solving this system is just a matter of calling the odeint function with +the correct arguments. + +:: + + pend_sol = odeint(pend_int, initial,t) + + plot(pend_sol) + +This gives us 2 plots, omega vs t and theta vs t. + +That brings us to the end of our discussion on ODEs and solving them in +Python. + +.. + Local Variables: + mode: rst + indent-tabs-mode: nil + sentence-end-double-space: nil + fill-column: 75 + End: diff --git a/lecture-notes/advanced-python/slides/arrays.tex b/lecture-notes/advanced-python/slides/arrays.tex new file mode 100644 index 0000000..e4501c8 --- /dev/null +++ b/lecture-notes/advanced-python/slides/arrays.tex @@ -0,0 +1,341 @@ +\section{Arrays} + +\begin{frame}[fragile] + \frametitle{Arrays: Introduction} + \begin{itemize} + \item Similar to lists, but homogeneous + \item Much faster than arrays + \end{itemize} + \begin{lstlisting} + In[]: a1 = array([1,2,3,4]) + In[]: a1 # 1-D + In[]: a2 = array([[1,2,3,4],[5,6,7,8]]) + In[]: a2 # 2-D + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{arange} and \texttt{shape}} + \begin{lstlisting} + In[]: ar1 = arange(1, 5) + In[]: ar2 = arange(1, 9) + In[]: print ar2 + In[]: ar2.shape = 2, 4 + In[]: print ar2 + \end{lstlisting} + \begin{itemize} + \item \texttt{linspace} and \texttt{loadtxt} also returned arrays + \end{itemize} + \begin{lstlisting} + In[]: ar1.shape + In[]: ar2.shape + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Special methods} + \begin{lstlisting} + In[]: identity(3) + \end{lstlisting} + \begin{itemize} + \item array of shape (3, 3) with diagonals as 1s, rest 0s + \end{itemize} + \begin{lstlisting} + In[]: zeros((4,5)) + \end{lstlisting} + \begin{itemize} + \item array of shape (4, 5) with all 0s + \end{itemize} + \begin{lstlisting} + In[]: a = zeros_like([1.5, 1, 2, 3]) + In[]: print a, a.dtype + \end{lstlisting} + \begin{itemize} + \item An array with all 0s, with similar shape and dtype as argument + \item Homogeneity makes the dtype of a to be float + \item \texttt{ones, ones\_like, empty, empty\_like} + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Operations on arrays} + \begin{lstlisting} + In[]: a1 + In[]: a1 * 2 + In[]: a1 + \end{lstlisting} + \begin{itemize} + \item The array is not changed; New array is returned + \end{itemize} + \begin{lstlisting} + In[]: a1 + 3 + In[]: a1 - 7 + In[]: a1 / 2.0 + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Operations on arrays \ldots} + \begin{itemize} + \item Like lists, we can assign the new array, the old name + \end{itemize} + \begin{lstlisting} + In[]: a1 = a1 + 2 + In[]: a1 + \end{lstlisting} + \begin{itemize} + \item \alert{Beware of Augmented assignment!} + \end{itemize} + \begin{lstlisting} + In[]: a, b = arange(1, 5), arange(1, 5) + In[]: print a, a.dtype, b, b.dtype + In[]: a = a/2.0 + In[]: b /= 2.0 + In[]: print a, a.dtype, b, b.dtype + \end{lstlisting} + \begin{itemize} + \item Operations on two arrays; element-wise + \end{itemize} + \begin{lstlisting} + In[]: a1 + a1 + In[]: a1 * a2 + \end{lstlisting} +\end{frame} + +\section{Accessing pieces of arrays} + +\begin{frame}[fragile] + \frametitle{Accessing \& changing elements} + \begin{lstlisting} + In[]: A = array([12, 23, 34, 45, 56]) + + In[]: C = array([[11, 12, 13, 14, 15], + [21, 22, 23, 24, 25], + [31, 32, 33, 34, 35], + [41, 42, 43, 44, 45], + [51, 52, 53, 54, 55]]) + + In[]: A[2] + In[]: C[2, 3] + \end{lstlisting} + \begin{itemize} + \item Indexing starts from 0 + \item Assign new values, to change elements + \end{itemize} + \begin{lstlisting} + In[]: A[2] = -34 + In[]: C[2, 3] = -34 + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Accessing rows} + \begin{itemize} + \item Indexing works just like with lists + \end{itemize} + \begin{lstlisting} + In[]: C[2] + In[]: C[4] + In[]: C[-1] + \end{lstlisting} + \begin{itemize} + \item Change the last row into all zeros + \end{itemize} + \begin{lstlisting} + In[]: C[-1] = [0, 0, 0, 0, 0] + \end{lstlisting} + OR + \begin{lstlisting} + In[]: C[-1] = 0 + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Accessing columns} + \begin{lstlisting} + In[]: C[:, 2] + In[]: C[:, 4] + In[]: C[:, -1] + \end{lstlisting} + \begin{itemize} + \item The first parameter is replaced by a \texttt{:} to specify we + require all elements of that dimension + \end{itemize} + \begin{lstlisting} + In[]: C[:, -1] = 0 + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Slicing} + \begin{lstlisting} + In[]: I = imread('squares.png') + In[]: imshow(I) + \end{lstlisting} + \begin{itemize} + \item The image is just an array + \end{itemize} + \begin{lstlisting} + In[]: print I, I.shape + \end{lstlisting} + \begin{enumerate} + \item Get the top left quadrant of the image + \item Obtain the square in the center of the image + \end{enumerate} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Slicing \ldots} + \begin{itemize} + \item Slicing works just like with lists + \end{itemize} + \begin{lstlisting} + In[]: C[0:3, 2] + In[]: C[2, 0:3] + In[]: C[2, :3] + \end{lstlisting} + \begin{lstlisting} + In[]: imshow(I[:150, :150]) + + In[]: imshow(I[75:225, 75:225]) + \end{lstlisting} +\end{frame} + +\begin{frame} +\frametitle{Image after slicing} +\includegraphics[scale=0.45]{../advanced_python/images/slice.png}\\ +\end{frame} + + + +\begin{frame}[fragile] + \frametitle{Striding} + \begin{itemize} + \item Compress the image to a fourth, by dropping alternate rows and + columns + \item We shall use striding + \item The idea is similar to striding in lists + \end{itemize} + \begin{lstlisting} + In[]: C[0:5:2, 0:5:2] + In[]: C[::2, ::2] + In[]: C[1::2, ::2] + \end{lstlisting} + \begin{itemize} + \item Now, the image can be shrunk by + \end{itemize} + \begin{lstlisting} + In[]: imshow(I[::2, ::2]) + \end{lstlisting} +\end{frame} + +\section{Matrix Operations} + +\begin{frame}[fragile] + \frametitle{Matrix Operations using \texttt{arrays}} + We can perform various matrix operations on \texttt{arrays}\\ + A few are listed below. + + \begin{center} + \begin{tabular}{lll} + Operation & How? & Example \\ + \hline + Transpose & \texttt{.T} & \texttt{A.T} \\ + Product & \texttt{dot} & \texttt{dot(A, B)} \\ + Inverse & \texttt{inv} & \texttt{inv(A)} \\ + Determinant & \texttt{det} & \texttt{det(A)} \\ + Sum of all elements & \texttt{sum} & \texttt{sum(A)} \\ + Eigenvalues & \texttt{eigvals} & \texttt{eigvals(A)} \\ + Eigenvalues \& Eigenvectors & \texttt{eig} & \texttt{eig(A)} \\ + Norms & \texttt{norm} & \texttt{norm(A)} \\ + SVD & \texttt{svd} & \texttt{svd(A)} \\ + \end{tabular} + \end{center} +\end{frame} + +\section{Least square fit} + +\begin{frame}[fragile] + \frametitle{Least Square Fit} + \begin{lstlisting} + In[]: L, t = loadtxt("pendulum.txt", + unpack=True) + In[]: L + In[]: t + In[]: tsq = t * t + In[]: plot(L, tsq, 'bo') + In[]: plot(L, tsq, 'r') + \end{lstlisting} + \begin{itemize} + \item Both the plots, aren't what we expect -- linear plot + \item Enter Least square fit! + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Matrix Formulation} + \begin{itemize} + \item We need to fit a line through points for the equation $T^2 = m \cdot L+c$ + \item In matrix form, the equation can be represented as $T_{sq} = A \cdot p$, where $T_{sq}$ is + $\begin{bmatrix} + T^2_1 \\ + T^2_2 \\ + \vdots\\ + T^2_N \\ + \end{bmatrix}$ + , A is + $\begin{bmatrix} + L_1 & 1 \\ + L_2 & 1 \\ + \vdots & \vdots\\ + L_N & 1 \\ + \end{bmatrix}$ + and p is + $\begin{bmatrix} + m\\ + c\\ + \end{bmatrix}$ + \item We need to find $p$ to plot the line + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Least Square Fit Line} + \begin{lstlisting} + In[]: A = array((L, ones_like(L))) + In[]: A.T + In[]: A + \end{lstlisting} + \begin{itemize} + \item We now have \texttt{A} and \texttt{tsq} + \end{itemize} + \begin{lstlisting} + In[]: result = lstsq(A, tsq) + \end{lstlisting} + \begin{itemize} + \item Result has a lot of values along with m and c, that we need + \end{itemize} + \begin{lstlisting} + In[]: m, c = result[0] + In[]: print m, c + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Least Square Fit Line} + \begin{itemize} + \item Now that we have m and c, we use them to generate line and plot + \end{itemize} + \begin{lstlisting} + In[]: tsq_fit = m * L + c + In[]: plot(L, tsq, 'bo') + In[]: plot(L, tsq_fit, 'r') + \end{lstlisting} +\end{frame} + +\begin{frame} +\frametitle{Least Square Fit Line} +\includegraphics[scale=0.45]{../advanced_python/images/lst-sq-fit.png}\\ +\end{frame} + + diff --git a/lecture-notes/advanced-python/slides/lambda.tex b/lecture-notes/advanced-python/slides/lambda.tex new file mode 100644 index 0000000..25c4f97 --- /dev/null +++ b/lecture-notes/advanced-python/slides/lambda.tex @@ -0,0 +1,189 @@ +\section{Functional programming} + +\begin{frame}[fragile] + \frametitle{List Comprehensions} + \begin{itemize} + \item A different style of Programming + \item Functions `emulate' mathematical functions + \item Output depends only on input arguments + \item There is no `state' associated with the program + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{List Comprehensions} + \begin{block}{} + Given a list of weights of people, and we need to + calculate the corresponding weights on the moon. Return a new + list, with each of the values divided by 6.0. + \end{block} + + \begin{itemize} + \item Solution using \texttt{for} loop is shown + \end{itemize} + \begin{lstlisting} + weights = [30, 45.5, 78, 81, 55.5, 62.5] + weights_moon = [] + for w in weights: + weights_moon.append(w/6.0) + print weights_moon + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{List Comprehensions \ldots} + \begin{itemize} + \item List comprehensions are compact and readable + \end{itemize} + \begin{lstlisting} + [ w/6.0 for w in weights ] + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{List Comprehensions \ldots} + \begin{itemize} + \item Return the weight on moon, only if weight on earth > 50 + \end{itemize} + \begin{lstlisting} + weights = [30, 45.5, 78, 81, 55.5, 62.5] + weights_moon = [] + for w in weights: + if w > 50: + weights_moon.append(w/6.0) + + print weights_moon + \end{lstlisting} + \begin{itemize} + \item List comprehension that checks for a condition + \end{itemize} + \begin{lstlisting} + [ w/6.0 for w in weights if w>50 ] + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{List Comprehensions \ldots} + \begin{itemize} + \item if weight > 50, return weight/6.0 + \item else, return weight*3.0 + \end{itemize} + \begin{lstlisting} + weights = [30, 45.5, 78, 81, 55.5, 62.5] + weights_migrate = [] + for w in weights: + if w > 50: + weights_migrate.append(w/6.0) + else: + weights_migrate.append(w * 3.0) + + print weights_migrate + \end{lstlisting} + \begin{itemize} + \item This problem \alert{CANNOT} be solved using list + comprehensions + \item Try \texttt{map} + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{map}} + \begin{itemize} + \item Takes a function and a sequence as arguments + \item Calls function with each element of sequence as argument + \item Returns a sequence with all the results as elements + \item We solve the easier problem first, using \texttt{map} + \end{itemize} + + \begin{lstlisting} + def moonize(weight): + return weight/6.0 + + map(moonize, weights) + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{map} \ldots} + \begin{lstlisting} + def migrate(weight): + if weight < 50: + return weight*3.0 + else: + return weight/6.0 + \end{lstlisting} + + \begin{itemize} + \item \texttt{migrate} compares weight with 50 and returns the + required value. + \item We can now use \texttt{map} + \end{itemize} + \begin{lstlisting} + map(migrate, weights) + \end{lstlisting} + \begin{itemize} + \item Now, we wish to get away with the function definition + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{lambda}} + \begin{itemize} + \item Allows function definition, anonymously + \end{itemize} + \begin{lstlisting} + map(lambda x: x/6.0, weights) + \end{lstlisting} + \begin{itemize} + \item \texttt{lambda} actually returns a function which we could in + fact assign to a name and use later. + \end{itemize} + \begin{lstlisting} + l_moonize = lambda x: x/6.0 + map(l_moonize, weights) + \end{lstlisting} + \begin{lstlisting} + l_migrate = lambda x: x*3.0 if x < 50 else x/6.0 + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{filter}} + + \begin{itemize} + \item We avoided discussion of problem of returning new weights only + when actual weight is more than 50. + \item \texttt{filter} can be used to filter out ``bad'' weights + \item Later, we could use \texttt{map} + \end{itemize} + \begin{lstlisting} + filter(lambda x: x > 50, weights) + \end{lstlisting} + \begin{itemize} + \item Takes a function and a sequence + \item Returns a sequence, containing only those elements of the + original sequence, for which the function returned \texttt{True} + \end{itemize} + \begin{lstlisting} + map(lambda x: x/6.0, filter(lambda x: x > 50, weights)) + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{reduce}} + \begin{itemize} + \item ``reduces'' a sequence + \end{itemize} + \begin{lstlisting} + reduce(lambda x,y: x*y, [1, 2, 3, 4]) + \end{lstlisting} + \begin{itemize} + \item Takes function and sequence as arguments; the function should + take two arguments + \item Passes first two elements of sequence, and continues to move + over the sequence, passing the output in the previous step and the + current element as the arguments + \item The function above essentially calculates $((1*2)*3)*4$ + \end{itemize} +\end{frame} + diff --git a/lecture-notes/advanced-python/slides/modules.tex b/lecture-notes/advanced-python/slides/modules.tex new file mode 100644 index 0000000..d6de640 --- /dev/null +++ b/lecture-notes/advanced-python/slides/modules.tex @@ -0,0 +1,163 @@ +\section{Using Python modules} + +\begin{frame}[fragile] + \frametitle{\texttt{hello.py}} + \begin{itemize} + \item Script to print `hello world' -- \texttt{hello.py} + \end{itemize} + \begin{lstlisting} + print "Hello world!" + \end{lstlisting} + \begin{itemize} + \item We have been running scripts from IPython + \end{itemize} + \begin{lstlisting} + In[]: %run -i hello.py + \end{lstlisting} + \begin{itemize} + \item Now, we run from the shell using python + \end{itemize} + \begin{lstlisting} + $ python hello.py + \end{lstlisting} %$ +\end{frame} + +\begin{frame}[fragile] + \frametitle{Simple plot} + \begin{itemize} + \item Save the following in \texttt{sine\_plot.py} + \end{itemize} + \begin{lstlisting} + x = linspace(-2*pi, 2*pi, 100) + plot(x, sin(x)) + show() + \end{lstlisting} + \begin{itemize} + \item Now, let us run the script + \end{itemize} + \begin{lstlisting} + $ python sine_plot.py + \end{lstlisting} % $ + \begin{itemize} + \item What's wrong? + \end{itemize} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{Importing} + \begin{itemize} + \item \texttt{-pylab} is importing a lot of functionality + \item Add the following to the top of your file + \end{itemize} + \begin{lstlisting} + from scipy import * + \end{lstlisting} + \begin{lstlisting} + $ python sine_plot.py + \end{lstlisting} % $ + \begin{itemize} + \item Now, plot is not found + \item Add the following as the second line of your script + \end{itemize} + \begin{lstlisting} + from pylab import * + \end{lstlisting} + \begin{lstlisting} + $ python sine_plot.py + \end{lstlisting} % $ + \begin{itemize} + \item It works! + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Importing \ldots} + \begin{itemize} + \item \texttt{*} imports everything from \texttt{scipy} and + \texttt{pylab} + \item But, It imports lot of unnecessary stuff + \item And two modules may contain the same name, causing a conflict + \item There are two ways out + \end{itemize} + \begin{lstlisting} + from scipy import linspace, pi, sin + from pylab import plot, show + \end{lstlisting} + \begin{itemize} + \item OR change the imports to following and + \item Replace \texttt{pi} with \texttt{scipy.pi}, etc. + \end{itemize} + \begin{lstlisting} + import scipy + import pylab + \end{lstlisting} +\end{frame} + +\section{Writing modules} + +\begin{frame}[fragile] + \frametitle{GCD script} + \begin{itemize} + \item Function that computes gcd of two numbers + \item Save it as \texttt{gcd\_script.py} + \end{itemize} + \begin{lstlisting} + def gcd(a, b): + while b: + a, b = b, a%b + return a + \end{lstlisting} + \begin{itemize} + \item Also add the tests to the file + \end{itemize} + \begin{lstlisting} + if gcd(40, 12) == 4 and gcd(12, 13) == 1: + print "Everything OK" + else: + print "The GCD function is wrong" + \end{lstlisting} + \begin{lstlisting} + $ python gcd_script.py + \end{lstlisting} % $ +\end{frame} + +\begin{frame}[fragile] + \frametitle{Python path} + \begin{itemize} + \item In IPython type the following + \end{itemize} + \begin{lstlisting} + import sys + sys.path + \end{lstlisting} + \begin{itemize} + \item List of locations where python searches for a module + \item \texttt{import sys} -- searches for file \texttt{sys.py} or + dir \texttt{sys} in all these locations + \item So, our own modules can be in any one of the locations + \item Current working directory is one of the locations + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{\_\_name\_\_}} + \begin{lstlisting} + import gcd_script + \end{lstlisting} + \begin{itemize} + \item The import is successful + \item But the test code, gets run + \item Add the tests to the following \texttt{if} block + \end{itemize} + \begin{lstlisting} + if __name__ == "__main__": + \end{lstlisting} + \begin{itemize} + \item Now the script runs properly + \item As well as the import works; test code not executed + \item \texttt{\_\_name\_\_} is local to every module and is equal + to \texttt{\_\_main\_\_} only when the file is run as a script. + \end{itemize} +\end{frame} + diff --git a/lecture-notes/advanced-python/slides/oop.tex b/lecture-notes/advanced-python/slides/oop.tex new file mode 100644 index 0000000..bdb983c --- /dev/null +++ b/lecture-notes/advanced-python/slides/oop.tex @@ -0,0 +1,226 @@ +\section{Object Oriented Programming} + +\begin{frame}[fragile] + \frametitle{Objectives} + At the end of this section, you will be able to - + \begin{itemize} + \item Understand the differences between Object Oriented Programming + and Procedural Programming + \item Appreciate the need for Object Oriented Programming + \item Read and understand Object Oriented Programs + \item Write simple Object Oriented Programs + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Example: Managing Talks} + \begin{itemize} + \item A list of talks at a conference + \item We want to manage the details of the talks + \end{itemize} + \begin{lstlisting} + talk = {'Speaker': 'Guido van Rossum', + 'Title': 'The History of Python' + 'Tags': 'python,history,C,advanced'} + + def get_first_name(talk): + return talk['Speaker'].split()[0] + + def get_tags(talk): + return talk['Tags'].split(',') + \end{lstlisting} + \begin{itemize} + \item Not convenient to handle large number of talks + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Objects and Methods} + \begin{itemize} + \item Objects group data with the procedures/functions + \item A single entity called \texttt{object} + \item Everything in Python is an object + \item Strings, Lists, Functions and even Modules + \end{itemize} + \begin{lstlisting} + s = "Hello World" + s.lower() + + l = [1, 2, 3, 4, 5] + l.append(6) + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Objects \ldots} + \begin{itemize} + \item Objects provide a consistent interface + \end{itemize} + \begin{lstlisting} + for element in (1, 2, 3): + print element + for key in {'one':1, 'two':2}: + print key + for char in "123": + print char + for line in open("myfile.txt"): + print line + for line in urllib2.urlopen('http://site.com'): + print line + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Classes} + \begin{itemize} + \item A new string, comes along with methods + \item A template or a blue-print, where these definitions lie + \item This blue print for building objects is called a + \texttt{class} + \item \texttt{s} is an object of the \texttt{str} class + \item An object is an ``instance'' of a class + \end{itemize} + \begin{lstlisting} + s = "Hello World" + type(s) + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Defining Classes} + \begin{itemize} + \item A class equivalent of the talk dictionary + \item Combines data and methods into a single entity + \end{itemize} + \begin{lstlisting} + class Talk: + """A class for the Talks.""" + + def __init__(self, speaker, title, tags): + self.speaker = speaker + self.title = title + self.tags = tags + + def get_speaker_firstname(self): + return self.speaker.split()[0] + + def get_tags(self): + return self.tags.split(',') + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{class} block} + \begin{itemize} + \item Defined just like a function block + \item \texttt{class} is a keyword + \item \texttt{Talk} is the name of the class + \item Classes also come with doc-strings + \item All the statements of within the class are inside the block + \end{itemize} + \begin{lstlisting} + class Talk: + """A class for the Talks.""" + + def __init__(self, speaker, title, tags): + self.speaker = speaker + self.title = title + self.tags = tags + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{self}} + \begin{itemize} + \item Every method has an additional first argument, \texttt{self} + \item \texttt{self} is a reference to the object itself, of which + the method is a part of + \item Variables of the class are referred to as \texttt{self.variablename} + \end{itemize} + \begin{lstlisting} + def get_speaker_firstname(self): + return self.speaker.split()[0] + + def get_tags(self): + return self.tags.split(',') + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Instantiating a Class} + \begin{itemize} + \item Creating objects or instances of a class is simple + \item We call the class name, with arguments as required by it's + \texttt{\_\_init\_\_} function. + \end{itemize} + \begin{lstlisting} + bdfl = Talk('Guido van Rossum', + 'The History of Python', + 'python,history,C,advanced') + \end{lstlisting} + \begin{itemize} + \item We can now call the methods of the Class + \end{itemize} + \begin{lstlisting} + bdfl.get_tags() + bdfl.get_speaker_firstname() + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{\_\_init\_\_} method} + \begin{itemize} + \item A special method + \item Called every time an instance of the class is created + \end{itemize} + \begin{lstlisting} + print bdfl.speaker + print bdfl.tags + print bdfl.title + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile, allowframebreaks] + \frametitle{Inheritance} + \begin{itemize} + \item Suppose, we wish to write a \texttt{Tutorial} class + \item It's almost same as \texttt{Talk} except for minor differences + \item We can ``inherit'' from \texttt{Talk} + \end{itemize} + \begin{lstlisting} + class Tutorial(Talk): + """A class for the tutorials.""" + + def __init__(self, speaker, title, tags, handson=True): + Talk.__init__(self, speaker, title, tags) + self.handson = handson + + def is_handson(self): + return self.handson + \end{lstlisting} + \begin{itemize} + \item Modified \texttt{\_\_init\_\_} method + \item New \texttt{is\_handson} method + \item It also has, \texttt{get\_tags} and + \texttt{get\_speaker\_firstname} + \end{itemize} + \begin{lstlisting} + numpy = Tutorial('Travis Oliphant', + 'Numpy Basics', + 'numpy,python,beginner') + numpy.is_handson() + numpy.get_speaker_firstname() + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Summary} + In this section we have learnt, + \begin{itemize} + \item the fundamental difference in paradigm, between Object Oriented + Programming and Procedural Programming + \item to write our own classes + \item to write new classes that inherit from existing classes + \end{itemize} +\end{frame} + diff --git a/lecture-notes/advanced-python/slides/plotting.tex b/lecture-notes/advanced-python/slides/plotting.tex new file mode 100644 index 0000000..fbc7aa2 --- /dev/null +++ b/lecture-notes/advanced-python/slides/plotting.tex @@ -0,0 +1,450 @@ +\section{Interactive Plotting} + +\begin{frame}[fragile] + \frametitle{First Plot} + \begin{itemize} + \item Start IPython with \texttt{-pylab} + \end{itemize} + \begin{lstlisting} + $ ipython -pylab + \end{lstlisting} % $ + \begin{lstlisting} + In[]: p = linspace(-pi,pi,100) + In[]: plot(p, cos(p)) + \end{lstlisting} +\end{frame} + + +\begin{frame}[fragile] + \frametitle{\texttt{linspace}} + \begin{itemize} + \item \texttt{p} has a hundred points in the range -pi to pi + \begin{lstlisting} + In[]: print p[0], p[-1], len(p) + \end{lstlisting} + \item Look at the doc-string of \texttt{linspace} for more details + \begin{lstlisting} + In[]: linspace? + \end{lstlisting} + \end{itemize} + \begin{itemize} + \item \texttt{plot} simply plots the two arguments with default + properties + \end{itemize} +\end{frame} + +\section{Embellishing Plots} + +\begin{frame}[fragile] + \frametitle{Plot color and thickness} + \begin{lstlisting} + In[]: clf() + In[]: plot(p, sin(p), 'r') + \end{lstlisting} + \begin{itemize} + \item Gives a sine curve in Red. + \end{itemize} + \begin{lstlisting} + In[]: plot(p, cos(p), linewidth=2) + \end{lstlisting} + \begin{itemize} + \item Sets line thickness to 2 + \end{itemize} + \begin{lstlisting} + In[]: clf() + In[]: plot(p, sin(p), '.') + \end{lstlisting} + \begin{itemize} + \item Produces a plot with only points + \end{itemize} + \begin{lstlisting} + In[]: plot? + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{title}} + \begin{lstlisting} + In[]: x = linspace(-2, 4, 50) + In[]: plot(x, -x*x + 4*x - 5, 'r', + linewidth=2) + In[]: title("Parabolic function -x^2+4x-5") + \end{lstlisting} + \begin{itemize} + \item We can set title using \LaTeX~ + \end{itemize} + \begin{lstlisting} + In[]: title("Parabolic function $-x^2+4x-5$") + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Axes labels} + \begin{lstlisting} + In[]: xlabel("x") + In[]: ylabel("f(x)") + \end{lstlisting} + \begin{itemize} + \item We could, if required use \LaTeX~ + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Annotate} + \begin{lstlisting} + In[]: annotate("local maxima", xy=(2, -1)) + \end{lstlisting} + \begin{itemize} + \item First argument is the annotation text + \item The argument to \texttt{xy} is a tuple that gives the location + of the text. + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Limits of Plot area} + \begin{lstlisting} + In[]: xlim() + In[]: ylim() + \end{lstlisting} + \begin{itemize} + \item With no arguments, \texttt{xlim} \& \texttt{ylim} get the + current limits + \item New limits are set, when arguments are passed to them + \end{itemize} + \begin{lstlisting} + In[]: xlim(-4, 5) + \end{lstlisting} + \begin{lstlisting} + In[]: ylim(-15, 2) + \end{lstlisting} +\end{frame} + +\begin{frame} +\frametitle{Plot} +\includegraphics[scale=0.45]{../advanced_python/images/plot.png}\\ +\end{frame} + + + +\section{Saving to Scripts} + +\begin{frame}[fragile] + \frametitle{Command history} + \begin{itemize} + \item To see the history of commands, we typed + \begin{lstlisting} + In[]: %hist + \end{lstlisting} + \item All commands, valid or invalid, appear in the history + \item \texttt{\%hist} is a magic command, available only in IPython + \end{itemize} + \begin{lstlisting} + In[]: %hist 5 + # last 5 commands + \end{lstlisting} + \begin{lstlisting} + In[]: %hist 5 10 + # commands between 5 and 10 + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Saving to a script} + \begin{itemize} + \item We wish to save commands for reproducing the parabola + \item Look at the history and identify the commands that will + reproduce the parabolic function along with all embellishment + \item \texttt{\%save} magic command to save the commands to a file + \end{itemize} + \begin{lstlisting} + In[]: %save plot_script.py 1 3-6 8 + \end{lstlisting} + \begin{itemize} + \item File name must have a \texttt{.py} extension + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Running the script} + \begin{lstlisting} + In[]: %run -i plot_script.py + \end{lstlisting} + \begin{itemize} + \item There were no errors in the plot, but we don't see it! + \item Running the script means, we are not in interactive mode + \item We need to explicitly ask for the image to be shown + \end{itemize} + \begin{lstlisting} + In[]: show() + \end{lstlisting} + \begin{itemize} + \item \texttt{-i} asks the interpreter to check for names, + unavailable in the script, in the interpreter + \item \texttt{sin}, \texttt{plot}, etc. are taken from the + interpreter + \end{itemize} +\end{frame} + +\section{Saving Plots} + +\begin{frame}[fragile] + \frametitle{\texttt{savefig}} + \begin{lstlisting} + In[]: x = linspace(-3*pi,3*pi,100) + In[]: plot(x,sin(x)) + In[]: savefig('sine.png') + \end{lstlisting} + \begin{itemize} + \item \texttt{savefig} takes one argument + \item The file-type is decided based on the extension + \item \texttt{savefig} can save as png, pdf, ps, eps, svg + \end{itemize} +\end{frame} + +\section{Multiple Plots} + +\begin{frame}[fragile] + \frametitle{Overlaid plots} + \begin{lstlisting} + In[]: x = linspace(0, 50, 10) + In[]: plot(x, sin(x)) + \end{lstlisting} + \begin{itemize} + \item The curve isn't as smooth as we expected + \item We chose too few points in the interval + \end{itemize} + \begin{lstlisting} + In[]: y = linspace(0, 50, 500) + In[]: plot(y, sin(y)) + \end{lstlisting} + \begin{itemize} + \item The plots are overlaid + \item It is the default behaviour of \texttt{pylab} + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Legend} + \begin{lstlisting} + In[]: legend(['sine-10 points', + 'sine-500 points']) + \end{lstlisting} + \begin{itemize} + \item Placed in the location, \texttt{pylab} thinks is `best' + \item \texttt{loc} parameter allows to change the location + \end{itemize} + \begin{lstlisting} + In[]: legend(['sine-10 points', + 'sine-500 points'], + loc='center') + \end{lstlisting} +\end{frame} + +\begin{frame} +\frametitle{Overlaid Plots} +\includegraphics[scale=0.45]{../advanced_python/images/overlaid.png}\\ +\end{frame} + + + +\begin{frame}[fragile] + \frametitle{Plotting in separate figures} + \begin{lstlisting} + In[]: clf() + In[]: x = linspace(0, 50, 500) + In[]: figure(1) + In[]: plot(x, sin(x), 'b') + In[]: figure(2) + In[]: plot(x, cos(x), 'g') + \end{lstlisting} + \begin{itemize} + \item \texttt{figure} command allows us to have plots separately + \item It is also used to switch context between the plots + \end{itemize} + \begin{lstlisting} + In[]: savefig('cosine.png') + In[]: figure(1) + In[]: title('sin(y)') + In[]: savefig('sine.png') + In[]: close() + In[]: close() + \end{lstlisting} + \begin{itemize} + \item \texttt{close('all')} closes all the figures + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Subplots} + \begin{lstlisting} + In[]: subplot(2, 1, 1) + \end{lstlisting} + \begin{itemize} + \item number of rows + \item number of columns + \item plot number, in serial order, to access or create + \end{itemize} + \begin{lstlisting} + In[]: subplot(2, 1, 2) + In[]: x = linspace(0, 50, 500) + In[]: plot(x, cos(x)) + + In[]: subplot(2, 1, 1) + In[]: y = linspace(0, 5, 100) + In[]: plot(y, y ** 2) + \end{lstlisting} +\end{frame} + +\begin{frame} +\frametitle{Subplots} +\includegraphics[scale=0.45]{../advanced_python/images/subplot.png}\\ +\end{frame} + + + +\section{Plotting Data} + +\begin{frame}[fragile] + \frametitle{Loading data} + \begin{itemize} + \item \texttt{primes.txt} contains a list of primes listed + column-wise + \item We read the data using \texttt{loadtxt} + \end{itemize} + \begin{lstlisting} + In[]: primes = loadtxt('primes.txt') + In[]: print primes + \end{lstlisting} + \begin{itemize} + \item \texttt{primes} is a sequence of floats + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Reading two column data} + \begin{itemize} + \item \texttt{pendulum.txt} has two columns of data + \item Length of pendulum in the first column + \item Corresponding time period in second column + \item \texttt{loadtxt} requires both columns to be of same length + \end{itemize} + \begin{lstlisting} + In[]: pend = loadtxt('pendulum.txt') + In[]: print pend + \end{lstlisting} + \begin{itemize} + \item \texttt{pend} is not a simple sequence like \texttt{primes} + \end{itemize} +\end{frame} + +\begin{frame}[fragile] + \frametitle{Unpacking with \texttt{loadtxt}} + \begin{lstlisting} + In[]: L, T = loadtxt('pendulum.txt', + unpack=True) + In[]: print L + In[]: print T + \end{lstlisting} + \begin{itemize} + \item We wish to plot L vs. $T^2$ + \item \texttt{square} function gives us the squares + \item (We could instead iterate over T and calculate) + \end{itemize} + \begin{lstlisting} + In[]: Tsq = square(T) + + In[]: plot(L, Tsq, '.') + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] + \frametitle{\texttt{errorbar}} + \begin{itemize} + \item Experimental data always has errors + \item \texttt{pendulum\_error.txt} contains errors in L and T + \item Read the values and make an error bar plot + \end{itemize} + \begin{lstlisting} + In[]: L, T, L_err, T_err = \ + loadtxt('pendulum_error.txt', + unpack=True) + In[]: Tsq = square(T) + + In[]: errorbar(L, Tsq , xerr=L_err, + yerr=T_err, fmt='b.') + \end{lstlisting} +\end{frame} + +\begin{frame} +\frametitle{Errorbar} +\includegraphics[scale=0.45]{../advanced_python/images/L-Tsq.png}\\ +\end{frame} + +\section{Other kinds of Plots} + +\begin{frame}[fragile] + \frametitle{Scatter Plot} + \begin{itemize} + \item The data is displayed as a collection of points + \item Value of one variable determines position along x-axis + \item Value of other variable determines position along y-axis + \item Let's plot the data of profits of a company + \end{itemize} + \begin{lstlisting} + In[]: year, profit = loadtxt( + 'company-a-data.txt', + dtype=type(int())) + + In[]: scatter(year, profit) + \end{lstlisting} + \begin{itemize} + \item \alert{\texttt{dtype=int}; default is float} + \end{itemize} +\end{frame} + +\begin{frame} +\frametitle{Scatter Plot} +\includegraphics[scale=0.45]{../advanced_python/images/scatter.png}\\ +\end{frame} + +\begin{frame}[fragile] + \frametitle{Pie Chart} + \begin{lstlisting} + In[]: pie(profit, labels=year) + \end{lstlisting} +\includegraphics[scale=0.35]{../advanced_python/images/pie.png}\\ +\end{frame} + +\begin{frame}[fragile] + \frametitle{Bar Chart} + \begin{lstlisting} + In[]: bar(year, profit) + \end{lstlisting} +\includegraphics[scale=0.35]{../advanced_python/images/bar.png}\\ +\end{frame} + +\begin{frame}[fragile] + \frametitle{Log-log plot} + \begin{itemize} + \item Plot a \texttt{log-log} chart of $y=5x^3$ for x from 1 to 20 + \end{itemize} + \begin{lstlisting} + In[]: x = linspace(1,20,100) + In[]: y = 5*x**3 + + In[]: loglog(x, y) + In[]: plot(x, y) + \end{lstlisting} + \begin{itemize} + \item Look at \url{http://matplotlib.sourceforge.net/contents.html} + for more! + \end{itemize} +\end{frame} + +\begin{frame} +\frametitle{Log-log plot Plot} +\includegraphics[scale=0.45]{../advanced_python/images/loglog.png}\\ +\end{frame} + + diff --git a/lecture-notes/advanced-python/slides/scipy.tex b/lecture-notes/advanced-python/slides/scipy.tex new file mode 100644 index 0000000..1116c3d --- /dev/null +++ b/lecture-notes/advanced-python/slides/scipy.tex @@ -0,0 +1,273 @@ +\section{Solving Equations} + +\begin{frame}[fragile] +\frametitle{Solution of linear equations} +Consider, + \begin{align*} + 3x + 2y - z & = 1 \\ + 2x - 2y + 4z & = -2 \\ + -x + \frac{1}{2}y -z & = 0 + \end{align*} +Solution: + \begin{align*} + x & = 1 \\ + y & = -2 \\ + z & = -2 + \end{align*} +\end{frame} + +\begin{frame}[fragile] +\frametitle{Solving using Matrices} +Let us now look at how to solve this using \texttt{matrices} + \begin{lstlisting} +In []: A = array([[3,2,-1], + [2,-2,4], + [-1, 0.5, -1]]) +In []: b = array([1, -2, 0]) +In []: x = solve(A, b) + \end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{Solution:} +\begin{lstlisting} +In []: x +Out[]: array([ 1., -2., -2.]) +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{Let's check!} +\begin{small} +\begin{lstlisting} +In []: Ax = dot(A, x) +In []: Ax +Out[]: array([ 1.00000000e+00, -2.00000000e+00, + -1.11022302e-16]) +\end{lstlisting} +\end{small} +\begin{block}{} +The last term in the matrix is actually \alert{0}!\\ +We can use \texttt{allclose()} to check. +\end{block} +\begin{lstlisting} +In []: allclose(Ax, b) +Out[]: True +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{\texttt{roots} of polynomials} +\begin{itemize} +\item \texttt{roots} function can find roots of polynomials +\item To calculate the roots of $x^2-5x+6$ +\end{itemize} +\begin{lstlisting} + In []: coeffs = [1, -5, 6] + In []: roots(coeffs) + Out[]: array([3., 2.]) +\end{lstlisting} +\vspace*{-.2in} +\begin{center} +\includegraphics[height=1.6in, interpolate=true]{images/roots} +\end{center} +\end{frame} + +\begin{frame}[fragile] +\frametitle{SciPy: \texttt{fsolve}} +\begin{small} +\begin{lstlisting} + In []: from scipy.optimize import fsolve +\end{lstlisting} +\end{small} +\begin{itemize} +\item Finds the roots of a system of non-linear equations +\item Input arguments - Function and initial estimate +\item Returns the solution +\end{itemize} +\end{frame} + +\begin{frame}[fragile] +\frametitle{\texttt{fsolve} \ldots} +Find the root of $sin(z)+cos^2(z)$ nearest to $0$ +\begin{lstlisting} +In []: def g(z): + ....: return sin(z)+cos(z)*cos(z) + +In []: fsolve(g, 0) +Out[]: -0.66623943249251527 +\end{lstlisting} +\begin{center} +\includegraphics[height=2in, interpolate=true]{images/fsolve} +\end{center} +\end{frame} + +\section{ODEs} + +\begin{frame}[fragile] +\frametitle{Solving ODEs using SciPy} +\begin{itemize} +\item Consider the spread of an epidemic in a population +\item $\frac{dy}{dt} = ky(L-y)$ gives the spread of the disease +\item $L$ is the total population. +\item Use $L = 2.5E5, k = 3E-5, y(0) = 250$ +\item Define a function as below +\end{itemize} +\begin{lstlisting} +In []: from scipy.integrate import odeint +In []: def epid(y, t): + .... k = 3.0e-5 + .... L = 2.5e5 + .... return k*y*(L-y) + .... +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{Solving ODEs using SciPy \ldots} +\begin{lstlisting} +In []: t = linspace(0, 12, 61) + +In []: y = odeint(epid, 250, t) + +In []: plot(t, y) +\end{lstlisting} +%Insert Plot +\end{frame} + +\begin{frame}[fragile] +\frametitle{Result} +\begin{center} +\includegraphics[height=2in, interpolate=true]{images/epid} +\end{center} +\end{frame} + + +\begin{frame}[fragile] +\frametitle{ODEs - Simple Pendulum} +We shall use the simple ODE of a simple pendulum. +\begin{equation*} +\ddot{\theta} = -\frac{g}{L}sin(\theta) +\end{equation*} +\begin{itemize} +\item This equation can be written as a system of two first order ODEs +\end{itemize} +\begin{align} +\dot{\theta} &= \omega \\ +\dot{\omega} &= -\frac{g}{L}sin(\theta) \\ + \text{At}\ t &= 0 : \nonumber \\ + \theta = \theta_0(10^o)\quad & \&\quad \omega = 0\ (Initial\ values)\nonumber +\end{align} +\end{frame} + +\begin{frame}[fragile] +\frametitle{ODEs - Simple Pendulum \ldots} +\begin{itemize} +\item Use \texttt{odeint} to do the integration +\end{itemize} +\begin{lstlisting} +In []: def pend_int(initial, t): + .... theta = initial[0] + .... omega = initial[1] + .... g = 9.81 + .... L = 0.2 + .... F=[omega, -(g/L)*sin(theta)] + .... return F + .... +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{ODEs - Simple Pendulum \ldots} +\begin{itemize} +\item \texttt{t} is the time variable \\ +\item \texttt{initial} has the initial values +\end{itemize} +\begin{lstlisting} +In []: t = linspace(0, 20, 101) +In []: initial = [10*2*pi/360, 0] +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{ODEs - Simple Pendulum \ldots} +%%\begin{small} +\texttt{} +%%\end{small} +\begin{lstlisting} +In []: from scipy.integrate import odeint +In []: pend_sol = odeint(pend_int, + initial,t) +\end{lstlisting} +\end{frame} + +\begin{frame}[fragile] +\frametitle{Result} +\begin{center} +\includegraphics[height=2in, interpolate=true]{images/ode} +\end{center} +\end{frame} + +%% \section{FFTs} + +%% \begin{frame}[fragile] +%% \frametitle{The FFT} +%% \begin{itemize} +%% \item We have a simple signal $y(t)$ +%% \item Find the FFT and plot it +%% \end{itemize} +%% \begin{lstlisting} +%% In []: t = linspace(0, 2*pi, 500) +%% In []: y = sin(4*pi*t) + +%% In []: f = fft(y) +%% In []: freq = fftfreq(500, t[1] - t[0]) + +%% In []: plot(freq[:250], abs(f)[:250]) +%% In []: grid() +%% \end{lstlisting} +%% \end{frame} + +%% \begin{frame}[fragile] +%% \frametitle{FFTs cont\dots} +%% \begin{lstlisting} +%% In []: y1 = ifft(f) # inverse FFT +%% In []: allclose(y, y1) +%% Out[]: True +%% \end{lstlisting} +%% \end{frame} + +%% \begin{frame}[fragile] +%% \frametitle{FFTs cont\dots} +%% Let us add some noise to the signal +%% \begin{lstlisting} +%% In []: yr = y + random(size=500)*0.2 +%% In []: yn = y + normal(size=500)*0.2 + +%% In []: plot(t, yr) +%% In []: figure() +%% In []: plot(freq[:250], +%% ...: abs(fft(yn))[:250]) +%% \end{lstlisting} +%% \begin{itemize} +%% \item \texttt{random}: produces uniform deviates in $[0, 1)$ +%% \item \texttt{normal}: draws random samples from a Gaussian +%% distribution +%% \item Useful to create a random matrix of any shape +%% \end{itemize} +%% \end{frame} + +%% \begin{frame}[fragile] +%% \frametitle{FFTs cont\dots} +%% Filter the noisy signal: +%% \begin{lstlisting} +%% In []: from scipy import signal +%% In []: yc = signal.wiener(yn, 5) +%% In []: clf() +%% In []: plot(t, yc) +%% In []: figure() +%% In []: plot(freq[:250], +%% ...: abs(fft(yc))[:250]) +%% \end{lstlisting} +%% Only scratched the surface here \dots +%% \end{frame} diff --git a/lecture-notes/advanced-python/slides/tmp.tex b/lecture-notes/advanced-python/slides/tmp.tex new file mode 100644 index 0000000..9913703 --- /dev/null +++ b/lecture-notes/advanced-python/slides/tmp.tex @@ -0,0 +1,316 @@ +% Created 2011-04-18 Mon 03:20 +\documentclass[presentation]{beamer} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{fixltx2e} +\usepackage{graphicx} +\usepackage{longtable} +\usepackage{float} +\usepackage{wrapfig} +\usepackage{soul} +\usepackage{textcomp} +\usepackage{marvosym} +\usepackage{wasysym} +\usepackage{latexsym} +\usepackage{amssymb} +\usepackage{hyperref} +\tolerance=1000 +\usepackage[english]{babel} \usepackage{ae,aecompl} +\usepackage{mathpazo,courier,euler} \usepackage[scaled=.95]{helvet} +\usepackage{listings} +\lstset{language=Python, basicstyle=\ttfamily\bfseries, +commentstyle=\color{red}\itshape, stringstyle=\color{darkgreen}, +showstringspaces=false, keywordstyle=\color{blue}\bfseries} +\providecommand{\alert}[1]{\textbf{#1}} + +\title{modules.rst.org} +\author{} +\date{\today} + +\usetheme{Warsaw}\usecolortheme{default}\useoutertheme{infolines}\setbeamercovered{transparent} +\begin{document} + +\maketitle + +\begin{frame} +\frametitle{Outline} +\setcounter{tocdepth}{3} +\tableofcontents +\end{frame} + + + + +\section{Using Python modules} +\label{sec-1} + + +We shall, in this section, see how to run Python scripts from the +command line, and more details about importing modules. + +Let us create a simple python script to print hello world. Open your +text editor and type the following, and save the script as \texttt{hello.py}. + +\begin{verbatim} +print "Hello world!" +\end{verbatim} + +Until now we have been running scripts from inside IPython, using + +\begin{verbatim} +%run -i hello.py +\end{verbatim} + +But, as we know, IPython is just an advanced interpreter and it is not +mandatory that every one who wants to run your program has IPython +installed. + +So, the right method to run the script, would be to run it using the +Python interpreter. Open the terminal and navigate to the directory +where \texttt{hello.py} is saved. + +Then run the script by saying, + +\begin{verbatim} +python hello.py +\end{verbatim} + +The script is executed and the string \texttt{Hello World!} has been printed. + +Now let us run a script that plots a simple sine curve in the range -2pi +to 2pi, using Python, instead of running it from within IPython. + +Type the following lines and save it in \texttt{sine\_plot.py} file. + +\begin{verbatim} +x = linspace(-2*pi, 2*pi, 100) +plot(x, sin(x)) +show() +\end{verbatim} + +Now let us run sine\_plot.py as a python script. + +\begin{verbatim} +python sine_plot.py +\end{verbatim} + +Do we get the plot? No! All we get is error messages. Python complains +that \texttt{linspace} isn't defined. What happened? Let us try to run the same +script from within IPython. Start IPython, with the \texttt{-pylab} argument +and run the script. It works! + +What is going on, here? IPython when started with the \texttt{-pylab} option, +is importing a whole set of functionality for us to work with, without +bothering about importing etc. + +Let us now try to fix the problem by importing \texttt{linspace}. + +Let's add the following line as the first line in the script. + +\begin{verbatim} +from scipy import * +\end{verbatim} + +Now let us run the script again, + +\begin{verbatim} +python sine_plot.py +\end{verbatim} + +Now we get an error, that says \texttt{plot} is not defined. Let's edit the +file and import this from pylab. Let's add the following line, as the +second line of our script. + +\begin{verbatim} +from pylab import * +\end{verbatim} + +And run the script, + +\begin{verbatim} +python sine_plot.py +\end{verbatim} + +Yes! it worked. So what did we do? + +We actually imported the required functions and keywords, using +\texttt{import}. By using the *, we are asking python to import everything from +the \texttt{scipy} and \texttt{pylab} modules. This isn't a good practice, as 1. it +imports a lot of unnecessary things 2. the two modules may have +functions with the same name, which would cause a conflict. + +One of the ways out is to import only the stuff that we need, +explicitly. + +Let us modify sine\_plot.py by replacing the import statements with the +following lines. + +\begin{verbatim} +from scipy import linspace, pi, sin +from pylab import plot, show +\end{verbatim} + +Now let us try running the code again as, + +\begin{verbatim} +python show_plot.py +\end{verbatim} + +As expected, this works. But, once the number of functions that you need +to import increases, this is slightly inconvenient. Also, you cannot use +functions with the same name, from different modules. To overcome this, +there's another method. + +We could just import the modules as it is, and use the functions or +other objects as a part of those modules. Change the import lines, to +the following. + +\begin{verbatim} +import scipy +import pylab +\end{verbatim} + +Now, replace \texttt{pi} with \texttt{scipy.pi}. Similarly, for \texttt{sin} and \texttt{linspace}. +Replace \texttt{plot} and \texttt{show} with \texttt{pylab.plot} and \texttt{pylab.show}, +respectively. + +Now, run the file and see that we get the output, as expected. + +We have learned how to import from modules, but what exactly is a +module? How is one written? + +A module is simply a Python script containing the definitions and +statements, which can be imported. So, it is very easy to create your +own modules. You just need to stick in all your definitions into your +python file and put the file in your current directory. + +When importing, Python searches the locations present in a variable +called the Python path. So, our module file should be present in one of +the locations in the Python path. The first location to be searched is +the current directory of the script being run. So, having our module +file in the current working directory, is the simplest way to allow it +to be used as a module and import things from it. + +Python has a very rich standard library of modules. It is very +extensive, offering a wide range of facilities. Some of the standard +modules are, + +for Math: math, random for Internet access: urllib2, smtplib for System, +Command line arguments: sys for Operating system interface: os for +regular expressions: re for compression: gzip, zipfile, tarfile And +there are lot more. + +Find more information at Python Library reference, +\texttt{http://docs.python.org/library/} + +There are a lot of other modules like pylab, scipy, Mayavi, etc which +are not part of the standard Python library. + +This brings us to the end of our discussion on modules and running +scripts from the command line. +\section{Writing modules} +\label{sec-2} + + +In this section we shall look at writing modules, in some more detail. +Often we will have to reuse the code that we have previously written. We +do that by writing functions. Functions can then be put into modules, +and imported as and when required. + +Let us first write a function that computes the gcd of two numbers and +save it in a script. + +\begin{verbatim} +def gcd(a, b): + while b: + a, b = b, a%b + return a +\end{verbatim} + +Now, we shall write a test function in the script that tests the gcd +function, to see if it works. + +\begin{verbatim} +if gcd(40, 12) == 4 and gcd(12, 13) == 1: + print "Everything OK" +else: + print "The GCD function is wrong" +\end{verbatim} + +Let us save the file as gcd\_script.py in \texttt{/home/fossee/gcd\_script.py} +and run it. + +\begin{verbatim} +$ python /home/fossee/gcd_script.py +\end{verbatim} + +We can see that the script is executed and everything is fine. + +What if we want to use the gcd function in some of our other scripts. +This is also possible since every python file can be used as a module. + +But first, we shall understand what happens when you import a module. + +Open IPython and type + +\begin{verbatim} +import sys +sys.path +\end{verbatim} + +This is a list of locations where python searches for a module when it +encounters an import statement. Hence, when we just did \texttt{import sys}, +python searches for a file named \texttt{sys.py} or a folder named \texttt{sys} in all +these locations one by one, until it finds one. We can place our script +in any one of these locations and import it. + +The first item in the list is an empty string which means the current +working directory is also searched. + +Alternatively, we can also import the module if we are working in same +directory where the script exists. + +Since we are in /home/fossee, we can simply do + +\begin{verbatim} +import gcd_script +\end{verbatim} + +We can see that the gcd\_script is imported. But the test code that we +added at the end of the file is also executed. + +But we want the test code to be executed only when the file is run as a +python script and not when it is imported. + +This is possible by using \texttt{\_\_name\_\_} variable. + +Go to the file and add + +\begin{verbatim} +if __name__ == "__main__": +\end{verbatim} + +before the test code and indent the test code. + +Let us first run the code. + +\begin{verbatim} +$ python gcd_script.py +\end{verbatim} + +We can see that the test runs successfully. + +Now we shall import the file + +\begin{verbatim} +import gcd_script +\end{verbatim} + +We see that now the test code is not executed. + +The \texttt{\_\_name\_\_} variable is local to every module and it is equal to +\texttt{\_\_main\_\_} only when the file is run as a script. Hence, all the code +that goes in to the if block, \texttt{if \_\_name\_\_ =} ``__main__'':= is executed +only when the file is run as a python script. + +\end{document} |