จริงๆแล้ววัตถุประสงค์ของการnp.meshgrid
พูดถึงในเอกสาร:
np.meshgrid
ส่งคืนเมทริกซ์พิกัดจากเวกเตอร์พิกัด
จัดทำอาร์เรย์พิกัด ND สำหรับการประเมินเวกเตอร์ของสนาม ND scalar / vector บน ND กริดซึ่งกำหนดอาร์เรย์อาร์เรย์หนึ่งมิติ x1, x2, ... , xn
ดังนั้นวัตถุประสงค์หลักคือการสร้างเมทริกซ์พิกัด
คุณอาจถามตัวเองว่า:
ทำไมเราต้องสร้างเมทริกซ์พิกัด?
เหตุผลที่คุณต้องการเมทริกซ์ประสานงานกับ Python / NumPy คือไม่มีความสัมพันธ์โดยตรงจากพิกัดกับค่ายกเว้นเมื่อพิกัดของคุณเริ่มต้นด้วยศูนย์และเป็นจำนวนเต็มบวกล้วนๆ จากนั้นคุณสามารถใช้ดัชนีของอาร์เรย์เป็นดัชนีได้ อย่างไรก็ตามในกรณีที่คุณไม่จำเป็นต้องจัดเก็บพิกัดข้างข้อมูลของคุณ นั่นคือที่มาของกริด
สมมติว่าข้อมูลของคุณคือ:
1 2 1
2 5 2
1 2 1
อย่างไรก็ตามแต่ละค่าแสดงพื้นที่กว้าง 2 กิโลเมตรในแนวนอนและ 3 กิโลเมตรในแนวตั้ง สมมติว่าต้นกำเนิดของคุณอยู่ที่มุมซ้ายบนและคุณต้องการอาร์เรย์ที่แสดงระยะทางที่คุณสามารถใช้:
import numpy as np
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)
โดยที่ v คือ:
array([[0, 0, 0],
[2, 2, 2],
[4, 4, 4]])
และ h:
array([[0, 3, 6],
[0, 3, 6],
[0, 3, 6]])
ดังนั้นถ้าคุณมีสองดัชนี, สมมุติว่าx
และy
(นั่นคือสาเหตุที่ค่าส่งคืนของmeshgrid
คือปกติxx
หรือxs
แทนx
ในกรณีนี้ฉันเลือกh
สำหรับแนวนอน!) จากนั้นคุณจะได้พิกัด x ของจุด, พิกัด y ของจุดและ ค่า ณ จุดนั้นโดยใช้:
h[x, y] # horizontal coordinate
v[x, y] # vertical coordinate
data[x, y] # value
ทำให้ง่ายต่อการติดตามพิกัดและ (สำคัญยิ่งกว่า) คุณสามารถส่งผ่านไปยังฟังก์ชันที่ต้องรู้พิกัด
คำอธิบายที่ยาวขึ้นเล็กน้อย
แต่np.meshgrid
ตัวเองไม่ได้มักจะมาใช้โดยตรงส่วนใหญ่เพียงแค่ใช้อย่างใดอย่างหนึ่งคล้ายวัตถุหรือnp.mgrid
np.ogrid
นี่np.mgrid
หมายถึงsparse=False
และกรณี (ผมหมายถึงข้อโต้แย้งของ) โปรดทราบว่ามีความแตกต่างอย่างมีนัยสำคัญระหว่าง
และกับ: ค่าที่ส่งคืนสองค่าแรก (หากมีสองค่าขึ้นไป) จะถูกกลับรายการ บ่อยครั้งที่สิ่งนี้ไม่สำคัญ แต่คุณควรให้ชื่อตัวแปรที่มีความหมายขึ้นอยู่กับบริบทnp.ogrid
sparse=True
sparse
np.meshgrid
np.meshgrid
np.ogrid
np.mgrid
ยกตัวอย่างเช่นในกรณีของตาราง 2D และmatplotlib.pyplot.imshow
มันทำให้รู้สึกถึงชื่อรายการแรกของกลับnp.meshgrid
x
และเป็นคนที่สองy
ในขณะที่มันเป็นวิธีอื่น ๆ รอบและnp.mgrid
np.ogrid
np.ogrid
และกระจัดกระจายกริด
>>> 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]])
อย่างที่บอกไปแล้วว่าเอาท์พุทกลับด้านเมื่อเทียบกับnp.meshgrid
นั่นคือเหตุผลที่ฉันเอามันออกมาyy, xx
แทน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]])
นี่ดูเหมือนพิกัดแล้วโดยเฉพาะเส้น x และ y สำหรับแปลง 2D
มองเห็น:
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
และกริดหนาแน่น / เนื้อออก
>>> 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]])
เช่นเดียวกับที่นี่: ผลลัพธ์จะถูกย้อนกลับเมื่อเทียบกับ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]])
ซึ่งแตกต่างจากogrid
อาร์เรย์เหล่านี้มีทั้งหมด xx
และyy
พิกัดใน -5 <= xx <= 5; -5 <= yy <= 5 ตาราง
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")
ฟังก์ชั่น
มันไม่ได้ จำกัด อยู่เพียงแค่ 2D เท่านั้นฟังก์ชันเหล่านี้ทำงานสำหรับมิติข้อมูลโดยพลการ
>>> 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.
แม้ว่าสิ่งเหล่านี้ยังสามารถใช้งานได้กับ 1D แต่ก็มีฟังก์ชั่นการสร้างกริด 1D ที่สอง (มากกว่าปกติ):
นอกจากนี้start
และstop
ยังสนับสนุนstep
อาร์กิวเมนต์ (ขั้นตอนที่ซับซ้อนที่แสดงถึงจำนวนของขั้นตอน):
>>> 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.]])
การประยุกต์ใช้งาน
คุณถามเกี่ยวกับวัตถุประสงค์และในความเป็นจริงแล้วกริดเหล่านี้มีประโยชน์อย่างยิ่งหากคุณต้องการระบบพิกัด
ตัวอย่างเช่นหากคุณมีฟังก์ชัน NumPy ที่คำนวณระยะทางในสองมิติ:
def distance_2d(x_point, y_point, x, y):
return np.hypot(x-x_point, y-y_point)
และคุณต้องการทราบระยะทางของแต่ละจุด:
>>> 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]])
เอาต์พุตจะเหมือนกันหากมีการส่งผ่านในกริดหนาแน่นแทนที่จะเป็นกริดเปิด การถ่ายทอด NumPys ทำให้เป็นไปได้!
ลองนึกภาพผลลัพธ์:
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()
และนี่ก็เป็นเมื่อ NumPys mgrid
และogrid
สะดวกมากเพราะช่วยให้คุณเปลี่ยนความละเอียดของเส้นกริดของคุณได้อย่างง่ายดาย:
ys, xs = np.ogrid[-5:5:200j, -5:5:200j]
# otherwise same code as above
อย่างไรก็ตามเนื่องจากimshow
ไม่รองรับx
และy
อินพุตหนึ่งจึงต้องเปลี่ยนเห็บด้วยมือ มันจะสะดวกจริงๆถ้าจะยอมรับx
และy
พิกัดใช่มั้ย
มันง่ายที่จะเขียนฟังก์ชั่นด้วย NumPy ซึ่งจัดการกับกริดอย่างเป็นธรรมชาติ นอกจากนี้ยังมีฟังก์ชั่นหลายอย่างใน NumPy, SciPy, matplotlib ที่คาดว่าคุณจะผ่านในกริด
ฉันชอบรูปภาพลองมาสำรวจ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)
สังเกตวิธีการตั้งค่าพิกัดอย่างถูกต้องแล้ว! density
ไม่ว่าจะเป็นกรณีที่ถ้าคุณเพิ่งผ่านใน
หรือเพื่อให้ตัวอย่างสนุกอื่นโดยใช้แบบจำลอง astropy (คราวนี้ผมไม่สนใจมากเกี่ยวกับพิกัดฉันเพียงแค่ใช้ในการสร้างบางตาราง):
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)
ถึงแม้ว่ามันจะเป็นเพียงแค่ "สำหรับรูปลักษณ์" ฟังก์ชั่นต่างๆที่เกี่ยวข้องกับรูปแบบการทำงานและเหมาะสม (เช่นscipy.interpolate.interp2d
,
scipy.interpolate.griddata
ได้แสดงตัวอย่างการใช้np.mgrid
) ใน SciPy ฯลฯ ต้องกริด งานเหล่านี้ส่วนใหญ่มีกริดแบบเปิดและกริดแบบหนาแน่น แต่บางงานจะทำงานร่วมกับหนึ่งในนั้นเท่านั้น
xx
yy
ส่วนที่ลึกลับสำหรับฉันคือเหตุผลที่ส่งคืนผลลัพธ์คู่นั้นและสิ่งที่พวกเขาดูเหมือน คำตอบของ Hai Phan นั้นมีประโยชน์สำหรับเรื่องนั้น ฉันเดาว่าทำเพื่อความสะดวกเนื่องจากพล็อตต้องการพารามิเตอร์สองตัวเช่นนั้น