Properties and segment tables
Properties are recording-level metadata that relates to an entire segment. When you query a dataset, properties appear as columns in the segment table and can be used to filter, sort, and analyze your segments. Common use cases for properties include tagging recordings with capture location, data format version, environmental conditions, or any other custom metadata relevant to your workflow.
Understanding properties understanding-properties
Let's use an example to illustrate how properties work and how they can be retrieved and queried using the Rerun Data Platform.
First, we create a few recordings with some properties:
rrd_paths = [RRD_DIR / f"recording_{i}.rrd" for i in range(5)]
for i, rrd_path in enumerate(rrd_paths):
with rr.RecordingStream("rerun_example_property") as rec:
rec.save(rrd_path)
rec.log("data", rr.Points2D(positions=[[i, i]]))
# properties can be any rerun data
rec.send_property("location", rr.GeoPoints(lat_lon=[[46.5, 6.5]]))
# custom data can be logged with `AnyValues`
rec.send_property(
"info",
rr.AnyValues(
index=i,
is_odd=i % 2 == 1,
),
)
# recording name is part of the built-in properties
rr.send_recording_name(f"segment_{i}")In this example, we use send_property() to attach metadata to each recording. Properties are regular Rerun data, so you can use any built-in archetype. Here we use GeoPoints to store a geographic location. For arbitrary data that doesn't fit an existing archetype, use AnyValues.
In addition to user-provided properties, Rerun automatically stores built-in properties using the RecordingInfo archetype.
Its start_time field is automatically populated, and its name field can be set with send_recording_name().
Internally, properties are logged under a reserved /__properties entity path and use static semantics since they apply to the entire recording rather than specific points in time.
Querying the segment table querying-the-segment-table
Once recordings are registered to a dataset, their properties become visible and queryable through the segment table. Here we use the local open-source Data Platform included with Rerun to illustrate this:
# load the demo recording in a temporary catalog
with rr.server.Server(datasets={"dataset": rrd_paths}) as server:
# obtain a dataset from the catalog
dataset = server.client().get_dataset("dataset")
segment_table = dataset.segment_table()
# sort and select columns of interest
segment_table = segment_table.sort(col("property:RecordingInfo:name")[0]).select(
"rerun_segment_id",
"property:RecordingInfo:name",
"property:RecordingInfo:start_time",
"property:info:index",
"property:info:is_odd",
"property:location:GeoPoints:positions",
)
print(segment_table)Output:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā rerun_segment_id ā property:RecordingInfo:name ā property:RecordingInfo:start_time ā property:info:index ā property:info:is_odd ā property:location:GeoPoints:positions ā
ā --- ā --- ā --- ā --- ā --- ā --- ā
ā type: Utf8 ā type: nullable List[nullable Utf8] ā type: nullable List[nullable i64] ā type: nullable List[nullable i64] ā type: nullable List[nullable bool] ā type: nullable List[nullable FixedSizeList[nullable f64; 2]] ā
ā ā archetype: RecordingInfo ā archetype: RecordingInfo ā component: index ā component: is_odd ā archetype: GeoPoints ā
ā ā component: RecordingInfo:name ā component: RecordingInfo:start_time ā entity_path: /__properties/info ā entity_path: /__properties/info ā component: GeoPoints:positions ā
ā ā component_type: Name ā component_type: Timestamp ā kind: data ā kind: data ā component_type: LatLon ā
ā ā entity_path: /__properties ā entity_path: /__properties ā ā ā entity_path: /__properties/location ā
ā ā kind: data ā kind: data ā ā ā kind: data ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā”
ā 4cc4df9667fd4c308c4e3511b5e0da98 ā [segment_0] ā [1769101329662761000] ā [0] ā [false] ā [[46.5, 6.5]] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā 473ec142a9464d51a1ee51cac71304ac ā [segment_1] ā [1769101329954056000] ā [1] ā [true] ā [[46.5, 6.5]] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā 444dc0d31567473ab6dd5e48c53423e5 ā [segment_2] ā [1769101329955512000] ā [2] ā [false] ā [[46.5, 6.5]] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā c66ec19194ca48648799d1e9d60c6fe6 ā [segment_3] ā [1769101329956199000] ā [3] ā [true] ā [[46.5, 6.5]] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā 2ef8804c3979415a8f8d35dc2b2adfa4 ā [segment_4] ā [1769101329957042000] ā [4] ā [false] ā [[46.5, 6.5]] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāThe segment table contains one row per recording, with each property appearing as a column.
The column metadata exposes the fact that properties are stored under the reserved /__properties entity path.
For simplicity, the column names are however prefixed with property: instead of the full entity path.
Since the segment table is a DataFusion DataFrame, you can use standard DataFrame operations for further processing and/or data conversion. For example, this is how the segment table can be filtered based on the values of a custom property:
interesting_segments = segment_table.filter(col("property:info:is_odd")[0])
print(interesting_segments)
Output:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā rerun_segment_id ā property:RecordingInfo:name ā property:RecordingInfo:start_time ā property:info:index ā property:info:is_odd ā property:location:GeoPoints:positions ā
ā --- ā --- ā --- ā --- ā --- ā --- ā
ā type: Utf8 ā type: nullable List[nullable Utf8] ā type: nullable List[nullable i64] ā type: nullable List[nullable i64] ā type: nullable List[nullable bool] ā type: nullable List[nullable FixedSizeList[nullable f64; 2]] ā
ā ā archetype: RecordingInfo ā archetype: RecordingInfo ā component: index ā component: is_odd ā archetype: GeoPoints ā
ā ā component: RecordingInfo:name ā component: RecordingInfo:start_time ā entity_path: /__properties/info ā entity_path: /__properties/info ā component: GeoPoints:positions ā
ā ā component_type: Name ā component_type: Timestamp ā kind: data ā kind: data ā component_type: LatLon ā
ā ā entity_path: /__properties ā entity_path: /__properties ā ā ā entity_path: /__properties/location ā
ā ā kind: data ā kind: data ā ā ā kind: data ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā”
ā 473ec142a9464d51a1ee51cac71304ac ā [segment_1] ā [1769101329954056000] ā [1] ā [true] ā [[46.5, 6.5]] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā c66ec19194ca48648799d1e9d60c6fe6 ā [segment_3] ā [1769101329956199000] ā [3] ā [true] ā [[46.5, 6.5]] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāFAQ faq
How are properties stored in the recording? how-are-properties-stored-in-the-recording
Properties are stored under the reserved /__properties entity path and are logged as static data, meaning they have no timeline association.
Logging directly under this entity path is not recommended.
Use the rr.send_property() or RecordingStream.send_property() API instead.
How are property columns named? how-are-property-columns-named
Property column names follow this general pattern:
property:$property_name:$Archetype:$fieldwhere $property_name is the name provided to send_property(), and $Archetype:$field is derived from the property data.
For example, a GeoPoints archetype logged under the entity location appears as property:location:GeoPoints:positions.
For built-in properties, the $property_name part is omitted, e.g., property:RecordingInfo:name.
The rr.AnyValues helper logs data without a defined archetype.
As a result, the corresponding columns do not have the $Archetype part, e.g., property:info:index.
Are properties visible in dataframe queries? are-properties-visible-in-dataframe-queries
Yes.
Dataframe queries can access properties by explicitly including the /__properties/** entity path filter, which is excluded by default.
When queried this way, the property column names follow the same rules described above.
df = dataset.filter_contents("__properties/*").reader(index=None)
df = df.sort("property:RecordingInfo:name").select(
"rerun_segment_id", "property:RecordingInfo:name", "property:info:index"
)
print(df)Output:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā rerun_segment_id ā property:RecordingInfo:name ā property:info:index ā
ā --- ā --- ā --- ā
ā type: Utf8 ā type: nullable List[nullable Utf8] ā type: nullable List[nullable i64] ā
ā ā archetype: RecordingInfo ā component: index ā
ā ā component: RecordingInfo:name ā entity_path: /__properties/info ā
ā ā component_type: Name ā is_static: true ā
ā ā entity_path: /__properties ā kind: data ā
ā ā is_static: true ā ā
ā ā kind: data ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāŖāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā”
ā 8e59232215294cb39bc35dad5605bdce ā [segment_0] ā [0] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā 2067b4357dd744648ee0462f39c4de14 ā [segment_1] ā [1] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā 2cf0ff4e3a8c4cf3a0e00e88050cdb01 ā [segment_2] ā [2] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā 780ac12de8694dc7a9a916ccbb8a7218 ā [segment_3] ā [3] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā 99bc7f4dc0c5469c9d154a1cb01e002c ā [segment_4] ā [4] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāCan the built-in properties be omitted from recordings? can-the-builtin-properties-be-omitted-from-recordings
Yes.
Both rr.init() and RecordingStream() accept a send_properties parameter (default: True).
Set it to False to prevent the built-in RecordingInfo properties from being automatically sent when the recording is created.