# Adding material to spheres sequentially using Python

I have the following script, which I was hoping would add a basic red material to my spheres as they are sequentially created. Unfortunately, the script does not work, in the sense that no material is added to any sphere. Indeed, no spheres are created, but in the absence of "bpy.ops.material.new()" and "bpy.context.object.active_material.diffuse_color = (1, 0, 0)", the script produces spheres.

import bpy, csv
fp = "C:/Blender/Spheres.csv"
with open( fp ) as csvfile:
for i, row in enumerate( rdr ):
if i == 0: continue # Skip column title
# Generate UV sphere at x = row0, y = row1, z = row2, and radius = row3.
bpy.ops.mesh.primitive_uv_sphere_add(size = float(row[3]), location = float(row[0]),float(row[1]),float(row[2])))
bpy.ops.material.new()
bpy.context.object.active_material.diffuse_color = (1, 0, 0)


A snippet of my CSV. spheres.csv

x;y;z;r
2.34;2.45;7.65;0.024
6.78;9.31;6.33;0.0467
3.36;8;1.04;0.3626

• You don't give us any information what "it does not work" means. You may also want to reduce your script to the bare minimum (I doubt that running meters.py is realy required) so that we don't have to investigate unnecessary code. – dr. Sybren Dec 7 '17 at 12:05
• @dr. Sybren, I have ammended the question to address your comment. Thank you. – user120911 Dec 7 '17 at 13:10
• Can you share (the first three lines of) your CSV file too? Since you say no sphere is created, maybe it never reaches the sphere creation operator? – dr. Sybren Dec 7 '17 at 13:23
• @ dr. Sybren. I have added a link to my CSV. – user120911 Dec 7 '17 at 13:33
• @ dr. Sybren. I have added a snippet instead. – user120911 Dec 7 '17 at 14:05

Since each sphere's material gets the same properties, I think it's a shame to create a new material for each sphere. Here's my solution, which:

• Doesn't use an operator to create a new material, but rather calls a regular function bpy.data.materials.new(). This is faster, doesn't create unnecessary undo steps, and directly returns the material;
• Uses next(rdr) to skip the first row, rather than using enumerate and checking the index each and every iteration;
• Uses bpy.path.abspath to convert a blendfile-relative path to an absolute path that Python understands;
• Separates data conversion from the strings obtained by the CSV reader to the floats you need for Blender;
• Uses slice notation to shorten the b.o.m.primitive_uv_sphere_add call;

import csv

import bpy

# Create the material
try:
mat = bpy.data.materials['Sphere']
except KeyError:
mat = bpy.data.materials.new('Sphere')
mat.diffuse_color = (1, 0, 0)

fp = "//spheres.csv"
with open(bpy.path.abspath(fp)) as csvfile:
next(rdr)  # Skip column title
for row in rdr:
# Generate UV sphere at x = row0, y = row1, z = row2, and radius = row3.
data = [float(x) for x in row]
bpy.context.object.material_slots[0].material = mat


A little correction:

import bpy, csv
#fp = "C:/Blender/Spheres.csv"
fp = "C:/temp/Spheres.csv"
with open( fp ) as csvfile:
for i, row in enumerate( rdr ):
if i == 0: continue # Skip column title
# Generate UV sphere at x = row0, y = row1, z = row2, and radius = row3.

• Don't use operators where it isn't necessary. bpy.ops.material.new() can be replaced by mat = bpy.data.materials.new('Sphere'), which is faster and doesn't make you guess that it's bpy.data.materials[-1]. – dr. Sybren Dec 9 '17 at 9:44