7  Graphing Functions

Graphs are fundamental tools for inspecting and communicating with data.

We begin by importing the pyplot plotting library along with numpy.

import matplotlib.pyplot as plt
import numpy as np

7.1 Graphing Functions

To graph a function, we need a set of \(x\) input values with corresponding \(y\) output values. We can generate a linearly spaced sequence with the np.linspace function. Here is how we might graph \(\sin(x)\) from \(x=0\) to \(x=10\):

# Data
x = np.linspace(0, 10, 100)
y = np.sin(x)

# Create and display the plot
plt.plot(x, y)
plt.show() 

We can turn on plt.grid(), or if we just want \(x\) and \(y\) axes, use:

# Data
x = np.linspace(0, 10, 100)
y = np.sin(x)

# Create and display the plot
plt.axhline(0)
plt.axvline(0)
plt.plot(x, y)
plt.show() 

Something interesting happens when we use fewer \(x\) values. Here is the same function with only 8 points:

# Data
x = np.linspace(0, 10, 8)
y = np.sin(x)

# Create and display the plot
plt.plot(x, y)
plt.show() 

The plt.plot function plots the points given and then connecting those points by lines. That means the points are accurate representations of the function but the lines between the points are approximations.

7.2 Tangent

Tangent is a particularly instructive example. When we graph \(\tan(x)\) it might look like this:

x = np.linspace(-2*np.pi, 2*np.pi, 500)
y = np.tan(x)

plt.plot(x, y)

Which leads to some observations:

  1. The infinite discontinuities don’t actually go to infinity here.
  2. Even though they don’t go to infinity, they go far, which dominates the window in the \(y\) direction
  3. The dicontinuities are connected when they shouldn’t be.

For observation 1., it is likely that we aren’t evaluating \(\tan\) at exactly \(\frac{\pi}{2}\). For observation 2. we can adjust our window using np.xlim and np.ylim. Let’s graph \(\tan\) again, but this time constrain the window in the y direction:

x = np.linspace(-2*np.pi, 2*np.pi, 500)
y = np.tan(x)

plt.plot(x, y)
plt.ylim([-10,10])

This is nice, but to address observation 3., those infinite discontinuities are still connected. Well, that might be okay if we understand what we are looking at. Alternatively, we could avoid connecting the lines with a scatter plot and lots of markers:

x = np.linspace(-2*np.pi, 2*np.pi, 10000)
y = np.tan(x)

plt.plot(x, y, '.', markersize=1)
plt.ylim([-10,10])

7.3 Python Functions

Python functions can be incredibly complex with many lines of code. They can take any number of inputs and return lists of objects or nothing at all. Here, we will look at the most simple case of functions that look like mathematical functions, which an input \(x\) and returns an output in terms of that input.

Python functions are defined using the def keyword. The body of a function is indented. Parentheses wrap input variables and we use the return keyword to return an output. Consider the following functions:

def f(x):
    return x**2

def g(x):
    return x**2 - 5*x + 2

These two functions correspond, respectively, to the functions: \[f(x)=x^{2}\] \[g(x)=x^2-5x+2\] While do not need to define functions this way to graph them, it makes function composition and operations on functions much nicer. For example, now that we have \(f\) and \(g\) defined, we can calculate and graph expressions like:

x = np.linspace(-1,5,100)

plt.plot( x, f(x), label='f')
plt.plot( x, g(x), label='g')
plt.plot( x, f(g(x)), label='f(g)')
plt.plot( x, 2*f(x) - 3*g(x), label='2f-3g')
plt.legend() 

7.4 Examples

Below are several example graphs.

x = np.linspace(-3,3,100)
y = x**2 - 4

plt.grid()
plt.axhline(0, color='black')
plt.axvline(0, color='black')
plt.plot(x,y, linewidth=3)

x = np.linspace(0,20,100)
y = x + np.sin(x)

plt.axhline(0, color='black')
plt.axvline(0, color='black')
plt.plot(x,y, color='orange')

x = np.linspace(0,10,100)
y = np.exp(-x)

plt.axhline(0, color='black')
plt.axvline(0, color='black')
plt.plot(x,y)

x = np.linspace(0,2,100)
y1 = np.exp(-x)
y2 = np.sin(x) 
y3 = np.cos(x) 

plt.axhline(0, color='black')
plt.axvline(0, color='black')
plt.plot(x,y1)
plt.plot(x,y2)
plt.plot(x,y3)

r = np.arange(0, 2, 0.01)
theta = 2 * np.pi * r

plt.subplot(111, projection='polar')
plt.plot(theta, r)                        

7.5 Graphing Summary

A function graphing template might look something like this:

import numpy as np 
import matplotlib.pyplot as plt 

# x,y data 
x = np.linspace(-10,10, 500)
y = x * np.sin(x)

# Turn on x-y axes 
plt.axhline(0, color='black')
plt.axvline(0, color='black')

# Plot 
plt.plot(x, y)

# Window 
plt.xlim([-10, 10])
plt.ylim([-10, 10])

# Labels 
plt.xlabel('x')
plt.ylabel('y') 
plt.title('x sin(x)')

plt.show() 

Exercises

  1. Plot the following functions over the interval \(-10 \leq x \leq 10\).

  2. The function \(f(x)=\frac{1}{x}\) is undefined at \(x=0\). When we graph this function from \(-1\) to \(1\), we don’t always get an error. For example,

    x = np.linspace(-1,1,50)
    y = 1/x 

    evaluates with no warning, while

    x = np.linspace(-1,1,51)
    y = 1/x 

    will give the warning:

    <python-input-10>:1: RuntimeWarning: divide by zero encountered in divide

    Explain why undefined functions might sometimes run into warnings and sometimes not.

  3. Graph the functions \(\sin\), \(\cos\), and \(\tan\) on the same plot. Be sure that your plot has reasonable bounds so the functions can be clearly viewed (don’t let the vertical asymptotes of \(\tan\) dominate the vertical zoom).

  4. The function \[f(x)=\sin\left(\frac{1}{x}\right)\] has some interesting behavior around \(x=0\). Create graphs of \(f(x)\) on the interval \([-1,1]\) using 10, 100, 1000, 10000 points. How many points is enough?

  5. Recreate the following graphs as closely as you can:

Graph Graph Graph Graph

  1. The solution to \[\cos(x) = x\] cannot be found algebraically. However, we can search for an approximate solution by inspecting the graph where \(y=\cos(x)\) intersects \(y=x\). Plot these two functions and use plt.xlim and plt.ylim to “zoom” on any points of intersection to estimate their \((x,y)\) coordinate.