matplotlib中的表面图

我有一个三元组列表,代表三维空间中的一组点。 我想绘制一个涵盖所有这些点的曲面。 mplot3d软件包中的plot_surface函数需要X,Y和Z二维数组。 plot_surface是绘制曲面的正确函数,如何将数据转换为所需的格式?

data = [(x1,y1,z1),(x2,y2,z2),.....,(xn,yn,zn)]

对于曲面而言,它与三元组列表有所不同,您应该传入二维数组中的网格。

如果你所有的是一个3d点的列表,而不是一些函数f(x, y) -> z ,那么你将会遇到一个问题,因为有多种方法可以将三维点云三angular剖分成一个曲面。

这是一个光滑的表面示例:

 import numpy as np from mpl_toolkits.mplot3d import Axes3D 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(x,y) for x,y in zip(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() 

在这里输入图像描述

我刚刚遇到了同样的问题。 我有3个1-D数组,而不是matplotlibplot_surface想要的2-D数组,均匀分布的数据。 我的数据碰巧在一个pandas.DataFrame所以这里是matplotlib.plot_surface例子 ,修改plot 3 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') 

这就是最初的例子。 将下一个位添加,从3个1-D数组中创build相同的图。

 # ~~~~ 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() 

这里是结果数字:

在这里输入图像描述在这里输入图像描述

检查官方的例子。 X,Y和Z确实是二维数组,numpy.meshgrid()是一个简单的方法来获取2d x,y网格中的1d x和y值。

http://matplotlib.sourceforge.net/mpl_examples/mplot3d/surface3d_demo.py

这里是pythonic的方式来将你的3元组转换为3 1d数组。

 data = [(1,2,3), (10,20,30), (11, 22, 33), (110, 220, 330)] X,Y,Z = zip(*data) In [7]: X Out[7]: (1, 10, 11, 110) In [8]: Y Out[8]: (2, 20, 22, 220) In [9]: Z Out[9]: (3, 30, 33, 330) 

这里是mtaplotlib delaunay三angular测量(插值),它将1d x,y,z转换成符合(?)的东西:

http://matplotlib.sourceforge.net/api/mlab_api.html#matplotlib.mlab.griddata

我用python中的一些代码用PANDAS来做这个,情节很美!

 from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt from matplotlib import cm import numpy as np import pandas as pd from sys import argv file = argv[1] x,y,z = np.loadtxt(file, unpack=True) df = pd.DataFrame({'x': x, 'y': y, 'z': z}) fig = plt.figure() ax = Axes3D(fig) surf = ax.plot_trisurf(df.x, df.y, df.z, cmap=cm.jet, linewidth=0.1) fig.colorbar(surf, shrink=0.5, aspect=5) plt.savefig('teste.pdf') plt.show() 

如果有必要,您可以通过vmin和vmax来定义颜色条的范围,例如

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

表面

在Matlab中,我只使用xy坐标上的delaunay函数(而不是z )做了类似的事情,然后用trimeshtrisurf ,使用z作为高度。

SciPy有Delaunay类,它基于Matlab的delaunay函数所在的基础QHull库,所以你应该得到相同的结果。

从那里开始,应该用几行代码将python-matplotlib示例中的Plotting 3D Polygons转换为您希望实现的内容,因为Delaunay为您提供了每个三angular形多边形的规范。