W rzeczywistości cel np.meshgridjest już wspomniany w dokumentacji:
np.meshgrid
Zwraca macierze współrzędnych z wektorów współrzędnych.
Twórz tablice współrzędnych ND dla wektoryzowanych ocen pól skalarnych / wektorowych ND na siatkach ND, biorąc pod uwagę jednowymiarowe tablice współrzędnych x1, x2, ..., xn.
Więc głównym celem jest utworzenie macierzy współrzędnych.
Prawdopodobnie po prostu zadałeś sobie pytanie:
Dlaczego musimy tworzyć macierze współrzędnych?
Powodem, dla którego potrzebujesz macierzy współrzędnych w Pythonie / NumPy, jest brak bezpośredniej relacji między współrzędnymi a wartościami, z wyjątkiem sytuacji, gdy współrzędne zaczynają się od zera i są czysto dodatnimi liczbami całkowitymi. Następnie możesz po prostu użyć indeksów tablicy jako indeksu. Jednak gdy tak nie jest, musisz jakoś przechowywać współrzędne obok swoich danych. Tam właśnie wchodzą siatki.
Załóżmy, że Twoje dane to:
1 2 1
2 5 2
1 2 1
Każda wartość reprezentuje jednak obszar o szerokości 2 kilometrów w poziomie i 3 kilometry w pionie. Załóżmy, że twoim początkiem jest lewy górny róg i potrzebujesz tablic reprezentujących odległość, którą możesz użyć:
import numpy as np
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)
gdzie v jest:
array([[0, 0, 0],
[2, 2, 2],
[4, 4, 4]])
i H:
array([[0, 3, 6],
[0, 3, 6],
[0, 3, 6]])
Więc jeśli masz dwa wskaźniki, powiedzmy xi y(dlatego wartość zwracana meshgridjest zwykle xxlub xszamiast xw tym przypadku wybrałem hpoziomo!), Możesz uzyskać współrzędną x punktu, współrzędną y punktu i wartość w tym punkcie przy użyciu:
h[x, y] # horizontal coordinate
v[x, y] # vertical coordinate
data[x, y] # value
To znacznie ułatwia śledzenie współrzędnych i (co ważniejsze) można przekazać je do funkcji, które muszą znać współrzędne.
Nieco dłuższe wyjaśnienie
Jednak np.meshgridsam nie jest często używany bezpośrednio, głównie używa się jednego z podobnych obiektów np.mgridlub np.ogrid. Tutaj np.mgridreprezentuje sparse=Falsei np.ogridten sparse=Trueprzypadek (odnoszę się do sparseargumentu np.meshgrid). Należy pamiętać, że istnieje znaczna różnica między
np.meshgridi np.ogrida np.mgrid: Pierwsze dwie zwracane wartości (jeśli są dwa lub więcej) są odwrócone. Często nie ma to znaczenia, ale powinieneś podać sensowne nazwy zmiennych w zależności od kontekstu.
Na przykład w przypadku siatki 2D matplotlib.pyplot.imshowsensowne jest nazwanie pierwszego zwróconego elementu np.meshgrid xi drugiego, ygdy jest odwrotnie dla np.mgridi np.ogrid.
np.ogrid i rzadkie siatki
>>> 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]])
Jak już powiedziano, wynik jest odwrócony w porównaniu do np.meshgrid, dlatego rozpakowałem go jako yy, xxzamiast 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]])
To już wygląda jak współrzędne, szczególnie linie xiy dla wykresów 2D.
Wizualizowane:
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 i gęste / rozwinięte siatki
>>> 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]])
To samo dotyczy tutaj: Wyjście jest odwrócone w porównaniu do 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]])
W przeciwieństwie do ogridtych tablic zawierają wszystkie xx i yywspółrzędne w -5 <= xx <= 5; -5 <= yy <= 5 siatki.
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")

Funkcjonalność
Te funkcje nie ograniczają się tylko do 2D, te funkcje działają dla dowolnych wymiarów (cóż, maksymalna liczba argumentów podanych do działania w Pythonie i maksymalna liczba wymiarów dozwolona przez NumPy):
>>> 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.
Nawet jeśli działają one również dla 1D, istnieją dwie (znacznie bardziej powszechne) funkcje tworzenia siatki 1D:
Oprócz argumentu starti stopobsługuje również stepargument (nawet złożone kroki reprezentujące liczbę kroków):
>>> 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.]])
Aplikacje
Pytałeś konkretnie o cel, a te siatki są niezwykle przydatne, jeśli potrzebujesz układu współrzędnych.
Na przykład, jeśli masz funkcję NumPy, która oblicza odległość w dwóch wymiarach:
def distance_2d(x_point, y_point, x, y):
return np.hypot(x-x_point, y-y_point)
I chcesz poznać odległość każdego punktu:
>>> 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]])
Wynik byłby identyczny, gdyby przejść przez gęstą siatkę zamiast otwartej siatki. Nadawanie NumPys umożliwia!
Wizualizujmy wynik:
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()

I to również wtedy, gdy NumPys mgridi ogridstają się bardzo wygodne, ponieważ pozwala łatwo zmienić rozdzielczość twoich siatek:
ys, xs = np.ogrid[-5:5:200j, -5:5:200j]
# otherwise same code as above

Ponieważ jednak imshownie obsługuje xi ydanych wejściowych, należy ręcznie zmieniać tiki. Byłoby naprawdę wygodne, gdyby zaakceptował współrzędne xi y, prawda?
NumPy ułatwia pisanie funkcji, które w naturalny sposób radzą sobie z siatkami. Ponadto istnieje kilka funkcji w NumPy, SciPy, matplotlib, które oczekują przejścia w siatce.
Lubię obrazy, więc zbadajmy 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)

Zwróć uwagę, jak współrzędne są już poprawnie ustawione! Nie byłoby tak, gdybyś właśnie zdał density.
Albo dać inny przykład zabawy przy użyciu modeli astropy (tym razem nie obchodzi wiele o współrzędnych, po prostu wykorzystać je do stworzenia jakiegoś siatkę):
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)

Chociaż jest to tylko „wygląd”, kilka funkcji związanych z modelami funkcjonalnymi i dopasowaniem (na przykład scipy.interpolate.interp2d,
scipy.interpolate.griddatanawet pokazuj przykłady użycia np.mgrid) w Scipy itp. Wymaga siatek. Większość z nich działa z otwartymi i gęstymi siatkami, jednak niektóre działają tylko z jedną z nich.
xxiyy. Tajemnicze dla mnie było to, dlaczego zwraca tę parę wyników i jak wyglądają. Odpowiedź Hai Phana jest do tego przydatna. Myślę, że robi to dla wygody, ponieważ fabuła chce dwóch takich parametrów.