web-dev-qa-db-fra.com

Numpy meshgrid en 3D

Le maillage de Numpy est très utile pour convertir deux vecteurs en grille de coordonnées. Quelle est la manière la plus simple de l'étendre à trois dimensions? Donc, étant donné trois vecteurs x, y et z, construisez des tableaux 3x3D (au lieu de tableaux 2x2D) qui peuvent être utilisés comme coordonnées.

41
astrofrog

Voici le code source de meshgrid:

def meshgrid(x,y):
    """
    Return coordinate matrices from two coordinate vectors.

    Parameters
    ----------
    x, y : ndarray
        Two 1-D arrays representing the x and y coordinates of a grid.

    Returns
    -------
    X, Y : ndarray
        For vectors `x`, `y` with lengths ``Nx=len(x)`` and ``Ny=len(y)``,
        return `X`, `Y` where `X` and `Y` are ``(Ny, Nx)`` shaped arrays
        with the elements of `x` and y repeated to fill the matrix along
        the first dimension for `x`, the second for `y`.

    See Also
    --------
    index_tricks.mgrid : Construct a multi-dimensional "meshgrid"
                         using indexing notation.
    index_tricks.ogrid : Construct an open multi-dimensional "meshgrid"
                         using indexing notation.

    Examples
    --------
    >>> X, Y = np.meshgrid([1,2,3], [4,5,6,7])
    >>> X
    array([[1, 2, 3],
           [1, 2, 3],
           [1, 2, 3],
           [1, 2, 3]])
    >>> Y
    array([[4, 4, 4],
           [5, 5, 5],
           [6, 6, 6],
           [7, 7, 7]])

    `meshgrid` is very useful to evaluate functions on a grid.

    >>> x = np.arange(-5, 5, 0.1)
    >>> y = np.arange(-5, 5, 0.1)
    >>> xx, yy = np.meshgrid(x, y)
    >>> z = np.sin(xx**2+yy**2)/(xx**2+yy**2)

    """
    x = asarray(x)
    y = asarray(y)
    numRows, numCols = len(y), len(x)  # yes, reversed
    x = x.reshape(1,numCols)
    X = x.repeat(numRows, axis=0)

    y = y.reshape(numRows,1)
    Y = y.repeat(numCols, axis=1)
    return X, Y

C'est assez simple à comprendre. J'ai étendu le modèle à un nombre arbitraire de dimensions, mais ce code n'est en aucun cas optimisé (et pas complètement vérifié non plus), mais vous obtenez ce pour quoi vous payez. J'espère que cela aide:

def meshgrid2(*arrs):
    arrs = Tuple(reversed(arrs))  #edit
    lens = map(len, arrs)
    dim = len(arrs)

    sz = 1
    for s in lens:
        sz*=s

    ans = []    
    for i, arr in enumerate(arrs):
        slc = [1]*dim
        slc[i] = lens[i]
        arr2 = asarray(arr).reshape(slc)
        for j, sz in enumerate(lens):
            if j!=i:
                arr2 = arr2.repeat(sz, axis=j) 
        ans.append(arr2)

    return Tuple(ans)
29
Paul

Numpy (à partir de 1.8 je pense) supporte désormais plus que la génération 2D de grilles de position avec meshgrid . Un ajout important qui m'a vraiment aidé est la possibilité de choisir l'ordre d'indexation (xy ou ij pour l'indexation cartésienne ou matricielle respectivement), que j'ai vérifié avec l'exemple suivant:

import numpy as np

x_ = np.linspace(0., 1., 10)
y_ = np.linspace(1., 2., 20)
z_ = np.linspace(3., 4., 30)

x, y, z = np.meshgrid(x_, y_, z_, indexing='ij')

assert np.all(x[:,0,0] == x_)
assert np.all(y[0,:,0] == y_)
assert np.all(z[0,0,:] == z_)
43
leifdenby

Pouvez-vous nous montrer comment vous utilisez np.meshgrid? Il y a de très bonnes chances que vous n'ayez vraiment pas besoin de meshgrid car la diffusion numpy peut faire la même chose sans générer un tableau répétitif.

Par exemple,

import numpy as np

x=np.arange(2)
y=np.arange(3)
[X,Y] = np.meshgrid(x,y)
S=X+Y

print(S.shape)
# (3, 2)
# Note that meshgrid associates y with the 0-axis, and x with the 1-axis.

print(S)
# [[0 1]
#  [1 2]
#  [2 3]]

s=np.empty((3,2))
print(s.shape)
# (3, 2)

# x.shape is (2,).
# y.shape is (3,).
# x's shape is broadcasted to (3,2)
# y varies along the 0-axis, so to get its shape broadcasted, we first upgrade it to
# have shape (3,1), using np.newaxis. Arrays of shape (3,1) can be broadcasted to
# arrays of shape (3,2).
s=x+y[:,np.newaxis]
print(s)
# [[0 1]
#  [1 2]
#  [2 3]]

Le fait est que S=X+Y peut et doit être remplacé par s=x+y[:,np.newaxis] car ce dernier ne nécessite pas la formation (éventuellement de grandes tailles) de tableaux répétitifs. Il se généralise également aux dimensions supérieures (plus d'axes) facilement. Vous venez d'ajouter np.newaxis si nécessaire pour effectuer la diffusion si nécessaire.

Voir http://www.scipy.org/EricsBroadcastingDoc pour en savoir plus sur la diffusion numpy.

7
unutbu

je pense que ce que tu veux c'est

X, Y, Z = numpy.mgrid[-10:10:100j, -10:10:100j, -10:10:100j]

par exemple.

5
Autoplectic

Voici une version multidimensionnelle de meshgrid que j'ai écrite:

def ndmesh(*args):
   args = map(np.asarray,args)
   return np.broadcast_arrays(*[x[(slice(None),)+(None,)*i] for i, x in enumerate(args)])

Notez que les tableaux renvoyés sont des vues des données de tableau d'origine, donc la modification des tableaux d'origine affectera les tableaux de coordonnées.

4
user545424

Au lieu d'écrire une nouvelle fonction, numpy.ix _ devrait faire ce que vous voulez.

Voici un exemple tiré de la documentation:

>>> ixgrid = np.ix_([0,1], [2,4])
>>> ixgrid
(array([[0],
   [1]]), array([[2, 4]]))
>>> ixgrid[0].shape, ixgrid[1].shape
((2, 1), (1, 2))'
4
j13r