Monday, September 28th, 2026¶
Last week, we started using matplotlib.pyplot to plot data. We were considering a function y(t,y0,g,v0) that returned the height at time t of an object in freefall with initial height y0, initial velocity v0, and constant of acceleration g.
def y(t,y0,v0=0,g=-9.8):
return (g/2)*t**2 + v0*t + y0
To get started with plotting, we import matplotlib.pyplot and typically assign it the name plt.
import matplotlib.pyplot as plt
We finished last class by plotting two curves: One showing the height vs time of an object in freefall from rest at an initial height of $1000$m on Earth, and the other the same but for an object on Mars.
y0 = 1000 # Initial height
g_Earth = -9.8 # Gravitational constant on Earth
g_Mars = -3.7 # Gravitational constant on Mars
t_list = [t for t in range(17)]
y_Earth_list = [y(t, y0, g=g_Earth) for t in t_list]
y_Mars_list = [y(t, y0, g=g_Mars) for t in t_list]
plt.plot(t_list, y_Earth_list)
plt.plot(t_list, y_Mars_list)
[<matplotlib.lines.Line2D at 0x1893d29e0d0>]
Customizing matpotlib plots¶
By default, the plot function will connect the supplied data points with a polygonal line, with the color selected automatically. We can include additional keyword arguments to change this behavior.
Changing the color¶
For example, the keyword argument color can be used to manually set the color. There are many color characters available:
'r': red'g': green'b': blue'k': black'm': magenta'c': cyan'y': yellow'C0','C1', ...'C9': a sequence of colors thatpyplotautomatically uses when no color is supplied
We can also supply certain color names (see Matplotlib documentation), or an RGB triple of integers (we will discuss this later in the course).
Exercise: Replicate the previous plot, then modify the code so that the path of the object on Earth is plotted in blue and the path of the object on Mars is plotted in red.
plt.plot(t_list, y_Earth_list, color='b')
plt.plot(t_list, y_Mars_list, color='r')
[<matplotlib.lines.Line2D at 0x1893db3bc50>]
Changing the marker style¶
The keyword argument marker can be used to change the marker style. Here are some of the available styles:
'.': point',': pixel'o': circle'^': triangle'*': star's': square'+': plus'x': x
More can be found in the Matplotlib documentation.
Exercise: Replicate the previous plot, then modify the code so that the Earth path uses triangle markers and the Mars path uses square markers.
plt.plot(t_list, y_Earth_list, color='b', marker='^')
plt.plot(t_list, y_Mars_list, color='r', marker='s')
[<matplotlib.lines.Line2D at 0x1893ebc4410>]
Changing the line style¶
The keyword argument linestyle can be used to change the line style. Here are some of the available styles:
'-'or'solid': solid line'--'or'dashed': dashed line':'or'dotted': dotted line'-.'or'dashdot': alternating dots and dashes''or'None': no line
More can be found in the Matplotlib documentation.
Exercise: Replicate the previous plot, then modify the code so that the Earth path uses a dashed line and the Mars path uses a dotted line.
plt.plot(t_list, y_Earth_list, color='b', marker='^', linestyle='--')
plt.plot(t_list, y_Mars_list, color='r', marker='s', linestyle=':')
[<matplotlib.lines.Line2D at 0x1893ec58190>]
Using the fmt string short-hand¶
When calling plt.plot, we can include a string after our $x$- and $y$-values with color, marker, and line configuration options. For example, the calling plt.plot(x_list, y_list, 'r*--') tells plt.plot to plot in red with stars for markers and dashed lines.
Exercise: Replicate the previous plot using the fmt string instead of the color, marker, and linestyle keyword arguments.
plt.plot(t_list, y_Earth_list, 'b^--')
plt.plot(t_list, y_Mars_list, 'rs:')
[<matplotlib.lines.Line2D at 0x1894501f750>]
Labeling plots¶
When graphing data, we should (almost) always include:
- A title, which can be added using the
titlefunction. - Axis labels, which can be added using the
xlabelandylabelfunctions.
When plotting several curves in a single figure, we should also label the curves and include a legend.
When calling the plot function, we can use the label keyword argument to give a label to the data being plotted.
We can then use the legend function to add a legend to the figure.
Note: Titles and labels can include LaTeX.
Exercise: Replicate the previous plot and add appropriate labels.
plt.plot(t_list, y_Earth_list, 'b^--', label='Earth')
plt.plot(t_list, y_Mars_list, 'rs:', label='Mars')
plt.xlabel('Time $t$ (in seconds)')
plt.ylabel('Height $y(t)$ (in meters)')
plt.title('Objects in free-fall')
plt.legend()
<matplotlib.legend.Legend at 0x189442d6cf0>
Further tweaks: axis limits, grid lines¶
We can use plt.grid() to add grid lines to the interior of the plot.
plt.plot(t_list, y_Earth_list, 'b^--', label='Earth')
plt.plot(t_list, y_Mars_list, 'rs:', label='Mars')
plt.xlabel('Time $t$ (in seconds)')
plt.ylabel('Height $y(t)$ (in meters)')
plt.title('Objects in free-fall')
plt.legend()
plt.grid()
We can change the horizontal and vertical limits using the plt.xlim and plt.ylim function.
Exercise: Modify the horizontal and vertical limits to approximate how long it takes for the object to hit the ground (i.e. reach $y(t)=0$) on Earth.
plt.plot(t_list, y_Earth_list, 'b^--', label='Earth')
plt.plot(t_list, y_Mars_list, 'rs:', label='Mars')
plt.xlabel('Time $t$ (in seconds)')
plt.ylabel('Height $y(t)$ (in meters)')
plt.title('Objects in free-fall')
plt.legend()
plt.grid()
plt.xlim(14,14.5)
plt.ylim(-25,25)
(-25.0, 25.0)
Generating a list of equally spaced data points¶
In the plots above, we generated our list of $t$ values by selecting only integer values in a given range. Suppose that we want to evaluate the function $y(t)$ on a more densely-packed list of $t$-values. Can we come up with a formulaic method for constructing such a list of $t$-values to be plugged in?
To do this, we can divide an interval $[a,b]$ of $t$ values up into $N$ equally spaced sub-intervals. In total, there will be $N+1$ points that will serve as the endpoints of these $N$ sub-intervals. That is, we have $$a = t_0 < t_1 < t_2 < \dots < t_N = b,$$ where each $t_i$ is an endpoint of one of the sub-intervals and the sub-interval width $\Delta t$ between $t_i$ and $t_{i+1}$ is constant.
Given this setup, what is the width $\Delta t$ of each sub-interval, and what are each of the endpoints $t_i$ for $i = 0, 1, 2, \dots, N$?
a = 0
b = 16
N = 1000
dt = (b - a)/N
t_list = []
for i in range(N+1):
t_list.append(a + i*dt)
a = 0
b = 16
N = 1000
dt = (b - a)/N
t_list = [(a + i*dt) for i in range(N+1)]
print(t_list[:10])
[0.0, 0.016, 0.032, 0.048, 0.064, 0.08, 0.096, 0.112, 0.128, 0.14400000000000002]
Exercise: Modify your code above to generate a list of $1000$ equally spaced $t$-values between $t=0$ and $t=16$. Then plot the trajectories on Earth and Mars for an object starting at an initial height of $1000$m with an initial velocity of $20$ m/s.
y0 = 1000
v0 = 20
y_Earth_list = [y(t, y0=y0, v0=v0, g=g_Earth) for t in t_list]
y_Mars_list = [y(t, y0=y0, v0=v0, g=g_Mars) for t in t_list]
plt.plot(t_list, y_Earth_list, 'b--', label='Earth')
plt.plot(t_list, y_Mars_list, 'r:', label='Mars')
plt.xlabel('Time $t$ (in seconds)')
plt.ylabel('Height $y(t)$ (in meters)')
plt.title('Objects in free-fall')
plt.legend()
plt.grid()
It is not hard to imagine that this is something that we will want to do very often (e.g. anytime that we are trying to plot a continuous function). We will soon see a much easier way to accomplish this same goal.
The second project deals with exploring triples of integers known as Pythagorean triples (see project page for details). We already have all of the Python tools necessary to find and explore these triples, and we will continue discussing using Matplotlib to visualize them.
One of the first tasks that we will need to tackle is to identify when we have a Pythagorean triple. To do so, it will be helpful if we can identify whether or not a given integer $n$ is a perfect square. That is, we want to determine if $n = m^2$ for some integer $m$.
Exercise: Write a function is_square that takes in an integer n and returns True if n is a perfect square and False otherwise.
25**(.5)
5.0
from math import sqrt
sqrt(25)
5.0
def is_square(n):
sqrt_n = sqrt(n)
int_sqrt_n = int(sqrt_n)
if sqrt_n == int_sqrt_n:
return True
else:
return False
def is_square(n):
sqrt_n = sqrt(n)
m = round(sqrt_n)
if m**2 == n:
return True
else:
return False
Exercise: Write a function is_ptriple that takes in a triple of integers $(a,b,c)$ and returns True if the triple is a Pythagorean triple, and False otherwise.
Exercise: Write a function is_pdouble that takes in a double of integers $(a,b)$ and returns True if the double is a Pythagorean double, and False otherwise.
Exercise: Generate all Pythagorean triples with $1 \leq a,b \leq 50$ and create a figure that plots $a$ versus $b$. You will need to generate separate lists that contain just the $a$ parts and just the $b$ parts of each Pythagorean triple.
ptriples = [[3, 4, 5],
[4, 3, 5],
[5, 12, 13],
[6, 8, 10],
[8, 6, 10],
[8, 15, 17],
[9, 12, 15],
[12, 5, 13],
[12, 9, 15],
[12, 16, 20],
[15, 8, 17],
[15, 20, 25],
[16, 12, 20],
[20, 15, 25]]
a_list = [ptriple[0] for ptriple in ptriples]
b_list = [ptriple[1] for ptriple in ptriples]
plt.plot(a_list, b_list, 'o')
plt.xlabel('$a$')
plt.ylabel('$b$')
plt.title('Pythagorean doubles')
Text(0.5, 1.0, 'Pythagorean doubles')