2012-01-12 43 views
10

Estoy tratando de trazar una superficie en python. Tengo una tabla de N por N valores. Creé dos vectores X e Y, cada uno de N elementos. Cuando intento para trazar este, consigo un error:trazado en 3D con python

ValueError: total size of new array must be unchanged 

He comprobado los ejemplos y veo allí que para N elementos de Z hay N elementos para X y Y.

Esto no tiene' tiene sentido para mí ¿Cómo es que necesito N elementos y no N por N?

Aquí es un ejemplo de código:

importación aleatoria matemáticas importación

from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.pyplot as plt 
import numpy as np 

bignum = 100 

mat = [] 
X = [] 
Y = [] 

for x in range(0,bignum): 
    mat.append([]) 
    X.append(x); 
    for y in range (0,bignum): 
     mat[x].append(random.random()) 
     Y.append(y) 

fig = plt.figure(figsize=plt.figaspect(2.)) 
ax = fig.add_subplot(1,1,1, projection='3d') 
surf = ax.plot_surface(X,Y,mat) 
+0

Se puede publicar las líneas de código que arrojan el error? – NoBugs

Respuesta

20

En primer lugar, no vuelvas a hacer cosas como esta:

mat = [] 
X = [] 
Y = [] 

for x in range(0,bignum): 
    mat.append([]) 
    X.append(x); 
    for y in range (0,bignum): 
     mat[x].append(random.random()) 
     Y.append(y) 

Eso es equivalente a:

mat = np.random.random((bignum, bignum)) 
X, Y = np.mgrid[:bignum, :bignum] 

... pero son órdenes de magnitud más rápidas y usa una fracción de la memoria que usar listas y luego convertir a matrices.

Sin embargo, su ejemplo funciona perfectamente.

from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.pyplot as plt 
import numpy as np 

bignum = 100 
mat = np.random.random((bignum, bignum)) 
X, Y = np.mgrid[:bignum, :bignum] 

fig = plt.figure() 
ax = fig.add_subplot(1,1,1, projection='3d') 
surf = ax.plot_surface(X,Y,mat) 
plt.show() 

enter image description here

Si usted lee la documentación de plot_surface, se dice claramente que X, se espera que Y y Z a ser matrices 2D.

Esto es para que pueda trazar superficies más complejas (por ejemplo, esferas) definiendo inherentemente la conectividad entre los puntos. (Por ejemplo, véase este ejemplo de la galería matplotlib: http://matplotlib.sourceforge.net/examples/mplot3d/surface3d_demo2.html)

Si tiene arrays 1D X e Y, y desea una superficie simple a partir de una rejilla 2D, a continuación, utilizar numpy.meshgrid o numpy.mgrid para generar el X apropiado y arrays Y 2D.

Editar: Sólo para explicar lo mgrid y meshgrid otra cosa, vamos a echar un vistazo a su salida:

print np.mgrid[:5, :5] 

rendimientos:

array([[[0, 0, 0, 0, 0], 
     [1, 1, 1, 1, 1], 
     [2, 2, 2, 2, 2], 
     [3, 3, 3, 3, 3], 
     [4, 4, 4, 4, 4]], 

     [[0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4]]]) 

Así, devuelve una sola, 3D matriz con una forma de 2x5x5, pero es más fácil pensar en esto como dos matrices en 2D. Uno representa las coordenadas i para cualquier punto en una cuadrícula de 5x5, mientras que el otro representa las coordenadas j.

Debido a trabajos de desembalaje la forma de pitón, podemos simplemente escribir:

xx, yy = np.mgrid[:5, :5] 

Python no le importa exactamente lo mgrid rendimientos, se acaba de tratar de descomprimirlo en dos artículos. Debido a que las matrices numpy iteran sobre sectores de su primer eje, obtendremos 2, 5x5 matrices si desempaquetamos una matriz con una forma de (2x5x5).Del mismo modo, podemos hacer cosas como:

xx, yy, zz = np.mgrid[:5, :5, :5] 

... y obtener 3, matrices 3D 5x5x5 de índices del. Además, si cortamos con un rango diferente (por ejemplo xx, yy = np.mgrid[10:15, 3:8] sería índices del azulejo del 10 al 14 (ambos inclusive) y 3 a 7 (ambos inclusive).

Hay un poco más que mgrid hace (que puede tomar argumentos de pasos complejos a linspace imitar, por ejemplo xx, yy = np.mgrid[0:1:10j, 0:5:5j] volverá 2 matrices de 10x5 con el aumento de los números entre 0-1 y 0-5, respectivamente), pero vamos a saltar a meshgrid por un segundo.

meshgrid toma dos arrays y los azulejos de forma similar a mgrid. Como un ejemplo:

x = np.arange(5) 
y = np.arange(5) 
xx, yy = np.meshgrid(x, y) 
print xx, yy 

rendimientos:

(array([[0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4], 
     [0, 1, 2, 3, 4]]), 

array([[0, 0, 0, 0, 0], 
     [1, 1, 1, 1, 1], 
     [2, 2, 2, 2, 2], 
     [3, 3, 3, 3, 3], 
     [4, 4, 4, 4, 4]])) 

meshgrid realmente sucede para devolver una tupla de 2, matrices 5x5 2D, pero esa distinción no importa. La diferencia clave es que las indicaciones no tienen que aumentar en una dirección particular. Simplemente teja las matrices que se le asignan. A modo de ejemplo:

x = [0.1, 2.4, -5, 19] 
y = [-4.3, 2, -1, 18.4] 
xx, yy = np.meshgrid(x, y) 

rendimientos:

(array([[ 0.1, 2.4, -5. , 19. ], 
     [ 0.1, 2.4, -5. , 19. ], 
     [ 0.1, 2.4, -5. , 19. ], 
     [ 0.1, 2.4, -5. , 19. ]]), 
array([[ -4.3, -4.3, -4.3, -4.3], 
     [ 2. , 2. , 2. , 2. ], 
     [ -1. , -1. , -1. , -1. ], 
     [ 18.4, 18.4, 18.4, 18.4]])) 

Como se dará cuenta, que sólo alicatado los valores que nos dio.

Básicamente, los usa cuando necesita trabajar con indicios de la misma forma que su cuadrícula de entrada. Es más útil cuando se quiere evaluar una función en los valores de una grilla.

E.g.

import numpy as np 
import matplotlib.pyplot as plt 

x, y = np.mgrid[-10:10, -10:10] 
dist = np.hypot(x, y) # Linear distance from point 0, 0 
z = np.cos(2 * dist/np.pi) 

plt.title(r'$\cos(\frac{2*\sqrt{x^2 + y^2}}{\pi})$', size=20) 
plt.imshow(z, origin='lower', interpolation='bicubic', 
      extent=(x.min(), x.max(), y.min(), y.max())) 
plt.colorbar() 
plt.show() 

enter image description here

+2

Joe, tienes razón, pero funcionaría en el ejemplo si 'X.append (x)' se moviera dentro del segundo ciclo. 'plot_surface' todavía funciona si tienes una matriz 1D que es NxN de largo. El error es decir que matplotlib no puede remodelar la matriz 1D para que sea una matriz N por N 2D. También eres demasiado rápido. – Yann

+0

Gracias. Esto es solo una prueba para ver que entiendo la gráfica de superficie. Yo, en realidad, planeo hacer algo similar a la transformación de Fourier y no sé cómo hacer una operación compleja o una operación condicional en una sola línea en Python. Voy a publicar una nueva pregunta para esto. – Yotam

+0

@Yann - ¡Ah, claro! En realidad, no ejecuté su código tal como fue publicado ... ¡Creo que debería haberlo hecho! Parece que realmente respondiste su pregunta, entonces. ... Y a pesar de lo que valga, me golpeaste al golpe aún más a menudo. :) –

Cuestiones relacionadas