Matplotlib Basics
Matplotlib Basics
Unidata Python Workshop
Questions¶
- How are line plots created using Matplotlib?
- What methods exist to customize the look of these plots?
Objectives¶
- Create a basic line plot.
- Add labels and grid lines to the plot.
- Plot multiple series of data.
- 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:
%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.
import matplotlib.pyplot as plt
import numpy as np
Now we generate some data to use while experimenting with plotting:
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).
# Create a figure
fig = plt.figure(figsize=(10, 6))
# Ask, out of a 1x1 grid, the first axes.
ax = fig.add_subplot(1, 1, 1)
# 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:
# 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:
ax.set_title('GFS Temperature Forecast', fontdict={'size':16})
fig
Of course, we can do so much more...
# 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.
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(1, 1, 1)
# 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)')
# Add labels and title
ax.set_xlabel('Time')
ax.set_ylabel('Temperature')
ax.set_title('Temperature Forecast')
# Add gridlines
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.
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(1, 1, 1)
# 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')
- 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
# Fake dewpoint data to plot
dewpoint = 0.9 * temps
dewpoint_1000 = 0.9 * temps_1000
# Create the figure
fig = plt.figure(figsize=(10, 6))
# YOUR CODE GOES HERE
# %load solutions/subplots.py
# Cell content replaced by load magic replacement.
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(1, 2, 1)
# 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')
ax2 = fig.add_subplot(1, 2, 2, sharex=ax, sharey=ax)
ax2.plot(times, dewpoint, color='tab:green', label='Dewpoint (surface)')
ax2.plot(times, dewpoint_1000, color='tab:green', linestyle=':', marker='o',
label='Dewpoint (isobaric level)')
ax2.set_xlabel('Time')
ax2.set_ylabel('Dewpoint')
ax2.set_title('Dewpoint Forecast')
ax2.grid(True)
ax2.legend(loc='upper left')
ax2.set_ylim(257, 312)
ax2.set_xlim(95, 162)
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.
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(1, 1, 1)
# 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.
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(1, 1, 1)
# 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)
- 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).
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(1, 1, 1)
# YOUR CODE GOES HERE
ax.set_xlabel('Temperature (surface)')
ax.set_ylabel('Temperature (1000 hPa)')
ax.set_title('Temperature Cross Plot')
ax.grid(True)
# %load solutions/color_scatter.py
# Cell content replaced by load magic replacement.
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(1, 1, 1)
ax.plot([285, 320], [285, 320], color='black', linestyle='--')
s = ax.scatter(temps, temps_1000, c= temps - temps_1000, cmap='bwr', vmin=-5, vmax=5)
fig.colorbar(s)
ax.set_xlabel('Temperature (surface)')
ax.set_ylabel('Temperature (1000 hPa)')
ax.set_title('Temperature Cross Plot')
ax.grid(True)
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.
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
Let's start with a simple imshow plot.
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.
fig, ax = plt.subplots()
ax.contour(X, Y, Z)
fig, ax = plt.subplots()
c = ax.contour(X, Y, Z, levels=np.arange(-2, 2, 0.25))
ax.clabel(c)
fig, ax = plt.subplots()
c = ax.contourf(X, Y, Z)
- 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.
# YOUR CODE GOES HERE
# %load solutions/imshow_contour.py
# Cell content replaced by load magic replacement.
fig, ax = plt.subplots()
im = ax.imshow(Z, interpolation='bilinear', cmap='PiYG',
origin='lower', extent=[-3, 3, -3, 3])
c = ax.contour(X, Y, Z, levels=np.arange(-2, 2, 0.5), colors='black')
ax.clabel(c)
Resources¶
The goal of this tutorial is to provide an overview of the use of the Matplotlib library. It covers creating simple line plots, but it is by no means comprehensive. For more information, try looking at the: