tiempo real matrices graficos graficas graficar grafica ejes coordenadas barras python matplotlib scipy visualization volume

python - real - matplotlib ejes



¿Cómo se muestra una gráfica 3D de una matriz 3D isosuperficie en matplotlib mplot3D o similar? (3)

Tengo una matriz numpy tridimensional. Me gustaría mostrar (en matplotlib) una buena trama 3D de una isosuperficie de esta matriz (o más estrictamente, mostrar una isosuperficie del campo escalar 3D definido por interpolación entre los puntos de muestra).

La parte mplot3D de matplotlib proporciona una buena compatibilidad con gráficos 3D, pero (hasta donde puedo ver) su API no tiene nada que simplemente tome una matriz tridimensional de valores escalares y muestre una isosuperficie. Sin embargo, sí es compatible con la visualización de una colección de polígonos, por lo que presumiblemente podría implementar el algoritmo de los cubos de marcha para generar dichos polígonos.

Parece bastante probable que ya se hayan implementado unos cubos de marcha fáciles de usar y que no los he encontrado, o que me falta una manera fácil de hacerlo. De forma alternativa, agradecería cualquier apuntador a otras herramientas para visualizar datos de matriz 3D fácilmente utilizables del mundo de Python / numpy / scipy.


Complementando la respuesta de @DanHickstein, también puede usar trisurf para visualizar los polígonos obtenidos en la fase de cubos de marcha.

import numpy as np from numpy import sin, cos, pi from skimage import measure import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D def fun(x, y, z): return cos(x) + cos(y) + cos(z) x, y, z = pi*np.mgrid[-1:1:31j, -1:1:31j, -1:1:31j] vol = fun(x, y, z) verts, faces = measure.marching_cubes(vol, 0, spacing=(0.1, 0.1, 0.1)) fig = plt.figure() ax = fig.add_subplot(111, projection=''3d'') ax.plot_trisurf(verts[:, 0], verts[:,1], faces, verts[:, 2], cmap=''Spectral'', lw=1) plt.show()

Actualización: 11 de mayo de 2018

Como se menciona en @DrBwts, ahora marching_cubes devuelve 4 valores. El siguiente código funciona.

import numpy as np from numpy import sin, cos, pi from skimage import measure import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D def fun(x, y, z): return cos(x) + cos(y) + cos(z) x, y, z = pi*np.mgrid[-1:1:31j, -1:1:31j, -1:1:31j] vol = fun(x, y, z) verts, faces, _, _ = measure.marching_cubes(vol, 0, spacing=(0.1, 0.1, 0.1)) fig = plt.figure() ax = fig.add_subplot(111, projection=''3d'') ax.plot_trisurf(verts[:, 0], verts[:,1], faces, verts[:, 2], cmap=''Spectral'', lw=1) plt.show()


Si desea mantener sus parcelas en matplotlib (mucho más fácil para producir imágenes de calidad de publicación que mayavi en mi opinión), entonces puede usar la función marching_cubes implementada en skimage y luego graficar los resultados en matplotlib usando

mpl_toolkits.mplot3d.art3d.Poly3DCollection

como se muestra en el enlace de arriba. Matplotlib hace un buen trabajo al renderizar la isosuperficie. Aquí hay un ejemplo que hice de algunos datos de tomografía real:


Solo para explicar mi comentario anterior, el trazado 3D de matplotlib en realidad no está destinado a algo tan complejo como las isosuperficies. Está destinado a producir resultados vectoriales bonitos y de calidad de publicación para gráficos en 3D realmente simples. No puede manejar polígonos 3D complejos, por lo que incluso si se implementa marching cubes usted mismo para crear la isosurface, no lo renderizaría correctamente.

Sin embargo, lo que puede hacer en su lugar es usar mayavi (su API mlab es un poco más conveniente que usar directamente mayavi), que usa VTK para procesar y visualizar datos multidimensionales.

Como un ejemplo rápido (modificado a partir de uno de los ejemplos de la galería mayavi):

import numpy as np from enthought.mayavi import mlab x, y, z = np.ogrid[-10:10:20j, -10:10:20j, -10:10:20j] s = np.sin(x*y*z)/(x*y*z) src = mlab.pipeline.scalar_field(s) mlab.pipeline.iso_surface(src, contours=[s.min()+0.1*s.ptp(), ], opacity=0.3) mlab.pipeline.iso_surface(src, contours=[s.max()-0.1*s.ptp(), ],) mlab.show()