Skip to main content

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.
Speckle objects form hierarchical graphs - tree-like structures where objects contain other objects, arrays of objects, and references to objects stored elsewhere. Unlike simple flat lists, these graphs require strategic navigation to:
  • 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
Key Concepts:
  • 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

  1. Find specific objects - “Get all walls” or “Find all meshes”
  2. Extract properties - “List all volumes” or “Get material quantities”
  3. Flatten hierarchy - “Convert nested structure to flat list”
  4. Group objects - “Organize by level” or “Group by category”
  5. 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.
When to use: Working with BIM data from connectors (Revit, Rhino, ArchiCAD, etc.). How it works:
  • Traverse recursively
  • Check if object has a properties dictionary
  • Filter based on property values (e.g., category == "Walls")
  • Collect matching objects
Best for:
  • v3 BIM objects (DataObject)
  • Finding objects by category, family, type
  • Filtering by quantities or metadata
  • Most common pattern for modern Speckle data
Example use cases:
  • “Find all walls” → filter by properties.category == "Walls"
  • “Get steel beams” → filter by properties.category == "Structural Framing" AND properties.material == "Steel"
  • “Objects on Level 1” → filter by properties.level == "Level 1"
When to use: You only want atomic, viewer-selectable objects. How it works:
  • Traverse recursively
  • Collect only objects with a displayValue property
  • These are the objects that appear as selectable items in the viewer
Best for:
  • Getting viewer-clickable objects
  • Counting actual BIM elements (not containers/groups)
  • Extracting geometry for visualization
  • Distinguishing atomic objects from organizational containers
Key insight: Objects without displayValue are typically containers, not atomic elements.

Strategy 3: elements[] Hierarchy Traversal

When to use: Objects are organized in a logical hierarchy using elements[] arrays.
The elements property is Speckle’s standardized convention for organizing hierarchical data. See The elements Convention for a detailed explanation of this pattern.
How it works:
  • Check if object has an elements property (list)
  • Recursively traverse only the elements array
  • Optionally filter during traversal
  • Ignores other properties
Best for:
  • Collections and Groups
  • Organized BIM hierarchies (Level → Room → Elements)
  • When you only care about the logical organization, not nested geometry
Advantage: Faster than full traversal, follows intentional structure

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
Best for:
  • Finding rare objects that could be anywhere
  • Building complete inventories
  • Ensuring nothing is missed
Cost: Slowest, visits everything

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_type property
  • Collect only objects matching the target type
  • Continue traversing to find all instances
Best for:
  • Finding geometry objects (Mesh, Line, Point, Arc, Circle, etc.)
  • Pure geometry workflows
  • Legacy v2 objects with typed BIM classes
Limited Use in v3 BIM Data: Most BIM objects from connectors are now DataObject instances with speckle_type = "Objects.Data.DataObject". Filtering by this type returns ALL BIM objects without differentiation. For BIM data, use Property-Filtered Traversal (Strategy 1) instead to filter by category, family, type, etc.

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:
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
How it works:
  1. Recursively traverse all objects
  2. Check if object has properties dictionary
  3. Filter based on property values
  4. Collect matches
Purpose: Find objects based on their properties dictionary values (v3 BIM pattern). When to use:
  • 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
Advantages:
  • Works with v3 object model
  • Can filter on any property value
  • Can combine multiple property conditions
  • Reflects how BIM data is actually organized
How it works:
  1. Traverse all objects
  2. Check if object is a DataObject
  3. Access the properties dictionary
  4. Filter based on property values
  5. Collect matches

Pattern 2: Find by Type (Geometry Only)

Purpose: Search for geometry primitives by speckle_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
When NOT to use:
  • ❌ 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
Limited Use for BIM Data: In v3, BIM objects are DataObject instances with speckle_type = "Objects.Data.DataObject". All walls, columns, beams, etc. have the same type. To find specific BIM elements, use Pattern 1 (Find by Property) to filter by category, family, type, etc.

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)
Advantages:
  • Easier to work with than nested structures
  • Can use standard Python list operations
  • Simple to convert to pandas DataFrame
  • Good for batch processing
Disadvantages:
  • Loses hierarchical relationships
  • Can be memory-intensive for large models
  • May include objects you don’t need
How it works:
  1. Start with empty results list
  2. Traverse entire object graph
  3. Collect objects matching criteria
  4. Return flat list
Alternative: Property-based flattening (most flexible):

Pattern 3a: Traverse elements[] Arrays

Purpose: Navigate object hierarchies by following the organizational structure defined by elements[] 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
How it works:
  1. Check if object has elements property (list)
  2. Recursively traverse only through elements arrays
  3. Optionally filter during traversal
  4. Ignore other properties like displayValue, geometry, etc.
Key concept: Many Speckle objects use elements[] to define parent-child relationships:
  • Collection objects have elements containing child objects
  • Group objects organize related objects in elements
  • Level hierarchies nest objects in elements
Advantages:
  • 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 for displayValue 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
Key concept: Not all objects in the graph are “real” elements:
  • Containers (Collections, Groups) organize but aren’t selectable
  • Proxies (LevelProxy, ColorProxy) reference but aren’t rendered
  • Atomic objects have displayValue and 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.
How it works:
  1. Traverse the entire graph
  2. Check if object has displayValue property
  3. Verify displayValue is not None
  4. Collect these objects
  5. Optionally filter further by properties
Result: A list of objects that exactly matches what users can select in the viewer.

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
Advantages:
  • 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
Key Optimization: Objects with 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:
  1. Traverse through elements[] arrays only (ignore other properties)
  2. At each object, check for displayValue
  3. Collect objects that have displayValue and STOP traversing deeper
  4. 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
Common groupings:
  • By BIM category (Walls, Columns, Floors)
  • By level/storey (“Level 1”, “Level 2”)
  • By family or type
  • By material
  • By any property value
How it works:
  1. First, flatten objects (Pattern 3)
  2. Iterate through flat list
  3. Extract grouping property from each object
  4. Build dictionary with property value as key
  5. Append objects to appropriate group
Result: Dictionary where keys are property values and values are lists of objects.

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

Use hasattr() before accessing: python # Good if hasattr(obj, "displayValue"): mesh = obj.displayValue # Bad - can crash mesh = obj.displayValue
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)
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
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
These patterns work with any Speckle data structure!

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
Last modified on July 18, 2026