Skip to content

Commit 27084ad

Browse files
teh-cmcWumpf
andauthored
End-to-end tagging: basic helpers for Python & Rust (#8332)
Introduce some very basic helpers so that overriding tags doesn't require a PhD. The goal here is not _great_, it's simply _not completely horrible_. ## Python Before: ```py class CustomPosition3DBatch(rr.ComponentBatchLike): def __init__(self: Any, positions: npt.ArrayLike) -> None: self.position = rr.components.Position3DBatch(positions) def component_descriptor(self) -> rr.ComponentDescriptor: return rr.ComponentDescriptor( "user.CustomPosition3D", archetype_name="user.CustomPoints3D", archetype_field_name="custom_positions", ) def as_arrow_array(self) -> pa.Array: return self.position.as_arrow_array() class CustomPoints3D(rr.AsComponents): def __init__(self: Any, positions: npt.ArrayLike, colors: npt.ArrayLike) -> None: self.positions = CustomPosition3DBatch(positions) self.colors = rr.components.ColorBatch(colors) def as_component_batches(self) -> Iterable[rr.ComponentBatchLike]: return ( [rr.IndicatorComponentBatch("user.CustomPoints3D")] + [ rr.DescribedComponentBatch( self.positions, self.positions.component_descriptor().or_with_overrides( archetype_name="user.CustomPoints3D", archetype_field_name="custom_positions" ), ) ] + [ rr.DescribedComponentBatch( self.colors, self.colors.component_descriptor().or_with_overrides( archetype_name="user.CustomPoints3D", archetype_field_name="colors" ), ) ] ) ``` After: ```py class CustomPoints3D(rr.AsComponents): def __init__(self: Any, positions: npt.ArrayLike, colors: npt.ArrayLike) -> None: self.positions = rr.components.Position3DBatch(positions).with_descriptor( rr.ComponentDescriptor( "user.CustomPosition3D", archetype_name="user.CustomPoints3D", archetype_field_name="custom_positions", ) ) self.colors = rr.components.ColorBatch(colors).or_with_descriptor_overrides( archetype_name="user.CustomPoints3D", archetype_field_name="colors", ) def as_component_batches(self) -> Iterable[rr.ComponentBatchLike]: return [rr.IndicatorComponentBatch("user.CustomPoints3D"), self.positions, self.colors] ``` ## Rust Before: ```rust #[derive(Debug, Clone, Copy)] struct CustomPosition3D(rerun::components::Position3D); impl rerun::SizeBytes for CustomPosition3D { #[inline] fn heap_size_bytes(&self) -> u64 { 0 } } impl rerun::Loggable for CustomPosition3D { #[inline] fn arrow2_datatype() -> arrow2::datatypes::DataType { rerun::components::Position3D::arrow2_datatype() } #[inline] fn to_arrow2_opt<'a>( data: impl IntoIterator<Item = Option<impl Into<std::borrow::Cow<'a, Self>>>>, ) -> rerun::SerializationResult<Box<dyn arrow2::array::Array>> where Self: 'a, { rerun::components::Position3D::to_arrow2_opt( data.into_iter().map(|opt| opt.map(Into::into).map(|c| c.0)), ) } } impl rerun::Component for CustomPosition3D { #[inline] fn descriptor() -> ComponentDescriptor { ComponentDescriptor::new("user.CustomPosition3D") } } struct CustomPoints3D { positions: Vec<CustomPosition3D>, colors: Option<Vec<rerun::components::Color>>, } impl CustomPoints3D { fn indicator() -> rerun::NamedIndicatorComponent { rerun::NamedIndicatorComponent("user.CustomPoints3DIndicator".into()) } fn overridden_position_descriptor() -> ComponentDescriptor { CustomPosition3D::descriptor() .or_with_archetype_name(|| "user.CustomPoints3D".into()) .or_with_archetype_field_name(|| "custom_positions".into()) } fn overridden_color_descriptor() -> ComponentDescriptor { rerun::components::Color::descriptor() .or_with_archetype_name(|| "user.CustomPoints3D".into()) .or_with_archetype_field_name(|| "colors".into()) } } impl rerun::AsComponents for CustomPoints3D { fn as_component_batches(&self) -> Vec<rerun::MaybeOwnedComponentBatch<'_>> { [ Some(Self::indicator().to_batch()), Some( rerun::MaybeOwnedComponentBatch::new(&self.positions as &dyn rerun::ComponentBatch) .with_descriptor_override(Self::overridden_position_descriptor()), ), self.colors.as_ref().map(|colors| { rerun::MaybeOwnedComponentBatch::new(colors as &dyn rerun::ComponentBatch) .with_descriptor_override(Self::overridden_color_descriptor()) }), ] .into_iter() .flatten() .collect() } } ``` After: ```rust struct CustomPoints3D { positions: Vec<rerun::components::Position3D>, colors: Option<Vec<rerun::components::Color>>, } impl CustomPoints3D { fn indicator() -> rerun::NamedIndicatorComponent { rerun::NamedIndicatorComponent("user.CustomPoints3DIndicator".into()) } fn overridden_position_descriptor() -> ComponentDescriptor { ComponentDescriptor { archetype_name: Some("user.CustomPoints3D".into()), archetype_field_name: Some("custom_positions".into()), component_name: "user.CustomPosition3D".into(), } } fn overridden_color_descriptor() -> ComponentDescriptor { <rerun::components::Color as rerun::Component>::descriptor() .or_with_archetype_name(|| "user.CustomPoints3D".into()) .or_with_archetype_field_name(|| "colors".into()) } } impl rerun::AsComponents for CustomPoints3D { fn as_component_batches(&self) -> Vec<rerun::MaybeOwnedComponentBatch<'_>> { [ Some(Self::indicator().to_batch()), Some( self.positions .with_descriptor(Self::overridden_position_descriptor()), ), self.colors .as_ref() .map(|colors| colors.with_descriptor(Self::overridden_color_descriptor())), ] .into_iter() .flatten() .collect() } } ``` ## C++ Too complicated, @Wumpf and I made the wise decision of giving up :upside_down_face: --------- Co-authored-by: Andreas Reich <[email protected]>
1 parent a580884 commit 27084ad

File tree

8 files changed

+107
-178
lines changed

8 files changed

+107
-178
lines changed

crates/store/re_types_core/src/loggable_batch.rs

+12
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ pub trait ComponentBatch: LoggableBatch {
4444
/// Every component batch is uniquely identified by its [`ComponentDescriptor`].
4545
fn descriptor(&self) -> Cow<'_, ComponentDescriptor>;
4646

47+
// Wraps the current [`ComponentBatch`] with the given descriptor.
48+
fn with_descriptor(
49+
&self,
50+
descriptor: ComponentDescriptor,
51+
) -> ComponentBatchCowWithDescriptor<'_>
52+
where
53+
Self: Sized,
54+
{
55+
ComponentBatchCowWithDescriptor::new(ComponentBatchCow::Ref(self as &dyn ComponentBatch))
56+
.with_descriptor_override(descriptor)
57+
}
58+
4759
/// The fully-qualified name of this component batch, e.g. `rerun.components.Position2D`.
4860
///
4961
/// This is a trivial but useful helper for `self.descriptor().component_name`.

docs/snippets/all/descriptors/descr_custom_archetype.py

+12-37
Original file line numberDiff line numberDiff line change
@@ -5,50 +5,25 @@
55
from typing import Any, Iterable
66

77
import numpy.typing as npt
8-
import pyarrow as pa
98
import rerun as rr # pip install rerun-sdk
109

1110

12-
class CustomPosition3DBatch(rr.ComponentBatchLike):
13-
def __init__(self: Any, positions: npt.ArrayLike) -> None:
14-
self.position = rr.components.Position3DBatch(positions)
15-
16-
def component_descriptor(self) -> rr.ComponentDescriptor:
17-
return rr.ComponentDescriptor(
18-
"user.CustomPosition3D",
19-
archetype_name="user.CustomPoints3D",
20-
archetype_field_name="custom_positions",
21-
)
22-
23-
def as_arrow_array(self) -> pa.Array:
24-
return self.position.as_arrow_array()
25-
26-
2711
class CustomPoints3D(rr.AsComponents):
2812
def __init__(self: Any, positions: npt.ArrayLike, colors: npt.ArrayLike) -> None:
29-
self.positions = CustomPosition3DBatch(positions)
30-
self.colors = rr.components.ColorBatch(colors)
13+
self.positions = rr.components.Position3DBatch(positions).with_descriptor(
14+
rr.ComponentDescriptor(
15+
"user.CustomPosition3D",
16+
archetype_name="user.CustomPoints3D",
17+
archetype_field_name="custom_positions",
18+
)
19+
)
20+
self.colors = rr.components.ColorBatch(colors).or_with_descriptor_overrides(
21+
archetype_name="user.CustomPoints3D",
22+
archetype_field_name="colors",
23+
)
3124

3225
def as_component_batches(self) -> Iterable[rr.ComponentBatchLike]:
33-
return (
34-
[rr.IndicatorComponentBatch("user.CustomPoints3D")]
35-
+ [
36-
rr.DescribedComponentBatch(
37-
self.positions,
38-
self.positions.component_descriptor().or_with_overrides(
39-
archetype_name="user.CustomPoints3D", archetype_field_name="custom_positions"
40-
),
41-
)
42-
]
43-
+ [
44-
rr.DescribedComponentBatch(
45-
self.colors,
46-
self.colors.component_descriptor().or_with_overrides(
47-
archetype_name="user.CustomPoints3D", archetype_field_name="colors"
48-
),
49-
)
50-
]
51-
)
26+
return [rr.IndicatorComponentBatch("user.CustomPoints3D"), self.positions, self.colors]
5227

5328

5429
rr.init("rerun_example_descriptors_custom_archetype")

docs/snippets/all/descriptors/descr_custom_archetype.rs

+18-57
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,7 @@
1-
use rerun::{
2-
external::arrow2, ChunkStore, ChunkStoreConfig, Component, ComponentDescriptor, VersionPolicy,
3-
};
4-
5-
#[derive(Debug, Clone, Copy)]
6-
struct CustomPosition3D(rerun::components::Position3D);
7-
8-
impl rerun::SizeBytes for CustomPosition3D {
9-
#[inline]
10-
fn heap_size_bytes(&self) -> u64 {
11-
0
12-
}
13-
}
14-
15-
impl rerun::Loggable for CustomPosition3D {
16-
#[inline]
17-
fn arrow2_datatype() -> arrow2::datatypes::DataType {
18-
rerun::components::Position3D::arrow2_datatype()
19-
}
20-
21-
#[inline]
22-
fn to_arrow2_opt<'a>(
23-
data: impl IntoIterator<Item = Option<impl Into<std::borrow::Cow<'a, Self>>>>,
24-
) -> rerun::SerializationResult<Box<dyn arrow2::array::Array>>
25-
where
26-
Self: 'a,
27-
{
28-
rerun::components::Position3D::to_arrow2_opt(
29-
data.into_iter().map(|opt| opt.map(Into::into).map(|c| c.0)),
30-
)
31-
}
32-
}
33-
34-
impl rerun::Component for CustomPosition3D {
35-
#[inline]
36-
fn descriptor() -> ComponentDescriptor {
37-
ComponentDescriptor::new("user.CustomPosition3D")
38-
}
39-
}
1+
use rerun::{ChunkStore, ChunkStoreConfig, ComponentBatch, ComponentDescriptor, VersionPolicy};
402

413
struct CustomPoints3D {
42-
positions: Vec<CustomPosition3D>,
4+
positions: Vec<rerun::components::Position3D>,
435
colors: Option<Vec<rerun::components::Color>>,
446
}
457

@@ -49,13 +11,15 @@ impl CustomPoints3D {
4911
}
5012

5113
fn overridden_position_descriptor() -> ComponentDescriptor {
52-
CustomPosition3D::descriptor()
53-
.or_with_archetype_name(|| "user.CustomPoints3D".into())
54-
.or_with_archetype_field_name(|| "custom_positions".into())
14+
ComponentDescriptor {
15+
archetype_name: Some("user.CustomPoints3D".into()),
16+
archetype_field_name: Some("custom_positions".into()),
17+
component_name: "user.CustomPosition3D".into(),
18+
}
5519
}
5620

5721
fn overridden_color_descriptor() -> ComponentDescriptor {
58-
rerun::components::Color::descriptor()
22+
<rerun::components::Color as rerun::Component>::descriptor()
5923
.or_with_archetype_name(|| "user.CustomPoints3D".into())
6024
.or_with_archetype_field_name(|| "colors".into())
6125
}
@@ -66,15 +30,12 @@ impl rerun::AsComponents for CustomPoints3D {
6630
[
6731
Some(Self::indicator().to_batch()),
6832
Some(
69-
rerun::ComponentBatchCowWithDescriptor::new(
70-
&self.positions as &dyn rerun::ComponentBatch,
71-
)
72-
.with_descriptor_override(Self::overridden_position_descriptor()),
33+
self.positions
34+
.with_descriptor(Self::overridden_position_descriptor()),
7335
),
74-
self.colors.as_ref().map(|colors| {
75-
rerun::ComponentBatchCowWithDescriptor::new(colors as &dyn rerun::ComponentBatch)
76-
.with_descriptor_override(Self::overridden_color_descriptor())
77-
}),
36+
self.colors
37+
.as_ref()
38+
.map(|colors| colors.with_descriptor(Self::overridden_color_descriptor())),
7839
]
7940
.into_iter()
8041
.flatten()
@@ -83,12 +44,12 @@ impl rerun::AsComponents for CustomPoints3D {
8344
}
8445

8546
fn example(rec: &rerun::RecordingStream) -> Result<(), Box<dyn std::error::Error>> {
86-
let position = CustomPosition3D(rerun::components::Position3D::new(1.0, 2.0, 3.0));
87-
let color = rerun::components::Color::new(0xFF00FFFF);
47+
let positions = rerun::components::Position3D::new(1.0, 2.0, 3.0);
48+
let colors = rerun::components::Color::new(0xFF00FFFF);
8849

8950
let points = CustomPoints3D {
90-
positions: vec![position],
91-
colors: Some(vec![color]),
51+
positions: vec![positions],
52+
colors: Some(vec![colors]),
9253
};
9354

9455
rec.log_static("data", &points as _)?;
@@ -152,7 +113,7 @@ fn check_tags(rec: &rerun::RecordingStream) {
152113
ComponentDescriptor {
153114
archetype_name: Some("user.CustomPoints3D".into()),
154115
archetype_field_name: Some("colors".into()),
155-
component_name: rerun::components::Color::name(),
116+
component_name: "rerun.components.Color".into(),
156117
},
157118
ComponentDescriptor {
158119
archetype_name: Some("user.CustomPoints3D".into()),

docs/snippets/all/descriptors/descr_custom_component.py

+8-21
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,18 @@
22

33
from __future__ import annotations
44

5-
from typing import Any
6-
7-
import numpy.typing as npt
8-
import pyarrow as pa
95
import rerun as rr # pip install rerun-sdk
106

11-
12-
class CustomPosition3DBatch(rr.ComponentBatchLike):
13-
def __init__(self: Any, positions: npt.ArrayLike) -> None:
14-
self.position = rr.components.Position3DBatch(positions)
15-
16-
def component_descriptor(self) -> rr.ComponentDescriptor:
17-
return rr.ComponentDescriptor(
18-
"user.CustomPosition3D",
19-
archetype_name="user.CustomArchetype",
20-
archetype_field_name="custom_positions",
21-
)
22-
23-
def as_arrow_array(self) -> pa.Array:
24-
return self.position.as_arrow_array()
25-
26-
277
rr.init("rerun_example_descriptors_custom_component")
288
rr.spawn()
299

30-
rr.log("data", [CustomPosition3DBatch([[1, 2, 3]])], static=True)
10+
positions = rr.components.Position3DBatch([1, 2, 3]).with_descriptor(
11+
rr.ComponentDescriptor(
12+
"user.CustomPosition3D",
13+
archetype_name="user.CustomArchetype",
14+
archetype_field_name="custom_positions",
15+
)
16+
)
17+
rr.log("data", [positions], static=True)
3118

3219
# The tags are indirectly checked by the Rust version (have a look over there for more info).

docs/snippets/all/descriptors/descr_custom_component.rs

+8-46
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,13 @@
1-
use rerun::{
2-
external::arrow2, ChunkStore, ChunkStoreConfig, Component, ComponentDescriptor, Loggable,
3-
VersionPolicy,
4-
};
5-
6-
#[derive(Debug, Clone, Copy)]
7-
struct CustomPosition3D(rerun::components::Position3D);
8-
9-
impl rerun::SizeBytes for CustomPosition3D {
10-
#[inline]
11-
fn heap_size_bytes(&self) -> u64 {
12-
0
13-
}
14-
}
15-
16-
impl Loggable for CustomPosition3D {
17-
#[inline]
18-
fn arrow2_datatype() -> arrow2::datatypes::DataType {
19-
rerun::components::Position3D::arrow2_datatype()
20-
}
21-
22-
#[inline]
23-
fn to_arrow2_opt<'a>(
24-
data: impl IntoIterator<Item = Option<impl Into<std::borrow::Cow<'a, Self>>>>,
25-
) -> rerun::SerializationResult<Box<dyn arrow2::array::Array>>
26-
where
27-
Self: 'a,
28-
{
29-
rerun::components::Position3D::to_arrow2_opt(
30-
data.into_iter().map(|opt| opt.map(Into::into).map(|c| c.0)),
31-
)
32-
}
33-
}
34-
35-
impl Component for CustomPosition3D {
36-
#[inline]
37-
fn descriptor() -> ComponentDescriptor {
38-
ComponentDescriptor {
39-
archetype_name: Some("user.CustomArchetype".into()),
40-
archetype_field_name: Some("custom_positions".into()),
41-
component_name: "user.CustomPosition3D".into(),
42-
}
43-
}
44-
}
1+
use rerun::{ChunkStore, ChunkStoreConfig, ComponentBatch, ComponentDescriptor, VersionPolicy};
452

463
fn example(rec: &rerun::RecordingStream) -> Result<(), Box<dyn std::error::Error>> {
47-
let position = CustomPosition3D(rerun::components::Position3D::new(1.0, 2.0, 3.0));
48-
rec.log_component_batches("data", true, [&position as &dyn rerun::ComponentBatch])?;
4+
let positions = rerun::components::Position3D::new(1.0, 2.0, 3.0);
5+
let positions = positions.with_descriptor(ComponentDescriptor {
6+
archetype_name: Some("user.CustomArchetype".into()),
7+
archetype_field_name: Some("custom_positions".into()),
8+
component_name: "user.CustomPosition3D".into(),
9+
});
10+
rec.log_component_batches("data", true, [&positions as &dyn rerun::ComponentBatch])?;
4911

5012
Ok(())
5113
}

docs/snippets/all/tutorials/custom_data.py

+10-17
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import rerun as rr
1313

1414

15-
class ConfidenceBatch(rr.ComponentBatchLike):
15+
class ConfidenceBatch(rr.ComponentBatchMixin):
1616
"""A batch of confidence data."""
1717

1818
def __init__(self: Any, confidence: npt.ArrayLike) -> None:
@@ -30,24 +30,17 @@ def as_arrow_array(self) -> pa.Array:
3030
class CustomPoints3D(rr.AsComponents):
3131
"""A custom archetype that extends Rerun's builtin `Points3D` archetype with a custom component."""
3232

33-
def __init__(self: Any, points3d: npt.ArrayLike, confidences: npt.ArrayLike) -> None:
34-
self.points3d = points3d
35-
self.confidences = confidences
33+
def __init__(self: Any, positions: npt.ArrayLike, confidences: npt.ArrayLike) -> None:
34+
self.points3d = rr.Points3D(positions)
35+
self.confidences = ConfidenceBatch(confidences).or_with_descriptor_overrides(
36+
archetype_name="user.CustomPoints3D", archetype_field_name="confidences"
37+
)
3638

3739
def as_component_batches(self) -> Iterable[rr.ComponentBatchLike]:
38-
points3d = np.asarray(self.points3d)
39-
confidences = ConfidenceBatch(self.confidences)
4040
return (
41-
list(rr.Points3D(points3d).as_component_batches()) # The components from Points3D
41+
list(self.points3d.as_component_batches()) # The components from Points3D
4242
+ [rr.IndicatorComponentBatch("user.CustomPoints3D")] # Our custom indicator
43-
+ [
44-
rr.DescribedComponentBatch(
45-
confidences,
46-
confidences.component_descriptor().or_with_overrides(
47-
archetype_name="user.CustomPoints3D", archetype_field_name="confidences"
48-
),
49-
)
50-
] # Custom confidence data
43+
+ [self.confidences] # Custom confidence data
5144
)
5245

5346

@@ -59,14 +52,14 @@ def log_custom_data() -> None:
5952
rr.log(
6053
"left/my_confident_point_cloud",
6154
CustomPoints3D(
62-
points3d=point_grid,
55+
positions=point_grid,
6356
confidences=[42],
6457
),
6558
)
6659

6760
rr.log(
6861
"right/my_polarized_point_cloud",
69-
CustomPoints3D(points3d=point_grid, confidences=np.arange(0, len(point_grid))),
62+
CustomPoints3D(positions=point_grid, confidences=np.arange(0, len(point_grid))),
7063
)
7164

7265

rerun_py/rerun_sdk/rerun/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
remote as remote,
3434
)
3535
from ._baseclasses import (
36+
ComponentBatchMixin as ComponentBatchMixin,
3637
ComponentColumn as ComponentColumn,
3738
ComponentDescriptor as ComponentDescriptor,
3839
DescribedComponentBatch as DescribedComponentBatch,

0 commit comments

Comments
 (0)