HOWTO · Matplotlib
Cómo crear un diagrama de superficie en Matplotlib
Podemos crear un diagrama de superficie en Matplotlib usando el método plot_surface().
En esta página
Para crear una gráfica de superficie 3D en Matplotlib, prepara matrices bidimensionales compatibles X, Y y Z, crea unos ejes con projection="3d" y pasa las matrices a Axes3D.plot_surface. El ejemplo siguiente construye una cuadrícula de coordenadas a partir de una función matemática, etiqueta los ejes, añade una barra de colores y guarda la figura. El mismo flujo de trabajo sirve para valores medidos cuando sus coordenadas y alturas pueden representarse en una cuadrícula rectangular.
Configuración del entorno
Instala NumPy para las operaciones con matrices y cuadrículas, y Matplotlib para crear gráficas. En una terminal, ejecuta python -m pip install numpy matplotlib en el entorno de Python que vayas a utilizar. Si ya administras los paquetes mediante un entorno o un cuaderno, instala ambos allí para que estén disponibles para el intérprete que ejecutará el script.
El ejemplo importa NumPy y matplotlib.pyplot. Matplotlib incluye la funcionalidad de gráficos 3D; projection="3d" crea los ejes tridimensionales, por lo que no hace falta importar Axes3D por separado. El método utilizado en esos ejes es Axes3D.plot_surface.
Preparación de los datos
Una gráfica de superficie asigna una altura a cada ubicación de un plano definido por dos coordenadas. Para coordenadas espaciadas regularmente, np.linspace() crea valores de coordenadas unidimensionales y np.meshgrid() los expande en cuadrículas bidimensionales X e Y. Calcula Z a partir de esas cuadrículas o proporciona alturas medidas organizadas en las mismas ubicaciones de la cuadrícula.
Las tres matrices deben tener formas compatibles: cada Z[i, j] es la altura correspondiente al par de coordenadas X[i, j], Y[i, j]. Las versiones actuales de Matplotlib también aceptan vectores de coordenadas unidimensionales x e y y los expanden frente a una Z bidimensional, pero la propia matriz de alturas debe seguir coincidiendo con las dimensiones de la cuadrícula: una Z calculada en una cuadrícula distinta de X e Y provoca un ValueError, como muestra la sección de resolución de problemas más abajo con una ejecución real. Primero, construye las cuadrículas de coordenadas y luego calcula o reorganiza las alturas sobre esas mismas cuadrículas. Si las mediciones dispersas no forman una cuadrícula rectangular, prepara o interpola los datos en una cuadrícula antes de usar plot_surface.
Creación de la gráfica de superficie
Este ejemplo completo utiliza la función radial suave sin(sqrt(x² + y²)). Crea las cuadrículas, dibuja la superficie, etiqueta las tres dimensiones, añade una escala de colores y guarda el resultado como surface-plot.png en el directorio actual. Ejecútalo en un entorno donde estén instalados NumPy y Matplotlib. El ejemplo no imprime nada en la consola: el resultado es una imagen guardada y una ventana de figura de Matplotlib cuando el backend activo permite mostrarla. Las etiquetas visibles que aparecen en el ejemplo se conservan en inglés porque el bloque de código permanece sin cambios.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
surface = ax.plot_surface(X, Y, Z, cmap="viridis")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title("Surface Plot")
fig.colorbar(surface, ax=ax, label="Z value")
fig.savefig("surface-plot.png", dpi=150, bbox_inches="tight")
plt.show()
Como este script no imprime texto, no hay ningún bloque de salida de consola. La barra de colores relaciona los colores de la superficie con sus valores; la cuadrícula define la geometría, mientras que el mapa de colores controla su aspecto. En un cuaderno, el entorno de gráficos suele mostrar la figura; en un script, plt.show() solicita que el backend de Matplotlib configurado la muestre.
Personalización de la gráfica de superficie
El ejemplo siguiente aplica las personalizaciones más habituales a la misma superficie. Cambia el mapa de colores a plasma, elimina los bordes de la malla y gira la cámara a una elevación y un azimut fijos antes de añadir la barra de colores y guardar la figura como customized-surface-plot.png.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
surface = ax.plot_surface(X, Y, Z, cmap="plasma", edgecolor="none")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title("Customized Surface Plot")
ax.view_init(elev=30, azim=45)
fig.colorbar(surface, ax=ax, label="Z value")
fig.savefig("customized-surface-plot.png", dpi=150, bbox_inches="tight")
plt.show()
Elige un mapa de colores que facilite la lectura de los cambios en Z. En este ejemplo, cmap="plasma" sustituye la progresión viridis del primer ejemplo, y la barra de colores ayuda a interpretar esa correspondencia. La opción edgecolor="none" elimina los bordes dibujados de la malla, que en una cuadrícula densa pueden distraer de la superficie continua; conserva los bordes predeterminados cuando quieras que la propia cuadrícula de muestreo siga visible.
Para cambiar la cámara, llama a ax.view_init(elev=30, azim=45) antes de guardar o mostrar la figura. elev cambia la elevación de la vista y azim gira la vista alrededor del eje vertical. Ajusta estos valores hasta que la forma y los ejes se vean con claridad; el mejor ángulo depende de los datos y de lo que quieras mostrar. En comparación con la primera figura, la cámara girada de la segunda figura deja ver mejor la ladera lejana del pico central.
En una cuadrícula densa, plot_surface puede utilizar controles de muestreo de filas y columnas, como rcount y ccount. Los valores más bajos dibujan menos filas y columnas muestreadas, lo que puede acelerar la representación de una superficie grande a costa del detalle visible. Mantén suficientes muestras para conservar los cambios importantes de los datos. Guarda una imagen para compartir con fig.savefig("surface-plot.png", dpi=150, bbox_inches="tight"); para que sea compatible con los backends de visualización que cierran la figura después de mostrarla, llama a esta función antes de plt.show(). Usa otro nombre de archivo o directorio si necesitas conservar varias versiones.
Comparación con una gráfica de malla de alambre
Una gráfica de malla de alambre dibuja solo las líneas de la cuadrícula de la misma superficie, sin caras rellenas ni mapa de colores. Axes3D.plot_wireframe acepta las mismas cuadrículas X, Y y Z, por lo que puedes cambiar entre ambas vistas sin preparar datos nuevos. La malla de alambre resulta útil cuando importa la propia estructura de la cuadrícula, cuando una superficie rellena ocultaría el lado lejano de la forma, o como comprobación estructural rápida de datos desconocidos antes de generar una superficie completa.
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
ax.plot_wireframe(X, Y, Z, rstride=2, cstride=2, color="tab:blue")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title("Wireframe Plot")
fig.savefig("wireframe-plot.png", dpi=150, bbox_inches="tight")
plt.show()
Los argumentos rstride y cstride omiten filas y columnas para que las líneas sigan siendo legibles; el ejemplo dibuja una de cada dos filas y columnas de una cuadrícula de 50 por 50. A diferencia de plot_surface, una malla de alambre no tiene colores de cara, así que no hay nada que una barra de colores pueda explicar. Para una presentación final, la superficie rellena suele comunicar mejor las diferencias de altura, mientras que la malla de alambre muestra con más claridad cómo se muestrea la propia cuadrícula.
Corregir un error por formas que no coinciden
El fallo más frecuente de plot_surface es una matriz Z cuya forma no coincide con las cuadrículas de coordenadas. El script siguiente calcula Z en una cuadrícula de 50 por 50, pero la pasa junto con las cuadrículas X e Y de 100 por 100:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
x_small = np.linspace(-5, 5, 50)
y_small = np.linspace(-5, 5, 50)
X_small, Y_small = np.meshgrid(x_small, y_small)
Z = np.sin(np.sqrt(X_small**2 + Y_small**2))
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
ax.plot_surface(X, Y, Z, cmap="viridis")
plt.show()
Al ejecutar el script, este se detiene en la llamada a plot_surface con este error:
ValueError: shape mismatch: objects cannot be broadcast to a single shape. Mismatch is between arg 0 with shape (100, 100) and arg 2 with shape (50, 50).
Para corregirlo, calcula Z a partir de las mismas cuadrículas que pasas a plot_surface, como hace el primer ejemplo, de modo que Z.shape sea igual a X.shape e Y.shape. Si no estás seguro, imprime las tres formas antes de graficar y compáralas: cada entrada de Z necesita exactamente un par de coordenadas, ni más ni menos.
Conclusión
Los pasos principales son crear cuadrículas de coordenadas, hacer que Z coincida con ellas, añadir unos ejes 3D y llamar a Axes3D.plot_surface. Un mapa y una barra de colores explican los valores de altura, mientras que los controles de vista y muestreo ayudan a mostrar la forma con claridad. Cuando necesites inspeccionar la propia cuadrícula, plot_wireframe representa los mismos datos como líneas. Guarda la figura cuando necesites un archivo de imagen y ajusta la resolución de la cuadrícula o la cámara según los datos que estés representando.
Preguntas frecuentes
-
¿Qué datos puedo usar para una gráfica de superficie?
Usa valores definidos mediante dos coordenadas, donde cada altura corresponda a una ubicación de una cuadrícula rectangular. Una función resulta práctica para una demostración; los valores medidos también sirven si están organizados en cuadrículas de coordenadas compatibles. Primero hay que convertir los puntos dispersos en una cuadrícula. -
¿Cómo instalo las bibliotecas necesarias?
Instala NumPy y Matplotlib en el entorno donde se ejecutará tu script conpython -m pip install numpy matplotlib. -
¿Puedo cambiar los colores de la superficie?
Sí. Define el argumentocmapdeplot_surfacey luego añade una barra de colores config.colorbar(surface, ax=ax)para mostrar la correspondencia entre colores y valores. -
¿Cómo cambio el ángulo de visión?
Usaax.view_init(elev=..., azim=...). La elevación cambia la altura de la cámara y el azimut cambia su giro alrededor de la gráfica. -
¿Por qué
X,YyZdeben tener formas compatibles?
Matplotlib necesita un par de coordenadas y una altura para cada ubicación de la cuadrícula. SiZse calculó en una cuadrícula distinta,plot_surfacelanza unValueErrorsobre formas que no se pueden difundir juntas. Crea las cuadrículas de coordenadas connp.meshgrid()y calculaZa partir de esas mismas cuadrículas para que las entradas correspondientes queden alineadas.