import matplotlib.pyplot as plt

"""
Explanation: An introduction to matplotlib
Matplotlib is a Python package used widely throughout the scientific Python community to produce high quality 2D publication graphics. It transparently supports a wide range of output formats including PNG (and other raster formats), PostScript/EPS, PDF and SVG and has interfaces for all of the major desktop GUI (Graphical User Interface) toolkits.
Matplotlib comes with a convenience sub-package called pyplot. For consistency with the wider maptlotlib community, this should always be imported as plt:
End of explanation
"""


fig = plt.figure()
plt.show()

"""
Explanation: The matplotlib Figure
At the heart of every matplotlib plot is the "Figure". The Figure is the top level concept that can be drawn to one of the many output formats, or simply just to screen.
Let's create our first Figure using pyplot, and then show it:
End of explanation
"""


ax = plt.axes()
plt.show()

"""
Explanation: On its own, drawing the Figure is uninteresting and will result in an empty piece of paper (that's why we didn't see anything above).
Other visible elements are added to a Figure to make a plot.  All visible items in Matplotlib are instances of the Artist class :  The Figure and Axes are both types of Artist.
To start with we can draw an Axes artist in the Figure, to represent our data space. The most basic Axes is rectangular and has tick labels and tick marks.  Multiple Axes artists can be placed on a Figure.
Let's go ahead and create a Figure with a single Axes, and show it using pyplot:
End of explanation
"""


ax = plt.axes()
line1, = ax.plot([0, 1, 2, 1.5], [3, 1, 2, 4])
plt.show()

"""
Explanation: Matplotlib's pyplot module makes the process of creating graphics easier by allowing us to skip some of the tedious object construction. For example, we did not need to manually create the Figure with plt.figure because it was implicit that we needed a Figure when we created the Axes.
Under the hood matplotlib still had to create a Figure; we just didn't need to capture it into a variable. We can access the created object with the "state" functions found in pyplot called gcf and gca.
Exercise 1
Go to matplotlib.org and search for what these strangely named functions do.
Hint: you will find multiple results so remember we are looking for the pyplot versions of these functions.
Working with the Axes
As has already been mentioned, most of your time building a graphic in matplotlib will be spent on the Axes. Whilst the matplotlib documentation for the Axes is very detailed, it is also rather difficult to navigate (though this is an area of ongoing improvement).
As a result, it is often easier to find new plot types by looking at the pyplot module's documentation.
The first and most common Axes method is plot. Go ahead and look at the plot documentation from the following sources:

http://matplotlib.org/api/pyplot_summary.html
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot
http://matplotlib.org/api/axes_api.html?#matplotlib.axes.Axes.plot

Plot can be used to draw one or more lines in axes data space:
End of explanation
"""


plt.plot([0, 1, 2, 1.5], [3, 1, 2, 4])
plt.show()

"""
Explanation: Notice how the Axes view limits (ax.viewLim) have been updated to include the whole of the line.
Should we want to add some spacing around the edges of our Axes we can set a margin using the margins method. Alternatively, we can manually set the limits with the set_xlim and set_ylim methods.
Exercise 2
Modify the previous example to produce three different Figures that control the limits of the Axes.
1. Manually set the x and y limits to $[0.5, 2]$ and $[1, 5]$ respectively.
2. Define a margin such that there is 10% whitespace inside the axes around the drawn line (Hint: numbers to margins are normalised such that 0% is 0.0 and 100% is 1.0).
3. Set a 10% margin on the Axes with the lower y limit set to 0. (Note: order is important here)

If we want to create a plot in its simplest form, without any modifications to the Figure or Axes, we can leave out the creation of artist variables. Our simple line example then becomes:
End of explanation
"""


ax_left = plt.subplot(1, 2, 1)
plt.plot([2,1,3,4])
plt.title('left = #1')

ax_left = plt.subplot(1, 2, 2)
plt.plot([4,1,3,2])
plt.title('right = #2')
plt.show()

"""
Explanation: The simplicity of this example shows how visualisations can be produced quickly and easily with matplotlib, but it is worth remembering that for full control of the Figure and Axes artists we can mix the convenience of pyplot with the power of matplotlib's object oriented design.
Exercise 3
By calling plot multiple times, create a single Axes showing the line plots of $y=sin(x)$ and $y=cos(x)$ in the interval $[0, 2\pi]$ with 200 linearly spaced $x$ samples.

Multiple Axes on the same Figure (aka subplot)
Matplotlib makes it relatively easy to add more than one Axes object to a Figure. The Figure.add_subplot() method, which is wrapped by the pyplot.subplot() function, adds an Axes in the grid position specified. To compute the position, we tell matplotlib the number of rows and columns (respectively) to divide the figure into, followed by the index of the axes to be created (1 based). 
For example, to create an axes grid with two columns, the grid specification would be plt.subplot(1, 2, &lt;plot_number&gt;).
The left-hand Axes is plot number 1, created with subplot(1, 2, 1), and the right-hand one is number 2, subplot(1, 2, 2) :
End of explanation
"""


top_right_ax = plt.subplot(2, 3, 3, title='#3 = top-right')
bottom_left_ax = plt.subplot(2, 3, 4, title='#4 = bottom-left')
plt.show()

"""
Explanation: Likewise, for plots above + below one another we would use two rows and one column, as in subplot(2, 1, &lt;plot_number&gt;).
Now let's expand our grid to two rows and three columns, and place one set of axes on the top right (grid specification (2, 3, 3)) and another on the bottom left (grid specification (2, 3, 4))
End of explanation
"""


import numpy as np

x = np.linspace(-180, 180, 60)
y = np.linspace(-90, 90, 30)
x2d, y2d = np.meshgrid(x, y)
data = np.cos(3 * np.deg2rad(x2d)) + np.sin(2 * np.deg2rad(y2d))

plt.contourf(x, y, data)
plt.show()

plt.imshow(data, extent=[-180, 180, -90, 90],
           interpolation='nearest', origin='lower')
plt.show()

plt.pcolormesh(x, y, data)
plt.show()

plt.scatter(x2d, y2d, c=data, s=15)
plt.show()

plt.bar(x, data.sum(axis=0), width=np.diff(x)[0])
plt.show()

plt.plot(x, data.sum(axis=0), linestyle='--',
         marker='d', markersize=10, color='red')
plt.show()

"""
Explanation: Exercise 3 continued: Copy the answer from the previous task (plotting $y=sin(x)$ and $y=cos(x)$) and add the appropriate plt.subplot calls to create a Figure with two rows of Axes, one showing $y=sin(x)$ and the other showing $y=cos(x)$.

Further plot types
Matplotlib comes with a huge variety of different plot types. Here is a quick demonstration of the more common ones.
End of explanation
"""


fig = plt.figure()
ax = plt.axes()
# Adjust the created axes so its topmost extent is 0.8 of the figure.
fig.subplots_adjust(top=0.8)

fig.suptitle('Figure title', fontsize=18, fontweight='bold')
ax.set_title('Axes title', fontsize=16)

ax.set_xlabel('The X axis')
ax.set_ylabel('The Y axis $y=f(x)$', fontsize=16)

ax.text(0.5, 0.5, 'Text centered at (0.5, 0.5)\nin data coordinates.',
        horizontalalignment='center', fontsize=14)

plt.show()

"""
Explanation: Titles, legends, colorbars and annotations
Matplotlib has convenience functions for the addition of plot elements such as titles, legends, colorbars and text based annotation.
The suptitle pyplot function allows us to set the title of a Figure, and the set_title method on an Axes allows us to set the title of an individual Axes. Additionally, an Axes has methods named set_xlabel and set_ylabel to label the respective x and y axes. Finally, we can add text, located by data coordinates, with the Axes text method:
End of explanation
"""


x = np.linspace(-3, 7, 200)
plt.plot(x, 0.5*x**3 - 3*x**2, linewidth=2,
         label='$f(x)=0.5x^3-3x^2$')
plt.plot(x, 1.5*x**2 - 6*x, linewidth=2, linestyle='--',
         label='Gradient of $f(x)$', )
plt.legend(loc='lower right')
plt.grid()
plt.show()

"""
Explanation: The creation of a legend is as simple as adding a "label" to lines of interest. This can be done in the call to plt.plot and then followed up with a call to plt.legend:
End of explanation
"""


x = np.linspace(-180, 180, 60)
y = np.linspace(-90, 90, 30)
x2d, y2d = np.meshgrid(x, y)
data = np.cos(3 * np.deg2rad(x2d)) + np.sin(2 * np.deg2rad(y2d))

plt.contourf(x, y, data)
plt.colorbar(orientation='horizontal')
plt.show()

"""
Explanation: Colorbars are created with the plt.colorbar function:
End of explanation
"""


x = np.linspace(-3, 7, 200)
plt.plot(x, 0.5*x**3 - 3*x**2, linewidth=2)
plt.annotate('Local minimum',
             xy=(4, -18),
             xytext=(-2, -40), fontsize=15,
             arrowprops={'facecolor': 'black', 'frac': 0.3})
plt.grid()
plt.show()

"""
Explanation: Matplotlib comes with powerful annotation capabilities, which  are described in detail at http://matplotlib.org/users/annotations_intro.html.
The annotation's power can mean that the syntax is a little harder to read, which is demonstrated by one of the simplest examples of using annotate:
End of explanation
"""


plt.plot(range(10))
plt.savefig('simple.svg')

"""
Explanation: Savefig & backends
Matplotlib allows you to specify a "backend" to drive rendering the Figure. The backend includes the graphical user interface (GUI) library to use, and the most used backend (as it is normally the default one) is the "TkAgg" backend. When plt.show() is called, this backend pops up a Figure in a new TkInter window, which is rendered by the anti-grain graphics library (also known as "agg"). Generally, the most common reason to want to change backends is for automated Figure production on a headless server. In this situation, the "agg" backend can be used:
import matplotlib
matplotlib.use('agg')
import matplotlib.pyplot as plt

Note: The backend must be chosen before importing pyplot for the first time, unless the force keyword is added.
Non-interactive backends such as the "agg" backend will do nothing when plt.show() is called - this is because there is nowhere (no graphical display) specified for a Figure to be displayed.
To save a Figure programmatically the savefig function can be used from any backend:
End of explanation
"""


