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 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 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 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 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
class ConfidenceBatch(rr.ComponentBatchMixin):
"""A batch of confidence data."""
def __init__(self: Any, confidence: npt.ArrayLike) -> None:
self.confidence = confidence
def component_descriptor(self) -> rr.ComponentDescriptor:
"""The descriptor of the custom component."""
return rr.ComponentDescriptor("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, positions: npt.ArrayLike, confidences: npt.ArrayLike) -> None:
self.points3d = rr.Points3D(positions)
self.confidences = ConfidenceBatch(confidences).or_with_descriptor_overrides(
archetype_name="user.CustomPoints3D", archetype_field_name="confidences"
)
def as_component_batches(self) -> Iterable[rr.ComponentBatchLike]:
return (
list(self.points3d.as_component_batches()) # The components from Points3D
+ [rr.IndicatorComponentBatch("user.CustomPoints3D")] # Our custom indicator
+ [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(
positions=point_grid,
confidences=[42],
),
)
rr.log(
"right/my_polarized_point_cloud",
CustomPoints3D(positions=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, views work under the hood using a variety of systems. For more information see the Extend the Viewer in Rust section.