⇦ Back

1 One Independent Variable, One Dependent Variable

1.1 Point-to-Point Curves

To create a simple line plot that connects points in a Cartesian plane:

  • Import the pyplot module from the Matplotlib library and give it the shorthand name plt
  • Create a plot with the plot() function

Here’s an example, showing a parabola (\(y = x^2\)):

import matplotlib.pyplot as plt

x = [1, 5, 9, 13]
y = [1, 25, 81, 169]

plt.plot(x, y)

1.2 Smooth Curves

When you only plot a few points as in the previous example, the resulting curve will look jagged. If you are plotting a continuous function like this it’s usually better to have it be a smooth curve. While it isn’t technically possible to plot a continuous curve using this method, you can at least make the line appear smooth by simply increasing the number of points you plot:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 13, 100)
y = x**2

plt.plot(x, y)

The above example is plotting 100 points and connecting them with straight lines. So the jagged edges still exist but they are now too small to be noticeable! Note the function that was used to create the x-data: Numpy’s linspace(). This function creates an array of numbers evenly spaced between a given start point and a given end point with the number of values created being the third input to the function. In this case the inputs were 0, 13 and 100, so 100 values were generated starting at 0 and ending at 13. The y-data was then created by taking the square of the x-data.

1.3 Vertical and Horizontal Lines

If you want to plot a straight line, you can simply plot two points and they will be connected as expected. In the special cases where you want to create horizontal or vertical lines that extend right to the ends of the graph in both directions, there are special functions axhline() and axvline():

# Plot a straight diagonal line
plt.plot([0, 9], [0, 8])
# Plot a horizontal line
plt.axhline(4)
# Plot a vertical line
plt.axvline(7)

1.4 Error Bars

Uncertainty can be communicated using the errorbar() function to plot error bars:

x = [1, 5, 9, 13]
y = [1, 25, 81, 169]
yerr = [1.5, 7.5, 15, 19]

plt.plot(x, y)
plt.errorbar(x, y, yerr=yerr, fmt='o', color='purple')

plt.show()

1.5 Formatting Options

Change the look of the plot with the following options:

  • Set the title with title()
  • Set the axis labels with ylabel() and xlabel()
  • Change the axis limits with ylim() and xlim()
  • Change the line colour and width using the c and lw keyword arguments in the plot() call (see this page for all the colour and line options)
  • Finally, display the plot with show()

Here’s an example using Manchester City’s log points after each matchweek of the 2018-19 English Premier League season:

import matplotlib.pyplot as plt

week = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
]
log_points = [
    3, 6, 7, 10, 13, 16, 19, 20, 23, 26, 29, 32, 35, 38, 41, 41, 44, 44, 44,
    47, 50, 53, 56, 56, 62, 65, 65, 68, 71, 74, 74, 80, 80, 83, 89, 92, 95, 98
]

plt.plot(week, log_points, c='#6caddf', lw=3)
plt.title('Manchester City in the 2018-19 Premier League')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)

plt.show()

1.6 More Options

Some more options that can be tinkered with:

  • Transparency of the line: use the alpha keyword argument within plot()
  • Gridlines: use the grid() function in which you can set which gridlines to mark (major, minor or both) and the axis to apply the lines to (x, y or both), along with other keyword arguments related to line plots
    • If you want minor gridlines and axis ticks you will also need to use plt.minorticks_on()
plt.plot(week, log_points, c='#6caddf', lw=3, alpha=0.5)
plt.title('Manchester City in the 2018-19 Premier League')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)
plt.grid(which='major', c='grey', lw='0.5', linestyle='-')

plt.show()

1.7 Text and Annotations

There is a difference between text and annotations on a graph:

  • Text labels are text only. They are added with the text() function which allows you to specify the x- and y-coordinates of the label’s position along with the string that should appear. There are also additional options that can be edited, such as ha (the horizontal alignment of the text), size and color
  • Annotations are text with arrows. These can be added with annotate() together with a number of arguments. These arguments can be specified by using their keywords or they can be given without keywords if they are in the following order:
    • text is the string that should appear
    • xy is a tuple containing the coordinates of the tip of the arrow. By default, these are interpreted as the Cartesian coordinates of the axes.
    • xytext is a tuple containing the coordinates of the text. Again, by default, these are Cartesian coordinates.
    • xycoords is the coordinate system that xy (the position of the tip of the arrow) is given in. There are a number of options but perhaps the most useful, besides Cartesian, is 'axes fraction' which allows you to specify the position as fractions of the width and height of the graph area. Unlike the default Cartesian coordinate system, this option allows you to add annotations outside of the actual graph area.
    • textcoords is similar to xycoords but is for the text, not the tip of the arrow. In addition to all the options available for xycoords you can use 'offset points' or 'offset pixels' which specifies the position of the text as an offset from the point it is annotating.
    • arrowprops is a dictionary of options for the arrow
  • Note that it is not compulsory for an annotation to have an arrow, which means that if you want to add text but also take advantage of the greater control that annotate() gives you you can do so. Conversely, you can create arrows without text by simply not specifying a string:
plt.plot(week, log_points, c='#6caddf', lw=3, alpha=0.5)
plt.title('Manchester City in the 2018-19 Premier League')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlim(1, 38)
# Add text and annotations
plt.text(33, 62, 'Final 14 matches', ha='center')
plt.text(33, 58, 'were all victories', ha='center')
plt.annotate(
    'Moved clear at the top of the table', (11, 29), (30, -20), textcoords='offset points',
    arrowprops=dict(facecolor='black', width=0.5, headwidth=5, headlength=7)
)
plt.annotate('Week 11', (11, 29), (-6, 6), textcoords='offset points', ha='right')
plt.annotate(
    '', (16 / 38, -0.07), (28 / 38, -0.07), 'axes fraction', 'axes fraction',
    arrowprops=dict(arrowstyle="<->", color='k')
)
plt.annotate('Dropped from top spot', (22 / 38, -0.12), xycoords='axes fraction', ha='center')

plt.show()

Read the full documentation for text labels here and for annotations here.

1.8 Multiple Groups

To plot multiple data series on the same axes, simply use the plot() function multiple times. When doing this, it’s usually best to include a legend. This is created via legend() after having specified the label keyword argument in the plot() calls:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# Get the data
data = pd.read_csv('Week-by-Week Points.csv')

# Plot
for team in list(data):
    log_points = data[team]
    week = np.arange(1, 39)
    plt.plot(week, log_points, label=team)
plt.title('2018-19 English Premier League')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)
plt.legend(fontsize='xx-small')

Of course, for this particular example, it makes sense to individually set the team colours:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# Get the data
data = pd.read_csv('Week-by-Week Points.csv')

# Create a dictionary of the colours
team_colours = {
    'AFC Bournemouth': '#8b0304',
    'Arsenal': '#ff0000',
    'Brighton': '#005daa',
    'Burnley': '#80bfff',
    'Cardiff': '#224781',
    'Chelsea': '#0000dd',
    'Crystal Palace': '#0a4af5',
    'Everton': '#274488',
    'Fulham': '#000000',
    'Huddersfield': '#176fc0',
    'Leicester': '#0101e8',
    'Liverpool': '#dd0000',
    'Man City': '#6caddf',
    'Man Utd': '#e80909',
    'Newcastle': '#000000',
    'Southampton': '#ed1a3b',
    'Spurs': '#132257',
    'Watford': '#fbee23',
    'West Ham': '#7f0000',
    'Wolves': '#fdbc02'
}

# Plot
for team in list(data):
    log_points = data[team]
    week = np.arange(1, 39)
    plt.plot(week, log_points, label=team, c=team_colours[team])
plt.title('2018-19 English Premier League')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)
plt.legend(fontsize='xx-small')

1.8.1 Positioning the Legend Outside the Axes

It often makes sense to place the legend outside of the axes to give it a bit more room. This requires some size adjustments using subplots_adjust() and more complicated arguments to be passed to legend():

for team in list(data):
    log_points = data[team]
    week = np.arange(1, 39)
    plt.plot(week, log_points, label=team, c=team_colours[team])
plt.title('2018-19 English Premier League Season')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)
plt.subplots_adjust(right=0.75)
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5), fontsize='small')

1.8.2 Manually Ordering the Legend

If you want the data series to appear in a particular order in the legend, you can assign each of them to a variable and then call those variables in the legend() call. In this example, the data for Fulham, Man City and Wolves are plotted in that order, but the order they appear in the legend is manually determined:

week = np.arange(1, 39)
man_city = [
    3, 6, 7, 10, 13, 16, 19, 20, 23, 26, 29, 32, 35, 38, 41, 41, 44, 44, 44,
    47, 50, 53, 56, 56, 62, 65, 65, 68, 71, 74, 74, 80, 80, 83, 89, 92, 95, 98
]
wolves = [
    1, 1, 2, 5, 8, 9, 12, 15, 15, 15, 15, 16, 16, 16, 19, 22, 25, 25, 26, 29,
    29, 29, 32, 35, 38, 39, 40, 40, 43, 44, 44, 47, 47, 47, 51, 54, 57, 57
]
fulham = [
    0, 0, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 8, 8, 9, 9, 9, 10, 11, 14, 14,
    14, 14, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 20, 23, 26, 26, 26
]

# Notice the commas after the variable names
fulham, = plt.plot(week, fulham, c='#000000')
man_city, = plt.plot(week, man_city, c='#6caddf')
wolves, = plt.plot(week, wolves, c='#fdbc02')
plt.title('2018-19 English Premier League Season')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)
plt.legend(
    (man_city, wolves, fulham),
    ('Man City', 'Wolves', 'Fulham'),
    loc='center left'
)

1.9 Colour Within, Under or Between Graphs

There are two methods of doing this. The first - fill() - will take the points you are plotting, draw straight lines between them (including from the last point back to the first point) and then fill in that enclosed area with colour. This means that, in order to get this method to work for our data, we need to add an extra point at the start and an extra point at the end. These will be at (1, 0) and (38, 0), respectively:

import matplotlib.pyplot as plt

week = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
]
log_points = [
    3, 6, 7, 10, 13, 16, 19, 20, 23, 26, 29, 32, 35, 38, 41, 41, 44, 44, 44,
    47, 50, 53, 56, 56, 62, 65, 65, 68, 71, 74, 74, 80, 80, 83, 89, 92, 95, 98
]

# Plot
plt.plot(week, log_points, c='#6caddf', lw=3)
plt.title('Manchester City in the 2018-19 Premier League')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)
# Add colour fill
week = [
    1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 38
]
log_points = [
    0, 3, 6, 7, 10, 13, 16, 19, 20, 23, 26, 29, 32, 35, 38, 41, 41, 44, 44, 44,
    47, 50, 53, 56, 56, 62, 65, 65, 68, 71, 74, 74, 80, 80, 83, 89, 92, 95, 98, 0
]
plt.fill(week, log_points, facecolor='#6caddf', alpha=0.5)

plt.show()

This is obviously quite obtuse, so a simpler option would be to use fill_between() which fills in the area between lines with colour. If you only specify one line then it will default to assuming that the second line is the x-axis:

import matplotlib.pyplot as plt

week = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
]
log_points = [
    3, 6, 7, 10, 13, 16, 19, 20, 23, 26, 29, 32, 35, 38, 41, 41, 44, 44, 44,
    47, 50, 53, 56, 56, 62, 65, 65, 68, 71, 74, 74, 80, 80, 83, 89, 92, 95, 98
]

# Plot
plt.plot(week, log_points, c='#6caddf', lw=3)
plt.title('Manchester City in the 2018-19 Premier League')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)
plt.fill_between(week, log_points, facecolor='#6caddf', alpha=0.5)

plt.show()

And then, of course, you still have the option of specifying a second line in order to fill in the area between those two:

week = np.arange(1, 39)
man_city = [
    3, 6, 7, 10, 13, 16, 19, 20, 23, 26, 29, 32, 35, 38, 41, 41, 44, 44, 44,
    47, 50, 53, 56, 56, 62, 65, 65, 68, 71, 74, 74, 80, 80, 83, 89, 92, 95, 98
]
wolves = [
    1, 1, 2, 5, 8, 9, 12, 15, 15, 15, 15, 16, 16, 16, 19, 22, 25, 25, 26, 29,
    29, 29, 32, 35, 38, 39, 40, 40, 43, 44, 44, 47, 47, 47, 51, 54, 57, 57
]

# Plot
plt.plot(week, man_city, c='#6caddf', label='Man City', lw=3)
plt.plot(week, wolves, c='#fdbc02', label='Wolves', lw=3)
plt.title('2018-19 English Premier League Season')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)
plt.legend()
plt.fill_between(week, man_city, wolves, facecolor='gray', alpha=0.5)

plt.show()

  • Use plt.fill_betweenx(y, x) to do the same thing as above but between two vertical curves (or between a curve and the y-axis)
  • Use the hatch keyword argument to apply a pattern to the shaded area. To increase the density of the shading, increase the number of characters when setting the hatch pattern (see here for more examples):
week = np.arange(1, 39)
man_city = [
    3, 6, 7, 10, 13, 16, 19, 20, 23, 26, 29, 32, 35, 38, 41, 41, 44, 44, 44,
    47, 50, 53, 56, 56, 62, 65, 65, 68, 71, 74, 74, 80, 80, 83, 89, 92, 95, 98
]
wolves = [
    1, 1, 2, 5, 8, 9, 12, 15, 15, 15, 15, 16, 16, 16, 19, 22, 25, 25, 26, 29,
    29, 29, 32, 35, 38, 39, 40, 40, 43, 44, 44, 47, 47, 47, 51, 54, 57, 57
]

# Plot
plt.plot(week, man_city, c='#6caddf', label='Man City', lw=3)
plt.plot(week, wolves, c='#fdbc02', label='Wolves', lw=3)
plt.title('2018-19 English Premier League Season')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)
plt.legend(framealpha=1)
plt.fill_betweenx(man_city, week, facecolor='#6caddf', alpha=0.5, hatch='++')
plt.fill_between(week, wolves, facecolor='#fdbc02', alpha=0.5, hatch='...')

plt.show()

1.10 Customising Axis Labels

1.10.1 Specifying Exact Tick Locations and Labels

Use yticks() and xticks() to:

  • Define the locations of the axis ticks
  • List the exact strings to be used as labels
import matplotlib.pyplot as plt

week = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
]
log_points = [
    3, 6, 7, 10, 13, 16, 19, 20, 23, 26, 29, 32, 35, 38, 41, 41, 44, 44, 44,
    47, 50, 53, 56, 56, 62, 65, 65, 68, 71, 74, 74, 80, 80, 83, 89, 92, 95, 98
]

plt.plot(week, log_points, c='#6caddf')
plt.title('Manchester City in the 2018-19 Premier League')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Month')
plt.xlim(1, 38)
plt.xticks(
    [1, 4, 7, 11, 14, 21, 25, 29, 32, 37],
    ['Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'Jan', 'Feb', 'Mar', 'Apr', 'May']
)

plt.show()

1.10.2 Plotting Text

In the previous example, the plot was created using numbers on the x-axis which were then replaced by text labels manually via the xticks() function. In this example, however, we ‘cut out the middleman’ and use text strings as the x-data from the start:

plt.rc('text', usetex=True)

month = [
    'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
    'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
]
temp = [
    6.7, 6.8, 8.8, 11.9, 14.7, 18.2,
    19.5, 19.3, 17.3, 13.5, 9.9, 7.0
]

plt.plot(month, temp, 'k')
plt.title('Climate of London')
plt.ylabel(r'Mean Daily Temperature [\textdegree C]')
plt.xlabel('Month')

The above data comes from Wikipedia.

1.10.3 Scaling and Formatting Tick Labels

If you want to change the scale on an axis, the best practice is to edit the values right as they are being passed into the function as opposed to creating a new variable. For example, the numbers that make up our x-data are in ‘weeks’ but if we want to scale them up to ‘days’ we merely need to convert the list into an array and then multiply it by 7. This should be done right in the argument of the plot() call instead of defining a new variable:

import matplotlib.pyplot as plt
import numpy as np

week = [
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
]
log_points = [
    3, 6, 7, 10, 13, 16, 19, 20, 23, 26, 29, 32, 35, 38, 41, 41, 44, 44, 44,
    47, 50, 53, 56, 56, 62, 65, 65, 68, 71, 74, 74, 80, 80, 83, 89, 92, 95, 98
]

plt.plot(np.array(week) * 7, log_points, c='#6caddf')
plt.title('Manchester City in the 2018-19 Premier League')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Day')
plt.xlim(7, 266)

plt.show()

The above is better than doing the following if all you want to do is re-scale the axis:

days = np.array(week) * 7
plt.plot(days, log_points, c='#6caddf')

Note that the format of the numbers on the axes can be changed to scientific notation by using the ticklabel_format(<axis>, <style>) function.

1.10.4 Using Log Scale

If you want to use logarithmic scales, take a look at the semilogy(), semilogx() or loglog() function, depending on which axis/axes you want to change:

import matplotlib.pyplot as plt
import numpy as np

# Fake up some data
x = np.linspace(0, 10, 50)
y = np.exp(x)

# Plot
plt.semilogy(x, y)
plt.title('The Exponential Function with Log Scaling')

1.10.5 Rotating Axis Labels

This can be done using the tick_params() function:

plt.plot(week, log_points, c='#6caddf')
plt.title('Manchester City in the 2018-19 Premier League')
plt.ylabel('Log Points')
plt.ylim(0, 100)
plt.xlabel('Week')
plt.xlim(1, 38)
plt.tick_params('x', labelrotation=30)

plt.show()

1.11 Sub-Plots

To create two (or more) completely separate plots in the same figure you will need to create sub-plots:

  • subplot(rcn) will create a sub-plot object where r is the total number of rows of plots you intend to make, c is the number of columns of plots you intend to make and n is the number that this plot will be within the grid of plots. For example, subplot(321) will divide your figure into a grid with 3 rows and 2 columns (ie space for 6 plots) and then create an empty sub-plot for the first (top-left) of these plots. The plots are numbered using ‘reading order’ (left-to-right, top-to-bottom), ie plot 2 will be top-right, plot 3 will be middle-left and so on.
  • In order to create enough space for all of these plots, it’s a good idea to re-size your figure. This topic is discussed on it’s own separate page but, in short, your options are:
    • figure(figsize=(w, h)) to set the width and height of the figure you are currently working on
    • rc('figure', figsize=(w, h)) to set the same figsize parameter as above but for all the figures in your code
  • Because title() creates a title for one individual plot, in order to create a title for the entire figure you need to use suptitle()
  • By default, the layout of the plots in a grid of sub-plots doesn’t use up the available space particularly well. This can be improved by using tight_layout()
import matplotlib.pyplot as plt
import numpy as np
import math

# Create data
x = np.linspace(0, math.tau, 100)

#
# Plot
#
plt.figure(figsize=(12, 5))
plt.suptitle('Trigonometric Functions')
# First sub-plot
plt.subplot(121)
plt.plot(x, np.sin(x))
plt.axhline(0, c='gray', alpha=0.5)
plt.title(r'$sin(\theta)$')
plt.ylabel(r'Amplitude, $A$')
plt.xlabel(r'Angle of Rotation, $\theta$ [radians]')
plt.xlim(0, math.tau)
# Second sub-plot
plt.subplot(122)
plt.plot(x, np.cos(x))
plt.axhline(0, c='gray', alpha=0.5)
plt.title(r'$cos(\theta)$')
plt.ylabel(r'Amplitude, $A$')
plt.xlabel(r'Angle of Rotation, $\theta$ [radians]')
plt.xlim(0, math.tau)
plt.xticks(
    [0, 0.25 * math.tau, 0.5 * math.tau, 0.75 * math.tau, math.tau],
    ['$0$', r'$\frac{1}{4}\tau$', r'$\frac{1}{2}\tau$', r'$\frac{3}{4}\tau$', r'$\tau$']
)
plt.tight_layout()

plt.show()

1.12 Latex and Image Size

See here for more about using Latex formatting in the title and axes’ labels and see here for more about changing the image size.

# Make figures A5 in size
A = 5
plt.rc('figure', figsize=[46.82 * .5**(.5 * A), 33.11 * .5**(.5 * A)])
# Image quality
plt.rc('figure', dpi=141)
# Be able to add Latex
plt.rc('text', usetex=True)
plt.rc('font', family='serif')
plt.rc('text.latex', preamble=r'\usepackage{textgreek}')

# Plot
plt.plot(week, log_points, c='#6caddf')
plt.title(r'How to Include \LaTeX\ in Labels')
plt.ylabel(r'Output, $T$ [\textdegree C]')
plt.ylim(0, 100)
plt.xlabel(r'Input, $t$ [\textmu s]')
plt.xlim(1, 38)
plt.text(20, 30, r'\textAlpha\textBeta\textGamma\textDelta\textEpsilon\textZeta\textEta\textTheta\textIota\textKappa\textLambda\textMu\textNu\textXi\textOmikron\textPi\textRho\textSigma\textTau\textUpsilon\textPhi\textChi\textPsi\textOmega')
plt.text(20, 24, r'\textalpha\textbeta\textgamma\textdelta\textepsilon\textzeta\texteta\texttheta\textiota\textkappa\textlambda\textmu\textmugreek\textnu\textxi\textomikron\textpi\textrho\textsigma\texttau\textupsilon\textphi\textchi\textpsi\textomega')
plt.text(20, 18, r'\textvarsigma\straightphi\scripttheta\straighttheta\straightepsilon')
plt.text(20, 12, r'$$\lim_{n \to \infty} \left(1+\frac{1}{n}\right)^n$$')

1.13 Finished?

Finally, save the plot as a PNG, JPG, PDF or other type of image with savefig() or display it in a pop-up window with show():

plt.savefig('Line Plot.png')

If you are plotting more than one figure in the same Python script use figure() and close() before and after each, respectively, in order to tell Python when one plot ends and the next one starts.

2 One Independent Variable, Two Dependent Variables

With two dependent variables you will often want two y-axes.

2.1 One Data Series

It’s not common to represent one series of data with two dependent variables on a 2D graph, but it can be useful when there is a constant relationship between the dependent variables. For example, if we take the force and pressure exerted on a piston, the relationship between the two (\(P = \frac{F}{A}\)) remains constant because the area of the piston head (\(A\)) doesn’t change. Here’s what the force vs time graph might look like:

import math
import matplotlib.pyplot as plt
import numpy as np

# Fake up some data
np.random.seed(20210319)
time = np.linspace(0, 10, 20)
force = time**2 + np.random.normal(size=20) * 2
area = (math.tau * 0.04**2) / 2

# Plot
plt.plot(time, force)
plt.title('Force vs Time')
plt.ylabel(r'Force, $F$ [N]')
plt.ylim(0, )
plt.xlabel(r'Time, $t$ [s]')
plt.xlim(0, 10)

plt.show()

Now, to add in the pressure, we need another whole set of axes. This can be achieved by ‘twinning’ the current x-axis (because the second y-axis will use the same x-axis as the first) via twinx() to create a new set of axes. This set won’t have any data on it yet, so we need to have calculated the pressure values in order to now plot them. It will also make sense to scale the pressure values by a factor of 1,000 so that they are in kilopascals instead of pascals:

import numpy as np

# Calculate
pressure = [f / area for f in force]

# Plot
plt.plot(time, force)
plt.title('Force and Pressure vs Time')
plt.ylabel(r'Force, $F$ [N]')
plt.ylim(0, )
plt.xlabel(r'Time, $t$ [s]')
plt.xlim(0, 10)
plt.twinx()
plt.plot(time, pressure)
plt.ylabel(r'Pressure, $P$ [kPa]')
plt.ylim(0, )

plt.show()

2.2 Two Data Series

In the previous example, the two axes both related to the same series of data. If, however, you want to plot two different but related series you will need to separate them more clearly:

  • Use different colours for the labels, the markers and the tick labels
    • The tick labels can be edited by accessing them through the yticks() or xticks() function
import numpy as np
import math
import matplotlib.pyplot as plt

# Fake up some data
np.random.seed(20210316)
x = np.linspace(0, 0.4 * math.tau, 20)
y_1 = np.sin(x) + np.random.normal(size=20) * 0.08
y_2 = 5 * np.sin(x * 0.75) + np.random.normal(size=20) * 0.08

#
# Plot
#
plt.title('Measurements vs Time')
plt.xlabel(r'Time, $t$ [s]')
# First dependent variable
plt.plot(x, y_1, c='b', marker='x')
plt.ylabel(r'Measurement 1, $m_1$ [m]', color='b')
plt.ylim(0, )
plt.yticks(c='b')
plt.xlim(0, )
# Create a second set of axes, twinned with the first x-axis
plt.twinx()
# Second dependent variable
plt.plot(x, y_2, c='r', marker='x')
plt.ylabel(r'Measurement 2, $m_2$ [m]', color='r')
plt.ylim(0, )
plt.yticks(c='r')

plt.show()

⇦ Back