Mathematical Functions¶
Create publication-quality mathematical function plots.
Mental Model
Plotting a math function means sampling it at many x-values and connecting the dots. Use np.linspace for smooth curves (100-1000 points), LaTeX labels for professional notation, and spine repositioning to place axes at the origin. The recipe is always: define x, compute y = f(x), then ax.plot(x, y).
A function plot is a geometric object — it reveals structure that formulas alone cannot convey: shape (convex, concave), growth rate (polynomial, exponential), curvature (how fast the slope changes), and critical points (zeros, extrema, inflections). Plotting \(f\), \(f'\), and \(f''\) together shows how these features are connected: \(f' = 0\) marks extrema, \(f'' = 0\) marks inflection points.
Basic Function Plot¶
```python import matplotlib.pyplot as plt import numpy as np
x = np.linspace(-2np.pi, 2np.pi, 100) y = np.sin(x)
fig, ax = plt.subplots(figsize=(10, 4)) ax.plot(x, y, 'b-', linewidth=2) ax.set_title(r'\(y = \sin(x)\)') ax.set_xlabel('\(x\)') ax.set_ylabel('\(y\)') ax.grid(True, alpha=0.3) plt.show() ```
Centered Axes Style¶
Create math-textbook style plots:
```python import matplotlib.pyplot as plt import numpy as np
x = np.linspace(-2np.pi, 2np.pi, 100) y = np.sin(x)
fig, ax = plt.subplots(figsize=(10, 4)) ax.plot(x, y, 'b-', linewidth=2)
Configure ticks¶
ax.set_yticks([-1, 0, 1]) ax.set_xticks([-2np.pi, -np.pi, 0, np.pi, 2np.pi]) ax.set_xticklabels([r'\(-2\pi\)', r'\(-\pi\)', '0', r'\(\pi\)', r'\(2\pi\)'])
Minor ticks¶
ax.set_xticks(np.linspace(-2np.pi, 2np.pi, 17), minor=True)
Move spines to origin¶
ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax.spines['bottom'].set_position('zero') ax.spines['left'].set_position('zero')
ax.set_title(r'\(y = \sin(x)\)', pad=20) plt.show() ```
Riemann Sum Visualization¶
A Riemann sum approximates the integral \(\int_a^b f(x)\,dx\) by summing rectangles. The choice of evaluation point within each rectangle matters:
- Left Riemann sum: evaluates \(f\) at the left edge of each sub-interval — underestimates for increasing functions
- Right Riemann sum: evaluates \(f\) at the right edge — overestimates for increasing functions
- Midpoint rule: evaluates at the center — typically more accurate for the same number of rectangles
As the number of rectangles \(n \to \infty\), all three converge to the true integral (for any Riemann-integrable function). The rate of convergence is \(O(1/n)\) for left/right and \(O(1/n^2)\) for midpoint.
```python import matplotlib.pyplot as plt import numpy as np
f = lambda x: x3 - x2 + x + 1
x = np.linspace(0, np.pi, 100) y = f(x)
n_grid = 20 x_grid = np.linspace(0, np.pi, n_grid + 1) y_grid = f(x_grid)
def draw_box(x0, x1, y0, ax, color="b"): ax.plot([x0, x1], [0, 0], color=color) ax.plot([x0, x1], [y0, y0], color=color) ax.plot([x0, x0], [0, y0], color=color) ax.plot([x1, x1], [0, y0], color=color)
fig, ax = plt.subplots(figsize=(12, 4)) ax.plot(x, y, 'r-', linewidth=2, label=r'\(f(x) = x^3 - x^2 + x + 1\)')
ax.spines["top"].set_visible(False) ax.spines["right"].set_visible(False) ax.spines["bottom"].set_position("zero") ax.spines["left"].set_position("zero")
integral_val = 0 for x0, x1, y0 in zip(x_grid[:-1], x_grid[1:], y_grid[:-1]): draw_box(x0, x1, y0, ax) integral_val += (x1 - x0) * y0
ax.set_title(f"Riemann Sum Approximation: {integral_val:.2f}") ax.legend() plt.show() ```
Star Polygon (Procedural)¶
```python import matplotlib.pyplot as plt import numpy as np
n = 10 skip = 3
thetas = np.linspace(0, 2*np.pi, n, endpoint=False) + np.pi/2 d_theta = thetas[1] - thetas[0]
def draw_line(theta, skip, ax, color="b"): x0 = np.cos(theta) y0 = np.sin(theta) x1 = np.cos(theta + d_theta * skip) y1 = np.sin(theta + d_theta * skip) ax.plot([x0, x1], [y0, y1], color=color)
fig, ax = plt.subplots(figsize=(4, 4)) for theta in thetas: draw_line(theta, skip, ax) ax.set_aspect('equal') ax.axis('off') ax.set_title(f'{n}-point star (skip={skip})') plt.show() ```
Star Polygon (Object-Oriented)¶
```python import matplotlib.pyplot as plt import numpy as np
class Star: def init(self, n, skip): self.n = n self.skip = skip self.thetas = np.linspace(0, 2*np.pi, n, endpoint=False) + np.pi/2 self.d_theta = self.thetas[1] - self.thetas[0]
def draw_line(self, theta, ax, color="b"):
x0 = np.cos(theta)
y0 = np.sin(theta)
x1 = np.cos(theta + self.d_theta * self.skip)
y1 = np.sin(theta + self.d_theta * self.skip)
ax.plot([x0, x1], [y0, y1], color=color)
def draw_star(self):
fig, ax = plt.subplots(figsize=(4, 4))
for theta in self.thetas:
self.draw_line(theta, ax)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title(f'{self.n}-point star (skip={self.skip})')
plt.show()
Create different stars¶
Star(10, 2).draw_star() Star(10, 3).draw_star() Star(12, 5).draw_star() ```
Derivative Visualization¶
```python import matplotlib.pyplot as plt import numpy as np
x = np.linspace(-5, 2, 100) y1 = x3 + 5*x2 + 10 # f(x) y2 = 3x2 + 10x # f'(x) y3 = 6*x + 10 # f''(x)
Critical points (where f'(x) = 0)¶
x_0 = 0 x_1 = -10/3
Function values at critical points¶
y1_0 = x_03 + 5*x_02 + 10 y1_1 = x_13 + 5*x_12 + 10
fig, ax = plt.subplots(figsize=(10, 6)) ax.plot(x, y1, color="blue", label=r"\(f(x) = x^3 + 5x^2 + 10\)", lw=2) ax.plot(x, y2, color="red", label=r"\(f'(x) = 3x^2 + 10x\)", lw=2) ax.plot(x, y3, color="green", label=r"\(f''(x) = 6x + 10\)", lw=2)
Mark critical points¶
ax.scatter([x_0, x_1], [y1_0, y1_1], color='k', s=50, zorder=5) ax.plot([x_0, x_0], [y1_0, 0], color='k', lw=1, ls='--') ax.plot([x_1, x_1], [y1_1, 0], color='k', lw=1, ls='--')
ax.axhline(0, color='k', lw=1) ax.set_xlabel("\(x\)") ax.set_ylabel("\(y\)") ax.set_xticks([-4, -2, 0, 2]) ax.set_yticks([-10, 0, 10, 20, 30])
ax.spines['bottom'].set_position(('data', -15)) ax.spines['left'].set_bounds(low=-15, high=41) ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False)
ax.legend(ncol=3, loc='upper left', frameon=False) ax.set_title('Function and Its Derivatives')
plt.show() ```
Multiple Functions Grid¶
```python import matplotlib.pyplot as plt import numpy as np
x = np.linspace(0.001, 1, 100) functions = [ (x**2, r'\(x^2\)'), (np.sin(x), r'\(\sin(x)\)'), (np.exp(x), r'\(e^x\)'), (np.log(x), r'\(\ln(x)\)'), (np.sin(x)/np.exp(x), r'\(\frac{\sin(x)}{e^x}\)'), (np.log(x)/np.exp(x), r'\(\frac{\ln(x)}{e^x}\)') ]
fig, axes = plt.subplots(2, 3, figsize=(12, 6))
for ax, (y, title) in zip(axes.flat, functions): ax.plot(x, y, 'b-', linewidth=2) ax.set_title(title, fontsize=14) ax.grid(True, alpha=0.3)
plt.tight_layout() plt.show() ```
Key Takeaways¶
- Use centered spines for textbook-style plots
- LaTeX notation in
$...$for mathematical labels set_aspect('equal')for geometric figures- Visualize derivatives and critical points
- Grid layouts compare multiple functions
Exercises¶
Exercise 1. Write code that plots \(y = \cos(x)\) from \(-2\pi\) to \(2\pi\) using centered spines (spines at the origin). Set x-tick labels to show \(-2\pi\), \(-\pi\), \(0\), \(\pi\), \(2\pi\) using LaTeX formatting.
Solution to Exercise 1
```python import matplotlib.pyplot as plt import numpy as np
x = np.linspace(-2 * np.pi, 2 * np.pi, 200) y = np.cos(x)
fig, ax = plt.subplots(figsize=(10, 4)) ax.plot(x, y, 'b-', linewidth=2)
ax.set_xticks([-2 * np.pi, -np.pi, 0, np.pi, 2 * np.pi]) ax.set_xticklabels([r'\(-2\pi\)', r'\(-\pi\)', '0', r'\(\pi\)', r'\(2\pi\)']) ax.set_yticks([-1, 0, 1])
ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax.spines['bottom'].set_position('zero') ax.spines['left'].set_position('zero')
ax.set_title(r'\(y = \cos(x)\)', pad=20) plt.show() ```
Exercise 2. Create a 2x2 subplot grid showing four functions: \(x^2\), \(\sin(x)\), \(e^x\), and \(\ln(x)\) (for \(x > 0\)). Use a shared range where appropriate and add LaTeX titles for each subplot.
Solution to Exercise 2
```python import matplotlib.pyplot as plt import numpy as np
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
x1 = np.linspace(-3, 3, 200) axes[0, 0].plot(x1, x1**2, 'b-', lw=2) axes[0, 0].set_title(r'\(y = x^2\)') axes[0, 0].grid(True, alpha=0.3)
x2 = np.linspace(-2 * np.pi, 2 * np.pi, 200) axes[0, 1].plot(x2, np.sin(x2), 'r-', lw=2) axes[0, 1].set_title(r'\(y = \sin(x)\)') axes[0, 1].grid(True, alpha=0.3)
x3 = np.linspace(-2, 3, 200) axes[1, 0].plot(x3, np.exp(x3), 'g-', lw=2) axes[1, 0].set_title(r'\(y = e^x\)') axes[1, 0].grid(True, alpha=0.3)
x4 = np.linspace(0.01, 5, 200) axes[1, 1].plot(x4, np.log(x4), 'm-', lw=2) axes[1, 1].set_title(r'\(y = \ln(x)\)') axes[1, 1].grid(True, alpha=0.3)
plt.tight_layout() plt.show() ```
Exercise 3. Write code that visualizes a left Riemann sum approximation for \(f(x) = \sin(x)\) on \([0, \pi]\) using 15 rectangles. Plot the function curve in red and draw the rectangles in blue.
Solution to Exercise 3
```python import matplotlib.pyplot as plt import numpy as np
f = np.sin a, b = 0, np.pi n_rect = 15
x_fine = np.linspace(a, b, 200) x_grid = np.linspace(a, b, n_rect + 1) dx = (b - a) / n_rect
fig, ax = plt.subplots(figsize=(10, 5)) ax.plot(x_fine, f(x_fine), 'r-', linewidth=2, label=r'\(f(x) = \sin(x)\)')
approx = 0 for i in range(n_rect): x0 = x_grid[i] height = f(x0) rect = plt.Rectangle((x0, 0), dx, height, edgecolor='blue', facecolor='lightblue', alpha=0.6) ax.add_patch(rect) approx += height * dx
ax.set_xlabel('\(x\)') ax.set_ylabel('\(y\)') ax.set_title(f'Left Riemann Sum ({n_rect} rectangles), Approx = {approx:.4f}') ax.legend() plt.show() ```
Exercise 4. Create a plot showing a function \(f(x) = x^3 - 3x\) and its derivative \(f'(x) = 3x^2 - 3\). Mark the critical points where \(f'(x) = 0\) with black dots and add vertical dashed lines from those points to the x-axis.
Solution to Exercise 4
```python import matplotlib.pyplot as plt import numpy as np
x = np.linspace(-3, 3, 200) f = x3 - 3 * x f_prime = 3 * x2 - 3
Critical points: 3x^2 - 3 = 0 => x = +/-1¶
cp_x = np.array([-1, 1]) cp_y = cp_x**3 - 3 * cp_x
fig, ax = plt.subplots(figsize=(10, 6)) ax.plot(x, f, 'b-', lw=2, label=r"\(f(x) = x^3 - 3x\)") ax.plot(x, f_prime, 'r--', lw=2, label=r"\(f'(x) = 3x^2 - 3\)")
ax.scatter(cp_x, cp_y, color='black', s=60, zorder=5) for cx, cy in zip(cp_x, cp_y): ax.plot([cx, cx], [cy, 0], 'k--', lw=1)
ax.axhline(0, color='gray', lw=0.5) ax.set_xlabel('\(x\)') ax.set_ylabel('\(y\)') ax.set_title('Function and Derivative with Critical Points') ax.legend() ax.grid(True, alpha=0.3) plt.show() ```