# Curve from a set of points

I want to make 3D visualisation of a neuron. How can I plot curves from a set of points ? The data is shown in the image.

I found an artist created a mesh with this data. Same posted below. Data is from this website. http://neuromorpho.org/neuron_info.jsp?neuron_name=211-6mt • Very close to this recent question blender.stackexchange.com/questions/153717/… (about creating curves) From that should be just matter of reading the file and follow the links between data lines. Sep 25 '19 at 17:52

From the provided data file, you can obtain this kind of rendering, with (for example) either creating splines (curves) or creating a mesh with skin modifier.  The script allows to:

• Load the data from the indicated site

• Convert it to inner objects (NeuronPoint class below)

And

• Either convert them to curve, creating a new curve for each data ramification

• Or create a mesh from this point and add a skin modifier in order to obtain the neuron branches

Here is the commented code and blend file:

import bpy
import random
from mathutils import Vector

# Store the information from the SWC text file
class NeuronPoint:
def __init__(self, id, type, x, y, z, radius, parent_id):
self.id = id
self.type = type
self.x = x
self.y = y
self.z = z
self.parent_id = parent_id
self.parent = None
self.children = []

@property
def coordinates(self):
return Vector( (self.x, self.y, self.z) )

# Read data from the file
file = open(file_name, "r")
points = {}
for line in [l for l in file if l and l != '#']:
string_data = line.split()
if string_data:
id = int(string_data) - 1
neuron_type = int(string_data)
x = float(string_data)
y = float(string_data)
z = float(string_data)
parent_id = int(string_data) - 1

neuron_point = NeuronPoint(id, neuron_type, x, y, z, radius, parent_id)
points[id] = neuron_point

for point in points.values():
point.parent = points.get( point.parent_id )
if point.parent:
point.parent.children.append( point )

return [p for p in points.values()]

def random_vector( random_amount ):
return Vector( (random.uniform(0,1), random.uniform(0,1), random.uniform(0,1)) ) * random_amount

# Cuts the data to have additional random points
def make_intermediate_points( points, point, min_distance, random_amount ):
point_co = point.coordinates
parent = point.parent
parent_co = parent.coordinates
vector = point_co - parent_co
distance = vector.length
# Do it only if distance is above the parameter
if distance > min_distance:
# Cut in half + random
intermediate_co = parent_co + (vector * 0.5) + random_vector(random_amount)
# Insert the new point in the hierarchy
new_point = NeuronPoint( len(points), point.type, *intermediate_co, intermediate_radius, parent.id )
points.append( new_point )
point.parent = new_point
point.parent_id = new_point.id
parent.children.remove( point )
parent.children.append( new_point )
new_point.parent = parent
new_point.children.append( point )

# Cut around this new point
make_intermediate_points( points, point, min_distance, random_amount )
make_intermediate_points( points, new_point, min_distance, random_amount )

# Cuts the data to have additional random points
def subdivide_points( points, min_distance, random_amount ):
for point in [p for p in points if p.parent]:
make_intermediate_points( points, point, min_distance, random_amount )
return points

def mesh_from_neuron_points( context, name, points, scale_factor = 0.01, radius_factor = 1 ):

# Gets vertices and edges from the points data
verts = [p.coordinates * scale_factor for p in points]
edges = [(p.id, p.parent_id) for p in points if p.parent]

# Create a mesh
mesh = bpy.data.meshes.new(name)
mesh.from_pydata(verts, edges, [])

# Create an object with this mesh
obj = bpy.data.objects.new(name, mesh)

# Add a subdivision surface (smooth the edges)
subdivision = obj.modifiers.new( "subdivision", 'SUBSURF' )
subdivision.render_levels = 1
subdivision.levels = 1
# Add a skin modifier in order to have thickness
skin = obj.modifiers.new( "skin", 'SKIN' )
skin.branch_smoothing = 0.5
# Smooth again with another subdivision
subdivision = obj.modifiers.new( "subdivision", 'SUBSURF' )

# Associates the radius to each skin vertex
for s, p in zip( obj.data.skin_vertices[''].data, points ):
if not p.children:

# Link the object to the scene
return obj

# Cuts the point set into continuous spline parts, creating a new part for each ramification
def splines_points_from_points( points ):
result = []
base_points = [p for p in points if not p.children]

while base_points:
next_points = []
for point in base_points:
current = [point]
result.append(current)
while point.parent:
point = point.parent
current.append(point)
if len(point.children) > 1:
next_points.append( point )
break
base_points = next_points

for spline in result:
spline.reverse()

return result

def curve_from_neuron_points( context, name, points, scale_factor = 0.01, radius_factor = 1 ):
# Create a curve with some bevel depth
curve = bpy.data.curves.new(name=name, type='CURVE')
curve.dimensions = '3D'
curve.bevel_depth = 1

# Create an object with it
obj = bpy.data.objects.new(name, curve)

# Calculate splines parts
splines_points = splines_points_from_points( points )

for spline_points in splines_points:
# Create a spline for each part
bezier_curve = curve.splines.new('BEZIER')
# Set the points
for bezier, point in zip(bezier_curve.bezier_points, spline_points):
bezier.co = point.coordinates * scale_factor
if not point.children:

# Link object to the scene
# Toggle handle type (faster than doing it point by point)
obj.select_set( True )
context.view_layer.objects.active = obj
bpy.ops.object.editmode_toggle()
bpy.ops.curve.select_all(action='SELECT')
bpy.ops.curve.handle_type_set(type='AUTOMATIC')
bpy.ops.object.editmode_toggle()

return obj

# Get the file name relative to this blend file
file_name = bpy.path.abspath("//test.txt")
# Read the file into points

# Some parameters to handle result scale
scale_factor = 0.1
# Subdivide the model with some random (optional)
points = subdivide_points( points, min_distance = 4, random_amount = 1 )
# Create the object as mesh with skin modifier
#obj = mesh_from_neuron_points( bpy.context, "test", points, scale_factor = scale_factor, radius_factor = radius_factor )
# Create the object as curve
obj = curve_from_neuron_points( bpy.context, "test", points, scale_factor = scale_factor, radius_factor = radius_factor )

# Set a material on it, if defined
mat = bpy.data.materials.get( "Material" )
if mat:
obj.data.materials.append(mat) • Wow great work. Thanks alot lemon. Where in the code I should add the coordinates? Sep 29 '19 at 16:49
• @RafeequeBinUsman, if you mean where the coordinates are read from the file, it is in the function called "read_neuron_points( file_name )" Oct 10 '19 at 4:40