# Introduction to `numpy`, `sympy` and `matplotlib`

Kevin J. Walchko
created 5 July 2017

---

Matplotlib, NumPy and pysym are open-source add-on modules to Python that provide common mathematical and numerical routines in pre-compiled, fast functions. These are growing into highly mature packages that provide functionality that meets, or perhaps exceeds, that associated with common commercial software like MatLab. There is little that Matlab can do that python, numpy and other modules can't do too.

Matplotlib is a plotting library modeled after Matlab's plotting commands. We will use `matplotlib` to produce some graphs, but really use it heavily when we get to image processing. Again, we will delay the image specific functions until we get to that point. Here we are just going to learn the basics.

## Objectives

- Understand how to do very basic linear algebra in python
- Understand how to do symbolic manipulation in python
- Understand how to use matplotlib
   - How to insert LaTeX math symbols into plots
- Understand how to plot engineering data in a Jupyter notebook

## References

- [numpy tutorial](https://docs.scipy.org/doc/numpy-dev/user/quickstart.html)
- [numpy for matlab users](https://docs.scipy.org/doc/numpy-dev/user/numpy-for-matlab-users.html)
- [sympy](http://www.sympy.org/en/index.html)
- [sympy tutorials](http://docs.sympy.org/latest/tutorial/index.html)
- [matplotlib examples](https://matplotlib.org/users/pyplot_tutorial.html)
- [matplotlib summary](https://matplotlib.org/api/pyplot_summary.html)
- [matplotlib gallery of plots](https://matplotlib.org/gallery.html)
- [LaTEX math symbols](http://web.ift.uib.no/Teori/KURS/WRK/TeX/symALL.html)

## Setup


```python
%matplotlib inline
from __future__ import division
from __future__ import print_function
import numpy as np  # common to rename numpy to np ... because programmers are lazy :)
from matplotlib import pyplot as plt
```

# How Does the Jupyter Notebook Work?

Well, I probably should have covered this last lesson, but there already was a lot of material in that lesson. This one is shorter. When you run the command `jupyter notebook` from a bash terminal, it lauches a webserver and a web browser that shows the contents of the current directory. When you click on a jupyter file, `lsn4.ipynb`, the webserver reads the file and launches a kernel to run the notebook. Kernels are processes that run interactive code in a particular programming language and return output to the user. 



Jupyter supports many different languages, we are only using python. However, there are a [bunch of kernels](https://github.com/jupyter/jupyter/wiki/Jupyter-kernels) for other languages you can use if you want, like: Go, Ruby, Julia, R, etc.

## How To Shut Things Down

Since you are launching both a web server and browser, you need to close the browser and shutdown the server. The server can be shutdown in one of two ways.

1. In the bash window, press contro-C
1. Or, just close the bash window

Either of these will work.

# Numpy

First let's do some simple matrix/vector operations, since we will need this for our serial manipulator work. We will also use `numpy` later for OpenCV imagery work, but we will push that off to later when we need it. There are some specific things we need  to understand when working with images that would be best covered right before we need it.


```python
# lets create an array
a = np.array([1,2,3])  # you could call this a 3 dimensional vector if you want
print(a)
```

    [1 2 3]



```python
# let's create a matrix with rows: [1,2,3], [4,5,6], and [6,7,8]
m = np.array([
    [1,2,3],
    [4,5,6],
    [6,7,8]
])
print('m =', m)
print('size', m.size)
print('shape', m.shape)
print('type', m.dtype)
```

    m = [[1 2 3]
     [4 5 6]
     [6 7 8]]
    size 9
    shape (3L, 3L)
    type int32


Now, generally we don't think about data types with python, but for math (and later working with images in OpenCV) we will. *Note:* you will probably have to prefix these with a namespace like `np`: `np.uint8`. This assumes you did the `import numpy as np`. 

| Data type	| Description |
|---|:---|
| bool_	| Boolean (True or False) stored as a byte
| int_	| Default integer type (same as C long; normally either int64 or int32)
| intc	| Identical to C int (normally int32 or int64)
| intp	| Integer used for indexing (same as C ssize_t; normally either int32 or int64)
| int8	| Byte (-128 to 127)
| int16	| Integer (-32768 to 32767)
| int32	| Integer (-2147483648 to 2147483647)
| int64	| Integer (-9223372036854775808 to 9223372036854775807)
| uint8	| Unsigned integer (0 to 255)
| uint16 | Unsigned integer (0 to 65535)
| uint32 | Unsigned integer (0 to 4294967295)
| uint64 | Unsigned integer (0 to 18446744073709551615)
| float_ | Shorthand for float64.
| float16 | Half precision float: sign bit, 5 bits exponent, 10 bits mantissa
| float32 | Single precision float: sign bit, 8 bits exponent, 23 bits mantissa
| float64 | Double precision float: sign bit, 11 bits exponent, 52 bits mantissa
| complex_ | Shorthand for complex128.
| complex64	| Complex number, represented by two 32-bit floats (real and imaginary components)
| complex128 | Complex number, represented by two 64-bit floats (real and imaginary components)

Honestely, I generally only use `np.float` for math or `np.unit8` for OpenCV. However, if you are calculating 3-phase power from ENGR 311, you *might* need `np.complex`, but I am not an AC power guy.


```python
# there are functions for special matrices
# zeros matrix
z = np.zeros((3,3))
print(z)

# Identity matrix
o = np.eye(3)
print(o)
```

    [[0. 0. 0.]
     [0. 0. 0.]
     [0. 0. 0.]]
    [[1. 0. 0.]
     [0. 1. 0.]
     [0. 0. 1.]]



```python
# numpy even works in multiple dimension beyond standard MxN matrices we will do for this class.
# numpy actually lets you do n dimensional tensor math, and if you are Einstein, that is awesome!
np.zeros((3,4,5)) # go on and add some more dimentions like: (3,3,3,3)
```




    array([[[0., 0., 0., 0., 0.],
            [0., 0., 0., 0., 0.],
            [0., 0., 0., 0., 0.],
            [0., 0., 0., 0., 0.]],
    
           [[0., 0., 0., 0., 0.],
            [0., 0., 0., 0., 0.],
            [0., 0., 0., 0., 0.],
            [0., 0., 0., 0., 0.]],
    
           [[0., 0., 0., 0., 0.],
            [0., 0., 0., 0., 0.],
            [0., 0., 0., 0., 0.],
            [0., 0., 0., 0., 0.]]])




```python
# let's multiply them together
# NOTE: you can NOT do v = M * a
a = np.array([1,2,3])
v = m.dot(a)
print('m * a = m.dot(a) =', v)
```

    m * a = m.dot(a) = [14 32 44]



```python
# let's remember what v and m are
print('v = ', v, '\n')
print('m = ', m, '\n')

# let's access the number of each ... all zero based arrays
print('first v:', v[0])   # this is a vector (or array) so only 1 number given to get the value
print('first m:', m[0,0]) # this is a matrix, so you need 2 numbers to get the value 

# now let's do the last number
print('last v:', v[2])
print('last m:', m[2,2])

# remember: m[row, column]
print('\nm[0,1]', m[0,1])
print('m[2]', m[2], ' this gives me the entire row')

# let's get their dimensions
print('\nlen(a):', len(v))
print('v.shape:', v.shape)
print('m.shape:', m.shape)
```

    v =  [14 32 44] 
    
    m =  [[1 2 3]
     [4 5 6]
     [6 7 8]] 
    
    first v: 14
    first m: 1
    last v: 44
    last m: 8
    
    m[0,1] 2
    m[2] [6 7 8]  this gives me the entire row
    
    len(a): 3
    v.shape: (3L,)
    m.shape: (3L, 3L)


**Remeber for later:** OpenCV uses numpy to represent images. We access things by Matrix[row, col]. During image processing we have the same matrix interface, but we access a pixel by Image[height, width]. Here, height and row are the same while column and width are the same. This is backwards from how we usually think about images or screen resolutions, width x height like: 640 x 480.


```python
n = np.array([
    [1,0,0],
    [0,2,0],
    [0,0,3]
])

# inverse
nn = np.linalg.inv(n)
print('nn:\n', nn)

# calculate the determinate
nn = np.linalg.det(n)
print('det(n) =',nn)

# calculate the norm
nn = np.linalg.norm(n)
print('norm(n) =', nn)
```

    nn:
     [[1.         0.         0.        ]
     [0.         0.5        0.        ]
     [0.         0.         0.33333333]]
    det(n) = 6.0
    norm(n) = 3.7416573867739413



```python
# too much typing ... let's shorten it
# just becareful not to alias another python function ... python for example
# already has a built in abs (absolute) function, but so numpy
from numpy.linalg import inv, det, norm

# inverse
nn = inv(n)
print('nn', nn)

# calculate the determinate
nn = det(n)
print('det(n)', nn)

# calculate the norm
nn = norm(n)
print('norm(n)', nn)
```

    nn [[1.         0.         0.        ]
     [0.         0.5        0.        ]
     [0.         0.         0.33333333]]
    det(n) 6.0
    norm(n) 3.7416573867739413



```python
# let's iterate over a matrix and print each value out
# remember, m.shape returns (rows, cols) tuple
m = np.array([
    [1,2,3],
    [4,5,6],
    [6,7,8]
])

# remember, shape gives rows, cols
mm, nn = m.shape
for i in range(mm):
    for j in range(nn):
        print('m[{}, {}] = {}'.format(i,j,m[i,j]))

print('') # add a blank line between the 2 prints
print(m)
```

    m[0, 0] = 1
    m[0, 1] = 2
    m[0, 2] = 3
    m[1, 0] = 4
    m[1, 1] = 5
    m[1, 2] = 6
    m[2, 0] = 6
    m[2, 1] = 7
    m[2, 2] = 8
    
    [[1 2 3]
     [4 5 6]
     [6 7 8]]



```python
# we can do it another way
# also, enumerate is a nice way to get a counter
for i, r in enumerate(m):
    for j, c in enumerate(r):
        print('m[{}, {}] = {}'.format(i,j,c))
```

    m[0, 0] = 1
    m[0, 1] = 2
    m[0, 2] = 3
    m[1, 0] = 4
    m[1, 1] = 5
    m[1, 2] = 6
    m[2, 0] = 6
    m[2, 1] = 7
    m[2, 2] = 8


## Documentation

If you don't understand what a function does, Google it or (like all python libraries) use the built in help system: `help(numpy.inv)`. 

You can also find out what is availble in a  package by: `dir(numpy)`. This would list everything in `numpy`. Or if you wanted to know what was in the linear algebra sub-package: `dir(numpy.linalg)`.

# Sympy

You can use sympy to manipulate equations symbolically. This will be useful later when we do forward/inverse kinematics.

1. get library and functions you need: from sympy import symbols, simplify
   1. you may also need other things like trig functions: from sympy import sin, cos, pi
1. define your symbols()
1. build your equations
1. then run simplify()
1. finally substitute in values for variables if needed


```python
from sympy import symbols, sin, cos, pi, simplify
```


```python
# create some symbols and a symbolic equation
a, b = symbols('a b')
eqn = sin(a)*sin(a)+cos(a)**2+sin(b)/cos(b) + a
print(eqn)
```

    a + sin(a)**2 + sin(b)/cos(b) + cos(a)**2



```python
# simplify the equations
# sin^2 + cos^2 = 1
# sin/cos = tan
e = simplify(eqn)
print(e)
```

    a + tan(b) + 1



```python
# e is a numpy object, uncomment and see all of the amazing function (methods in CompSci lingo) that are associated with it
dir(e)
```




    ['__abs__',
     '__add__',
     '__class__',
     '__complex__',
     '__delattr__',
     '__div__',
     '__doc__',
     '__eq__',
     '__float__',
     '__floordiv__',
     '__format__',
     '__ge__',
     '__getattribute__',
     '__getnewargs__',
     '__getstate__',
     '__gt__',
     '__hash__',
     '__init__',
     '__int__',
     '__le__',
     '__long__',
     '__lt__',
     '__mod__',
     '__module__',
     '__mul__',
     '__ne__',
     '__neg__',
     '__new__',
     '__pos__',
     '__pow__',
     '__radd__',
     '__rdiv__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__rfloordiv__',
     '__rmod__',
     '__rmul__',
     '__rpow__',
     '__rsub__',
     '__rtruediv__',
     '__setattr__',
     '__setstate__',
     '__sizeof__',
     '__slots__',
     '__str__',
     '__sub__',
     '__subclasshook__',
     '__truediv__',
     '_args',
     '_assumptions',
     '_combine_inverse',
     '_compare_pretty',
     '_constructor_postprocessor_mapping',
     '_diff_wrt',
     '_eval_adjoint',
     '_eval_as_leading_term',
     '_eval_conjugate',
     '_eval_derivative',
     '_eval_difference_delta',
     '_eval_evalf',
     '_eval_expand_complex',
     '_eval_interval',
     '_eval_is_algebraic',
     '_eval_is_algebraic_expr',
     '_eval_is_antihermitian',
     '_eval_is_commutative',
     '_eval_is_complex',
     '_eval_is_finite',
     '_eval_is_hermitian',
     '_eval_is_imaginary',
     '_eval_is_integer',
     '_eval_is_irrational',
     '_eval_is_negative',
     '_eval_is_nonnegative',
     '_eval_is_nonpositive',
     '_eval_is_odd',
     '_eval_is_polynomial',
     '_eval_is_positive',
     '_eval_is_rational',
     '_eval_is_rational_function',
     '_eval_is_real',
     '_eval_is_zero',
     '_eval_lseries',
     '_eval_nseries',
     '_eval_power',
     '_eval_rewrite',
     '_eval_subs',
     '_eval_transpose',
     '_evalf',
     '_exec_constructor_postprocessors',
     '_expand_hint',
     '_explicit_class_assumptions',
     '_from_args',
     '_from_mpmath',
     '_has',
     '_has_matcher',
     '_hashable_content',
     '_matches_commutative',
     '_matches_simple',
     '_mhash',
     '_mpc_',
     '_new_rawargs',
     '_op_priority',
     '_parse_order',
     '_prop_handler',
     '_random',
     '_recursive_call',
     '_sage_',
     '_sorted_args',
     '_subs',
     '_to_mpmath',
     '_xreplace',
     'adjoint',
     'apart',
     'args',
     'args_cnc',
     'as_base_exp',
     'as_coeff_Add',
     'as_coeff_Mul',
     'as_coeff_add',
     'as_coeff_exponent',
     'as_coeff_mul',
     'as_coefficient',
     'as_coefficients_dict',
     'as_content_primitive',
     'as_expr',
     'as_independent',
     'as_leading_term',
     'as_numer_denom',
     'as_ordered_factors',
     'as_ordered_terms',
     'as_poly',
     'as_powers_dict',
     'as_real_imag',
     'as_terms',
     'as_two_terms',
     'assumptions0',
     'atoms',
     'cancel',
     'canonical_variables',
     'class_key',
     'coeff',
     'collect',
     'combsimp',
     'compare',
     'compute_leading_term',
     'conjugate',
     'copy',
     'could_extract_minus_sign',
     'count',
     'count_ops',
     'default_assumptions',
     'diff',
     'doit',
     'dummy_eq',
     'equals',
     'evalf',
     'expand',
     'extract_additively',
     'extract_branch_factor',
     'extract_leading_order',
     'extract_multiplicatively',
     'factor',
     'find',
     'flatten',
     'fourier_series',
     'fps',
     'free_symbols',
     'fromiter',
     'func',
     'getO',
     'getn',
     'has',
     'identity',
     'integrate',
     'invert',
     'is_Add',
     'is_AlgebraicNumber',
     'is_Atom',
     'is_Boolean',
     'is_Derivative',
     'is_Dummy',
     'is_Equality',
     'is_Float',
     'is_Function',
     'is_Indexed',
     'is_Integer',
     'is_Matrix',
     'is_Mul',
     'is_Not',
     'is_Number',
     'is_NumberSymbol',
     'is_Order',
     'is_Piecewise',
     'is_Point',
     'is_Poly',
     'is_Pow',
     'is_Rational',
     'is_Relational',
     'is_Symbol',
     'is_Vector',
     'is_Wild',
     'is_algebraic',
     'is_algebraic_expr',
     'is_antihermitian',
     'is_commutative',
     'is_comparable',
     'is_complex',
     'is_composite',
     'is_constant',
     'is_even',
     'is_finite',
     'is_hermitian',
     'is_hypergeometric',
     'is_imaginary',
     'is_infinite',
     'is_integer',
     'is_irrational',
     'is_negative',
     'is_noninteger',
     'is_nonnegative',
     'is_nonpositive',
     'is_nonzero',
     'is_number',
     'is_odd',
     'is_polar',
     'is_polynomial',
     'is_positive',
     'is_prime',
     'is_rational',
     'is_rational_function',
     'is_real',
     'is_symbol',
     'is_transcendental',
     'is_zero',
     'leadterm',
     'limit',
     'lseries',
     'make_args',
     'match',
     'matches',
     'n',
     'normal',
     'nseries',
     'nsimplify',
     'powsimp',
     'primitive',
     'radsimp',
     'ratsimp',
     'rcall',
     'refine',
     'removeO',
     'replace',
     'rewrite',
     'round',
     'separate',
     'series',
     'simplify',
     'sort_key',
     'subs',
     'taylor_term',
     'together',
     'transpose',
     'trigsimp',
     'xreplace']




```python
# substitute in some numbers for a and b
ee=e.subs([(b, 2.0), (a, 3.0)])
print(ee)
```

    1.81496013673848



```python
# this should give us the same answer
import math
3.0+math.tan(2.0)+1.0
```




    1.8149601367384811



# Matplotlib

This will allow us to plot sensor data, robot arm positions, a path through a map, images, etc. We will cover a few commands here, but revisit this later when we are doing image processing. The key commands are:

- plt.plot()
- plt.subplot()
- plt.legend()
- plt.title()
- plt.ylabel() and plt.xlabel()
- plt.grit()
- plt.text()

There really isn't anything hard here, just examples of the plotting commands we will use the most. See the [Matplotlib gallery](https://matplotlib.org/gallery.html) for more examples of what is possible.


```python
# Prepare the data
x = np.linspace(0, 100, 10)  # linspace(start, stop, number_of_points)
y = np.linspace(0, 10, 10)

# Plot the data
plt.plot(x, y, label='linear')

# make it look nice
plt.grid(True)
plt.legend()
plt.title('title')
plt.ylabel('y $\Omega$')  # you can also include latex math symbols
plt.xlabel('x');  # note, if you don't put the ';' at the end, it prints 
                  # the object address. Not an issue, but it annoys me
```


```python
from math import cos

# Prepare the data
x = np.linspace(0, 5, 100)  # linspace(start, stop, how_many_inbetween)
y1 = x                      # simple stupid y = x linear line
y2 = [n*cos(n) for n in y1] # remember this fancy way to use a for loop and create an array?

# similar to matlab
plt.plot(x,y1, 'r-', x,y2, 'b^')  # if you only put 1 array, plot assumes it is the y-axis

# make it look nice
plt.grid(True)
plt.title('title')
plt.ylabel('y1 and y2')
plt.xlabel('x');
```


```python
# let's put more than one plot together ... every use subplot in Matlab?
plt.subplot(1,2,1)
plt.plot(x, label='linear')
plt.title('no grid')

plt.subplot(1,2,2)
plt.plot(x, label='linear')
plt.title('grid');
plt.grid(True)
```

# Quiz Next Class

You can do the entire thing ahead of time if you want ... take a look at the next lesson. I suggest you come into class with the answers done. **Do not work with anyone else, come to me if you have questions!** I want this to be a learning oppertunity! You are now considered to know python, jupyter, matplotlib, and sympy.

# Exercises

- Run back through this notebook and play with things so you understand it. This will lay the foundation for the Quiz and Lab 2.

# Questions

1. How do you create a 2x3 matrix?
1. How do you create a 3x3 zero or ones (identity) matrix?
1. How do you add, multiply or divide 2 matrices together? How about a matrix and a vector?
1. How do you plot y = 3x-5 between [-5,5]? Make sure you turn on the grid, label the axes and give it title.


-----------

<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>.


```python

```

6b43e09166fcc56482045a68c4558c62af5db432
ipynb
Jupyter Notebook
website/block_1_basics/lsn4/lsn4.ipynb
MarsUniversity/ece387-robotics
96f855c0109823b0de279a0db2f3f862d3bd9009
MIT
2017-07-11T17:24:11.000Z
2017-07-11T17:24:11.000Z
website/block_1_basics/lsn4/lsn4.ipynb
MarsUniversity/ece387-robotics
96f855c0109823b0de279a0db2f3f862d3bd9009
MIT
2017-07-30T23:49:15.000Z
2017-09-25T02:32:06.000Z
website/block_1_basics/lsn4/lsn4.ipynb
MarsUniversity/ece387-robotics
96f855c0109823b0de279a0db2f3f862d3bd9009
MIT
Qwen/Qwen-72B
1. YES
2. YES