{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# PHYS201 PHYSICS IIA - *Python Lab 1*\n", "\n", "*Alexei Gilchrist*, 2014\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 1 Introduction \n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will be learning the programming language *Python* and some of the packages that are useful for numerical computation. As programming languages go, *Python* is easy to learn and is used widely so it's a rewarding language to master. There are a number of ways of running *Python* programs ranging from the command line through to using various GUI's (in fact you can use Python to create the GUI's).\n", "\n", "The numerical labs for phys201 will take place in *ipython notebooks* like this one. \n", "The notebook is interactive - you can modify and run code in the cells and save the result. The code cells have a prefix \"In [*n*]:\" where *n* indicates the sequence in which the cell was evaluated. The output of the code is typically shown in another cell immediately following, prefixed with \"Out [*n*]:\". To run a cell use *shift-enter* or select *Run* from the *Cell* menu above.\n", "\n", "You should run each code cell in the workbook and make sure you understand why it produces the output it does. Some of the code cells depend on definitions made in previous ones so you will get the best resutls if you run them in sequence. As you work through the material there will be a number of exercises marked with \"Exercise\". Complete those exercises, save the result and hand in the file at the end of the lab. \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This workbook has been based partially on the following notebooks:\n", "\n", "* [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/gist/rpmuller/5920182) by Rick Muller\n", "* [Lectures on Scientific Computing with Python](http://nbviewer.ipython.org/github/jrjohansson/scientific-python-lectures/tree/master) by J.R. Johansson." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 2 Basic Python\n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll cover the basics of *Python* fairly quickly. You are encouraged to play with the expressions in the cells and explore the language. We'll only cover just enough to get you started using it for the material in phys201. Often there will be variations or extra options available for a command that will not be mentioned. As your proficiency with the language increases you will find more elegant ways of coding the same task. If you get stuck or want to find out more there are lots of resources on the web. Here are some excellent starting tutorials:\n", "\n", "* [The Python Tutorial](http://docs.python.org/2/tutorial/)\n", "* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/)\n", "* [Dive into Python](http://www.diveintopython.net/toc/index.html)\n", "\n", "The official python documentation is here:\n", "\n", "* [Python 2.0 Docs](http://docs.python.org/2/)\n", "* [The Python Language Reference](http://docs.python.org/2/reference/index.html) - Has the exact definition of the *Python* syntax, though it's a little hard to read.\n", "* [The Python Standard Library](http://docs.python.org/2/library/) - Descriptions of the standard set of modules shipped with *Python*\n", "\n", "And here is some more:\n", "\n", "* [Think Python](http://www.greenteapress.com/thinkpython/) - A free book on *Python* programming\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.1 Arithmetic" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can use python as a calculator, normal order of operations applies, for instance try running the following cell:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "9*(2+3)-40+2**2" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the ipython notebook, the last expression is shown as the output of a cell. If you want to print off intermediate values use the `print` function" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print(12)\n", "print(12*12)\n", "print(12*12*12)\n", "print(12*12*12*12)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is one gotcha that we need to deal with from the outset. In python2 interger division truncates the remainder so that the result is also an integer. This is a convetion inherited from programming languages like C or Fortran. We can avoid this by explicitly writing numbers in floating point when we do division or converting the number explicitly to a *float*. Of course we could also convert numbers explicitly to intergers if we need to too (with *int*)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print(5/2)\n", "print(5/2.)\n", "print(5/float(2))\n", "print(5/int(2.5))" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An interesting feature of *Python* is that complex numbers are native types. (In fact this is the reason that drove me to learn *Python* many years ago!). An imaginary number is immediately followed with a \"j\":" ] }, { "cell_type": "code", "collapsed": false, "input": [ "2j" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A general complex number is the adition of a real with an imaginary number, for example" ] }, { "cell_type": "code", "collapsed": false, "input": [ "2+1j + 4+2j" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and" ] }, { "cell_type": "code", "collapsed": false, "input": [ "(2+1j)*(4+2j)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also use the command `complex` if it's more convenient, it takes two arguments - the real part and the imaginary part:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "z=complex(2,4)\n", "print(z)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, complex numbers have some methods and attributes defined on them. Three useful ones are," ] }, { "cell_type": "code", "collapsed": false, "input": [ "print( z.real, z.imag, z.conjugate() )\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ " Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Given the pure imaginary number $i=\\sqrt{-1}$, calculate $i^i$ by direct calculation:" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.2 Modules" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Much of the functionality of python is provided by *modules*, which can be imported to provide functions, classes, constants etc. *Python* comes with a large collection of such modules called the Python Standard Library which provides tools for accesing files, manipulating strings, parsing xml etc. For example, the *math* module contains a number of useful mathematical functions and we can use those function by first importing the module" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import math" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can access the constant $\\pi$ for instance" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print(math.pi)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes it's more convenient to import some symbols in that module to the local namespace so we don;t have to keep writing \"math.\" all the time. We can do this in the following way" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from math import pi, cos\n", "\n", "cos(pi)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We could even import every symbol in *math* using" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from math import *\n", "\n", "sin(pi/2.0)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The advantage of this approach is that all the constants and functions in the math module are now available without having to type the prefix \"math.\". The dissadvantage is that we've now filled our namespace with a whole lof of definitions we may not want and which may conflict with objects we have already defined. In general it's cleaner to stick to one of the first forms for importing modules." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The module `cmath` is a companion to `math` that defines functions that handle complex numbers, including some functions that redefine those in `math`, extending them to the complex domain." ] }, { "cell_type": "code", "collapsed": false, "input": [ "import cmath" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following will yield an error when we use the `exp` from `math`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "math.exp(math.pi*1j)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "but by using the same function from `cmath` it works (note the numerical roundoff error):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "cmath.exp(math.pi*1j)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ " Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Given the pure imaginary number $i=\\sqrt{-1}$, calculate $i^i$ by using Euler's formula $e^{i\\theta}=\\cos\\theta+i\\sin\\theta$ as shown in lectures." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.3 Getting help" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are several ways of getting help or seeing what is available that don't rely on looking at external documentation. The built in *dir* function will show all the members of a module or class and this can give you an idea of what is available" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print(dir(math))" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is also the *help* function which is really useful:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "help(math)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.4 Strings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Strings in *Python* can be defined using single quotes (') or double quotes (\") so long at they match. This lets you easily embed quotes in a string " ] }, { "cell_type": "code", "collapsed": false, "input": [ "print(\"Albert O'Connor\")\n", "print('He said \"hello!\"')" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some of the math operators are overloaded to also work on strings, for instance '+' concaternates strings and '*' repeats them" ] }, { "cell_type": "code", "collapsed": false, "input": [ "\"Good\" + \" \" + \"Morning!\"" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "\"=\"*30" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.5 Objects" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Everything in *Python* is an *object*. Don't worry too much about what this means, for us it just means that even simple things like numbers have 'attributes' and 'methods' (functions) as we saw with complex numbers. For numbers these are not very interesting except they define what a number *is*. For strings there are lots of useful methods. You can access these attributes and methods by a dot (.) followed by the attribute or method name. " ] }, { "cell_type": "code", "collapsed": false, "input": [ "\"this is a upper case string\".upper()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Take a moment to skim the docs to be aware of some of the methods available for strings:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "help(str)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to produce nicely formatted output, use `format`. This will alow the string to act like a template into which we can insert values. `{0}` will substitute in the first value passed, `{1}` the second, and so on:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "\"Parameters: g={0}, time={1}s, initial angle={2:.3f} radians\".format(9.81, 10, pi/2)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is actually quite a rich mini-language to format parameters just the way you want them. This is hinted at in the last parameter above, the `:.3f` forces the output to only show 3 figures after the decimal place. To learn more about formatting options see [Format String Syntax](http://docs.python.org/2/library/string.html#formatstrings)." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.6 Comments" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Python* ignores anything on a line after a # symbol so you can use this to add comments to your code or to temporarily dissable some code. If the character appears inside a string though, it's treated as just another character and doesn't get ignored. It's always a good idea to add comments in code even if you are writing the code just for yourself. A hint or two as to why you are doing something a particular way will make your code much more readable." ] }, { "cell_type": "code", "collapsed": false, "input": [ "# this is a comment and won't get evaluated\n", "# a = 10\n", "a = 15\n", "\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.7 Variables" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Variables are defined with an equals (=) and the value can be any object. In fact, the kind of object you assign to a variable can change during the execution of a program - it doesn't have to remain the same type. The variable name has to start with an alphabetical character or underscore and can contain alphanumeric characters and underscores. It's generally good practice to give variables meaningful names." ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = 10\n", "B_2 = 5\n", "print(A**B_2)\n", "\n", "A = \"Five \"\n", "print(A*B_2)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some names are reserved for the language and you can't use those for variables:\n", "\n", " and, as, assert, break, class, continue, def, del, elif, else, except, \n", " exec, finally, for, from, global, if, import, in, is, lambda, not, or,\n", " pass, print, raise, return, try, while, with, yield" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.8 Exceptions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When python fails to understand a statement it will throw an *exception*. It will indicate where it thinks the error is and what the error was. Often this is enough to figure out what went wrong. For example, the following are easy to understand even with limited knowledge of *Python* (run each example to see the error)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "someundefinedname" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "*A" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "100/0" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "'sdsdsdsd" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ " Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Look at the exceptions thrown and fix the following snippets of code:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "welcome_message = \"Buenos dias! \"'" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "2*(23+5*(1/(2+3))+16" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "anne = 23\n", "bob = 27\n", "carl = 33\n", "\n", "average = (ane+bob+carl)/3.0" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.9 Lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lists in *Python* are defined using either [ ] or ( ). The difference between the two is that you can change values in the list defined with [ ] but not with ( ) which is called a *tuple*" ] }, { "cell_type": "code", "collapsed": false, "input": [ "weekdays = [\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can access an item in a list using the index of that item (N.B. in *Python* indices begin at 0) and square brackets [ ]:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print( weekdays[0] )\n", "print( weekdays[3] )" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you'd rather count from the end you can use negative numbers:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "weekend = [ weekdays[-2], weekdays[-1] ]\n", "weekend" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Even more useful, you can use *slices* with \":\". Instead of passing a single interger as index you pass a starting and ending integer separated by \":\" (note that the end value is not included in the result)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "weekdays[0:5]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lists don't have to be made of the same kind of object, you can mix them freely including nesting other lists and tuples" ] }, { "cell_type": "code", "collapsed": false, "input": [ "mixedlist = [ 1.0, 100, \"Elephant\", (\"mouse\", \"rat\"), weekend ]\n", "mixedlist" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we acess the lass item which happens to be a list, and acess the first item of that list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "mixedlist[-1][0]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lists have a bunch of useful methods defined on them, for instance to add and remove values. A brief description is available with the command `help(list)`. Ignore the methods that start with an underscore (\\_) - these are used to define things like how the list is initialised, how it is to handle the + operation etc." ] }, { "cell_type": "code", "collapsed": false, "input": [ "help(list)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For example `.append(n)` will add object `n` onto the end of a list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "mylist = [2,4,6,8]\n", "\n", "mylist.append(100)\n", "\n", "mylist" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are also built in commands that operate on lists such as `len` to find the length of a list:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "len(mixedlist)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A useful command that generates a range of numbers in a list is `range`. It can take one, two, or three arguments. With one argument it yields a list of positive intergers less than the argument:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "range(10)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Two arguments specify the begining and the end (not inclusive):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "range(2,20)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The third arguments is a step size:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "range(10,20,2)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This command is particularly useful in loops which are introduced below." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ " Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using nested lists, create a structure to represent the following 3x3 matrix: $A=\\begin{pmatrix}1&4&7\\\\2&5&8\\\\3&6&9\\end{pmatrix}$. Make sure to set up the lists so that `A[r][c]` accesses the element at row `r` and column `c`. e.g. `A[1][2]=8` and `A[2][0]=3` (Remember indexes start at 0)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = \n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.10 Dictionaries" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dictionaries are another very useful container in *Python*. These are a key-value store and are defined with { }. In practice the keys are usually strings and the values are some abritrary objects, though it's possible to use most objects as keys too." ] }, { "cell_type": "code", "collapsed": false, "input": [ "D = {'one':'Some random string', 'five':100.12}" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "D['one']" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "D[12] = 'this has a number for a key'\n", "D" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "D.keys()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "D.values()" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`len` also works for dictionaries:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "len(D)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ " Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Add a code cell below and construct a dictionary with three entries each of which is a list. Show how to access a particular value in one of the lists*" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.11 The Truth and Booleans" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition to numbers and strings we also have the `True` and `False` Boolean values. *Python* has a variety of ways of comparing two objects and we can use such comparisons in conditional statements and loops to test various conditions.\n", "\n", "* `A==B`: is `A` equal to `B`?\n", "* `A!=B`: is `A` not equal to `B`?\n", "* `A>B`, `A>=B`, `A10 ) or ( A%3==0 )" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ " Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Explain why in the following test, the first is true and the second is false:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print( 1 == 1.0 )\n", "print( 1 is 1.0 )" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Double click this cell and write your answer*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> Incidentally, you can set the cell type via the dropdown menu at the top. This cell is of type \"Markdown\" and you can use the *Markdown* syntax for formating and LaTeX for typesetting maths. See the following for more details and feel free to experiment: \n", "\n", "> * [Markdown syntax](http://daringfireball.net/projects/markdown/basics)\n", "> * [LaTeX Mathematics Wikibook](http://en.wikibooks.org/wiki/LaTeX/Mathematics)" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.12 If and Blocks" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One of the most distinctive features of *Python* is that it uses indentation to group pieces of code. If you are used to another language like *C* this may seem weird at first. After a while you will find that it makes code much more readable. Conditional statements, loops, functions etc all use spacing to delineate pieces of code. *Python* uses a colon (\":\"), followed by indentation level to define a block of code to be grouped together.\n", "\n", "The first use of these blocks we'll examine is the `if` statement which has the following pattern:\n", "\n", "\n", " if A==B:\n", " # these statements get\n", " # executed if A==B\n", " elif A==C:\n", " # these statements get\n", " # executed if A==C and \n", " # the first test doesn't match\n", " else:\n", " # these execute if nothing else matched\n", "\n", "\n", "You can omit the `elif` part and the `else` part if necessary.\n", "\n", "Play with the following piece of code, try setting different values of `A` and seeing the result." ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = 10\n", "\n", "if A > 9:\n", " out = \"A is greater than 9\"\n", "elif A > 4:\n", " out = \"A is between 5 and 9\"\n", "else:\n", " out = \"A is less then 5\"\n", " \n", "print(out)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ " Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Design a test which will determine if a number is a square or not (i.e 1, 4, 9, 16, ...), and create an `if` statement that prints out either 'square' or 'not square'. *Hint: `int(f)` will return the integer part for a floating point number `f`*. Remember to test your function for various values." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.13 Loops" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are two main looping structures in *Python*: `for` loops and the `while` statement. They have the following patterns:\n", "\n", " for variable1 in list:\n", " # variable1 takes on each value in list \n", " code\n", "\n", "and\n", "\n", " while test_is_true:\n", " # this code will be repeatedly executed until test_is_true returns False\n", " code" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For instance, `range(20)` creates a list with the numbers 0-19:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "range(20)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now loop over the list and print out something deep and meaningful:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "for i in range(20):\n", " print \"The square of {0:>2} is {1:>3}\".format(i, i*i)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same could be done with a `while` loop:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "i = 0\n", "while i < 20:\n", " print \"The square of {0:>2} is {1:>3}\".format(i, i*i)\n", " i = i+1" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes it's necessary to break out of the loop before it's finished. In those cases use the keyword `break`. It will work both inside `for` and `while`, and it exits out of the innermost loop. For example, `while True:` creates an infinite loop since the test condition is always true, but `break` exits out of it:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "i = 0\n", "while True:\n", " i = i + 10\n", " if i > 95:\n", " break\n", "print(i)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to skip to the next iteration of the loop use the command `continue`. Try to predict what the following code does before you run it. `x%y` calculates the remainder of `x/y`. " ] }, { "cell_type": "code", "collapsed": false, "input": [ "for x in range(30):\n", " if x%3==0:\n", " print(x)\n", " else:\n", " continue\n", " " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ " Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Below is the result of five measurements in a list. Write some code to loop over the values and print them out right-aligned with 3 decimal places. *Hint: use the formating mini-language*" ] }, { "cell_type": "code", "collapsed": false, "input": [ "measurements = [100.274, 99.0, 4, 123.2, 20.55]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2.14 Functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functions let you parcel pieces of code, give it a name, and reuse that piece of code over and over. They can accept parameters and return values, so in effect they let you extend the language however you want. (*Python* let's you define new *objects* too but that is beyond the scope of these labs.) It's important to realise that when you define a function the code in the function is not executed. It's executed only when you *call* the function." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functions are defined with the `def` keyword and have the following pattern:\n", "\n", "\n", " def function_name(optionalparameter1, optionalparameter2, ...):\n", " function_code\n", " return optional_return_value\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The return value is optional and the `return` statement can be omitted if the function doesn't return anything. A call to the function above would look something like `function_name(parameter)`, and its only at this point that the code in the function is evaluated." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that any variables defined within the function only exist inside the function (the range over which they exist is called their *scope*). This makes functions independent pieces of code and much easier to debug. If you need access to some external variable in a function you can always pass it as an argument." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def some_function():\n", " A = 100\n", " print(A)\n", "\n", "A = 10\n", "print(A)\n", "some_function()\n", "print(A)\n", "some_function()\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following is taken from (http://nbviewer.ipython.org/gist/rpmuller/5920182). It defines the function `fibonacci` which takes one argument and a returns a list of numbers:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def fibonacci(sequence_length):\n", " \"Return the Fibonacci sequence of length *sequence_length*\"\n", " sequence = [0,1]\n", " if sequence_length < 1:\n", " print \"Fibonacci sequence only defined for length 1 or greater\"\n", " return\n", " if 0 < sequence_length < 3:\n", " return sequence[:sequence_length]\n", " for i in range(2,sequence_length): \n", " sequence.append(sequence[i-1]+sequence[i-2])\n", " return sequence" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now call `fibonacci()` for different sequence_lengths" ] }, { "cell_type": "code", "collapsed": false, "input": [ "fibonacci(2)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "fibonacci(15)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This function is not very robust - it expects a number as a parameter but it doesn't check that it actually received a number. If we pass something else like a string it will break at some point and throw an exception:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "fibonacci(\"text\")" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you write code where you are expecting input from an external source then it's important to check that the input is sane and to handle errors nicely. At the same time it's important to test the function you write over the range of values you expect just to make sure you have programmed what you thought you did. In fact there are coding methodologies that advocate writing the tests first before you write the function. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `fibonacci` function will return a list and we can use it as such. Consequently we can assign the output to a variable, use it directly in calculation, or access its values. e.g. make sure you understand what is going on in the following:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "fibonacci(11)[6]*2" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is a function that will be useful for this lab - it generates a list of numbers from a minimum to a maximum with an abritrary step size. As opposed to the built in `range` function, our function will allow floating point numbers. In the next lab we will find much more efficient ways of generating such data, but for now we'll roll our own." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def rangef(xmin, xmax, dx):\n", " out = []\n", " steps = int(round((xmax-xmin)/float(dx)))\n", " for step in range(steps):\n", " x = step*dx+xmin\n", " out.append(x)\n", " \n", " return out" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, for example, we can generate ranges like" ] }, { "cell_type": "code", "collapsed": false, "input": [ "rangef(0.5,5,.5)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ " Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Write a function that will take four parameters: `omega`, `x0`, `phi`, and a list of times; and which outputs a list with the value of a harmonic oscillator at those times. i.e. it calculates $x_0\\cos(\\omega t+\\phi)$." ] }, { "cell_type": "code", "collapsed": true, "input": [ "def harmonic_oscillator(omega, x0, phi, times):\n", " # write your code here\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3 Matplotlib\n", "\n", "---\n", "\n", "Above we introduced modules, such as `math`, and how they add to the built in functionality of the language. *Python* has a rich eco-system of third-party modules including some excellent ones for scientific analysis. In the remainder of this lab we'll look at `matplotlib` - a module for producing graphs. In the next lab we'll look at modules for arrays, matrices and linear algebra. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a more in depth at what is possible with `matplotlib` take a look at the following:\n", "\n", "* [Matplotlib](http://matplotlib.org) - matplotlib home\n", "* [2D and 3D plotting in Python](http://nbviewer.ipython.org/github/jrjohansson/scientific-python-lectures/blob/master/Lecture-4-Matplotlib.ipynb) - an ipython notebook introducing matplotlib\n", "* [Matplotlib gallery and code](http://matplotlib.org/gallery.html) - examples of what matplotlib can do\n", "* [Matplotlib In-depth](http://www.astro.washington.edu/users/vanderplas/Astr599/notebooks/12_AdvancedMatplotlib) - A notebook by Jake Vanderplas" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following command is called *cell magic* and is part of ipython notebook. This particulat command will ensure that any plots we generate are placed inline in the notebook instead of opening a new window" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%matplotlib inline" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "No we import the module and give it an alias to it's easier to type:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import matplotlib.pyplot as plt" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First generate some data (make sure you've run the cell that defines `rangef`)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "X = rangef(-5,5,.05)\n", "Y = []\n", "for x in X:\n", " Y.append(exp(-x**2/2.0)*cos(5*x))" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that we have two lists `X` and `Y` we can generate a plot with the following code:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "fig = plt.figure() # create a figure object\n", "axes = fig.add_axes([0,0,1,1]) # the list defines the extent of the axes: left, bottom, width, height (range 0 to 1)\n", "axes.plot(X, Y, 'go-') # plot a green line with circle symbols" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some of the formatting options that are available in `plot` are:\n", "\n", "* Line styles: '-' solid, '--' dashed, '-.' dash-dot, ':' dotted\n", "* Marker styles '' no marker, '.' point, 'o' circle, 'v' triangle down, '^' triangle up, '*' star, 'x' x, 'D' diamond\n", "* Colours: \u2018b\u2019 blue, \u2018g\u2019 green, \u2018r\u2019 red, \u2018c\u2019 cyan, \u2018m\u2019 magenta, \u2018y\u2019 yellow, \u2018k\u2019 black, 'w' white" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is of course a lot more that you can do with `matplotlib`, this is the barest essentials to get you plotting." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ " Exercise" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Plot the values of your `harmonic_oscillator` function from the exercise above for three different frequencies and showing at least a few oscillations at the lowest frequency." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }