Entities and Components

Data model data-model

The core of Rerun's data model is inspired by the ideas of the Entity Component System (ECS) architecture pattern. In short, an ECS is a composition-oriented framework in which entities represent generic objects while components describe data associated with those entities.

  • Entities are the "things" that you log with the rr.log()function. They are represented by the entity path string which is passed as first argument.
  • Components, however, are what contains the data that is associated with those "things". For example, position, color, pixel data, etc.

Entities are like folders, and components are like files.

Additionally, the Rerun SDKs expose two additional concepts:

  • Archetypes are coherent set of components corresponding to primitive such as 2D points or 3D boxes. In the Rerun SDKs, archetypes take the form of builder objects that assist with the creation of such component sets. They are meant as high-level, convenience helpers that can be bypassed entirely if/when required by advanced use-cases.
  • Datatypes are regular data structures that components occasionally rely on when fundamental data types (float, uint32, etc.) are not sufficient.

Logging and viewing data logging-and-viewing-data

All the data that you log within Rerun is mapped to the concepts of entities and components. For example, consider the case of logging a point:

rr.log("my_point", rr.Points2D([32.7, 45.9], color=[255, 0, 0]))

This statement uses the rr.Points2D archetype. Internally, this archetype builds a set of, in this case, two components: Position2D and Color. Then, the rr.log() function records these two components and associate them with the "my_point" entity.

Later, the Space View for spatial types queries the data store for all the entities that have a Position2D component. In this case it would find the "my_point" entity. This query additionally returns the Color component because that component is associated with the same entity. These two components are recognized as corresponding to the Points2D archetype, which informs the Viewer on how to display the corresponding entity.

See the Types reference for a list of archetypes, components, and datatypes.

Adding custom data adding-custom-data

Although both the SDKs' archetype objects and the space view are based on the same archetype definition (and are actually implemented using code that is automatically generated based on that definition), they both operate on arbitrary collection of components. Neither the SDKs nor the Viewer enforce or require that an entity should contain a specific set of component. The Rerun Viewer will display any data in a generic form, but its space views will only work on sets of components it can make sense of.

Your entity could have any number of additional components as well. This isn't a problem. Any components that aren't relevant to the scene that the space view is drawing are safely ignored. Also, Rerun even allows you to log your own set of components, bypassing archetypes altogether.

In Python, the rr.AnyValues helper object can be used to add custom component(s) to an archetype:

"""Log extra values with a Points2D."""

import rerun as rr
import rerun.blueprint as rrb

rr.init("rerun_example_extra_values", spawn=True)

rr.log(
    "extra_values",
    rr.Points2D([[-1, -1], [-1, 1], [1, -1], [1, 1]]),
    rr.AnyValues(
        confidence=[0.3, 0.4, 0.5, 0.6],
    ),
)

# Set view bounds:
rr.send_blueprint(rrb.Spatial2DView(visual_bounds=rrb.VisualBounds2D(x_range=[-1.5, 1.5], y_range=[-1.5, 1.5])))

It can also be used log an entirely custom set of components:

"""Log arbitrary data."""

import rerun as rr

rr.init("rerun_example_any_values", spawn=True)

rr.log(
    "any_values",
    rr.AnyValues(
        confidence=[1.2, 3.4, 5.6],
        description="Bla bla bla…",
    ),
)

For more complex use-cases, custom objects implementing the rr.AsComponents protocol can be used. For Rust, the rerun::AsComponents trait must be implemented:

#!/usr/bin/env python3
"""Shows how to implement custom archetypes and components."""

from __future__ import annotations

import argparse
from typing import Any, Iterable

import numpy as np
import numpy.typing as npt
import pyarrow as pa
import rerun as rr  # pip install rerun-sdk


class ConfidenceBatch(rr.ComponentBatchLike):
    """A batch of confidence data."""

    def __init__(self: Any, confidence: npt.ArrayLike) -> None:
        self.confidence = confidence

    def component_name(self) -> str:
        """The name of the custom component."""
        return "user.Confidence"

    def as_arrow_array(self) -> pa.Array:
        """The arrow batch representing the custom component."""
        return pa.array(self.confidence, type=pa.float32())


class CustomPoints3D(rr.AsComponents):
    """A custom archetype that extends Rerun's builtin `Points3D` archetype with a custom component."""

    def __init__(self: Any, points3d: npt.ArrayLike, confidences: npt.ArrayLike) -> None:
        self.points3d = points3d
        self.confidences = confidences

    def as_component_batches(self) -> Iterable[rr.ComponentBatchLike]:
        points3d = np.asarray(self.points3d)
        return (
            list(rr.Points3D(points3d).as_component_batches())  # The components from Points3D
            + [rr.IndicatorComponentBatch("user.CustomPoints3D")]  # Our custom indicator
            + [ConfidenceBatch(self.confidences)]  # Custom confidence data
        )


def log_custom_data() -> None:
    lin = np.linspace(-5, 5, 3)
    z, y, x = np.meshgrid(lin, lin, lin, indexing="ij")
    point_grid = np.vstack([x.flatten(), y.flatten(), z.flatten()]).T

    rr.log(
        "left/my_confident_point_cloud",
        CustomPoints3D(
            points3d=point_grid,
            confidences=[42],
        ),
    )

    rr.log(
        "right/my_polarized_point_cloud",
        CustomPoints3D(points3d=point_grid, confidences=np.arange(0, len(point_grid))),
    )


def main() -> None:
    parser = argparse.ArgumentParser(description="Logs rich data using the Rerun SDK.")
    rr.script_add_args(parser)
    args = parser.parse_args()

    rr.script_setup(args, "rerun_example_custom_data")
    log_custom_data()
    rr.script_teardown(args)


if __name__ == "__main__":
    main()

Empty entities empty-entities

An entity without components is nothing more than an identity (represented by its entity path). It contains no data, and has no type. When you log a piece of data, all that you are doing is setting the values of one or more components associated with that entity.

ECS systems ecs-systems

There is a third concept we haven't touched on: systems are processes which operate on the entities based on the components they possess. Rerun is still settling on the exact form of formalized systems and outside of Rust Viewer code it is not yet possible to write your own systems. However, space views work under the hood using a variety of systems. For more information see the Extend the Viewer in Rust section.