# Plotting Graphs¶

In this notebook, we will cover variables in Python, Numpy arrays, and plotting with Matplotlib.

We will mostly be following Chapter 1 of Programming for Computations - Python by Svein Linge and Hans Petter Langtangen.

## Variables¶

Variables can be assigned values with the = operator.

In [1]:
x = 3


The variable keeps the same value until it is changed by the program.

In [2]:
print(x)

3


In math the statement x=x+1 is always False (assuming x is a real number). In Python, it means that the program should first compute the value of x+1 and then store it in the variable x. This results in 4 being stored in x.

In [3]:
x = x+1
print(x)

4


Note that variables can store more than just numbers. Here, we store and add two strings (which concatenates).

In [4]:
s1 = "We are using "
s2 = "Python to compute."
print(s1+s2)

We are using Python to compute.


Here we store a 4-tuple in v.

In [5]:
v = (1,2,3,4)
print(v)

(1, 2, 3, 4)


Tuples are not quite vectors, for example, 3*v is three copies of v concatenated.

In [6]:
3*v

Out[6]:
(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4)

In [7]:
v + (5,6)

Out[7]:
(1, 2, 3, 4, 5, 6)

You can access the individual entries using the form v[i] where i runs from zero up through one less than the number of entries in v. For example the 4th entry can be obtained by:

In [8]:
v[3]

Out[8]:
4

We'll come back to discussing tuples later in the course.

## Numerical Python (NumPy)¶

Numpy is the main numerical math package. It has support for vectors and matrices that Python lacks.

You load Numpy with the command:

In [9]:
import numpy as np    # standard way of importing numpy


Now commands in the Numpy package can be called with the syntax np.command.

(The text after # above is a comment and is ignored by Python.)

In lieu of tuples, we can use numpy arrays for vectors. For example:

In [10]:
v = np.array([1,2,3,4])
v

Out[10]:
array([1, 2, 3, 4])
In [11]:
3*v

Out[11]:
array([ 3,  6,  9, 12])
In [12]:
v+v

Out[12]:
array([2, 4, 6, 8])

Computing cos(v) with cos from the math package will fail, but numpy has its own cosine function which evaluates termwise. So, np.cos(v) will compute $$(\cos 1, \cos 2, \cos 3, \cos 4).$$

In [13]:
np.cos(v)

Out[13]:
array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362])

You can type np. and press the Tab key to see what commands are available. Then you can type np.abs? and Shift-Enter (for example) to see the documentation of a command.

## Plotting with Matplotlib¶

You can import Mathplotlib's pyplot using:

In [14]:
import matplotlib.pyplot as plt

In [15]:
x = np.array([-2, -1, 0, 1, 2])


We'll plot the points $(x_i,y_i)$ where $x_i$ is in the list above and $y_i=x_i^2-1$. Arithmetic in arrays is done component wise. So the following list gives the y-values:

In [16]:
y = x*x-1
y

Out[16]:
array([ 3,  0, -1,  0,  3])

The following gives a plot of the points $(x_i, y_i)$:

In [17]:
plt.plot(x, y, 'ro')
plt.show()


The string 'ro' above indicates that this is a list plot: The o indicates to plot points, and the r indicates to plot in red. Other options for plotting can be found by typing plt.plot? and Shift+Enter. You need to scroll down to the bottom of the Notes section to see a complete description of the fmt string. Alternately take a look at the api posted to the matplotlib website.

In [18]:
plt.show(plt.plot(x, y))


To get a nicer curve, we should use more points. The following gives 101 points equally spaced between -2 and 2:

In [19]:
x = np.linspace(-2, 2, 101) # 1001 might be better than 101...
x

Out[19]:
array([-2.  , -1.96, -1.92, -1.88, -1.84, -1.8 , -1.76, -1.72, -1.68,
-1.64, -1.6 , -1.56, -1.52, -1.48, -1.44, -1.4 , -1.36, -1.32,
-1.28, -1.24, -1.2 , -1.16, -1.12, -1.08, -1.04, -1.  , -0.96,
-0.92, -0.88, -0.84, -0.8 , -0.76, -0.72, -0.68, -0.64, -0.6 ,
-0.56, -0.52, -0.48, -0.44, -0.4 , -0.36, -0.32, -0.28, -0.24,
-0.2 , -0.16, -0.12, -0.08, -0.04,  0.  ,  0.04,  0.08,  0.12,
0.16,  0.2 ,  0.24,  0.28,  0.32,  0.36,  0.4 ,  0.44,  0.48,
0.52,  0.56,  0.6 ,  0.64,  0.68,  0.72,  0.76,  0.8 ,  0.84,
0.88,  0.92,  0.96,  1.  ,  1.04,  1.08,  1.12,  1.16,  1.2 ,
1.24,  1.28,  1.32,  1.36,  1.4 ,  1.44,  1.48,  1.52,  1.56,
1.6 ,  1.64,  1.68,  1.72,  1.76,  1.8 ,  1.84,  1.88,  1.92,
1.96,  2.  ])
In [20]:
y = x*x-1

In [21]:
plt.plot(x, y)
plt.show()


Here is a nicer plot:

In [22]:
x = np.linspace(-2, 2, 101)
y = x*x-1
plot3 = plt.plot(x, y,'g')
plt.xlabel('$x$') # The dollar signs denote LaTeX.
plt.ylabel('$y$')
plt.title('The graph of $y=x^2-1$')
plt.grid(True)
plt.show()


The plot command can also plot several functions at once. You just repeat the notation inside of plt.plot() twice. For example:

In [23]:
plt.plot(x, 2*x, 'r', x, 4-2*x**2, 'g')
plt.grid(True)
plt.show()


There is also no reason that the x-values have to be equally spaced. Here is an example.

In [24]:
theta_values = np.linspace(0, 2*np.pi, 100)
plt.plot(np.cos(theta_values), np.sin(theta_values))
plt.show()


Because of the aspect ratio, the circle looks like an ellipse. The following corrects this.

In [25]:
theta_values = np.linspace(0, 2*np.pi, 100)
plt.axes().set_aspect(1)
plt.plot(np.cos(theta_values), np.sin(theta_values))
plt.show()


## A taste of functions¶

I think it is good to introduce the idea of simple python functions for mathematics. (In programming, there is another related notion of function.)

The following represents the function $f(x)=x^3-x$.

In [26]:
def f(x):
return x**3 - x


The function can act on numbers:

In [27]:
f(1)

Out[27]:
0
In [28]:
f(2)

Out[28]:
6

It also can be used for plotting.

In [29]:
x_values = np.linspace(-1.5, 1.5, 100)

In [30]:
plt.plot(x_values, f(x_values))
plt.show()


Functions don't need to simply return numbers, they can return any Python object. In particular, a function can return a function. Here is an example of currying, when a function returns a function.

The Gaussian with expected value $m$ and variation $s$ is given by the formula $$f(x)=\frac{1}{s \sqrt{2 \pi}} \exp \left(-\frac{1}{2} \left(\frac{x-m}{s}\right)^2\right).$$

In [31]:
from numpy import sqrt, exp, pi

def gaussian(m, s):
def f(x):
return exp(-0.5 * ((x-m)/s)**2)/(sqrt(2*pi)*s)
return f


Note that gaussian returns the function f, and the function f can make use of the variables m and s that were passed to Gaussian.

The following gives the gaussian with $m=0$ and $s=2$.

In [32]:
g = gaussian(0, 2)


Then we can evaluate $g$ like a normal function.

In [33]:
g(1)

Out[33]:
0.17603266338214976

The following plots the Gaussian.

In [34]:
x_values = np.linspace(-10, 10, 100)
plt.plot(x_values, g(x_values))
plt.show()