diff --git a/Cargo.lock b/Cargo.lock index ab5baf245f151..39a4683d3a468 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4904,10 +4904,13 @@ dependencies = [ "re_entity_db", "re_log_types", "re_renderer", + "re_space_view", "re_tracing", + "re_types", "re_types_core", "re_ui", "re_viewer_context", + "re_viewport_blueprint", ] [[package]] diff --git a/crates/store/re_types/definitions/rerun/blueprint.fbs b/crates/store/re_types/definitions/rerun/blueprint.fbs index d6ddcb840da7a..63055f1639f1f 100644 --- a/crates/store/re_types/definitions/rerun/blueprint.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint.fbs @@ -17,9 +17,11 @@ include "./blueprint/components/panel_state.fbs"; include "./blueprint/components/query_expression.fbs"; include "./blueprint/components/root_container.fbs"; include "./blueprint/components/row_share.fbs"; +include "./blueprint/components/sort_order.fbs"; include "./blueprint/components/space_view_class.fbs"; include "./blueprint/components/space_view_maximized.fbs"; include "./blueprint/components/space_view_origin.fbs"; +include "./blueprint/components/table_group_by.fbs"; include "./blueprint/components/tensor_dimension_index_slider.fbs"; include "./blueprint/components/view_fit.fbs"; include "./blueprint/components/viewer_recommendation_hash.fbs"; @@ -41,6 +43,7 @@ include "./blueprint/archetypes/visible_time_ranges.fbs"; include "./blueprint/archetypes/visual_bounds2d.fbs"; include "./blueprint/archetypes/plot_legend.fbs"; +include "./blueprint/archetypes/range_table_settings.fbs"; include "./blueprint/archetypes/scalar_axis.fbs"; include "./blueprint/views/bar_chart.fbs"; diff --git a/crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_settings.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_settings.fbs new file mode 100644 index 0000000000000..abc3ccbec5fd0 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_settings.fbs @@ -0,0 +1,23 @@ +include "arrow/attributes.fbs"; +include "python/attributes.fbs"; +include "rust/attributes.fbs"; + +include "rerun/attributes.fbs"; + +namespace rerun.blueprint.archetypes; + + +/// Configuration for the sorting of the rows of a time range table. +table TableRowOrder ( + "attr.rerun.scope": "blueprint", + "attr.rust.derive": "Copy", + "attr.rust.generate_field_info" +) { + // --- Optional --- + + /// The type of the background. + group_by: rerun.blueprint.components.TableGroupBy ("attr.rerun.component_optional", nullable, order: 1000); + + /// Color used for the `SolidColor` background type. + sort_order: rerun.blueprint.components.SortOrder ("attr.rerun.component_optional", nullable, order: 2000); +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/sort_order.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/sort_order.fbs new file mode 100644 index 0000000000000..94e2310f79cc3 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/components/sort_order.fbs @@ -0,0 +1,20 @@ +include "arrow/attributes.fbs"; +include "python/attributes.fbs"; +include "rust/attributes.fbs"; + +include "rerun/datatypes.fbs"; +include "rerun/attributes.fbs"; + +namespace rerun.blueprint.components; + + +/// Sort order for data table. +enum SortOrder: byte ( + "attr.rerun.scope": "blueprint" +) { + /// Ascending + Ascending (default), + + /// Descending + Descending, +} diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs new file mode 100644 index 0000000000000..e0a1eb76e9816 --- /dev/null +++ b/crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs @@ -0,0 +1,20 @@ +include "arrow/attributes.fbs"; +include "python/attributes.fbs"; +include "rust/attributes.fbs"; + +include "rerun/datatypes.fbs"; +include "rerun/attributes.fbs"; + +namespace rerun.blueprint.components; + + +/// Primary element by which to group by in a temporal data table. +enum TableGroupBy: byte ( + "attr.rerun.scope": "blueprint" +) { + /// Group by entity. + Entity (default), + + /// Group by instance. + Time, +} diff --git a/crates/store/re_types/src/blueprint/archetypes/.gitattributes b/crates/store/re_types/src/blueprint/archetypes/.gitattributes index 6501c56053ed9..91ddfedffbf62 100644 --- a/crates/store/re_types/src/blueprint/archetypes/.gitattributes +++ b/crates/store/re_types/src/blueprint/archetypes/.gitattributes @@ -7,6 +7,7 @@ plot_legend.rs linguist-generated=true scalar_axis.rs linguist-generated=true space_view_blueprint.rs linguist-generated=true space_view_contents.rs linguist-generated=true +table_row_order.rs linguist-generated=true tensor_scalar_mapping.rs linguist-generated=true tensor_slice_selection.rs linguist-generated=true tensor_view_fit.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/archetypes/mod.rs b/crates/store/re_types/src/blueprint/archetypes/mod.rs index c1ae16766e61c..2a38af4fdc267 100644 --- a/crates/store/re_types/src/blueprint/archetypes/mod.rs +++ b/crates/store/re_types/src/blueprint/archetypes/mod.rs @@ -5,6 +5,7 @@ mod plot_legend; mod scalar_axis; mod space_view_blueprint; mod space_view_contents; +mod table_row_order; mod tensor_scalar_mapping; mod tensor_slice_selection; mod tensor_view_fit; @@ -17,6 +18,7 @@ pub use self::plot_legend::PlotLegend; pub use self::scalar_axis::ScalarAxis; pub use self::space_view_blueprint::SpaceViewBlueprint; pub use self::space_view_contents::SpaceViewContents; +pub use self::table_row_order::TableRowOrder; pub use self::tensor_scalar_mapping::TensorScalarMapping; pub use self::tensor_slice_selection::TensorSliceSelection; pub use self::tensor_view_fit::TensorViewFit; diff --git a/crates/store/re_types/src/blueprint/archetypes/table_row_order.rs b/crates/store/re_types/src/blueprint/archetypes/table_row_order.rs new file mode 100644 index 0000000000000..b88418a6d3840 --- /dev/null +++ b/crates/store/re_types/src/blueprint/archetypes/table_row_order.rs @@ -0,0 +1,201 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_settings.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Archetype**: Configuration for the sorting of the rows of a time range table. +#[derive(Clone, Debug, Copy)] +pub struct TableRowOrder { + /// The type of the background. + pub group_by: Option, + + /// Color used for the `SolidColor` background type. + pub sort_order: Option, +} + +impl ::re_types_core::SizeBytes for TableRowOrder { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.group_by.heap_size_bytes() + self.sort_order.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + >::is_pod() + && >::is_pod() + } +} + +static REQUIRED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 0usize]> = + once_cell::sync::Lazy::new(|| []); + +static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.TableRowOrderIndicator".into()]); + +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.blueprint.components.TableGroupBy".into(), + "rerun.blueprint.components.SortOrder".into(), + ] + }); + +static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 3usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.blueprint.components.TableRowOrderIndicator".into(), + "rerun.blueprint.components.TableGroupBy".into(), + "rerun.blueprint.components.SortOrder".into(), + ] + }); + +impl TableRowOrder { + /// The total number of components in the archetype: 0 required, 1 recommended, 2 optional + pub const NUM_COMPONENTS: usize = 3usize; +} + +/// Indicator component for the [`TableRowOrder`] [`::re_types_core::Archetype`] +pub type TableRowOrderIndicator = ::re_types_core::GenericIndicatorComponent; + +impl ::re_types_core::Archetype for TableRowOrder { + type Indicator = TableRowOrderIndicator; + + #[inline] + fn name() -> ::re_types_core::ArchetypeName { + "rerun.blueprint.archetypes.TableRowOrder".into() + } + + #[inline] + fn display_name() -> &'static str { + "Table row order" + } + + #[inline] + fn indicator() -> MaybeOwnedComponentBatch<'static> { + static INDICATOR: TableRowOrderIndicator = TableRowOrderIndicator::DEFAULT; + MaybeOwnedComponentBatch::Ref(&INDICATOR) + } + + #[inline] + fn required_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + REQUIRED_COMPONENTS.as_slice().into() + } + + #[inline] + fn recommended_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + RECOMMENDED_COMPONENTS.as_slice().into() + } + + #[inline] + fn optional_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + OPTIONAL_COMPONENTS.as_slice().into() + } + + #[inline] + fn all_components() -> ::std::borrow::Cow<'static, [ComponentName]> { + ALL_COMPONENTS.as_slice().into() + } + + #[inline] + fn from_arrow_components( + arrow_data: impl IntoIterator)>, + ) -> DeserializationResult { + re_tracing::profile_function!(); + use ::re_types_core::{Loggable as _, ResultExt as _}; + let arrays_by_name: ::std::collections::HashMap<_, _> = arrow_data + .into_iter() + .map(|(name, array)| (name.full_name(), array)) + .collect(); + let group_by = + if let Some(array) = arrays_by_name.get("rerun.blueprint.components.TableGroupBy") { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.TableRowOrder#group_by")? + .into_iter() + .next() + .flatten() + } else { + None + }; + let sort_order = + if let Some(array) = arrays_by_name.get("rerun.blueprint.components.SortOrder") { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.TableRowOrder#sort_order")? + .into_iter() + .next() + .flatten() + } else { + None + }; + Ok(Self { + group_by, + sort_order, + }) + } +} + +impl ::re_types_core::AsComponents for TableRowOrder { + fn as_component_batches(&self) -> Vec> { + re_tracing::profile_function!(); + use ::re_types_core::Archetype as _; + [ + Some(Self::indicator()), + self.group_by + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + self.sort_order + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + ] + .into_iter() + .flatten() + .collect() + } +} + +impl ::re_types_core::ArchetypeReflectionMarker for TableRowOrder {} + +impl TableRowOrder { + /// Create a new `TableRowOrder`. + #[inline] + pub fn new() -> Self { + Self { + group_by: None, + sort_order: None, + } + } + + /// The type of the background. + #[inline] + pub fn with_group_by( + mut self, + group_by: impl Into, + ) -> Self { + self.group_by = Some(group_by.into()); + self + } + + /// Color used for the `SolidColor` background type. + #[inline] + pub fn with_sort_order( + mut self, + sort_order: impl Into, + ) -> Self { + self.sort_order = Some(sort_order.into()); + self + } +} diff --git a/crates/store/re_types/src/blueprint/components/.gitattributes b/crates/store/re_types/src/blueprint/components/.gitattributes index 6a9874206dede..249397ddf0c75 100644 --- a/crates/store/re_types/src/blueprint/components/.gitattributes +++ b/crates/store/re_types/src/blueprint/components/.gitattributes @@ -12,8 +12,10 @@ mod.rs linguist-generated=true panel_state.rs linguist-generated=true query_expression.rs linguist-generated=true row_share.rs linguist-generated=true +sort_order.rs linguist-generated=true space_view_class.rs linguist-generated=true space_view_origin.rs linguist-generated=true +table_group_by.rs linguist-generated=true tensor_dimension_index_slider.rs linguist-generated=true view_fit.rs linguist-generated=true viewer_recommendation_hash.rs linguist-generated=true diff --git a/crates/store/re_types/src/blueprint/components/mod.rs b/crates/store/re_types/src/blueprint/components/mod.rs index 3389f6f39b392..06ecd4230c455 100644 --- a/crates/store/re_types/src/blueprint/components/mod.rs +++ b/crates/store/re_types/src/blueprint/components/mod.rs @@ -13,10 +13,12 @@ mod panel_state; mod panel_state_ext; mod query_expression; mod row_share; +mod sort_order; mod space_view_class; mod space_view_class_ext; mod space_view_origin; mod space_view_origin_ext; +mod table_group_by; mod tensor_dimension_index_slider; mod tensor_dimension_index_slider_ext; mod view_fit; @@ -38,8 +40,10 @@ pub use self::lock_range_during_zoom::LockRangeDuringZoom; pub use self::panel_state::PanelState; pub use self::query_expression::QueryExpression; pub use self::row_share::RowShare; +pub use self::sort_order::SortOrder; pub use self::space_view_class::SpaceViewClass; pub use self::space_view_origin::SpaceViewOrigin; +pub use self::table_group_by::TableGroupBy; pub use self::tensor_dimension_index_slider::TensorDimensionIndexSlider; pub use self::view_fit::ViewFit; pub use self::viewer_recommendation_hash::ViewerRecommendationHash; diff --git a/crates/store/re_types/src/blueprint/components/sort_order.rs b/crates/store/re_types/src/blueprint/components/sort_order.rs new file mode 100644 index 0000000000000..b81f37a2dc765 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/sort_order.rs @@ -0,0 +1,163 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/sort_order.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Component**: Sort order for data table. +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Default)] +pub enum SortOrder { + /// Ascending + #[default] + Ascending = 1, + + /// Descending + Descending = 2, +} + +impl ::re_types_core::reflection::Enum for SortOrder { + #[inline] + fn variants() -> &'static [Self] { + &[Self::Ascending, Self::Descending] + } + + #[inline] + fn docstring_md(self) -> &'static str { + match self { + Self::Ascending => "Ascending", + Self::Descending => "Descending", + } + } +} + +impl ::re_types_core::SizeBytes for SortOrder { + #[inline] + fn heap_size_bytes(&self) -> u64 { + 0 + } + + #[inline] + fn is_pod() -> bool { + true + } +} + +impl std::fmt::Display for SortOrder { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Ascending => write!(f, "Ascending"), + Self::Descending => write!(f, "Descending"), + } + } +} + +::re_types_core::macros::impl_into_cow!(SortOrder); + +impl ::re_types_core::Loggable for SortOrder { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.SortOrder".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::Union( + std::sync::Arc::new(vec![ + Field::new("_null_markers", DataType::Null, true), + Field::new("Ascending", DataType::Null, true), + Field::new("Descending", DataType::Null, true), + ]), + Some(std::sync::Arc::new(vec![0i32, 1i32, 2i32])), + UnionMode::Sparse, + ) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + // Sparse Arrow union + let data: Vec<_> = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + datum + }) + .collect(); + let num_variants = 2usize; + let types = data + .iter() + .map(|a| match a.as_deref() { + None => 0, + Some(value) => *value as i8, + }) + .collect(); + let fields: Vec<_> = + std::iter::repeat(NullArray::new(DataType::Null, data.len()).boxed()) + .take(1 + num_variants) + .collect(); + UnionArray::new(Self::arrow_datatype(), types, fields, None).boxed() + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + Ok({ + let arrow_data = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.SortOrder")?; + let arrow_data_types = arrow_data.types(); + arrow_data_types + .iter() + .map(|typ| match typ { + 0 => Ok(None), + 1 => Ok(Some(Self::Ascending)), + 2 => Ok(Some(Self::Descending)), + _ => Err(DeserializationError::missing_union_arm( + Self::arrow_datatype(), + "", + *typ as _, + )), + }) + .collect::>>() + .with_context("rerun.blueprint.components.SortOrder")? + }) + } +} diff --git a/crates/store/re_types/src/blueprint/components/table_group_by.rs b/crates/store/re_types/src/blueprint/components/table_group_by.rs new file mode 100644 index 0000000000000..68233f10a75b2 --- /dev/null +++ b/crates/store/re_types/src/blueprint/components/table_group_by.rs @@ -0,0 +1,163 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs". + +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::cloned_instead_of_copied)] +#![allow(clippy::map_flatten)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] + +use ::re_types_core::external::arrow2; +use ::re_types_core::ComponentName; +use ::re_types_core::SerializationResult; +use ::re_types_core::{ComponentBatch, MaybeOwnedComponentBatch}; +use ::re_types_core::{DeserializationError, DeserializationResult}; + +/// **Component**: Primary element by which to group by in a temporal data table. +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Default)] +pub enum TableGroupBy { + /// Group by entity. + #[default] + Entity = 1, + + /// Group by instance. + Time = 2, +} + +impl ::re_types_core::reflection::Enum for TableGroupBy { + #[inline] + fn variants() -> &'static [Self] { + &[Self::Entity, Self::Time] + } + + #[inline] + fn docstring_md(self) -> &'static str { + match self { + Self::Entity => "Group by entity.", + Self::Time => "Group by instance.", + } + } +} + +impl ::re_types_core::SizeBytes for TableGroupBy { + #[inline] + fn heap_size_bytes(&self) -> u64 { + 0 + } + + #[inline] + fn is_pod() -> bool { + true + } +} + +impl std::fmt::Display for TableGroupBy { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Entity => write!(f, "Entity"), + Self::Time => write!(f, "Time"), + } + } +} + +::re_types_core::macros::impl_into_cow!(TableGroupBy); + +impl ::re_types_core::Loggable for TableGroupBy { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.TableGroupBy".into() + } + + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + #![allow(clippy::wildcard_imports)] + use arrow2::datatypes::*; + DataType::Union( + std::sync::Arc::new(vec![ + Field::new("_null_markers", DataType::Null, true), + Field::new("Entity", DataType::Null, true), + Field::new("Time", DataType::Null, true), + ]), + Some(std::sync::Arc::new(vec![0i32, 1i32, 2i32])), + UnionMode::Sparse, + ) + } + + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + // Sparse Arrow union + let data: Vec<_> = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + datum + }) + .collect(); + let num_variants = 2usize; + let types = data + .iter() + .map(|a| match a.as_deref() { + None => 0, + Some(value) => *value as i8, + }) + .collect(); + let fields: Vec<_> = + std::iter::repeat(NullArray::new(DataType::Null, data.len()).boxed()) + .take(1 + num_variants) + .collect(); + UnionArray::new(Self::arrow_datatype(), types, fields, None).boxed() + }) + } + + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + #![allow(clippy::wildcard_imports)] + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + Ok({ + let arrow_data = arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + let expected = Self::arrow_datatype(); + let actual = arrow_data.data_type().clone(); + DeserializationError::datatype_mismatch(expected, actual) + }) + .with_context("rerun.blueprint.components.TableGroupBy")?; + let arrow_data_types = arrow_data.types(); + arrow_data_types + .iter() + .map(|typ| match typ { + 0 => Ok(None), + 1 => Ok(Some(Self::Entity)), + 2 => Ok(Some(Self::Time)), + _ => Err(DeserializationError::missing_union_arm( + Self::arrow_datatype(), + "", + *typ as _, + )), + }) + .collect::>>() + .with_context("rerun.blueprint.components.TableGroupBy")? + }) + } +} diff --git a/crates/viewer/re_edit_ui/src/lib.rs b/crates/viewer/re_edit_ui/src/lib.rs index af4efaf8b46e7..2f42e654a776d 100644 --- a/crates/viewer/re_edit_ui/src/lib.rs +++ b/crates/viewer/re_edit_ui/src/lib.rs @@ -15,6 +15,7 @@ use datatype_editors::{ display_name_ui, display_text_ui, edit_bool, edit_f32_min_to_max_float, edit_f32_zero_to_max, edit_f32_zero_to_one, edit_multiline_string, edit_singleline_string, edit_view_enum, }; +use re_types::blueprint::components::{SortOrder, TableGroupBy}; use re_types::{ blueprint::components::{BackgroundKind, Corner2D, LockRangeDuringZoom, ViewFit, Visible}, components::{ @@ -68,8 +69,6 @@ pub fn register_editors(registry: &mut re_viewer_context::ComponentUiRegistry) { colormap_edit_or_view_ui(ctx.render_ctx, ui, value) }); registry.add_singleline_edit_or_view(|_ctx, ui, value| edit_view_enum::(ui, value)); - registry - .add_singleline_edit_or_view(|_ctx, ui, value| edit_view_enum::(ui, value)); registry.add_singleline_edit_or_view(|_ctx, ui, value| edit_view_enum::(ui, value)); registry.add_singleline_edit_or_view(|_ctx, ui, value| edit_view_enum::(ui, value)); registry.add_singleline_edit_or_view(|_ctx, ui, value| { @@ -79,6 +78,9 @@ pub fn register_editors(registry: &mut re_viewer_context::ComponentUiRegistry) { edit_view_enum::(ui, value) }); registry.add_singleline_edit_or_view(|_ctx, ui, value| edit_view_enum::(ui, value)); + registry.add_singleline_edit_or_view(|_ctx, ui, value| edit_view_enum::(ui, value)); + registry + .add_singleline_edit_or_view(|_ctx, ui, value| edit_view_enum::(ui, value)); registry.add_multiline_edit_or_view(visual_bounds2d::multiline_edit_visual_bounds2d); registry.add_singleline_edit_or_view(visual_bounds2d::singleline_edit_visual_bounds2d); diff --git a/crates/viewer/re_space_view_dataframe/Cargo.toml b/crates/viewer/re_space_view_dataframe/Cargo.toml index 483c6804cf68b..a6ff38a428fb8 100644 --- a/crates/viewer/re_space_view_dataframe/Cargo.toml +++ b/crates/viewer/re_space_view_dataframe/Cargo.toml @@ -24,10 +24,13 @@ re_data_ui.workspace = true re_entity_db.workspace = true re_log_types.workspace = true re_renderer.workspace = true +re_space_view.workspace = true re_tracing.workspace = true +re_types.workspace = true re_types_core.workspace = true re_ui.workspace = true re_viewer_context.workspace = true +re_viewport_blueprint.workspace = true egui_extras.workspace = true egui.workspace = true diff --git a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index 427ad5955fade..27253e00bead7 100644 --- a/crates/viewer/re_space_view_dataframe/src/space_view_class.rs +++ b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs @@ -1,18 +1,22 @@ +use crate::visualizer_system::EmptySystem; +use egui::Ui; use egui_extras::{Column, TableRow}; -use std::collections::{BTreeMap, BTreeSet}; - use re_chunk_store::{ChunkStore, LatestAtQuery, RangeQuery, RowId}; use re_data_ui::item_ui::{entity_path_button, instance_path_button}; use re_entity_db::InstancePath; -use re_log_types::{EntityPath, Instance, ResolvedTimeRange, Timeline}; +use re_log_types::{EntityPath, Instance, ResolvedTimeRange, TimeInt, Timeline}; +use re_space_view::view_property_ui; +use re_types::blueprint::archetypes::{PlotLegend, TableRowOrder}; +use re_types::blueprint::components::{SortOrder, TableGroupBy}; use re_types_core::datatypes::TimeRange; use re_types_core::{ComponentName, SpaceViewClassIdentifier}; +use re_ui::list_item; use re_viewer_context::{ - QueryRange, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewState, + QueryRange, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewState, SpaceViewSystemExecutionError, SystemExecutionOutput, UiLayout, ViewQuery, ViewerContext, }; - -use crate::visualizer_system::EmptySystem; +use re_viewport_blueprint::ViewProperty; +use std::collections::{BTreeMap, BTreeSet}; #[derive(Default)] pub struct DataframeSpaceView; @@ -63,29 +67,54 @@ impl SpaceViewClass for DataframeSpaceView { Default::default() } + fn selection_ui( + &self, + ctx: &ViewerContext<'_>, + ui: &mut Ui, + state: &mut dyn SpaceViewState, + _space_origin: &EntityPath, + space_view_id: SpaceViewId, + ) -> Result<(), SpaceViewSystemExecutionError> { + list_item::list_item_scope(ui, "dataframe_view_selection_ui", |ui| { + view_property_ui::(ctx, ui, space_view_id, self, state); + }); + + Ok(()) + } + fn ui( &self, ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - _state: &mut dyn SpaceViewState, + state: &mut dyn SpaceViewState, query: &ViewQuery<'_>, _system_output: SystemExecutionOutput, ) -> Result<(), SpaceViewSystemExecutionError> { re_tracing::profile_function!(); + let row_order = ViewProperty::from_archetype::( + ctx.blueprint_db(), + ctx.blueprint_query, + query.space_view_id, + ); + let group_by = row_order.component_or_fallback::(ctx, self, state)?; + let sort_order = row_order.component_or_fallback::(ctx, self, state)?; + // TODO(ab): we probably want a less "implicit" way to switch from temporal vs. latest at tables. let is_range_query = query .iter_all_data_results() .any(|data_result| data_result.property_overrides.query_range.is_time_range()); if is_range_query { - entity_and_time_vs_component_ui(ctx, ui, query) + entity_and_time_vs_component_ui(ctx, ui, query, group_by, sort_order) } else { entity_and_instance_vs_component_ui(ctx, ui, query) } } } +re_viewer_context::impl_component_fallback_provider!(DataframeSpaceView => []); + /// Show a table with entities and time as rows, and components as columns. /// /// Here, a "row" is a tuple of (entity_path, time, row_id). This means that both "over logging" @@ -105,6 +134,8 @@ fn entity_and_time_vs_component_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, query: &ViewQuery<'_>, + group_by: TableGroupBy, + sort_order: SortOrder, ) -> Result<(), SpaceViewSystemExecutionError> { re_tracing::profile_function!(); @@ -171,17 +202,36 @@ fn entity_and_time_vs_component_ui( }) .collect::>(); - let rows = rows_to_chunk.keys().collect::>(); + let mut rows = rows_to_chunk.keys().collect::>(); + + // apply group_by + match group_by { + TableGroupBy::Entity => {} // already correctly sorted + TableGroupBy::Time => rows.sort_by_key(|(entity_path, time, _)| (*time, entity_path)), + }; + if sort_order == SortOrder::Descending { + rows.reverse(); + } + + let entity_header = |ui: &mut egui::Ui| { + ui.strong("Entity"); + }; + let time_header = |ui: &mut egui::Ui| { + ui.strong("Time"); + }; // Draw the header row. let header_ui = |mut row: egui_extras::TableRow<'_, '_>| { - row.col(|ui| { - ui.strong("Entity"); - }); - - row.col(|ui| { - ui.strong("Time"); - }); + match group_by { + TableGroupBy::Entity => { + row.col(entity_header); + row.col(time_header); + } + TableGroupBy::Time => { + row.col(time_header); + row.col(entity_header); + } + } row.col(|ui| { ui.strong("Row ID"); @@ -194,6 +244,27 @@ fn entity_and_time_vs_component_ui( } }; + let latest_at_query = query.latest_at_query(); + let entity_ui = |ui: &mut egui::Ui, entity_path: &EntityPath| { + entity_path_button( + ctx, + &latest_at_query, + ctx.recording(), + ui, + Some(query.space_view_id), + entity_path, + ); + }; + + let time_ui = |ui: &mut egui::Ui, time: &TimeInt| { + ui.label( + query + .timeline + .typ() + .format(*time, ctx.app_options.time_zone), + ); + }; + // Draw a single line of the table. This is called for each _visible_ row, so it's ok to // duplicate some of the querying. let latest_at_query = query.latest_at_query(); @@ -202,25 +273,16 @@ fn entity_and_time_vs_component_ui( let row_chunk = rows_to_chunk.get(row_key).unwrap(); let (entity_path, time, row_id) = row_key; - row.col(|ui| { - entity_path_button( - ctx, - &latest_at_query, - ctx.recording(), - ui, - Some(query.space_view_id), - entity_path, - ); - }); - - row.col(|ui| { - ui.label( - query - .timeline - .typ() - .format(*time, ctx.app_options.time_zone), - ); - }); + match group_by { + TableGroupBy::Entity => { + row.col(|ui| entity_ui(ui, entity_path)); + row.col(|ui| time_ui(ui, time)); + } + TableGroupBy::Time => { + row.col(|ui| time_ui(ui, time)); + row.col(|ui| entity_ui(ui, entity_path)); + } + }; row.col(|ui| { row_id_ui(ui, row_id); diff --git a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs index f7eb9218a0253..3b285ea98be6b 100644 --- a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs +++ b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs @@ -11,8 +11,10 @@ pub use re_types::blueprint::components::LockRangeDuringZoom; pub use re_types::blueprint::components::PanelState; pub use re_types::blueprint::components::QueryExpression; pub use re_types::blueprint::components::RowShare; +pub use re_types::blueprint::components::SortOrder; pub use re_types::blueprint::components::SpaceViewClass; pub use re_types::blueprint::components::SpaceViewOrigin; +pub use re_types::blueprint::components::TableGroupBy; pub use re_types::blueprint::components::TensorDimensionIndexSlider; pub use re_types::blueprint::components::ViewFit; pub use re_types::blueprint::components::ViewerRecommendationHash; @@ -48,9 +50,11 @@ pub fn is_valid_blueprint(blueprint: &EntityDb) -> bool { && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) + && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) + && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) && validate_component::(blueprint) diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 234bc7889215c..09baec388123f 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -146,6 +146,13 @@ fn generate_component_reflection() -> Result::name(), + ComponentReflection { + docstring_md: "Sort order for data table.", + placeholder: Some(SortOrder::default().to_arrow()?), + }, + ), ( ::name(), ComponentReflection { @@ -167,6 +174,13 @@ fn generate_component_reflection() -> Result::name(), + ComponentReflection { + docstring_md: "Primary element by which to group by in a temporal data table.", + placeholder: Some(TableGroupBy::default().to_arrow()?), + }, + ), ( ::name(), ComponentReflection { @@ -613,6 +627,22 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { ], }, ), + ( + ArchetypeName::new("rerun.blueprint.archetypes.TableRowOrder"), + ArchetypeReflection { + display_name: "Table row order", + docstring_md: "Configuration for the sorting of the rows of a time range table.", + fields: vec![ + ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.TableGroupBy".into(), display_name : + "Group by", docstring_md : "The type of the background.", }, + ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.SortOrder".into(), display_name : + "Sort order", docstring_md : + "Color used for the `SolidColor` background type.", }, + ], + }, + ), ( ArchetypeName::new("rerun.blueprint.archetypes.TensorScalarMapping"), ArchetypeReflection { diff --git a/rerun_cpp/src/rerun/blueprint/archetypes.hpp b/rerun_cpp/src/rerun/blueprint/archetypes.hpp index 8dfd7175e565e..03f21ca4bdff1 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes.hpp @@ -9,6 +9,7 @@ #include "blueprint/archetypes/scalar_axis.hpp" #include "blueprint/archetypes/space_view_blueprint.hpp" #include "blueprint/archetypes/space_view_contents.hpp" +#include "blueprint/archetypes/table_row_order.hpp" #include "blueprint/archetypes/tensor_scalar_mapping.hpp" #include "blueprint/archetypes/tensor_slice_selection.hpp" #include "blueprint/archetypes/tensor_view_fit.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes index c941889168aa0..b190995becbcb 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes @@ -15,6 +15,8 @@ space_view_blueprint.cpp linguist-generated=true space_view_blueprint.hpp linguist-generated=true space_view_contents.cpp linguist-generated=true space_view_contents.hpp linguist-generated=true +table_row_order.cpp linguist-generated=true +table_row_order.hpp linguist-generated=true tensor_scalar_mapping.cpp linguist-generated=true tensor_scalar_mapping.hpp linguist-generated=true tensor_slice_selection.cpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.cpp new file mode 100644 index 0000000000000..09492f06d9851 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.cpp @@ -0,0 +1,38 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_settings.fbs". + +#include "table_row_order.hpp" + +#include "../../collection_adapter_builtins.hpp" + +namespace rerun::blueprint::archetypes {} + +namespace rerun { + + Result> AsComponents::serialize( + const blueprint::archetypes::TableRowOrder& archetype + ) { + using namespace blueprint::archetypes; + std::vector cells; + cells.reserve(3); + + if (archetype.group_by.has_value()) { + auto result = DataCell::from_loggable(archetype.group_by.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + if (archetype.sort_order.has_value()) { + auto result = DataCell::from_loggable(archetype.sort_order.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + { + auto indicator = TableRowOrder::IndicatorComponent(); + auto result = DataCell::from_loggable(indicator); + RR_RETURN_NOT_OK(result.error); + cells.emplace_back(std::move(result.value)); + } + + return cells; + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp new file mode 100644 index 0000000000000..891176bc18d23 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp @@ -0,0 +1,69 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_settings.fbs". + +#pragma once + +#include "../../blueprint/components/sort_order.hpp" +#include "../../blueprint/components/table_group_by.hpp" +#include "../../collection.hpp" +#include "../../compiler_utils.hpp" +#include "../../data_cell.hpp" +#include "../../indicator_component.hpp" +#include "../../result.hpp" + +#include +#include +#include +#include + +namespace rerun::blueprint::archetypes { + /// **Archetype**: Configuration for the sorting of the rows of a time range table. + struct TableRowOrder { + /// The type of the background. + std::optional group_by; + + /// Color used for the `SolidColor` background type. + std::optional sort_order; + + public: + static constexpr const char IndicatorComponentName[] = + "rerun.blueprint.components.TableRowOrderIndicator"; + + /// Indicator component, used to identify the archetype when converting to a list of components. + using IndicatorComponent = rerun::components::IndicatorComponent; + + public: + TableRowOrder() = default; + TableRowOrder(TableRowOrder&& other) = default; + + /// The type of the background. + TableRowOrder with_group_by(rerun::blueprint::components::TableGroupBy _group_by) && { + group_by = std::move(_group_by); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + + /// Color used for the `SolidColor` background type. + TableRowOrder with_sort_order(rerun::blueprint::components::SortOrder _sort_order) && { + sort_order = std::move(_sort_order); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + }; + +} // namespace rerun::blueprint::archetypes + +namespace rerun { + /// \private + template + struct AsComponents; + + /// \private + template <> + struct AsComponents { + /// Serialize all set component batches. + static Result> serialize( + const blueprint::archetypes::TableRowOrder& archetype + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components.hpp b/rerun_cpp/src/rerun/blueprint/components.hpp index 45e6beaf7803c..6d72c740fbf27 100644 --- a/rerun_cpp/src/rerun/blueprint/components.hpp +++ b/rerun_cpp/src/rerun/blueprint/components.hpp @@ -18,9 +18,11 @@ #include "blueprint/components/query_expression.hpp" #include "blueprint/components/root_container.hpp" #include "blueprint/components/row_share.hpp" +#include "blueprint/components/sort_order.hpp" #include "blueprint/components/space_view_class.hpp" #include "blueprint/components/space_view_maximized.hpp" #include "blueprint/components/space_view_origin.hpp" +#include "blueprint/components/table_group_by.hpp" #include "blueprint/components/tensor_dimension_index_slider.hpp" #include "blueprint/components/view_fit.hpp" #include "blueprint/components/viewer_recommendation_hash.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/components/.gitattributes b/rerun_cpp/src/rerun/blueprint/components/.gitattributes index 11d00c3d18753..1afaab8ac7bcb 100644 --- a/rerun_cpp/src/rerun/blueprint/components/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/components/.gitattributes @@ -21,9 +21,13 @@ panel_state.hpp linguist-generated=true query_expression.hpp linguist-generated=true root_container.hpp linguist-generated=true row_share.hpp linguist-generated=true +sort_order.cpp linguist-generated=true +sort_order.hpp linguist-generated=true space_view_class.hpp linguist-generated=true space_view_maximized.hpp linguist-generated=true space_view_origin.hpp linguist-generated=true +table_group_by.cpp linguist-generated=true +table_group_by.hpp linguist-generated=true tensor_dimension_index_slider.hpp linguist-generated=true view_fit.cpp linguist-generated=true view_fit.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/components/sort_order.cpp b/rerun_cpp/src/rerun/blueprint/components/sort_order.cpp new file mode 100644 index 0000000000000..b1a4ec0e58147 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/sort_order.cpp @@ -0,0 +1,62 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/sort_order.fbs". + +#include "sort_order.hpp" + +#include +#include + +namespace rerun { + const std::shared_ptr& + Loggable::arrow_datatype() { + static const auto datatype = arrow::sparse_union({ + arrow::field("_null_markers", arrow::null(), true, nullptr), + arrow::field("Ascending", arrow::null(), true), + arrow::field("Descending", arrow::null(), true), + }); + return datatype; + } + + Result> Loggable::to_arrow( + const blueprint::components::SortOrder* instances, size_t num_instances + ) { + // TODO(andreas): Allow configuring the memory pool. + arrow::MemoryPool* pool = arrow::default_memory_pool(); + auto datatype = arrow_datatype(); + + ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) + if (instances && num_instances > 0) { + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + static_cast(builder.get()), + instances, + num_instances + )); + } + std::shared_ptr array; + ARROW_RETURN_NOT_OK(builder->Finish(&array)); + return array; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::SparseUnionBuilder* builder, const blueprint::components::SortOrder* elements, + size_t num_elements + ) { + if (builder == nullptr) { + return rerun::Error(ErrorCode::UnexpectedNullArgument, "Passed array builder is null."); + } + if (elements == nullptr) { + return rerun::Error( + ErrorCode::UnexpectedNullArgument, + "Cannot serialize null pointer to arrow array." + ); + } + + ARROW_RETURN_NOT_OK(builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + const auto variant = elements[elem_idx]; + ARROW_RETURN_NOT_OK(builder->Append(static_cast(variant))); + } + + return Error::ok(); + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/sort_order.hpp b/rerun_cpp/src/rerun/blueprint/components/sort_order.hpp new file mode 100644 index 0000000000000..a292ab9bd19ac --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/sort_order.hpp @@ -0,0 +1,52 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/sort_order.fbs". + +#pragma once + +#include "../../result.hpp" + +#include +#include + +namespace arrow { + class Array; + class DataType; + class SparseUnionBuilder; +} // namespace arrow + +namespace rerun::blueprint::components { + /// **Component**: Sort order for data table. + enum class SortOrder : uint8_t { + + /// Ascending + Ascending = 1, + + /// Descending + Descending = 2, + }; +} // namespace rerun::blueprint::components + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.SortOrder"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Serializes an array of `rerun::blueprint:: components::SortOrder` into an arrow array. + static Result> to_arrow( + const blueprint::components::SortOrder* instances, size_t num_instances + ); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::SparseUnionBuilder* builder, const blueprint::components::SortOrder* elements, + size_t num_elements + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/table_group_by.cpp b/rerun_cpp/src/rerun/blueprint/components/table_group_by.cpp new file mode 100644 index 0000000000000..6cf091ead3ce4 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/table_group_by.cpp @@ -0,0 +1,64 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs". + +#include "table_group_by.hpp" + +#include +#include + +namespace rerun { + const std::shared_ptr& + Loggable::arrow_datatype() { + static const auto datatype = arrow::sparse_union({ + arrow::field("_null_markers", arrow::null(), true, nullptr), + arrow::field("Entity", arrow::null(), true), + arrow::field("Time", arrow::null(), true), + }); + return datatype; + } + + Result> Loggable::to_arrow( + const blueprint::components::TableGroupBy* instances, size_t num_instances + ) { + // TODO(andreas): Allow configuring the memory pool. + arrow::MemoryPool* pool = arrow::default_memory_pool(); + auto datatype = arrow_datatype(); + + ARROW_ASSIGN_OR_RAISE(auto builder, arrow::MakeBuilder(datatype, pool)) + if (instances && num_instances > 0) { + RR_RETURN_NOT_OK( + Loggable::fill_arrow_array_builder( + static_cast(builder.get()), + instances, + num_instances + ) + ); + } + std::shared_ptr array; + ARROW_RETURN_NOT_OK(builder->Finish(&array)); + return array; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::SparseUnionBuilder* builder, const blueprint::components::TableGroupBy* elements, + size_t num_elements + ) { + if (builder == nullptr) { + return rerun::Error(ErrorCode::UnexpectedNullArgument, "Passed array builder is null."); + } + if (elements == nullptr) { + return rerun::Error( + ErrorCode::UnexpectedNullArgument, + "Cannot serialize null pointer to arrow array." + ); + } + + ARROW_RETURN_NOT_OK(builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + const auto variant = elements[elem_idx]; + ARROW_RETURN_NOT_OK(builder->Append(static_cast(variant))); + } + + return Error::ok(); + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/table_group_by.hpp b/rerun_cpp/src/rerun/blueprint/components/table_group_by.hpp new file mode 100644 index 0000000000000..580ac1cc04d04 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/table_group_by.hpp @@ -0,0 +1,52 @@ +// DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs". + +#pragma once + +#include "../../result.hpp" + +#include +#include + +namespace arrow { + class Array; + class DataType; + class SparseUnionBuilder; +} // namespace arrow + +namespace rerun::blueprint::components { + /// **Component**: Primary element by which to group by in a temporal data table. + enum class TableGroupBy : uint8_t { + + /// Group by entity. + Entity = 1, + + /// Group by instance. + Time = 2, + }; +} // namespace rerun::blueprint::components + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.TableGroupBy"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Serializes an array of `rerun::blueprint:: components::TableGroupBy` into an arrow array. + static Result> to_arrow( + const blueprint::components::TableGroupBy* instances, size_t num_instances + ); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::SparseUnionBuilder* builder, const blueprint::components::TableGroupBy* elements, + size_t num_elements + ); + }; +} // namespace rerun diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes index ac20f8caae1f0..e9b7ed7aca7c4 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes @@ -9,6 +9,7 @@ plot_legend.py linguist-generated=true scalar_axis.py linguist-generated=true space_view_blueprint.py linguist-generated=true space_view_contents.py linguist-generated=true +table_row_order.py linguist-generated=true tensor_scalar_mapping.py linguist-generated=true tensor_slice_selection.py linguist-generated=true tensor_view_fit.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py index 3af18008eb45c..7e0f853a05159 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py @@ -9,6 +9,7 @@ from .scalar_axis import ScalarAxis from .space_view_blueprint import SpaceViewBlueprint from .space_view_contents import SpaceViewContents +from .table_row_order import TableRowOrder from .tensor_scalar_mapping import TensorScalarMapping from .tensor_slice_selection import TensorSliceSelection from .tensor_view_fit import TensorViewFit @@ -24,6 +25,7 @@ "ScalarAxis", "SpaceViewBlueprint", "SpaceViewContents", + "TableRowOrder", "TensorScalarMapping", "TensorSliceSelection", "TensorViewFit", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/table_row_order.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/table_row_order.py new file mode 100644 index 0000000000000..12b301bd09ac4 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/table_row_order.py @@ -0,0 +1,82 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_settings.fbs". + +# You can extend this class by creating a "TableRowOrderExt" class in "table_row_order_ext.py". + +from __future__ import annotations + +from typing import Any + +from attrs import define, field + +from ..._baseclasses import ( + Archetype, +) +from ...blueprint import components as blueprint_components +from ...error_utils import catch_and_log_exceptions + +__all__ = ["TableRowOrder"] + + +@define(str=False, repr=False, init=False) +class TableRowOrder(Archetype): + """**Archetype**: Configuration for the sorting of the rows of a time range table.""" + + def __init__( + self: Any, + *, + group_by: blueprint_components.TableGroupByLike | None = None, + sort_order: blueprint_components.SortOrderLike | None = None, + ): + """ + Create a new instance of the TableRowOrder archetype. + + Parameters + ---------- + group_by: + The type of the background. + sort_order: + Color used for the `SolidColor` background type. + + """ + + # You can define your own __init__ function as a member of TableRowOrderExt in table_row_order_ext.py + with catch_and_log_exceptions(context=self.__class__.__name__): + self.__attrs_init__(group_by=group_by, sort_order=sort_order) + return + self.__attrs_clear__() + + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( + group_by=None, # type: ignore[arg-type] + sort_order=None, # type: ignore[arg-type] + ) + + @classmethod + def _clear(cls) -> TableRowOrder: + """Produce an empty TableRowOrder, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + + group_by: blueprint_components.TableGroupByBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=blueprint_components.TableGroupByBatch._optional, # type: ignore[misc] + ) + # The type of the background. + # + # (Docstring intentionally commented out to hide this field from the docs) + + sort_order: blueprint_components.SortOrderBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=blueprint_components.SortOrderBatch._optional, # type: ignore[misc] + ) + # Color used for the `SolidColor` background type. + # + # (Docstring intentionally commented out to hide this field from the docs) + + __str__ = Archetype.__str__ + __repr__ = Archetype.__repr__ # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes index e232a7f04c35f..93184d1eccce3 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes @@ -18,9 +18,11 @@ panel_state.py linguist-generated=true query_expression.py linguist-generated=true root_container.py linguist-generated=true row_share.py linguist-generated=true +sort_order.py linguist-generated=true space_view_class.py linguist-generated=true space_view_maximized.py linguist-generated=true space_view_origin.py linguist-generated=true +table_group_by.py linguist-generated=true tensor_dimension_index_slider.py linguist-generated=true view_fit.py linguist-generated=true viewer_recommendation_hash.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py index 10f98717719d1..3307a07114eda 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py @@ -30,9 +30,11 @@ from .query_expression import QueryExpression, QueryExpressionBatch, QueryExpressionType from .root_container import RootContainer, RootContainerBatch, RootContainerType from .row_share import RowShare, RowShareBatch, RowShareType +from .sort_order import SortOrder, SortOrderArrayLike, SortOrderBatch, SortOrderLike, SortOrderType from .space_view_class import SpaceViewClass, SpaceViewClassBatch, SpaceViewClassType from .space_view_maximized import SpaceViewMaximized, SpaceViewMaximizedBatch, SpaceViewMaximizedType from .space_view_origin import SpaceViewOrigin, SpaceViewOriginBatch, SpaceViewOriginType +from .table_group_by import TableGroupBy, TableGroupByArrayLike, TableGroupByBatch, TableGroupByLike, TableGroupByType from .tensor_dimension_index_slider import ( TensorDimensionIndexSlider, TensorDimensionIndexSliderBatch, @@ -106,6 +108,11 @@ "RowShare", "RowShareBatch", "RowShareType", + "SortOrder", + "SortOrderArrayLike", + "SortOrderBatch", + "SortOrderLike", + "SortOrderType", "SpaceViewClass", "SpaceViewClassBatch", "SpaceViewClassType", @@ -115,6 +122,11 @@ "SpaceViewOrigin", "SpaceViewOriginBatch", "SpaceViewOriginType", + "TableGroupBy", + "TableGroupByArrayLike", + "TableGroupByBatch", + "TableGroupByLike", + "TableGroupByType", "TensorDimensionIndexSlider", "TensorDimensionIndexSliderBatch", "TensorDimensionIndexSliderType", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/sort_order.py b/rerun_py/rerun_sdk/rerun/blueprint/components/sort_order.py new file mode 100644 index 0000000000000..70c932379614c --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/sort_order.py @@ -0,0 +1,93 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/sort_order.fbs". + +# You can extend this class by creating a "SortOrderExt" class in "sort_order_ext.py". + +from __future__ import annotations + +from typing import Literal, Sequence, Union + +import pyarrow as pa + +from ..._baseclasses import ( + BaseBatch, + BaseExtensionType, + ComponentBatchMixin, +) + +__all__ = ["SortOrder", "SortOrderArrayLike", "SortOrderBatch", "SortOrderLike", "SortOrderType"] + + +from enum import Enum + + +class SortOrder(Enum): + """**Component**: Sort order for data table.""" + + Ascending = 1 + """Ascending""" + + Descending = 2 + """Descending""" + + +SortOrderLike = Union[SortOrder, Literal["ascending", "descending"]] +SortOrderArrayLike = Union[SortOrderLike, Sequence[SortOrderLike]] + + +class SortOrderType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.components.SortOrder" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.sparse_union([ + pa.field("_null_markers", pa.null(), nullable=True, metadata={}), + pa.field("Ascending", pa.null(), nullable=True, metadata={}), + pa.field("Descending", pa.null(), nullable=True, metadata={}), + ]), + self._TYPE_NAME, + ) + + +class SortOrderBatch(BaseBatch[SortOrderArrayLike], ComponentBatchMixin): + _ARROW_TYPE = SortOrderType() + + @staticmethod + def _native_to_pa_array(data: SortOrderArrayLike, data_type: pa.DataType) -> pa.Array: + if isinstance(data, (SortOrder, int, str)): + data = [data] + + types: list[int] = [] + + for value in data: + if value is None: + types.append(0) + elif isinstance(value, SortOrder): + types.append(value.value) # Actual enum value + elif isinstance(value, int): + types.append(value) # By number + elif isinstance(value, str): + if hasattr(SortOrder, value): + types.append(SortOrder[value].value) # fast path + elif value.lower() == "ascending": + types.append(SortOrder.Ascending.value) + elif value.lower() == "descending": + types.append(SortOrder.Descending.value) + else: + raise ValueError(f"Unknown SortOrder kind: {value}") + else: + raise ValueError(f"Unknown SortOrder kind: {value}") + + buffers = [ + None, + pa.array(types, type=pa.int8()).buffers()[1], + ] + children = (1 + 2) * [pa.nulls(len(data))] + + return pa.UnionArray.from_buffers( + type=data_type, + length=len(data), + buffers=buffers, + children=children, + ) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/table_group_by.py b/rerun_py/rerun_sdk/rerun/blueprint/components/table_group_by.py new file mode 100644 index 0000000000000..1136d14a3bce7 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/table_group_by.py @@ -0,0 +1,93 @@ +# DO NOT EDIT! This file was auto-generated by crates/build/re_types_builder/src/codegen/python/mod.rs +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs". + +# You can extend this class by creating a "TableGroupByExt" class in "table_group_by_ext.py". + +from __future__ import annotations + +from typing import Literal, Sequence, Union + +import pyarrow as pa + +from ..._baseclasses import ( + BaseBatch, + BaseExtensionType, + ComponentBatchMixin, +) + +__all__ = ["TableGroupBy", "TableGroupByArrayLike", "TableGroupByBatch", "TableGroupByLike", "TableGroupByType"] + + +from enum import Enum + + +class TableGroupBy(Enum): + """**Component**: Primary element by which to group by in a temporal data table.""" + + Entity = 1 + """Group by entity.""" + + Time = 2 + """Group by instance.""" + + +TableGroupByLike = Union[TableGroupBy, Literal["entity", "time"]] +TableGroupByArrayLike = Union[TableGroupByLike, Sequence[TableGroupByLike]] + + +class TableGroupByType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.components.TableGroupBy" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.sparse_union([ + pa.field("_null_markers", pa.null(), nullable=True, metadata={}), + pa.field("Entity", pa.null(), nullable=True, metadata={}), + pa.field("Time", pa.null(), nullable=True, metadata={}), + ]), + self._TYPE_NAME, + ) + + +class TableGroupByBatch(BaseBatch[TableGroupByArrayLike], ComponentBatchMixin): + _ARROW_TYPE = TableGroupByType() + + @staticmethod + def _native_to_pa_array(data: TableGroupByArrayLike, data_type: pa.DataType) -> pa.Array: + if isinstance(data, (TableGroupBy, int, str)): + data = [data] + + types: list[int] = [] + + for value in data: + if value is None: + types.append(0) + elif isinstance(value, TableGroupBy): + types.append(value.value) # Actual enum value + elif isinstance(value, int): + types.append(value) # By number + elif isinstance(value, str): + if hasattr(TableGroupBy, value): + types.append(TableGroupBy[value].value) # fast path + elif value.lower() == "entity": + types.append(TableGroupBy.Entity.value) + elif value.lower() == "time": + types.append(TableGroupBy.Time.value) + else: + raise ValueError(f"Unknown TableGroupBy kind: {value}") + else: + raise ValueError(f"Unknown TableGroupBy kind: {value}") + + buffers = [ + None, + pa.array(types, type=pa.int8()).buffers()[1], + ] + children = (1 + 2) * [pa.nulls(len(data))] + + return pa.UnionArray.from_buffers( + type=data_type, + length=len(data), + buffers=buffers, + children=children, + )