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)