-
The Python script, AddBlenderCustomPropertiesFromCSV.py, will read a formatted csv (comma seperated value) file and use its contents to set Custom Properties.
-
The Blender Add-on, AddBlenderCustomPropertiesFromCSVAddOn.py, will perform the same task, but as an Add-on integrated into the 3D View Tool Panel.
-
The file loaded must be in a csv.DictReader class format readable with QUOTE_NONNUMERIC quoting:
QUOTE_NONNUMERIC
... When used with the reader, input fields that are not quoted are converted to floats.
-
Therefore, non-numeric components (including column headers) must be enclosed within double qutoes.
-
The script or Add-on can be used to 'enrich' a Blender file, that will be exported to a glTF file, with embedded data.
- When a Blender file is exported to a glTF file, the Custom Properties are placed in the extras properties associated with the mesh.
- Run the AddBlenderCustomPropertiesFromCSV.py script from within Blender and respond to the input prompt with filename (format: [folder]/filename.csv ) that contains the data to update the Custom Properies.
Note:
- The input method awaits a response from the system console, not the Blender Python Interactive console.
- Alternatively install AddBlenderCustomPropertiesFromCSVAddOn.py as a Blender Add-on
- Add-on name is 'CVS to Custom Properties' under Object;
- Then select file with file selector;
- Select 'Add Custom Props' button to initiate the Python script that adds Customp Properties.
- Note: The file testWithAddOn.blend has the Blender add-on in a text editor window ready to be added directly for a quick-test scenario that doesn't involve User Preferences.
- All text values (including column headers) must be double quoted in the .csv file.
- The Python Scripts will throw an exception error if they attempt to convert an un-quoted string to a float numeric.
- Microsoft Excel does not add double quotes around text values automatically with its Save As option.
- One option is to use the CVSFile utility macro in the vba folder.
- The video, How to Write Your Very First Macro in Microsft Excel offers a helpful tutorial.
- To use the CVSFile utility macro, cut-and-paste the macro's code into the VBA editor (as per the video) and excute it on the sheet that contains the data to export.
- The video, How to Write Your Very First Macro in Microsft Excel offers a helpful tutorial.
Sub CSVFile()
' Modified from: https://stackoverflow.com/questions/846839/excel-how-to-add-double-quotes-to-strings-only-in-csv-file
' Author: https://github.com/MarioDelgadoSr
'
' Macro will export selection or current sheet in a format compatible with Python's QUOTE_NONNUMERIC quoting.
' See: https://docs.python.org/3/library/csv.html
Dim SrcRg As Range
Dim CurrRow As Range
Dim CurrCell As Range
Dim CurrTextStr As String
Dim ListSep As String
Dim FName As Variant
'Prompt User for save file location
FName = Application.GetSaveAsFilename("", "CSV File (*.csv), *.csv")
If FName <> False Then
'ListSep = Application.International(xlListSeparator)
ListSep = ","
If Selection.Cells.Count > 1 Then
Set SrcRg = Selection
Else
Set SrcRg = ActiveSheet.UsedRange
End If
Open FName For Output As #1
For Each CurrRow In SrcRg.Rows
CurrTextStr = ""
For Each CurrCell In CurrRow.Cells
' Quote only text value
DblQuoteStr = IIf(Application.IsText(CurrCell.Value), """", "")
CurrTextStr = CurrTextStr & DblQuoteStr & CurrCell.Value & DblQuoteStr & ListSep
Next 'CurCell
While Right(CurrTextStr, 1) = ListSep
'Remove last ',' on the line
CurrTextStr = Left(CurrTextStr, Len(CurrTextStr) - 1)
Wend
Print #1, CurrTextStr
Next 'CurrRow
Close #1
End If
End Sub
- Another option is to use OpenOffice as detailed in this post.
- Assuming a Blender object (.type = 'MESH');
- With a name == 'object1';
- The following csv file contents will assign the Blender mesh Custom Properties :
- A numeric float value of prop1 to property 'propName1';
- A string value of "prop2" to 'propertyName2':
"objectName","propName1","propName2"
"object1",prop1,"prop2"
- The sanitize = True option will sanitize a mesh's name to be consitent wth Three.js naming requirements for nodes.
Contents of AddBlenderCustomPropertiesFromCSV.py:
# Python script to set Blender Custom Properties for a mesh (.type == 'MESH')
# Author: Mario Delgado, LinkedIn: https://www.linkedin.com/in/mario-delgado-5b6195155/
# Source: http://github.com/MarioDelgadoSr/AddBlenderCustomPropertiesFromCSV
#
# Custom Properties: https://docs.blender.org/manual/en/latest/data_system/custom_properties.html?highlight=custom%20properties
import bpy, csv
# santize = True will convert Blender's duplicate object name to a Three.js sanitized name
# This is only a concern when exporting Blender to glTF files with the intent of importing
# them into Three.js. Any names with mesh glTF nodes with '.' in the name will have the '.' removed.
# So sanitizing the names before exporting to glTF (and eventually Three.js) will provide for consitency
# in any processes that depend on a consitent and accurate node name.
# See Three.js sanitizing: https://discourse.threejs.org/t/issue-with-gltfloader-and-objects-with-dots-in-their-name-attribute/6726
sanitize = True #True or False
# input: https://docs.python.org/3/library/functions.html#input
# Note: input awaits a response from the system console, not the Blender Python Interactive console
# System Console: https://docs.blender.org/manual/en/dev/advanced/command_line/launch/windows.html?highlight=toggle%20system%20console
# Python Interactive Console: https://docs.blender.org/manual/en/dev/editors/python_console.html
filePath = input("Enter file name path (folder/filename.csv):") #Example: Type "c:/data/keys.csv" when prompted in the conole
# Example of content in .csv file, line 1 contains column heading (Object Name and Properties):
#
# "objectName","propName1","propName2",...
# "object1","prop1",prop2,...
# "object2","prop1",prop2,...
#
# Script will assign bpy.data.objects[objectName].data[propNameN] = propN
# * The quoted propNs will be treated as strings
# * The un-quoted propNs will be converted to float.
print("********************************Add Blender Custom Properties ********************************************")
print(" ")
print("Adding Custom Properties with the following options:")
print(" ")
print("filePath: ", filePath)
print("sanitize: ", str(sanitize))
print(" ")
with open( filePath ) as csvfile: # https://docs.python.org/3/library/csv.html
rdr = csv.DictReader( csvfile, quoting = csv.QUOTE_NONNUMERIC )
for row in rdr:
meshName = row[rdr.fieldnames[0]]
print("******************************** meshName:", meshName ,"********************************************")
print(" properties before assignment(s): ", bpy.data.objects[meshName].data.items())
for x in range (1, len(rdr.fieldnames)):
propName = rdr.fieldnames[x]
propValue = row[propName]
# List Comprehension: https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions
mesh = [obj for obj in bpy.data.objects if obj.name == meshName and obj.type == 'MESH'][0]
if sanitize:
mesh.name = mesh.name.replace(".","")
print (" Mesh's name sanitized from: ",meshName, " to: ", mesh.name)
meshName = mesh.name
#Custom Property Assigned to Object, this assures userData on ThreeJS is assigned to groups as well
mesh[propName] = propValue
print(" Updated meshName: ", meshName, ", propName: ", propName, ", propValue:", mesh[propName])
print(" properties after assignment(s): ", bpy.data.objects[meshName].items())
print("")
- Assuming a Blender object (.type = 'MESH');
- With a name == 'object1';
- The following csv file contents will assign the Blender mesh a Custom Properties numeric float value of prop1 to property 'propName1' and a string value of "prop2" to 'propertyName2':
"objectName","propName1","propName2"
"object1",prop1,"prop2"
- Once installed , the Blender Add-on will be registered in the Tools panel:
Contents of AddBlenderCustomPropertiesFromCSVAddOn.py:
# Add-on Tutorial: https://youtu.be/OEkrQGFqM10
# Python script to set Blender Custom Properties for a mesh (.type == 'MESH')
# Author: Mario Delgado, LinkedIn: https://www.linkedin.com/in/mario-delgado-5b6195155/
# Source: http://github.com/MarioDelgadoSr/AddBlenderCustomPropertiesFromCSV
#
# Custom Properties: https://docs.blender.org/manual/en/latest/data_system/custom_properties.html?highlight=custom%20properties
# Modified from: https://blender.stackexchange.com/questions/26898/how-to-create-a-folder-dialog/26906#26906
bl_info = {"name": "CVS to Custom Properties", "category": "Object"}
import bpy, csv
from bpy.props import (StringProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
EnumProperty,
PointerProperty,
)
from bpy.types import (Panel,
Operator,
AddonPreferences,
PropertyGroup,
)
class addPropsSettings(PropertyGroup):
path = StringProperty(
name="",
description="Path to Directory",
default="",
maxlen=1024,
subtype='FILE_PATH')
sanitize_bool = BoolProperty( #https://blender.stackexchange.com/questions/35007/how-can-i-add-a-checkbox-in-the-tools-ui
name="Sanitize Mesh Name",
description="Sanitize the Mesh Name",
default = True
)
class processCustom(bpy.types.Operator):
bl_idname = "object.process_custom"
bl_label = ""
filePath = bpy.props.StringProperty()
sanitize = bpy.props.BoolProperty()
def execute(self, context):
filePath = self.filePath
sanitize = self.sanitize
# santize = True will convert Blender's duplicate object name to a Three.js sanitized name
# This is only a concern when exporting Blender to glTF files with the intent of importing
# them into Three.js. Any names with mesh glTF nodes with '.' in the name will have the '.' removed.
# So sanitizing the names before exporting to glTF (and eventually Three.js) will provide for consitency
# in any processes that depend on a consitent and accurate node name.
# See Three.js sanitizing: https://discourse.threejs.org/t/issue-with-gltfloader-and-objects-with-dots-in-their-name-attribute/6726
#sanitize = True #True or False
# input: https://docs.python.org/3/library/functions.html#input
# Note: input awaits a response from the system console, not the Blender Python Interactive console
# System Console: https://docs.blender.org/manual/en/dev/advanced/command_line/launch/windows.html?highlight=toggle%20system%20console
# Python Interactive Console: https://docs.blender.org/manual/en/dev/editors/python_console.html
#filePath = input("Enter file name path (folder/filename.csv):") #Example: Type "c:/data/keys.csv" when prompted in the conole
# Example of content in .csv file, line 1 contains column heading (Object Name and Properties):
#
# "objectName","propName1","propName2",...
# "object1","prop1",prop2,...
# "object2","prop1",prop2,...
#
# Script will assign bpy.data.objects[objectName].data[propNameN] = propN
# * The quoted propNs will be treated as strings
# * The un-quoted propNs will be converted to float.
print("********************************Add Blender Custom Properties ********************************************")
print(" ")
print("Adding Custom Properties with the following options:")
print(" ")
print("filePath: ", filePath)
print("sanitize: ", str(sanitize))
print(" ")
# https://docs.python.org/3/library/csv.html
with open( filePath ) as csvfile:
rdr=csv.DictReader(csvfile,quoting=csv.QUOTE_NONNUMERIC)
for row in rdr:
meshName = row[rdr.fieldnames[0]]
print("******************************** meshName:", meshName ,"********************************************")
print(" properties before assignment(s): ", bpy.data.objects[meshName].data.items())
for x in range (1, len(rdr.fieldnames)):
propName = rdr.fieldnames[x]
propValue = row[propName]
# List Comprehension: https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions
mesh = [obj for obj in bpy.data.objects if obj.name == meshName and obj.type == 'MESH'][0]
if sanitize:
mesh.name = mesh.name.replace(".","")
print (" Mesh's name sanitized from: ",meshName, " to: ", mesh.name)
meshName = mesh.name
#Custom Property Assigned to Object, this assures userData on ThreeJS is assigned to groups as well
mesh[propName]=propValue
print(" Update meshName: ", meshName, ",propName: ", propName, ", proValue: ", mesh[propName])
print(" properties after assignment(s): ", bpy.data.objects[meshName].items())
print("")
return {'FINISHED'}
# ---------------------------------------------------------------------------------
# Customize Tool Panel and add file selector and check box for sanitize option
# ---------------------------------------------------------------------------------
class addCustomProperitesPanel(Panel):
bl_idname = "addCustomProperitesPanel"
bl_label = "CSV to Custom Props" # scn.csv_to_custom_props
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_category = "Tools"
bl_context = "objectmode"
def draw(self, context):
layout = self.layout
scn = context.scene
col = layout.column(align=True)
col.prop(scn.csv_to_custom_props, "path", text="") #The file path selected by the user
col.prop(scn.csv_to_custom_props, "sanitize_bool","Sanitize Mesh Name") #The sanitize option True/False
#Passing property: https://blenderartists.org/t/how-to-pass-two-arguments-to-a-button-operator/497013/8
processCustomButton = col.operator("object.process_custom", text="Add Custom Props")
processCustomButton.filePath = scn.csv_to_custom_props.path
processCustomButton.sanitize = scn.csv_to_custom_props.sanitize_bool
# ------------------------------------------------------------------------
# register and unregister functions
# ------------------------------------------------------------------------
def register():
bpy.utils.register_module(__name__)
bpy.types.Scene.csv_to_custom_props = PointerProperty(type=addPropsSettings)
def unregister():
bpy.utils.unregister_module(__name__)
del bpy.types.Scene.csv_to_custom_props
if __name__ == "__main__":
register()
- Open test.blend file in test folder.
- Run AddBlenderCustomPropertiesFromCSV.py Python script.
- Reference test.csv in test folder when prompted by input prompt.
Note:
- The input method awaits a response from the system console, not the Blender Python Interactive console.
- Alternatively install AddBlenderCustomPropertiesFromCSVAddOn.py as a Blender Add-on
- Add-on name is 'CVS to Custom Properties' under Object;
- Then select file with file selector;
- Select 'Add Custom Props' button to initiate the Python script that adds Customp Properties.
- Note: The file testWithAddOn.blend has the Blender Add-on ready for a quick test, without having to install via User Preferences.
Screen Shot of Installed Add-on
"Mesh","value"
"Cube.000",10
"Cube.001",20
The output is the same for either AddBlenderCustomPropertiesFromCSV.py script or AddBlenderCustomPropertiesFromCSVAddOn.py Add-on:
********************************Add Blender Custom Properties ********************************************
Adding Custom Properties with the following options:
filePath: c:\temp\test.csv
sanitize: True
******************************** meshName: Cube.000 ********************************************
properties before assignment(s): []
Mesh's name sanitized from: Cube.000 to: Cube000
Updated meshName: Cube000 , propName: value , propValue: 10.0
properties after assignment(s): [('value', 10.0)]
******************************** meshName: Cube.001 ********************************************
properties before assignment(s): []
Mesh's name sanitized from: Cube.001 to: Cube001
Updated meshName: Cube001 , propName: value , propValue: 20.0
properties after assignment(s): [('value', 20.0)]
The file test.gltf is a glTF file exported after the data was added to the Blender scene.
-
The repository folder contains several glTF files created with the Python script used to demonstrate the My Data Visualizer application.
-
These Blender generated exports can simply be 'dragged-and-droped' into the visualization application. The application will read both the 3D visual and data information dynamically.
- Mario Delgado Github: MarioDelgadoSr
- LinkedIn: Mario Delgado
- My Data Visualizer: A data visualization application using the DataVisual design pattern.
This project is licensed under the MIT License - see the LICENSE.md file for details