# Matplotlib Basics

## Overview:

• Teaching: 20 minutes
• Exercises: 10 minutes

### Questions

1. How are line plots created using Matplotlib?
2. What methods exist to customize the look of these plots?

### Objectives

1. Create a basic line plot.
2. Add labels and grid lines to the plot.
3. Plot multiple series of data.
4. Plot imshow, contour, and filled contour plots.

## Plotting with Matplotlib

Matplotlib is a python 2D plotting library which produces publication quality figures in a variety of hardcopy formats and interactive environments across platforms.

The first step is to set up our notebook environment so that matplotlib plots appear inline as images:

``````

In [ ]:

%matplotlib inline

``````

Next we import the matplotlib library's `pyplot` interface; this interface is the simplest way to create new Matplotlib figures. To shorten this long name, we import it as `plt` to keep things short but clear.

``````

In [ ]:

import matplotlib.pyplot as plt
import numpy as np

``````

Now we generate some data to use while experimenting with plotting:

``````

In [ ]:

times = np.array([ 93.,  96.,  99., 102., 105., 108., 111., 114., 117.,
120., 123., 126., 129., 132., 135., 138., 141., 144.,
147., 150., 153., 156., 159., 162.])
temps = np.array([310.7, 308.0, 296.4, 289.5, 288.5, 287.1, 301.1, 308.3,
311.5, 305.1, 295.6, 292.4, 290.4, 289.1, 299.4, 307.9,
316.6, 293.9, 291.2, 289.8, 287.1, 285.8, 303.3, 310.])

``````

Now we come to two quick lines to create a plot. Matplotlib has two core objects: the `Figure` and the `Axes`. The `Axes` is an individual plot with an x-axis, a y-axis, labels, etc; it has all of the various plotting methods we use. A `Figure` holds one or more `Axes` on which we draw; think of the `Figure` as the level at which things are saved to files (e.g. PNG, SVG)

Below the first line asks for a `Figure` 10 inches by 6 inches. We then ask for an `Axes` or subplot on the `Figure`. After that, we call `plot`, with `times` as the data along the x-axis (independant values) and `temps` as the data along the y-axis (the dependant values).

``````

In [ ]:

# Create a figure
fig = plt.figure(figsize=(10, 6))

# Ask, out of a 1x1 grid, the first axes.

# Plot times as x-variable and temperatures as y-variable
ax.plot(times, temps)

``````

From there, we can do things like ask the axis to add labels for x and y:

``````

In [ ]:

# Add some labels to the plot
ax.set_xlabel('Time')
ax.set_ylabel('Temperature')

# Prompt the notebook to re-display the figure after we modify it
fig

``````

We can also add a title to the plot:

``````

In [ ]:

ax.set_title('GFS Temperature Forecast', fontdict={'size':16})

fig

``````

Of course, we can do so much more...

``````

In [ ]:

# Set up more temperature data
temps_1000 = np.array([316.0, 316.3, 308.9, 304.0, 302.0, 300.8, 306.2, 309.8,
313.5, 313.3, 308.3, 304.9, 301.0, 299.2, 302.6, 309.0,
311.8, 304.7, 304.6, 301.8, 300.6, 299.9, 306.3, 311.3])

``````

Here we call `plot` more than once to plot multiple series of temperature on the same plot; when plotting we pass `label` to `plot` to facilitate automatic creation. This is added with the `legend` call. We also add gridlines to the plot using the `grid()` call.

``````

In [ ]:

fig = plt.figure(figsize=(10, 6))

# Plot two series of data
# The label argument is used when generating a legend.
ax.plot(times, temps, label='Temperature (surface)')
ax.plot(times, temps_1000, label='Temperature (1000 mb)')

ax.set_xlabel('Time')
ax.set_ylabel('Temperature')
ax.set_title('Temperature Forecast')

ax.grid(True)

# Add a legend to the upper left corner of the plot
ax.legend(loc='upper left')

``````

We're not restricted to the default look of the plots, but rather we can override style attributes, such as `linestyle` and `color`. `color` can accept a wide array of options for color, such as `red` or `blue` or HTML color codes. Here we use some different shades of red taken from the Tableau color set in matplotlib, by using `tab:red` for color.

``````

In [ ]:

fig = plt.figure(figsize=(10, 6))

# Specify how our lines should look
ax.plot(times, temps, color='tab:red', label='Temperature (surface)')
ax.plot(times, temps_1000, color='tab:red', linestyle='--',
label='Temperature (isobaric level)')

# Same as above
ax.set_xlabel('Time')
ax.set_ylabel('Temperature')
ax.set_title('Temperature Forecast')
ax.grid(True)
ax.legend(loc='upper left')

``````

### Exercise

• Use `add_subplot` to create two different subplots on the figure
• Create one subplot for temperature, and one for dewpoint
• Set the title of each subplot as appropriate
• Use `ax.set_xlim` and `ax.set_ylim` to control the plot boundaries
• BONUS: Experiment with passing `sharex` and `sharey` to `add_subplot` to share plot limits
``````

In [ ]:

# Fake dewpoint data to plot
dewpoint = 0.9 * temps
dewpoint_1000 = 0.9 * temps_1000

# Create the figure
fig = plt.figure(figsize=(10, 6))

``````

#### Solution

``````

In [ ]:

``````

## Scatter Plots

Maybe it doesn't make sense to plot your data as a line plot, but with markers (a scatter plot). We can do this by setting the `linestyle` to none and specifying a marker type, size, color, etc.

``````

In [ ]:

fig = plt.figure(figsize=(10, 6))

# Specify no line with circle markers
ax.plot(temps, temps_1000, linestyle='None', marker='o', markersize=5)

ax.set_xlabel('Temperature (surface)')
ax.set_ylabel('Temperature (1000 hPa)')
ax.set_title('Temperature Cross Plot')
ax.grid(True)

``````

You can also use the `scatter` methods, which is slower, but will give you more control, such as being able to color the points individually based upon a third variable.

``````

In [ ]:

fig = plt.figure(figsize=(10, 6))

# Specify no line with circle markers
ax.scatter(temps, temps_1000)

ax.set_xlabel('Temperature (surface)')
ax.set_ylabel('Temperature (1000 hPa)')
ax.set_title('Temperature Cross Plot')
ax.grid(True)

``````

### Exercise

• Beginning with our code above, add the `c` keyword argument to the `scatter` call and color the points by the difference between the surface and 1000 hPa temperature.
• Add a 1:1 line to the plot (slope of 1, intercept of zero). Use a black dashed line.
• BONUS: Change the color map to be something more appropriate for this plot.
• BONUS: Try to add a colorbar to the plot (have a look at the matplotlib documentation for help).
``````

In [ ]:

fig = plt.figure(figsize=(10, 6))

ax.set_xlabel('Temperature (surface)')
ax.set_ylabel('Temperature (1000 hPa)')
ax.set_title('Temperature Cross Plot')
ax.grid(True)

``````

#### Solution

``````

In [ ]:

``````

## imshow/contour

• `imshow` displays the values in an array as colored pixels, similar to a heat map.
• `contour` creates contours around data.
• `contourf` creates filled contours around data.

First let's create some fake data to work with - let's use a bivariate normal distribution.

``````

In [ ]:

x = y = np.arange(-3.0, 3.0, 0.025)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2

``````

``````

In [ ]:

fig, ax = plt.subplots()
im = ax.imshow(Z, interpolation='bilinear', cmap='RdYlGn',
origin='lower', extent=[-3, 3, -3, 3])

``````

We can also create contours around the data.

``````

In [ ]:

fig, ax = plt.subplots()
ax.contour(X, Y, Z)

``````
``````

In [ ]:

fig, ax = plt.subplots()
c = ax.contour(X, Y, Z, levels=np.arange(-2, 2, 0.25))
ax.clabel(c)

``````
``````

In [ ]:

fig, ax = plt.subplots()
c = ax.contourf(X, Y, Z)

``````

### Exercise

• Create a figure using imshow and contour that is a heatmap in the colormap of your choice. Overlay black contours with a 0.5 contour interval.
``````

In [ ]:

``````

#### Solution

``````

In [ ]: