跳轉到

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()

觀察重點:

  1. \(x^2 - 2x - 3\) 交 \(y=0\) 於 \(x=-1, 3\) ,與 solve 一致。
  2. \(x^3 - 3x + 1\) 有三個實根,圖形一眼看出約在 \(-2, 0.35, 1.5\) 。
  3. \(\sin x = x/2\) 的非零根(約 \(\pm 1.895\) )沒有公式解,只能 nsolve。
  4. \(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

練習:

  1. 畫 \(y = |x|\) (sp.Abs),說明為何 \(x=0\) 不可微。
  2. 疊畫 \(\sin x\) 與泰勒逼近 \(x - x^3/6 + x^5/120\) ,觀察逼近何處失效。
  3. 用 plot3d 畫 \(z = e^{-(x^2+y^2)}\) ,山頂在哪裡?
  4. 對 \(x = \cos(x)\) 先畫圖估根,再用 nsolve 求精確值比較誤差。