Trên thực tế mục đích np.meshgrid
đã được đề cập trong tài liệu:
np.meshgrid
Trả về ma trận tọa độ từ các vectơ tọa độ.
Tạo các mảng tọa độ ND cho các đánh giá được vector hóa của các trường vô hướng / vectơ ND trên các lưới ND, được đưa ra các mảng tọa độ một chiều x1, x2, ..., xn.
Vì vậy, mục đích chính của nó là tạo ra ma trận tọa độ.
Có lẽ bạn chỉ tự hỏi:
Tại sao chúng ta cần tạo ma trận tọa độ?
Lý do bạn cần ma trận tọa độ với Python / NumPy là vì không có mối quan hệ trực tiếp từ tọa độ đến giá trị, ngoại trừ khi tọa độ của bạn bắt đầu bằng 0 và hoàn toàn là số nguyên dương. Sau đó, bạn chỉ có thể sử dụng các chỉ số của một mảng làm chỉ mục. Tuy nhiên, khi đó không phải là trường hợp bạn cần lưu trữ tọa độ cùng với dữ liệu của mình. Đó là nơi lưới điện đi vào.
Giả sử dữ liệu của bạn là:
1 2 1
2 5 2
1 2 1
Tuy nhiên, mỗi giá trị đại diện cho một vùng rộng 2 km theo chiều ngang và 3 km theo chiều dọc. Giả sử nguồn gốc của bạn là góc trên bên trái và bạn muốn các mảng biểu thị khoảng cách bạn có thể sử dụng:
import numpy as np
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)
trong đó v là:
array([[0, 0, 0],
[2, 2, 2],
[4, 4, 4]])
và h:
array([[0, 3, 6],
[0, 3, 6],
[0, 3, 6]])
Vì vậy, nếu bạn có hai chỉ số, giả sử x
và y
(đó là lý do tại sao giá trị trả về meshgrid
thường là xx
hoặc xs
thay vì x
trong trường hợp này tôi chọn h
theo chiều ngang!) Thì bạn có thể lấy tọa độ x của điểm, tọa độ y của điểm và giá trị tại thời điểm đó bằng cách sử dụng:
h[x, y] # horizontal coordinate
v[x, y] # vertical coordinate
data[x, y] # value
Điều đó giúp việc theo dõi tọa độ dễ dàng hơn nhiều và (thậm chí quan trọng hơn) bạn có thể chuyển chúng đến các hàm cần biết tọa độ.
Một lời giải thích dài hơn một chút
Tuy nhiên, np.meshgrid
bản thân nó không thường được sử dụng trực tiếp, hầu hết chỉ sử dụng một trong những đối tượng tương tựnp.mgrid
hoặc np.ogrid
. Dưới đây np.mgrid
đại diện cho sparse=False
và np.ogrid
các sparse=True
trường hợp (tôi tham khảo các sparse
đối số của np.meshgrid
). Lưu ý rằng có một sự khác biệt đáng kể giữa
np.meshgrid
và np.ogrid
và np.mgrid
: Hai giá trị được trả về đầu tiên (nếu có hai hoặc nhiều hơn) được đảo ngược. Thường thì điều này không quan trọng nhưng bạn nên đặt tên biến có ý nghĩa tùy thuộc vào ngữ cảnh.
Ví dụ, trong trường hợp lưới 2D và matplotlib.pyplot.imshow
việc đặt tên cho mục được trả lại đầu tiên np.meshgrid
x
và thứ hai trong y
khi đó là cách khác để tìm np.mgrid
và np.ogrid
.
np.ogrid
và lưới thưa thớt
>>> import numpy as np
>>> yy, xx = np.ogrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5],
[-4],
[-3],
[-2],
[-1],
[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5]])
Như đã nói, đầu ra bị đảo ngược khi so sánh với np.meshgrid
, đó là lý do tại sao tôi giải nén nó yy, xx
thay vì xx, yy
:
>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6), sparse=True)
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5],
[-4],
[-3],
[-2],
[-1],
[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5]])
Điều này đã trông giống như tọa độ, cụ thể là các đường x và y cho các ô 2D.
Hình dung:
yy, xx = np.ogrid[-5:6, -5:6]
plt.figure()
plt.title('ogrid (sparse meshgrid)')
plt.grid()
plt.xticks(xx.ravel())
plt.yticks(yy.ravel())
plt.scatter(xx, np.zeros_like(xx), color="blue", marker="*")
plt.scatter(np.zeros_like(yy), yy, color="red", marker="x")
np.mgrid
và lưới điện dày đặc
>>> yy, xx = np.mgrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
[-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]])
Áp dụng tương tự ở đây: Đầu ra được đảo ngược so với np.meshgrid
:
>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6))
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
[-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]])
Không giống như ogrid
các mảng này chứa tất cả xx
và yy
tọa độ trong -5 <= xx <= 5; -5 <= yy <= 5 lưới.
yy, xx = np.mgrid[-5:6, -5:6]
plt.figure()
plt.title('mgrid (dense meshgrid)')
plt.grid()
plt.xticks(xx[0])
plt.yticks(yy[:, 0])
plt.scatter(xx, yy, color="red", marker="x")
Chức năng
Không chỉ giới hạn ở 2D, các hàm này hoạt động cho các kích thước tùy ý (tốt, có số lượng đối số tối đa được cung cấp cho hàm trong Python và số lượng kích thước tối đa mà NumPy cho phép):
>>> x1, x2, x3, x4 = np.ogrid[:3, 1:4, 2:5, 3:6]
>>> for i, x in enumerate([x1, x2, x3, x4]):
... print('x{}'.format(i+1))
... print(repr(x))
x1
array([[[[0]]],
[[[1]]],
[[[2]]]])
x2
array([[[[1]],
[[2]],
[[3]]]])
x3
array([[[[2],
[3],
[4]]]])
x4
array([[[[3, 4, 5]]]])
>>> # equivalent meshgrid output, note how the first two arguments are reversed and the unpacking
>>> x2, x1, x3, x4 = np.meshgrid(np.arange(1,4), np.arange(3), np.arange(2, 5), np.arange(3, 6), sparse=True)
>>> for i, x in enumerate([x1, x2, x3, x4]):
... print('x{}'.format(i+1))
... print(repr(x))
# Identical output so it's omitted here.
Ngay cả khi chúng cũng hoạt động cho 1D, có hai hàm tạo lưới 1D (phổ biến hơn nhiều):
Bên cạnh start
và stop
đối số, nó cũng hỗ trợ step
đối số (thậm chí các bước phức tạp đại diện cho số bước):
>>> x1, x2 = np.mgrid[1:10:2, 1:10:4j]
>>> x1 # The dimension with the explicit step width of 2
array([[1., 1., 1., 1.],
[3., 3., 3., 3.],
[5., 5., 5., 5.],
[7., 7., 7., 7.],
[9., 9., 9., 9.]])
>>> x2 # The dimension with the "number of steps"
array([[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.]])
Các ứng dụng
Bạn đặc biệt hỏi về mục đích và trên thực tế, các lưới này cực kỳ hữu ích nếu bạn cần một hệ tọa độ.
Ví dụ: nếu bạn có hàm NumPy tính toán khoảng cách theo hai chiều:
def distance_2d(x_point, y_point, x, y):
return np.hypot(x-x_point, y-y_point)
Và bạn muốn biết khoảng cách của từng điểm:
>>> ys, xs = np.ogrid[-5:5, -5:5]
>>> distances = distance_2d(1, 2, xs, ys) # distance to point (1, 2)
>>> distances
array([[9.21954446, 8.60232527, 8.06225775, 7.61577311, 7.28010989,
7.07106781, 7. , 7.07106781, 7.28010989, 7.61577311],
[8.48528137, 7.81024968, 7.21110255, 6.70820393, 6.32455532,
6.08276253, 6. , 6.08276253, 6.32455532, 6.70820393],
[7.81024968, 7.07106781, 6.40312424, 5.83095189, 5.38516481,
5.09901951, 5. , 5.09901951, 5.38516481, 5.83095189],
[7.21110255, 6.40312424, 5.65685425, 5. , 4.47213595,
4.12310563, 4. , 4.12310563, 4.47213595, 5. ],
[6.70820393, 5.83095189, 5. , 4.24264069, 3.60555128,
3.16227766, 3. , 3.16227766, 3.60555128, 4.24264069],
[6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
2.23606798, 2. , 2.23606798, 2.82842712, 3.60555128],
[6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
1.41421356, 1. , 1.41421356, 2.23606798, 3.16227766],
[6. , 5. , 4. , 3. , 2. ,
1. , 0. , 1. , 2. , 3. ],
[6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
1.41421356, 1. , 1.41421356, 2.23606798, 3.16227766],
[6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
2.23606798, 2. , 2.23606798, 2.82842712, 3.60555128]])
Đầu ra sẽ giống hệt nhau nếu một trong một lưới dày đặc thay vì lưới mở. Phát sóng NumPys làm cho nó có thể!
Hãy hình dung kết quả:
plt.figure()
plt.title('distance to point (1, 2)')
plt.imshow(distances, origin='lower', interpolation="none")
plt.xticks(np.arange(xs.shape[1]), xs.ravel()) # need to set the ticks manually
plt.yticks(np.arange(ys.shape[0]), ys.ravel())
plt.colorbar()
Và đây cũng là khi NumPys mgrid
và ogrid
trở nên rất thuận tiện vì nó cho phép bạn dễ dàng thay đổi độ phân giải của lưới:
ys, xs = np.ogrid[-5:5:200j, -5:5:200j]
# otherwise same code as above
Tuy nhiên, vì imshow
không hỗ trợ x
và y
đầu vào nên người ta phải thay đổi dấu tích bằng tay. Sẽ thật sự thuận tiện nếu nó chấp nhận x
và y
tọa độ, phải không?
Thật dễ dàng để viết các hàm với NumPy xử lý một cách tự nhiên với các lưới. Hơn nữa, có một số chức năng trong NumPy, SciPy, matplotlib mong bạn vượt qua trong lưới.
Tôi thích hình ảnh vì vậy hãy khám phá matplotlib.pyplot.contour
:
ys, xs = np.mgrid[-5:5:200j, -5:5:200j]
density = np.sin(ys)-np.cos(xs)
plt.figure()
plt.contour(xs, ys, density)
Lưu ý cách tọa độ đã được đặt chính xác! Đó sẽ không phải là trường hợp nếu bạn vừa thông qua density
.
Hoặc để đưa ra một ví dụ thú vị khác bằng cách sử dụng các mô hình astropy (lần này tôi không quan tâm nhiều đến tọa độ, tôi chỉ sử dụng chúng để tạo một số lưới):
from astropy.modeling import models
z = np.zeros((100, 100))
y, x = np.mgrid[0:100, 0:100]
for _ in range(10):
g2d = models.Gaussian2D(amplitude=100,
x_mean=np.random.randint(0, 100),
y_mean=np.random.randint(0, 100),
x_stddev=3,
y_stddev=3)
z += g2d(x, y)
a2d = models.AiryDisk2D(amplitude=70,
x_0=np.random.randint(0, 100),
y_0=np.random.randint(0, 100),
radius=5)
z += a2d(x, y)
Mặc dù đó chỉ là "cho ngoại hình" một số chức năng liên quan đến mô hình chức năng và phù hợp (ví dụ scipy.interpolate.interp2d
,
scipy.interpolate.griddata
thậm chí hiển thị ví dụ sử dụng np.mgrid
) trong scipy vv yêu cầu lưới. Hầu hết trong số này hoạt động với lưới mở và lưới dày đặc, tuy nhiên một số chỉ hoạt động với một trong số chúng.
xx
vàyy
. Phần bí ẩn đối với tôi là tại sao nó trả về cặp kết quả đó, và chúng trông như thế nào. Câu trả lời của Hải Phan rất hữu ích cho việc đó. Tôi đoán nó làm điều đó cho thuận tiện, vì cốt truyện muốn hai tham số như thế.