Python. Getting all Revit built-in subcategories

Hello,

I would like to get all Built-in categories and subcategories, but doing this script in python I only can get by the Categories.

import System
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

doc = DocumentManager.Instance.CurrentDBDocument

#create workset collector
userCategories = doc.Settings.Categories
#extract workset's name and ids
names, ids, builtInNames = [], [], []
for i in userCategories:
	try:
		names.append(i.Name)
	except:
		names.append("failure")
	try:
		ids.append(i.Id.IntegerValue)
	except:
		ids.append("failure")
	try:
		tempID = i.Id.IntegerValue
	except:
		tempID = "failure"
	try:
		builtInNames.append(System.Enum.ToObject(BuiltInCategory, tempID))
	except:
		builtInNames.append("failure")

builtInNameStr = []
for y in builtInNames:
	try:
		builtInNameStr.append(str(y))
	except:
		builtInNameStr.append("stringConversionFailure")

OUT = userCategories, names, ids, builtInNameStr, builtInNames

This doesn’t quite make sense to me, as elements can contain geometry in multiple sub-categories… Are you after just the geometry of a given sub-category?

2 Likes

I want to know if there are instances of subcategories in the revit documents, so my input would be a list of BUILT-IN subcategories but I get it to work with categories only so I want to expand on this because for exampleI could not get the internal origin, project base point which are under the Category Site. Geometry sounds a joke here

1 Like

Hi All
You can use lookup node into BriMohareb_2023 package. To get all geometry in the selection element then filter by the subcategory you need. Or use “get geo by subcategory” node in the same package.

image

what do you mean by sub-category? any example?

Not sure you can do this at project level. My first thinking would be to programatically edit/check/close all loadable families in background and report any that have the object styles present in them of a given name. You could limit by one category given they dont cross categories so wouldnt be too exhaustive.

Hello @GavinCrump I just want to be able to get all elements of built in subcategories by giving their name as input, for example Site - Internal Origin, which built-in category is something like OST_InternalOrigin. I don’t need user created subcategories of loadable families and i don’t need to get any geometry, just any project instance elements with the ID

Hi,
maybe like this ?

1 Like

It works but I only want to get Built-in subcategories from that allSubcategories output

something like this?

1 Like

Perhaps adding a check to get the parent will help, as any sub category will return a value while non-sub categories will return a null value.

hello, I tried it and it does what I need, although I think for this case I would need only builtin categories in case of the subcategories in any families placed on the project are identical than other Builtin category.

I resolved partially modifying this part of the code but I cannot get the builtInNames because some of them thay are not builtin, so I get null result based on the code shared above.

AllCategories = doc.Settings.Categories
AllSubCategories = [subcat for cat in doc.Settings.Categories for subcat in cat.SubCategories]

userCategories=[x for n in (AllCategories,AllSubCategories) for x in n]

you can use OfCategoryId() method

import sys
import clr
import System
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument

def ElementsByCategory(category, document=doc):
	collector = FilteredElementCollector(document).OfCategoryId(category.Id).WhereElementIsNotElementType()
	return list(collector)

all_Elems_byCategories = sum([ElementsByCategory(cat) for cat in doc.Settings.Categories], [])
all_Elems_by_SubCategories = sum([ElementsByCategory(subcat) for cat in doc.Settings.Categories for subcat in cat.SubCategories], [])

OUT = all_Elems_byCategories, all_Elems_by_SubCategories
1 Like

thank you very much, all working great, I do not want to get all elements, I want to get the categories first, your first answer was quite right and it works, although I would like to filter only the built-in subcategories. Maybe there is a straight forward code to get built-in subcategories?
image

Could you check if the category is a built in before proceeding?

If this returns null you’ve got a non-built in category.

1 Like

an other way

import sys
import clr
import System
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument

def ElementsByCategory(category, document=doc):
	collector = FilteredElementCollector(document).OfCategoryId(category.Id).WhereElementIsNotElementType()
	return list(collector)

dictBic = {ElementId(bic) : bic for bic in System.Enum.GetValues(BuiltInCategory)}
allsubCategories = [cat for cat in doc.Settings.Categories if cat.Id in dictBic]
all_Elems_by_SubCategories = sum([ElementsByCategory(subcat) for cat in allsubCategories for subcat in cat.SubCategories], [])

OUT = all_Elems_by_SubCategories
5 Likes

very smart and short code, thanks, quite a lot to keep learning