# In IPython or the IPython notebook, it's easiest to use the pylab magic, which
# imports matplotlib, numpy, and scipy.

# The matplotlib notebook flag means that plots will be shown interactively in the
# notebooks, rather than in pop-up windows.

%matplotlib notebook

import numpy as np
import matplotlib.pyplot as plt

"""
Explanation: Plotting with matplotlib
1. Getting Started
1.1 What is matplotlib?
Matplotlib is the most popular and mature library for plotting data using
Python. It has all of the functionality you would expect, including the ability to control
the formatting of plots and figures at a very fine level.
The official matplotlib documentation is at http://matplotlib.org/
The matplotlib gallery is at http://matplotlib.org/gallery.html
1.2 Importing matplotlib
Matplotlib is often used through 'pyplot', which provides a high-level interface for
plotting.
End of explanation
"""


# First we make some data to plot
x = np.linspace(-2*np.pi, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)

"""
Explanation: 2. Creating Figures
There are two major challenges with creating figures. First is understanding the
syntax to actually make the basic plot appear. Second is formatting the basic plot to look
exactly how you would like it to look. In general, the formatting will probably take you
longer...
Within pyplot (currently imported as 'plt'), there are two basic ways to go about making
plots - using the Matlab-like clone, and using the object-oriented approach. The latter
provides better control over plot features, while only requiring slightly more typing. It's
easy to quickly outgrow the Matlab clone, so we'll go right to the object-oriented syntax.
2.1 A first plot
In simple matplotlib plotting, there are two concepts to distinguish:


Figure - the entire figure, like what you might see in a journal, including all
subplots, axes, lines, labels, etc. The whole enchilada.  


Subplot/Axes - one of the sub-sections of the figure, labeled (a), (b), etc. in
articles. Each subplot will contain one Axes object, which is the container where all of the
useful stuff, such as actual lines, legends, labels, etc., are actually housed.


For example, here's how to make one figure with two subplots, the second of which contains
two lines.
End of explanation
"""


fig, axes = plt.subplots(1,2)

"""
Explanation: First, create an empty figure with 2 subplots
using the subplots method
figure, axes = plt.subplots(rows, columns)


The arguments (1, 2) indicate 1 row and 2 cols
The function plt.subplots returns an object for the figure and for each axes
There are multiple ways to accomplish this same goal, but this is probably the simplest - notice that each subplot is associated with one of the axes objects.
End of explanation
"""



fig, axes = plt.subplots(1,2)

# We plot one line on the first axis
axes[0].plot(x, y1)
# and both lines on the second axis
axes[1].plot(x, y1)
axes[1].plot(x, y2);

"""
Explanation: Now let's actually plot the data using the plot method on an axis
axis.plot(x, y)
You can plot multiple lines on an axis
End of explanation
"""


fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1)
axes[1].plot(x, y1)
axes[1].plot(x, y2)

plt.tight_layout();

"""
Explanation: Many of the basic formatting problems you have will be solved by the magic of tight_layout. Before you start tweaking how you figure looks, try it out.
plt.tight_layout()
End of explanation
"""


fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1)
axes[1].plot(x, y1)
axes[1].plot(x, y2)

fig.savefig('first_plot.png', format='png');

"""
Explanation: To save your figure you can use the savefig command:
fig.savefig('fileanme', format='png')

Format options include png, pdf, ps, eps and svg
End of explanation
"""


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

fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1, color='r', linewidth=5)
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--')
axes[1].plot(x, y2, color='green', linestyle='-.');

"""
Explanation: TRY IT
Create a line graph plotting the function f(x) = x^3 for values of x 0-10.
3. Formatting Figures
The formatting of figures often takes longer than actually setting them up and adding data. There are many different approaches to formatting figures in matplotlib (many goals can be accomplished in different ways, using different commands), and you will come across many of these as you learn more. The tips below give a few simple ways to get started.
3.1 Line formatting
The plot method has several available keyword arguments that you can use to change the line formatting.

color - Chages color of line. examples: 'red', 'blue', 'r', 'k', 0.5, '#ffaa00', (0,0.5,0.75)
linewidth - Weight of line. Takes float value in points (like font)
linestyle - Solid, dashed, or other. examples: -, --, -.
End of explanation
"""


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

fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1, color='r', linewidth=5)
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--')
axes[1].plot(x, y2, color='green', linestyle='-.')
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, 1]);

"""
Explanation: 3.2 Tick marks
You can set the values where the ticks are located using the xticks and yticks methods.
They take a list of values
plt.xticks([val1, val2, val3])
plt.yticks([yval1, yval2, yval3])
End of explanation
"""


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

fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1, color='r', linewidth=5)
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--')
axes[1].plot(x, y2, color='green', linestyle='-.')

# Set the current axis to the first subplot
fig.sca(axes[0])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, 1])

# Set the current axis to the second subplot
fig.sca(axes[1])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, 1]);

"""
Explanation: Oh no! That changed it for the last plot but not for the first plot. 
To set each plot individually, you need to set the current axis to the subplot you are interested in using the method sca. Then you can use xticks and yticks.
plt.sca(axis)
plt.xticks([val1, val2, val3])
plt.yticks([yval1, yval2, yval3])
End of explanation
"""


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

fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1, color='r', linewidth=5)
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--')
axes[1].plot(x, y2, color='green', linestyle='-.')

# Set the current axis to the first subplot
fig.sca(axes[0])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, 1])


# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1)

# Set the current axis to the second subplot
fig.sca(axes[1])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, 1])


# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1);

"""
Explanation: 3.3 Axis limits
Setting the limits of the axes is very similar to setting the ticks. The command to set the limits are xlim and ylim. Remember if you have more than one subplot, you will need to set the current axis before you set that axis' limits.
plt.sca(axis)
plt.xlim(xmin, xmax)
plt.ylim(ymin, ymax)
End of explanation
"""


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

fig, axes = plt.subplots(1,2)
axes[0].plot(x, y1, color='r', linewidth=5)
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--')
axes[1].plot(x, y2, color='green', linestyle='-.')

# Set the current axis to the first subplot
fig.sca(axes[0])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], ['-pi', '-pi/2', '0', 'pi/2', 'pi'])
# You probably don't want to set the labels when you just want the exact numbers.
plt.yticks([-1, 0, 1], ['-1', '0', '1'])


# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1)

# Set the current axis to the second subplot
fig.sca(axes[1])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], ['-pi', '-pi/2', '0', 'pi/2', 'pi'])
plt.yticks([-1, 0, 1], ['-1', '0', '1'])


# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1);

"""
Explanation: 3.4 Setting tick labels
To set the tick labels, you pass a second parameter to the xticks and yticks methods with a list of labels for that axis. 
plt.sca(axis)
plt.xticks([tickvalues], [ticklabels])
plt.yticks([tickvalues], [ticklabels])
End of explanation
"""


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

fig, axes = plt.subplots(1,2)
# Let's set labels here
axes[0].plot(x, y1, color='r', linewidth=5, label='sin(x)')
axes[1].plot(x, y1, color='#ffaa00', linewidth=0.5, linestyle='--', label='sin(x)')
axes[1].plot(x, y2, color='green', linestyle='-.', label='cos(x)')

# Set the current axis to the first subplot
fig.sca(axes[0])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], ['-pi', '-pi/2', '0', 'pi/2', 'pi'])
# You probably don't want to set the labels when you just want the exact numbers.
plt.yticks([-1, 0, 1], ['-1', '0', '1'])
plt.legend(loc='best')

# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1)

# Set the current axis to the second subplot
fig.sca(axes[1])
# set x and y ticks
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], ['-pi', '-pi/2', '0', 'pi/2', 'pi'])
plt.yticks([-1, 0, 1], ['-1', '0', '1'])
plt.legend(loc='upper right')

# set x and y limits
plt.xlim(-np.pi, np.pi)
plt.ylim(-1, 1);

"""
Explanation: 3.5 Legend
When you create a line on a plot, you can pass it a keyword argument label and then create a legend that will use that label using the legend method. The legend method takes an optional parameter of loc for the location of the legend. You can see the values allowed here: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.legend This is another one of those commands that you need to set the current axis if you have more than one subplot.
plt.plot(x,y, label='my_label')
plt.legend(loc='best')
End of explanation
"""


# Make some data to plot
x = np.arange(0, 100)
y = np.random.rand(100)  # 100 random numbers

# Make a figure with 6 subplots and axes
# Notice that we are doing some arguement unpacking to get six subplots. You can use indexing instead if you prefer
fig, ((ax1, ax2), (ax3, ax4), (ax5, ax6)) = plt.subplots(3, 2)

# Add data to each axis. Optional arguments to each method will customize each plot.
ax1.bar(x,y)
ax2.scatter(x,y)
ax3.barh(x,y)
ax4.boxplot(x)
ax5.loglog(x,y)
ax6.semilogx(x,y)

"""
Explanation: TRY IT
Go back to your plot of f(x) = x^3 for values of x 0-10. Try out some of the formatting options you just learned to make your plot look "just right"
4. Other types of plots
Matplotlib is more than just line plots, let's see what else it can do.
1.1 Other plots
In the examples above, we used the plot method to make line plots. There are also methods to
make scatter plots, barplots, histograms, loglog plots, semilog plots, etc.
# Bar graph
ax.bar(x, y)

# Scatter plot
ax.scatter(x,y)

# Horizontal bar plot
ax.barh(x,y)

# Boxplot
ax.boxplot(x)

# Log-log plot
ax.loglog(x,y)

# Semilog plot
ax.semilogx(x,y)
ax.semilogy(x,y)

Plots too squished? Check out plt.tight_layout()
End of explanation
"""


fig, ax = plt.subplots(1,1)
ax.scatter(x, y, marker='x')
ax.scatter(x, y + 2, marker='>', color='#00aaff')

"""
Explanation: Many of the same formatting options as the line plot are available for these additional plots. There are also some other options. The gallery (section 5) is the best place to find all the options. 
Let's try changing the marker on the scatter plot: http://matplotlib.org/exmples/lines_bars_and_markers/marker_reference.html
End of explanation
"""


# Read image from file and display it
img1 = plt.imread('astronaut.png')
# Uncomment following line to prove it still works without the alpha channel
# img1 = img1[:,:, 0:3]
fig, ax = plt.subplots(1,1)
ax.imshow(img1)

# We can plot random noise in the viridis colormap.
img2 = np.random.rand(128, 128)

fig, ax = plt.subplots(1,1)
ax = ax.imshow(img2, cmap='viridis')

"""
Explanation: 4.2 Plotting images
Matplotlib also makes it easy to plot images. For this, you can use the plot method imshow
(syntax borrowed from Matlab).
To load in an image we use the imread function. This takes a file path and reads the file into a numpy ndarray
To plot an image, you can use imshow function giving it an array. 
A 1D array will be rendered as grayscale and a 3D or (4D with transparency) array will be a full color image.
To set the colormap of a grayscale image, you can use the optional cmap key word argument to imshow. Options available are listed here: http://matplotlib.org/examples/color/colormaps_reference.html
End of explanation
"""


# %load http://matplotlib.org/mpl_examples/pylab_examples/contour_demo.py

"""
Explanation: TRY IT
Plot the cubes from 1-10 in a vertical bar chart and in a scatter plot (2 separate subplots). Change the colors of the bars to green. Change the marker of the scatter plot to plus signs.
5. The matplotlib gallery
It can be very intimidating to try to craft exactly the figure that you want, especially if
you are used to being able to adjust things visually using a program like Excel.
If you get stuck and don't know where to start, or just want to learn more about what
matplotlib can do, a great option is to have a look at the matplotlib gallery, which can be
found at http://matplotlib.org/gallery.html. A good way to get started is to find a figure
here that sort of looks like what you want, copy the code, and modify it for your own needs.
5.1 Exploring the matplotlib gallery
Have a look at the matplotlib gallery. If find a cool looking figure you can copy the code into a code line. You can of course do this manually but you can also use IPython "load magic" Type %loadpy and then the URL of the py file containing the code, and it will automatically copy it into a cell below. Run the cell with the code to see the
figure. Now you can make small (or large) tweaks to get your perfect figure.
Note that some of the examples might require packages that are not installed on your machine (in particular those that make maps) - if this is the case, pick another example for the purposes of this exercise.
Hint to get the raw python url right click on the source code link towards the top and pick copy link.
End of explanation
"""


