%matplotlib inline

import matplotlib.pyplot as plt

"""
Explanation: <span style="color: #B40486">BASIC PYTHON FOR RESEARCHERS</span>
by Megat Harun Al Rashid bin Megat Ahmad
last updated: April 14, 2016

<span style="color: #29088A">7. Data Visualization and Plotting</span>
The <span style="color: #0000FF">$Matplotlib$</span> library can be considered as the default data visualization and plotting tools for Python, even though there are others libraries that can be used e.g. <span style="color: #0000FF">$Chaco$</span>, <span style="color: #0000FF">$PyX$</span>, <span style="color: #0000FF">$Bokeh$</span> and <span style="color: #0000FF">$Lightning$</span>. In this tutorial, we will focus exclusively on <span style="color: #0000FF">$Matplotlib$</span> and explore the basics and few of its large number of advanced features. 

7.1 Basic Plotting
Users can start plotting with the minimum lines of codes to create a simple line plot. In a 2-dimensional plot, data for x and y coordinates can be represented by lists or <span style="color: #0000FF">$NumPy$</span> arrays. Users can import the plotting function from the <span style="color: #0000FF">$Matplotlib$</span> library as well as specify on how to display it.
End of explanation
"""


# Data in lists
x = [1,2,3,4,5]
y = [21,34,78,12,9]

# Plot x against y
plt.plot(x, y)      

"""
Explanation: Here the line (<span style="color: #B404AE">%</span>matplotlib inline) means that the plot when created will be displayed on the working document. The second line import the plotting function of <span style="color: #0000FF">$Matplotlib$</span> library.
End of explanation
"""


%matplotlib qt

plt.plot(x, y)

"""
Explanation: Replacing the first line with <span style="color: #B404AE">%</span>matplotlib qt, an interactive plotting graphical user interface (GUI) will be displayed instead in a separate window (similar to MATLAB).
End of explanation
"""


%matplotlib inline

plt.plot(x, y)
plt.title('Plot Title')
plt.xlabel("label x")                           # naming the x-axis label
plt.ylabel("label y")                           # naming the y-axis label
plt.legend(['data'], loc='upper right')         # displaying legend and its position

# saving the image plot with specific resolution
plt.savefig("Tutorial7/First_Image.png", dpi = 300)   

"""
Explanation: <img src="Tutorial7/MatplotlibQt.png" width="500" >
This GUI allows users to interactively inspect the plot .e.g. enlarging specific plot region for details, moving the plot on the canvas, changing the axis range and colors etc.
However, we will only use (<span style="color: #B404AE">%</span>matplotlib inline) for the remainder of this tutorial. Let us see some other basic codes that are needed to prepare more than a simple plot.
End of explanation
"""


import numpy as np

x = [1.0,2.0,3.0,4.0,5.0]
y1 = [21,34,78,12,9]
y2 = [10,25,63,26,15]

plt.figure(figsize=(12, 6))                     # set the figure canvas size before plotting

# Two plots here in the same graph, each on top the other going down the list
plt.plot(x,y2,'b--s', ms = 8, mfc = 'r', label='data 1')
plt.plot(x,y1,'g-o', linewidth = 4, ms = 12, mfc = 'magenta', alpha = 0.5, label='data 2')

plt.xlim(0.5,5.5)                               # setting x-axis range
plt.ylim(0,100)                                 # setting y-axis range

plt.xticks(np.linspace(0.5,5.5,11))             # creating x ticks using numpy array
plt.yticks(np.linspace(0,100,11))               # creating y ticks using numpy array

plt.grid()                                      # showing grid (according to ticks)

plt.xlabel("label x")                           # naming the x-axis label
plt.ylabel("label y")                           # naming the y-axis label
plt.legend(loc='upper right')                   # displaying legend and its position

# saving the image plot with specific resolution
plt.savefig("Tutorial7/Second_Image.eps", dpi = 100)   

"""
Explanation: In the above example, the same x and y data are used (both of which have been declared beforehand), instead of just plotting, users can add title of the graph, names for x and y axes, insert legend and save the file with specific resolution (in this case as .png file).  It is not necessary to declare <span style="color: #B404AE">%</span>matplotlib inline in the cell when it is already declared in previous cell (but if <span style="color: #B404AE">%</span>matplotlib qt was declared at some cells previously, then <span style="color: #B404AE">%</span>matplotlib inline needs to be re-declared again). Much more features can be added (like below) and we will see these one by one.
End of explanation
"""


x_data = np.linspace(0.5,2.5,20)      # Creating data
x_data

# y data are calculated inside plot() function

fig = plt.figure(figsize=(8, 6))                # set the figure canvas size before plotting

axes1 = fig.add_axes([0.1, 0.1, 0.9, 0.9])      # creating first plot and its positions on canvas
axes2 = fig.add_axes([0.2, 0.55, 0.35, 0.35])   # creating second plot and its position on canvas

# main figure
axes1.plot(x_data,np.exp(x_data),'go-')         # green with square object and line
axes1.set_xlabel('x main')
axes1.set_ylabel('y main')
axes1.set_title('main title')

# embedded figure
axes2.plot(x_data,x_data**(-1),'r--')           # just a red dashed line
axes2.set_xlabel('x embedded')
axes2.set_ylabel('y embedded')
axes2.set_title('embedded title')


"""
Explanation: 7.2 Multiple Plots
Multiple plots can be created in many ways. It can be done by specifying the position of these plots on the whole canvas.
End of explanation
"""


# y data are calculated inside plot() function

plt.subplot(1,2,1)                        # graph with one row, two columns at position 1
plt.plot(x_data,np.exp(x_data),'go-')     # green with square object and line
plt.subplot(1,2,2)                        # graph with one row, two columns at position 2
plt.plot(x_data,x_data**(-1),'r--')       # just a red dashed line

plt.subplot(2,2,1)
plt.plot(x_data,np.exp(x_data),'go-')
plt.subplot(2,2,2)
plt.plot(x_data,x_data**(-1),'r--')
plt.subplot(2,2,4)
plt.plot(x_data,x_data,'bs-')

"""
Explanation: The input cell above shows the user how to embed a plot within a plot by specifying the initial coordinates and sizes of the plots. A slightly different syntax is used here with the sub plot properties assigned to variables axes1 and axes2. From here on it is easy to add features to each plot by operating on the each plot variable.
It is possibly much better to use sub plotting functions (depends on users taste) like <span style="color: #0000FF">$subplot(i,j,k)$</span> function where <span style="color: #0000FF">$i$</span> represents number of rows, <span style="color: #0000FF">$j$</span> represents number of columns and <span style="color: #0000FF">$k$</span> is the position of the plot (moving horizontally to the left from above to below) as shown for <span style="color: #0000FF">$i$</span> = 2 and <span style="color: #0000FF">$j$</span> = 2 below. 
<img src="Tutorial7/Grid1.png" width="200" >
End of explanation
"""


# A canvas of 2 x 3 graph

plot1 = plt.subplot2grid((2,3), (0,0), rowspan=2)   # a(i,j) = starting at (0,0) and extend to (1,0)
plot2 = plt.subplot2grid((2,3), (0,1), colspan=2)   # a(i,j) = starting at (0,1) and extend to (0,2)
plot3 = plt.subplot2grid((2,3), (1,1))              # a(i,j) = starting at (1,1)
plot4 = plt.subplot2grid((2,3), (1,2))              # a(i,j) = starting at (1,2)

"""
Explanation: Other subplot functions like <span style="color: #0000FF">$subplot2grid()$</span> and <span style="color: #0000FF">$gridspec()$</span> allow more control on the produced multi-plots. In the case of <span style="color: #0000FF">$subplot2grid()$</span>, the location of a plot in a 2-dimensional graphical grid can be specified using coordinate (i,j) with both i and j starting at $0$.
End of explanation
"""


# A canvas of 2 x 3 graph

p1 = plt.subplot2grid((2,3), (0,0), rowspan=2)   # a(i,j) = starting at (0,0) and extend to (1,0)
p2 = plt.subplot2grid((2,3), (0,1), colspan=2)   # a(i,j) = starting at (0,1) and extend to (0,2)
p3 = plt.subplot2grid((2,3), (1,1))              # a# it return best fit values for parameters
# pass the function name, x array, y array, initial value of parameters (in list)(i,j) = starting at (1,1)
p4 = plt.subplot2grid((2,3), (1,2))              # a(i,j) = starting at (1,2)
plt.tight_layout()

"""
Explanation: The axes numerics are quite messy becuase of overlapping. User can use the <span style="color: #0000FF">$tight{_}layout()$</span> function to automatically tidy up the whole graph.
End of explanation
"""


# A canvas of 2 x 3 graph

plt.figure(figsize=(8,4))

p1 = plt.subplot2grid((2,3), (0,0), rowspan=2)   # a(i,j) = starting at (0,0) and extend to (1,0)
p2 = plt.subplot2grid((2,3), (0,1), colspan=2)   # a(i,j) = starting at (0,1) and extend to (0,2)
p3 = plt.subplot2grid((2,3), (1,1))              # a(i,j) = starting at (1,1)
p4 = plt.subplot2grid((2,3), (1,2))              # a(i,j) = starting at (1,2)
plt.tight_layout()

p1.plot(x_data,np.exp(x_data),'go-')
p2.plot(x_data,2.0*np.exp(-((x_data-1.5)**2/(2*0.05))),'ms-')   # Gaussian function for y value
p3.plot(x_data,x_data,'bs-')
p4.plot(x_data,x_data**(-1),'r--')

"""
Explanation: We can now add some data inside these plots using data in x_data (and also increase the canvas size).
End of explanation
"""


# a 2 x 2 grid plot with specified relative width and height

plt.figure(figsize=(8,4))

gs = plt.GridSpec(2, 2, width_ratios=[1,2],height_ratios=[2.5,1.5])   # a 2 x 2 grid plot

gp1 = plt.subplot(gs[0])
gp2 = plt.subplot(gs[1])
gp3 = plt.subplot(gs[2])
gp4 = plt.subplot(gs[3])
plt.tight_layout()

gp1.plot(x_data,np.exp(x_data),'go-')
gp2.plot(x_data,2.0*np.exp(-((x_data-1.5)**2/(2*0.05))),'ms-')
gp3.plot(x_data,x_data,'bs-')
gp4.plot(x_data,x_data**(-1),'r--')
gp4.set_yticks(np.linspace(0.4,2.0,5))          # setting the y ticks for plot 4

"""
Explanation: Relative size of row and column can be specified using <span style="color: #0000FF">$GridSpec()$</span>:
End of explanation
"""


plt.figure(figsize=(12,4))

gs1 = plt.GridSpec(3, 3, width_ratios=[1.5,1,1.5],height_ratios=[1.5,1,1.5])
gs1.update(left=0.05, right=0.48, wspace=0.3, hspace=0.4)        # size on canvas
fp1 = plt.subplot(gs1[:2, :2])
fp2 = plt.subplot(gs1[0, 2])
fp3 = plt.subplot(gs1[2, :2])
fp4 = plt.subplot(gs1[1:, 2])

gs2 = plt.GridSpec(3, 3, width_ratios=[1.6,1,1.4],height_ratios=[1.3,1,1.7])
gs2.update(left=0.55, right=0.98, wspace=0.3, hspace=0.4)       # size on canvas
afp1 = plt.subplot(gs2[:2,0])
afp2 = plt.subplot(gs2[:2, 1:])
afp3 = plt.subplot(gs2[2, :-1])
afp4 = plt.subplot(gs2[2, -1])


"""
Explanation: <span style="color: #0000FF">$GridSpec()$</span> also allows the users to mix relative lengths of rows and columns with plots that extend these rows and columns (much like <span style="color: #0000FF">$subplot2grid()$</span>).
End of explanation
"""


plt.figure(figsize=(12,4))

gs1 = plt.GridSpec(3, 3, width_ratios=[1.5,1,1.5],height_ratios=[1.5,1,1.5])
gs1.update(left=0.05, right=0.48, wspace=0.3, hspace=0.4)        # size on canvas
fp1 = plt.subplot(gs1[:2, :2])
fp2 = plt.subplot(gs1[0, 2])
fp3 = plt.subplot(gs1[2, :2])
fp4 = plt.subplot(gs1[1:, 2])

gs2 = plt.GridSpec(3, 3, width_ratios=[1.6,1,1.4],height_ratios=[1.3,1,1.7])
gs2.update(left=0.55, right=0.98, wspace=0.3, hspace=0.4)       # size on canvas
afp1 = plt.subplot(gs2[:2,0])
afp2 = plt.subplot(gs2[:2, 1:])
afp3 = plt.subplot(gs2[2, :-1])
afp4 = plt.subplot(gs2[2, -1])

fp1.plot(x_data,2.0*np.exp(-((x_data-1.5)**2/(2*0.05))),'ms-')
fp2.plot(x_data,np.exp(x_data),'go-')
fp2.set_yticks(np.linspace(0,14,5))
fp3.plot(x_data,x_data,'bs-')
fp4.plot(x_data,x_data**(-1),'r--')

afp1.plot(x_data,x_data**(-1),'r--')
afp2.plot(x_data,2.0*np.exp(-((x_data-1.5)**2/(2*0.05))),'ms-')
afp3.plot(x_data,np.exp(x_data),'go-')
afp4.plot(x_data,x_data,'bs-')
afp4.set_yticks(np.linspace(0,3,6))

"""
Explanation: Similarly, let add some data:
End of explanation
"""


xl = np.linspace(4,6,31)
Lf = 5*(0.02/((xl-5)**2 + 0.02))                  # Cauchy or Lorentz distribution

# Setting the canvas size and also resolution
plt.figure(figsize=(14,5), dpi=100)

# Assigning plotting function to variable, here subplot() is used
# even though there is only one plot
# and no ticks created on the frame (ticks are specified later)
Lp = plt.subplot(xticks=[], yticks=[])

# Plot certain borders with width specified
Lp.spines['bottom'].set_linewidth(2)
Lp.spines['left'].set_linewidth(2)

plt.subplots_adjust(left=0.1, right=0.9, top=0.75, bottom=0.25)        # size on canvas

# Plotting
Lp.plot(xl, Lf, color="r", linewidth=2.0, linestyle="-")

# Title and Axes and Legend
Lp.set_title('Cauchy \nDistribution', fontsize=18, color='blue',\
             horizontalalignment='left', fontweight='bold', x=0.05, y=1.05)
Lp.set_xlabel(r'$x$', fontsize=20, fontweight='bold', color='g')
Lp.set_ylabel(r'$L(x) = A\left[\frac{\gamma}{(x - x_{o})^{2} + \gamma}\right]$', \
              fontsize=20, fontweight='bold', color='#DF0101')

# Legend
## Anchoring legend on the canvas and made it translucent
Lp.legend([r'$Lorentz$'], fontsize=18, bbox_to_anchor=[0.2, 0.98]).get_frame().set_alpha(0.5)  

# Axes ticks and ranges
ytick_list = np.linspace(0,6,7)
Lp.set_xticks(np.linspace(0,10,11))
Lp.set_yticks(ytick_list)
Lp.set_xticklabels(["$%.1f$" % xt for xt in (np.linspace(0,10,11))], fontsize = 14)
Lp.set_yticklabels(["$%d$" % yt for yt in ytick_list], fontsize = 14)

## Major ticks
Lp.tick_params(axis='x', which = 'major', direction='out', top = 'off', width=2, length=10, pad=15)
Lp.tick_params(axis='y', which = 'major', direction='in', right = 'off', width=2, length=10, pad=5)

## Minor ticks
Lp.set_xticks(np.linspace(-0.2,10.2,53), minor=True)
Lp.tick_params(axis='x', which = 'minor', direction='out', top = 'off', width=1, length=5)

# Grid
Lp.grid(which='major', color='#0B3B0B', alpha=0.75, linestyle='dashed', linewidth=1.2)
Lp.grid(which='minor', color='#0B3B0B', linewidth=1.2)

# Save the plot in many formats (compare the differences)
plt.savefig("Tutorial7/Third_Image.eps", dpi = 500)
plt.savefig("Tutorial7/Third_Image.jpeg", dpi = 75)

"""
Explanation: 7.3 Setting the features of the plot
Features of a plot like label font size, legend position, ticks number etc. can be specified. There are many ways to do all of these and one of the way (possibly with the easiest syntax to understand) is shown in the codes below. It is good practice to assigned the plotting function to a variable before setting these features. This is very useful when doing multiple plotting.
End of explanation
"""


xv = np.linspace(0,10,11)
yv = 5*xv

# Setting the canvas size and also resolution
plt.figure(figsize=(14,4), dpi=100)

plt.xlim(0,50)
plt.ylim(0,50)

Lp = plt.subplot()

# Plot without top and right borders
Lp.spines['top'].set_visible(False)
Lp.spines['right'].set_visible(False)

# Show ticks only on left and bottom spines
Lp.yaxis.set_ticks_position('left')
Lp.xaxis.set_ticks_position('bottom')

# Title and axes labels
Lp.set_title('Variety of Plot')
Lp.set_xlabel(r'$x$')
Lp.set_ylabel(r'$y$')

# Plotting
## Line widths and colors
Lp.plot(xv+2, yv, color="blue", linewidth=0.25)
Lp.plot(xv+4, yv, color="red", linewidth=0.50)
Lp.plot(xv+6, yv, color="m", linewidth=1.00)
Lp.plot(xv+8, yv, color="blue", linewidth=2.00)

## Linestype options: ‘-‘, ‘–’, ‘-.’, ‘:’, ‘steps’
Lp.plot(xv+12, yv, color="red", lw=2, linestyle='-')
Lp.plot(xv+14, yv, color="#08088A", lw=2, ls='-.')
Lp.plot(xv+16, yv, color="red", lw=2, ls=':')

## Dash line can be cusotomized
line, = Lp.plot(xv+20, yv, color="blue", lw=2)
line.set_dashes([5, 10, 15, 10]) # format: line length, space length, ...

## Possible marker symbols: marker = '+', 'o', '*', 's', ',', '.', '1', '2', '3', '4', ...
Lp.plot(xv+24, yv, color="#0B3B0B", lw=2, ls='', marker='+', markersize = 12)
Lp.errorbar(xv+26, yv, color="green", lw=2, ls='', marker='o', yerr=5)
Lp.plot(xv+28, yv, color="green", lw=2, ls='', marker='s')
Lp.plot(xv+30, yv, color="#0B3B0B", lw=2, ls='', marker='1', ms = 12)

# Marker sizes and colorsplt.errorbar(x, y, xerr=0.2, yerr=0.4)

Lp.plot(xv+34, yv, color="r", lw=1, ls='-', marker='o', markersize=3)
Lp.plot(xv+36, yv, color="g", lw=1, ls='-', marker='o', markersize=5)
Lp.plot(xv+38, yv, color="purple", lw=1, ls='-', marker='o', markersize=8, markerfacecolor="red")
Lp.plot(xv+40, yv, color="purple", lw=1, ls='-', marker='s', markersize=8, 
        markerfacecolor="yellow", markeredgewidth=2, markeredgecolor="blue");

"""
Explanation: The <span style="color: #0000FF">$r\${text}\$$</span> notation allows the writing of mathematical equations using <span style="color: #0000FF">$LaTeX$</span> syntax. 
Let us now see some variety of plot lines that can be created.
End of explanation
"""


people = ['Rechtschaffen', 'Tadashi', 'Vertueux', 'Justo', 'Salleh']
num_of_publ = [20,34,51,18,46]

y_pos = np.arange(len(people))

plt.title('Academic Output')
plt.barh(y_pos, num_of_publ, align='center', color = '#DF0101', alpha=0.5)
plt.yticks(y_pos, people)
plt.xlabel('Number of Publications')
plt.ylabel('Academicians')


"""
Explanation: I suppose most aspects of the line plot have been covered but please remember that there are many ways in which a line plot can be created.
Histograms and bar charts can be plotted with similar syntax but will be explored further when we learn <span style="color: #0000FF">$Pandas$</span> in the next tutorial. <span style="color: #0000FF">$Pandas$</span> has a rich approach to produce histogram/bar charts with <span style="color: #0000FF">$Matplotlib$</span>. Some examples of histograms/bars charts:
Some examples of histograms/bars charts from <span style="color: #0000FF">$Matplotlib$</span>:
End of explanation
"""


n = np.random.randn(100000)              # a 1D normalized random array with 100,000 elements

fig, Hp = plt.subplots(1,2,figsize=(12,4))

# Each bin represents number of element (y-axis values) with 
# certain values in the bin range (x-axis)
Hp[0].hist(n, bins = 50, color = 'red', alpha = 0.25)
Hp[0].set_title("Normal Distribution with bins = 50")
Hp[0].set_xlim((min(n), max(n)))

Hp[1].hist(n, bins = 25, color = 'g')
ni = plt.hist(n, cumulative=True, bins=25, visible=False)     # Extract the data
Hp[1].set_title("Normal Distribution with bins = 25")
Hp[1].set_xlim((min(n), max(n)))
Hp[1].set_ylim(0, 15000)


ni

"""
Explanation: It is possible to extract the data from histogram/bar chart.
End of explanation
"""


'''Plot histogram with multiple sample sets and demonstrate:

    * Use of legend with multiple sample sets
    * Stacked bars
    * Step curve with a color fill
    * Data sets of different sample sizes
'''
n_bins = 10                       # Number of bins to be displayed
x = np.random.randn(1000, 3)      # A 2D normalized random array with 3 x 1,000 elements

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10,8))
ax0, ax1, ax2, ax3 = axes.flat    # Assigning the axes list to different variables

colors = ['red', 'tan', 'lime']
# {normed = 1} means that y-axis values are normalized
ax0.hist(x, n_bins, normed=1, histtype='bar', color=colors, label=colors)
ax0.legend(prop={'size': 10})
ax0.set_title('bars with legend')

ax1.hist(x, n_bins, normed=1, histtype='bar', stacked=True)
ax1.set_title('stacked bar')

ax2.hist(x, n_bins, histtype='step', stacked=True, fill=True)
ax2.set_title('stepfilled')

# Make a multiple-histogram of data-sets with different length
# or inhomogeneous 2D normalized random array

x_multi = [np.random.randn(n) for n in [10000, 5000, 2000]]  

ax3.hist(x_multi, n_bins, histtype='bar')
ax3.set_title('different sample sizes')

plt.tight_layout()

"""
Explanation: The histogram plots below is an example from one of the <span style="color: #0000FF">$Matplotlib$</span> gallery example with some slight modifications and added comments.
End of explanation
"""


from mpl_toolkits.mplot3d.axes3d import Axes3D

# 2D Gaussian Plot (3D image)

import matplotlib.cm as cm
import matplotlib.ticker as ticker

a = 12.0
b = 5.0
c = 0.3

fig = plt.figure(figsize=(6,4))
ax = fig.gca(projection='3d')                  # Passing a projection='3d' argument
X = np.linspace(4, 6, 100)
Y = np.linspace(4, 6, 100)
X, Y = np.meshgrid(X, Y)
R = (X-b)**2/(2*c**2) + (Y-b)**2/(2*c**2)      # Use the declared a,b,c values in 1D-Gaussian
Z = a*np.exp(-R)

# Applying the plot features to variable surf
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.hsv,
                       linewidth=0, antialiased=True, alpha=0.3)

ax.set_zlim(-1.01, 14)
ax.zaxis.set_major_locator(ticker.LinearLocator(8))
ax.zaxis.set_major_formatter(ticker.FormatStrFormatter('%.1f'))

fig.colorbar(surf, shrink=0.4, aspect=10)
ax.view_init(30, 40)                          # Angles of viewing

plt.tight_layout()

"""
Explanation: 7.4 3D Plotting
A 3D plot can be created by importing the Axes3D class and passing a projection='3d' argument.
End of explanation
"""


fig_wire = plt.figure(figsize=(12,6))

# Wireframe plot
ax1 = fig_wire.add_subplot(1,2,1, projection='3d')
ax1.plot_wireframe(X, Y, Z, rstride=4, cstride=4, alpha=0.75)
ax1.view_init(55, 30)
ax1.set_zlim(-2, 14)
ax1.set_title('Wireframe')

# Surface plot
ax2 = fig_wire.add_subplot(1,2,2, projection='3d')
ax2.plot_surface(X, Y, Z, rstride=6, cstride=6, alpha=0.45)
ax2.view_init(30, 30)
ax2.set_title('Surface and Contour')

# Different color maps used for each contours
# the offset argument refers to the position of contour
ax2.contour(X, Y, Z, zdir='x', offset=3, cmap=cm.hsv)
ax2.contour(X, Y, Z, zdir='y', offset=3, cmap=cm.prism)
ax2.contour(X, Y, Z, zdir='z', offset=-8, cmap=cm.coolwarm)

# Axes range for contours
ax2.set_xlim3d(3, 7)
ax2.set_ylim3d(3, 7)
ax2.set_zlim3d(-8, 20)

fig_wire.tight_layout()

"""
Explanation: Using the data X, Y and Z in the computer memory from the above cell, we create a wireframe plot and a surface plot with contour projection.
End of explanation
"""


# Brownian motion of particle suspended in liquid

nu = 0.7978E-3            # Pa s
kB = 1.3806488E-23        # m^2 kg s^-2 K^-1
d = 0.001                 # 1 micron
T = 30+273.15             # Kelvin

D = kB*T/(3*np.pi*nu*d)

dt = 0.00001

dl = np.sqrt(2*D*dt)

xp = np.random.uniform(0,0.0001,20)
yp = np.random.uniform(-0.00000005,0.000000005,20)

for value in range(0,xp.size,1):

    angle1 = np.random.normal(0,np.pi,500)
    xb = xp[value]+np.cumsum(dl*np.cos(angle1))
    yb = yp[value]+np.cumsum(dl*np.sin(angle1))

plt.figure(figsize=(6,4))    
plt.plot(xb,yb)

from matplotlib import animation       # Importing the animation module

fig, ax = plt.subplots(figsize=(6,4))

xr = np.sqrt((xb.max()-xb.min())**2)/20.0
yr = np.sqrt((yb.max()-yb.min())**2)/20.0

ax.set_xlim([(xb.min()-xr), (xb.max()+xr)])
ax.set_ylim([(yb.min()-yr), (yb.max()+yr)])

line1, = ax.plot([], [], 'ro-')
line2, = ax.plot([], [], color="blue", lw=1)

x2 = np.array([])
y2 = np.array([])

def init():
    line1.set_data([], [])
    line2.set_data([], [])

def update(n): 
    # n = frame counter

    global x2, y2
    x2 = np.hstack((x2,xb[n]))
    y2 = np.hstack((y2,yb[n]))
    line1.set_data([xb[n],xb[n+1]],[yb[n],yb[n+1]])
    line2.set_data(x2, y2)
    
# Creating the animation
# anim = animation.FuncAnimation(fig, update, init_func=init, frames=len(xb)-1, blit=True)
anim = animation.FuncAnimation(fig, update, init_func=init, frames=len(xb)-1)

# Saving the animation film in .mp4 format
anim.save('Tutorial7/Brownian.mp4', fps=10, writer="avconv", codec="libx264")

plt.close(fig)

"""
Explanation: 7.5 Animated Plotting
<span style="color: #0000FF">$Matplotlib$</span> has the ability to generate a movie file from sequences of figures. Let see an example of the syntax needed to capture a Brownian motion in a video (it is necessary to explicitly import the animation module from <span style="color: #0000FF">$Matplotlib$</span>).
End of explanation
"""


from IPython.display import HTML
video = open("Tutorial7/Brownian.mp4", "rb").read()
video_encoded = video.encode("base64")
video_tag = '<video controls alt="test" src="data:video/x-m4v;base64,{0}">'.format(video_encoded)
HTML(video_tag)

"""
Explanation: Creating the video in a correct video format that can be run by your browser may require the installation of these tools (in my case with Ubuntu 14.04LTS):
sudo apt-get install ffmpeg libav-tools
sudo apt-get install libavcodec-extra-*
Different linux variants and other operating systems may require further tuning.
The video can then be displayed:
End of explanation
"""


