Archicad Python API
About automating tasks in Archicad using the Python API.

Object Exporter in Python: Getting more properties

sdeisher
Contributor

I am looking to modify the Excel Exporter script provided by Graphisoft to give me a list of objects, their associated rooms/levels, and a handful of User Defined properties. I'm having a few issues that I could use some help with:

 

  1. I can't find the proper Built In property that will actually return the level/story name or the associated zone/room. The ones I've added in my script are all coming back blank.
  2. I want to get some User Defined properties but don't understand the syntax. I've exported a list of possible properties; here is an example of a property for the Model number of a product that I'd like to include in the script: 
    UserDefinedPropertyUserId {localizedName: [Product Info - Facilities Management, Model], type: UserDefined}

Can anyone help me with this?

from archicad import ACConnection, handle_dependencies
from typing import List
import os, sys

handle_dependencies('openpyxl')

from openpyxl import Workbook

conn = ACConnection.connect()
assert conn

acc = conn.commands
act = conn.types
acu = conn.utilities

scriptFolder = os.path.dirname(os.path.realpath(__file__))

################################ CONFIGURATION #################################
worksheetTitlesAndElements = {
    "Objects": acc.GetElementsByType("Object"),
}
propertyUserIds = [
    act.BuiltInPropertyUserId("General_ElementID"),
    act.BuiltInPropertyUserId("IdAndCategories_Name"),

#these properties are all returning blank values; I want them to give me the object room and level name and number
    act.BuiltInPropertyUserId("General_RelatedZoneName"),
    act.BuiltInPropertyUserId("General_RelatedZoneNumber"),
    act.BuiltInPropertyUserId("General_FromZone"),
    act.BuiltInPropertyUserId("General_FromZoneNumber"),

#down here I'd like to add some user defined properties but can't get the syntax to work. I have tried the act.UserDefinedPropertyUserID method and it gives me an error, something to do with classes and strings
]
outputFolder = scriptFolder
outputFileName = "Objects.xlsx"
################################################################################


def AutoFitWorksheetColumns(ws):
    for columnCells in ws.columns:
        length = max(len(str(cell.value)) for cell in columnCells)
        ws.column_dimensions[columnCells[0].column_letter].width = length


def PrintWorksheetContent(ws):
    for columnCells in ws.columns:
        for cell in columnCells:
            print(f"{ws.title}!{cell.column_letter}{cell.row}={cell.value}")


def FillExcelWorksheetWithPropertyValuesOfElements(ws, propertyIds: List[act.PropertyIdArrayItem], elements: List[act.ElementIdArrayItem]):
    propertyValuesDictionary = acu.GetPropertyValuesDictionary(elements, propertyIds)
    propertyDefinitionsDictionary = dict(zip(propertyIds, acc.GetDetailsOfProperties(propertyIds)))

    ws.cell(row=2, column=1).value = "Element Guid"
    row = 3
    for element, valuesDictionary in propertyValuesDictionary.items():
        ws.cell(row=row, column=1).value = str(element.elementId.guid)
        column = 2
        for propertyId, propertyValue in valuesDictionary.items():
            if row == 3:
                ws.cell(row=1, column=column).value = str(propertyId.propertyId.guid)
                propertyDefinition = propertyDefinitionsDictionary[propertyId].propertyDefinition
                ws.cell(row=2, column=column).value = f"{propertyDefinition.group.name} / {propertyDefinition.name}"
            ws.cell(row=row, column=column).value = propertyValue
            column += 1
        row += 1

    AutoFitWorksheetColumns(ws)
    PrintWorksheetContent(ws)


propertyIds = acc.GetPropertyIds(propertyUserIds)
wb = Workbook()
ws = wb.active

i = 0
for title, elements in worksheetTitlesAndElements.items():
    if i == 0:
        ws.title = title
    else:
        ws = wb.create_sheet(title)
    FillExcelWorksheetWithPropertyValuesOfElements(ws, propertyIds, elements)
    i += 1

excelFilePath = os.path.join(outputFolder, outputFileName)
wb.save(excelFilePath)
acu.OpenFile(excelFilePath)

if os.path.exists(excelFilePath):
    print("Saved Excel")

 

2023 M2 Max Macbook Pro
Ventura 13.4
ArchiCAD 27
1 REPLY 1
JT1986
Booster

2nd question:

This should work for properties that you have created yourself:

#Example
act.UserDefinedPropertyId(["Product Info - Facilities Management", "Model"]) #First the name of the property group, second the property name(id) in that particular group. Note the square brackets.

 

1st question:

I don't think that there is  a built-in property type for the level/story name that you can use in a Python script to retrieve the information directly from the Archicad project. However, you can create a property (type: expression) inside the Archicad project which retrieves the story/level name and use it in a Python script as a UserDefinedPropertyUserId -type. Just make sure that the property is available for all classifications and the elements are classified. Otherwise, the Excel worksheet will have a blank cell for unclassified elements. Call this property in the same way in the Python script as in the example above.

 

These two types work with doors and windows but not with objects. Therefore, they return a blank value to cells in an Excel worksheet.

    act.BuiltInPropertyUserId("General_FromZone"),
    act.BuiltInPropertyUserId("General_FromZoneNumber"),

 

These two, in other hand, should work with the objects. At least I got the right data transferred to Excel.  The only time the data didn't show up in the Excel file was when the layer of the zones was invisible in the project when running the script.

    act.BuiltInPropertyUserId("General_RelatedZoneName"),
    act.BuiltInPropertyUserId("General_RelatedZoneNumber"),

 

-JT