From d41c53f191b8b86f43787fb52b3b4de104116161 Mon Sep 17 00:00:00 2001
From: Antoine Beyeler <49431240+abey79@users.noreply.github.com>
Date: Tue, 17 Dec 2024 12:14:58 +0100
Subject: [PATCH 01/30] Add better support for scrolling content to our modals
(#8492)
### What
This PR builds proper scrollability to our modals, thereby fixing:
- an ugly glitch with large add/remove entity modal
- add view/container modal not scrollable with very small viewer window
size
#### Before
#### After
---------
Co-authored-by: Clement Rey
---
.../src/view_entity_picker.rs | 18 +--
crates/viewer/re_ui/src/modal.rs | 144 +++++++++++++++---
.../src/ui/add_view_or_container_modal.rs | 4 +-
.../check_modal_scrolling.py | 46 ++++++
4 files changed, 171 insertions(+), 41 deletions(-)
create mode 100644 tests/python/release_checklist/check_modal_scrolling.py
diff --git a/crates/viewer/re_selection_panel/src/view_entity_picker.rs b/crates/viewer/re_selection_panel/src/view_entity_picker.rs
index 513111b3bb9c..d1a6b7ecb4fc 100644
--- a/crates/viewer/re_selection_panel/src/view_entity_picker.rs
+++ b/crates/viewer/re_selection_panel/src/view_entity_picker.rs
@@ -1,4 +1,3 @@
-use egui::NumExt as _;
use itertools::Itertools;
use nohash_hasher::IntMap;
@@ -39,6 +38,7 @@ impl ViewEntityPicker {
re_ui::modal::ModalWrapper::new("Add/remove Entities")
.default_height(640.0)
.full_span_content(true)
+ .scrollable([false, true])
},
|ui, open| {
let Some(view_id) = &self.view_id else {
@@ -51,21 +51,7 @@ impl ViewEntityPicker {
return;
};
- // Make the modal size less jumpy and work around https://github.com/emilk/egui/issues/5138
- // TODO(ab): move that boilerplate to `ModalWrapper` by adding a `scrollable` flag.
- let max_height = 0.85 * ui.ctx().screen_rect().height();
- let min_height = 0.3 * ui.ctx().screen_rect().height().at_most(max_height);
-
- egui::ScrollArea::vertical()
- .min_scrolled_height(max_height)
- .max_height(max_height)
- .show(ui, |ui| {
- add_entities_ui(ctx, ui, view);
-
- if ui.min_rect().height() < min_height {
- ui.add_space(min_height - ui.min_rect().height());
- }
- });
+ add_entities_ui(ctx, ui, view);
},
);
}
diff --git a/crates/viewer/re_ui/src/modal.rs b/crates/viewer/re_ui/src/modal.rs
index e6f7b9113c18..1f5963ee7d65 100644
--- a/crates/viewer/re_ui/src/modal.rs
+++ b/crates/viewer/re_ui/src/modal.rs
@@ -1,3 +1,5 @@
+use eframe::emath::NumExt;
+
use crate::{DesignTokens, UiExt as _};
/// Helper object to handle a [`ModalWrapper`] window.
@@ -83,6 +85,7 @@ pub struct ModalWrapper {
min_height: Option,
default_height: Option,
full_span_content: bool,
+ scrollable: egui::Vec2b,
}
impl ModalWrapper {
@@ -94,6 +97,7 @@ impl ModalWrapper {
min_height: None,
default_height: None,
full_span_content: false,
+ scrollable: false.into(),
}
}
@@ -131,6 +135,13 @@ impl ModalWrapper {
self
}
+ /// Enclose the contents in a scroll area.
+ #[inline]
+ pub fn scrollable(mut self, scrollable: impl Into) -> Self {
+ self.scrollable = scrollable.into();
+ self
+ }
+
/// Show the modal window.
///
/// Typically called by [`ModalHandler::ui`].
@@ -148,7 +159,7 @@ impl ModalWrapper {
area = area.default_height(default_height);
}
- let modal_response = egui::Modal::new("add_view_or_container_modal".into())
+ let modal_response = egui::Modal::new(id.with("modal"))
.frame(egui::Frame {
fill: ctx.style().visuals.panel_fill,
..Default::default()
@@ -168,38 +179,82 @@ impl ModalWrapper {
ui.set_min_height(min_height);
}
- egui::Frame {
- inner_margin: egui::Margin::symmetric(DesignTokens::view_padding(), 0.0),
- ..Default::default()
- }
+ //
+ // Title bar
+ //
+
+ view_padding_frame(&ViewPaddingFrameParams {
+ left_and_right: true,
+ top: true,
+ bottom: false,
+ })
.show(ui, |ui| {
- ui.add_space(DesignTokens::view_padding());
Self::title_bar(ui, &self.title, &mut open);
ui.add_space(DesignTokens::view_padding());
ui.full_span_separator();
+ });
- if self.full_span_content {
- // no further spacing for the content UI
- content_ui(ui, &mut open)
- } else {
- // we must restore vertical spacing and add view padding at the bottom
- ui.add_space(item_spacing_y);
-
- egui::Frame {
- inner_margin: egui::Margin {
- bottom: DesignTokens::view_padding(),
- ..Default::default()
- },
- ..Default::default()
+ //
+ // Inner content
+ //
+
+ let wrapped_content_ui = |ui: &mut egui::Ui, open: &mut bool| -> R {
+ // We always have side margin, but these must happen _inside_ the scroll area
+ // (if any). Otherwise, the scroll bar is not snug with the right border and
+ // may interfere with the action buttons of `ListItem`s.
+ view_padding_frame(&ViewPaddingFrameParams {
+ left_and_right: true,
+ top: false,
+ bottom: false,
+ })
+ .show(ui, |ui| {
+ if self.full_span_content {
+ // no further spacing for the content UI
+ content_ui(ui, open)
+ } else {
+ // we must restore vertical spacing and add view padding at the bottom
+ ui.add_space(item_spacing_y);
+
+ view_padding_frame(&ViewPaddingFrameParams {
+ left_and_right: false,
+ top: false,
+ bottom: true,
+ })
+ .show(ui, |ui| {
+ ui.spacing_mut().item_spacing.y = item_spacing_y;
+ content_ui(ui, open)
+ })
+ .inner
}
+ })
+ .inner
+ };
+
+ //
+ // Optional scroll area
+ //
+
+ if self.scrollable.any() {
+ // Make the modal size less jumpy and work around https://github.com/emilk/egui/issues/5138
+ let max_height = 0.85 * ui.ctx().screen_rect().height();
+ let min_height = 0.3 * ui.ctx().screen_rect().height().at_most(max_height);
+
+ egui::ScrollArea::new(self.scrollable)
+ .min_scrolled_height(max_height)
+ .max_height(max_height)
.show(ui, |ui| {
- ui.spacing_mut().item_spacing.y = item_spacing_y;
- content_ui(ui, &mut open)
+ let res = wrapped_content_ui(ui, &mut open);
+
+ if ui.min_rect().height() < min_height {
+ ui.add_space(min_height - ui.min_rect().height());
+ }
+
+ res
})
.inner
- }
- })
- .inner
+ } else {
+ wrapped_content_ui(ui, &mut open)
+ }
});
if modal_response.should_close() {
@@ -230,3 +285,44 @@ impl ModalWrapper {
});
}
}
+
+struct ViewPaddingFrameParams {
+ left_and_right: bool,
+ top: bool,
+ bottom: bool,
+}
+
+/// Utility to produce a [`egui::Frame`] with padding on some sides.
+#[inline]
+fn view_padding_frame(params: &ViewPaddingFrameParams) -> egui::Frame {
+ let ViewPaddingFrameParams {
+ left_and_right,
+ top,
+ bottom,
+ } = *params;
+ egui::Frame {
+ inner_margin: egui::Margin {
+ left: if left_and_right {
+ DesignTokens::view_padding()
+ } else {
+ 0.0
+ },
+ right: if left_and_right {
+ DesignTokens::view_padding()
+ } else {
+ 0.0
+ },
+ top: if top {
+ DesignTokens::view_padding()
+ } else {
+ 0.0
+ },
+ bottom: if bottom {
+ DesignTokens::view_padding()
+ } else {
+ 0.0
+ },
+ },
+ ..Default::default()
+ }
+}
diff --git a/crates/viewer/re_viewport_blueprint/src/ui/add_view_or_container_modal.rs b/crates/viewer/re_viewport_blueprint/src/ui/add_view_or_container_modal.rs
index 4a38ee15a48f..63f2fc83e02f 100644
--- a/crates/viewer/re_viewport_blueprint/src/ui/add_view_or_container_modal.rs
+++ b/crates/viewer/re_viewport_blueprint/src/ui/add_view_or_container_modal.rs
@@ -1,11 +1,12 @@
//! Modal for adding a new view of container to an existing target container.
-use crate::{ViewBlueprint, ViewportBlueprint};
use re_ui::UiExt as _;
use re_viewer_context::{
blueprint_id_to_tile_id, icon_for_container_kind, ContainerId, RecommendedView, ViewerContext,
};
+use crate::{ViewBlueprint, ViewportBlueprint};
+
#[derive(Default)]
pub struct AddViewOrContainerModal {
target_container: Option,
@@ -30,6 +31,7 @@ impl AddViewOrContainerModal {
re_ui::modal::ModalWrapper::new("Add view or container")
.min_width(500.0)
.full_span_content(true)
+ .scrollable([false, true])
},
|ui, keep_open| modal_ui(ui, ctx, viewport, self.target_container, keep_open),
);
diff --git a/tests/python/release_checklist/check_modal_scrolling.py b/tests/python/release_checklist/check_modal_scrolling.py
new file mode 100644
index 000000000000..8859f69acc17
--- /dev/null
+++ b/tests/python/release_checklist/check_modal_scrolling.py
@@ -0,0 +1,46 @@
+from __future__ import annotations
+
+import os
+from argparse import Namespace
+from uuid import uuid4
+
+import rerun as rr
+import rerun.blueprint as rrb
+
+README = """\
+# Modal scrolling
+
+* Select the 2D view
+* Open the Entity Path Filter modal
+* Make sure it behaves properly, including scrolling
+"""
+
+
+def log_readme() -> None:
+ rr.log("readme", rr.TextDocument(README, media_type=rr.MediaType.MARKDOWN), timeless=True)
+
+
+def log_many_entities() -> None:
+ for i in range(0, 1000):
+ rr.log(f"points/{i}", rr.Points2D([(i, i)]))
+
+
+def run(args: Namespace) -> None:
+ rr.script_setup(
+ args,
+ f"{os.path.basename(__file__)}",
+ recording_id=uuid4(),
+ default_blueprint=rrb.Grid(rrb.Spatial2DView(origin="/"), rrb.TextDocumentView(origin="readme")),
+ )
+
+ log_readme()
+ log_many_entities()
+
+
+if __name__ == "__main__":
+ import argparse
+
+ parser = argparse.ArgumentParser(description="Interactive release checklist")
+ rr.script_add_args(parser)
+ args = parser.parse_args()
+ run(args)
From 6b00c77ceb36d549fedba1efc9319b20e65b74f5 Mon Sep 17 00:00:00 2001
From: Antoine Beyeler <49431240+abey79@users.noreply.github.com>
Date: Tue, 17 Dec 2024 12:27:28 +0100
Subject: [PATCH 02/30] Improve the tooltip of the `Force*` graph view
properties (#8501)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
### Related
- fixes #8456
### What
βπ»
---
.../blueprint/archetypes/force_center.fbs | 4 ++-
.../archetypes/force_collision_radius.fbs | 6 +++--
.../rerun/blueprint/archetypes/force_link.fbs | 4 ++-
.../blueprint/archetypes/force_many_body.fbs | 5 +++-
.../blueprint/archetypes/force_position.fbs | 4 ++-
.../src/blueprint/archetypes/force_center.rs | 8 ++++--
.../archetypes/force_collision_radius.rs | 10 +++++---
.../src/blueprint/archetypes/force_link.rs | 8 ++++--
.../blueprint/archetypes/force_many_body.rs | 10 ++++++--
.../blueprint/archetypes/force_position.rs | 8 ++++--
crates/store/re_types/src/reflection/mod.rs | 25 +++++++++++--------
.../reference/types/views/graph_view.md | 10 ++++----
.../blueprint/archetypes/force_center.hpp | 8 ++++--
.../archetypes/force_collision_radius.hpp | 10 +++++---
.../rerun/blueprint/archetypes/force_link.hpp | 8 ++++--
.../blueprint/archetypes/force_many_body.hpp | 10 ++++++--
.../blueprint/archetypes/force_position.hpp | 8 ++++--
.../blueprint/archetypes/force_center.py | 8 ++++--
.../archetypes/force_collision_radius.py | 10 +++++---
.../rerun/blueprint/archetypes/force_link.py | 8 ++++--
.../blueprint/archetypes/force_many_body.py | 10 ++++++--
.../blueprint/archetypes/force_position.py | 8 ++++--
22 files changed, 136 insertions(+), 54 deletions(-)
diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_center.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_center.fbs
index c3b477bf49d0..a574b9c696c0 100644
--- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_center.fbs
+++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_center.fbs
@@ -4,7 +4,9 @@ namespace rerun.blueprint.archetypes;
struct ForceCenter (
"attr.rerun.scope": "blueprint"
) {
- /// Whether the force is enabled.
+ /// Whether the center force is enabled.
+ ///
+ /// The center force tries to move the center of mass of the graph towards the origin.
enabled: rerun.blueprint.components.Enabled ("attr.rerun.component_optional", nullable, order: 100);
/// The strength of the force.
diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_collision_radius.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_collision_radius.fbs
index 9ffcf43376ff..f4a4e760b59a 100644
--- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_collision_radius.fbs
+++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_collision_radius.fbs
@@ -1,10 +1,12 @@
namespace rerun.blueprint.archetypes;
-/// Resolves collisions between the bounding spheres, according to the radius of the nodes.
+/// Resolves collisions between the bounding circles, according to the radius of the nodes.
struct ForceCollisionRadius (
"attr.rerun.scope": "blueprint"
) {
- /// Whether the force is enabled.
+ /// Whether the collision force is enabled.
+ ///
+ /// The collision force resolves collisions between nodes based on the bounding circle defined by their radius.
enabled: rerun.blueprint.components.Enabled ("attr.rerun.component_optional", nullable, order: 100);
/// The strength of the force.
diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_link.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_link.fbs
index fc963b757cf3..2d34b1c936ae 100644
--- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_link.fbs
+++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_link.fbs
@@ -4,7 +4,9 @@ namespace rerun.blueprint.archetypes;
struct ForceLink (
"attr.rerun.scope": "blueprint"
) {
- /// Whether the force is enabled.
+ /// Whether the link force is enabled.
+ ///
+ /// The link force aims to achieve a target distance between two nodes that are connected by one ore more edges.
enabled: rerun.blueprint.components.Enabled ("attr.rerun.component_optional", nullable, order: 100);
/// The target distance between two nodes.
diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_many_body.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_many_body.fbs
index edafce01c777..abc576912fca 100644
--- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_many_body.fbs
+++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_many_body.fbs
@@ -6,7 +6,10 @@ namespace rerun.blueprint.archetypes;
struct ForceManyBody (
"attr.rerun.scope": "blueprint"
) {
- /// Whether the force is enabled.
+ /// Whether the many body force is enabled.
+ ///
+ /// The many body force is applied on each pair of nodes in a way that ressembles an electrical charge. If the
+ /// strength is smaller than 0, it pushes nodes apart; if it is larger than 0, it pulls them together.
enabled: rerun.blueprint.components.Enabled ("attr.rerun.component_optional", nullable, order: 100);
/// The strength of the force.
diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_position.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_position.fbs
index 7ff9fd24d340..6689b95b48d7 100644
--- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_position.fbs
+++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/force_position.fbs
@@ -4,7 +4,9 @@ namespace rerun.blueprint.archetypes;
struct ForcePosition (
"attr.rerun.scope": "blueprint"
) {
- /// Whether the force is enabled.
+ /// Whether the position force is enabled.
+ ///
+ /// The position force pulls nodes towards a specific position, similar to gravity.
enabled: rerun.blueprint.components.Enabled ("attr.rerun.component_optional", nullable, order: 100);
/// The strength of the force.
diff --git a/crates/store/re_types/src/blueprint/archetypes/force_center.rs b/crates/store/re_types/src/blueprint/archetypes/force_center.rs
index 9cb1870a5af5..5f12962b42dc 100644
--- a/crates/store/re_types/src/blueprint/archetypes/force_center.rs
+++ b/crates/store/re_types/src/blueprint/archetypes/force_center.rs
@@ -21,7 +21,9 @@ use ::re_types_core::{DeserializationError, DeserializationResult};
/// **Archetype**: Tries to move the center of mass of the graph to the origin.
#[derive(Clone, Debug)]
pub struct ForceCenter {
- /// Whether the force is enabled.
+ /// Whether the center force is enabled.
+ ///
+ /// The center force tries to move the center of mass of the graph towards the origin.
pub enabled: Option,
/// The strength of the force.
@@ -207,7 +209,9 @@ impl ForceCenter {
}
}
- /// Whether the force is enabled.
+ /// Whether the center force is enabled.
+ ///
+ /// The center force tries to move the center of mass of the graph towards the origin.
#[inline]
pub fn with_enabled(
mut self,
diff --git a/crates/store/re_types/src/blueprint/archetypes/force_collision_radius.rs b/crates/store/re_types/src/blueprint/archetypes/force_collision_radius.rs
index 71055ab49f0f..9f4536a2b750 100644
--- a/crates/store/re_types/src/blueprint/archetypes/force_collision_radius.rs
+++ b/crates/store/re_types/src/blueprint/archetypes/force_collision_radius.rs
@@ -18,10 +18,12 @@ use ::re_types_core::{ComponentBatch, ComponentBatchCowWithDescriptor};
use ::re_types_core::{ComponentDescriptor, ComponentName};
use ::re_types_core::{DeserializationError, DeserializationResult};
-/// **Archetype**: Resolves collisions between the bounding spheres, according to the radius of the nodes.
+/// **Archetype**: Resolves collisions between the bounding circles, according to the radius of the nodes.
#[derive(Clone, Debug)]
pub struct ForceCollisionRadius {
- /// Whether the force is enabled.
+ /// Whether the collision force is enabled.
+ ///
+ /// The collision force resolves collisions between nodes based on the bounding circle defined by their radius.
pub enabled: Option,
/// The strength of the force.
@@ -250,7 +252,9 @@ impl ForceCollisionRadius {
}
}
- /// Whether the force is enabled.
+ /// Whether the collision force is enabled.
+ ///
+ /// The collision force resolves collisions between nodes based on the bounding circle defined by their radius.
#[inline]
pub fn with_enabled(
mut self,
diff --git a/crates/store/re_types/src/blueprint/archetypes/force_link.rs b/crates/store/re_types/src/blueprint/archetypes/force_link.rs
index 9c6fe8aa11d2..f294b0eb9818 100644
--- a/crates/store/re_types/src/blueprint/archetypes/force_link.rs
+++ b/crates/store/re_types/src/blueprint/archetypes/force_link.rs
@@ -21,7 +21,9 @@ use ::re_types_core::{DeserializationError, DeserializationResult};
/// **Archetype**: Aims to achieve a target distance between two nodes that are connected by an edge.
#[derive(Clone, Debug)]
pub struct ForceLink {
- /// Whether the force is enabled.
+ /// Whether the link force is enabled.
+ ///
+ /// The link force aims to achieve a target distance between two nodes that are connected by one ore more edges.
pub enabled: Option,
/// The target distance between two nodes.
@@ -249,7 +251,9 @@ impl ForceLink {
}
}
- /// Whether the force is enabled.
+ /// Whether the link force is enabled.
+ ///
+ /// The link force aims to achieve a target distance between two nodes that are connected by one ore more edges.
#[inline]
pub fn with_enabled(
mut self,
diff --git a/crates/store/re_types/src/blueprint/archetypes/force_many_body.rs b/crates/store/re_types/src/blueprint/archetypes/force_many_body.rs
index 9720ff5a4f17..026e249436d4 100644
--- a/crates/store/re_types/src/blueprint/archetypes/force_many_body.rs
+++ b/crates/store/re_types/src/blueprint/archetypes/force_many_body.rs
@@ -23,7 +23,10 @@ use ::re_types_core::{DeserializationError, DeserializationResult};
/// If `strength` is smaller than 0, it pushes nodes apart, if it is larger than 0 it pulls them together.
#[derive(Clone, Debug)]
pub struct ForceManyBody {
- /// Whether the force is enabled.
+ /// Whether the many body force is enabled.
+ ///
+ /// The many body force is applied on each pair of nodes in a way that ressembles an electrical charge. If the
+ /// strength is smaller than 0, it pushes nodes apart; if it is larger than 0, it pulls them together.
pub enabled: Option,
/// The strength of the force.
@@ -211,7 +214,10 @@ impl ForceManyBody {
}
}
- /// Whether the force is enabled.
+ /// Whether the many body force is enabled.
+ ///
+ /// The many body force is applied on each pair of nodes in a way that ressembles an electrical charge. If the
+ /// strength is smaller than 0, it pushes nodes apart; if it is larger than 0, it pulls them together.
#[inline]
pub fn with_enabled(
mut self,
diff --git a/crates/store/re_types/src/blueprint/archetypes/force_position.rs b/crates/store/re_types/src/blueprint/archetypes/force_position.rs
index e106a452c2a2..cc74aa2aabf4 100644
--- a/crates/store/re_types/src/blueprint/archetypes/force_position.rs
+++ b/crates/store/re_types/src/blueprint/archetypes/force_position.rs
@@ -21,7 +21,9 @@ use ::re_types_core::{DeserializationError, DeserializationResult};
/// **Archetype**: Similar to gravity, this force pulls nodes towards a specific position.
#[derive(Clone, Debug)]
pub struct ForcePosition {
- /// Whether the force is enabled.
+ /// Whether the position force is enabled.
+ ///
+ /// The position force pulls nodes towards a specific position, similar to gravity.
pub enabled: Option,
/// The strength of the force.
@@ -246,7 +248,9 @@ impl ForcePosition {
}
}
- /// Whether the force is enabled.
+ /// Whether the position force is enabled.
+ ///
+ /// The position force pulls nodes towards a specific position, similar to gravity.
#[inline]
pub fn with_enabled(
mut self,
diff --git a/crates/store/re_types/src/reflection/mod.rs b/crates/store/re_types/src/reflection/mod.rs
index 2deab0ebfb3c..05839fe7c80e 100644
--- a/crates/store/re_types/src/reflection/mod.rs
+++ b/crates/store/re_types/src/reflection/mod.rs
@@ -2040,8 +2040,9 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap {
fields: vec![
ArchetypeFieldReflection { name : "enabled", display_name :
"Enabled", component_name : "rerun.blueprint.components.Enabled"
- .into(), docstring_md : "Whether the force is enabled.", is_required
- : false, }, ArchetypeFieldReflection { name : "strength",
+ .into(), docstring_md :
+ "Whether the center force is enabled.\n\nThe center force tries to move the center of mass of the graph towards the origin.",
+ is_required : false, }, ArchetypeFieldReflection { name : "strength",
display_name : "Strength", component_name :
"rerun.blueprint.components.ForceStrength".into(), docstring_md :
"The strength of the force.", is_required : false, },
@@ -2057,8 +2058,9 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap {
fields: vec![
ArchetypeFieldReflection { name : "enabled", display_name :
"Enabled", component_name : "rerun.blueprint.components.Enabled"
- .into(), docstring_md : "Whether the force is enabled.", is_required
- : false, }, ArchetypeFieldReflection { name : "strength",
+ .into(), docstring_md :
+ "Whether the collision force is enabled.\n\nThe collision force resolves collisions between nodes based on the bounding circle defined by their radius.",
+ is_required : false, }, ArchetypeFieldReflection { name : "strength",
display_name : "Strength", component_name :
"rerun.blueprint.components.ForceStrength".into(), docstring_md :
"The strength of the force.", is_required : false, },
@@ -2079,8 +2081,9 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap {
fields: vec![
ArchetypeFieldReflection { name : "enabled", display_name :
"Enabled", component_name : "rerun.blueprint.components.Enabled"
- .into(), docstring_md : "Whether the force is enabled.", is_required
- : false, }, ArchetypeFieldReflection { name : "distance",
+ .into(), docstring_md :
+ "Whether the link force is enabled.\n\nThe link force aims to achieve a target distance between two nodes that are connected by one ore more edges.",
+ is_required : false, }, ArchetypeFieldReflection { name : "distance",
display_name : "Distance", component_name :
"rerun.blueprint.components.ForceDistance".into(), docstring_md :
"The target distance between two nodes.", is_required : false, },
@@ -2101,8 +2104,9 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap {
fields: vec![
ArchetypeFieldReflection { name : "enabled", display_name :
"Enabled", component_name : "rerun.blueprint.components.Enabled"
- .into(), docstring_md : "Whether the force is enabled.", is_required
- : false, }, ArchetypeFieldReflection { name : "strength",
+ .into(), docstring_md :
+ "Whether the many body force is enabled.\n\nThe many body force is applied on each pair of nodes in a way that ressembles an electrical charge. If the\nstrength is smaller than 0, it pushes nodes apart; if it is larger than 0, it pulls them together.",
+ is_required : false, }, ArchetypeFieldReflection { name : "strength",
display_name : "Strength", component_name :
"rerun.blueprint.components.ForceStrength".into(), docstring_md :
"The strength of the force.\n\nIf `strength` is smaller than 0, it pushes nodes apart, if it is larger than 0 it pulls them together.",
@@ -2119,8 +2123,9 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap {
fields: vec![
ArchetypeFieldReflection { name : "enabled", display_name :
"Enabled", component_name : "rerun.blueprint.components.Enabled"
- .into(), docstring_md : "Whether the force is enabled.", is_required
- : false, }, ArchetypeFieldReflection { name : "strength",
+ .into(), docstring_md :
+ "Whether the position force is enabled.\n\nThe position force pulls nodes towards a specific position, similar to gravity.",
+ is_required : false, }, ArchetypeFieldReflection { name : "strength",
display_name : "Strength", component_name :
"rerun.blueprint.components.ForceStrength".into(), docstring_md :
"The strength of the force.", is_required : false, },
diff --git a/docs/content/reference/types/views/graph_view.md b/docs/content/reference/types/views/graph_view.md
index 7e39cfc769e4..e222d74616b7 100644
--- a/docs/content/reference/types/views/graph_view.md
+++ b/docs/content/reference/types/views/graph_view.md
@@ -14,30 +14,30 @@ Somethings outside of these bounds may also be visible due to letterboxing.
### `force_link`
Allows to control the interaction between two nodes connected by an edge.
-* `enabled`: Whether the force is enabled.
+* `enabled`: Whether the link force is enabled.
* `distance`: The target distance between two nodes.
* `iterations`: Specifies how often this force should be applied per iteration.
### `force_many_body`
A force between each pair of nodes that ressembles an electrical charge.
-* `enabled`: Whether the force is enabled.
+* `enabled`: Whether the many body force is enabled.
* `strength`: The strength of the force.
### `force_position`
Similar to gravity, this force pulls nodes towards a specific position.
-* `enabled`: Whether the force is enabled.
+* `enabled`: Whether the position force is enabled.
* `strength`: The strength of the force.
* `position`: The position where the nodes should be pulled towards.
### `force_collision_radius`
Resolves collisions between the bounding spheres, according to the radius of the nodes.
-* `enabled`: Whether the force is enabled.
+* `enabled`: Whether the collision force is enabled.
* `strength`: The strength of the force.
* `iterations`: Specifies how often this force should be applied per iteration.
### `force_center`
Tries to move the center of mass of the graph to the origin.
-* `enabled`: Whether the force is enabled.
+* `enabled`: Whether the center force is enabled.
* `strength`: The strength of the force.
## API reference links
diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/force_center.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/force_center.hpp
index 8c3854765b91..4a76fb9c2ff7 100644
--- a/rerun_cpp/src/rerun/blueprint/archetypes/force_center.hpp
+++ b/rerun_cpp/src/rerun/blueprint/archetypes/force_center.hpp
@@ -19,7 +19,9 @@
namespace rerun::blueprint::archetypes {
/// **Archetype**: Tries to move the center of mass of the graph to the origin.
struct ForceCenter {
- /// Whether the force is enabled.
+ /// Whether the center force is enabled.
+ ///
+ /// The center force tries to move the center of mass of the graph towards the origin.
std::optional enabled;
/// The strength of the force.
@@ -36,7 +38,9 @@ namespace rerun::blueprint::archetypes {
ForceCenter() = default;
ForceCenter(ForceCenter&& other) = default;
- /// Whether the force is enabled.
+ /// Whether the center force is enabled.
+ ///
+ /// The center force tries to move the center of mass of the graph towards the origin.
ForceCenter with_enabled(rerun::blueprint::components::Enabled _enabled) && {
enabled = std::move(_enabled);
// See: https://github.com/rerun-io/rerun/issues/4027
diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/force_collision_radius.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/force_collision_radius.hpp
index 5b8ff3d1d511..f51201ee8bd0 100644
--- a/rerun_cpp/src/rerun/blueprint/archetypes/force_collision_radius.hpp
+++ b/rerun_cpp/src/rerun/blueprint/archetypes/force_collision_radius.hpp
@@ -18,9 +18,11 @@
#include
namespace rerun::blueprint::archetypes {
- /// **Archetype**: Resolves collisions between the bounding spheres, according to the radius of the nodes.
+ /// **Archetype**: Resolves collisions between the bounding circles, according to the radius of the nodes.
struct ForceCollisionRadius {
- /// Whether the force is enabled.
+ /// Whether the collision force is enabled.
+ ///
+ /// The collision force resolves collisions between nodes based on the bounding circle defined by their radius.
std::optional enabled;
/// The strength of the force.
@@ -42,7 +44,9 @@ namespace rerun::blueprint::archetypes {
ForceCollisionRadius() = default;
ForceCollisionRadius(ForceCollisionRadius&& other) = default;
- /// Whether the force is enabled.
+ /// Whether the collision force is enabled.
+ ///
+ /// The collision force resolves collisions between nodes based on the bounding circle defined by their radius.
ForceCollisionRadius with_enabled(rerun::blueprint::components::Enabled _enabled) && {
enabled = std::move(_enabled);
// See: https://github.com/rerun-io/rerun/issues/4027
diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/force_link.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/force_link.hpp
index 0d88538bc59b..b543152710b4 100644
--- a/rerun_cpp/src/rerun/blueprint/archetypes/force_link.hpp
+++ b/rerun_cpp/src/rerun/blueprint/archetypes/force_link.hpp
@@ -20,7 +20,9 @@
namespace rerun::blueprint::archetypes {
/// **Archetype**: Aims to achieve a target distance between two nodes that are connected by an edge.
struct ForceLink {
- /// Whether the force is enabled.
+ /// Whether the link force is enabled.
+ ///
+ /// The link force aims to achieve a target distance between two nodes that are connected by one ore more edges.
std::optional enabled;
/// The target distance between two nodes.
@@ -42,7 +44,9 @@ namespace rerun::blueprint::archetypes {
ForceLink() = default;
ForceLink(ForceLink&& other) = default;
- /// Whether the force is enabled.
+ /// Whether the link force is enabled.
+ ///
+ /// The link force aims to achieve a target distance between two nodes that are connected by one ore more edges.
ForceLink with_enabled(rerun::blueprint::components::Enabled _enabled) && {
enabled = std::move(_enabled);
// See: https://github.com/rerun-io/rerun/issues/4027
diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/force_many_body.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/force_many_body.hpp
index c5267b3cf692..9b0e2686745d 100644
--- a/rerun_cpp/src/rerun/blueprint/archetypes/force_many_body.hpp
+++ b/rerun_cpp/src/rerun/blueprint/archetypes/force_many_body.hpp
@@ -21,7 +21,10 @@ namespace rerun::blueprint::archetypes {
///
/// If `strength` is smaller than 0, it pushes nodes apart, if it is larger than 0 it pulls them together.
struct ForceManyBody {
- /// Whether the force is enabled.
+ /// Whether the many body force is enabled.
+ ///
+ /// The many body force is applied on each pair of nodes in a way that ressembles an electrical charge. If the
+ /// strength is smaller than 0, it pushes nodes apart; if it is larger than 0, it pulls them together.
std::optional enabled;
/// The strength of the force.
@@ -40,7 +43,10 @@ namespace rerun::blueprint::archetypes {
ForceManyBody() = default;
ForceManyBody(ForceManyBody&& other) = default;
- /// Whether the force is enabled.
+ /// Whether the many body force is enabled.
+ ///
+ /// The many body force is applied on each pair of nodes in a way that ressembles an electrical charge. If the
+ /// strength is smaller than 0, it pushes nodes apart; if it is larger than 0, it pulls them together.
ForceManyBody with_enabled(rerun::blueprint::components::Enabled _enabled) && {
enabled = std::move(_enabled);
// See: https://github.com/rerun-io/rerun/issues/4027
diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/force_position.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/force_position.hpp
index 36d740ce7393..3c6fbf9d266b 100644
--- a/rerun_cpp/src/rerun/blueprint/archetypes/force_position.hpp
+++ b/rerun_cpp/src/rerun/blueprint/archetypes/force_position.hpp
@@ -20,7 +20,9 @@
namespace rerun::blueprint::archetypes {
/// **Archetype**: Similar to gravity, this force pulls nodes towards a specific position.
struct ForcePosition {
- /// Whether the force is enabled.
+ /// Whether the position force is enabled.
+ ///
+ /// The position force pulls nodes towards a specific position, similar to gravity.
std::optional enabled;
/// The strength of the force.
@@ -40,7 +42,9 @@ namespace rerun::blueprint::archetypes {
ForcePosition() = default;
ForcePosition(ForcePosition&& other) = default;
- /// Whether the force is enabled.
+ /// Whether the position force is enabled.
+ ///
+ /// The position force pulls nodes towards a specific position, similar to gravity.
ForcePosition with_enabled(rerun::blueprint::components::Enabled _enabled) && {
enabled = std::move(_enabled);
// See: https://github.com/rerun-io/rerun/issues/4027
diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_center.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_center.py
index 7d026c887d70..5804b3c0db7f 100644
--- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_center.py
+++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_center.py
@@ -32,7 +32,9 @@ def __init__(
Parameters
----------
enabled:
- Whether the force is enabled.
+ Whether the center force is enabled.
+
+ The center force tries to move the center of mass of the graph towards the origin.
strength:
The strength of the force.
@@ -63,7 +65,9 @@ def _clear(cls) -> ForceCenter:
default=None,
converter=blueprint_components.EnabledBatch._optional, # type: ignore[misc]
)
- # Whether the force is enabled.
+ # Whether the center force is enabled.
+ #
+ # The center force tries to move the center of mass of the graph towards the origin.
#
# (Docstring intentionally commented out to hide this field from the docs)
diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_collision_radius.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_collision_radius.py
index 80464759b93f..169c8f5e7ba0 100644
--- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_collision_radius.py
+++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_collision_radius.py
@@ -21,7 +21,7 @@
@define(str=False, repr=False, init=False)
class ForceCollisionRadius(Archetype):
- """**Archetype**: Resolves collisions between the bounding spheres, according to the radius of the nodes."""
+ """**Archetype**: Resolves collisions between the bounding circles, according to the radius of the nodes."""
def __init__(
self: Any,
@@ -36,7 +36,9 @@ def __init__(
Parameters
----------
enabled:
- Whether the force is enabled.
+ Whether the collision force is enabled.
+
+ The collision force resolves collisions between nodes based on the bounding circle defined by their radius.
strength:
The strength of the force.
iterations:
@@ -72,7 +74,9 @@ def _clear(cls) -> ForceCollisionRadius:
default=None,
converter=blueprint_components.EnabledBatch._optional, # type: ignore[misc]
)
- # Whether the force is enabled.
+ # Whether the collision force is enabled.
+ #
+ # The collision force resolves collisions between nodes based on the bounding circle defined by their radius.
#
# (Docstring intentionally commented out to hide this field from the docs)
diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_link.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_link.py
index bf24c7265d63..f3c179715a0a 100644
--- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_link.py
+++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_link.py
@@ -36,7 +36,9 @@ def __init__(
Parameters
----------
enabled:
- Whether the force is enabled.
+ Whether the link force is enabled.
+
+ The link force aims to achieve a target distance between two nodes that are connected by one ore more edges.
distance:
The target distance between two nodes.
iterations:
@@ -72,7 +74,9 @@ def _clear(cls) -> ForceLink:
default=None,
converter=blueprint_components.EnabledBatch._optional, # type: ignore[misc]
)
- # Whether the force is enabled.
+ # Whether the link force is enabled.
+ #
+ # The link force aims to achieve a target distance between two nodes that are connected by one ore more edges.
#
# (Docstring intentionally commented out to hide this field from the docs)
diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_many_body.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_many_body.py
index 4750ac834505..1881af385409 100644
--- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_many_body.py
+++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_many_body.py
@@ -36,7 +36,10 @@ def __init__(
Parameters
----------
enabled:
- Whether the force is enabled.
+ Whether the many body force is enabled.
+
+ The many body force is applied on each pair of nodes in a way that ressembles an electrical charge. If the
+ strength is smaller than 0, it pushes nodes apart; if it is larger than 0, it pulls them together.
strength:
The strength of the force.
@@ -69,7 +72,10 @@ def _clear(cls) -> ForceManyBody:
default=None,
converter=blueprint_components.EnabledBatch._optional, # type: ignore[misc]
)
- # Whether the force is enabled.
+ # Whether the many body force is enabled.
+ #
+ # The many body force is applied on each pair of nodes in a way that ressembles an electrical charge. If the
+ # strength is smaller than 0, it pushes nodes apart; if it is larger than 0, it pulls them together.
#
# (Docstring intentionally commented out to hide this field from the docs)
diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_position.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_position.py
index 61e63623c9c2..aa83eb92516d 100644
--- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_position.py
+++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/force_position.py
@@ -36,7 +36,9 @@ def __init__(
Parameters
----------
enabled:
- Whether the force is enabled.
+ Whether the position force is enabled.
+
+ The position force pulls nodes towards a specific position, similar to gravity.
strength:
The strength of the force.
position:
@@ -70,7 +72,9 @@ def _clear(cls) -> ForcePosition:
default=None,
converter=blueprint_components.EnabledBatch._optional, # type: ignore[misc]
)
- # Whether the force is enabled.
+ # Whether the position force is enabled.
+ #
+ # The position force pulls nodes towards a specific position, similar to gravity.
#
# (Docstring intentionally commented out to hide this field from the docs)
From 49fb94fa25a2466ec597baa7531949d64482c41b Mon Sep 17 00:00:00 2001
From: Andreas Reich
Date: Tue, 17 Dec 2024 12:43:54 +0100
Subject: [PATCH 03/30] Fix ui radius crashing graph view (#8502)
---
crates/viewer/re_view_graph/src/visualizers/nodes.rs | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/crates/viewer/re_view_graph/src/visualizers/nodes.rs b/crates/viewer/re_view_graph/src/visualizers/nodes.rs
index 2d7c1f0176da..b03a0c3121f6 100644
--- a/crates/viewer/re_view_graph/src/visualizers/nodes.rs
+++ b/crates/viewer/re_view_graph/src/visualizers/nodes.rs
@@ -3,7 +3,6 @@ use re_chunk::LatestAtQuery;
use re_log_types::{EntityPath, Instance};
use re_query::{clamped_zip_2x4, range_zip_1x4};
use re_types::components::{Color, Radius, ShowLabels};
-use re_types::datatypes::Float32;
use re_types::{
self, archetypes,
components::{self},
@@ -23,6 +22,8 @@ pub struct NodeVisualizer {
pub data: ahash::HashMap,
}
+pub const FALLBACK_RADIUS: f32 = 4.0;
+
/// The label information of a [`re_types::archetypes::GraphNodes`].
#[derive(Clone)]
pub enum Label {
@@ -120,7 +121,8 @@ impl VisualizerSystem for NodeVisualizer {
color,
},
_ => Label::Circle {
- radius: radius.unwrap_or(4.0),
+ // Radius is negative for UI radii, but we don't handle this here.
+ radius: radius.unwrap_or(FALLBACK_RADIUS).abs(),
color,
},
};
@@ -160,7 +162,7 @@ impl TypedComponentFallbackProvider for NodeVisualizer {
impl TypedComponentFallbackProvider for NodeVisualizer {
fn fallback_for(&self, _ctx: &QueryContext<'_>) -> Radius {
- Radius(Float32(4.0f32))
+ FALLBACK_RADIUS.into()
}
}
From d5d0d4c0642db3a1c1253345b16fb98a2288661c Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt
Date: Tue, 17 Dec 2024 14:00:14 +0100
Subject: [PATCH 04/30] Update egui to the commit before 0.30.0 (#8506)
Make sure we test everything that went into 0.30.0, while we wait for
* https://github.com/lampsitter/egui_commonmark/pull/69
---
Cargo.lock | 25 +++++++++++++------------
Cargo.toml | 14 +++++++-------
2 files changed, 20 insertions(+), 19 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 5500cc0e61f3..951fba200727 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1934,7 +1934,7 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]]
name = "ecolor"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
dependencies = [
"bytemuck",
"color-hex",
@@ -1951,7 +1951,7 @@ checksum = "18aade80d5e09429040243ce1143ddc08a92d7a22820ac512610410a4dd5214f"
[[package]]
name = "eframe"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
dependencies = [
"ahash",
"bytemuck",
@@ -1990,7 +1990,7 @@ dependencies = [
[[package]]
name = "egui"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
dependencies = [
"accesskit",
"ahash",
@@ -2007,7 +2007,7 @@ dependencies = [
[[package]]
name = "egui-wgpu"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
dependencies = [
"ahash",
"bytemuck",
@@ -2026,7 +2026,7 @@ dependencies = [
[[package]]
name = "egui-winit"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
dependencies = [
"accesskit_winit",
"ahash",
@@ -2068,7 +2068,7 @@ dependencies = [
[[package]]
name = "egui_extras"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
dependencies = [
"ahash",
"egui",
@@ -2085,7 +2085,7 @@ dependencies = [
[[package]]
name = "egui_glow"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
dependencies = [
"ahash",
"bytemuck",
@@ -2102,7 +2102,7 @@ dependencies = [
[[package]]
name = "egui_kittest"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
dependencies = [
"dify",
"egui",
@@ -2171,7 +2171,7 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "emath"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
dependencies = [
"bytemuck",
"serde",
@@ -2287,7 +2287,7 @@ dependencies = [
[[package]]
name = "epaint"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
dependencies = [
"ab_glyph",
"ahash",
@@ -2306,7 +2306,7 @@ dependencies = [
[[package]]
name = "epaint_default_fonts"
version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0823a36952a6791a0e28e6e8eac4f35639ab3091#0823a36952a6791a0e28e6e8eac4f35639ab3091"
+source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
[[package]]
name = "equivalent"
@@ -3731,7 +3731,8 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
[[package]]
name = "kittest"
version = "0.1.0"
-source = "git+https://github.com/rerun-io/kittest?branch=main#06e01f17fed36a997e1541f37b2d47e3771d7533"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f659954571a3c132356bd15c25f0dcf14d270a28ec5c58797adc2f432831bed5"
dependencies = [
"accesskit",
"accesskit_consumer 0.25.0",
diff --git a/Cargo.toml b/Cargo.toml
index 39f77691d90b..8a8b7a28d3e9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -554,13 +554,13 @@ significant_drop_tightening = "allow" # An update of parking_lot made this trigg
# As a last resport, patch with a commit to our own repository.
# ALWAYS document what PR the commit hash is part of, or when it was merged into the upstream trunk.
-ecolor = { git = "https://github.com/emilk/egui.git", rev = "0823a36952a6791a0e28e6e8eac4f35639ab3091" } # egui master 2024-12-16 15:08
-eframe = { git = "https://github.com/emilk/egui.git", rev = "0823a36952a6791a0e28e6e8eac4f35639ab3091" } # egui master 2024-12-16 15:08
-egui = { git = "https://github.com/emilk/egui.git", rev = "0823a36952a6791a0e28e6e8eac4f35639ab3091" } # egui master 2024-12-16 15:08
-egui_extras = { git = "https://github.com/emilk/egui.git", rev = "0823a36952a6791a0e28e6e8eac4f35639ab3091" } # egui master 2024-12-16 15:08
-egui_kittest = { git = "https://github.com/emilk/egui.git", rev = "0823a36952a6791a0e28e6e8eac4f35639ab3091" } # egui master 2024-12-16 15:08
-egui-wgpu = { git = "https://github.com/emilk/egui.git", rev = "0823a36952a6791a0e28e6e8eac4f35639ab3091" } # egui master 2024-12-16 15:08
-emath = { git = "https://github.com/emilk/egui.git", rev = "0823a36952a6791a0e28e6e8eac4f35639ab3091" } # egui master 2024-12-16 15:08
+ecolor = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+eframe = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+egui = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+egui_extras = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+egui_kittest = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+egui-wgpu = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+emath = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
# Useful while developing:
# ecolor = { path = "../../egui/crates/ecolor" }
From cd524ea21b0bd8b9a635401886deccca53125a3e Mon Sep 17 00:00:00 2001
From: Andreas Reich
Date: Tue, 17 Dec 2024 15:04:38 +0100
Subject: [PATCH 05/30] Fix graph node hover (#8508)
* no hover at all
* no highlight on non-text box nodes
---
crates/viewer/re_view_graph/src/ui/draw.rs | 7 +++++++
crates/viewer/re_view_graph/src/view.rs | 4 +++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/crates/viewer/re_view_graph/src/ui/draw.rs b/crates/viewer/re_view_graph/src/ui/draw.rs
index 4122377be478..bc6f30e285ea 100644
--- a/crates/viewer/re_view_graph/src/ui/draw.rs
+++ b/crates/viewer/re_view_graph/src/ui/draw.rs
@@ -130,6 +130,13 @@ fn draw_circle_label(
Color32::TRANSPARENT,
Stroke::new(2.0, visuals.selection.stroke.color),
);
+ } else if highlight.hover == HoverHighlight::Hovered {
+ painter.circle(
+ resp.rect.center(),
+ radius - 2.0,
+ Color32::TRANSPARENT,
+ Stroke::new(2.0, visuals.widgets.hovered.bg_fill),
+ );
}
resp
diff --git a/crates/viewer/re_view_graph/src/view.rs b/crates/viewer/re_view_graph/src/view.rs
index 3bef101d01c3..11b08183f761 100644
--- a/crates/viewer/re_view_graph/src/view.rs
+++ b/crates/viewer/re_view_graph/src/view.rs
@@ -200,7 +200,9 @@ Display a graph of nodes and edges.
}
});
- if resp.hovered() {
+ // Don't set the view to hovered if something else was already hovered.
+ // (this can only mean that a graph node/edge was hovered)
+ if resp.hovered() && ctx.selection_state().hovered_items().is_empty() {
ctx.selection_state().set_hovered(Item::View(query.view_id));
}
From 0a5fe0873042f40eaf7f3e714d65df7b50876f17 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jochen=20G=C3=B6rtler?=
Date: Tue, 17 Dec 2024 15:30:49 +0100
Subject: [PATCH 06/30] Fix setting fallback `Position2D` and geometry
improvements (#8505)
### Related
* Closes #8503.
### What
This fixes setting the fallback value in the selection panel.
It also deals with geometry that can't be drawn in a meaningful way
because of that.
---
.../re_view_graph/src/layout/provider.rs | 42 +++++++++++++------
.../release_checklist/check_graph_view.py | 11 +++++
2 files changed, 40 insertions(+), 13 deletions(-)
diff --git a/crates/viewer/re_view_graph/src/layout/provider.rs b/crates/viewer/re_view_graph/src/layout/provider.rs
index b49f3f6669a0..d9c718d29146 100644
--- a/crates/viewer/re_view_graph/src/layout/provider.rs
+++ b/crates/viewer/re_view_graph/src/layout/provider.rs
@@ -139,13 +139,17 @@ impl ForceLayoutProvider {
layout: &Layout,
params: &ForceLayoutParams,
) -> Self {
- let nodes = request.all_nodes().map(|(id, v)| {
- if let Some(rect) = layout.get_node(&id) {
- let pos = rect.center();
- fj::Node::from(v).position(pos.x as f64, pos.y as f64)
- } else {
- fj::Node::from(v)
+ let nodes = request.all_nodes().map(|(id, template)| {
+ let node = fj::Node::from(template);
+
+ if template.fixed_position.is_none() {
+ if let Some(rect) = layout.get_node(&id) {
+ let pos = rect.center();
+ return node.position(pos.x as f64, pos.y as f64);
+ }
}
+
+ node
});
let radii = request
.all_nodes()
@@ -207,13 +211,17 @@ impl ForceLayoutProvider {
target: edge.target,
})
.or_default();
- geometries.push(EdgeGeometry {
- target_arrow,
- path: line_segment(
- layout.nodes[&edge.source],
- layout.nodes[&edge.target],
- ),
- });
+
+ let source = layout.nodes[&edge.source];
+ let target = layout.nodes[&edge.target];
+
+ // We only draw edges if they can be displayed meaningfully.
+ if source.center() != target.center() && !source.intersects(target) {
+ geometries.push(EdgeGeometry {
+ target_arrow,
+ path: line_segment(source, target),
+ });
+ }
} else {
// Multiple edges occupy the same space, so we fan them out.
let num_edges = edges.len();
@@ -222,6 +230,14 @@ impl ForceLayoutProvider {
let source_rect = layout.nodes[slot_source];
let target_rect = layout.nodes[slot_target];
+ if source_rect.center() == target_rect.center()
+ || source_rect.intersects(target_rect)
+ {
+ // There is no meaningful geometry to draw here.
+ // Keep in mind that self-edges are handled separately above.
+ continue;
+ }
+
let d = (target_rect.center() - source_rect.center()).normalized();
let source_pos = source_rect.intersects_ray_from_center(d);
diff --git a/tests/python/release_checklist/check_graph_view.py b/tests/python/release_checklist/check_graph_view.py
index 97e9964394bd..27ae31d839c4 100644
--- a/tests/python/release_checklist/check_graph_view.py
+++ b/tests/python/release_checklist/check_graph_view.py
@@ -15,6 +15,7 @@
* `graph` has directed edges, while `graph2` has undirected edges.
* `graph` and `graph2` are shown in two different viewers.
* There is a third viewer, `Both`, that shows both `graph` and `graph2` in the same viewer.
+* The `coincident` viewer shows two nodes, `A` and `B`, at the same position
"""
@@ -22,6 +23,10 @@ def log_readme() -> None:
rr.log("readme", rr.TextDocument(README, media_type=rr.MediaType.MARKDOWN), static=True)
+def log_coincident_nodes() -> None:
+ rr.log("coincident", rr.GraphNodes(["A", "B"], labels=["A", "B"], positions=[[-150, 0], [150, 0]]))
+
+
def log_graphs() -> None:
DATA = [
("A", None),
@@ -51,6 +56,7 @@ def run(args: Namespace) -> None:
log_readme()
log_graphs()
+ log_coincident_nodes()
rr.send_blueprint(
rrb.Blueprint(
@@ -58,6 +64,11 @@ def run(args: Namespace) -> None:
rrb.GraphView(origin="graph", name="Graph 1"),
rrb.GraphView(origin="graph2", name="Graph 2"),
rrb.GraphView(name="Both", contents=["/graph", "/graph2"]),
+ rrb.GraphView(
+ origin="coincident",
+ name="Coincident nodes",
+ overrides={"coincident": [rr.components.Position2D([0, 0])]},
+ ),
rrb.TextDocumentView(origin="readme", name="Instructions"),
)
)
From 57b45e7162a9c4f07cc2da0da3416f6cf7783697 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt
Date: Tue, 17 Dec 2024 16:58:13 +0100
Subject: [PATCH 07/30] Hide outline rectangle around views (#8507)
* Closes https://github.com/rerun-io/rerun/issues/8494
Removes the highlighted rectangle around views that are hovered or
selected.
Why? Because we already have the tab title for this.
Keeps it for containers, because they have no tab title.
https://github.com/user-attachments/assets/bb407161-f3a8-4c66-bbd9-816f8dd28561
---
crates/viewer/re_viewport/src/viewport_ui.rs | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/crates/viewer/re_viewport/src/viewport_ui.rs b/crates/viewer/re_viewport/src/viewport_ui.rs
index ad4d3a005480..602c57a7f67b 100644
--- a/crates/viewer/re_viewport/src/viewport_ui.rs
+++ b/crates/viewer/re_viewport/src/viewport_ui.rs
@@ -165,6 +165,13 @@ impl ViewportUi {
continue;
};
+ if matches!(contents, Contents::View(_))
+ && !should_display_drop_destination_frame
+ {
+ // We already light up the view tab title; that is enough
+ continue;
+ }
+
// We want the rectangle to be on top of everything in the viewport,
// including stuff in "zoom-pan areas", like we use in the graph view.
let top_layer_id =
From 75c6f146c89a9543a37c56cf61fc275b543891e7 Mon Sep 17 00:00:00 2001
From: Antoine Beyeler <49431240+abey79@users.noreply.github.com>
Date: Tue, 17 Dec 2024 17:41:11 +0100
Subject: [PATCH 08/30] Fix the event count in the static-over-temporal error
message (#8513)
Regression introduced in #6934 and caught by
`check_static_components_ui`
Before:
![image](https://github.com/user-attachments/assets/b06bea44-ae51-4989-a3a2-eb4f4a7e1bc0)
After:
![image](https://github.com/user-attachments/assets/1250995a-6ae8-42ad-90c9-aee42234ff4f)
---
crates/store/re_chunk_store/src/stats.rs | 20 ++++++++++++++++++++
crates/viewer/re_data_ui/src/component.rs | 3 +--
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/crates/store/re_chunk_store/src/stats.rs b/crates/store/re_chunk_store/src/stats.rs
index 1f281b8179be..213d946b9b23 100644
--- a/crates/store/re_chunk_store/src/stats.rs
+++ b/crates/store/re_chunk_store/src/stats.rs
@@ -320,4 +320,24 @@ impl ChunkStore {
.sum()
})
}
+
+ /// Returns the number of temporal events logged for an entity for a specific component on all timelines.
+ ///
+ /// This ignores static events.
+ pub fn num_temporal_events_for_component_on_all_timelines(
+ &self,
+ entity_path: &EntityPath,
+ component_name: ComponentName,
+ ) -> u64 {
+ self.all_timelines()
+ .iter()
+ .map(|timeline| {
+ self.num_temporal_events_for_component_on_timeline(
+ timeline,
+ entity_path,
+ component_name,
+ )
+ })
+ .sum()
+ }
}
diff --git a/crates/viewer/re_data_ui/src/component.rs b/crates/viewer/re_data_ui/src/component.rs
index eeab5dabdbf0..663923ddb5cd 100644
--- a/crates/viewer/re_data_ui/src/component.rs
+++ b/crates/viewer/re_data_ui/src/component.rs
@@ -75,8 +75,7 @@ impl DataUi for ComponentPathLatestAtResults<'_> {
let temporal_message_count = engine
.store()
- .num_temporal_events_for_component_on_timeline(
- &query.timeline(),
+ .num_temporal_events_for_component_on_all_timelines(
entity_path,
*component_name,
);
From 7a19d102bfeb3b132432741b58f39c58b2ae65d1 Mon Sep 17 00:00:00 2001
From: Andreas Reich
Date: Tue, 17 Dec 2024 17:53:57 +0100
Subject: [PATCH 09/30] Fix Plane3D component ui when it's non-editable (#8509)
* Fixes https://github.com/rerun-io/rerun/issues/8488
Shows normal always as a vec now
![image](https://github.com/user-attachments/assets/b23a1437-bc67-4054-abc3-04d3a7fa973f)
Editable one is unchanged (we'd need more space for edit boxes, so we
rely on multiline ui):
![image](https://github.com/user-attachments/assets/ebf0b8e6-c116-49f4-be99-10731e9c99b8)
---
crates/viewer/re_component_ui/src/plane3d.rs | 62 +++++++++++---------
1 file changed, 33 insertions(+), 29 deletions(-)
diff --git a/crates/viewer/re_component_ui/src/plane3d.rs b/crates/viewer/re_component_ui/src/plane3d.rs
index 2b3484f60e19..d0432dd7a4a2 100644
--- a/crates/viewer/re_component_ui/src/plane3d.rs
+++ b/crates/viewer/re_component_ui/src/plane3d.rs
@@ -83,37 +83,41 @@ pub fn edit_or_view_plane3d(
let distance = value.distance();
ui.label("n");
- // Show simplified combobox if this is axis aligned.
- let mut axis_dir = AxisDirection::from(glam::Vec3::from(value.normal()));
- let normal_response = response_with_changes_of_inner(
- egui::ComboBox::from_id_salt("plane_normal")
- .selected_text(format!("{axis_dir}"))
- .height(250.0)
- .show_ui(ui, |ui| {
- let mut variants = AxisDirection::VARIANTS.iter();
- #[allow(clippy::unwrap_used)] // We know there's more than zero variants.
- let variant = variants.next().unwrap();
-
- let mut response =
- ui.selectable_value(&mut axis_dir, *variant, variant.to_string());
- for variant in variants {
- response |= ui.selectable_value(&mut axis_dir, *variant, variant.to_string());
- }
-
- if let MaybeMutRef::MutRef(value) = value {
+
+ let normal_response = if let Some(value_mut) = value.as_mut() {
+ // Show simplified combobox if this is axis aligned.
+ let mut axis_dir = AxisDirection::from(glam::Vec3::from(value_mut.normal()));
+ response_with_changes_of_inner(
+ egui::ComboBox::from_id_salt("plane_normal")
+ .selected_text(format!("{axis_dir}"))
+ .height(250.0)
+ .show_ui(ui, |ui| {
+ let mut variants = AxisDirection::VARIANTS.iter();
+ #[allow(clippy::unwrap_used)] // We know there's more than zero variants.
+ let variant = variants.next().unwrap();
+
+ let mut response =
+ ui.selectable_value(&mut axis_dir, *variant, variant.to_string());
+ for variant in variants {
+ response |=
+ ui.selectable_value(&mut axis_dir, *variant, variant.to_string());
+ }
if let Ok(new_dir) = glam::Vec3::try_from(axis_dir) {
- **value = components::Plane3D::new(new_dir, distance);
+ *value_mut = components::Plane3D::new(new_dir, distance);
}
- }
- response
- }),
- )
- .on_hover_text(format!(
- "{} {} {}",
- re_format::format_f32(value.normal().x()),
- re_format::format_f32(value.normal().y()),
- re_format::format_f32(value.normal().z()),
- ));
+ response
+ }),
+ )
+ .on_hover_text(format!(
+ "{} {} {}",
+ re_format::format_f32(value.normal().x()),
+ re_format::format_f32(value.normal().y()),
+ re_format::format_f32(value.normal().z()),
+ ))
+ } else {
+ let normal = value.normal();
+ edit_or_view_vec3d_raw(ui, &mut MaybeMutRef::Ref(&normal))
+ };
ui.label("d");
let mut maybe_mut_distance = match value {
From 13b56d789e1b6db381d7c273c54ed19a63e2c415 Mon Sep 17 00:00:00 2001
From: Clement Rey
Date: Tue, 17 Dec 2024 17:59:58 +0100
Subject: [PATCH 10/30] Fix missing `ComponentBatchCow` export in public lib
(#8515)
Title.
---
crates/top/re_sdk/src/lib.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crates/top/re_sdk/src/lib.rs b/crates/top/re_sdk/src/lib.rs
index ebb46e4ef346..2ef51e0e1dd7 100644
--- a/crates/top/re_sdk/src/lib.rs
+++ b/crates/top/re_sdk/src/lib.rs
@@ -91,7 +91,7 @@ pub mod time {
pub use time::{Time, TimePoint, Timeline};
pub use re_types_core::{
- Archetype, ArchetypeName, AsComponents, Component, ComponentBatch,
+ Archetype, ArchetypeName, AsComponents, Component, ComponentBatch, ComponentBatchCow,
ComponentBatchCowWithDescriptor, ComponentDescriptor, ComponentName, DatatypeName,
DeserializationError, DeserializationResult, GenericIndicatorComponent, Loggable,
LoggableBatch, NamedIndicatorComponent, SerializationError, SerializationResult, SizeBytes,
From 5a5e2b5a46e12284976c6d669ac83eb088b972fb Mon Sep 17 00:00:00 2001
From: Clement Rey
Date: Tue, 17 Dec 2024 18:25:00 +0100
Subject: [PATCH 11/30] egui 0.30 (#8516)
Title.
---
Cargo.lock | 304 ++++++++++--------
Cargo.toml | 40 +--
.../re_component_ui/src/marker_shape.rs | 2 +-
3 files changed, 189 insertions(+), 157 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 951fba200727..60076725fe56 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -38,7 +38,7 @@ dependencies = [
"accesskit_consumer 0.26.0",
"atspi-common",
"serde",
- "thiserror",
+ "thiserror 1.0.65",
"zvariant",
]
@@ -187,7 +187,7 @@ dependencies = [
"ndk-context",
"ndk-sys 0.6.0+11769913",
"num_enum",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -318,7 +318,7 @@ dependencies = [
"argh_shared",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -691,7 +691,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -731,7 +731,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -748,7 +748,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -854,7 +854,7 @@ dependencies = [
"num-derive",
"num-rational",
"num-traits",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -1066,7 +1066,7 @@ checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -1108,7 +1108,7 @@ dependencies = [
"sha2",
"ssri",
"tempfile",
- "thiserror",
+ "thiserror 1.0.65",
"tokio",
"tokio-stream",
"walkdir",
@@ -1125,7 +1125,7 @@ dependencies = [
"polling",
"rustix",
"slab",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -1156,7 +1156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03fa8484a7f2eef80e6dd2e2be90b322b9c29aeb1bbc206013d6eb2104db7241"
dependencies = [
"serde",
- "thiserror",
+ "thiserror 1.0.65",
"toml",
]
@@ -1205,7 +1205,7 @@ dependencies = [
"semver",
"serde",
"serde_json",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -1321,7 +1321,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "696283b40e1a39d208ee614b92e5f6521d16962edeb47c48372585ec92419943"
dependencies = [
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -1355,7 +1355,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -1768,7 +1768,7 @@ dependencies = [
"ident_case",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -1779,7 +1779,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -1877,7 +1877,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -1933,8 +1933,9 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]]
name = "ecolor"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d72e9c39f6e11a2e922d04a34ec5e7ef522ea3f5a1acfca7a19d16ad5fe50f5"
dependencies = [
"bytemuck",
"color-hex",
@@ -1950,8 +1951,9 @@ checksum = "18aade80d5e09429040243ce1143ddc08a92d7a22820ac512610410a4dd5214f"
[[package]]
name = "eframe"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2f2d9e7ea2d11ec9e98a8683b6eb99f9d7d0448394ef6e0d6d91bd4eb817220"
dependencies = [
"ahash",
"bytemuck",
@@ -1989,8 +1991,9 @@ dependencies = [
[[package]]
name = "egui"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "252d52224d35be1535d7fd1d6139ce071fb42c9097773e79f7665604f5596b5e"
dependencies = [
"accesskit",
"ahash",
@@ -2006,8 +2009,9 @@ dependencies = [
[[package]]
name = "egui-wgpu"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26c1e821d2d8921ef6ce98b258c7e24d9d6aab2ca1f9cdf374eca997e7f67f59"
dependencies = [
"ahash",
"bytemuck",
@@ -2016,7 +2020,7 @@ dependencies = [
"epaint",
"log",
"profiling",
- "thiserror",
+ "thiserror 1.0.65",
"type-map",
"web-time",
"wgpu",
@@ -2025,8 +2029,9 @@ dependencies = [
[[package]]
name = "egui-winit"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e84c2919cd9f3a38a91e8f84ac6a245c19251fd95226ed9fae61d5ea564fce3"
dependencies = [
"accesskit_winit",
"ahash",
@@ -2044,9 +2049,9 @@ dependencies = [
[[package]]
name = "egui_commonmark"
-version = "0.18.0"
+version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f169228b94d1c8eb9330b7ea1b5f65b1193b6bea95159c87f574ed4aff8c172"
+checksum = "43d76bd08ab5264071aab3bd0ad0f5bdc34cf36cbb4be4c17c853a935c84d5fe"
dependencies = [
"egui",
"egui_commonmark_backend",
@@ -2056,9 +2061,9 @@ dependencies = [
[[package]]
name = "egui_commonmark_backend"
-version = "0.18.0"
+version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcd08f95abeb137e59c9bfdd0880d362bff74a83afe13805fde7a2d014ef773d"
+checksum = "47acd9dde83a575127a498e4ef77b00377f85c258ae259214bb125c79efefd00"
dependencies = [
"egui",
"egui_extras",
@@ -2067,8 +2072,9 @@ dependencies = [
[[package]]
name = "egui_extras"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d7a8198c088b1007108cb2d403bc99a5e370999b200db4f14559610d7330126"
dependencies = [
"ahash",
"egui",
@@ -2084,8 +2090,9 @@ dependencies = [
[[package]]
name = "egui_glow"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3eaf6264cc7608e3e69a7d57a6175f438275f1b3889c1a551b418277721c95e6"
dependencies = [
"ahash",
"bytemuck",
@@ -2101,8 +2108,9 @@ dependencies = [
[[package]]
name = "egui_kittest"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27fe1ba792adf7a7bd8c51852d2dfa2a1711aea05bc532f9aa5f54a15533d33e"
dependencies = [
"dify",
"egui",
@@ -2114,9 +2122,9 @@ dependencies = [
[[package]]
name = "egui_plot"
-version = "0.29.0"
+version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8dca4871c15d51aadb79534dcf51a8189e5de3426ee7b465eb7db9a0a81ea67"
+checksum = "c226cae80a6ee10c4d3aaf9e33bd9e9b2f1c0116b6036bdc2a1cfc9d2d0dcc10"
dependencies = [
"ahash",
"egui",
@@ -2125,9 +2133,9 @@ dependencies = [
[[package]]
name = "egui_table"
-version = "0.1.0"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ef148ce13d97a23376b92d3c5d0dddedd98c28b17053ceb326b31b92ea45d07"
+checksum = "dc957dce337da3794d73f0c20a998e205850ed8a0fa1410432bddf31133667f8"
dependencies = [
"egui",
"serde",
@@ -2136,8 +2144,9 @@ dependencies = [
[[package]]
name = "egui_tiles"
-version = "0.10.1"
-source = "git+https://github.com/rerun-io/egui_tiles?rev=48e0ef566479000a23d8dabf84badced98f1b9a6#48e0ef566479000a23d8dabf84badced98f1b9a6"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "588dcf9028464fb4d23baf1f7805c13927fb540f2f9096f7d177b814848645a3"
dependencies = [
"ahash",
"egui",
@@ -2170,8 +2179,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "emath"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4fe73c1207b864ee40aa0b0c038d6092af1030744678c60188a05c28553515d"
dependencies = [
"bytemuck",
"serde",
@@ -2216,7 +2226,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -2237,7 +2247,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -2248,7 +2258,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -2269,7 +2279,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -2286,8 +2296,9 @@ dependencies = [
[[package]]
name = "epaint"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5666f8d25236293c966fbb3635eac18b04ad1914e3bab55bc7d44b9980cafcac"
dependencies = [
"ab_glyph",
"ahash",
@@ -2305,8 +2316,9 @@ dependencies = [
[[package]]
name = "epaint_default_fonts"
-version = "0.29.1"
-source = "git+https://github.com/emilk/egui.git?rev=0fb340fe89e9476b2fec15c2eff1405e51e5c04e#0fb340fe89e9476b2fec15c2eff1405e51e5c04e"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66f6ddac3e6ac6fd4c3d48bb8b1943472f8da0f43a4303bcd8a18aa594401c80"
[[package]]
name = "equivalent"
@@ -2514,7 +2526,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -2616,7 +2628,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -2794,7 +2806,7 @@ dependencies = [
"inflections",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -3440,7 +3452,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -3676,7 +3688,7 @@ dependencies = [
"combine",
"jni-sys",
"log",
- "thiserror",
+ "thiserror 1.0.65",
"walkdir",
"windows-sys 0.45.0",
]
@@ -4076,7 +4088,7 @@ checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e"
dependencies = [
"miette-derive",
"once_cell",
- "thiserror",
+ "thiserror 1.0.65",
"unicode-width",
]
@@ -4088,7 +4100,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -4213,7 +4225,7 @@ dependencies = [
"rustc-hash 1.1.0",
"spirv",
"termcolor",
- "thiserror",
+ "thiserror 1.0.65",
"unicode-xid",
]
@@ -4270,7 +4282,7 @@ dependencies = [
"ndk-sys 0.6.0+11769913",
"num_enum",
"raw-window-handle",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -4397,7 +4409,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -4460,7 +4472,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -4929,7 +4941,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -5111,7 +5123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
dependencies = [
"proc-macro2",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -5149,7 +5161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30"
dependencies = [
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -5179,7 +5191,7 @@ dependencies = [
"prost",
"prost-types",
"regex",
- "syn 2.0.85",
+ "syn 2.0.87",
"tempfile",
]
@@ -5193,7 +5205,7 @@ dependencies = [
"itertools 0.13.0",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -5314,7 +5326,7 @@ dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -5327,7 +5339,7 @@ dependencies = [
"proc-macro2",
"pyo3-build-config",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -5363,7 +5375,7 @@ dependencies = [
"rustc-hash 2.0.0",
"rustls 0.23.18",
"socket2",
- "thiserror",
+ "thiserror 1.0.65",
"tokio",
"tracing",
]
@@ -5380,7 +5392,7 @@ dependencies = [
"rustc-hash 2.0.0",
"rustls 0.23.18",
"slab",
- "thiserror",
+ "thiserror 1.0.65",
"tinyvec",
"tracing",
]
@@ -5519,7 +5531,7 @@ dependencies = [
"serde",
"serde_json",
"sha2",
- "thiserror",
+ "thiserror 1.0.65",
"time",
"url",
"uuid",
@@ -5635,7 +5647,7 @@ dependencies = [
"re_types_core",
"serde",
"similar-asserts",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -5665,7 +5677,7 @@ dependencies = [
"re_types",
"re_types_core",
"similar-asserts",
- "thiserror",
+ "thiserror 1.0.65",
"tinyvec",
"web-time",
]
@@ -5762,7 +5774,7 @@ dependencies = [
"re_tracing",
"re_types",
"tempfile",
- "thiserror",
+ "thiserror 1.0.65",
"uuid",
"walkdir",
]
@@ -5895,7 +5907,7 @@ dependencies = [
"re_types_core",
"serde",
"similar-asserts",
- "thiserror",
+ "thiserror 1.0.65",
"web-time",
]
@@ -5935,7 +5947,7 @@ dependencies = [
"re_protos",
"re_smart_channel",
"re_types",
- "thiserror",
+ "thiserror 1.0.65",
"tokio",
"tokio-stream",
"tonic",
@@ -5989,7 +6001,7 @@ dependencies = [
"re_types",
"rmp-serde",
"serde_test",
- "thiserror",
+ "thiserror 1.0.65",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
@@ -6028,7 +6040,7 @@ dependencies = [
"serde_bytes",
"similar-asserts",
"static_assertions",
- "thiserror",
+ "thiserror 1.0.65",
"time",
"typenum",
"uuid",
@@ -6077,7 +6089,7 @@ dependencies = [
"num-rational",
"serde",
"serde_json",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -6085,7 +6097,7 @@ name = "re_protos"
version = "0.21.0-alpha.1+dev"
dependencies = [
"prost",
- "thiserror",
+ "thiserror 1.0.65",
"tonic",
"tonic-web-wasm-client",
]
@@ -6128,7 +6140,7 @@ dependencies = [
"re_types_core",
"seq-macro",
"similar-asserts",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -6192,7 +6204,7 @@ dependencies = [
"slotmap",
"smallvec",
"static_assertions",
- "thiserror",
+ "thiserror 1.0.65",
"tinystl",
"tobj",
"type-map",
@@ -6261,7 +6273,7 @@ dependencies = [
"re_web_viewer_server",
"re_ws_comms",
"similar-asserts",
- "thiserror",
+ "thiserror 1.0.65",
"webbrowser",
]
@@ -6278,7 +6290,7 @@ dependencies = [
"re_log_encoding",
"re_log_types",
"re_smart_channel",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -6422,7 +6434,7 @@ dependencies = [
"serde",
"similar-asserts",
"smallvec",
- "thiserror",
+ "thiserror 1.0.65",
"uuid",
]
@@ -6450,7 +6462,7 @@ dependencies = [
"re_tracing",
"rust-format",
"serde",
- "syn 2.0.85",
+ "syn 2.0.87",
"tempfile",
"toml",
"unindent",
@@ -6479,7 +6491,7 @@ dependencies = [
"re_tuid",
"serde",
"smallvec",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -6531,7 +6543,7 @@ dependencies = [
"re_rav1d",
"re_tracing",
"serde",
- "thiserror",
+ "thiserror 1.0.65",
"wasm-bindgen",
"web-sys",
]
@@ -6599,7 +6611,7 @@ dependencies = [
"re_ui",
"re_viewer_context",
"re_viewport_blueprint",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -6689,7 +6701,7 @@ dependencies = [
"re_viewport_blueprint",
"serde",
"smallvec",
- "thiserror",
+ "thiserror 1.0.65",
"vec1",
"web-time",
]
@@ -6714,7 +6726,7 @@ dependencies = [
"re_view",
"re_viewer_context",
"re_viewport_blueprint",
- "thiserror",
+ "thiserror 1.0.65",
"wgpu",
]
@@ -6844,7 +6856,7 @@ dependencies = [
"serde_json",
"strum",
"strum_macros",
- "thiserror",
+ "thiserror 1.0.65",
"uuid",
"wasm-bindgen",
"wasm-bindgen-futures",
@@ -6903,7 +6915,7 @@ dependencies = [
"slotmap",
"smallvec",
"strum_macros",
- "thiserror",
+ "thiserror 1.0.65",
"uuid",
"wasm-bindgen-futures",
"wgpu",
@@ -6955,7 +6967,7 @@ dependencies = [
"re_viewer_context",
"slotmap",
"smallvec",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -6965,7 +6977,7 @@ dependencies = [
"document-features",
"re_analytics",
"re_log",
- "thiserror",
+ "thiserror 1.0.65",
"tiny_http",
]
@@ -6985,7 +6997,7 @@ dependencies = [
"re_memory",
"re_smart_channel",
"re_tracing",
- "thiserror",
+ "thiserror 1.0.65",
"tungstenite",
]
@@ -7015,7 +7027,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom",
"libredox",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -7163,7 +7175,7 @@ dependencies = [
"reqwest 0.11.27",
"serde",
"task-local-extensions",
- "thiserror",
+ "thiserror 1.0.65",
]
[[package]]
@@ -7641,7 +7653,7 @@ dependencies = [
"cargo-manifest",
"cargo_metadata 0.18.1",
"serde",
- "thiserror",
+ "thiserror 1.0.65",
"toml",
"tracing",
]
@@ -7880,7 +7892,7 @@ checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -7903,7 +7915,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -8108,7 +8120,7 @@ dependencies = [
"log",
"memmap2 0.9.5",
"rustix",
- "thiserror",
+ "thiserror 1.0.65",
"wayland-backend",
"wayland-client",
"wayland-csd-frame",
@@ -8220,7 +8232,7 @@ dependencies = [
"serde",
"sha-1",
"sha2",
- "thiserror",
+ "thiserror 1.0.65",
"xxhash-rust",
]
@@ -8277,7 +8289,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -8315,9 +8327,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.85"
+version = "2.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
+checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
dependencies = [
"proc-macro2",
"quote",
@@ -8347,7 +8359,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -8498,7 +8510,16 @@ version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5"
dependencies = [
- "thiserror-impl",
+ "thiserror-impl 1.0.65",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767"
+dependencies = [
+ "thiserror-impl 2.0.7",
]
[[package]]
@@ -8509,7 +8530,18 @@ checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
]
[[package]]
@@ -8698,7 +8730,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -8822,7 +8854,7 @@ dependencies = [
"prost-build",
"prost-types",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -8841,7 +8873,7 @@ dependencies = [
"httparse",
"js-sys",
"pin-project",
- "thiserror",
+ "thiserror 1.0.65",
"tonic",
"tower-service",
"wasm-bindgen",
@@ -8916,7 +8948,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -8956,7 +8988,7 @@ dependencies = [
"rustls 0.23.18",
"rustls-pki-types",
"sha1",
- "thiserror",
+ "thiserror 1.0.65",
"utf-8",
"webpki-roots 0.26.6",
]
@@ -9187,9 +9219,9 @@ dependencies = [
[[package]]
name = "walkers"
-version = "0.29.0"
+version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0688ad9bfb3bd49d997a6fb831e9ef21e251f4698c07e2f9902dcdb72d254bd"
+checksum = "70ca9bf7f5ff8a6d57de654d06fb25e5c6d60e0acc7e938d6fc15324b8e22a2f"
dependencies = [
"egui",
"egui_extras",
@@ -9201,7 +9233,7 @@ dependencies = [
"lru",
"reqwest 0.11.27",
"reqwest-middleware",
- "thiserror",
+ "thiserror 2.0.7",
"tokio",
"wasm-bindgen-futures",
]
@@ -9231,7 +9263,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -9271,7 +9303,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
"wasm-bindgen-shared",
]
@@ -9339,7 +9371,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -9646,7 +9678,7 @@ dependencies = [
"raw-window-handle",
"rustc-hash 1.1.0",
"smallvec",
- "thiserror",
+ "thiserror 1.0.65",
"wgpu-hal",
"wgpu-types",
]
@@ -9685,7 +9717,7 @@ dependencies = [
"renderdoc-sys",
"rustc-hash 1.1.0",
"smallvec",
- "thiserror",
+ "thiserror 1.0.65",
"wasm-bindgen",
"web-sys",
"wgpu-types",
@@ -9784,7 +9816,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -9795,7 +9827,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -10244,7 +10276,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
"synstructure",
]
@@ -10304,7 +10336,7 @@ checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
"zbus-lockstep",
"zbus_xml",
"zvariant",
@@ -10319,7 +10351,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
"zvariant_utils",
]
@@ -10365,7 +10397,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -10385,7 +10417,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
"synstructure",
]
@@ -10414,7 +10446,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -10467,7 +10499,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
"zvariant_utils",
]
@@ -10479,5 +10511,5 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
diff --git a/Cargo.toml b/Cargo.toml
index 8a8b7a28d3e9..25af7569328a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -124,27 +124,27 @@ dav1d = { package = "re_rav1d", version = "0.1.3", default-features = false }
# dav1d = { version = "0.10.3" } # Requires separate install of `dav1d` library. Fast in debug builds. Useful for development.
# egui-crates:
-ecolor = "0.29.1"
-eframe = { version = "0.29.1", default-features = false, features = [
+ecolor = "0.30.0"
+eframe = { version = "0.30.0", default-features = false, features = [
"accesskit",
"default_fonts",
"wayland",
"x11",
] }
-egui = { version = "0.29.1", features = [
+egui = { version = "0.30.0", features = [
"callstack",
"color-hex",
"log",
"rayon",
] }
-egui_commonmark = { version = "0.18", default-features = false }
-egui_extras = { version = "0.29.1", features = ["http", "image", "serde"] }
-egui_kittest = { version = "0.29.1", features = ["wgpu", "snapshot"] }
-egui_plot = "0.29.0" # https://github.com/emilk/egui_plot
-egui_table = "0.1.0" # https://github.com/rerun-io/egui_table
-egui_tiles = "0.10.1" # https://github.com/rerun-io/egui_tiles
-egui-wgpu = "0.29.1"
-emath = "0.29.1"
+egui_commonmark = { version = "0.19", default-features = false }
+egui_extras = { version = "0.30.0", features = ["http", "image", "serde"] }
+egui_kittest = { version = "0.30.0", features = ["wgpu", "snapshot"] }
+egui_plot = "0.30.0" # https://github.com/emilk/egui_plot
+egui_table = "0.2.0" # https://github.com/rerun-io/egui_table
+egui_tiles = "0.11.0" # https://github.com/rerun-io/egui_tiles
+egui-wgpu = "0.30.0"
+emath = "0.30.0"
# All of our direct external dependencies should be found here:
ahash = "0.8"
@@ -293,7 +293,7 @@ url = "2.3"
uuid = "1.1"
vec1 = "1.8"
walkdir = "2.0"
-walkers = "0.29"
+walkers = "0.32"
# NOTE: `rerun_js/web-viewer/build-wasm.mjs` is HIGHLY sensitive to changes in `wasm-bindgen`.
# Whenever updating `wasm-bindgen`, update this and the narrower dependency specifications in
# `crates/viewer/re_viewer/Cargo.toml`, and make sure that the build script still works.
@@ -554,13 +554,13 @@ significant_drop_tightening = "allow" # An update of parking_lot made this trigg
# As a last resport, patch with a commit to our own repository.
# ALWAYS document what PR the commit hash is part of, or when it was merged into the upstream trunk.
-ecolor = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
-eframe = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
-egui = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
-egui_extras = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
-egui_kittest = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
-egui-wgpu = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
-emath = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+# ecolor = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+# eframe = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+# egui = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+# egui_extras = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+# egui_kittest = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+# egui-wgpu = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
+# emath = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec15c2eff1405e51e5c04e" } # egui master 2024-12-16 just pre 0.30.0 release
# Useful while developing:
# ecolor = { path = "../../egui/crates/ecolor" }
@@ -574,7 +574,7 @@ emath = { git = "https://github.com/emilk/egui.git", rev = "0fb340fe89e9476b2fec
# egui_plot = { git = "https://github.com/emilk/egui_plot.git", rev = "1f6ae49a5f6bf43a869c215dea0d3028be8d742a" }
# egui_plot = { path = "../../egui_plot/egui_plot" }
-egui_tiles = { git = "https://github.com/rerun-io/egui_tiles", rev = "48e0ef566479000a23d8dabf84badced98f1b9a6" } # https://github.com/rerun-io/egui_tiles/pull/89 2024-11-19
+# egui_tiles = { git = "https://github.com/rerun-io/egui_tiles", rev = "48e0ef566479000a23d8dabf84badced98f1b9a6" } # https://github.com/rerun-io/egui_tiles/pull/89 2024-11-19
#egui_tiles = { path = "../egui_tiles" }
# egui_commonmark = { git = "https://github.com/rerun-io/egui_commonmark", rev = "7a9dc755bfa351a3796274cb8ca87129b051c084" } # https://github.com/lampsitter/egui_commonmark/pull/65
diff --git a/crates/viewer/re_component_ui/src/marker_shape.rs b/crates/viewer/re_component_ui/src/marker_shape.rs
index 5c08682ee1f4..92ceaa4245e4 100644
--- a/crates/viewer/re_component_ui/src/marker_shape.rs
+++ b/crates/viewer/re_component_ui/src/marker_shape.rs
@@ -81,7 +81,7 @@ pub(crate) fn paint_marker(
.filled(true);
let bounds = egui_plot::PlotBounds::new_symmetrical(0.5);
- let transform = egui_plot::PlotTransform::new(rect, bounds, true, true);
+ let transform = egui_plot::PlotTransform::new(rect, bounds, [true, true].into());
let mut shapes = vec![];
points.shapes(ui, &transform, &mut shapes);
From 06fed3db111fe3bd958e2cd4a9bcbeddf1d037fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jochen=20G=C3=B6rtler?=
Date: Tue, 17 Dec 2024 18:28:08 +0100
Subject: [PATCH 12/30] Fix graph view node highlight on hover (#8512)
### What
This fixes a problem introduced by #8495 that was only partially fixed
by #8508, with graph view highlights flickering (ping-ponging) in the
blueprint view.
---
crates/viewer/re_view_graph/src/ui/draw.rs | 14 +++++++-------
crates/viewer/re_view_graph/src/view.rs | 19 +++++++++++++++----
2 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/crates/viewer/re_view_graph/src/ui/draw.rs b/crates/viewer/re_view_graph/src/ui/draw.rs
index bc6f30e285ea..ad58886a3761 100644
--- a/crates/viewer/re_view_graph/src/ui/draw.rs
+++ b/crates/viewer/re_view_graph/src/ui/draw.rs
@@ -330,6 +330,7 @@ pub fn draw_graph(
layout: &Layout,
query: &ViewQuery<'_>,
lod: LevelOfDetail,
+ hover_click_item: &mut Option<(Item, Response)>,
) -> Rect {
let entity_path = graph.entity();
let entity_highlights = query.highlights.entity_highlight(entity_path.hash());
@@ -363,19 +364,18 @@ pub fn draw_graph(
});
});
- ctx.handle_select_hover_drag_interactions(
- &response,
- Item::DataResult(query.view_id, instance_path.clone()),
- false,
- );
-
- // double click selects the entire entity
+ // Warning! The order is very important here.
if response.double_clicked() {
// Select the entire entity
ctx.selection_state().set_selection(Item::DataResult(
query.view_id,
instance_path.entity_path.clone().into(),
));
+ } else if response.hovered() || response.clicked() {
+ *hover_click_item = Some((
+ Item::DataResult(query.view_id, instance_path.clone()),
+ response.clone(),
+ ));
}
response
diff --git a/crates/viewer/re_view_graph/src/view.rs b/crates/viewer/re_view_graph/src/view.rs
index 11b08183f761..b7ecf8b0d91e 100644
--- a/crates/viewer/re_view_graph/src/view.rs
+++ b/crates/viewer/re_view_graph/src/view.rs
@@ -1,3 +1,4 @@
+use egui::Response;
use re_log_types::EntityPath;
use re_types::{
blueprint::{
@@ -191,18 +192,28 @@ Display a graph of nodes and edges.
let level_of_detail = LevelOfDetail::from_scaling(ui_from_world.scaling);
+ let mut hover_click_item: Option<(Item, Response)> = None;
+
let resp = zoom_pan_area(ui, &mut ui_from_world, |ui| {
let mut world_bounding_rect = egui::Rect::NOTHING;
for graph in &graphs {
- let graph_rect = draw_graph(ui, ctx, graph, layout, query, level_of_detail);
+ let graph_rect = draw_graph(
+ ui,
+ ctx,
+ graph,
+ layout,
+ query,
+ level_of_detail,
+ &mut hover_click_item,
+ );
world_bounding_rect = world_bounding_rect.union(graph_rect);
}
});
- // Don't set the view to hovered if something else was already hovered.
- // (this can only mean that a graph node/edge was hovered)
- if resp.hovered() && ctx.selection_state().hovered_items().is_empty() {
+ if let Some((item, response)) = hover_click_item {
+ ctx.handle_select_hover_drag_interactions(&response, item, false);
+ } else if resp.hovered() {
ctx.selection_state().set_hovered(Item::View(query.view_id));
}
From b1fe788bf0186d9b5763ceebd29a6f7e30a9139d Mon Sep 17 00:00:00 2001
From: Clement Rey
Date: Tue, 17 Dec 2024 18:30:22 +0100
Subject: [PATCH 13/30] Fix broken doc test (#8517)
This broke `cargo t --all --all-features`, which is not run on CI, hence
why it doesn't show up there.
---
crates/top/rerun/src/lib.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/crates/top/rerun/src/lib.rs b/crates/top/rerun/src/lib.rs
index 486e96a4ae7a..c96f194d11a6 100644
--- a/crates/top/rerun/src/lib.rs
+++ b/crates/top/rerun/src/lib.rs
@@ -81,12 +81,13 @@
//! You can buffer the log messages in memory and then show them in an embedded viewer:
//!
//! ```no_run
+//! # let main_thread_token = re_capabilities::MainThreadToken::i_promise_i_am_on_the_main_thread();
//! # fn log_to(rec: &rerun::RecordingStream) {}
//! let (rec, storage) = rerun::RecordingStreamBuilder::new("rerun_example_app").memory()?;
//! log_to(&rec);
//!
//! // Will block program execution!
-//! rerun::native_viewer::show(storage.take());
+//! rerun::native_viewer::show(main_thread_token, storage.take());
//!
//! # Ok::<(), Box>(())
//! ```
From a040ce3ef13fc944dbbb0d2ad186a99e9dd0b7fd Mon Sep 17 00:00:00 2001
From: Antoine Beyeler <49431240+abey79@users.noreply.github.com>
Date: Tue, 17 Dec 2024 22:53:06 +0100
Subject: [PATCH 14/30] Make all checklists force activate their blueprints
(#8520)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
βπ»
This ensure a clean blueprint slate for checklists without having to
`rerun reset`
---------
Co-authored-by: Clement Rey
---
tests/python/release_checklist/README.md | 6 -
.../release_checklist/check_1d_tensor_data.py | 2 +
.../check_all_components_ui.py | 2 +
.../release_checklist/check_annotations.py | 2 +
tests/python/release_checklist/check_bgr.py | 3 +-
.../check_blueprint_bw_compat.py | 9 +-
.../check_blueprint_overrides.py | 39 +++---
.../check_chroma_subsampling.py | 3 +-
.../check_colormap_edit_ui.py | 3 +-
.../check_component_and_transform_clamping.py | 3 +-
.../check_container_hierarchy.py | 2 +
...ntext_menu_add_entity_to_new_space_view.py | 3 +-
.../check_context_menu_collapse_expand_all.py | 3 +-
...heck_context_menu_invalid_sub_container.py | 3 +-
.../check_context_menu_multi_selection.py | 3 +-
.../check_context_menu_single_selection.py | 3 +-
...xt_menu_single_selection_blueprint_tree.py | 3 +-
.../check_context_menu_suggested_origin.py | 3 +-
.../check_deselect_on_escape.py | 2 +
.../check_drag_and_drop_selection.py | 3 +-
.../release_checklist/check_draw_order.py | 10 +-
.../check_entity_drag_and_drop.py | 3 +-
tests/python/release_checklist/check_focus.py | 3 +-
.../release_checklist/check_graph_view.py | 26 ++--
.../check_graph_view_multi_self_edges.py | 22 ++--
.../release_checklist/check_heuristics_2d.py | 2 +
.../check_heuristics_mixed_2d_and_3d.py | 2 +
.../check_heuristics_mixed_all_root.py | 2 +
.../check_hover_select_reset.py | 2 +
.../check_latest_at_partial_updates.py | 6 +-
.../check_modal_scrolling.py | 6 +-
.../check_mono_entity_views.py | 3 +-
.../release_checklist/check_notebook.py | 2 +-
.../check_out_of_tree_data_results.py | 3 +-
.../release_checklist/check_overrides_2d.py | 113 +++++++++---------
.../check_parallelism_caching_reentrancy.py | 3 +-
.../release_checklist/check_plot_overrides.py | 2 +
.../check_range_partial_updates.py | 6 +-
.../release_checklist/check_rbl_import.py | 9 +-
.../release_checklist/check_scalar_clears.py | 2 +
.../check_static_components_ui.py | 2 +
.../check_static_override.py | 2 +
.../check_transform3d_hierarchy.py | 9 +-
.../python/release_checklist/check_version.py | 2 +
tests/python/release_checklist/check_video.py | 23 ++--
45 files changed, 197 insertions(+), 168 deletions(-)
diff --git a/tests/python/release_checklist/README.md b/tests/python/release_checklist/README.md
index ec710d70a2cf..d41559405ab9 100644
--- a/tests/python/release_checklist/README.md
+++ b/tests/python/release_checklist/README.md
@@ -3,12 +3,6 @@
# Interactive release checklist
Welcome to the release checklist.
-_**β Make sure to clean your blueprints if you want to start from a clean slate β **_
-
-```
-pixi run rerun reset
-```
-
Run the testlist with:
```
pixi run -e examples python tests/python/release_checklist/main.py
diff --git a/tests/python/release_checklist/check_1d_tensor_data.py b/tests/python/release_checklist/check_1d_tensor_data.py
index ae418182e979..2e7aa43ad5cc 100644
--- a/tests/python/release_checklist/check_1d_tensor_data.py
+++ b/tests/python/release_checklist/check_1d_tensor_data.py
@@ -50,6 +50,8 @@ def run(args: Namespace) -> None:
log_readme()
log_1d_data()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_all_components_ui.py b/tests/python/release_checklist/check_all_components_ui.py
index 0849f5983c8b..0885c5010ccc 100644
--- a/tests/python/release_checklist/check_all_components_ui.py
+++ b/tests/python/release_checklist/check_all_components_ui.py
@@ -299,6 +299,8 @@ def run(args: Namespace) -> None:
log_readme()
log_some_views()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_annotations.py b/tests/python/release_checklist/check_annotations.py
index 3e8ff3f8012b..a63db849ce91 100644
--- a/tests/python/release_checklist/check_annotations.py
+++ b/tests/python/release_checklist/check_annotations.py
@@ -55,6 +55,8 @@ def run(args: Namespace) -> None:
log_readme()
log_annotations()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_bgr.py b/tests/python/release_checklist/check_bgr.py
index f1316e5c0504..8011e6692ff9 100644
--- a/tests/python/release_checklist/check_bgr.py
+++ b/tests/python/release_checklist/check_bgr.py
@@ -75,7 +75,8 @@ def download_example_image_as_rgb() -> np.ndarray:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
sample_image_rgb_u8 = download_example_image_as_rgb()
log_readme()
diff --git a/tests/python/release_checklist/check_blueprint_bw_compat.py b/tests/python/release_checklist/check_blueprint_bw_compat.py
index dabc4fff1e5d..ee67012b93f5 100644
--- a/tests/python/release_checklist/check_blueprint_bw_compat.py
+++ b/tests/python/release_checklist/check_blueprint_bw_compat.py
@@ -54,12 +54,9 @@ def log_readme() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(
- args,
- f"{os.path.basename(__file__)}",
- recording_id=uuid4(),
- default_blueprint=rrb.Grid(rrb.TextDocumentView(origin="readme")),
- )
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+
+ rr.send_blueprint(rrb.Grid(rrb.TextDocumentView(origin="readme")), make_active=True, make_default=True)
log_readme()
diff --git a/tests/python/release_checklist/check_blueprint_overrides.py b/tests/python/release_checklist/check_blueprint_overrides.py
index 8fe9f5a91f6e..d09472cf39f6 100644
--- a/tests/python/release_checklist/check_blueprint_overrides.py
+++ b/tests/python/release_checklist/check_blueprint_overrides.py
@@ -34,26 +34,6 @@ def log_plots() -> None:
cos_of_t = cos(float(t) / 10.0)
rr.log("plots/cos", rr.Scalar(cos_of_t))
- rr.send_blueprint(
- rrb.Blueprint(
- rrb.Grid(
- rrb.TextDocumentView(origin="readme", name="Instructions"),
- rrb.TimeSeriesView(
- name="Plots",
- defaults=[rr.components.Color([0, 0, 255])],
- overrides={
- "plots/cos": [
- rrb.VisualizerOverrides("SeriesPoint"),
- rr.components.Color([0, 255, 0]),
- # TODDO(#6670): This should just be `rr.components.MarkerShape.Cross`
- rr.components.MarkerShapeBatch("cross"),
- ],
- },
- ),
- )
- )
- )
-
def run(args: Namespace) -> None:
rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
@@ -61,6 +41,25 @@ def run(args: Namespace) -> None:
log_readme()
log_plots()
+ blueprint = rrb.Blueprint(
+ rrb.Grid(
+ rrb.TextDocumentView(origin="readme", name="Instructions"),
+ rrb.TimeSeriesView(
+ name="Plots",
+ defaults=[rr.components.Color([0, 0, 255])],
+ overrides={
+ "plots/cos": [
+ rrb.VisualizerOverrides("SeriesPoint"),
+ rr.components.Color([0, 255, 0]),
+ # TODDO(#6670): This should just be `rr.components.MarkerShape.Cross`
+ rr.components.MarkerShapeBatch("cross"),
+ ],
+ },
+ ),
+ )
+ )
+ rr.send_blueprint(blueprint, make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_chroma_subsampling.py b/tests/python/release_checklist/check_chroma_subsampling.py
index c072c57a995e..cb321b1e1807 100644
--- a/tests/python/release_checklist/check_chroma_subsampling.py
+++ b/tests/python/release_checklist/check_chroma_subsampling.py
@@ -220,7 +220,8 @@ def log_data() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_data()
diff --git a/tests/python/release_checklist/check_colormap_edit_ui.py b/tests/python/release_checklist/check_colormap_edit_ui.py
index 7d7279469cd7..f022c49cdafb 100644
--- a/tests/python/release_checklist/check_colormap_edit_ui.py
+++ b/tests/python/release_checklist/check_colormap_edit_ui.py
@@ -35,7 +35,8 @@ def blueprint() -> rrb.BlueprintLike:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_depth_image()
diff --git a/tests/python/release_checklist/check_component_and_transform_clamping.py b/tests/python/release_checklist/check_component_and_transform_clamping.py
index cfabe06a2fb2..66f6c832d99b 100644
--- a/tests/python/release_checklist/check_component_and_transform_clamping.py
+++ b/tests/python/release_checklist/check_component_and_transform_clamping.py
@@ -73,7 +73,8 @@ def log_data() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_data()
diff --git a/tests/python/release_checklist/check_container_hierarchy.py b/tests/python/release_checklist/check_container_hierarchy.py
index 90150e3c6514..b602b0a2c422 100644
--- a/tests/python/release_checklist/check_container_hierarchy.py
+++ b/tests/python/release_checklist/check_container_hierarchy.py
@@ -91,6 +91,8 @@ def run(args: Namespace) -> None:
log_readme()
log_some_views()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_context_menu_add_entity_to_new_space_view.py b/tests/python/release_checklist/check_context_menu_add_entity_to_new_space_view.py
index 2bd104a8927a..ee01607dcac6 100644
--- a/tests/python/release_checklist/check_context_menu_add_entity_to_new_space_view.py
+++ b/tests/python/release_checklist/check_context_menu_add_entity_to_new_space_view.py
@@ -58,7 +58,8 @@ def log_some_views() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_some_views()
diff --git a/tests/python/release_checklist/check_context_menu_collapse_expand_all.py b/tests/python/release_checklist/check_context_menu_collapse_expand_all.py
index ee1d9d74ffa8..05d378b7e522 100644
--- a/tests/python/release_checklist/check_context_menu_collapse_expand_all.py
+++ b/tests/python/release_checklist/check_context_menu_collapse_expand_all.py
@@ -51,7 +51,8 @@ def log_some_views() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_some_views()
diff --git a/tests/python/release_checklist/check_context_menu_invalid_sub_container.py b/tests/python/release_checklist/check_context_menu_invalid_sub_container.py
index 9a32db71f704..670f3118b68f 100644
--- a/tests/python/release_checklist/check_context_menu_invalid_sub_container.py
+++ b/tests/python/release_checklist/check_context_menu_invalid_sub_container.py
@@ -46,7 +46,8 @@ def log_some_views() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_some_views()
diff --git a/tests/python/release_checklist/check_context_menu_multi_selection.py b/tests/python/release_checklist/check_context_menu_multi_selection.py
index 8864588a4fd4..7c42f59bbc8e 100644
--- a/tests/python/release_checklist/check_context_menu_multi_selection.py
+++ b/tests/python/release_checklist/check_context_menu_multi_selection.py
@@ -83,7 +83,8 @@ def log_some_views() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_some_views()
diff --git a/tests/python/release_checklist/check_context_menu_single_selection.py b/tests/python/release_checklist/check_context_menu_single_selection.py
index 14f7d5180281..5b9a3a9aca54 100644
--- a/tests/python/release_checklist/check_context_menu_single_selection.py
+++ b/tests/python/release_checklist/check_context_menu_single_selection.py
@@ -109,7 +109,8 @@ def log_some_views() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_some_views()
diff --git a/tests/python/release_checklist/check_context_menu_single_selection_blueprint_tree.py b/tests/python/release_checklist/check_context_menu_single_selection_blueprint_tree.py
index 4b5ab7a340f1..bcf310ca2fda 100644
--- a/tests/python/release_checklist/check_context_menu_single_selection_blueprint_tree.py
+++ b/tests/python/release_checklist/check_context_menu_single_selection_blueprint_tree.py
@@ -85,7 +85,8 @@ def log_some_views() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_some_views()
diff --git a/tests/python/release_checklist/check_context_menu_suggested_origin.py b/tests/python/release_checklist/check_context_menu_suggested_origin.py
index 02c120940bdb..a0b4933f8def 100644
--- a/tests/python/release_checklist/check_context_menu_suggested_origin.py
+++ b/tests/python/release_checklist/check_context_menu_suggested_origin.py
@@ -76,7 +76,8 @@ def log_some_views() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_some_views()
diff --git a/tests/python/release_checklist/check_deselect_on_escape.py b/tests/python/release_checklist/check_deselect_on_escape.py
index e74698bc9656..dd86cfeb7fa8 100644
--- a/tests/python/release_checklist/check_deselect_on_escape.py
+++ b/tests/python/release_checklist/check_deselect_on_escape.py
@@ -38,6 +38,8 @@ def run(args: Namespace) -> None:
log_readme()
log_some_data()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_drag_and_drop_selection.py b/tests/python/release_checklist/check_drag_and_drop_selection.py
index 2ca4d7ee9b82..1c1f90ce5fcc 100644
--- a/tests/python/release_checklist/check_drag_and_drop_selection.py
+++ b/tests/python/release_checklist/check_drag_and_drop_selection.py
@@ -63,7 +63,8 @@ def log_some_scalar_entities() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_some_scalar_entities()
diff --git a/tests/python/release_checklist/check_draw_order.py b/tests/python/release_checklist/check_draw_order.py
index df6ed675cbd0..87e397d6bf48 100644
--- a/tests/python/release_checklist/check_draw_order.py
+++ b/tests/python/release_checklist/check_draw_order.py
@@ -71,11 +71,11 @@ def run_2d_layering() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(
- args,
- f"{os.path.basename(__file__)}",
- recording_id=uuid4(),
- default_blueprint=rrb.Grid(rrb.Spatial2DView(origin="/"), rrb.TextDocumentView(origin="readme")),
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(
+ rrb.Blueprint(rrb.Grid(rrb.Spatial2DView(origin="/"), rrb.TextDocumentView(origin="readme"))),
+ make_active=True,
+ make_default=True,
)
log_readme()
diff --git a/tests/python/release_checklist/check_entity_drag_and_drop.py b/tests/python/release_checklist/check_entity_drag_and_drop.py
index 0e9d718064dd..85439d8cf03b 100644
--- a/tests/python/release_checklist/check_entity_drag_and_drop.py
+++ b/tests/python/release_checklist/check_entity_drag_and_drop.py
@@ -79,7 +79,8 @@ def log_some_scalar_entities() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_some_scalar_entities()
diff --git a/tests/python/release_checklist/check_focus.py b/tests/python/release_checklist/check_focus.py
index 91c25335f0e7..2bdbe82ce447 100644
--- a/tests/python/release_checklist/check_focus.py
+++ b/tests/python/release_checklist/check_focus.py
@@ -42,7 +42,8 @@ def log_some_views() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_some_views()
diff --git a/tests/python/release_checklist/check_graph_view.py b/tests/python/release_checklist/check_graph_view.py
index 27ae31d839c4..4998792806e9 100644
--- a/tests/python/release_checklist/check_graph_view.py
+++ b/tests/python/release_checklist/check_graph_view.py
@@ -59,19 +59,19 @@ def run(args: Namespace) -> None:
log_coincident_nodes()
rr.send_blueprint(
- rrb.Blueprint(
- rrb.Grid(
- rrb.GraphView(origin="graph", name="Graph 1"),
- rrb.GraphView(origin="graph2", name="Graph 2"),
- rrb.GraphView(name="Both", contents=["/graph", "/graph2"]),
- rrb.GraphView(
- origin="coincident",
- name="Coincident nodes",
- overrides={"coincident": [rr.components.Position2D([0, 0])]},
- ),
- rrb.TextDocumentView(origin="readme", name="Instructions"),
- )
- )
+ rrb.Grid(
+ rrb.GraphView(origin="graph", name="Graph 1"),
+ rrb.GraphView(origin="graph2", name="Graph 2"),
+ rrb.GraphView(name="Both", contents=["/graph", "/graph2"]),
+ rrb.GraphView(
+ origin="coincident",
+ name="Coincident nodes",
+ overrides={"coincident": [rr.components.Position2D([0, 0])]},
+ ),
+ rrb.TextDocumentView(origin="readme", name="Instructions"),
+ ),
+ make_default=True,
+ make_active=True,
)
diff --git a/tests/python/release_checklist/check_graph_view_multi_self_edges.py b/tests/python/release_checklist/check_graph_view_multi_self_edges.py
index 8b43cac93fc0..bef301ff7c23 100644
--- a/tests/python/release_checklist/check_graph_view_multi_self_edges.py
+++ b/tests/python/release_checklist/check_graph_view_multi_self_edges.py
@@ -55,17 +55,17 @@ def run(args: Namespace) -> None:
log_readme()
rr.send_blueprint(
- rrb.Blueprint(
- rrb.Grid(
- rrb.GraphView(origin="graph", name="Multiple edges and self-edges"),
- rrb.GraphView(
- origin="graph",
- name="Multiple edges and self-edges (without labels)",
- defaults=[rr.components.ShowLabels(False)],
- ),
- rrb.TextDocumentView(origin="readme", name="Instructions"),
- )
- )
+ rrb.Grid(
+ rrb.GraphView(origin="graph", name="Multiple edges and self-edges"),
+ rrb.GraphView(
+ origin="graph",
+ name="Multiple edges and self-edges (without labels)",
+ defaults=[rr.components.ShowLabels(False)],
+ ),
+ rrb.TextDocumentView(origin="readme", name="Instructions"),
+ ),
+ make_active=True,
+ make_default=True,
)
diff --git a/tests/python/release_checklist/check_heuristics_2d.py b/tests/python/release_checklist/check_heuristics_2d.py
index a951d05bec2f..96549cbf06ea 100644
--- a/tests/python/release_checklist/check_heuristics_2d.py
+++ b/tests/python/release_checklist/check_heuristics_2d.py
@@ -70,6 +70,8 @@ def run(args: Namespace) -> None:
log_readme()
log_images()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_heuristics_mixed_2d_and_3d.py b/tests/python/release_checklist/check_heuristics_mixed_2d_and_3d.py
index ba151b266d41..18ee34985583 100644
--- a/tests/python/release_checklist/check_heuristics_mixed_2d_and_3d.py
+++ b/tests/python/release_checklist/check_heuristics_mixed_2d_and_3d.py
@@ -56,6 +56,8 @@ def run(args: Namespace) -> None:
log_images()
log_3d_scene()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_heuristics_mixed_all_root.py b/tests/python/release_checklist/check_heuristics_mixed_all_root.py
index 5b90b33e876a..38c2e1cbf12b 100644
--- a/tests/python/release_checklist/check_heuristics_mixed_all_root.py
+++ b/tests/python/release_checklist/check_heuristics_mixed_all_root.py
@@ -29,6 +29,8 @@ def run(args: Namespace) -> None:
rr.log("points2d", rr.Points2D([[0, 0], [1, 1], [3, 2]], labels=["a", "b", "c"]))
rr.log("readme", rr.TextDocument(README, media_type=rr.MediaType.MARKDOWN), timeless=True)
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_hover_select_reset.py b/tests/python/release_checklist/check_hover_select_reset.py
index a83560ba7150..253949bb0c7d 100644
--- a/tests/python/release_checklist/check_hover_select_reset.py
+++ b/tests/python/release_checklist/check_hover_select_reset.py
@@ -108,6 +108,8 @@ def run(args: Namespace) -> None:
log_graph()
log_map()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_latest_at_partial_updates.py b/tests/python/release_checklist/check_latest_at_partial_updates.py
index 18d25bdbb82c..13bf39d61437 100644
--- a/tests/python/release_checklist/check_latest_at_partial_updates.py
+++ b/tests/python/release_checklist/check_latest_at_partial_updates.py
@@ -65,10 +65,6 @@ def blueprint() -> rrb.BlueprintLike:
),
]
),
- # NOTE: It looks nice but it's very annoying when going through several checklists.
- # rrb.BlueprintPanel(state="collapsed"),
- # rrb.TimePanel(state="collapsed"),
- # rrb.SelectionPanel(state="collapsed"),
)
@@ -119,7 +115,7 @@ def log_points() -> None:
def run(args: Namespace) -> None:
rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
- rr.send_blueprint(blueprint())
+ rr.send_blueprint(blueprint(), make_default=True, make_active=True)
log_readme()
log_points()
diff --git a/tests/python/release_checklist/check_modal_scrolling.py b/tests/python/release_checklist/check_modal_scrolling.py
index 8859f69acc17..bfb7e61df626 100644
--- a/tests/python/release_checklist/check_modal_scrolling.py
+++ b/tests/python/release_checklist/check_modal_scrolling.py
@@ -30,7 +30,11 @@ def run(args: Namespace) -> None:
args,
f"{os.path.basename(__file__)}",
recording_id=uuid4(),
- default_blueprint=rrb.Grid(rrb.Spatial2DView(origin="/"), rrb.TextDocumentView(origin="readme")),
+ )
+ rr.send_blueprint(
+ rrb.Grid(rrb.Spatial2DView(origin="/"), rrb.TextDocumentView(origin="readme")),
+ make_active=True,
+ make_default=True,
)
log_readme()
diff --git a/tests/python/release_checklist/check_mono_entity_views.py b/tests/python/release_checklist/check_mono_entity_views.py
index 90a45b40b821..b5c242635ee1 100644
--- a/tests/python/release_checklist/check_mono_entity_views.py
+++ b/tests/python/release_checklist/check_mono_entity_views.py
@@ -44,7 +44,8 @@ def blueprint() -> rrb.BlueprintLike:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_data()
diff --git a/tests/python/release_checklist/check_notebook.py b/tests/python/release_checklist/check_notebook.py
index 978acd0c2932..42612295067d 100644
--- a/tests/python/release_checklist/check_notebook.py
+++ b/tests/python/release_checklist/check_notebook.py
@@ -23,8 +23,8 @@ def run(args: Namespace) -> None:
args,
f"{os.path.basename(__file__)}",
recording_id=uuid4(),
- default_blueprint=rrb.Grid(rrb.TextDocumentView(origin="readme")),
)
+ rr.send_blueprint(rrb.Grid(rrb.TextDocumentView(origin="readme")), make_active=True, make_default=True)
log_readme()
diff --git a/tests/python/release_checklist/check_out_of_tree_data_results.py b/tests/python/release_checklist/check_out_of_tree_data_results.py
index 99f1edf440c7..e1d71272f26c 100644
--- a/tests/python/release_checklist/check_out_of_tree_data_results.py
+++ b/tests/python/release_checklist/check_out_of_tree_data_results.py
@@ -38,7 +38,8 @@ def log_data() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_data()
diff --git a/tests/python/release_checklist/check_overrides_2d.py b/tests/python/release_checklist/check_overrides_2d.py
index d8dc0c24de94..64ef757769e4 100644
--- a/tests/python/release_checklist/check_overrides_2d.py
+++ b/tests/python/release_checklist/check_overrides_2d.py
@@ -67,6 +67,13 @@ def log_boxes() -> None:
rr.Arrows2D(origins=[[-2.0, 0.0], [0.0, 0.0], [2.0, 0.0]], vectors=[[-2.0, 1.0], [0.0, 2.0], [2.0, 1.0]]),
)
+
+def run(args: Namespace) -> None:
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+
+ log_readme()
+ log_boxes()
+
visual_bounds = rrb.VisualBounds2D(x_range=[-5.5, 5.5], y_range=[-3.0, 3.0])
overrides = {
"arrows": [
@@ -87,68 +94,58 @@ def log_boxes() -> None:
rr.components.TextBatch(["TeenyYellow", "AverageCyan", "GigaPurple"]),
]
- rr.send_blueprint(
- rrb.Blueprint(
- rrb.Grid(
- rrb.TextDocumentView(origin="readme", name="Instructions"),
- rrb.Vertical(
- rrb.Spatial2DView(
- name="1) Overrides, logged values & defaults",
- visual_bounds=visual_bounds,
- overrides=overrides,
- defaults=defaults,
- ),
- rrb.Spatial2DView(
- name="2) Logged values & defaults",
- visual_bounds=visual_bounds,
- defaults=defaults,
- ),
- rrb.Spatial2DView(
- name="3) Logged values only",
- visual_bounds=visual_bounds,
- ),
+ blueprint = rrb.Blueprint(
+ rrb.Grid(
+ rrb.TextDocumentView(origin="readme", name="Instructions"),
+ rrb.Vertical(
+ rrb.Spatial2DView(
+ name="1) Overrides, logged values & defaults",
+ visual_bounds=visual_bounds,
+ overrides=overrides,
+ defaults=defaults,
+ ),
+ rrb.Spatial2DView(
+ name="2) Logged values & defaults",
+ visual_bounds=visual_bounds,
+ defaults=defaults,
),
- rrb.Vertical(
- rrb.Spatial2DView(
- name="What you should get after removing overrides from 1)",
- visual_bounds=visual_bounds,
- defaults=defaults,
- ),
- rrb.Spatial2DView(
- name="What you should get after removing defaults from 2)",
- visual_bounds=visual_bounds,
- ),
- rrb.Spatial2DView(
- name="What you should get after adding overrides & defaults to 3)",
- visual_bounds=visual_bounds,
- overrides={
- "arrows": [
- rrb.VisualizerOverrides([
- rrb.visualizers.Arrows2D,
- rrb.visualizers.Points2D,
- ]),
- rr.components.Color([255, 255, 255]),
- rr.components.Radius(0.1),
- rr.components.Text("Cerberus"),
- rr.components.Position2D([0.0, 0.0]),
- ]
- },
- ),
+ rrb.Spatial2DView(
+ name="3) Logged values only",
+ visual_bounds=visual_bounds,
),
- grid_columns=3,
- column_shares=[1, 1, 1],
),
- rrb.BlueprintPanel(state="collapsed"),
- rrb.TimePanel(state="collapsed"),
- )
+ rrb.Vertical(
+ rrb.Spatial2DView(
+ name="What you should get after removing overrides from 1)",
+ visual_bounds=visual_bounds,
+ defaults=defaults,
+ ),
+ rrb.Spatial2DView(
+ name="What you should get after removing defaults from 2)",
+ visual_bounds=visual_bounds,
+ ),
+ rrb.Spatial2DView(
+ name="What you should get after adding overrides & defaults to 3)",
+ visual_bounds=visual_bounds,
+ overrides={
+ "arrows": [
+ rrb.VisualizerOverrides([
+ rrb.visualizers.Arrows2D,
+ rrb.visualizers.Points2D,
+ ]),
+ rr.components.Color([255, 255, 255]),
+ rr.components.Radius(0.1),
+ rr.components.Text("Cerberus"),
+ rr.components.Position2D([0.0, 0.0]),
+ ]
+ },
+ ),
+ ),
+ grid_columns=3,
+ column_shares=[1, 1, 1],
+ ),
)
-
-
-def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
-
- log_readme()
- log_boxes()
+ rr.send_blueprint(blueprint, make_active=True, make_default=True)
if __name__ == "__main__":
diff --git a/tests/python/release_checklist/check_parallelism_caching_reentrancy.py b/tests/python/release_checklist/check_parallelism_caching_reentrancy.py
index 304d66c1644d..842a1dd2e6da 100644
--- a/tests/python/release_checklist/check_parallelism_caching_reentrancy.py
+++ b/tests/python/release_checklist/check_parallelism_caching_reentrancy.py
@@ -177,7 +177,8 @@ def log_spatial() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_text_logs()
diff --git a/tests/python/release_checklist/check_plot_overrides.py b/tests/python/release_checklist/check_plot_overrides.py
index cc3a482bb3ce..c46d88669f4f 100644
--- a/tests/python/release_checklist/check_plot_overrides.py
+++ b/tests/python/release_checklist/check_plot_overrides.py
@@ -62,6 +62,8 @@ def run(args: Namespace) -> None:
log_readme()
log_plots()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_range_partial_updates.py b/tests/python/release_checklist/check_range_partial_updates.py
index 39220eaf58d7..caeb50c805fc 100644
--- a/tests/python/release_checklist/check_range_partial_updates.py
+++ b/tests/python/release_checklist/check_range_partial_updates.py
@@ -98,10 +98,6 @@ def blueprint() -> rrb.BlueprintLike:
],
grid_columns=3,
),
- # NOTE: It looks nice but it's very annoying when going through several checklists.
- # rrb.BlueprintPanel(state="collapsed"),
- # rrb.TimePanel(state="collapsed"),
- # rrb.SelectionPanel(state="collapsed"),
)
@@ -134,7 +130,7 @@ def log_points() -> None:
def run(args: Namespace) -> None:
rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
- rr.send_blueprint(blueprint())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
log_readme()
log_points()
diff --git a/tests/python/release_checklist/check_rbl_import.py b/tests/python/release_checklist/check_rbl_import.py
index 942fb8d3e33d..c74e93305f5d 100644
--- a/tests/python/release_checklist/check_rbl_import.py
+++ b/tests/python/release_checklist/check_rbl_import.py
@@ -37,9 +37,6 @@ def log_external_blueprint() -> None:
rrb.TextDocumentView(origin="readme"),
column_shares=[3, 2],
),
- rrb.BlueprintPanel(state="collapsed"),
- rrb.SelectionPanel(state="collapsed"),
- rrb.TimePanel(state="collapsed"),
).save("some_unrelated_blueprint_app_id", tmp.name)
rr.log_file_from_path(tmp.name)
@@ -76,7 +73,9 @@ def run(args: Namespace) -> None:
args,
f"{os.path.basename(__file__)}",
recording_id=uuid4(),
- default_blueprint=rrb.Blueprint(
+ )
+ rr.send_blueprint(
+ rrb.Blueprint(
rrb.Horizontal(
rrb.TimeSeriesView(origin="/"),
rrb.TextDocumentView(origin="readme"),
@@ -86,6 +85,8 @@ def run(args: Namespace) -> None:
rrb.SelectionPanel(state="collapsed"),
rrb.TimePanel(state="collapsed"),
),
+ make_active=True,
+ make_default=True,
)
log_readme()
diff --git a/tests/python/release_checklist/check_scalar_clears.py b/tests/python/release_checklist/check_scalar_clears.py
index 81e922bf93c1..c3f025ccbaca 100644
--- a/tests/python/release_checklist/check_scalar_clears.py
+++ b/tests/python/release_checklist/check_scalar_clears.py
@@ -46,6 +46,8 @@ def run(args: Namespace) -> None:
log_readme()
log_plots()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_static_components_ui.py b/tests/python/release_checklist/check_static_components_ui.py
index 61bb20845ee1..6c53e9d66ca3 100644
--- a/tests/python/release_checklist/check_static_components_ui.py
+++ b/tests/python/release_checklist/check_static_components_ui.py
@@ -62,6 +62,8 @@ def run(args: Namespace) -> None:
log_readme()
log_some_views()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_static_override.py b/tests/python/release_checklist/check_static_override.py
index ddf28ccb33f3..7c2748c9733a 100644
--- a/tests/python/release_checklist/check_static_override.py
+++ b/tests/python/release_checklist/check_static_override.py
@@ -29,6 +29,8 @@ def run(args: Namespace) -> None:
# Log it again, to ensure that the newest one is visible
rr.log("points", rr.Points3D([[0, 0, 0], [1, 1, 1], [2, 2, 2]]), static=True)
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_transform3d_hierarchy.py b/tests/python/release_checklist/check_transform3d_hierarchy.py
index 5e0d0f81bf8d..ea54715593ee 100644
--- a/tests/python/release_checklist/check_transform3d_hierarchy.py
+++ b/tests/python/release_checklist/check_transform3d_hierarchy.py
@@ -72,9 +72,9 @@ def log_data() -> None:
rr.set_time_sequence("steps", 4)
path += "scale_back_mat3x3/"
# fmt: off
- rr.log(path, rr.Transform3D(mat3x3=[1.0, 0.0, 0.0,
- 0.0, 5.0, 0.0,
- 0.0, 0.0, 1.0]))
+ rr.log(path, rr.Transform3D(mat3x3=[1.0, 0.0, 0.0,
+ 0.0, 5.0, 0.0,
+ 0.0, 0.0, 1.0]))
# fmt: on
rr.set_time_sequence("steps", 5)
@@ -112,7 +112,8 @@ def log_data() -> None:
def run(args: Namespace) -> None:
- rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4(), default_blueprint=blueprint())
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_active=True, make_default=True)
# Extract the rerun_obj.zip file
with zipfile.ZipFile(f"{rerun_obj_path}.zip", "r") as zip_ref:
diff --git a/tests/python/release_checklist/check_version.py b/tests/python/release_checklist/check_version.py
index 78d34a59a5d2..35ede9dc7f44 100644
--- a/tests/python/release_checklist/check_version.py
+++ b/tests/python/release_checklist/check_version.py
@@ -38,6 +38,8 @@ def run(args: Namespace) -> None:
log_readme()
log_the_versions()
+ rr.send_blueprint(rr.blueprint.Blueprint(auto_layout=True, auto_views=True), make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
diff --git a/tests/python/release_checklist/check_video.py b/tests/python/release_checklist/check_video.py
index 5dd2f4aec54d..14720f3cc626 100644
--- a/tests/python/release_checklist/check_video.py
+++ b/tests/python/release_checklist/check_video.py
@@ -66,20 +66,19 @@ def run(args: Namespace) -> None:
static=True, # Static, so it shows up in the "video_time" timeline!
)
- rr.send_blueprint(
- rrb.Blueprint(
- rrb.Grid(
- rrb.TextDocumentView(origin="readme", name="Instructions"),
- rrb.Spatial3DView(origin="/", name="AV1 frustum", contents="av1"),
- rrb.Spatial2DView(origin="av1", name="AV1"),
- rrb.Spatial2DView(origin="h264", name="H.264"),
- rrb.Spatial2DView(origin="h265", name="H.265"),
- rrb.Spatial2DView(origin="vp9", name="VP9"),
- ),
- rrb.TimePanel(state="collapsed"),
- )
+ blueprint = rrb.Blueprint(
+ rrb.Grid(
+ rrb.TextDocumentView(origin="readme", name="Instructions"),
+ rrb.Spatial3DView(origin="/", name="AV1 frustum", contents="av1"),
+ rrb.Spatial2DView(origin="av1", name="AV1"),
+ rrb.Spatial2DView(origin="h264", name="H.264"),
+ rrb.Spatial2DView(origin="h265", name="H.265"),
+ rrb.Spatial2DView(origin="vp9", name="VP9"),
+ ),
)
+ rr.send_blueprint(blueprint, make_active=True, make_default=True)
+
if __name__ == "__main__":
import argparse
From 091e57a6c0085e2ccfcc8477cc1b322f1ffef60f Mon Sep 17 00:00:00 2001
From: Zeljko Mihaljcic <7150613+zehiko@users.noreply.github.com>
Date: Wed, 18 Dec 2024 07:57:54 +0100
Subject: [PATCH 15/30] Catalog view: fetch StoreInfo from the catalog and do
the catalog data enrichment on the viewer side (#8504)
### What
Rerun Data Platform now supports simple filtering by recording ids and
also stores (some of the) fields required to create StoreInfo, hence
we can fetch it from the catalog.
Also, instead of doing all the arrow data manipulation to make
DataframePart convertible to Rerun Chunk on the ReDap side, we now
do it on the viewer side.
---
crates/store/re_grpc_client/src/lib.rs | 177 ++++++++++++++++++++++---
1 file changed, 160 insertions(+), 17 deletions(-)
diff --git a/crates/store/re_grpc_client/src/lib.rs b/crates/store/re_grpc_client/src/lib.rs
index 5b6f553ee428..f324862dc3a8 100644
--- a/crates/store/re_grpc_client/src/lib.rs
+++ b/crates/store/re_grpc_client/src/lib.rs
@@ -5,6 +5,7 @@ mod address;
pub use address::{InvalidRedapAddress, RedapAddress};
use re_chunk::external::arrow2;
use re_log_types::external::re_types_core::ComponentDescriptor;
+use re_protos::remote_store::v0::CatalogFilter;
use re_types::blueprint::archetypes::{ContainerBlueprint, ViewportBlueprint};
use re_types::blueprint::archetypes::{ViewBlueprint, ViewContents};
use re_types::blueprint::components::{ContainerKind, RootContainer};
@@ -16,6 +17,7 @@ use url::Url;
// ----------------------------------------------------------------------------
use std::error::Error;
+use std::sync::Arc;
use arrow2::array::Utf8Array as Arrow2Utf8Array;
use arrow2::datatypes::Field as Arrow2Field;
@@ -175,6 +177,43 @@ async fn stream_recording_async(
StorageNodeClient::new(tonic_client).max_decoding_message_size(usize::MAX)
};
+ re_log::debug!("Fetching catalog data for {recording_id}β¦");
+
+ let resp = client
+ .query_catalog(QueryCatalogRequest {
+ column_projection: None, // fetch all columns
+ filter: Some(CatalogFilter {
+ recording_ids: vec![RecordingId {
+ id: recording_id.clone(),
+ }],
+ }),
+ })
+ .await
+ .map_err(TonicStatusError)?
+ .into_inner()
+ .filter_map(|resp| {
+ resp.and_then(|r| {
+ decode(r.encoder_version(), &r.payload)
+ .map_err(|err| tonic::Status::internal(err.to_string()))
+ })
+ .transpose()
+ })
+ .collect::, tonic::Status>>()
+ .await
+ .map_err(TonicStatusError)?;
+
+ if resp.len() != 1 || resp[0].num_rows() != 1 {
+ return Err(StreamError::ChunkError(re_chunk::ChunkError::Malformed {
+ reason: format!(
+ "expected exactly one recording with id {recording_id}, got {}",
+ resp.len()
+ ),
+ }));
+ }
+
+ let store_info = store_info_from_catalog_chunk(&resp[0], &recording_id)?;
+ let store_id = store_info.store_id.clone();
+
re_log::debug!("Fetching {recording_id}β¦");
let mut resp = client
@@ -196,19 +235,6 @@ async fn stream_recording_async(
drop(client);
- // TODO(zehiko) - we need a separate gRPC endpoint for fetching Store info REDAP #85
- let store_id = StoreId::from_string(StoreKind::Recording, recording_id.clone());
-
- let store_info = StoreInfo {
- application_id: ApplicationId::from("redap_recording"),
- store_id: store_id.clone(),
- cloned_from: None,
- is_official_example: false,
- started: Time::now(),
- store_source: StoreSource::Unknown,
- store_version: None,
- };
-
// We need a whole StoreInfo here.
if tx
.send(LogMsg::SetStoreInfo(SetStoreInfo {
@@ -242,6 +268,51 @@ async fn stream_recording_async(
Ok(())
}
+fn store_info_from_catalog_chunk(
+ tc: &TransportChunk,
+ recording_id: &str,
+) -> Result {
+ let store_id = StoreId::from_string(StoreKind::Recording, recording_id.to_owned());
+
+ let (_field, data) = tc
+ .components()
+ .find(|(f, _)| f.name == "application_id")
+ .ok_or(StreamError::ChunkError(re_chunk::ChunkError::Malformed {
+ reason: "no application_id field found".to_owned(),
+ }))?;
+ let app_id = data
+ .as_any()
+ .downcast_ref::>()
+ .ok_or(StreamError::ChunkError(re_chunk::ChunkError::Malformed {
+ reason: format!("application_id must be a utf8 array: {:?}", tc.schema),
+ }))?
+ .value(0);
+
+ let (_field, data) = tc
+ .components()
+ .find(|(f, _)| f.name == "start_time")
+ .ok_or(StreamError::ChunkError(re_chunk::ChunkError::Malformed {
+ reason: "no start_time field found".to_owned(),
+ }))?;
+ let start_time = data
+ .as_any()
+ .downcast_ref::()
+ .ok_or(StreamError::ChunkError(re_chunk::ChunkError::Malformed {
+ reason: format!("start_time must be an int64 array: {:?}", tc.schema),
+ }))?
+ .value(0);
+
+ Ok(StoreInfo {
+ application_id: ApplicationId::from(app_id),
+ store_id: store_id.clone(),
+ cloned_from: None,
+ is_official_example: false,
+ started: Time::from_ns_since_epoch(start_time),
+ store_source: StoreSource::Unknown,
+ store_version: None,
+ })
+}
+
async fn stream_catalog_async(
tx: re_smart_channel::Sender,
redap_endpoint: Url,
@@ -318,16 +389,88 @@ async fn stream_catalog_async(
re_log::info!("Starting to read...");
while let Some(result) = resp.next().await {
- let mut tc = result.map_err(TonicStatusError)?;
- // received TransportChunk doesn't have ChunkId, hence we need to add it before converting
- // to Chunk
+ let input = result.map_err(TonicStatusError)?;
+
+ // Catalog received from the ReDap server isn't suitable for direct conversion to a Rerun Chunk:
+ // - conversion expects "data" columns to be ListArrays, hence we need to convert any individual row column data to ListArray
+ // - conversion expects the input TransportChunk to have a ChunkId so we need to add that piece of metadata
+
+ let mut fields = Vec::new();
+ let mut arrays = Vec::new();
+ // add the (row id) control field
+ let (row_id_field, row_id_data) = input.controls().next().ok_or(
+ StreamError::ChunkError(re_chunk::ChunkError::Malformed {
+ reason: "no control field found".to_owned(),
+ }),
+ )?;
+
+ fields.push(
+ Arrow2Field::new(
+ RowId::name().to_string(), // need to rename to Rerun Chunk expected control field
+ row_id_field.data_type().clone(),
+ false, /* not nullable */
+ )
+ .with_metadata(TransportChunk::field_metadata_control_column()),
+ );
+ arrays.push(row_id_data.clone());
+
+ // next add any timeline field
+ for (field, data) in input.timelines() {
+ fields.push(field.clone());
+ arrays.push(data.clone());
+ }
+
+ // now add all the 'data' fields - we slice each column array into individual arrays and then convert the whole lot into a ListArray
+ for (field, data) in input.components() {
+ let data_field_inner =
+ Arrow2Field::new("item", field.data_type().clone(), true /* nullable */);
+
+ let data_field = Arrow2Field::new(
+ field.name.clone(),
+ arrow2::datatypes::DataType::List(Arc::new(data_field_inner.clone())),
+ false, /* not nullable */
+ )
+ .with_metadata(TransportChunk::field_metadata_data_column());
+
+ let mut sliced: Vec> = Vec::new();
+ for idx in 0..data.len() {
+ let mut array = data.clone();
+ array.slice(idx, 1);
+ sliced.push(array);
+ }
+
+ let data_arrays = sliced.iter().map(|e| Some(e.as_ref())).collect::>();
+ #[allow(clippy::unwrap_used)] // we know we've given the right field type
+ let data_field_array: arrow2::array::ListArray =
+ re_chunk::util::arrays_to_list_array(
+ data_field_inner.data_type().clone(),
+ &data_arrays,
+ )
+ .unwrap();
+
+ fields.push(data_field);
+ arrays.push(Box::new(data_field_array));
+ }
+
+ let mut schema = arrow2::datatypes::Schema::from(fields);
+ schema.metadata.insert(
+ TransportChunk::CHUNK_METADATA_KEY_ENTITY_PATH.to_owned(),
+ "catalog".to_owned(),
+ );
+
+ // modified and enriched TransportChunk
+ let mut tc = TransportChunk {
+ schema,
+ data: arrow2::chunk::Chunk::new(arrays),
+ };
+
tc.schema.metadata.insert(
TransportChunk::CHUNK_METADATA_KEY_ID.to_owned(),
ChunkId::new().to_string(),
);
let mut chunk = Chunk::from_transport(&tc)?;
- // enrich catalog data with RecordingUri that's based on the ReDap endpoint (that we know)
+ // finally, enrich catalog data with RecordingUri that's based on the ReDap endpoint (that we know)
// and the recording id (that we have in the catalog data)
let host = redap_endpoint
.host()
From 84da13220f7bbd880a579a37853ebb1ea8b81a2c Mon Sep 17 00:00:00 2001
From: Jeremy Leibs
Date: Wed, 18 Dec 2024 08:20:46 +0100
Subject: [PATCH 16/30] Update the remote APIs to take and send a Table (#8521)
This allows the update APIs to now support multi-recording updates, and
generally gives users more direct control over things like the column
metadata, etc.
---
.../proto/rerun/v0/remote_store.proto | 1 -
.../re_protos/src/v0/rerun.remote_store.v0.rs | 2 -
examples/python/remote/metadata.py | 17 +-
rerun_py/rerun_bindings/rerun_bindings.pyi | 22 +--
rerun_py/rerun_bindings/types.py | 5 +-
rerun_py/src/remote.rs | 158 ++++++------------
6 files changed, 83 insertions(+), 122 deletions(-)
diff --git a/crates/store/re_protos/proto/rerun/v0/remote_store.proto b/crates/store/re_protos/proto/rerun/v0/remote_store.proto
index 2955f45b8b3c..5d2f68ca3794 100644
--- a/crates/store/re_protos/proto/rerun/v0/remote_store.proto
+++ b/crates/store/re_protos/proto/rerun/v0/remote_store.proto
@@ -44,7 +44,6 @@ message RegisterRecordingRequest {
// ---------------- UpdateCatalog -----------------
message UpdateCatalogRequest {
- rerun.common.v0.RecordingId recording_id = 1;
DataframePart metadata = 2;
}
diff --git a/crates/store/re_protos/src/v0/rerun.remote_store.v0.rs b/crates/store/re_protos/src/v0/rerun.remote_store.v0.rs
index 1429146e776d..a755b57daac4 100644
--- a/crates/store/re_protos/src/v0/rerun.remote_store.v0.rs
+++ b/crates/store/re_protos/src/v0/rerun.remote_store.v0.rs
@@ -47,8 +47,6 @@ impl ::prost::Name for RegisterRecordingRequest {
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateCatalogRequest {
- #[prost(message, optional, tag = "1")]
- pub recording_id: ::core::option::Option,
#[prost(message, optional, tag = "2")]
pub metadata: ::core::option::Option,
}
diff --git a/examples/python/remote/metadata.py b/examples/python/remote/metadata.py
index e199499d8f2a..31371bfac2d3 100644
--- a/examples/python/remote/metadata.py
+++ b/examples/python/remote/metadata.py
@@ -14,23 +14,31 @@
subparsers = parser.add_subparsers(dest="subcommand")
print_cmd = subparsers.add_parser("print", help="Print everything")
+ register_cmd = subparsers.add_parser("register", help="Register a new recording")
update_cmd = subparsers.add_parser("update", help="Update metadata for a recording")
update_cmd.add_argument("id", help="ID of the recording to update")
update_cmd.add_argument("key", help="Key of the metadata to update")
update_cmd.add_argument("value", help="Value of the metadata to update")
+ register_cmd.add_argument("storage_url", help="Storage URL to register")
+
args = parser.parse_args()
# Register the new rrd
conn = rr.remote.connect("http://0.0.0.0:51234")
- catalog = pl.from_arrow(conn.query_catalog())
+ catalog = pl.from_arrow(conn.query_catalog().read_all())
if args.subcommand == "print":
print(catalog)
- if args.subcommand == "update":
+ elif args.subcommand == "register":
+ extra_metadata = pa.Table.from_pydict({"extra": [42]})
+ id = conn.register(args.storage_url, extra_metadata)
+ print(f"Registered new recording with ID: {id}")
+
+ elif args.subcommand == "update":
id = catalog.filter(catalog["id"].str.starts_with(args.id)).select(pl.first("id")).item()
if id is None:
@@ -38,4 +46,7 @@
exit(1)
print(f"Updating metadata for {id}")
- conn.update_catalog(id, {args.key: pa.array([args.value])})
+ new_metadata = pa.Table.from_pydict({"id": [id], args.key: [args.value]})
+ print(new_metadata)
+
+ conn.update_catalog(new_metadata)
diff --git a/rerun_py/rerun_bindings/rerun_bindings.pyi b/rerun_py/rerun_bindings/rerun_bindings.pyi
index 53fd6781b43f..bd046bf15069 100644
--- a/rerun_py/rerun_bindings/rerun_bindings.pyi
+++ b/rerun_py/rerun_bindings/rerun_bindings.pyi
@@ -3,7 +3,7 @@ from typing import Iterator, Optional, Sequence, Union
import pyarrow as pa
-from .types import AnyColumn, AnyComponentColumn, ComponentLike, IndexValuesLike, MetadataLike, ViewContentsLike
+from .types import AnyColumn, AnyComponentColumn, ComponentLike, IndexValuesLike, TableLike, ViewContentsLike
class IndexColumnDescriptor:
"""
@@ -581,7 +581,7 @@ class StorageNodeClient:
"""Get the metadata for all recordings in the storage node."""
...
- def register(self, storage_url: str, metadata: Optional[dict[str, MetadataLike]] = None) -> str:
+ def register(self, storage_url: str, metadata: Optional[TableLike] = None) -> str:
"""
Register a recording along with some metadata.
@@ -589,22 +589,24 @@ class StorageNodeClient:
----------
storage_url : str
The URL to the storage location.
- metadata : dict[str, MetadataLike]
- A dictionary where the keys are the metadata columns and the values are pyarrow arrays.
+ metadata : Optional[Table | RecordBatch]
+ A pyarrow Table or RecordBatch containing the metadata to update.
+ This Table must contain only a single row.
"""
...
- def update_catalog(self, id: str, metadata: dict[str, MetadataLike]) -> None:
+ def update_catalog(self, metadata: TableLike) -> None:
"""
- Update the metadata for the recording with the given id.
+ Update the catalog metadata for one or more recordings.
+
+ The updates are provided as a pyarrow Table or RecordBatch containing the metadata to update.
+ The Table must contain an 'id' column, which is used to specify the recording to update for each row.
Parameters
----------
- id : str
- The id of the recording to update.
- metadata : dict[str, MetadataLike]
- A dictionary where the keys are the metadata columns and the values are pyarrow arrays.
+ metadata : Table | RecordBatch
+ A pyarrow Table or RecordBatch containing the metadata to update.
"""
...
diff --git a/rerun_py/rerun_bindings/types.py b/rerun_py/rerun_bindings/types.py
index c5ddf94e7477..a38e70036d34 100644
--- a/rerun_py/rerun_bindings/types.py
+++ b/rerun_py/rerun_bindings/types.py
@@ -68,4 +68,7 @@
This can be any numpy-compatible array of integers, or a [`pa.Int64Array`][]
"""
-MetadataLike: TypeAlias = pa.Array
+TableLike: TypeAlias = Union[pa.Table, pa.RecordBatch, pa.RecordBatchReader]
+"""
+A type alias for TableLike pyarrow objects.
+"""
diff --git a/rerun_py/src/remote.rs b/rerun_py/src/remote.rs
index a74f3a1a0666..2619d3990088 100644
--- a/rerun_py/src/remote.rs
+++ b/rerun_py/src/remote.rs
@@ -1,11 +1,12 @@
#![allow(unsafe_op_in_unsafe_fn)]
use arrow::{
- array::{ArrayData, RecordBatch, RecordBatchIterator, RecordBatchReader},
+ array::{RecordBatch, RecordBatchIterator, RecordBatchReader},
datatypes::Schema,
+ ffi_stream::ArrowArrayStreamReader,
pyarrow::PyArrowType,
};
// False positive due to #[pyfunction] macro
-use pyo3::{exceptions::PyRuntimeError, prelude::*, types::PyDict, Bound, PyResult};
+use pyo3::{exceptions::PyRuntimeError, prelude::*, Bound, PyResult};
use re_chunk::{Chunk, TransportChunk};
use re_chunk_store::ChunkStore;
use re_dataframe::ChunkStoreHandle;
@@ -134,17 +135,14 @@ impl PyStorageNodeClient {
/// ----------
/// storage_url : str
/// The URL to the storage location.
- /// metadata : dict[str, MetadataLike]
- /// A dictionary where the keys are the metadata columns and the values are pyarrow arrays.
+ /// metadata : Optional[Table | RecordBatch]
+ /// A pyarrow Table or RecordBatch containing the metadata to update.
+ /// This Table must contain only a single row.
#[pyo3(signature = (
storage_url,
metadata = None
))]
- fn register(
- &mut self,
- storage_url: &str,
- metadata: Option<&Bound<'_, PyDict>>,
- ) -> PyResult {
+ fn register(&mut self, storage_url: &str, metadata: Option) -> PyResult {
self.runtime.block_on(async {
let storage_url = url::Url::parse(storage_url)
.map_err(|err| PyRuntimeError::new_err(err.to_string()))?;
@@ -152,51 +150,32 @@ impl PyStorageNodeClient {
let _obj = object_store::ObjectStoreScheme::parse(&storage_url)
.map_err(|err| PyRuntimeError::new_err(err.to_string()))?;
- let payload = metadata
+ let metadata = metadata
.map(|metadata| {
- let (schema, data): (
- Vec,
- Vec>,
- ) = metadata
- .iter()
- .map(|(key, value)| {
- let key = key.to_string();
- let value = value.extract::()?;
- let value_array = value.to_arrow2()?;
- let field = arrow2::datatypes::Field::new(
- key,
- value_array.data_type().clone(),
- true,
- );
- Ok((field, value_array))
- })
- .collect::>>()?
- .into_iter()
- .unzip();
-
- let schema = arrow2::datatypes::Schema::from(schema);
- let data = arrow2::chunk::Chunk::new(data);
-
- let metadata_tc = TransportChunk {
- schema: schema.clone(),
- data,
- };
+ let metadata = metadata.into_record_batch()?;
+
+ if metadata.num_rows() != 1 {
+ return Err(PyRuntimeError::new_err(
+ "Metadata must contain exactly one row",
+ ));
+ }
+
+ let metadata_tc = TransportChunk::from_arrow_record_batch(&metadata);
encode(EncoderVersion::V0, metadata_tc)
.map_err(|err| PyRuntimeError::new_err(err.to_string()))
})
.transpose()?
- // TODO(zehiko) this is going away soon
- .ok_or(PyRuntimeError::new_err("No metadata"))?;
+ .map(|payload| DataframePart {
+ encoder_version: EncoderVersion::V0 as i32,
+ payload,
+ });
let request = RegisterRecordingRequest {
// TODO(jleibs): Description should really just be in the metadata
description: Default::default(),
storage_url: storage_url.to_string(),
- metadata: Some(DataframePart {
- encoder_version: EncoderVersion::V0 as i32,
- payload,
- }),
+ metadata,
typ: RecordingType::Rrd.into(),
};
@@ -226,48 +205,33 @@ impl PyStorageNodeClient {
})
}
- /// Update the metadata for the recording with the given id.
+ /// Update the catalog metadata for one or more recordings.
+ ///
+ /// The updates are provided as a pyarrow Table or RecordBatch containing the metadata to update.
+ /// The Table must contain an 'id' column, which is used to specify the recording to update for each row.
///
/// Parameters
/// ----------
- /// id : str
- /// The id of the recording to update.
- /// metadata : dict[str, MetadataLike]
- /// A dictionary where the keys are the metadata columns and the values are pyarrow arrays.
+ /// metadata : Table | RecordBatch
+ /// A pyarrow Table or RecordBatch containing the metadata to update.
#[pyo3(signature = (
- id,
metadata
))]
- fn update_catalog(&mut self, id: &str, metadata: &Bound<'_, PyDict>) -> PyResult<()> {
+ #[allow(clippy::needless_pass_by_value)]
+ fn update_catalog(&mut self, metadata: MetadataLike) -> PyResult<()> {
self.runtime.block_on(async {
- let (schema, data): (
- Vec,
- Vec>,
- ) = metadata
- .iter()
- .map(|(key, value)| {
- let key = key.to_string();
- let value = value.extract::()?;
- let value_array = value.to_arrow2()?;
- let field =
- arrow2::datatypes::Field::new(key, value_array.data_type().clone(), true);
- Ok((field, value_array))
- })
- .collect::>>()?
- .into_iter()
- .unzip();
+ let metadata = metadata.into_record_batch()?;
- let schema = arrow2::datatypes::Schema::from(schema);
-
- let data = arrow2::chunk::Chunk::new(data);
+ // TODO(jleibs): This id name should probably come from `re_protos`
+ if metadata.schema().column_with_name("id").is_none() {
+ return Err(PyRuntimeError::new_err(
+ "Metadata must contain an 'id' column",
+ ));
+ }
- let metadata_tc = TransportChunk {
- schema: schema.clone(),
- data,
- };
+ let metadata_tc = TransportChunk::from_arrow_record_batch(&metadata);
let request = UpdateCatalogRequest {
- recording_id: Some(RecordingId { id: id.to_owned() }),
metadata: Some(DataframePart {
encoder_version: EncoderVersion::V0 as i32,
payload: encode(EncoderVersion::V0, metadata_tc)
@@ -363,39 +327,23 @@ impl PyStorageNodeClient {
/// A type alias for metadata.
#[derive(FromPyObject)]
enum MetadataLike {
- PyArrow(PyArrowType),
- // TODO(jleibs): Support converting other primitives
+ RecordBatch(PyArrowType),
+ Reader(PyArrowType),
}
impl MetadataLike {
- fn to_arrow2(&self) -> PyResult> {
- match self {
- Self::PyArrow(array) => {
- let array = arrow2::array::from_data(&array.0);
- if array.len() == 1 {
- Ok(array)
- } else {
- Err(PyRuntimeError::new_err(
- "Metadata must be a single array, not a list",
- ))
- }
- }
- }
- }
-
- #[allow(dead_code)]
- fn to_arrow(&self) -> PyResult> {
- match self {
- Self::PyArrow(array) => {
- let array = arrow::array::make_array(array.0.clone());
- if array.len() == 1 {
- Ok(array)
- } else {
- Err(PyRuntimeError::new_err(
- "Metadata must be a single array, not a list",
- ))
- }
- }
- }
+ fn into_record_batch(self) -> PyResult {
+ let (schema, batches) = match self {
+ Self::RecordBatch(record_batch) => (record_batch.0.schema(), vec![record_batch.0]),
+ Self::Reader(reader) => (
+ reader.0.schema(),
+ reader.0.collect::, _>>().map_err(|err| {
+ PyRuntimeError::new_err(format!("Failed to read RecordBatches: {err}"))
+ })?,
+ ),
+ };
+
+ arrow::compute::concat_batches(&schema, &batches)
+ .map_err(|err| PyRuntimeError::new_err(err.to_string()))
}
}
From e9b2bff3801b8b8bf2f01270d7f847fdf803506c Mon Sep 17 00:00:00 2001
From: Andreas Reich
Date: Wed, 18 Dec 2024 08:42:38 +0100
Subject: [PATCH 17/30] Hide graph edges from individual graph node ui (#8511)
### Related
* https://github.com/rerun-io/rerun/issues/7026
### What
Lots of considerations & (soft) implications in this hack, see comment.
The important outcome here is that node hover now looks like this:
![image](https://github.com/user-attachments/assets/5f4e693b-19cf-4ac5-b359-1354dd8377e9)
node selection:
![image](https://github.com/user-attachments/assets/be75a273-bcb6-4bd4-b90a-5a19c994eb0f)
and node entity selection (note that edges are still around:
![image](https://github.com/user-attachments/assets/e76c7cf9-3a1b-4687-bc61-10c6ace02103)
also you can still browse the edges:
![image](https://github.com/user-attachments/assets/90c5d116-e9fe-4e4f-8032-ce8687e80097)
---
crates/viewer/re_data_ui/src/instance_path.rs | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/crates/viewer/re_data_ui/src/instance_path.rs b/crates/viewer/re_data_ui/src/instance_path.rs
index c2bdecf82db7..7030face69d7 100644
--- a/crates/viewer/re_data_ui/src/instance_path.rs
+++ b/crates/viewer/re_data_ui/src/instance_path.rs
@@ -67,7 +67,7 @@ impl DataUi for InstancePath {
.filter(|c| c.is_indicator_component())
.count();
- let components = latest_at(db, query, entity_path, &components);
+ let mut components = latest_at(db, query, entity_path, &components);
if components.is_empty() {
ui_layout.label(
@@ -96,6 +96,20 @@ impl DataUi for InstancePath {
),
);
} else {
+ // TODO(#7026): Instances today are too poorly defined:
+ // For many archetypes it makes sense to slice through all their component arrays with the same index.
+ // However, there are cases when there are multiple dimensions of slicing that make sense.
+ // This is most obvious for meshes & graph nodes where there are different dimensions for vertices/edges/etc.
+ //
+ // For graph nodes this is particularly glaring since our indicices imply nodes today and
+ // unlike with meshes it's very easy to hover & select individual nodes.
+ // In order to work around the GraphEdges showing up associated with random nodes, we just hide them here.
+ // (this is obviously a hack and these relationships should be formalized such that they are accessible to the UI, see ticket link above)
+ if !self.is_all() {
+ components
+ .retain(|(component, _chunk)| component != &components::GraphEdge::name());
+ }
+
component_list_ui(
ctx,
ui,
From ed05c75a0ce9d06c1dd786aefc94c22a8630ac7a Mon Sep 17 00:00:00 2001
From: Antoine Beyeler <49431240+abey79@users.noreply.github.com>
Date: Wed, 18 Dec 2024 09:02:02 +0100
Subject: [PATCH 18/30] Fix multi-entity drag-and-drop only adding one entity
(#8519)
### Related
* Related to #8518
* Related to #8431
### What
Fix a bug in #8431 where multi-entity drag-and-drop would only add a
single entity due to a foot-gun in our entity path filter mutation API
(see #8518 for more). Also add a new checklist.
---
crates/top/rerun/src/commands/entrypoint.rs | 6 +-
crates/viewer/re_viewport/src/viewport_ui.rs | 22 ++++---
.../src/view_contents.rs | 34 ++++++++++-
.../check_multi_entity_drag_and_drop.py | 60 +++++++++++++++++++
4 files changed, 107 insertions(+), 15 deletions(-)
create mode 100644 tests/python/release_checklist/check_multi_entity_drag_and_drop.py
diff --git a/crates/top/rerun/src/commands/entrypoint.rs b/crates/top/rerun/src/commands/entrypoint.rs
index 5ef16f301e40..6ea1089cb469 100644
--- a/crates/top/rerun/src/commands/entrypoint.rs
+++ b/crates/top/rerun/src/commands/entrypoint.rs
@@ -621,7 +621,7 @@ where
}
fn run_impl(
- main_thread_token: crate::MainThreadToken,
+ _main_thread_token: crate::MainThreadToken,
_build_info: re_build_info::BuildInfo,
call_source: CallSource,
args: Args,
@@ -838,10 +838,10 @@ fn run_impl(
} else {
#[cfg(feature = "native_viewer")]
return re_viewer::run_native_app(
- main_thread_token,
+ _main_thread_token,
Box::new(move |cc| {
let mut app = re_viewer::App::new(
- main_thread_token,
+ _main_thread_token,
_build_info,
&call_source.app_env(),
startup_options,
diff --git a/crates/viewer/re_viewport/src/viewport_ui.rs b/crates/viewer/re_viewport/src/viewport_ui.rs
index 602c57a7f67b..ceba4abe229e 100644
--- a/crates/viewer/re_viewport/src/viewport_ui.rs
+++ b/crates/viewer/re_viewport/src/viewport_ui.rs
@@ -6,7 +6,7 @@ use ahash::HashMap;
use egui_tiles::{Behavior as _, EditAction};
use re_context_menu::{context_menu_ui_for_item, SelectionUpdateBehavior};
-use re_log_types::{EntityPath, EntityPathRule};
+use re_log_types::{EntityPath, EntityPathRule, RuleEffect};
use re_ui::{design_tokens, ContextExt as _, DesignTokens, Icon, UiExt as _};
use re_viewer_context::{
blueprint_id_to_tile_id, icon_for_container_kind, Contents, DragAndDropFeedback,
@@ -277,14 +277,18 @@ impl ViewportUi {
if ctx.egui_ctx.input(|i| i.pointer.any_released()) {
egui::DragAndDrop::clear_payload(ctx.egui_ctx);
- for entity in entities {
- if can_entity_be_added(entity) {
- view_blueprint.contents.raw_add_entity_inclusion(
- ctx,
- EntityPathRule::including_subtree(entity.clone()),
- );
- }
- }
+ view_blueprint
+ .contents
+ .mutate_entity_path_filter(ctx, |filter| {
+ for entity in entities {
+ if can_entity_be_added(entity) {
+ filter.add_rule(
+ RuleEffect::Include,
+ EntityPathRule::including_subtree(entity.clone()),
+ );
+ }
+ }
+ });
ctx.selection_state()
.set_selection(Item::View(view_blueprint.id));
diff --git a/crates/viewer/re_viewport_blueprint/src/view_contents.rs b/crates/viewer/re_viewport_blueprint/src/view_contents.rs
index ef4079f1f515..7988a7c9d65a 100644
--- a/crates/viewer/re_viewport_blueprint/src/view_contents.rs
+++ b/crates/viewer/re_viewport_blueprint/src/view_contents.rs
@@ -142,6 +142,9 @@ impl ViewContents {
);
}
+ /// Set the entity path filter. WARNING: a single mutation is allowed per frame, or data will be
+ /// lost.
+ //TODO(#8518): address this massive foot-gun.
pub fn set_entity_path_filter(
&self,
ctx: &ViewerContext<'_>,
@@ -184,40 +187,65 @@ impl ViewContents {
}
}
- /// Remove a subtree and any existing rules that it would match.
+ /// Perform arbitrary mutation on the entity path filter. WARNING: a single mutation is allowed
+ /// per frame, or data will be lost.
+ ///
+ /// This method exists because of the single mutation per frame limitation. It currently is the
+ /// only way to perform multiple mutations on the entity path filter in a single frame.
+ //TODO(#8518): address this massive foot-gun.
+ pub fn mutate_entity_path_filter(
+ &self,
+ ctx: &ViewerContext<'_>,
+ f: impl FnOnce(&mut EntityPathFilter),
+ ) {
+ let mut new_entity_path_filter = self.entity_path_filter.clone();
+ f(&mut new_entity_path_filter);
+ self.set_entity_path_filter(ctx, &new_entity_path_filter);
+ }
+
+ /// Remove a subtree and any existing rules that it would match. WARNING: a single mutation is
+ /// allowed per frame, or data will be lost.
///
/// Because most-specific matches win, if we only add a subtree exclusion
/// it can still be overridden by existing inclusions. This method ensures
/// that not only do we add a subtree exclusion, but clear out any existing
/// inclusions or (now redundant) exclusions that would match the subtree.
+ //TODO(#8518): address this massive foot-gun.
pub fn remove_subtree_and_matching_rules(&self, ctx: &ViewerContext<'_>, path: EntityPath) {
let mut new_entity_path_filter = self.entity_path_filter.clone();
new_entity_path_filter.remove_subtree_and_matching_rules(path);
self.set_entity_path_filter(ctx, &new_entity_path_filter);
}
- /// Directly add an exclusion rule to the [`EntityPathFilter`].
+ /// Directly add an exclusion rule to the [`EntityPathFilter`]. WARNING: a single mutation is
+ /// allowed per frame, or data will be lost.
///
/// This is a direct modification of the filter and will not do any simplification
/// related to overlapping or conflicting rules.
///
/// If you are trying to remove an entire subtree, prefer using [`Self::remove_subtree_and_matching_rules`].
+ //TODO(#8518): address this massive foot-gun.
pub fn raw_add_entity_exclusion(&self, ctx: &ViewerContext<'_>, rule: EntityPathRule) {
let mut new_entity_path_filter = self.entity_path_filter.clone();
new_entity_path_filter.add_rule(RuleEffect::Exclude, rule);
self.set_entity_path_filter(ctx, &new_entity_path_filter);
}
- /// Directly add an inclusion rule to the [`EntityPathFilter`].
+ /// Directly add an inclusion rule to the [`EntityPathFilter`]. WARNING: a single mutation is
+ /// allowed per frame, or data will be lost.
///
/// This is a direct modification of the filter and will not do any simplification
/// related to overlapping or conflicting rules.
+ //TODO(#8518): address this massive foot-gun.
pub fn raw_add_entity_inclusion(&self, ctx: &ViewerContext<'_>, rule: EntityPathRule) {
let mut new_entity_path_filter = self.entity_path_filter.clone();
new_entity_path_filter.add_rule(RuleEffect::Include, rule);
self.set_entity_path_filter(ctx, &new_entity_path_filter);
}
+ /// Remove rules for a given entity. WARNING: a single mutation is allowed per frame, or data
+ /// will be lost.
+ //TODO(#8518): address this massive foot-gun.
pub fn remove_filter_rule_for(&self, ctx: &ViewerContext<'_>, ent_path: &EntityPath) {
let mut new_entity_path_filter = self.entity_path_filter.clone();
new_entity_path_filter.remove_rule_for(ent_path);
diff --git a/tests/python/release_checklist/check_multi_entity_drag_and_drop.py b/tests/python/release_checklist/check_multi_entity_drag_and_drop.py
new file mode 100644
index 000000000000..e541458b3881
--- /dev/null
+++ b/tests/python/release_checklist/check_multi_entity_drag_and_drop.py
@@ -0,0 +1,60 @@
+from __future__ import annotations
+
+import os
+from argparse import Namespace
+from uuid import uuid4
+
+import numpy as np
+import rerun as rr
+import rerun.blueprint as rrb
+
+README = """\
+# Multi-entity drag-and-drop
+
+This test checks that dragging multiple entities to a view correctly adds all entities.
+
+1. Multi-select `cos_curve` and `line_curve` entities in the streams tree.
+2. Drag them to the PLOT view.
+3. _Expect_: both entities are visible in the plot view and each are listed in the view's entity path filter.
+"""
+
+
+def log_readme() -> None:
+ rr.log("readme", rr.TextDocument(README, media_type=rr.MediaType.MARKDOWN), static=True)
+
+
+def blueprint() -> rrb.BlueprintLike:
+ return rrb.Vertical(
+ rrb.TextDocumentView(origin="readme"),
+ rrb.TimeSeriesView(origin="/", contents=[], name="PLOT"),
+ )
+
+
+def log_some_scalar_entities() -> None:
+ times = np.arange(100)
+ curves = [
+ ("cos_curve", np.cos(times / 100 * 2 * np.pi)),
+ ("line_curve", times / 100 + 0.2),
+ ]
+
+ time_column = rr.TimeSequenceColumn("frame", times)
+
+ for path, curve in curves:
+ rr.send_columns(path, times=[time_column], components=[rr.components.ScalarBatch(curve)])
+
+
+def run(args: Namespace) -> None:
+ rr.script_setup(args, f"{os.path.basename(__file__)}", recording_id=uuid4())
+ rr.send_blueprint(blueprint(), make_default=True, make_active=True)
+
+ log_readme()
+ log_some_scalar_entities()
+
+
+if __name__ == "__main__":
+ import argparse
+
+ parser = argparse.ArgumentParser(description="Interactive release checklist")
+ rr.script_add_args(parser)
+ args = parser.parse_args()
+ run(args)
From c5ee5d35d178950aece1d7f65a42a42367e2f9f0 Mon Sep 17 00:00:00 2001
From: Antoine Beyeler <49431240+abey79@users.noreply.github.com>
Date: Wed, 18 Dec 2024 09:23:31 +0100
Subject: [PATCH 19/30] Fix cargo warning (#8523)
The warning:
```
warning: /Users/hhip/src/rerun/crates/utils/re_capabilities/Cargo.toml: `default-features` is ignored for egui, since `default-features` was not specified for `workspace.dependencies.egui`, this could become a hard error in the future
```
---
crates/utils/re_capabilities/Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crates/utils/re_capabilities/Cargo.toml b/crates/utils/re_capabilities/Cargo.toml
index d4c36f8b600e..7b9a410df627 100644
--- a/crates/utils/re_capabilities/Cargo.toml
+++ b/crates/utils/re_capabilities/Cargo.toml
@@ -31,5 +31,5 @@ egui = ["dep:egui"]
# External dependencies:
document-features.workspace = true
-egui = { workspace = true, default-features = false, optional = true }
+egui = { workspace = true, optional = true }
static_assertions.workspace = true
From 9d38189191ca028a2beffb1c247dfd3a2a64d6d8 Mon Sep 17 00:00:00 2001
From: Antoine Beyeler <49431240+abey79@users.noreply.github.com>
Date: Wed, 18 Dec 2024 11:40:35 +0100
Subject: [PATCH 20/30] Fix undo not working in some entity drag-and-drop
instances (#8526)
This is a band-aid patch to address an issue with entity path filter
which would result in the following behaviours:
- the entity path filter would be perma-writen to the blueprint store
when the view is selected (in some cases)
- in such cases, this would break undo on user change (aka with entity
drag-and-drop)
The core issue is deeper and might cause panics with rust 1.81+. The
TL;DR is that the current `EntityPathFilter` type is ambiguous as to
whether its content has substitutions (aka $origin) applied or not. In
particular `Eq` and `Ord` apply to unsubstituted, resp. substituted
content (which can lead to the above panic). This should be further
cleaned by having two structures, one unsubstituted and another
substituted.
---------
Co-authored-by: Clement Rey
---
crates/store/re_log_types/src/path/entity_path_filter.rs | 5 ++++-
crates/viewer/re_selection_panel/src/selection_panel.rs | 9 +++++++--
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/crates/store/re_log_types/src/path/entity_path_filter.rs b/crates/store/re_log_types/src/path/entity_path_filter.rs
index a59629c1e089..9f94525e9bcc 100644
--- a/crates/store/re_log_types/src/path/entity_path_filter.rs
+++ b/crates/store/re_log_types/src/path/entity_path_filter.rs
@@ -16,8 +16,11 @@ pub enum EntityPathFilterParseError {
}
/// A set of substitutions for entity paths.
+///
+/// Important: the same substitutions must be used in every place we parse entity path filters.
+// TODO(ab): the above requirement is a foot-gun we already fell in and should be addressed.
#[derive(Default)]
-pub struct EntityPathSubs(pub HashMap);
+pub struct EntityPathSubs(HashMap);
impl EntityPathSubs {
/// Create a new set of substitutions from a single origin.
diff --git a/crates/viewer/re_selection_panel/src/selection_panel.rs b/crates/viewer/re_selection_panel/src/selection_panel.rs
index 9d2cf9e3209c..4bec1216ff8d 100644
--- a/crates/viewer/re_selection_panel/src/selection_panel.rs
+++ b/crates/viewer/re_selection_panel/src/selection_panel.rs
@@ -7,7 +7,7 @@ use re_data_ui::{
DataUi,
};
use re_entity_db::{EntityPath, InstancePath};
-use re_log_types::{ComponentPath, EntityPathFilter};
+use re_log_types::{ComponentPath, EntityPathFilter, EntityPathSubs};
use re_types::blueprint::components::Interactive;
use re_ui::{
icons,
@@ -559,7 +559,12 @@ fn entity_path_filter_ui(
}
// Apply the edit.
- let new_filter = EntityPathFilter::parse_forgiving(&filter_string, &Default::default());
+ //
+ // NOTE: The comparison of `EntityPathFilter` is done on the _expanded_ data (i.e. with variables substituted),
+ // so we must make sure to expand the new filter too before we compare it to the existing one.
+ // See
+ let new_filter =
+ EntityPathFilter::parse_forgiving(&filter_string, &EntityPathSubs::new_with_origin(origin));
if &new_filter == filter {
None // no change
} else {
From fd1adf94980dd2fff0ae1a6904f60db89c1a539f Mon Sep 17 00:00:00 2001
From: Andreas Reich
Date: Wed, 18 Dec 2024 13:29:03 +0100
Subject: [PATCH 21/30] Use single log call in graph examples (#8527)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Makes the graph examples look a lil bit nicer and more compact.
Note that this is a very recent thing that we can do this in Rust π₯³
Also, embedds `graph_directed` in the examples (this has been done
directly on the release branch already)
* [x] full check passed in order to confirm the example output is still
the same (tested this locally but who knows)
---
.../rerun/archetypes/graph_edges.fbs | 2 +-
.../rerun/archetypes/graph_nodes.fbs | 2 +-
.../re_types/src/archetypes/graph_edges.rs | 30 +++++++++++++++++++
.../re_types/src/archetypes/graph_nodes.rs | 30 +++++++++++++++++++
.../all/archetypes/graph_directed.cpp | 7 +----
.../snippets/all/archetypes/graph_directed.py | 3 --
.../snippets/all/archetypes/graph_directed.rs | 14 ++++-----
.../all/archetypes/graph_undirected.cpp | 7 +----
.../all/archetypes/graph_undirected.py | 9 +++---
.../all/archetypes/graph_undirected.rs | 16 +++++-----
.../src/rerun/archetypes/graph_edges.hpp | 24 +++++++++++++++
.../src/rerun/archetypes/graph_nodes.hpp | 24 +++++++++++++++
.../rerun_sdk/rerun/archetypes/graph_edges.py | 27 +++++++++++++++++
.../rerun_sdk/rerun/archetypes/graph_nodes.py | 27 +++++++++++++++++
14 files changed, 185 insertions(+), 37 deletions(-)
diff --git a/crates/store/re_types/definitions/rerun/archetypes/graph_edges.fbs b/crates/store/re_types/definitions/rerun/archetypes/graph_edges.fbs
index a20ea2d39fa1..337787158f71 100644
--- a/crates/store/re_types/definitions/rerun/archetypes/graph_edges.fbs
+++ b/crates/store/re_types/definitions/rerun/archetypes/graph_edges.fbs
@@ -7,7 +7,7 @@ namespace rerun.archetypes;
/// By default, edges are undirected.
///
/// \example archetypes/graph_undirected !api title="Simple undirected graph" image="https://static.rerun.io/graph_undirected/15f46bec77452a8c6220558e4403b99cac188e2e/1200w.png"
-/// \example archetypes/graph_directed !api title="Simple directed graph" image="https://static.rerun.io/graph_directed/ca29a37b65e1e0b6482251dce401982a0bc568fa/1200w.png"
+/// \example archetypes/graph_directed title="Simple directed graph" image="https://static.rerun.io/graph_directed/ca29a37b65e1e0b6482251dce401982a0bc568fa/1200w.png"
table GraphEdges (
"attr.docs.category": "Graph",
"attr.docs.unreleased",
diff --git a/crates/store/re_types/definitions/rerun/archetypes/graph_nodes.fbs b/crates/store/re_types/definitions/rerun/archetypes/graph_nodes.fbs
index 7e7ddb535164..142a88dd2444 100644
--- a/crates/store/re_types/definitions/rerun/archetypes/graph_nodes.fbs
+++ b/crates/store/re_types/definitions/rerun/archetypes/graph_nodes.fbs
@@ -5,7 +5,7 @@ namespace rerun.archetypes;
/// A list of nodes in a graph with optional labels, colors, etc.
///
/// \example archetypes/graph_undirected !api title="Simple undirected graph" image="https://static.rerun.io/graph_undirected/15f46bec77452a8c6220558e4403b99cac188e2e/1200w.png"
-/// \example archetypes/graph_directed !api title="Simple directed graph" image="https://static.rerun.io/graph_directed/ca29a37b65e1e0b6482251dce401982a0bc568fa/1200w.png"
+/// \example archetypes/graph_directed title="Simple directed graph" image="https://static.rerun.io/graph_directed/ca29a37b65e1e0b6482251dce401982a0bc568fa/1200w.png"
table GraphNodes (
"attr.docs.category": "Graph",
"attr.docs.unreleased",
diff --git a/crates/store/re_types/src/archetypes/graph_edges.rs b/crates/store/re_types/src/archetypes/graph_edges.rs
index a4aee2905982..d30dfea19a76 100644
--- a/crates/store/re_types/src/archetypes/graph_edges.rs
+++ b/crates/store/re_types/src/archetypes/graph_edges.rs
@@ -23,6 +23,36 @@ use ::re_types_core::{DeserializationError, DeserializationResult};
/// By default, edges are undirected.
///
/// β οΈ **This type is experimental and may be removed in future versions**
+///
+/// ## Example
+///
+/// ### Simple directed graph
+/// ```ignore
+/// fn main() -> Result<(), Box> {
+/// let rec = rerun::RecordingStreamBuilder::new("rerun_example_graph_directed").spawn()?;
+///
+/// rec.log(
+/// "simple",
+/// &[
+/// &rerun::GraphNodes::new(["a", "b", "c"])
+/// .with_positions([(0.0, 100.0), (-100.0, 0.0), (100.0, 0.0)])
+/// .with_labels(["A", "B", "C"]) as &dyn rerun::AsComponents,
+/// &rerun::GraphEdges::new([("a", "b"), ("b", "c"), ("c", "a")]).with_directed_edges(),
+/// ],
+/// )?;
+///
+/// Ok(())
+/// }
+/// ```
+///
+///
+///
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GraphEdges {
/// A list of node tuples.
diff --git a/crates/store/re_types/src/archetypes/graph_nodes.rs b/crates/store/re_types/src/archetypes/graph_nodes.rs
index 7a2c73d84601..3f3e707e185f 100644
--- a/crates/store/re_types/src/archetypes/graph_nodes.rs
+++ b/crates/store/re_types/src/archetypes/graph_nodes.rs
@@ -21,6 +21,36 @@ use ::re_types_core::{DeserializationError, DeserializationResult};
/// **Archetype**: A list of nodes in a graph with optional labels, colors, etc.
///
/// β οΈ **This type is experimental and may be removed in future versions**
+///
+/// ## Example
+///
+/// ### Simple directed graph
+/// ```ignore
+/// fn main() -> Result<(), Box> {
+/// let rec = rerun::RecordingStreamBuilder::new("rerun_example_graph_directed").spawn()?;
+///
+/// rec.log(
+/// "simple",
+/// &[
+/// &rerun::GraphNodes::new(["a", "b", "c"])
+/// .with_positions([(0.0, 100.0), (-100.0, 0.0), (100.0, 0.0)])
+/// .with_labels(["A", "B", "C"]) as &dyn rerun::AsComponents,
+/// &rerun::GraphEdges::new([("a", "b"), ("b", "c"), ("c", "a")]).with_directed_edges(),
+/// ],
+/// )?;
+///
+/// Ok(())
+/// }
+/// ```
+///
+///
+///
#[derive(Clone, Debug, PartialEq)]
pub struct GraphNodes {
/// A list of node IDs.
diff --git a/docs/snippets/all/archetypes/graph_directed.cpp b/docs/snippets/all/archetypes/graph_directed.cpp
index 3f09463b0eac..97b902d7bb4d 100644
--- a/docs/snippets/all/archetypes/graph_directed.cpp
+++ b/docs/snippets/all/archetypes/graph_directed.cpp
@@ -10,12 +10,7 @@ int main() {
"simple",
rerun::GraphNodes({"a", "b", "c"})
.with_positions({{0.0, 100.0}, {-100.0, 0.0}, {100.0, 0.0}})
- .with_labels({"A", "B", "C"})
- );
-
- // Note: We log to the same entity here.
- rec.log(
- "simple",
+ .with_labels({"A", "B", "C"}),
rerun::GraphEdges({{"a", "b"}, {"b", "c"}, {"c", "a"}})
// Graphs are undirected by default.
.with_graph_type(rerun::components::GraphType::Directed)
diff --git a/docs/snippets/all/archetypes/graph_directed.py b/docs/snippets/all/archetypes/graph_directed.py
index 63a803138a3b..d4471994c178 100644
--- a/docs/snippets/all/archetypes/graph_directed.py
+++ b/docs/snippets/all/archetypes/graph_directed.py
@@ -9,8 +9,5 @@
rr.GraphNodes(
node_ids=["a", "b", "c"], positions=[(0.0, 100.0), (-100.0, 0.0), (100.0, 0.0)], labels=["A", "B", "C"]
),
-)
-rr.log(
- "simple",
rr.GraphEdges(edges=[("a", "b"), ("b", "c"), ("c", "a")], graph_type="directed"),
)
diff --git a/docs/snippets/all/archetypes/graph_directed.rs b/docs/snippets/all/archetypes/graph_directed.rs
index be05ad8bd407..8a411238fb45 100644
--- a/docs/snippets/all/archetypes/graph_directed.rs
+++ b/docs/snippets/all/archetypes/graph_directed.rs
@@ -5,14 +5,12 @@ fn main() -> Result<(), Box> {
rec.log(
"simple",
- &rerun::GraphNodes::new(["a", "b", "c"])
- .with_positions([(0.0, 100.0), (-100.0, 0.0), (100.0, 0.0)])
- .with_labels(["A", "B", "C"]),
- )?;
- // Note: We log to the same entity here.
- rec.log(
- "simple",
- &rerun::GraphEdges::new([("a", "b"), ("b", "c"), ("c", "a")]).with_directed_edges(),
+ &[
+ &rerun::GraphNodes::new(["a", "b", "c"])
+ .with_positions([(0.0, 100.0), (-100.0, 0.0), (100.0, 0.0)])
+ .with_labels(["A", "B", "C"]) as &dyn rerun::AsComponents,
+ &rerun::GraphEdges::new([("a", "b"), ("b", "c"), ("c", "a")]).with_directed_edges(),
+ ],
)?;
Ok(())
diff --git a/docs/snippets/all/archetypes/graph_undirected.cpp b/docs/snippets/all/archetypes/graph_undirected.cpp
index 2d7e82ddba24..e81fecf36655 100644
--- a/docs/snippets/all/archetypes/graph_undirected.cpp
+++ b/docs/snippets/all/archetypes/graph_undirected.cpp
@@ -10,12 +10,7 @@ int main() {
"simple",
rerun::GraphNodes({"a", "b", "c"})
.with_positions({{0.0, 100.0}, {-100.0, 0.0}, {100.0, 0.0}})
- .with_labels({"A", "B", "C"})
- );
-
- // Note: We log to the same entity here.
- rec.log(
- "simple",
+ .with_labels({"A", "B", "C"}),
rerun::GraphEdges({{"a", "b"}, {"b", "c"}, {"c", "a"}})
// Optional: graphs are undirected by default.
.with_graph_type(rerun::components::GraphType::Undirected)
diff --git a/docs/snippets/all/archetypes/graph_undirected.py b/docs/snippets/all/archetypes/graph_undirected.py
index 2397bfc31c5b..556a3782cfc0 100644
--- a/docs/snippets/all/archetypes/graph_undirected.py
+++ b/docs/snippets/all/archetypes/graph_undirected.py
@@ -9,8 +9,9 @@
rr.GraphNodes(
node_ids=["a", "b", "c"], positions=[(0.0, 100.0), (-100.0, 0.0), (100.0, 0.0)], labels=["A", "B", "C"]
),
-)
-rr.log(
- "simple",
- rr.GraphEdges(edges=[("a", "b"), ("b", "c"), ("c", "a")], graph_type="undirected"),
+ rr.GraphEdges(
+ edges=[("a", "b"), ("b", "c"), ("c", "a")],
+ # Optional: graphs are undirected by default.
+ graph_type="undirected",
+ ),
)
diff --git a/docs/snippets/all/archetypes/graph_undirected.rs b/docs/snippets/all/archetypes/graph_undirected.rs
index affd0ec3d0ee..c87219a931f2 100644
--- a/docs/snippets/all/archetypes/graph_undirected.rs
+++ b/docs/snippets/all/archetypes/graph_undirected.rs
@@ -5,14 +5,14 @@ fn main() -> Result<(), Box> {
rec.log(
"simple",
- &rerun::GraphNodes::new(["a", "b", "c"])
- .with_positions([(0.0, 100.0), (-100.0, 0.0), (100.0, 0.0)])
- .with_labels(["A", "B", "C"]),
- )?;
- // Note: We log to the same entity here.
- rec.log(
- "simple",
- &rerun::GraphEdges::new([("a", "b"), ("b", "c"), ("c", "a")]).with_undirected_edges(), // Optional: graphs are undirected by default.
+ &[
+ &rerun::GraphNodes::new(["a", "b", "c"])
+ .with_positions([(0.0, 100.0), (-100.0, 0.0), (100.0, 0.0)])
+ .with_labels(["A", "B", "C"]) as &dyn rerun::AsComponents,
+ &rerun::GraphEdges::new([("a", "b"), ("b", "c"), ("c", "a")])
+ // Optional: graphs are undirected by default.
+ .with_undirected_edges(),
+ ],
)?;
Ok(())
diff --git a/rerun_cpp/src/rerun/archetypes/graph_edges.hpp b/rerun_cpp/src/rerun/archetypes/graph_edges.hpp
index 4e60d8e23d82..a19940a3a351 100644
--- a/rerun_cpp/src/rerun/archetypes/graph_edges.hpp
+++ b/rerun_cpp/src/rerun/archetypes/graph_edges.hpp
@@ -21,6 +21,30 @@ namespace rerun::archetypes {
///
/// By default, edges are undirected.
///
+ /// ## Example
+ ///
+ /// ### Simple directed graph
+ /// ![image](https://static.rerun.io/graph_directed/ca29a37b65e1e0b6482251dce401982a0bc568fa/full.png)
+ ///
+ /// ```cpp
+ /// #include
+ ///
+ /// int main() {
+ /// const auto rec = rerun::RecordingStream("rerun_example_graph_directed");
+ /// rec.spawn().exit_on_failure();
+ ///
+ /// rec.log(
+ /// "simple",
+ /// rerun::GraphNodes({"a", "b", "c"})
+ /// .with_positions({{0.0, 100.0}, {-100.0, 0.0}, {100.0, 0.0}})
+ /// .with_labels({"A", "B", "C"}),
+ /// rerun::GraphEdges({{"a", "b"}, {"b", "c"}, {"c", "a"}})
+ /// // Graphs are undirected by default.
+ /// .with_graph_type(rerun::components::GraphType::Directed)
+ /// );
+ /// }
+ /// ```
+ ///
/// β **This is an experimental API! It is not fully supported, and is likely to change significantly in future versions.**
struct GraphEdges {
/// A list of node tuples.
diff --git a/rerun_cpp/src/rerun/archetypes/graph_nodes.hpp b/rerun_cpp/src/rerun/archetypes/graph_nodes.hpp
index 1323569a7137..3ee519b9e729 100644
--- a/rerun_cpp/src/rerun/archetypes/graph_nodes.hpp
+++ b/rerun_cpp/src/rerun/archetypes/graph_nodes.hpp
@@ -23,6 +23,30 @@
namespace rerun::archetypes {
/// **Archetype**: A list of nodes in a graph with optional labels, colors, etc.
///
+ /// ## Example
+ ///
+ /// ### Simple directed graph
+ /// ![image](https://static.rerun.io/graph_directed/ca29a37b65e1e0b6482251dce401982a0bc568fa/full.png)
+ ///
+ /// ```cpp
+ /// #include
+ ///
+ /// int main() {
+ /// const auto rec = rerun::RecordingStream("rerun_example_graph_directed");
+ /// rec.spawn().exit_on_failure();
+ ///
+ /// rec.log(
+ /// "simple",
+ /// rerun::GraphNodes({"a", "b", "c"})
+ /// .with_positions({{0.0, 100.0}, {-100.0, 0.0}, {100.0, 0.0}})
+ /// .with_labels({"A", "B", "C"}),
+ /// rerun::GraphEdges({{"a", "b"}, {"b", "c"}, {"c", "a"}})
+ /// // Graphs are undirected by default.
+ /// .with_graph_type(rerun::components::GraphType::Directed)
+ /// );
+ /// }
+ /// ```
+ ///
/// β **This is an experimental API! It is not fully supported, and is likely to change significantly in future versions.**
struct GraphNodes {
/// A list of node IDs.
diff --git a/rerun_py/rerun_sdk/rerun/archetypes/graph_edges.py b/rerun_py/rerun_sdk/rerun/archetypes/graph_edges.py
index 4fa4c6017d9b..a1568b980108 100644
--- a/rerun_py/rerun_sdk/rerun/archetypes/graph_edges.py
+++ b/rerun_py/rerun_sdk/rerun/archetypes/graph_edges.py
@@ -26,6 +26,33 @@ class GraphEdges(Archetype):
By default, edges are undirected.
β οΈ **This is an experimental API! It is not fully supported, and is likely to change significantly in future versions.**
+
+ Example
+ -------
+ ### Simple directed graph:
+ ```python
+ import rerun as rr
+
+ rr.init("rerun_example_graph_directed", spawn=True)
+
+ rr.log(
+ "simple",
+ rr.GraphNodes(
+ node_ids=["a", "b", "c"], positions=[(0.0, 100.0), (-100.0, 0.0), (100.0, 0.0)], labels=["A", "B", "C"]
+ ),
+ rr.GraphEdges(edges=[("a", "b"), ("b", "c"), ("c", "a")], graph_type="directed"),
+ )
+ ```
+
+
+
+
"""
def __init__(self: Any, edges: datatypes.Utf8PairArrayLike, *, graph_type: components.GraphTypeLike | None = None):
diff --git a/rerun_py/rerun_sdk/rerun/archetypes/graph_nodes.py b/rerun_py/rerun_sdk/rerun/archetypes/graph_nodes.py
index bed4372bbaad..13426e12ae29 100644
--- a/rerun_py/rerun_sdk/rerun/archetypes/graph_nodes.py
+++ b/rerun_py/rerun_sdk/rerun/archetypes/graph_nodes.py
@@ -24,6 +24,33 @@ class GraphNodes(Archetype):
**Archetype**: A list of nodes in a graph with optional labels, colors, etc.
β οΈ **This is an experimental API! It is not fully supported, and is likely to change significantly in future versions.**
+
+ Example
+ -------
+ ### Simple directed graph:
+ ```python
+ import rerun as rr
+
+ rr.init("rerun_example_graph_directed", spawn=True)
+
+ rr.log(
+ "simple",
+ rr.GraphNodes(
+ node_ids=["a", "b", "c"], positions=[(0.0, 100.0), (-100.0, 0.0), (100.0, 0.0)], labels=["A", "B", "C"]
+ ),
+ rr.GraphEdges(edges=[("a", "b"), ("b", "c"), ("c", "a")], graph_type="directed"),
+ )
+ ```
+
+
+
+
"""
def __init__(
From 5b62c37d940351fdf7845229fa084866bbb8f777 Mon Sep 17 00:00:00 2001
From: Jeremy Leibs
Date: Wed, 18 Dec 2024 13:41:51 +0100
Subject: [PATCH 22/30] Add docstring about need for
`include_indicator_columns=True` (#8528)
### Related
- https://github.com/rerun-io/rerun/issues/8522
### What
Explains how to avoid hitting an issue.
---
rerun_py/rerun_sdk/rerun/dataframe.py | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/rerun_py/rerun_sdk/rerun/dataframe.py b/rerun_py/rerun_sdk/rerun/dataframe.py
index b525bf1e9e81..777a962b6b72 100644
--- a/rerun_py/rerun_sdk/rerun/dataframe.py
+++ b/rerun_py/rerun_sdk/rerun/dataframe.py
@@ -77,7 +77,13 @@ def as_arrow_array(self) -> pa.Array:
def send_record_batch(batch: pa.RecordBatch, rec: Optional[RecordingStream] = None) -> None:
- """Coerce a single pyarrow `RecordBatch` to Rerun structure."""
+ """
+ Coerce a single pyarrow `RecordBatch` to Rerun structure.
+
+ If this `RecordBatch` came from a call to [`RecordingView.view`][rerun.dataframe.RecordingView.view], you
+ will want to make sure the `view` call includes `include_indicator_columns = True` or else the
+ viewer will not know about the archetypes in the data.
+ """
indexes = []
data: defaultdict[str, list[Any]] = defaultdict(list)
@@ -112,7 +118,14 @@ def send_record_batch(batch: pa.RecordBatch, rec: Optional[RecordingStream] = No
def send_dataframe(df: pa.RecordBatchReader | pa.Table, rec: Optional[RecordingStream] = None) -> None:
- """Coerce a pyarrow `RecordBatchReader` or `Table` to Rerun structure."""
+ """
+ Coerce a pyarrow `RecordBatchReader` or `Table` to Rerun structure.
+
+ If this `Table` came from a call to [`RecordingView.view`][rerun.dataframe.RecordingView.view], you
+ will want to make sure the `view` call includes `include_indicator_columns = True` or else the
+ viewer will not know about the archetypes in the data.
+
+ """
if isinstance(df, pa.Table):
df = df.to_reader()
From e9d047615a8ed07dbe4425bcfbfffc183aeabf6b Mon Sep 17 00:00:00 2001
From: Antoine Beyeler <49431240+abey79@users.noreply.github.com>
Date: Wed, 18 Dec 2024 14:59:36 +0100
Subject: [PATCH 23/30] Enable GH releases for RC (#8524)
This PR enables the creation of GH releases (as draft and marked as
pre-release) for RCs.
Motivations for doing so:
- test that part of the workflow, in particular that all binaries are
correctly produced
- test the binary using `cargo binstall`
- these releases a single-click deletable from GH (if we want to do so)
- GH releases marked as "pre-release" aren't displayed in the GH project
page
Pending questions: do we want that? what about alphas?
---
.github/workflows/release.yml | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index d046c9cfedc2..ec762a5278db 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -321,7 +321,7 @@ jobs:
github-release:
name: "GitHub Release"
- if: inputs.release-type == 'final'
+ if: inputs.release-type == 'rc' || inputs.release-type == 'final'
needs:
[
version,
@@ -347,9 +347,16 @@ jobs:
run: |
version="${{ needs.version.outputs.final }}"
commit="${{ needs.version.outputs.release-commit }}"
+
+ if [ ${{ inputs.release-type }} = "final" ]; then
+ pre_arg=""
+ else
+ pre_arg="--prerelease"
+ fi
+
git tag $version $commit
git push origin $version
- gh release create $version --verify-tag --draft --title $version
+ gh release create $version --verify-tag --draft --title $version $pre_arg
- name: Create comment
env:
From 879e531ae8b2026b71fb3255f6d324691552a863 Mon Sep 17 00:00:00 2001
From: Emil Ernerfeldt
Date: Wed, 18 Dec 2024 15:00:34 +0100
Subject: [PATCH 24/30] Tensor shape and dimension names as separate arrow
fields (#8376)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
### Related
* Closes https://github.com/rerun-io/rerun/issues/6830
### What
β οΈ Breaks tensors in .rrd files!
In `TensorData` we used to have `shape: [TensorDimension]` with `struct
TensorDimension { size: u64, name: Option }`.
Now `TensorData` has `shape: [u64], names: Option<[String]>` instead.
So basically a AoS -> SoA change
### TODO
* [x] Port Python
* [x] Port C++
* [x] Document in migration guide
* [x] Run `@rerun-bot full-check`
---------
Co-authored-by: Antoine Beyeler
---
crates/store/re_chunk/src/iter.rs | 2 +-
.../re_types/definitions/rerun/datatypes.fbs | 1 -
.../rerun/datatypes/tensor_data.fbs | 13 +-
.../rerun/datatypes/tensor_dimension.fbs | 15 -
.../src/archetypes/depth_image_ext.rs | 10 +-
.../re_types/src/archetypes/image_ext.rs | 16 +-
.../src/archetypes/segmentation_image_ext.rs | 10 +-
.../re_types/src/archetypes/tensor_ext.rs | 41 +--
.../re_types/src/datatypes/.gitattributes | 1 -
crates/store/re_types/src/datatypes/mod.rs | 3 -
.../re_types/src/datatypes/tensor_data.rs | 246 ++++++++++++++--
.../re_types/src/datatypes/tensor_data_ext.rs | 137 +++++----
.../src/datatypes/tensor_dimension.rs | 266 ------------------
.../src/datatypes/tensor_dimension_ext.rs | 60 ----
crates/store/re_types/src/image.rs | 20 +-
crates/store/re_types/tests/types/tensor.rs | 75 +----
.../store/re_types_core/src/arrow_buffer.rs | 10 +
crates/top/rerun/src/commands/rrd/compare.rs | 4 +
crates/top/rerun/src/lib.rs | 8 +-
crates/top/rerun/src/sdk.rs | 2 +-
crates/viewer/re_data_ui/src/tensor.rs | 39 +--
.../re_view_tensor/src/dimension_mapping.rs | 7 +-
crates/viewer/re_view_tensor/src/lib.rs | 35 ++-
.../src/tensor_dimension_mapper.rs | 5 +-
.../viewer/re_view_tensor/src/tensor_tests.rs | 2 +-
.../viewer/re_view_tensor/src/view_class.rs | 44 ++-
.../reference/migration/migration-0-21.md | 3 +
.../reference/types/components/tensor_data.md | 6 +-
docs/content/reference/types/datatypes.md | 1 -
.../reference/types/datatypes/.gitattributes | 1 -
.../reference/types/datatypes/tensor_data.md | 21 +-
.../types/datatypes/tensor_dimension.md | 36 ---
docs/snippets/README.md | 6 +-
rerun_cpp/src/rerun.hpp | 1 -
rerun_cpp/src/rerun/archetypes/tensor.hpp | 4 +-
rerun_cpp/src/rerun/archetypes/tensor_ext.cpp | 10 +-
.../src/rerun/components/tensor_data.hpp | 7 +-
.../src/rerun/components/tensor_data_ext.cpp | 4 +-
rerun_cpp/src/rerun/datatypes.hpp | 1 -
rerun_cpp/src/rerun/datatypes/.gitattributes | 2 -
rerun_cpp/src/rerun/datatypes/tensor_data.cpp | 47 ++--
rerun_cpp/src/rerun/datatypes/tensor_data.hpp | 24 +-
.../src/rerun/datatypes/tensor_data_ext.cpp | 6 +-
.../src/rerun/datatypes/tensor_dimension.cpp | 77 -----
.../src/rerun/datatypes/tensor_dimension.hpp | 66 -----
.../rerun/datatypes/tensor_dimension_ext.cpp | 21 --
rerun_py/README.md | 5 +
rerun_py/rerun_sdk/rerun/_validators.py | 9 +-
.../rerun/archetypes/bar_chart_ext.py | 2 +-
.../rerun_sdk/rerun/archetypes/tensor_ext.py | 8 +-
.../rerun_sdk/rerun/datatypes/.gitattributes | 1 -
.../rerun_sdk/rerun/datatypes/__init__.py | 5 -
.../rerun_sdk/rerun/datatypes/tensor_data.py | 37 +--
.../rerun/datatypes/tensor_data_ext.py | 87 +++---
.../rerun/datatypes/tensor_dimension.py | 71 -----
rerun_py/tests/unit/test_tensor.py | 41 +--
tests/cpp/roundtrips/tensor/main.cpp | 4 +-
.../check_all_components_ui.py | 2 +-
58 files changed, 637 insertions(+), 1051 deletions(-)
delete mode 100644 crates/store/re_types/definitions/rerun/datatypes/tensor_dimension.fbs
delete mode 100644 crates/store/re_types/src/datatypes/tensor_dimension.rs
delete mode 100644 crates/store/re_types/src/datatypes/tensor_dimension_ext.rs
delete mode 100644 docs/content/reference/types/datatypes/tensor_dimension.md
delete mode 100644 rerun_cpp/src/rerun/datatypes/tensor_dimension.cpp
delete mode 100644 rerun_cpp/src/rerun/datatypes/tensor_dimension.hpp
delete mode 100644 rerun_cpp/src/rerun/datatypes/tensor_dimension_ext.cpp
delete mode 100644 rerun_py/rerun_sdk/rerun/datatypes/tensor_dimension.py
diff --git a/crates/store/re_chunk/src/iter.rs b/crates/store/re_chunk/src/iter.rs
index 571c5995c48b..1534d9ac0a28 100644
--- a/crates/store/re_chunk/src/iter.rs
+++ b/crates/store/re_chunk/src/iter.rs
@@ -710,7 +710,7 @@ impl Chunk {
Err(err) => {
if cfg!(debug_assertions) {
panic!(
- "deserialization failed for {}, data discarded: {}",
+ "[DEBUG-ONLY] deserialization failed for {}, data discarded: {}",
C::name(),
re_error::format_ref(&err),
);
diff --git a/crates/store/re_types/definitions/rerun/datatypes.fbs b/crates/store/re_types/definitions/rerun/datatypes.fbs
index 5772f4c3b8d5..fa325413e155 100644
--- a/crates/store/re_types/definitions/rerun/datatypes.fbs
+++ b/crates/store/re_types/definitions/rerun/datatypes.fbs
@@ -27,7 +27,6 @@ include "./datatypes/rgba32.fbs";
include "./datatypes/rotation_axis_angle.fbs";
include "./datatypes/tensor_buffer.fbs";
include "./datatypes/tensor_data.fbs";
-include "./datatypes/tensor_dimension.fbs";
include "./datatypes/tensor_dimension_selection.fbs";
include "./datatypes/time_int.fbs";
include "./datatypes/uint16.fbs";
diff --git a/crates/store/re_types/definitions/rerun/datatypes/tensor_data.fbs b/crates/store/re_types/definitions/rerun/datatypes/tensor_data.fbs
index 1624be6e00f3..6301c33c7abb 100644
--- a/crates/store/re_types/definitions/rerun/datatypes/tensor_data.fbs
+++ b/crates/store/re_types/definitions/rerun/datatypes/tensor_data.fbs
@@ -19,8 +19,17 @@ table TensorData (
"attr.python.array_aliases": "npt.ArrayLike",
"attr.rust.derive": "PartialEq,"
) {
- /// The shape of the tensor, including optional names for each dimension.
- shape: [rerun.datatypes.TensorDimension] (order: 200);
+ /// The shape of the tensor, i.e. the length of each dimension.
+ shape: [uint64] (order: 200);
+
+ /// The names of the dimensions of the tensor (optional).
+ ///
+ /// If set, should be the same length as [datatypes.TensorData.shape].
+ /// If it has a different length your names may show up improperly,
+ /// and some constructors may produce a warning or even an error.
+ ///
+ /// Example: `["height", "width", "channel", "batch"]`.
+ names: [string] (order: 250, nullable);
/// The content/data.
buffer: rerun.datatypes.TensorBuffer (order: 300);
diff --git a/crates/store/re_types/definitions/rerun/datatypes/tensor_dimension.fbs b/crates/store/re_types/definitions/rerun/datatypes/tensor_dimension.fbs
deleted file mode 100644
index 7d755a8b81e5..000000000000
--- a/crates/store/re_types/definitions/rerun/datatypes/tensor_dimension.fbs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace rerun.datatypes;
-
-// ---
-
-/// A single dimension within a multi-dimensional tensor.
-// TODO(jleibs): Support for stride.
-table TensorDimension (
- "attr.rust.derive_only": "Clone, Default, Eq, PartialEq"
-) {
- /// The length of this dimension.
- size: ulong (order: 100);
-
- /// The name of this dimension, e.g. "width", "height", "channel", "batch', β¦.
- name: string (order: 200, nullable);
-}
diff --git a/crates/store/re_types/src/archetypes/depth_image_ext.rs b/crates/store/re_types/src/archetypes/depth_image_ext.rs
index b1c7044c0914..af72285a3edd 100644
--- a/crates/store/re_types/src/archetypes/depth_image_ext.rs
+++ b/crates/store/re_types/src/archetypes/depth_image_ext.rs
@@ -20,7 +20,7 @@ impl DepthImage {
let tensor_data: TensorData = data
.try_into()
.map_err(ImageConstructionError::TensorDataConversion)?;
- let shape = tensor_data.shape;
+ let TensorData { shape, buffer, .. } = tensor_data;
let non_empty_dim_inds = find_non_empty_dim_indices(&shape);
@@ -28,13 +28,11 @@ impl DepthImage {
return Err(ImageConstructionError::BadImageShape(shape));
}
- let (blob, datatype) = blob_and_datatype_from_tensor(tensor_data.buffer);
+ let (blob, datatype) = blob_and_datatype_from_tensor(buffer);
- let (height, width) = (&shape[non_empty_dim_inds[0]], &shape[non_empty_dim_inds[1]]);
- let height = height.size as u32;
- let width = width.size as u32;
+ let (height, width) = (shape[non_empty_dim_inds[0]], shape[non_empty_dim_inds[1]]);
- let image_format = ImageFormat::depth([width, height], datatype);
+ let image_format = ImageFormat::depth([width as u32, height as u32], datatype);
Ok(Self {
buffer: blob.into(),
diff --git a/crates/store/re_types/src/archetypes/image_ext.rs b/crates/store/re_types/src/archetypes/image_ext.rs
index 1beff5061887..0304cecb27fe 100644
--- a/crates/store/re_types/src/archetypes/image_ext.rs
+++ b/crates/store/re_types/src/archetypes/image_ext.rs
@@ -33,17 +33,17 @@ impl Image {
let tensor_data: TensorData = data
.try_into()
.map_err(ImageConstructionError::TensorDataConversion)?;
- let shape = tensor_data.shape;
+ let TensorData { shape, buffer, .. } = tensor_data;
let non_empty_dim_inds = find_non_empty_dim_indices(&shape);
let is_shape_correct = match color_model {
ColorModel::L => non_empty_dim_inds.len() == 2,
ColorModel::RGB | ColorModel::BGR => {
- non_empty_dim_inds.len() == 3 && shape[non_empty_dim_inds[2]].size == 3
+ non_empty_dim_inds.len() == 3 && shape[non_empty_dim_inds[2]] == 3
}
ColorModel::RGBA | ColorModel::BGRA => {
- non_empty_dim_inds.len() == 3 && shape[non_empty_dim_inds[2]].size == 4
+ non_empty_dim_inds.len() == 3 && shape[non_empty_dim_inds[2]] == 4
}
};
@@ -51,15 +51,13 @@ impl Image {
return Err(ImageConstructionError::BadImageShape(shape));
}
- let (blob, datatype) = blob_and_datatype_from_tensor(tensor_data.buffer);
+ let (blob, datatype) = blob_and_datatype_from_tensor(buffer);
- let (height, width) = (&shape[non_empty_dim_inds[0]], &shape[non_empty_dim_inds[1]]);
- let height = height.size as u32;
- let width = width.size as u32;
+ let (height, width) = (shape[non_empty_dim_inds[0]], shape[non_empty_dim_inds[1]]);
let image_format = ImageFormat {
- width,
- height,
+ width: width as _,
+ height: height as _,
pixel_format: None,
channel_datatype: Some(datatype),
color_model: Some(color_model),
diff --git a/crates/store/re_types/src/archetypes/segmentation_image_ext.rs b/crates/store/re_types/src/archetypes/segmentation_image_ext.rs
index 4c2f71375b39..a90856eb24d3 100644
--- a/crates/store/re_types/src/archetypes/segmentation_image_ext.rs
+++ b/crates/store/re_types/src/archetypes/segmentation_image_ext.rs
@@ -19,7 +19,7 @@ impl SegmentationImage {
let tensor_data: TensorData = data
.try_into()
.map_err(ImageConstructionError::TensorDataConversion)?;
- let shape = tensor_data.shape;
+ let TensorData { shape, buffer, .. } = tensor_data;
let non_empty_dim_inds = find_non_empty_dim_indices(&shape);
@@ -27,13 +27,11 @@ impl SegmentationImage {
return Err(ImageConstructionError::BadImageShape(shape));
}
- let (blob, datatype) = blob_and_datatype_from_tensor(tensor_data.buffer);
+ let (blob, datatype) = blob_and_datatype_from_tensor(buffer);
- let (height, width) = (&shape[non_empty_dim_inds[0]], &shape[non_empty_dim_inds[1]]);
- let height = height.size as u32;
- let width = width.size as u32;
+ let (height, width) = (shape[non_empty_dim_inds[0]], shape[non_empty_dim_inds[1]]);
- let image_format = ImageFormat::segmentation([width, height], datatype);
+ let image_format = ImageFormat::segmentation([width as _, height as _], datatype);
Ok(Self {
buffer: blob.into(),
diff --git a/crates/store/re_types/src/archetypes/tensor_ext.rs b/crates/store/re_types/src/archetypes/tensor_ext.rs
index c7063b0b6264..2bfa7c1f08ef 100644
--- a/crates/store/re_types/src/archetypes/tensor_ext.rs
+++ b/crates/store/re_types/src/archetypes/tensor_ext.rs
@@ -1,4 +1,4 @@
-use crate::datatypes::{TensorData, TensorDimension};
+use crate::datatypes::TensorData;
use re_types_core::ArrowString;
@@ -24,37 +24,16 @@ impl Tensor {
/// Update the `names` of the contained [`TensorData`] dimensions.
///
- /// Any existing Dimension names will be overwritten.
+ /// Any existing names will be overwritten.
///
- /// If too many, or too few names are provided, this function will warn and only
- /// update the subset of names that it can.
- pub fn with_dim_names(self, names: impl IntoIterator- >) -> Self {
- let names: Vec<_> = names.into_iter().map(|x| Some(x.into())).collect();
- if names.len() != self.data.0.shape.len() {
- re_log::warn_once!(
- "Wrong number of names provided for tensor dimension. {} provided but {} expected.",
- names.len(),
- self.data.0.shape.len(),
- );
- }
- Self {
- data: TensorData {
- shape: self
- .data
- .0
- .shape
- .into_iter()
- .zip(names.into_iter().chain(std::iter::repeat(None)))
- .map(|(dim, name)| TensorDimension {
- size: dim.size,
- name: name.or(dim.name),
- })
- .collect(),
- buffer: self.data.0.buffer,
- }
- .into(),
- value_range: None,
- }
+ /// If the wrong number of names are given, a warning will be logged,
+ /// and the names might not show up correctly.
+ pub fn with_dim_names(
+ mut self,
+ names: impl IntoIterator
- >,
+ ) -> Self {
+ self.data.0 = self.data.0.with_dim_names(names);
+ self
}
}
diff --git a/crates/store/re_types/src/datatypes/.gitattributes b/crates/store/re_types/src/datatypes/.gitattributes
index 289cbd45793c..5995b6d6c716 100644
--- a/crates/store/re_types/src/datatypes/.gitattributes
+++ b/crates/store/re_types/src/datatypes/.gitattributes
@@ -25,7 +25,6 @@ rgba32.rs linguist-generated=true
rotation_axis_angle.rs linguist-generated=true
tensor_buffer.rs linguist-generated=true
tensor_data.rs linguist-generated=true
-tensor_dimension.rs linguist-generated=true
tensor_dimension_index_selection.rs linguist-generated=true
tensor_dimension_selection.rs linguist-generated=true
utf8pair.rs linguist-generated=true
diff --git a/crates/store/re_types/src/datatypes/mod.rs b/crates/store/re_types/src/datatypes/mod.rs
index d1edf377eb08..f18d728fd794 100644
--- a/crates/store/re_types/src/datatypes/mod.rs
+++ b/crates/store/re_types/src/datatypes/mod.rs
@@ -46,8 +46,6 @@ mod tensor_buffer;
mod tensor_buffer_ext;
mod tensor_data;
mod tensor_data_ext;
-mod tensor_dimension;
-mod tensor_dimension_ext;
mod tensor_dimension_index_selection;
mod tensor_dimension_selection;
mod tensor_dimension_selection_ext;
@@ -95,7 +93,6 @@ pub use self::rgba32::Rgba32;
pub use self::rotation_axis_angle::RotationAxisAngle;
pub use self::tensor_buffer::TensorBuffer;
pub use self::tensor_data::TensorData;
-pub use self::tensor_dimension::TensorDimension;
pub use self::tensor_dimension_index_selection::TensorDimensionIndexSelection;
pub use self::tensor_dimension_selection::TensorDimensionSelection;
pub use self::utf8pair::Utf8Pair;
diff --git a/crates/store/re_types/src/datatypes/tensor_data.rs b/crates/store/re_types/src/datatypes/tensor_data.rs
index 0d19cb6190a6..4d75cc0c12e3 100644
--- a/crates/store/re_types/src/datatypes/tensor_data.rs
+++ b/crates/store/re_types/src/datatypes/tensor_data.rs
@@ -28,8 +28,17 @@ use ::re_types_core::{DeserializationError, DeserializationResult};
/// which stores a contiguous array of typed values.
#[derive(Clone, Debug, PartialEq)]
pub struct TensorData {
- /// The shape of the tensor, including optional names for each dimension.
- pub shape: Vec,
+ /// The shape of the tensor, i.e. the length of each dimension.
+ pub shape: ::re_types_core::ArrowBuffer,
+
+ /// The names of the dimensions of the tensor (optional).
+ ///
+ /// If set, should be the same length as [`datatypes::TensorData::shape`][crate::datatypes::TensorData::shape].
+ /// If it has a different length your names may show up improperly,
+ /// and some constructors may produce a warning or even an error.
+ ///
+ /// Example: `["height", "width", "channel", "batch"]`.
+ pub names: Option>,
/// The content/data.
pub buffer: crate::datatypes::TensorBuffer,
@@ -47,11 +56,20 @@ impl ::re_types_core::Loggable for TensorData {
"shape",
DataType::List(std::sync::Arc::new(Field::new(
"item",
- ::arrow_datatype(),
+ DataType::UInt64,
false,
))),
false,
),
+ Field::new(
+ "names",
+ DataType::List(std::sync::Arc::new(Field::new(
+ "item",
+ DataType::Utf8,
+ false,
+ ))),
+ true,
+ ),
Field::new(
"buffer",
::arrow_datatype(),
@@ -76,11 +94,20 @@ impl ::re_types_core::Loggable for TensorData {
"shape",
DataType::List(std::sync::Arc::new(Field::new(
"item",
- ::arrow_datatype(),
+ DataType::UInt64,
false,
))),
false,
),
+ Field::new(
+ "names",
+ DataType::List(std::sync::Arc::new(Field::new(
+ "item",
+ DataType::Utf8,
+ false,
+ ))),
+ true,
+ ),
Field::new(
"buffer",
::arrow_datatype(),
@@ -113,29 +140,73 @@ impl ::re_types_core::Loggable for TensorData {
let any_nones = somes.iter().any(|some| !*some);
any_nones.then(|| somes.into())
};
+ {
+ let offsets =
+ arrow::buffer::OffsetBuffer::::from_lengths(shape.iter().map(
+ |opt| opt.as_ref().map_or(0, |datum| datum.num_instances()),
+ ));
+ let shape_inner_data: ScalarBuffer<_> = shape
+ .iter()
+ .flatten()
+ .map(|b| b.as_slice())
+ .collect::>()
+ .concat()
+ .into();
+ let shape_inner_validity: Option = None;
+ as_array_ref(ListArray::try_new(
+ std::sync::Arc::new(Field::new("item", DataType::UInt64, false)),
+ offsets,
+ as_array_ref(PrimitiveArray::::new(
+ shape_inner_data,
+ shape_inner_validity,
+ )),
+ shape_validity,
+ )?)
+ }
+ },
+ {
+ let (somes, names): (Vec<_>, Vec<_>) = data
+ .iter()
+ .map(|datum| {
+ let datum =
+ datum.as_ref().map(|datum| datum.names.clone()).flatten();
+ (datum.is_some(), datum)
+ })
+ .unzip();
+ let names_validity: Option = {
+ let any_nones = somes.iter().any(|some| !*some);
+ any_nones.then(|| somes.into())
+ };
{
let offsets = arrow::buffer::OffsetBuffer::::from_lengths(
- shape
+ names
.iter()
.map(|opt| opt.as_ref().map_or(0, |datum| datum.len())),
);
- let shape_inner_data: Vec<_> =
- shape.into_iter().flatten().flatten().collect();
- let shape_inner_validity: Option = None;
+ let names_inner_data: Vec<_> =
+ names.into_iter().flatten().flatten().collect();
+ let names_inner_validity: Option = None;
as_array_ref(ListArray::try_new(
- std::sync::Arc::new(Field::new(
- "item",
- ::arrow_datatype(),
- false,
- )),
+ std::sync::Arc::new(Field::new("item", DataType::Utf8, false)),
offsets,
{
- _ = shape_inner_validity;
- crate::datatypes::TensorDimension::to_arrow_opt(
- shape_inner_data.into_iter().map(Some),
- )?
+ let offsets = arrow::buffer::OffsetBuffer::::from_lengths(
+ names_inner_data.iter().map(|datum| datum.len()),
+ );
+ let inner_data: arrow::buffer::Buffer = names_inner_data
+ .into_iter()
+ .flat_map(|s| s.into_arrow2_buffer())
+ .collect();
+ #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+ as_array_ref(unsafe {
+ StringArray::new_unchecked(
+ offsets,
+ inner_data,
+ names_inner_validity,
+ )
+ })
},
- shape_validity,
+ names_validity,
)?)
}
},
@@ -208,7 +279,7 @@ impl ::re_types_core::Loggable for TensorData {
.ok_or_else(|| {
let expected = DataType::List(std::sync::Arc::new(Field::new(
"item",
- ::arrow_datatype(),
+ DataType::UInt64,
false,
)));
let actual = arrow_data.data_type().clone();
@@ -220,10 +291,133 @@ impl ::re_types_core::Loggable for TensorData {
} else {
let arrow_data_inner = {
let arrow_data_inner = &**arrow_data.values();
- crate::datatypes::TensorDimension::from_arrow2_opt(arrow_data_inner)
+ arrow_data_inner
+ .as_any()
+ .downcast_ref::()
+ .ok_or_else(|| {
+ let expected = DataType::UInt64;
+ let actual = arrow_data_inner.data_type().clone();
+ DeserializationError::datatype_mismatch(expected, actual)
+ })
.with_context("rerun.datatypes.TensorData#shape")?
+ .values()
+ };
+ let offsets = arrow_data.offsets();
+ arrow2::bitmap::utils::ZipValidity::new_with_validity(
+ offsets.windows(2),
+ arrow_data.validity(),
+ )
+ .map(|elem| {
+ elem.map(|window| {
+ let start = window[0] as usize;
+ let end = window[1] as usize;
+ if arrow_data_inner.len() < end {
+ return Err(DeserializationError::offset_slice_oob(
+ (start, end),
+ arrow_data_inner.len(),
+ ));
+ }
+
+ #[allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
+ let data = unsafe {
+ arrow_data_inner
+ .clone()
+ .sliced_unchecked(start, end - start)
+ };
+ let data = ::re_types_core::ArrowBuffer::from(data);
+ Ok(data)
+ })
+ .transpose()
+ })
+ .collect::>>>()?
+ }
+ .into_iter()
+ }
+ };
+ let names = {
+ if !arrays_by_name.contains_key("names") {
+ return Err(DeserializationError::missing_struct_field(
+ Self::arrow_datatype(),
+ "names",
+ ))
+ .with_context("rerun.datatypes.TensorData");
+ }
+ let arrow_data = &**arrays_by_name["names"];
+ {
+ let arrow_data = arrow_data
+ .as_any()
+ .downcast_ref::>()
+ .ok_or_else(|| {
+ let expected = DataType::List(std::sync::Arc::new(Field::new(
+ "item",
+ DataType::Utf8,
+ false,
+ )));
+ let actual = arrow_data.data_type().clone();
+ DeserializationError::datatype_mismatch(expected, actual)
+ })
+ .with_context("rerun.datatypes.TensorData#names")?;
+ if arrow_data.is_empty() {
+ Vec::new()
+ } else {
+ let arrow_data_inner = {
+ let arrow_data_inner = &**arrow_data.values();
+ {
+ let arrow_data_inner = arrow_data_inner
+ .as_any()
+ .downcast_ref::>()
+ .ok_or_else(|| {
+ let expected = DataType::Utf8;
+ let actual = arrow_data_inner.data_type().clone();
+ DeserializationError::datatype_mismatch(
+ expected, actual,
+ )
+ })
+ .with_context("rerun.datatypes.TensorData#names")?;
+ let arrow_data_inner_buf = arrow_data_inner.values();
+ let offsets = arrow_data_inner.offsets();
+ arrow2::bitmap::utils::ZipValidity::new_with_validity(
+ offsets.windows(2),
+ arrow_data_inner.validity(),
+ )
+ .map(|elem| {
+ elem.map(|window| {
+ let start = window[0] as usize;
+ let end = window[1] as usize;
+ let len = end - start;
+ if arrow_data_inner_buf.len() < end {
+ return Err(
+ DeserializationError::offset_slice_oob(
+ (start, end),
+ arrow_data_inner_buf.len(),
+ ),
+ );
+ }
+
+ #[allow(
+ unsafe_code,
+ clippy::undocumented_unsafe_blocks
+ )]
+ let data = unsafe {
+ arrow_data_inner_buf
+ .clone()
+ .sliced_unchecked(start, len)
+ };
+ Ok(data)
+ })
+ .transpose()
+ })
+ .map(|res_or_opt| {
+ res_or_opt.map(|res_or_opt| {
+ res_or_opt
+ .map(|v| ::re_types_core::ArrowString::from(v))
+ })
+ })
+ .collect::>>>()
+ .with_context("rerun.datatypes.TensorData#names")?
.into_iter()
- .collect::>()
+ }
+ .collect::>()
};
let offsets = arrow_data.offsets();
arrow2::bitmap::utils::ZipValidity::new_with_validity(
@@ -272,15 +466,16 @@ impl ::re_types_core::Loggable for TensorData {
.into_iter()
};
arrow2::bitmap::utils::ZipValidity::new_with_validity(
- ::itertools::izip!(shape, buffer),
+ ::itertools::izip!(shape, names, buffer),
arrow_data.validity(),
)
.map(|opt| {
- opt.map(|(shape, buffer)| {
+ opt.map(|(shape, names, buffer)| {
Ok(Self {
shape: shape
.ok_or_else(DeserializationError::missing_data)
.with_context("rerun.datatypes.TensorData#shape")?,
+ names,
buffer: buffer
.ok_or_else(DeserializationError::missing_data)
.with_context("rerun.datatypes.TensorData#buffer")?,
@@ -298,12 +493,13 @@ impl ::re_types_core::Loggable for TensorData {
impl ::re_types_core::SizeBytes for TensorData {
#[inline]
fn heap_size_bytes(&self) -> u64 {
- self.shape.heap_size_bytes() + self.buffer.heap_size_bytes()
+ self.shape.heap_size_bytes() + self.names.heap_size_bytes() + self.buffer.heap_size_bytes()
}
#[inline]
fn is_pod() -> bool {
- >::is_pod()
+ <::re_types_core::ArrowBuffer>::is_pod()
+ &&