python 可視化函數 2

2021-02-27
Project

前言

延續上一篇
昨天在研究牛頓法、擬牛頓法、梯度下降法,在學著將它們的迭代過程畫出來的過程學到了可視化函數的新東西,留點紀錄。

主體

等高線圖


需要用到contour這個函數,先來最簡單的

$sin(x) \times y^{\frac{2}{3}}$:

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import numpy as np
import matplotlib.pyplot as plt
import math

# 目標函數
f = lambda x, y: np.sin(x) * np.power(y ** 2, 1./3.)

# 產生數據點
X = np.linspace(-3, 3, 256)
Y = np.linspace(-3, 3, 256)

X, Y = np.meshgrid(X, Y)
Z = f(X, Y)

# x, y 標籤
plt.xlabel("x")
plt.ylabel("y")

# 等高線圖
C = plt.contour(X, Y, Z)
# 寫出等高線的高度
plt.clabel(C, inline = True)


輪廓等高圖

需要用到contourf。

$sin(x) \times y^{\frac{2}{3}}$:

code:

1
2
# 只有這裡不一樣
C = plt.contourf(X, Y, Z)

如果需要的函數不支援np.array這種操作(例如:math的函數),就需要自己一個一個展開X, Y

1
2
3
4
5
6
7
8
9
10
11
12
X, Y = np.meshgrid(X, Y)
Z = X * 0 # 一定要*0,強迫複製出一個新的array

i = 0
for x, y in zip(X, Y):
j = 0
for xx , yy in zip(x, y):
Z[i][j] = f(xx, yy)
j = j + 1
i = i + 1

plt.contour(X, Y, Z)


三維平面等高線

結合上一次的3D函數,這次我們要在它下面畫出投影的等高線

$sin(\sqrt{x^2+y^2})$:

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

f = lambda x, y : np.sin(np.sqrt(x ** 2 + y ** 2))

fig = plt.figure()
ax = Axes3D(fig)

ax.view_init(45, 20)

X = np.linspace(-3, 3, 256)
Y = np.linspace(-3, 3, 256)
X, Y = np.meshgrid(X, Y)

Z = f(X, Y)

ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')

ax.plot_surface(X, Y, Z, rstride = 1, cstride = 1, cmap = 'jet')

# 與上篇相比多加了這行
# offset代表將圖投影到z軸某個座標,這裡選最小值,也就是地板
ax.contour(X, Y, Z, offset = Z.min())

甚至可以畫出各面的投影

1
2
3
4
# zdir代表投影到哪個座標
ax.contour(X, Y, Z, zdir = 'z', offset = Z.min())
ax.contour(X, Y, Z, zdir = 'x', offset = X.min())
ax.contour(X, Y, Z, zdir = 'y', offset = Y.min())


$f(x, y) = cos(\sqrt{x^2 + y^2})$:

$f(x, y) = e^{-x^2-y^2}$

$f(x, y) = ln(x^2 + y^2)$

$f(x, y) = xe^{-x^2-y^2}$

$f(x, y) = sin(x) * y^{\frac{2}{3}}$


向量場圖

最簡單的,每個點$(x,y)$都有向量$\vec{v}(x, y)$

code:

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-3, 3, 10)
Y = np.linspace(-3, 3, 10)

X, Y = np.meshgrid(X, Y)
u, v = X, Y

# 畫出向量,第一對(X, Y)代表位置(x, y), 第二對(u, v)代表指向
plt.quiver(X, Y, u, v)

而應用在函數上,可以利用梯度函數numpy.gradient來設定向量方向,這樣就知道函數的大致走向。
$sin(x) \times y^{\frac{2}{3}}$:

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
f = lambda x, y: np.sin(x) * np.power(y ** 2, 1./3.)

X = np.linspace(-2, 2, 20)
Y = np.linspace(-2, 2, 20)

X, Y = np.meshgrid(X, Y)
Z = f(X, Y)

# 梯度函數
# 不知道為甚麼向量方向要倒過來才能正確,可能跟gradient函數有關
v, u = np.gradient(Z)

plt.quiver(X, Y, u, v)
C = plt.contour(X, Y, Z)
plt.clabel(C, inline = True)


$f(x, y) = xe^{-x^2-y^2}$:

$f(x, y) = ln(x^2 + y^2)$

$f(x, y) = cos(\sqrt{x^2 + y^2})$:


三維向量場

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fig = plt.figure()
ax = Axes3D(fig)

ax.view_init(45, 45)

X = np.linspace(-.8, 1, 9)
Y = np.linspace(-.8, 1, 9)
Z = np.linspace(-.8, 1, 3)

X, Y, Z = np.meshgrid(X, Y, Z)

u = np.sin(X) * np.cos(Y)
v = -np.cos(X) * np.cos(Z)
w = np.cos(Y) * np.sin(Z)

ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')

ax.quiver(X, Y, Z, u, v, w, length = .1, normalize=True)

結語

目前都是看什麼、需要什麼,然後才學什麼。總感覺很不扎實,希望上了大學可以有一系列連貫的學習路程。

Reference

https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.contour.html
https://blog.csdn.net/lens___/article/details/83960810
https://www.itread01.com/content/1550129762.html
https://matplotlib.org/stable/gallery/mplot3d/contour3d_3.html
https://oemiliatano.github.io/2020/04/22/3D-functions/
https://www.mathworks.com/help/matlab/ref/gradient.html
https://www.pluvet.com/2020/04/10/%E5%A6%82%E4%BD%95%E5%9C%A8-python-%E4%B8%AD%E7%BB%98%E5%88%B6%E5%90%91%E9%87%8F%E5%9C%BA%EF%BC%88%E4%BD%BF%E7%94%A8-matplotlib%EF%BC%89/
https://www.cnpython.com/qa/112014
https://sq.163yun.com/blog/article/236582359586304000
https://blog.csdn.net/qq_41856733/article/details/102677984
https://numpy.org/doc/stable/reference/generated/numpy.gradient.html