gráficos de superficie en matplotlib

Resuelto Graddy asked hace 12 años • 9 respuestas

Tengo una lista de 3 tuplas que representan un conjunto de puntos en el espacio 3D. Quiero trazar una superficie que cubra todos estos puntos.

La plot_surfacefunción en el mplot3dpaquete requiere que los argumentos X, Y y Z sean matrices 2D. ¿Es plot_surfacela función correcta para trazar la superficie y cómo transformo mis datos al formato requerido?

data = [(x1,y1,z1),(x2,y2,z2),.....,(xn,yn,zn)]
Graddy avatar Feb 07 '12 11:02 Graddy
Aceptado

Para superficies es un poco diferente a una lista de 3 tuplas, debes pasar una cuadrícula para el dominio en matrices 2D.

Si todo lo que tiene es una lista de puntos 3D, en lugar de alguna función f(x, y) -> z, entonces tendrá un problema porque hay varias formas de triangular esa nube de puntos 3D en una superficie.

Aquí hay un ejemplo de superficie lisa:

import numpy as np
from mpl_toolkits.mplot3d import Axes3D  
# Axes3D import has side effects, it enables using projection='3d' in add_subplot
import matplotlib.pyplot as plt
import random

def fun(x, y):
    return x**2 + y

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(-3.0, 3.0, 0.05)
X, Y = np.meshgrid(x, y)
zs = np.array(fun(np.ravel(X), np.ravel(Y)))
Z = zs.reshape(X.shape)

ax.plot_surface(X, Y, Z)

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

3d

wim avatar Feb 07 '2012 04:02 wim

Puede leer datos directamente desde algún archivo y trazar.

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

x,y,z = np.loadtxt('your_file', unpack=True)

fig = plt.figure()
ax = Axes3D(fig)
surf = ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0.1)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.savefig('teste.pdf')
plt.show()

Si es necesario, puede pasar vmin y vmax para definir el rango de la barra de colores, por ejemplo

surf = ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0.1, vmin=0, vmax=2000)

superficie

Sección de bonificación

Me preguntaba cómo hacer algunos gráficos interactivos, en este caso con datos artificiales.

from __future__ import print_function
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
from IPython.display import Image

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

def f(x, y):
    return np.sin(np.sqrt(x ** 2 + y ** 2))

def plot(i):

    fig = plt.figure()
    ax = plt.axes(projection='3d')

    theta = 2 * np.pi * np.random.random(1000)
    r = i * np.random.random(1000)
    x = np.ravel(r * np.sin(theta))
    y = np.ravel(r * np.cos(theta))
    z = f(x, y)

    ax.plot_trisurf(x, y, z, cmap='viridis', edgecolor='none')
    fig.tight_layout()

interactive_plot = interactive(plot, i=(2, 10))
interactive_plot
Emanuel Fontelles avatar Sep 21 '2017 23:09 Emanuel Fontelles

Me acabo de encontrar con este mismo problema. Tengo datos espaciados uniformemente que se encuentran en 3 matrices 1-D en lugar de las matrices 2-D que matplotlibdesea plot_surface. Mis datos estaban en un formato, pandas.DataFrameasí que aquí está el matplotlib.plot_surfaceejemplo con las modificaciones para trazar 3 matrices 1-D.

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np

X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
    linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)

ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

fig.colorbar(surf, shrink=0.5, aspect=5)
plt.title('Original Code')

Ese es el ejemplo original. Agregar el siguiente bit crea el mismo gráfico a partir de 3 matrices 1-D.

# ~~~~ MODIFICATION TO EXAMPLE BEGINS HERE ~~~~ #
import pandas as pd
from scipy.interpolate import griddata
# create 1D-arrays from the 2D-arrays
x = X.reshape(1600)
y = Y.reshape(1600)
z = Z.reshape(1600)
xyz = {'x': x, 'y': y, 'z': z}

# put the data into a pandas DataFrame (this is what my data looks like)
df = pd.DataFrame(xyz, index=range(len(xyz['x']))) 

# re-create the 2D-arrays
x1 = np.linspace(df['x'].min(), df['x'].max(), len(df['x'].unique()))
y1 = np.linspace(df['y'].min(), df['y'].max(), len(df['y'].unique()))
x2, y2 = np.meshgrid(x1, y1)
z2 = griddata((df['x'], df['y']), df['z'], (x2, y2), method='cubic')

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(x2, y2, z2, rstride=1, cstride=1, cmap=cm.coolwarm,
    linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)

ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

fig.colorbar(surf, shrink=0.5, aspect=5)
plt.title('Meshgrid Created from 3 1D Arrays')
# ~~~~ MODIFICATION TO EXAMPLE ENDS HERE ~~~~ #

plt.show()

Aquí están las cifras resultantes:

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Steven C. Howell avatar May 29 '2015 21:05 Steven C. Howell