Surface graphics in matplotlib

I have a list of 3 sets representing a set of points in 3D space. I want to build a surface covering all of these points. The plot_surface function in the mplot3d package requires X, Y, and Z, which are 2d arrays, as arguments. Is plot_surface the correct function to build a surface and how to convert my data to the required format?

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

+82
python matplotlib
Feb 07 2018-12-12T00:
source share
7 answers

For surfaces, this is slightly different from the list of three tuples, you must pass the grid for the domain in 2d arrays.

If all you have is a list of 3d points, and not some function f(x, y) β†’ z , then you will have a problem, because there are several ways to triangulate this 3d cloud of points on the surface.

Here is an example with a smooth surface:

 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

+96
Feb 07 2018-12-12T00:
source share

I just stumbled upon the same problem. I have uniformly distributed data that are in 3 1-D arrays instead of the two-dimensional arrays that matplotlib plot_surface . My data ended up in pandas.DataFrame , so here is an example of matplotlib.plot_surface with changes in building 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') 

This is an original example. Adding this next bit creates the same graph 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 numbers:

enter image description hereenter image description here

+18
May 29 '15 at 9:35
source share

You can read data directly from some file and graph.

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

If necessary, you can pass vmin and vmax to determine the range of the color scale, for example

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

surface

Bonus Section

I was wondering how to make some interactive graphs, in this case with artificial data

 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 
+17
Sep 21 '17 at 23:18
source share

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

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

here's a pythonic way to convert your 3-tuples into 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 to something compatible (?):

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

+3
Feb 07 2018-12-12T00:
source share

In Matlab, I did something similar, using the delaunay function only for the codes x , y (not z ), and then build with trimesh or trisurf , using z as the height.

SciPy has a Delaunay class, which is based on the same QHull base library as the Matlab delaunay function, so you should get the same results.

From there, it needs to be a few lines of code to convert this example of 3D polygons in the python-matplotlib example to what you want to achieve, since delaunay gives you the specification of each triangular polygon.

+1
Oct. 15 '14 at 1:25
source share

In order to listen, Emanuel had the answer that I (and probably many others) are looking for. If you have 3D scattered data in 3 separate arrays, pandas are incredible help and work much better than other options. For development, suppose your x, y, z are some arbitrary variables. In my case, it was c, gamma and errors, because I tested the vector support machine. There are many potential options for building data:

  • scatter3D (cParams, gammas, avg_errors_array) - this works, but too simplified
  • plot_wireframe (cParams, gammas, avg_errors_array) - this works, but will look ugly if your data is not sorted beautifully, as is the case with massive chunks of real scientific data
  • ax.plot3D (cParams, gammas, avg_errors_array) - similar to the framework

Wireframe graph of data

Wireframe plot of the data

3d data scatter

3d scatter of the data

The code looks like this:

  fig = plt.figure() ax = fig.gca(projection='3d') ax.set_xlabel('c parameter') ax.set_ylabel('gamma parameter') ax.set_zlabel('Error rate') #ax.plot_wireframe(cParams, gammas, avg_errors_array) #ax.plot3D(cParams, gammas, avg_errors_array) #ax.scatter3D(cParams, gammas, avg_errors_array, zdir='z',cmap='viridis') df = pd.DataFrame({'x': cParams, 'y': gammas, 'z': avg_errors_array}) 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('./plots/avgErrs_vs_C_andgamma_type_%s.png'%(k)) plt.show() 

Here is the final result:

plot_trisurf of xyz data

+1
Apr 02 '18 at 6:12
source share

It is not possible to directly create a three-dimensional surface using your data. I would recommend you build an interpolation model using some tools like pykridge . The process will include three steps:

  1. Train the interpolation model using pykridge
  2. Build a grid from X and Y using a meshgrid
  3. Interpolate values ​​for Z

Having created your grid and the corresponding Z values, you are now ready to go to plot_surface . Please note that depending on the size of your data, the meshgrid function may work for a while. The workaround is to create evenly distributed samples using np.linspace for the X and Y axes, and then apply interpolation to derive the necessary Z values. If so, the interpolated values ​​may differ from the original Z because X and Y have changed.

0
Sep 19 '18 at 7:43
source share



All Articles