Overview
Data traversal is the systematic process of navigating Speckle’s object graphs to extract data, find specific objects, and preserve hierarchical context. Understanding traversal is fundamental to working with Speckle data effectively.Prerequisites: This guide assumes familiarity with the Base
class and data
types. If you’re new to Speckle objects, start with
those concepts first.
- Extract all objects of a specific type (e.g., all walls, all meshes)
- Preserve parent-child relationships and organizational context
- Filter data based on properties or structure
- Build analysis pipelines that understand object hierarchies
- Graph Structure: Objects are connected through properties (parent → child relationships)
- Traversal: The process of visiting every object in a graph systematically
- Filtering: Selecting only objects that match specific criteria during traversal
- Flattening: Converting a hierarchical graph into a flat list of objects
Understanding Object Graphs
Speckle data comes in different structural complexities depending on the source and use case. Understanding these patterns helps you choose the right traversal strategy.Simple Graph (Custom Data)
Medium Graph (Simple Model)
Complex Graph (BIM Data)
Why Traversal Matters
Different data structures require different traversal strategies:Common Traversal Goals
- Find specific objects - “Get all walls” or “Find all meshes”
- Extract properties - “List all volumes” or “Get material quantities”
- Flatten hierarchy - “Convert nested structure to flat list”
- Group objects - “Organize by level” or “Group by category”
- Analyze relationships - “Which objects are on Level 1?”
Traversal Strategies Explained
For v3 Data: The most effective strategies are Property-Filtered, displayValue-Based,
and elements[] Hierarchy traversal. Type-filtered traversal using
speckle_type is primarily
useful for geometry primitives (Mesh, Point, Line) but not for BIM objects, which are now generic
DataObject instances with semantics in their properties.Strategy 1: Property-Filtered Traversal ⭐ Recommended for v3
When to use: Working with BIM data from connectors (Revit, Rhino, ArchiCAD, etc.). How it works:- Traverse recursively
- Check if object has a
propertiesdictionary - Filter based on property values (e.g.,
category == "Walls") - Collect matching objects
- v3 BIM objects (DataObject)
- Finding objects by category, family, type
- Filtering by quantities or metadata
- Most common pattern for modern Speckle data
- “Find all walls” → filter by
properties.category == "Walls" - “Get steel beams” → filter by
properties.category == "Structural Framing"ANDproperties.material == "Steel" - “Objects on Level 1” → filter by
properties.level == "Level 1"
Strategy 2: displayValue-Based Traversal ⭐ Recommended for v3
When to use: You only want atomic, viewer-selectable objects. How it works:- Traverse recursively
- Collect only objects with a
displayValueproperty - These are the objects that appear as selectable items in the viewer
- Getting viewer-clickable objects
- Counting actual BIM elements (not containers/groups)
- Extracting geometry for visualization
- Distinguishing atomic objects from organizational containers
Strategy 3: elements[] Hierarchy Traversal
When to use: Objects are organized in a logical hierarchy usingelements[] arrays.
The
elements property is Speckle’s standardized convention for organizing hierarchical data. See
The elements Convention for
a detailed explanation of this pattern.- Check if object has an
elementsproperty (list) - Recursively traverse only the elements array
- Optionally filter during traversal
- Ignores other properties
- Collections and Groups
- Organized BIM hierarchies (Level → Room → Elements)
- When you only care about the logical organization, not nested geometry
Strategy 4: Full Recursive Traversal
When to use: You need to visit EVERY object in the graph, regardless of type or depth. How it works:- Start at root object
- Visit each property on the object
- For each property that’s a Base object, list, or dict, recurse into it
- Continue until all branches are explored
- Finding rare objects that could be anywhere
- Building complete inventories
- Ensuring nothing is missed
Strategy 5: Type-Filtered Traversal (Limited Use in v3)
When to use: Looking for geometry primitives (Mesh, Point, Line, etc.). How it works:- Traverse recursively
- Check each object’s
speckle_typeproperty - Collect only objects matching the target type
- Continue traversing to find all instances
- Finding geometry objects (Mesh, Line, Point, Arc, Circle, etc.)
- Pure geometry workflows
- Legacy v2 objects with typed BIM classes
Choosing the Right Pattern
Use this decision tree for v3 data:Basic Traversal Techniques
Technique 1: Direct Property Access
When to use: You know the exact structure and property names. Advantages: Fastest, most efficient, no unnecessary traversal.Technique 2: Iterate All Members
When you want to explore:Technique 3: Recursive Search
Find all objects matching criteria:Pattern 1: Find by Property ⭐ Primary Pattern for v3
Purpose: Search for objects based on their properties (the standard v3 pattern). When to use:- Working with BIM data from any connector (Revit, Rhino, ArchiCAD, etc.)
- Need to find objects by category, family, type, level, material
- Filtering by quantities, parameters, or metadata
- This is the primary pattern for modern Speckle data
- Recursively traverse all objects
- Check if object has
propertiesdictionary - Filter based on property values
- Collect matches
- Working with v3 BIM data (DataObject)
- Need to find objects by category (“Walls”, “Columns”, “Floors”)
- Filtering by BIM properties (loadBearing, fireRating, family, type)
- Need to find objects with specific quantities or metadata
- Works with v3 object model
- Can filter on any property value
- Can combine multiple property conditions
- Reflects how BIM data is actually organized
- Traverse all objects
- Check if object is a DataObject
- Access the
propertiesdictionary - Filter based on property values
- Collect matches
Pattern 2: Find by Type (Geometry Only)
Purpose: Search for geometry primitives byspeckle_type.
When to use:
- Looking for geometry objects (Mesh, Point, Line, Arc, Circle, etc.)
- Pure geometry workflows without BIM semantics
- Need to find all instances of a specific geometry class
- ❌ BIM data from connectors (use Pattern 1 - Find by Property instead)
- ❌ Need to differentiate walls from columns (use properties)
- ❌ Any data where semantics are in the properties dictionary
Pattern 3: Build Flat List
Purpose: Convert hierarchical object graphs into flat lists for easier processing. When to use:- Need to process all objects of a certain type
- Want to use list operations (filter, map, sort)
- Building dataframes or CSV exports
- Running aggregate calculations (sum, average, count)
- Easier to work with than nested structures
- Can use standard Python list operations
- Simple to convert to pandas DataFrame
- Good for batch processing
- Loses hierarchical relationships
- Can be memory-intensive for large models
- May include objects you don’t need
- Start with empty results list
- Traverse entire object graph
- Collect objects matching criteria
- Return flat list
Pattern 3a: Traverse elements[] Arrays
Purpose: Navigate object hierarchies by following the organizational structure defined byelements[] arrays.
When to use:
- Data is organized in Collections or Groups
- Objects have a logical hierarchy (Building → Level → Room → Elements)
- Want to respect the intentional organization
- Need faster traversal by ignoring non-structural properties
- Check if object has
elementsproperty (list) - Recursively traverse only through elements arrays
- Optionally filter during traversal
- Ignore other properties like displayValue, geometry, etc.
elements[] to define parent-child relationships:
- Collection objects have
elementscontaining child objects - Group objects organize related objects in
elements - Level hierarchies nest objects in
elements
- Faster than full traversal
- Follows logical organization
- Respects data structure intent
- Avoids traversing geometry details
Pattern 3b: Find Atomic/Displayable Objects
Purpose: Find only atomic, viewer-selectable objects by filtering fordisplayValue presence.
When to use:
- Need to count actual BIM elements (not containers or groups)
- Want objects that appear as selectable items in the viewer
- Building element lists for UI selection
- Extracting objects that have visual representation
- Need to match what users see in the 3D viewer
- Containers (Collections, Groups) organize but aren’t selectable
- Proxies (LevelProxy, ColorProxy) reference but aren’t rendered
- Atomic objects have
displayValueand ARE selectable in the viewer
Why displayValue matters: Objects with a
displayValue property represent atomic, selectable
items in the Speckle viewer. Each object with displayValue can be clicked, selected, and queried
independently in the 3D view. The displayValue typically contains a list of Mesh objects that
define the visual representation.- Traverse the entire graph
- Check if object has
displayValueproperty - Verify
displayValueis not None - Collect these objects
- Optionally filter further by properties
Combined Pattern: Elements + DisplayValue
Purpose: Efficiently find atomic BIM objects by combining structural traversal with displayValue filtering. When to use:- Large BIM models where full traversal is slow
- Data is organized in elements[] hierarchy
- Only want viewer-selectable objects
- Need to skip containers and organizational objects
- Faster than full traversal (follows elements[] only)
- More precise than elements[] alone (filters to atomic objects)
- Gets you exactly what users see in the viewer
- Skips geometry details and nested references
displayValue are typically leaf nodes - they don’t have children with displayValues. This means you can stop traversing deeper once you find a displayValue, making traversal much more efficient.
Strategy:
- Traverse through elements[] arrays only (ignore other properties)
- At each object, check for displayValue
- Collect objects that have displayValue and STOP traversing deeper
- Skip containers and organizational objects automatically
Pattern 4: Group by Property
Purpose: Organize flat lists of objects into groups based on shared property values. When to use:- Need to analyze objects by category, type, or level
- Building summaries (“count by type”)
- Preparing data for reports or charts
- Want to process each group separately
- Need to find relationships between objects
- By BIM category (Walls, Columns, Floors)
- By level/storey (“Level 1”, “Level 2”)
- By family or type
- By material
- By any property value
- First, flatten objects (Pattern 3)
- Iterate through flat list
- Extract grouping property from each object
- Build dictionary with property value as key
- Append objects to appropriate group
Pattern 5: Extract to DataFrame
Convert graph to tabular data:Pattern 6: Count by Type
Quick statistics:Handling Unknown Structures
When you don’t know the structure ahead of time:Performance Optimization
Memoization
Cache traversal results:Early Termination
Stop when found:Complete Example: Building Analysis
Best Practices
Always check property existence
Always check property existence
Use
hasattr() before accessing: python # Good if hasattr(obj, "displayValue"): mesh = obj.displayValue # Bad - can crash mesh = obj.displayValue Skip private members
Skip private members
Don’t traverse
_ prefixed properties: python # Good for name in obj.get_member_names(): if not name.startswith("_"): value = getattr(obj, name) # Bad - includes internals for name in dir(obj): value = getattr(obj, name) Handle both lists and single values
Handle both lists and single values
Properties can be lists or single objects:
python # Good display = obj.displayValue meshes = display if isinstance(display, list) else [display] # Bad - assumes always list for mesh in obj.displayValue: # Crashes if not list pass Use type filters to reduce traversal
Use type filters to reduce traversal
Limit traversal scope when possible:
python # Good - focused property search (v3 pattern) walls = find_by_property(obj, "category", "Walls") # Less good - searches everything then filters all_objects = find_all(obj, lambda x: True) walls = [o for o in all_objects if hasattr(o, "properties") and o.properties.get("category") == "Walls"] Summary
Effective traversal requires:- ✅ Understanding the graph - Know if it’s simple, medium, or complex
- ✅ Choosing the right pattern - Type, property, flatten, group
- ✅ Defensive coding - Check before accessing
- ✅ Performance awareness - Cache results, terminate early
- ✅ Flexibility - Handle unknown structures gracefully
Next Steps
BIM Data Patterns
Apply these traversal techniques to complex BIM data
Simple Data Patterns
Working with custom and simple model data
Data Types
Understanding the three types of data
API Reference
Client and operations API documentation