Introduction to Python

Note that BornAgain Win/Mac requires Python 2.7

Clone the BornAgain Tutorial Repository

From command line:

git clone https://github.com/scgmlz/BornAgain-tutorial.git

Windows/Mac: can also use Github Desktop.

Power Users: Build BornAgain with Python 3 Support

git clone https://github.com/scgmlz/BornAgain.git
mkdir build; cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DBORNAGAIN_USE_PYTHON3=ON
make && make install

Verify your Python Environment

Check the Python version:

$ python --version
Python 3.5.2

Check for numpy and matplotlib

$ python -c "import numpy"
$ python -c "import matplotlib"

Check for BornAgain Python module

$ python -c "import bornagain"

Running Python

  • Direct from command line:

    $ python -c "print 'hello, world'"
    hello, world
  • Run script from command line:

    $ echo "print 'hello, world'" > hello.py
    $ python hello.py
    hello, world
  • Default interactive interpreter:

    $ python
    >>> x = 5
    >>> x * x
    25
  • IPython interactive interpreter:

    $ ipython
    In [1]: x = 5
    In [2]: x * x
    Out [2]: 25
  • IPython interactive notebook:

    $ ipython notebook
  • Jupyter interactive notebook:

    $ jupyter notebook
  • Run within PyCharm IDE

Notebook support is included by default with Anaconda, and can be installed as an optional package on most Linux distros.

Python 2.7 vs. 3.5 Compatibility

There are a few important differences between Python 2.7 and 3.5. The line below is used to ensure that this notebook remains compatible with both. There is a list of differences between Python 2.7 and 3.5 near the end of this notebook.


In [1]:
from __future__ import print_function

Basic Data Types

Python has many data types, e.g.

  • numeric: int, float, complex
  • string
  • boolean values, i.e. true and false
  • sequences: list, tuple
  • dict

Variables are declared via assignment:

x = 5

In [2]:
# scratch area

Numeric Types

Python numeric types are similar to those in other languages such as C/C++.

x = 5           # int
x = 10**100     # long (2.7) or int (3.5)
x = 3.141592    # float
x = 1.0j        # complex

Note: ordinary machine types can be accessed/manipulated through the ctypes module.


In [3]:
# scratch area

Arithmetic Operations

3 + 2           # addition
3 - 2           # subtraction
3 * 2           # multiplication
3 ** 2          # exponentiation
3 / 2           # division (warning: int (2.7) or float (3.5))
3 % 2           # modulus

In [4]:
# scratch area

Exercise

Use the Python interpreter to perform some basic arithemetic.

Strings

x = "hello"   # string enclosed with double quotes
y = 'world'   # string enclosed with single quotes
x + ' ' + y   # string concatenation via +
"{} + {} = {}".format(5 , 6, 5+6) # string formatting

In [5]:
# scratch area

Lists

x = [1, 2, 3]     # initialize list
x[1] = 0          # modify element
x.append(4)       # append to end
x.extend([5, 6]) # extend
x[3:5]            # slice

In [6]:
# scratch area

Tuples

Tuples are similar to lists, but are immutable:

x = (1, 2, 3)   # initialize a tuple with ()
x[0] = 4        # will result in error

In [7]:
# scratch area

List Comprehension

Comprehension provides a convenient way to create new lists:

[ i for i in range (5) ]      # result: [0, 1, 2, 3, 4]
[ i**2 for i in range (5) ]  # result: [0, 1, 4, 9, 16]
the_list = [5, 2, 6, 1]    
[ i**2 for i in the_list ]   # result [25, 4, 36, 1]

In [8]:
# scratch area

Exercise

Create a list of floating point numbers and then create a second list which contains the squares of the entries of teh fist list

Boolean Values and Comparisons

Boolean types take the values True or False. The result of a comparison operator is boolean.

5 < 6    # evalutes to True
5 >= 6   # evaluates to False
5 == 6   # evaluates to False

Logical operations:

True and False  # False
True or False   # True
not True        # False
True ^ False    # True (exclusive or)

In [9]:
# scratch area

Functions

Functions are defined with def:

def hello():
    print 'hello, world'

Note: Python uses indentation to denote blocks of code, rather than braces {} as in many other languages. It is common to use either 4 spaces or 2 spaces to indent. It doesn't matter, as long as you are consistent.

Use the return keyword for a function which returns a value:

def square(x):
    return x**2

In [10]:
# scratch area

Loops and Flow Control

For loop:


In [40]:
for i in range(10):
    print(i**2)


0
1
4
9
16
25
36
49
64
81

It is also possible to use for..in to iterate through elements of a list:


In [42]:
for i in ['hello', 'world']:
    print(i)


hello
world

While loops have the form while condition:


In [13]:
i = 0
while i < 10:
    print(i**2)
    i = i + 1


hello
world

The keywords break and continue can be used for flow control inside a loop

  • continue: skip to the next iteration of the loop
  • break: jump out of the loop entirely

In [65]:
for i in range(10):
    if i == 3:
        continue
    if i == 7:
        break
    print(i)


0
1
2
4
5
6

Use the keywords if, elif, else for branching

if 5 > 6:
    # never reached
    pass
elif 1 > 2:
    # reached
    pass
else:
    # never reached
    pass

In [15]:
# scratch area

Exercise

Write a function fib(n) which returns the nth Fibonacci number. The Fibonacci numbers are defined by

  • fib(0) = fib(1) = 1
  • fib(n) = fib(n-1) + fib(n-2) for n >= 2.

Exercise

”Write a program that prints the numbers from 1 to 100. But for multiples of three print Fizz instead of the number and for the multiples of five print Buzz. For numbers which are multiples of both three and five print FizzBuzz.”

http://wiki.c2.com/?FizzBuzzTest


In [16]:
# scratch area

Modules

Load external modules (built-in or user-defined) via import:


In [17]:
import math
print(math.pi)
print(math.sin(math.pi/2.0))


3.141592653589793
1.0

Rename modules with as:


In [18]:
import math as m
print(m.pi)


3.141592653589793

Load specific functions or submodules:


In [19]:
from math import pi, sin
print(sin(pi/2.0))


1.0

In [20]:
# scratch area

User-defined Modules

Any code written in a separate file (with .py extension) can be imported as a module. Suppose we have a script my_module.py which defines a function do_something(). Then we can call it as


In [67]:
import my_module
my_module.do_something()


doing something from my_module!

Exercise

Implement your FizzBuzz solution as a function called FizzBuzz() in a module called fizzbuzz. Check that it works by importing it and calling FizzBuzz() in a separate script.


In [21]:
# scratch area

numpy

numpy is a module used for numerical calculation. The main data type is numpy.array, which is a multidimensional array of numbers (integer, float, complex).


In [68]:
import numpy as np
x = np.array([1, 2, 3, 4])
print(x.sum())
print(x.mean())


10
2.5

The basic arithmetic operations work elementwise on numpy arrays:


In [69]:
x = np.array([1, 2, 3, 4])
y = np.array([5, 6, 7, 8])

print(x + y)
print(x * y)
print(x / y)


[ 6  8 10 12]
[ 5 12 21 32]
[ 0.2         0.33333333  0.42857143  0.5       ]

It is also possible to call functions on numpy arrays:


In [70]:
x = np.array([1, 2, 3, 4])
print(np.sin(x))
print(np.log(x))


[ 0.84147098  0.90929743  0.14112001 -0.7568025 ]
[ 0.          0.69314718  1.09861229  1.38629436]

In [22]:
# scratch area

Generating numpy Arrays

numpy arrays can be generated with zeros, ones, linspace, and rand:


In [71]:
print(np.zeros(4))
print(np.ones(3))
print(np.linspace(-1, 1, num=4))
print(np.random.rand(2))


[ 0.  0.  0.  0.]
[ 1.  1.  1.]
[-1.         -0.33333333  0.33333333  1.        ]
[ 0.34741091  0.66844901]

In [72]:
# scratch area

Plotting with matplotlib

We use matplotlib.pyplot for plotting:


In [73]:
import numpy as np
from matplotlib import pyplot as plt

x = np.linspace(-3.14, 3.14, num=100)
y = np.sin(x)

plt.plot(x, y)
plt.xlabel('x values')
plt.ylabel('y')
plt.title('y=sin(x)')
plt.show()


Exercise

Create plots the following functions

  • f(x) = log(x)
  • f(x) = sqrt(x)
  • f(x) = x**2
  • f(x) = log(1 + x**2)
  • anything else you might find interesting or challenging

Combining Plots

Plots can be combined using addition:


In [74]:
x = np.linspace(-10, 10, num=100)

y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.arctan(x)


plt.plot(x, y1, x, y2, x, y3)
plt.show()



In [ ]:

todo array manipulation routines numpy.flipud, fliplr, transpose, rot90, flatten, ravel

Colormap Plots

Plot color maps with pcolormesh:


In [81]:
x = np.linspace (-1, 1, num =100)
y = np.linspace (-1, 1, num =100)
xx, yy = np.meshgrid (x, y)
z = np.sin(xx**2 + yy**2 + yy)
plt.pcolormesh(x, y, z, shading = 'gouraud')
plt.show()


Or with imshow:


In [86]:
plt.imshow(z, aspect='auto')
plt.show()


Note that the image is flipped because images start from top left and go to bottom right. We can fix this with flipud:


In [87]:
plt.imshow(np.flipud(z), aspect='auto')
plt.show()



In [27]:
# scratch area

3D Plots


In [88]:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm

%matplotlib inline
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(xx, yy, z, rstride=5, cstride=5, cmap=cm.coolwarm, linewidth=1, antialiased=True)
plt.show()


3D Wireframe Plot


In [89]:
%matplotlib inline
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_wireframe(xx, yy, z, rstride=5, cstride=5, antialiased=True)
plt.show()


See http://matplotlib.org/gallery.html

Plotting Exercise

Consider the function f(x, y) = exp(x + 1.0j*y) for −4 ≤ x, y ≤ 4. Create colormap and 3d plots of the magnitude, real, and imaginary parts of f.


In [30]:
# scratch

Plotting Images


In [90]:
x = np.linspace(-2, 2, num=100)
y = np.linspace(-2, 2, num=100)

result = np.flipud(np.array([[u*v for u in x] for v in y]))

fig = plt.figure()
plt.imshow(result, extent=[x.min(), x.max(), y.min(), y.max()], aspect='auto')
plt.show()


Classes

Classes can be used to package data and methods together:


In [91]:
class SomeClass:
    def __init__ (self, x):
        self.x = x

    def doSomething(self):
        print("my x value is {}".format(self.x))
        
obj = SomeClass(5)
obj.doSomething()


my x value is 5

In [33]:
# scratch area

Inheritance

Classes can be derived from others:


In [34]:
class SomeOtherClass (SomeClass):
    def __init__ (self, x, y):
        SomeClass.__init__ (self, x) 
        self.y = y

    def doSomethingElse(self):
        print("my y value is {}".format(self.y))
        
other_obj = SomeOtherClass(5, 6)
other_obj.doSomething()
other_obj.doSomethingElse()


my x value is 5
my y value is 6

Polymorphism

An instance of a derived class is automatically an instance of its base class:


In [92]:
print('The type of obj is {}'.format(type(obj)))
print('The type of other_obj is {}'.format(type(other_obj)))

print('obj is instance of SomeClass? {}'.format(isinstance(obj, SomeClass)))
print('obj is instance of SomeOtherClass? {}'.format(isinstance(obj, SomeOtherClass)))

print('other_obj is instance of SomeClass? {}'.format(isinstance(obj, SomeClass)))
print('other_obj is instance of SomeOtherClass? {}'.format( isinstance(obj, SomeOtherClass)))


The type of obj is <class '__main__.SomeClass'>
The type of other_obj is <class '__main__.SomeOtherClass'>
obj is instance of SomeClass? True
obj is instance of SomeOtherClass? False
other_obj is instance of SomeClass? True
other_obj is instance of SomeOtherClass? False

In [36]:
# scratch area

Exercise

todo


In [37]:
# todo

todo Python 2 vs. 3 Key differences include: print statement integer division int vs. long new style classes some standard modules/functions have been moved/renamed The “ future ” module can be used to write code compatible with both Python 2 and 3.


In [ ]: