surface plots in matplotlib

匿名 (未验证) 提交于 2019-12-03 02:11:02

问题:

I have a list of 3-tuples representing a set of points in 3D space. I want to plot a surface that covers all these points. The plot_surface function in the mplot3d package requires as arguments X,Y and Z which are 2d arrays. Is plot_surface the right function to plot surface and how do I transform my data in to the required format ?

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

回答1:

For surfaces it's a bit different than a list of 3-tuples, you should pass in a grid for the domain in 2d arrays.

If all you have is a list of 3d points, rather than some function f(x, y) -> z, then you will have a problem because there are multiple ways to triangulate that 3d point cloud into a surface.

Here's a smooth surface example:

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



回答2:

I just came across this same problem. I have evenly spaced data that is in 3 1-D arrays instead of the 2-D arrays that matplotlib's plot_surface wants. My data happened to be in a pandas.DataFrame so here is the matplotlib.plot_surface example with the modifications to plot 3 1-D arrays.

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') 

That is the original example. Adding this next bit on creates the same plot from 3 1-D arrays.

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

Here are the resulting figures:



回答3:

I do this with some lines in python using PANDAS, the plot is beatiful!

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

If necessary you can pass vmin and vmax to define the colorbar range, e.g.

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



回答4:

check the official example. X,Y and Z are indeed 2d arrays, numpy.meshgrid() is a simple way to get 2d x,y mesh out of 1d x and y values.

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

here's pythonic way to convert your 3-tuples to 3 1d arrays.

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) 

Here's mtaplotlib delaunay triangulation (interpolation), it converts 1d x,y,z into something compliant (?):

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



回答5:

In Matlab I did something similar using the delaunay function on the x, y coords only (not the z), then plotting with trimesh or trisurf, using z as the height.

SciPy has the Delaunay class, which is based on the same underlying QHull library that the Matlab's delaunay function is, so you should get identical results.

From there, it should be a few lines of code to convert this Plotting 3D Polygons in python-matplotlib example into what you wish to achieve, as Delaunay gives you the specification of each triangular polygon.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!