4.2 畫圖:plot 與 plot3d#
本節目標#
- 會用
plot()畫符號運算式並控制視窗(xlim/ylim) - 會多函數疊圖、
plot_parametric參數曲線、plot3d曲面 - 會把 SymPy 與 Matplotlib 混用
- 動手實驗:畫出第 3 章方程的圖形理解根
畫圖是理解函數的眼睛#
代數給精確答案,圖形給直覺。SymPy 內建繪圖(底層是 Matplotlib),介面是「符號優先」:
import sympy as sp
x = sp.Symbol('x')
sp.plot(x**2 - 4*x + 3, (x, -2, 6))
plot() 基本用法與視窗控制#
p = sp.plot(
x**2 - 4*x + 3, (x, -2, 6),
title="$f(x) = x^2 - 4x + 3$",
xlabel="x", ylabel="y",
ylim=(-3, 10), # y 軸範圍(xlim 同理)
line_color="steelblue",
show=False,
)
p.show()
| 參數 | 作用 |
|---|---|
(x, a, b) | 自變數範圍 |
xlim, ylim | 顯示視窗範圍 |
title / xlabel / ylabel | 標題與軸標籤 |
line_color, show=False | 顏色;先不顯示以便後製 |
xlim/ylim 是探索關鍵:同一函數在不同視窗下樣貌完全不同——「視窗決定敘事」。畫好的物件可後製:p[0].line_color = "red"、p.legend = True。
多函數疊圖#
多個運算式放進同一個 plot 就會疊在一起,最適合回答「誰比較大、在哪相交」:
p = sp.plot(x**2, x + 2, (x, -3, 3), legend=True, show=False)
p[0].line_color = "blue"; p[0].label = "$x^2$"
p[1].line_color = "red"; p[1].label = "$x + 2$"
p.show()
print(sp.solve(sp.Eq(x**2, x + 2), x)) # [-1, 2] ← 與交點一致
參數曲線:plot_parametric#
\(x\) 、 \(y\) 都是參數 \(t\) 的函數時:
t = sp.Symbol('t')
sp.plot_parametric(sp.cos(t), sp.sin(t), (t, 0, 2*sp.pi)) # 圓
sp.plot_parametric(sp.sin(3*t), sp.sin(4*t),
(t, 0, 2*sp.pi), title="Lissajous") # 利薩如曲線
3D 曲面:plot3d#
from sympy.plotting import plot3d
x, y = sp.symbols('x y')
plot3d(x**2 + y**2, (x, -2, 2), (y, -2, 2),
title="$z = x^2 + y^2$(碗形)")
plot3d(x**2 - y**2, (x, -2, 2), (y, -2, 2),
title="$z = x^2 - y^2$(馬鞍面)")
\(z = x^2 + y^2\) 像碗、全方位上升; \(z = x^2 - y^2\) 沿 \(x\) 升沿 \(y\) 降,是馬鞍面——這是第 5 章極值與鞍點的視覺基礎。3D 圖可拖曳旋轉,多轉幾個角度觀察。
與 Matplotlib 混用#
最佳工作流:SymPy 定義 → lambdify 求值 → Matplotlib 畫圖:
import numpy as np
import matplotlib.pyplot as plt
f = sp.lambdify(x, sp.sin(x)/x, 'numpy')
g = sp.lambdify(x, sp.cos(x), 'numpy')
xs = np.linspace(-10, 10, 500)
fig, ax = plt.subplots()
ax.plot(xs, f(xs), label="$\\sin x / x$")
ax.plot(xs, g(xs), "--", label="$\\cos x$")
ax.legend(); plt.show()
# 存檔:plt.savefig("fig.png", dpi=150)
動手實驗#
畫出第 3 章方程的圖形理解根:方程式 \(f(x) = 0\) 的根就是圖形與 \(x\) 軸交點。
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
x = sp.Symbol('x')
problems = [
("$x^2 - 2x - 3 = 0$", x**2 - 2*x - 3),
("$x^3 - 3x + 1 = 0$", x**3 - 3*x + 1),
("$\\sin(x) = x/2$", sp.sin(x) - x/2),
("$e^{-x} = x$", sp.exp(-x) - x),
]
fig, axes = plt.subplots(2, 2, figsize=(10, 7))
for ax, (title, expr) in zip(axes.flat, problems):
roots = []
for r in sp.solve(sp.Eq(expr, 0), x):
if r.is_real:
roots.append(float(r))
if not roots: # 無公式解 → 數值解
try:
roots = [float(sp.nsolve(expr, x, 0.5))]
except Exception:
pass
a = min(roots) - 2 if roots else -5
b = max(roots) + 2 if roots else 5
xs = np.linspace(a, b, 400)
ax.plot(xs, sp.lambdify(x, expr, 'numpy')(xs))
ax.axhline(0, color="gray", linewidth=0.5)
for r in roots:
ax.plot(r, 0, "ro")
ax.set_title(title); ax.grid(alpha=0.3)
plt.tight_layout(); plt.show()
觀察重點:
- \(x^2 - 2x - 3\) 交 \(y=0\) 於 \(x=-1, 3\) ,與
solve一致。 - \(x^3 - 3x + 1\) 有三個實根,圖形一眼看出約在 \(-2, 0.35, 1.5\) 。
- \(\sin x = x/2\) 的非零根(約 \(\pm 1.895\) )沒有公式解,只能
nsolve。 - \(e^{-x} = x\) 因單調性交點唯一(約 \(0.567\) )。
進一步挑戰:疊畫 \(x^2-4x+3\) 與其導數 \(2x-4\) ,看最低點處導數為 0;用 plot3d 畫 \(z = xy\) 觀察馬鞍面;畫 \(x = t^2-1,\ y = t^3-t\) 找自交點。
小結與練習#
plot(expr, (x, a, b))直接畫符號式,xlim/ylim控制視窗、legend加圖例- 疊圖讓「解方程」變「找交點」,根的個數與位置一目了然
plot_parametric畫參數曲線,plot3d畫曲面(碗形與馬鞍面)- 最佳工作流:SymPy →
lambdify→ NumPy → Matplotlib
練習:
- 畫 \(y = |x|\) (
sp.Abs),說明為何 \(x=0\) 不可微。 - 疊畫 \(\sin x\) 與泰勒逼近 \(x - x^3/6 + x^5/120\) ,觀察逼近何處失效。
- 用
plot3d畫 \(z = e^{-(x^2+y^2)}\) ,山頂在哪裡? - 對 \(x = \cos(x)\) 先畫圖估根,再用
nsolve求精確值比較誤差。