FABRIZIO GUERRIERI

Blog about Technology, Artificial Intelligence, AR/VR, and Electronics

Use Python to plot Surface graphs of irregular Datasets

Do you want to plot a surface graph of a 3D dataset but your data is not distributed on a regular meshgrid? No need to worry as Matplotlib’s trisurf got you covered. Here is how to use it.

First things first

Let’s add the proper libraries, shall we?

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

Generate the sample data

Create an irregular grid of (x,y) coordinates and the relative z-data

points = 500
data = np.zeros([points,3])
x = np.random.rand(points)*100
y = np.random.rand(points)*100
z = np.sinc((x-20)/100*3.14) + np.sinc((y-50)/100*3.14)

Plot the generated grid on a scatter graph, just to verify there is no cheating here…

fig = plt.figure()
ax = fig.add_subplot(1,1,1)

ax.scatter(x, y, marker=".", c="#DC143C", edgecolors="black", s=100)
ax.set_xlabel('X')
ax.set_ylabel('Y')

plt.show()

Random points on a grid

Looks quite irregular to me. Let’s continue

Triangulation

The first things to do is to use the (x,y) coordinates to subdivide the plane into a set of triangles. The Triangulation method uses the Delaunay triangulation algorithm for the job and returns the object triang

triang contains an unstructured triangular grid from (x,y) coordinates:

If you want to know more about the Triangulation method you can check Matplotlib’s API

triang = mtri.Triangulation(x, y)

Let’s have a look at the (x,y) coordinates and the triangles

fig = plt.figure()
ax = fig.add_subplot(1,1,1)

ax.triplot(triang, c="#D3D3D3", marker='.', markerfacecolor="#DC143C",
    markeredgecolor="black", markersize=10)

ax.set_xlabel('X')
ax.set_ylabel('Y')
plt.show()

Points with triangles

Depending on the dataset and the algorithm used for the triangulation, some triangles might cause artifact in the 3D surface. In case that happens, it is possible to mask out some of them. In this example we eliminate the triangles for which at least one point is outside of an arbitrary boundary

isBad = np.where((x<1) | (x>99) | (y<1) | (y>99), True, False)

mask = np.any(isBad[triang.triangles],axis=1)
triang.set_mask(mask)

Let’s plot again the 2D surface with the (x,y) coordinates and the new triangles. Note how some triangles at the periphery of the plane are now missing.

fig = plt.figure()
ax = fig.add_subplot(1,1,1)

ax.triplot(triang, c="#D3D3D3", marker='.', markerfacecolor="#DC143C", 
    markeredgecolor="black", markersize=10)

ax.set_xlabel('X')
ax.set_ylabel('Y')
plt.show()

Remove bad triangles

Finally let’s plot the 3D surface using plot_trisurf

fig = plt.figure()
ax = fig.add_subplot(1,1,1, projection='3d')

ax.plot_trisurf(triang, z, cmap='jet')
ax.scatter(x,y,z, marker='.', s=10, c="black", alpha=0.5)
ax.view_init(elev=60, azim=-45)

ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()

Final result

Sep 10, 2017

comments powered by Disqus