# Create model from XYZ data points

I'm trying to create a 3D heat map model out of data that I have from a csv file. I have a few thousand data points with XYZ coordinates.

I'm able to import the data into blender as a point cloud with this python script, however I would like to create a model with solid faces. Is there a way when importing the data to somehow join the points to create faces instead of generating thousands of separate points?

Currently, this what I have in terms of point cloud

The end product would look something like this (minus the texture) and obviously the model wouldn't be as regular as this one

Any help is greatly appreciated!

• Are the points in a regular order? Or may their index be semi-random? In the last case, you should probably obtain better results with Meshlab which has several tool for meshing pointclouds. Mar 27 '17 at 22:21
• Has said @Carlo, is there some constant aspects in the cloud of points? For instance in the file itself or because X,Y are a grid? To go further, could you give an access to a sample file? Mar 28 '17 at 11:42
• The points are indexed randomly based on an arbitrary origin. I've uploaded a sample of the csv and a picture of what the data is representing. The X and Y coordinates are indeed a grid, while the Z value represent the power levels at that location. I've been able to mesh the point cloud in Meshlab with the Poisson reconstruction, however I'd ideally want to automate the model creation process in Blender only if possible. Mar 28 '17 at 12:46

From the file you provided, here is the result:

Effectively, this is not as regular as the sample image in the question!!

This script works only if we have a rectangular grid along X and Y.

Here is commented code (tell me if some additional explanations are needed):

import bpy
import csv
from operator import itemgetter

csvfile = open('G:\\Telechargements\\Heatmap_ES_output_01.csv')

inFile = csv.reader(csvfile, delimiter=',', quotechar='"')
inFile.__next__()

#Read and sort the vertices coordinates (sort by x and y)
vertices = sorted( [(float(r[0]), float(r[1]), float(r[2])) for r in inFile], key = itemgetter(0,1) )

#********* Assuming we have a rectangular grid *************
xSize = next( i for i in range( len(vertices) ) if vertices[i][0] != vertices[i+1][0] ) + 1 #Find the first change in X
ySize = len(vertices) // xSize

#Generate the polygons (four vertices linked in a face)
polygons = [(i, i - 1, i - 1 + xSize, i + xSize) for i in range( 1, len(vertices) - xSize ) if i % xSize != 0]

name = "grid"
mesh = bpy.data.meshes.new( name ) #Create the mesh (inner data)
obj = bpy.data.objects.new( name, mesh ) #Create an object

obj.data.from_pydata( vertices, [], polygons ) #Associate vertices and polygons

obj.scale = (1, 5, 0.2) #Scale it (if needed)
for p in obj.data.polygons: #Set smooth shading (if needed)
p.use_smooth = True

bpy.context.scene.objects.link( obj ) #Link the object to the scene


Blender 2.8

For 2.8:

The last line:

bpy.context.scene.objects.link( obj )


should be replaced by:

bpy.context.scene.collection.objects.link( obj )

• This works perfectly for the data that I have. If you don't mind, could you explain the line 'polygons = [(i, i - 1, i - 1 + xSize, i + xSize) for i in range( 1, len(vertices) - xSize ) if i % xSize != 0]' ? I get that it creates the face between 4 vertices, but I don't understand the 'if' statement at the end. Merci! Mar 28 '17 at 17:17
• i modulo the width. That allows to skip 0, 1*width, 2*width, ... as vertex index. Between 3 points you have 2 faces (edges). Je ne sais pas si je suis clair... !! Mar 28 '17 at 17:27

Here's a possible solution using Sverchok add-on:

Basically we can import the points directly from the cvs file with the Text input node and transform the coordinates in vertices with the Vector in node.

Then what's left is to provide a sequence of indexes based on the specific grid of acquisition. In this particular case, we are defining the first polygon (a quad) and then repeating the process for every quadrlet with a combination of list managing and a int range.

The last segment of the algorithm is used to get rid of the faces built by the vertices of a row and the first of another. In this particular case is deleting one item of the list every 216.

• Interesting (+1). About your note, this is precisely the question of the OP in the comment (the need of i%xSize). Is there a way to do it with Sverchock? Mar 28 '17 at 17:51
• Yes, you can implement the same math you used, or use methods like the one I added to the answer. Mar 28 '17 at 18:25
• I tried to plot using your script. It is showing error can you have quick look CSV file is here drive.google.com/open?id=1VRqSRnDcolSaYv-_6UsfdKV8uaov3Z41 Feb 23 '20 at 23:13
• Unfortunately the script works only for a rectangular grid distribution of points like the one provided by the OP. Yours needs a different implementation, like a marching cube alghorithm or something similar. There is no trivial solution. Feb 27 '20 at 18:56