Imports the `numpy`

library as the name `np`

. This is a very common convention.

`import numpy as np`

Comparing Python lists and NumPy arrays.

a_list is a Python list

```
a_list = [1, 2, 3, 4, 5]
print('a_list is type', type(a_list))
```

a_array is a NumPy array

```
a_array = np.array(a_list)
print('a_array is type', type(a_array))
```

Can create Numpy arrays from a Python list and vice-versa

```
b_array = np.array([3, 2, 4, 1, 5])
b_list = list(b_array)
```

The `+`

operator concatenates two lists

`print('a_list + b_list =', a_list + b_list)`

The `+`

operator performs pairwise component addition for two arrays

`print('a_array + b_array =', a_array + b_array)`

The `+`

operator can also add a scalar to an array

`print('a_array + 5 =', a_array + 5)`

Similarly, `*`

will perform pairwise component multiplication

`print('a_array * b_array = ', a_array * b_array)`

Remember that when applied to a list and a scaler
`*`

will perform multiple concatenations

`print('a_list * 3 =', a_list * 3)`

When applied to two lists, however, `*`

yields

`TypeError: can't multiply sequence by non-int of type 'list'`

print('a_list * b_list =', a_list * b_list)

Importing the `pearsonr`

method from the `scipy.stats.stats`

module.
`scipy`

builds on `numpy`

.

`from scipy.stats.stats import pearsonr`

eight lists and their correlations

```
a = [1, 2, 3, 4, 5] # initial list
b = [1, 2, 3, 4, 5] # identical to `a`
c = [0, 1, 2, 3, 4] # identical to `a` minus 1
d = [2, 4, 6, 8, 10] # identical to `a` * 2
e = [1, 2, 3, 5, 4] # very similar, but not identical to `a`
f = [1, 5, 4, 2, 3] # not similar to `a`
g = [5, 4, 3, 2, 1] # opposite of `a`
h = [1, 1, 1, 1, 1] # flat shape; standard deviation of `h` is 0
```

Correlations between `a`

and the other lists:

```
comparisons = [b, c, d, e, f, g, h]
for comparison in comparisons:
```

`pearsonr`

returns a tuple corresponding to the r and p values

` corr, p = pearsonr(a, comparison)`

Correlation between `a`

and `b`

, `c`

, and `d`

is 1.0 (maximal).

Correlation between `a`

and `e`

is 0.9 (high, but not maximal).

Correlation between `a`

and `f`

is 0.1, indicating almost no correlation.

Correlation between `a`

and `g`

is -1.0,indicating a maximal inverse
inverse correlation.

Correlation between `a`

and `h`

is `nan`

(not a number), since the
calculation of correlation involves division by the standard deviations
(which for `h`

is 0).

` print('Correlation between', a, 'and', comparison, ':', corr)`

`harmonic_distance`

measures the Euclidean distance between two interval
vectors. This is identical to Richard Teitelbaum's "similarity index".
You can substitute different distance measures from the
`scipy.spatial.distance`

module. For instance, using `cityblock`

distance
recreates Robert Morris' "SIM" measure.

`p`

and `q`

are lists of pitches. `harmonic_distance`

depends on
music21 and scipy.

Returns the harmonic distance of `p`

and `q`

interpreted as chords based on
the Euclidean distance from the `scipy.spatial.distance`

module. Prints an
error message and returns `None`

if the lists are of unequal length.

`def harmonic_distance(p, q):`

```
from music21 import chord
from scipy.spatial import distance
if len(p) != len(q):
print('lists of pitches are of unequal lengths')
return None
```

Using the `music21`

`Chord`

class `.intervalVector`

property

```
iv_p = chord.Chord(p).intervalVector
iv_q = chord.Chord(q).intervalVector
return distance.euclidean(iv_p, iv_q)
```

Using `harmonic_distance`

to compare the harmonic similarity of three
`chords`

```
chords = [[0, 2, 3, 7], [0, 2, 4, 6], [0, 4, 8, 11]]
print('Harmonic distances')
for i in range(2):
u = chords[i]
for j in range(i+1, 3):
v = chords[j]
print(u, '<-->', v, ':', harmonic_distance(u, v))
```

`pyplot`

is a module in `matplotlib`

for plotting. `matplotlib depends on`

numpy`. See https://matplotlib.org/api/pyplot_api.html for more details.

`import matplotlib.pyplot as plt`

plotting two lists on the plane

```
x = [1, 2, 3, 4, 5]
y = [1, 7, 4, 2, 3]
plt.plot(x, y)
```

plot should automatically open

`plt.show()`

`arange`

is the `numpy`

array equivalent of Python's built-in `range`

function.

```
x = np.arange(20)
print('x is', x)
```

plot f(x) = x**2

```
print('x squared is', x**2)
plt.plot(x, x**2)
plt.show()
```

plot f(x) = sin(2πx/20) using `numpy`

's `sin`

function and `pi`

constant

```
y = np.sin(x * 2 * np.pi / len(x))
plt.plot(x, y)
plt.show()
```