import numpy as np

a = np.array([1, 2, 3, 4])
a

type(a)

2*a  # multiple ndarray by number

b = np.array([2, 3, 4, 5])
print(a)
print(b)

a+b  # two array summation

a*b

np.log(a)  # apply functions to array

"""
Explanation: Numpy
Numpy stands for Numerical Python, is the foundational package for scientific computing in Python. It provides
- A fast and efficient multidimensional arrary object ndarray
- Functions for performing element-wise computation with arrays and mathematical operations between arrays
- Linear algebra operations, Fourier transform, and random number generation
End of explanation
"""


a

a[1]

a[1:3]

# omitted boundaries are assumed to be the beginning (or end) of the array

a[:3]  # grap first three elements

a[::2] # element with step size 2

"""
Explanation: index and slicing
var[lower:upper:step]
End of explanation
"""


c = np.array([[0, 1, 2, 3],
          [10, 11, 12, 13]])
c

c[0, 3]  # get the first row and fourth number

c[1]  # get the second row

c[0, 2:4]  # get the first rown and slicing the first row

"""
Explanation: Multi-Dimensional Arrays
End of explanation
"""


print(a)
a.shape

b = a.reshape((2, 2))
b

b.T

c[:, 2:4] # slice the row

print(c)
c.shape

a.size

c.size

"""
Explanation: Basic info of array
End of explanation
"""


a = np.array([1, 2, 3])
b = np.array([2, 3, 4])

# Stack arrays in sequence vertically (row wise).
np.vstack([a, b])

# Stack arrays in sequence horizontally (column wise).
np.hstack([a, b])

"""
Explanation: Joining arrays
End of explanation
"""


a = np.array([[1, 2, 3],
            [4, 5, 6]])
a

np.sum(a)

np.sum(a, axis=0)

np.sum(a, axis=1)

np.max(a)

np.min(a, axis=0)

np.prod(a)

"""
Explanation: Array Calculation Methods
End of explanation
"""


np.arange(4)  # arange(start, stop=None, step=1)

np.arange(1, 5, 2)

np.ones(4)  # ones(shape)

np.ones((2, 3))

np.zeros((2, 3)) # zeros(shape)

np.linspace(0, 1, 5)  # Generate N evenly spaced elements between start and stop values

"""
Explanation: Array creation Functions
End of explanation
"""



from IPython.core.display import HTML
HTML("<iframe src=http://www.numpy.org/  width=800 height=350></iframe>")

"""
Explanation: For more detail of numpy please refer to Numpy.org
End of explanation
"""


%matplotlib inline
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 20)
y = np.sin(x)
plt.xlabel('x label')  # set label for x coordinate
plt.ylabel('y label')  # set label for y coordinates
plt.title('Sin Function')
plt.plot(x, y)

"""
Explanation: matplotlib

matplotlib for producing plots and other 2D data visualizations. It is well-suited for creating plots suitable for publication.
End of explanation
"""


x = np.linspace(0, 2*np.pi, 20)
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x, y1)
plt.plot(x, y2)

"""
Explanation: Draw two plots on one coordinate
End of explanation
"""


x = np.linspace(0, 2*np.pi, 20)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure()
ax1 = plt.subplot(211)
ax1.plot(x, y1)

ax2 = plt.subplot(212)
ax2.plot(x, y2)

"""
Explanation: Working with multiple figures and axes

figure represents the whole picture
axes represents each plot with independ coordinate
The subplot() command specifies (numrows, numcols, fignum) where fignum ranges from 1 to numrows * numcols.
End of explanation
"""


x = np.linspace(0, 2*np.pi, 20)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure()
ax1 = plt.subplot(211)
ax1.plot(x, y1, label='Sin', color='b')
ax1.legend()  # show the label of plots on ax1

ax2 = plt.subplot(212)
ax2.plot(x, y2, label='Cos', color='r')
ax2.legend()  # show the label of plotson ax2

"""
Explanation: Show the labels of each plot
Specify color of each plot
End of explanation
"""


x = np.linspace(0, 2*np.pi, 20)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure()
ax1 = plt.subplot(211)
ax1.plot(x, y1, label='Sin', color='b')
ax1.legend()  # show the label on ax1
ax1.set_xlim(-10, 10)  # set the boundary of x coordinate

ax2 = plt.subplot(212)
ax2.plot(x, y2, label='Cos', color='r')
ax2.legend()  # show the label on ax2
ax2.set_ylim(-2, 2)  # set the boundary of y coordinate

"""
Explanation: Set boundary of each coordinate
End of explanation
"""


r1 = np.random.normal(0, 10, 1000)
_ = plt.hist(r1, bins=50, normed=True)

"""
Explanation: Histogram
End of explanation
"""


x = np.random.normal(0, 10, 100)
y = np.random.normal(5, 3, 100)
plt.scatter(x, y)

"""
Explanation: Scatterplot
End of explanation
"""


r1 = np.random.normal(0, 10, 100)
r2 = np.random.gamma(1, 2, 100)
r3 = r1 + r2
_ = plt.boxplot(r3)

"""
Explanation: Boxplots
End of explanation
"""


HTML("<iframe src=https://matplotlib.org/index.html width=800 height=350></iframe>")

"""
Explanation: For more detail of matplotlib please refer to matplotlib.org
End of explanation
"""


from scipy import linalg  # import linear algebra operations

arr = np.array([[1, 2],
               [3, 4]])
linalg.det(arr)  # compute the determinant of a square matrix

linalg.inv(arr)  # compute the inverse of a squar matrix

"""
Explanation: SciPy
SciPy is a collection of packages addressing a number of different standard problem domain in scientific computing. Here is some packages you may use:
- scipy.integrate: numerical integration routines and differential equation solvers
- scipy.linalg: linear algebra routines and matrix decompositions
- scipy.optimize: function optimizers and root finding algorithms
- scipy.stats: standard probability distributions (cdf, pdf, sampler and etc)

Example of linear algebra operations
End of explanation
"""


from scipy import optimize
def f(x):
    return x**2 + 10*np.sin(x)

x = np.arange(-10, 10, 0.1)
plt.plot(x, f(x))

result = optimize.minimize(f, x0=0)
result.x

plt.plot(x, f(x))
plt.axvline(result.x)  # plot a vertical lines at result x

"""
Explanation: Example of optimization algorithm
End of explanation
"""


from scipy import stats

samples = np.random.normal(size=100)
plt.hist(samples, bins = 20, normed=True, label='Histogram of samples')
x_space = np.linspace(*plt.xlim())

pdf = stats.norm.pdf(x_space)
plt.plot(x_space, pdf, label='PDF')
plt.legend()

"""
Explanation: Example of probability distributions method
End of explanation
"""


HTML("<iframe src=https://www.scipy.org/scipylib/index.html width=800 height=350></iframe>")

"""
Explanation: For more detail of matplotlib please refer to scipy.org
End of explanation
"""


a = np.array([1, 3, 5, 7, 8, 9])

"""
Explanation: Exercises 1
Write a Python program to reverse an array (first element becomes last)
End of explanation
"""


