Dr Jon Shiach, Department of Computing and Mathematics, Manchester Metropolitan University
On successful completion of this page readers will be able to:
We can use Python to produce plots of data and save them to a file. Here we will look at how we can create the most common types of plots.
matplotlib is a library of functions that allows us to produce plots of data within a Python program. Like with other libraries, we need to import it using the import
command. For example, to import the matplotlib
module pyplot
which is used for the most common plots we use the following code
import matplotlib.pyplot as plt
This will allow us to call pyplot
functions using the precursor plt.
.
Before we can produce a plot we need to create a figure object and an axis object. The simplest way to do this is to use the plt.subplots
command (pyplot.subplots help page).
fig, ax = plt.subplots()
Here fig
and ax
are the names we have given to the figure and axis objects respectively (think of these as variable names).
To plot a simple two-dimensional function we can use the plt.plot
command (pyplot.plot help page).
plt.plot(x, y)
plt.show()
where x
and y
are one-dimensional arrays. The plt.show()
command is used to show the current plot.
The NumPy command np.linspace
is useful for generating an array of x
values (numpy.linspace help page).
x = np.linspace(start, end, num)
This creates an array x
with num
equally spaced values between start
and end
inclusive.
The Python code below plots the function $y=x^2$. Enter it into the code cell below and execute it to see the result.
import numpy as np
# Generate co-ordiante arrays
x = np.linspace(-2, 2, 50)
y = x ** 2
# Plot figure
fig, ax = plt.subplots()
plt.plot(x, y)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
# Generate co-ordinate arrays
x = np.linspace(-2, 2, 50)
y = x ** 2
# Plot figure
fig, ax = plt.subplots()
plt.plot(x, y)
plt.show()
We can change the appearance of the line by specifying the format after the co-ordinates in the plt.plot
command.
plt.plot(x, y, fmt)
Where fmt
is a character string that specifies the colour, marker and line styles.
fmt = "[marker][line][colour]"
The characters for some of the marker, line and colour styles are shown in the table below. Note that these are optional, e.g., if no marker character is specified then the data will be plotted as a line without markers. Also it doesn"t matter what order the characters in fmt
are, e.g., "r-o"
produces the same result as "o-r"
.
Character | Description | Character | Description | Character | Description |
---|---|---|---|---|---|
"." |
point marker | "-" |
solid line | "b" |
blue |
"," |
pixel marker | "--" |
dashed line | "g" |
green |
"o" |
circle marker | "-." |
dash-dot line | "r" |
red |
"v" |
triangle down marker | ":" |
dotted line | "c" |
cyan |
"^" |
triangle up marker | "m" |
magenta | ||
"s" |
square marker | "y" |
yellow | ||
"*" |
star marker | "k" |
black | ||
"+" |
plus marker | "w" |
white | ||
"x" |
x marker |
The Python commands below plots the same function $y=x^2$ from example 1 using a red line with a circle marking each point (the fig
command tells Python to show the figure fig
again so we can see the affect of the changes). Enter them into the code cell below and execute it to see the result.
fig, ax = plt.subplots()
plt.plot(x, y, "r-o") # Plot red line with circle markers
plt.show()
fig, ax = plt.subplots()
plt.plot(x, y, "r-o") # Plot red line with circle markers
plt.show()
The axis scale can be adjusted using the plt.xlim
and plt.ylim
commands (pyplot.xlim help page)
plt.xlim(xmin, xmax)
plt.ylim(ymin, ymax)
where xmin
and xmax
are the minimum and maximum value on the $x$-axis (and similar for $y$).
We can set the aspect ratio of the plot which controls the height and with of the axes using the ax.set_aspect
command (pyplot.set_aspect help page)
ax.set_aspect(value)
Here value
is either "auto"
, "equal"
or num
as described in the table below.
value | description |
---|---|
"auto" |
automatic; fill the position rectangle with data |
"equal" |
same scaling from data to plot units for $x$ and $y$ |
num |
a circle will be stretched such that the height is num times the width |
The commands below change the axis limits and aspect ratio to the plot from example 2. Enter them into the code cell below and execute it to see the result.
fig, ax = plt.subplots()
plt.plot(x, y, "r-o") # Plot red line with circle markers
plt.xlim(0, 2) # set x axis range to [-1, 1]
plt.ylim(0, 2) # set y axis range to [-1, 2]
plt.show()
fig, ax = plt.subplots()
plt.plot(x, y, "r-o") # Plot red line with circle markers
plt.xlim(0, 2) # set x axis range to [-1, 1]
plt.ylim(0, 2) # set y axis range to [-1, 2]
plt.show()
Axis labels and titles can be added to a plot using the plt.xlabel
, plt.ylabel
and plt.title
commands (plt.xlabel help page, plt.title help page).
plt.xlabel("x axis label", fontsize=size)
plt.ylabel("y axis label", fontsize=size)
plt.title("plot title", fontsize=size)
Where fontsize=size
is optional and specifies fontsize in pt.
The following commands add axis labels and title to the plot from example 2. Enter them into the code cell below and execute it to see the result.
fig, ax = plt.subplots()
plt.plot(x, y, "r-o")
plt.xlabel("$x$", fontsize=12) # x axis label
plt.ylabel("$y$", fontsize=12) # y axis label
plt.title("$y = x^2$", fontsize=12) # plot title
plt.show()
fig, ax = plt.subplots()
plt.plot(x, y, "r-o")
plt.xlabel("$x$", fontsize=12) # x axis label
plt.ylabel("$y$", fontsize=12) # y axis label
plt.title("$y = x^2$", fontsize=12) # plot title
plt.show()
Note: the use of the dollar signs in the strings for the axis labels and titles tells Python format the text using $\LaTeX$. This is optional but useful when you want to include maths formatting in the labels.
We can save a figure to a file so that we can import it into other documents using the savefig
command (pyplot.savefig help page).
fig.savefig(filename)
Where filename
includes the extension for the image type used. Most common image formats are supported, e.g., png, jpeg, svg etc., but png (Portable Network Graphics) files are preferred for importing into electronic documents.
The command below saves the figure fig
as a png file using the file name myplot.png
. Enter it into the code cell below and execute it. Check that an image file containing your plot has been produced and open it to see the result.
fig.savefig("myplot.png")
fig.savefig("myplot.png")
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 4 * np.pi, 200)
y = np.sin(x)
fig, ax = plt.subplots()
plt.plot(x, y, "r")
plt.ylim([-2, 2])
plt.xlabel("$x$")
plt.ylabel("$y$")
plt.title("$y = \sin(x)$")
plt.show()
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 200)
y = x ** 2 - 3 * x + 2
fig, ax = plt.subplots()
plt.plot(x, y)
plt.xlabel("$x$")
plt.ylabel("$y$")
plt.title("$y = x^2 - 3x + 2x$")
plt.show()
t = np.linspace(-4, 4, 100)
s = 2 * t ** 3 + 3 * t ** 2 - 8 * t + 6
fig, ax = plt.subplots()
plt.plot(t, s, "g-")
plt.xlim(-4, 4)
plt.ylim(-50, 50)
plt.xlabel("$t$")
plt.ylabel("$s$")
plt.title("$s = 2t^3 + 3t^2 - 8t + 6$")
plt.show()
To include multiple plots on the same axis simply add another plot
command.
plt.plot(x1, y1) # first plot
plt.plot(x2, y2) # second plot
The commands below plots the three functions $y=x^2$, $y=x^3$ and $y=x^4$ over the domain $x\in[-2,2]$ on the same set of axes. Enter them into the code cell below and execute it to see the result.
# Generate co-ordinate arrays
x = np.linspace(-2, 2, 100)
y1 = x ** 2 # first function
y2 = x ** 3 # second function
y3 = x ** 4 # third function
# Plot functions
fig, ax = plt.subplots()
plt.plot(x, y1, "-r") # first plot
plt.plot(x, y2, "-b") # second plot
plt.plot(x, y3, "-k") # third plot
plt.xlabel("$x$", fontsize=12)
plt.ylabel("$y$", fontsize=12)
plt.show()
# Generate co-ordinate arrays
x = np.linspace(-2, 2, 100)
y1 = x ** 2 # first function
y2 = x ** 3 # second function
y3 = x ** 4 # third function
# Plot functions
fig, ax = plt.subplots()
plt.plot(x, y1, "-r") # first plot
plt.plot(x, y2, "-b") # second plot
plt.plot(x, y3, "-k") # third plot
plt.xlabel("$x$", fontsize=12)
plt.ylabel("$y$", fontsize=12)
plt.show()
A legend can be added to a plot using the legend
command (pyplot.legend help page) but first we need to add a label to each plot
command.
plt.plot(x, y1, label="1st plot label")
plt.plot(x, y2, label="2nd plot label")
Once the individual plots have labels associated with them we can add a legend using
plt.legend(fontsize=size, loc=location)
Where fontsize
and loc
are optional arguments. location
is a character string from one of "uppper left"
, "upper center
, upper right"
, "left"
, "center"
, "right"
, "lower left"
, "lower center"
and "lower right"
The commands below add a legend to the plot from example 6. Enter them into the code cell below and execute it to see the result.
fig, ax = plt.subplots()
plt.plot(x, y1, "-r") # first plot
plt.plot(x, y2, "-b") # second plot
plt.plot(x, y3, "-k") # third plot
plt.xlabel("x", fontsize=12)
plt.ylabel("y", fontsize=12)
plt.legend()
plt.show()
fig, ax = plt.subplots()
plt.plot(x, y1, "-r", label="$y=x^2$")
plt.plot(x, y2, "-b", label="$y=x^3$")
plt.plot(x, y3, "-k", label="$y=x^4$")
plt.xlabel("$x$")
plt.ylabel("$y$")
plt.legend()
plt.show()
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-2 * np.pi, 2 * np.pi, 100)
y1 = np.sin(x)
y2 = np.cos(x)
fig, ax = plt.subplots()
plt.plot(x, y1, "r-", label="$y = \sin(x)$")
plt.plot(x, y2, "b--", label="$y = \cos(x)$")
plt.xlim(-2 * np.pi, 2 * np.pi)
plt.ylim(-2, 2)
plt.xlabel("$x$")
plt.ylabel("$y$")
plt.legend(loc="upper left")
plt.show()
ax.set_aspect("equal")
command to display the circles in the correct aspect ratio (so they look like circles and not ellipses).import numpy as np
import matplotlib.pyplot as plt
cx, cy = 5, 5
theta = np.linspace(0, 2 * np.pi, 100)
fig, ax = plt.subplots()
for r in range(1, 5):
x = cx + r * np.cos(theta)
y = cy + r * np.sin(theta)
plt.plot(x, y)
plt.xlim(0, 10)
plt.ylim(0, 10)
ax.set_aspect("equal")
plt.xlabel("$x$", fontsize=12)
plt.ylabel("$y$", fontsize=12)
plt.show()
Scatter plots can be produced using the scatter
command (pyplot.scatter help page)
plt.scatter(x, y, color=[colour], marker=[marker style])
Where x
and y
are one-dimensional co-ordinate arrays and [colour]
and [marker style]
are characters (see Plot Styles section)
The following commands produce a scatter plot of 100 random points with co-ordinates in the range $x,y\in[0, 1]$. Enter them into the code cell below and execute it to see the result.
# Generate co-ordinate arrays
x = np.random.rand(100, 1)
y = np.random.rand(100, 1)
# Plot scatterplot
fig, ax = plt.subplots()
plt.scatter(x, y, color="r", marker="o")
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.xlabel("$x$", fontsize=12)
plt.ylabel("$y$", fontsize=12)
plt.show()
# Generate co-ordinate arrays
x = np.random.rand(100, 1)
y = np.random.rand(100, 1)
# Plot scatterplot
fig, ax = plt.subplots()
plt.scatter(x, y, color="r", marker="o")
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.xlabel("$x$", fontsize=12)
plt.ylabel("$y$", fontsize=12)
plt.show()
x
and y
provided in the code cell below.import numpy as np
import matplotlib.pyplot as plt
x = np.array([ 0.1734, 0.3909, 0.8314, 0.8034, 0.0605, \
0.3993, 0.5269, 0.4168, 0.6569, 0.6280 ])
y = np.array([ 0.0717, 0.1665, 0.7881, 0.5486, 0.0702, \
0.2382, 0.3031, 0.2341, 0.4335, 0.4265 ])
fig, ax = plt.subplots()
plt.scatter(x, y)
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.xlabel("$x$", fontsize=12)
plt.ylabel("$y$", fontsize=12)
plt.show()
np.linalg.lstsq
which calculates the least squares solution which minimises the difference between the points $(x_i,y_i)$ and the line $y=mx+c$.m, c = np.linalg.lstsq(A, y, rcond=None)[0]
A
, calculate the line of best fit for the data from question 6 and add it to your scatter plot.import numpy as np
import matplotlib.pyplot as plt
# Calculate line of best fit
A = np.ones((10,2))
A[:,0] = x
m, c = np.linalg.lstsq(A, y, rcond=None)[0]
# Plot data
fig, ax = plt.subplots()
plt.scatter(x, y)
plt.plot(x, m * x + c, "r")
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.xlabel("$x$", fontsize=12)
plt.ylabel("$y$", fontsize=12)
plt.title(f"line of best fit: $y = {m:0.4f}x + {c:0.4f}$.", fontsize=12)
plt.show()
To create a 3D plot we first need to create a 3D axis using the Axes3D
toolkit which is done using the following commands.
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = plt.axes(projection="3d")
3D surface plots can be generated using the ax.plot_surface
command (Axes3D.plot_surface help page).
ax.plot_surface(X, Y, Z, cmap="jet", edgecolor="k")
where X
, Y
and Z
are two-dimensional co-ordinate arrays. The optional arguments are:
cmap="jet"
applies the jet
colormapedgecolor="k"
draws the edges of the polygons that make up the surfaceTo produce a surface plot of the bivariate function $z=f(x,y)$ we require $x$ and $y$ co-ordinates in the domain. The np.meshgrid
command is useful for generating these (numpy.meshgrid help page).
X, Y = np.meshgrid(x co-ordinate array, y co-ordinate array)
The Python commands below generates two $4\times 6$ element matrixes X
and Y
containing the co-ordinates of points in the domain $\{(x, y):x, y \in \mathbb{R}, 0\leq x \leq 5, 0 \leq y \leq 6\}$ using an increment of 1 in the $x$ direction and 2 in the $y$ direction. Enter it into the code cell below and execute it to see the result.
x = np.arange(0, 6, 1)
y = np.arange(0, 7, 2)
X, Y = np.meshgrid(x, y)
print(X, end="\n\n")
print(Y)
x = np.arange(0, 6, 1)
y = np.arange(0, 7, 2)
X, Y = np.meshgrid(x, y)
print(X)
print()
print(Y)
[[0 1 2 3 4 5] [0 1 2 3 4 5] [0 1 2 3 4 5] [0 1 2 3 4 5]] [[0 0 0 0 0 0] [2 2 2 2 2 2] [4 4 4 4 4 4] [6 6 6 6 6 6]]
The Python code below produces a surface plot of the two-dimensional surface $z=\sin(x) + \cos(y)$ over the domain $x,y\in [0, 4\pi]$. Enter it into the code cell below and execute it to see the result.
from mpl_toolkits.mplot3d import Axes3D
# Generate co-ordinate arrays
x = np.linspace(0, 4 * np.pi, 50)
y = np.linspace(0, 4 * np.pi, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
# Plot surface
fig = plt.figure(figsize=(10, 6))
ax = plt.axes(projection="3d")
ax.plot_surface(X, Y, Z, cmap="jet", edgecolor="k")
plt.xlim(0, 4 * np.pi)
plt.ylim(0, 4 * np.pi)
ax.set_zlim(-3, 3)
ax.set_xlabel("$x$")
ax.set_ylabel("$y$")
ax.set_zlabel("$z$")
plt.show()
from mpl_toolkits.mplot3d import Axes3D
# Generate co-ordinate arrays
x = np.linspace(0, 4 * np.pi, 50)
y = np.linspace(0, 4 * np.pi, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
# Plot surface
fig = plt.figure(figsize=(10, 6))
ax = plt.axes(projection="3d")
ax.plot_surface(X, Y, Z, cmap="jet", edgecolor="k")
plt.xlim(0, 4 * np.pi)
plt.ylim(0, 4 * np.pi)
ax.set_zlim(-3, 3)
ax.set_xlabel("$x$", fontsize=12)
ax.set_ylabel("$y$", fontsize=12)
ax.set_zlabel("$z$", fontsize=12)
plt.title("$z = \sin(x) + \cos(y)$", fontsize=12)
plt.show()
With 3D plots we can control the position of the viewpoint using the view_init
command
ax.view_init(elevation, azimuth)
where elevation
and azimuth
are the angles (in degrees) that specify the vertical and horizontal position of the viewpoint relative to the centre of view.
The Python commands below changes the surface plot produced in example 10 so that it is viewed from the viewpoint with elevation $45^\circ$ and azimuth $15^\circ$. Enter it into the code cell below and execute it to see the result.
ax.view_init(45, 15)
display(fig)
ax.view_init(45, 15)
display(fig)
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Generate co-ordinate arrays
x = np.linspace(0, 1, 20)
y = np.linspace(0, 1, 20)
X, Y = np.meshgrid(x, y)
Z = np.exp(-20 * ((X - 0.5) ** 2 + (Y - 0.5) ** 2))
# Plot surface
fig = plt.figure(figsize=(10,6))
ax = plt.axes(projection="3d")
ax.plot_surface(X, Y, Z, cmap="jet", edgecolor="k")
plt.xlim(0, 1)
plt.ylim(0, 1)
ax.set_zlim(0, 1)
ax.set_xlabel("$x$", fontsize=12)
ax.set_ylabel("$y$", fontsize=12)
ax.set_zlabel("$z$", fontsize=12)
plt.show()
Contour plots show points of equal value can be produced using the contour
command (pyplot.contour help page).
plt.contour(X, Y, Z)
The Python commands below produces a contour plot of the same bivariate function used in example 10. Enter it into the code cell below and execute it to see the result.
# Generate co-ordinate arrays
x = np.linspace(0, 4 * np.pi, 200)
y = np.linspace(0, 4 * np.pi, 200)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
# Contour plot
fig, ax = plt.subplots()
plt.contour(X, Y, Z)
plt.xlim(0, 4 * np.pi)
plt.ylim(0, 4 * np.pi)
plt.xlabel("$x$", fontsize=12)
plt.ylabel("$y$", fontsize=12)
plt.show()
# Generate co-ordinate arrays
x = np.linspace(0, 4 * np.pi, 200)
y = np.linspace(0, 4 * np.pi, 200)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
# Contour plot
fig, ax = plt.subplots()
plt.contour(X, Y, Z)
plt.xlim(0, 4 * np.pi)
plt.ylim(0, 4 * np.pi)
plt.xlabel("$x$", fontsize=12)
plt.ylabel("$y$", fontsize=12)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
# Generate co-ordinate arrays
x = np.linspace(-2, 3, 200)
y = np.linspace(-2, 3, 200)
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
# Contour plot
fig, ax = plt.subplots()
plt.contour(X, Y, Z)
plt.xlabel("$x$", fontsize=12)
plt.ylabel("$y$", fontsize=12)
plt.show()
Image plots (also known as raster plots) are plots which consist of an array of small squares called pixels. In Python image plots can be produced using the imshow
commands (pyplot.imshow help page).
plt.imshow(img)
Where img
is a NumPy array one of the following forms:
The following commands generate a random array of $10\times 10$ pixels and plots them using the imshow
command. Enter them into the code cell below and execute it.
img = np.random.rand(10, 10)
imgplot = plt.imshow(img, cmap="jet")
The optional command cmap="jet"
applies the jet
colormap.
img = np.random.rand(10, 10)
imgplot = plt.imshow(img, cmap="jet")
We can read in an image file into $m\times n \times 3$ NumPy array using the imread
command from the matplotlib.image
library (image.imread help page).
import matplotlib.image as mpimg
img = mpimg.imread(filename)
Where filename
is the name of the image file. This allows us to perform image manipulation operations on the image.
The Python commands below reads in the pixel data from an image, determines the size of the image and plots it using the imshow
command. Enter them into the code cell below and execute it to see the result.
import matplotlib.image as mpimg
# Read in image data
img = mpimg.imread("flower.jpg")
# Determine figure size based on the image size
height, width, nbands = img.shape
print(f"This image is {width} wide by {height} high and has {nbands} colour bands.")
# Plot image data
fig = plt.subplots()
imgplot = plt.imshow(img)
import matplotlib.image as mpimg
# Read in image data
img = mpimg.imread("flower.jpg")
# Determine figure size based on the image size
height, width, nbands = img.shape
print(f"This image is {width} wide by {height} high and has {nbands} colour bands.")
# Plot image data
fig = plt.subplots()
imgplot = plt.imshow(img)
This image is 1024 wide by 951 high and has 3 colour bands.
for
loops to generate a $11 \times 11$ array X
where the value of each element is the distance from the centre element, i.e.,Plot X
using the image
command.
X = np.zeros((11, 11))
for i in range(11):
for j in range(11):
X[i,j] = np.sqrt((i - 5) ** 2 + (j - 5) ** 2)
imgplot = plt.imshow(X, cmap="jet")
new_JD_building.jpeg
from the Moodle area for this unit and copy to the same folder that this Jupyter notebook is stored in. Load the data from this image into a NumPy array, determine the number of pixels in the image and plot the image.# Read in image data
img = mpimg.imread("new_JD_building.jpg")
# Determine figure size based on image size
height, width, nbands = img.shape
print(f"This image is {width} wide by {height} high and has {nbands} colour bands.")
# Plot image data
fig = plt.subplots()
imgplot = plt.imshow(img)