2009-12-01 13 views
36

Le maillage de Numpy est très utile pour convertir deux vecteurs en une grille de coordonnées. Quel est le moyen le plus simple d'étendre ceci à 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.Grille maillée Numpy en 3D

Répondre

26

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 

Il 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é par erreur), mais vous obtenez ce que vous payez. Hope it helps:

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) 
+1

Dans le cas d'une grille maillée 3d, en utilisant un exemple comme celui fourni dans numpy doc pour meshgrib, cela retournera Z, Y, X au lieu de X, Y, Z. Le remplacement de l'instruction return par 'return tuple (ans [:: - 1])' peut résoudre ce problème. – levesque

+0

@Paul si la longueur du tableau x ou y est longue alors la commande x.repeat() plante et envoie une erreur mémoire. Est-il possible d'éviter cette erreur? – Dalek

+0

@Dalek Quelle est la durée des tableaux? Se pourrait-il que vous manquiez de mémoire? Par exemple, s'il y a 3 tableaux, 4096 entrées chacun, et que chaque entrée contient un double (ie 8 octets), alors pour les entrées seules nous avons besoin de (8 * 4 * 2 ** 10) ** 3 octets = 2 ** 45 octets = 32 * 2 ** 40 octets = 32 To de mémoire, ce qui est évidemment énorme. J'espère ne pas avoir fait une erreur ici. –

5

Je pense que ce que vous voulez est

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

par exemple.

+0

Merci, mais ce n'est pas tout à fait ce que J'ai besoin - meshgrid utilise réellement les valeurs des vecteurs pour générer le tableau 2D, et les valeurs peuvent être irrégulièrement espacées. – astrofrog

7

Pouvez-vous nous montrer comment vous utilisez np.meshgrid? Il y a de très fortes chances que vous n'ayez vraiment pas besoin de meshgrid car la diffusion numérique peut faire la même chose sans générer de 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 point est que S=X+Y peut et doit être remplacé par s=x+y[:,np.newaxis] parce celui-ci ne nécessite pas (peut-être) de grandes tableaux répétitifs à former. Il généralise également aux dimensions plus élevées (plus d'axes) facilement. Vous venez d'ajouter np.newaxis où nécessaire pour effectuer la diffusion si nécessaire. Voir http://www.scipy.org/EricsBroadcastingDoc pour plus d'informations sur la diffusion numérique.

4

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

Voici un exemple 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

ce serait bien si vous pouviez dire comment? ... –

4

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

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 retournés sont vues des données du tableau d'origine, donc changer les tableaux d'origine affectera les tableaux de coordonnées.

+0

a fait l'affaire pour moi, merci beaucoup! – somada141

31

Numpy (à partir de 1,8 je pense) prend maintenant en charge plus élevé que la génération 2D de grilles de position avec meshgrid. Un ajout important qui m'a vraiment aidé est la capacité de choisir l'ordre d'indexation (soit xy ou ij pour l'indexation cartésien ou matrice respectivement), que je vérifiais 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_)