From c9ce90a6cf29aa2376df9606c1f71ed0b9d647f6 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Fri, 12 Jul 2024 10:43:08 +0200 Subject: [PATCH 01/17] First proto for range table, enabled visible time range in selection panel --- Cargo.lock | 1 + crates/viewer/re_selection_panel/Cargo.toml | 1 + .../src/visible_time_range_ui.rs | 2 + .../src/space_view_class.rs | 482 +++++++++++++----- .../re_viewer_context/src/query_range.rs | 10 + 5 files changed, 364 insertions(+), 132 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a009d59d4387..691660e72c0b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4829,6 +4829,7 @@ dependencies = [ "re_log_types", "re_query", "re_space_view", + "re_space_view_dataframe", "re_space_view_spatial", "re_space_view_time_series", "re_tracing", diff --git a/crates/viewer/re_selection_panel/Cargo.toml b/crates/viewer/re_selection_panel/Cargo.toml index 4c6ddfba6474..2e7d11d249d4 100644 --- a/crates/viewer/re_selection_panel/Cargo.toml +++ b/crates/viewer/re_selection_panel/Cargo.toml @@ -27,6 +27,7 @@ re_entity_db.workspace = true re_log_types.workspace = true re_log.workspace = true re_query.workspace = true +re_space_view_dataframe.workspace = true re_space_view_spatial.workspace = true re_space_view_time_series.workspace = true re_space_view.workspace = true diff --git a/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs b/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs index c95d42bb7ab4..86b701cd01f1 100644 --- a/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs +++ b/crates/viewer/re_selection_panel/src/visible_time_range_ui.rs @@ -5,6 +5,7 @@ use egui::{NumExt as _, Response, Ui}; use re_entity_db::TimeHistogram; use re_log_types::{EntityPath, ResolvedTimeRange, TimeType, TimeZone, TimelineName}; +use re_space_view_dataframe::DataframeSpaceView; use re_space_view_spatial::{SpatialSpaceView2D, SpatialSpaceView3D}; use re_space_view_time_series::TimeSeriesSpaceView; use re_types::{ @@ -24,6 +25,7 @@ static VISIBLE_HISTORY_SUPPORTED_SPACE_VIEWS: once_cell::sync::Lazy< SpatialSpaceView3D::identifier(), SpatialSpaceView2D::identifier(), TimeSeriesSpaceView::identifier(), + DataframeSpaceView::identifier(), ] .map(Into::into) .into() 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 aa86130bf69d..5f22b9b01837 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,15 +1,15 @@ -use std::collections::BTreeSet; +use egui_extras::{Column, TableRow}; +use std::collections::{BTreeMap, BTreeSet}; -use egui_extras::Column; - -use re_chunk_store::{ChunkStore, LatestAtQuery}; -use re_data_ui::item_ui::instance_path_button; +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, Timeline}; -use re_types_core::SpaceViewClassIdentifier; +use re_log_types::{EntityPath, Instance, ResolvedTimeRange, Timeline}; +use re_types_core::datatypes::TimeRange; +use re_types_core::{ComponentName, SpaceViewClassIdentifier}; use re_viewer_context::{ - SpaceViewClass, SpaceViewClassRegistryError, SpaceViewState, SpaceViewSystemExecutionError, - SystemExecutionOutput, UiLayout, ViewQuery, ViewerContext, + QueryRange, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewState, + SpaceViewSystemExecutionError, SystemExecutionOutput, UiLayout, ViewQuery, ViewerContext, }; use crate::visualizer_system::EmptySystem; @@ -27,7 +27,6 @@ impl SpaceViewClass for DataframeSpaceView { } fn icon(&self) -> &'static re_ui::Icon { - //TODO(ab): fix that icon &re_ui::icons::SPACE_VIEW_DATAFRAME } @@ -69,153 +68,372 @@ impl SpaceViewClass for DataframeSpaceView { ctx: &ViewerContext<'_>, ui: &mut egui::Ui, _state: &mut dyn SpaceViewState, - query: &ViewQuery<'_>, _system_output: SystemExecutionOutput, ) -> Result<(), SpaceViewSystemExecutionError> { re_tracing::profile_function!(); - // These are the entity paths whose content we must display. - let sorted_entity_paths: BTreeSet<_> = query + // 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() - .filter(|data_result| data_result.is_visible(ctx)) - .map(|data_result| &data_result.entity_path) - .cloned() - .collect(); + .any(|data_result| data_result.property_overrides.query_range.is_time_range()); - let latest_at_query = query.latest_at_query(); - - let sorted_instance_paths: Vec<_>; - let sorted_components: BTreeSet<_>; - { - re_tracing::profile_scope!("query"); - - // Produce a sorted list of each entity with all their instance keys. This will be the rows - // of the table. - // - // Important: our semantics here differs from other built-in space views. "Out-of-bound" - // instance keys (aka instance keys from a secondary component that cannot be joined with a - // primary component) are not filtered out. Reasons: - // - Primary/secondary component distinction only makes sense with archetypes, which we - // ignore. TODO(#4466): make archetypes more explicit? - // - This space view is about showing all user data anyways. - // - // Note: this must be a `Vec<_>` because we need random access for `body.rows()`. - sorted_instance_paths = sorted_entity_paths - .iter() - .flat_map(|entity_path| { - sorted_instance_paths_for( - entity_path, - ctx.recording_store(), - &query.timeline, - &latest_at_query, + if is_range_query { + entity_and_time_vs_component_ui(ctx, ui, query) + } else { + entity_and_instance_vs_component_ui(ctx, ui, query) + } + } +} + +/// 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" +/// (i.e. logging multiple times the same entity/component at the same timestamp) and "split +/// logging" (i.e. multiple log calls on the same [entity, time] but with different components) +/// lead to multiple rows. In other words, no joining is done here. +/// +/// Also: +/// - View entities have their query range "forced" to a range query. If set to "latest at", they +/// are converted to Rel(0)-Rel(0). +/// - Only the data logged in the query range is displayed. There is no implicit "latest at" like +/// it's done for regular views. +/// - Static data is always shown. +/// - When both static and non-static data exist for the same entity/component, the non-static data +/// is never shown (as per our data model). +fn entity_and_time_vs_component_ui( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + query: &ViewQuery<'_>, +) -> Result<(), SpaceViewSystemExecutionError> { + re_tracing::profile_function!(); + + // These are the entity paths whose content we must display. + let sorted_entity_paths = sorted_visible_entity_path(ctx, query); + + let sorted_components: BTreeSet<_> = { + re_tracing::profile_scope!("query components"); + + // Produce a sorted list of all components that are present in one or more entities. + // These will be the columns of the table. + sorted_entity_paths + .iter() + .flat_map(|entity_path| { + ctx.recording_store() + .all_components(&query.timeline, entity_path) + .unwrap_or_default() + }) + // TODO(#4466): make showing/hiding indicators components an explicit optional + .filter(|comp| !comp.is_indicator_component()) + .collect() + }; + + // Build the full list of rows, along with the chunk where the data is + let rows_to_chunk = query + .iter_all_data_results() + .filter(|data_result| data_result.is_visible(ctx)) + .flat_map(|data_result| { + let time_range = match &data_result.property_overrides.query_range { + QueryRange::TimeRange(time_range) => time_range.clone(), + QueryRange::LatestAt => TimeRange::AT_CURSOR, + }; + + let resolved_time_range = + ResolvedTimeRange::from_relative_time_range(&time_range, ctx.current_query().at()); + + sorted_components.iter().flat_map(move |component| { + ctx.recording_store() + .range_relevant_chunks( + &RangeQuery::new(query.timeline, resolved_time_range), + &data_result.entity_path, + *component, ) - }) - .collect(); - - // Produce a sorted list of all components that are present in one or more entities. This - // will be the columns of the table. - sorted_components = sorted_entity_paths - .iter() - .flat_map(|entity_path| { - ctx.recording_store() - .all_components(&query.timeline, entity_path) - .unwrap_or_default() - }) - // TODO(#4466): make showing/hiding indicators components an explicit optional - .filter(|comp| !comp.is_indicator_component()) - .collect(); + .into_iter() + .flat_map(move |chunk| { + chunk + .indices(&query.timeline) + .into_iter() + .flat_map(|iter| { + iter.filter(|(time, _)| { + time.is_static() || resolved_time_range.contains(*time) + }) + .map(|(time, row_id)| { + ( + (data_result.entity_path.clone(), time, row_id), + chunk.clone(), + ) + }) + }) + .collect::>() + .into_iter() + }) + }) + }) + .collect::>(); + + let rows = rows_to_chunk.keys().collect::>(); + + // Draw the header row. + let header_ui = |mut row: egui_extras::TableRow<'_, '_>| { + row.col(|ui| { + ui.strong("Entity"); + }); + + row.col(|ui| { + ui.strong("Time"); + }); + + row.col(|ui| { + ui.strong("Row ID"); + }); + + for comp in &sorted_components { + row.col(|ui| { + ui.strong(comp.short_name()); + }); } + }; - // Draw the header row. - let header_ui = |mut row: egui_extras::TableRow<'_, '_>| { + // 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(); + let row_ui = |mut row: egui_extras::TableRow<'_, '_>| { + let row_key = rows[row.index()]; + 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, + None, + entity_path, + ); + }); + + row.col(|ui| { + ui.label( + query + .timeline + .typ() + .format(*time, ctx.app_options.time_zone), + ); + }); + + row.col(|ui| { + row_id_ui(ui, row_id); + }); + + for component_name in &sorted_components { row.col(|ui| { - ui.strong("Entity"); + let content = row_chunk.cell(*row_id, component_name); + + if let Some(content) = content { + ctx.component_ui_registry.ui_raw( + ctx, + ui, + UiLayout::List, + &latest_at_query, + ctx.recording(), + &entity_path, + *component_name, + &*content, + ); + } else { + ui.weak("-"); + } }); + } + }; - for comp in &sorted_components { - row.col(|ui| { - ui.strong(comp.short_name()); - }); - } - }; + table_ui(ui, &sorted_components, header_ui, rows.len(), row_ui); + + Ok(()) +} + +fn entity_and_instance_vs_component_ui( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + query: &ViewQuery<'_>, +) -> Result<(), SpaceViewSystemExecutionError> { + re_tracing::profile_function!(); + + // These are the entity paths whose content we must display. + let sorted_entity_paths = sorted_visible_entity_path(ctx, query); + let latest_at_query = query.latest_at_query(); + + let sorted_instance_paths: Vec<_>; + let sorted_components: BTreeSet<_>; + { + re_tracing::profile_scope!("query"); + + // Produce a sorted list of each entity with all their instance keys. This will be the rows + // of the table. + // + // Important: our semantics here differs from other built-in space views. "Out-of-bound" + // instance keys (aka instance keys from a secondary component that cannot be joined with a + // primary component) are not filtered out. Reasons: + // - Primary/secondary component distinction only makes sense with archetypes, which we + // ignore. TODO(#4466): make archetypes more explicit? + // - This space view is about showing all user data anyways. + // + // Note: this must be a `Vec<_>` because we need random access for `body.rows()`. + sorted_instance_paths = sorted_entity_paths + .iter() + .flat_map(|entity_path| { + sorted_instance_paths_for( + entity_path, + ctx.recording_store(), + &query.timeline, + &latest_at_query, + ) + }) + .collect(); - // 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 row_ui = |mut row: egui_extras::TableRow<'_, '_>| { - let instance = &sorted_instance_paths[row.index()]; + // Produce a sorted list of all components that are present in one or more entities. This + // will be the columns of the table. + sorted_components = sorted_entity_paths + .iter() + .flat_map(|entity_path| { + ctx.recording_store() + .all_components(&query.timeline, entity_path) + .unwrap_or_default() + }) + // TODO(#4466): make showing/hiding indicators components an explicit optional + .filter(|comp| !comp.is_indicator_component()) + .collect(); + } + // Draw the header row. + let header_ui = |mut row: egui_extras::TableRow<'_, '_>| { + row.col(|ui| { + ui.strong("Entity"); + }); + + for comp in &sorted_components { row.col(|ui| { - instance_path_button(ctx, &latest_at_query, ctx.recording(), ui, None, instance); + ui.strong(comp.short_name()); }); + } + }; + + // 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 row_ui = |mut row: egui_extras::TableRow<'_, '_>| { + let instance = &sorted_instance_paths[row.index()]; + + row.col(|ui| { + instance_path_button(ctx, &latest_at_query, ctx.recording(), ui, None, instance); + }); + + for component_name in &sorted_components { + row.col(|ui| { + let results = ctx.recording().query_caches().latest_at( + ctx.recording_store(), + &latest_at_query, + &instance.entity_path, + [*component_name], + ); - for component_name in &sorted_components { - row.col(|ui| { - let results = ctx.recording().query_caches().latest_at( - ctx.recording_store(), + if let Some(results) = + // This is a duplicate of the one above, but this ok since this codes runs + // *only* for visible rows. + results.components.get(component_name) + { + ctx.component_ui_registry.ui( + ctx, + ui, + UiLayout::List, &latest_at_query, + ctx.recording(), &instance.entity_path, - [*component_name], + results, + &instance.instance, ); + } else { + ui.weak("-"); + } + }); + } + }; + + table_ui( + ui, + &sorted_components, + header_ui, + sorted_instance_paths.len(), + row_ui, + ); + + Ok(()) +} + +// ------------------------------------------------------------------------------------------------- +// Utilities + +fn table_ui( + ui: &mut egui::Ui, + sorted_components: &BTreeSet, + header_ui: impl FnOnce(egui_extras::TableRow<'_, '_>), + row_count: usize, + row_ui: impl FnMut(TableRow<'_, '_>), +) { + re_tracing::profile_function!(); + + egui::ScrollArea::horizontal() + .auto_shrink([false, false]) + .show(ui, |ui| { + ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend); - if let Some(results) = - // This is a duplicate of the one above, but this ok since this codes runs - // *only* for visible rows. - results.components.get(component_name) - { - ctx.component_ui_registry.ui( - ctx, - ui, - UiLayout::List, - &latest_at_query, - ctx.recording(), - &instance.entity_path, - results, - &instance.instance, - ); - } else { - ui.weak("-"); - } - }); + egui::Frame { + inner_margin: egui::Margin::same(5.0), + ..Default::default() } - }; - - { - re_tracing::profile_scope!("table UI"); - - egui::ScrollArea::both() - .auto_shrink([false, false]) - .show(ui, |ui| { - ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend); - - egui::Frame { - inner_margin: egui::Margin::same(5.0), - ..Default::default() - } - .show(ui, |ui| { - egui_extras::TableBuilder::new(ui) - .columns( - Column::auto_with_initial_suggestion(200.0).clip(true), - 1 + sorted_components.len(), - ) - .resizable(true) - .vscroll(false) - .auto_shrink([false, true]) - .striped(true) - .header(re_ui::DesignTokens::table_line_height(), header_ui) - .body(|body| { - body.rows( - re_ui::DesignTokens::table_line_height(), - sorted_instance_paths.len(), - row_ui, - ); - }); + .show(ui, |ui| { + egui_extras::TableBuilder::new(ui) + .columns( + Column::auto_with_initial_suggestion(200.0).clip(true), + 3 + sorted_components.len(), + ) + .resizable(true) + .vscroll(true) + //TODO(ab): remove when https://github.com/emilk/egui/pull/4817 is merged + .max_scroll_height(f32::INFINITY) + .auto_shrink([false, false]) + .striped(true) + .header(re_ui::DesignTokens::table_line_height(), header_ui) + .body(|body| { + body.rows(re_ui::DesignTokens::table_line_height(), row_count, row_ui); }); - }); - } + }); + }); +} - Ok(()) - } +fn row_id_ui(ui: &mut egui::Ui, row_id: &RowId) { + let s = row_id.to_string(); + let split_pos = s.char_indices().nth_back(5); + + ui.label(match split_pos { + Some((pos, _)) => &s[pos..], + None => &s, + }) + .on_hover_text(s); +} + +/// Returns a sorted list of all entities that are visible in the view. +//TODO(ab): move to ViewQuery? +fn sorted_visible_entity_path( + ctx: &ViewerContext<'_>, + query: &ViewQuery<'_>, +) -> BTreeSet { + query + .iter_all_data_results() + .filter(|data_result| data_result.is_visible(ctx)) + .map(|data_result| &data_result.entity_path) + .cloned() + .collect() } /// Returns a sorted, deduplicated iterator of all instance paths for a given entity. diff --git a/crates/viewer/re_viewer_context/src/query_range.rs b/crates/viewer/re_viewer_context/src/query_range.rs index 2fcc1c89b7d3..67b15cf312e9 100644 --- a/crates/viewer/re_viewer_context/src/query_range.rs +++ b/crates/viewer/re_viewer_context/src/query_range.rs @@ -8,3 +8,13 @@ pub enum QueryRange { #[default] LatestAt, } + +impl QueryRange { + pub fn is_latest_at(&self) -> bool { + matches!(self, QueryRange::LatestAt) + } + + pub fn is_time_range(&self) -> bool { + matches!(self, QueryRange::TimeRange(_)) + } +} From e76582a9c8d08b578924d13743b8f0d8ad2dcd19 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Fri, 12 Jul 2024 11:13:39 +0200 Subject: [PATCH 02/17] Link to _view_ entities (not data store entities) --- .../re_space_view_dataframe/src/space_view_class.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) 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 5f22b9b01837..427ad5955fad 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 @@ -208,7 +208,7 @@ fn entity_and_time_vs_component_ui( &latest_at_query, ctx.recording(), ui, - None, + Some(query.space_view_id), entity_path, ); }); @@ -325,7 +325,14 @@ fn entity_and_instance_vs_component_ui( let instance = &sorted_instance_paths[row.index()]; row.col(|ui| { - instance_path_button(ctx, &latest_at_query, ctx.recording(), ui, None, instance); + instance_path_button( + ctx, + &latest_at_query, + ctx.recording(), + ui, + Some(query.space_view_id), + instance, + ); }); for component_name in &sorted_components { @@ -338,7 +345,7 @@ fn entity_and_instance_vs_component_ui( ); if let Some(results) = - // This is a duplicate of the one above, but this ok since this codes runs + // This is a duplicate of the one above, but this is ok since this codes runs // *only* for visible rows. results.components.get(component_name) { From c66c84f2340eaebb85c0da9d7e566f3f321bc718 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Fri, 12 Jul 2024 15:25:13 +0200 Subject: [PATCH 03/17] Add view properties to choose group by (entity or time) and sort order (asc vs desc) --- Cargo.lock | 3 + .../re_types/definitions/rerun/blueprint.fbs | 3 + .../archetypes/range_table_settings.fbs | 23 ++ .../rerun/blueprint/components/sort_order.fbs | 20 ++ .../blueprint/components/table_group_by.fbs | 20 ++ .../src/blueprint/archetypes/.gitattributes | 1 + .../re_types/src/blueprint/archetypes/mod.rs | 2 + .../blueprint/archetypes/table_row_order.rs | 201 ++++++++++++++++++ .../src/blueprint/components/.gitattributes | 2 + .../re_types/src/blueprint/components/mod.rs | 4 + .../src/blueprint/components/sort_order.rs | 163 ++++++++++++++ .../blueprint/components/table_group_by.rs | 163 ++++++++++++++ crates/viewer/re_edit_ui/src/lib.rs | 6 +- .../viewer/re_space_view_dataframe/Cargo.toml | 3 + .../src/space_view_class.rs | 132 +++++++++--- .../src/blueprint/validation_gen/mod.rs | 4 + crates/viewer/re_viewer/src/reflection/mod.rs | 30 +++ rerun_cpp/src/rerun/blueprint/archetypes.hpp | 1 + .../rerun/blueprint/archetypes/.gitattributes | 2 + .../blueprint/archetypes/table_row_order.cpp | 38 ++++ .../blueprint/archetypes/table_row_order.hpp | 69 ++++++ rerun_cpp/src/rerun/blueprint/components.hpp | 2 + .../rerun/blueprint/components/.gitattributes | 4 + .../rerun/blueprint/components/sort_order.cpp | 62 ++++++ .../rerun/blueprint/components/sort_order.hpp | 52 +++++ .../blueprint/components/table_group_by.cpp | 64 ++++++ .../blueprint/components/table_group_by.hpp | 52 +++++ .../rerun/blueprint/archetypes/.gitattributes | 1 + .../rerun/blueprint/archetypes/__init__.py | 2 + .../blueprint/archetypes/table_row_order.py | 82 +++++++ .../rerun/blueprint/components/.gitattributes | 2 + .../rerun/blueprint/components/__init__.py | 12 ++ .../rerun/blueprint/components/sort_order.py | 93 ++++++++ .../blueprint/components/table_group_by.py | 93 ++++++++ 34 files changed, 1374 insertions(+), 37 deletions(-) create mode 100644 crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_settings.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/sort_order.fbs create mode 100644 crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs create mode 100644 crates/store/re_types/src/blueprint/archetypes/table_row_order.rs create mode 100644 crates/store/re_types/src/blueprint/components/sort_order.rs create mode 100644 crates/store/re_types/src/blueprint/components/table_group_by.rs create mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/sort_order.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/sort_order.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/table_group_by.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/table_group_by.hpp create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/archetypes/table_row_order.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/sort_order.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/table_group_by.py diff --git a/Cargo.lock b/Cargo.lock index 691660e72c0b..4db0cc9fa650 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4903,10 +4903,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 d6ddcb840da7..63055f1639f1 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 000000000000..abc3ccbec5fd --- /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 000000000000..94e2310f79cc --- /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 000000000000..e0a1eb76e981 --- /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 6501c56053ed..91ddfedffbf6 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 c1ae16766e61..2a38af4fdc26 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 000000000000..b88418a6d384 --- /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 6a9874206ded..249397ddf0c7 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 3389f6f39b39..06ecd4230c45 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 000000000000..b81f37a2dc76 --- /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 000000000000..68233f10a75b --- /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 af4efaf8b46e..2f42e654a776 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 483c6804cf68..a6ff38a428fb 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 427ad5955fad..27253e00bead 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 f7eb9218a025..3b285ea98be6 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 234bc7889215..09baec388123 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 8dfd7175e565..03f21ca4bdff 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 c941889168aa..b190995becbc 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 000000000000..09492f06d985 --- /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 000000000000..891176bc18d2 --- /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 45e6beaf7803..6d72c740fbf2 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 11d00c3d1875..1afaab8ac7bc 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 000000000000..b1a4ec0e5814 --- /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 000000000000..a292ab9bd19a --- /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 000000000000..6cf091ead3ce --- /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 000000000000..580ac1cc04d0 --- /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 ac20f8caae1f..e9b7ed7aca7c 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 3af18008eb45..7e0f853a0515 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 000000000000..12b301bd09ac --- /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 e232a7f04c35..93184d1eccce 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 10f98717719d..3307a07114ed 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 000000000000..70c932379614 --- /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 000000000000..1136d14a3bce --- /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, + ) From 01615d73f05d8f393db7f99f69c4b5c7dc547f90 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Fri, 12 Jul 2024 17:56:28 +0200 Subject: [PATCH 04/17] Fix after rebase --- .../viewer/re_space_view_dataframe/src/space_view_class.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 27253e00bead..7679cd997640 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 @@ -6,7 +6,7 @@ use re_data_ui::item_ui::{entity_path_button, instance_path_button}; use re_entity_db::InstancePath; 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::archetypes::TableRowOrder; use re_types::blueprint::components::{SortOrder, TableGroupBy}; use re_types_core::datatypes::TimeRange; use re_types_core::{ComponentName, SpaceViewClassIdentifier}; @@ -182,7 +182,8 @@ fn entity_and_time_vs_component_ui( .into_iter() .flat_map(move |chunk| { chunk - .indices(&query.timeline) + .clone() + .iter_indices(&query.timeline) .into_iter() .flat_map(|iter| { iter.filter(|(time, _)| { @@ -195,6 +196,7 @@ fn entity_and_time_vs_component_ui( ) }) }) + //TODO(ab): cmc help!? .collect::>() .into_iter() }) From 907263784bb7f303c62e108c992c3f419ae12127 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Fri, 12 Jul 2024 18:39:25 +0200 Subject: [PATCH 05/17] Avoid intermediate allocation in the row iterator --- .../src/space_view_class.rs | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) 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 7679cd997640..9e0010c9987c 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 @@ -180,25 +180,21 @@ fn entity_and_time_vs_component_ui( *component, ) .into_iter() - .flat_map(move |chunk| { + .filter_map(|chunk| { chunk .clone() .iter_indices(&query.timeline) - .into_iter() - .flat_map(|iter| { - iter.filter(|(time, _)| { - time.is_static() || resolved_time_range.contains(*time) - }) - .map(|(time, row_id)| { - ( - (data_result.entity_path.clone(), time, row_id), - chunk.clone(), - ) - }) + .map(|iter_indices| (iter_indices, chunk)) + }) + .flat_map(move |(indices_iter, chunk)| { + indices_iter + .filter(move |(time, _)| { + time.is_static() || resolved_time_range.contains(*time) + }) + .map(move |(time, row_id)| { + let chunk = chunk.clone(); + ((data_result.entity_path.clone(), time, row_id), chunk) }) - //TODO(ab): cmc help!? - .collect::>() - .into_iter() }) }) }) @@ -267,8 +263,7 @@ fn entity_and_time_vs_component_ui( ); }; - // Draw a single line of the table. This is called for each _visible_ row, so it's ok to - // duplicate some of the querying. + // Draw a single line of the table. This is called for each _visible_ row. let latest_at_query = query.latest_at_query(); let row_ui = |mut row: egui_extras::TableRow<'_, '_>| { let row_key = rows[row.index()]; From 2c95e88694030658037ba6ebd37e2297719271d7 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Fri, 12 Jul 2024 22:00:19 +0200 Subject: [PATCH 06/17] Clean up --- .../src/space_view_class.rs | 144 ++++++++++++------ .../re_viewer_context/src/query_range.rs | 4 +- 2 files changed, 101 insertions(+), 47 deletions(-) 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 9e0010c9987c..ac25741a0b73 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,7 +1,7 @@ use crate::visualizer_system::EmptySystem; use egui::Ui; use egui_extras::{Column, TableRow}; -use re_chunk_store::{ChunkStore, LatestAtQuery, RangeQuery, RowId}; +use re_chunk_store::{Chunk, 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, TimeInt, Timeline}; @@ -17,6 +17,7 @@ use re_viewer_context::{ }; use re_viewport_blueprint::ViewProperty; use std::collections::{BTreeMap, BTreeSet}; +use std::sync::Arc; #[derive(Default)] pub struct DataframeSpaceView; @@ -106,10 +107,12 @@ impl SpaceViewClass for DataframeSpaceView { .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, group_by, sort_order) + entity_and_time_vs_component_ui(ctx, ui, query, group_by, sort_order); } else { - entity_and_instance_vs_component_ui(ctx, ui, query) + entity_and_instance_vs_component_ui(ctx, ui, query); } + + Ok(()) } } @@ -117,7 +120,7 @@ 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" +/// Here, a "row" is a tuple of `(entity_path, time, row_id)`. This means that both "over logging" /// (i.e. logging multiple times the same entity/component at the same timestamp) and "split /// logging" (i.e. multiple log calls on the same [entity, time] but with different components) /// lead to multiple rows. In other words, no joining is done here. @@ -130,28 +133,32 @@ re_viewer_context::impl_component_fallback_provider!(DataframeSpaceView => []); /// - Static data is always shown. /// - When both static and non-static data exist for the same entity/component, the non-static data /// is never shown (as per our data model). + 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!(); - // These are the entity paths whose content we must display. - let sorted_entity_paths = sorted_visible_entity_path(ctx, query); + // + // Produce a sorted list of all components we are interested id. + // + // TODO(ab): add support for filtering components more narrowly. let sorted_components: BTreeSet<_> = { re_tracing::profile_scope!("query components"); // Produce a sorted list of all components that are present in one or more entities. // These will be the columns of the table. - sorted_entity_paths - .iter() - .flat_map(|entity_path| { + query + .iter_all_data_results() + .filter(|data_result| data_result.is_visible(ctx)) + .flat_map(|data_result| { ctx.recording_store() - .all_components(&query.timeline, entity_path) + .all_components(&query.timeline, &data_result.entity_path) .unwrap_or_default() }) // TODO(#4466): make showing/hiding indicators components an explicit optional @@ -159,7 +166,66 @@ fn entity_and_time_vs_component_ui( .collect() }; - // Build the full list of rows, along with the chunk where the data is + // + // Build the full list of rows, along with the chunk where the data is. Rows are keyed by an + // (entity, time, row_id) tuple (see function docstring). These keys are mapped to the + // corresponding chunk that contains the actual data. + // + // We build a big, monolithic iterator for all the rows. The following code builds that by + // breaking it into several functions for sanity purpose, from innermost to outermost. + // + + type RowKey = (EntityPath, TimeInt, RowId); + + #[inline] + fn map_chunk_indices_to_key_value_iter<'a>( + indices_iter: impl Iterator + 'a, + chunk: Arc, + entity_path: EntityPath, + resolved_time_range: ResolvedTimeRange, + ) -> impl Iterator)> + 'a { + indices_iter + .filter(move |(time, _)| time.is_static() || resolved_time_range.contains(*time)) + .map(move |(time, row_id)| { + let chunk = chunk.clone(); + ((entity_path.clone(), time, row_id), chunk) + }) + } + + #[inline] + fn entity_components_to_key_value_iter<'a>( + ctx: &ViewerContext<'_>, + entity_path: &'a EntityPath, + component: &'a ComponentName, + timeline: Timeline, + resolved_time_range: ResolvedTimeRange, + ) -> impl Iterator)> + 'a { + let range_query = RangeQuery::new(timeline, resolved_time_range); + + ctx.recording_store() + .range_relevant_chunks(&range_query, entity_path, *component) + .into_iter() + // This does two things: + // 1) Filter out instances where `chunk.iter_indices()` returns `None`. + // 2) Exploit the fact that the returned iterator (if any) is *not* bound to the + // lifetime of the chunk (it has an internal Arc). + .filter_map(move |chunk| { + chunk + .clone() + .iter_indices(&timeline) + .map(|iter_indices| (iter_indices, chunk)) + }) + .flat_map(move |(indices_iter, chunk)| { + map_chunk_indices_to_key_value_iter( + indices_iter, + chunk, + entity_path.clone(), + resolved_time_range, + ) + }) + } + + // all the rows! let rows_to_chunk = query .iter_all_data_results() .filter(|data_result| data_result.is_visible(ctx)) @@ -173,33 +239,21 @@ fn entity_and_time_vs_component_ui( ResolvedTimeRange::from_relative_time_range(&time_range, ctx.current_query().at()); sorted_components.iter().flat_map(move |component| { - ctx.recording_store() - .range_relevant_chunks( - &RangeQuery::new(query.timeline, resolved_time_range), - &data_result.entity_path, - *component, - ) - .into_iter() - .filter_map(|chunk| { - chunk - .clone() - .iter_indices(&query.timeline) - .map(|iter_indices| (iter_indices, chunk)) - }) - .flat_map(move |(indices_iter, chunk)| { - indices_iter - .filter(move |(time, _)| { - time.is_static() || resolved_time_range.contains(*time) - }) - .map(move |(time, row_id)| { - let chunk = chunk.clone(); - ((data_result.entity_path.clone(), time, row_id), chunk) - }) - }) + entity_components_to_key_value_iter( + ctx, + &data_result.entity_path, + component, + query.timeline, + resolved_time_range, + ) }) }) .collect::>(); + // + // Row sorting/grouping based on view properties. + // + let mut rows = rows_to_chunk.keys().collect::>(); // apply group_by @@ -211,6 +265,10 @@ fn entity_and_time_vs_component_ui( rows.reverse(); } + // + // Drawing code. + // + let entity_header = |ui: &mut egui::Ui| { ui.strong("Entity"); }; @@ -267,7 +325,7 @@ fn entity_and_time_vs_component_ui( let latest_at_query = query.latest_at_query(); let row_ui = |mut row: egui_extras::TableRow<'_, '_>| { let row_key = rows[row.index()]; - let row_chunk = rows_to_chunk.get(row_key).unwrap(); + let row_chunk = &rows_to_chunk[row_key]; let (entity_path, time, row_id) = row_key; match group_by { @@ -296,7 +354,7 @@ fn entity_and_time_vs_component_ui( UiLayout::List, &latest_at_query, ctx.recording(), - &entity_path, + entity_path, *component_name, &*content, ); @@ -308,15 +366,13 @@ fn entity_and_time_vs_component_ui( }; table_ui(ui, &sorted_components, header_ui, rows.len(), row_ui); - - Ok(()) } fn entity_and_instance_vs_component_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, query: &ViewQuery<'_>, -) -> Result<(), SpaceViewSystemExecutionError> { +) { re_tracing::profile_function!(); // These are the entity paths whose content we must display. @@ -351,7 +407,7 @@ fn entity_and_instance_vs_component_ui( }) .collect(); - // Produce a sorted list of all components that are present in one or more entities. This + // Produce a sorted list of all components that are present in one or more entities. These // will be the columns of the table. sorted_components = sorted_entity_paths .iter() @@ -432,13 +488,12 @@ fn entity_and_instance_vs_component_ui( sorted_instance_paths.len(), row_ui, ); - - Ok(()) } // ------------------------------------------------------------------------------------------------- // Utilities +/// Display a nicely configured table with the provided header ui, row ui, and row count. fn table_ui( ui: &mut egui::Ui, sorted_components: &BTreeSet, @@ -465,7 +520,7 @@ fn table_ui( ) .resizable(true) .vscroll(true) - //TODO(ab): remove when https://github.com/emilk/egui/pull/4817 is merged + //TODO(ab): remove when https://github.com/emilk/egui/pull/4817 is merged/released .max_scroll_height(f32::INFINITY) .auto_shrink([false, false]) .striped(true) @@ -489,7 +544,6 @@ fn row_id_ui(ui: &mut egui::Ui, row_id: &RowId) { } /// Returns a sorted list of all entities that are visible in the view. -//TODO(ab): move to ViewQuery? fn sorted_visible_entity_path( ctx: &ViewerContext<'_>, query: &ViewQuery<'_>, diff --git a/crates/viewer/re_viewer_context/src/query_range.rs b/crates/viewer/re_viewer_context/src/query_range.rs index 67b15cf312e9..6db79b699ec7 100644 --- a/crates/viewer/re_viewer_context/src/query_range.rs +++ b/crates/viewer/re_viewer_context/src/query_range.rs @@ -11,10 +11,10 @@ pub enum QueryRange { impl QueryRange { pub fn is_latest_at(&self) -> bool { - matches!(self, QueryRange::LatestAt) + matches!(self, Self::LatestAt) } pub fn is_time_range(&self) -> bool { - matches!(self, QueryRange::TimeRange(_)) + matches!(self, Self::TimeRange(_)) } } From ba0cb75c1615b9a1863f9c199574bcb0760f4fc2 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 15 Jul 2024 09:13:26 +0200 Subject: [PATCH 07/17] Update help markdown --- .../src/space_view_class.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) 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 36ffd8d31f71..17bfc5cfdfeb 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 @@ -38,7 +38,23 @@ impl SpaceViewClass for DataframeSpaceView { fn help_markdown(&self, _egui_ctx: &egui::Context) -> String { "# Dataframe view -Show the data contained in entities in a table. Each entity is represented by as many rows as it has instances." +This view displays the content of the entities it contains in tabular form. Click on the view and +use the _Entity path filter_ to control which entities are displayed. + +## View types + +The Dataframe view operates in two modes: the _latest at_ mode and the _time range_ mode. + +In the _latest at_ mode, the view displays the latest data for the timeline and time set in the time +panel. A row is shown for each entity instance. + +The _time range_ mode, the view displays all the data logged within the time range set for each +view entity. In this mode, each row corresponds to an entity and time pair. Rows are further split +if multiple `rr.log()` calls were made for the same entity/time. Static data is also displayed. + +The view switches to _time range_ mode as soon as a single one of its entities has its visible time +range set to _Override_. Each entity may have its own time range setting. (To set the same time range +for all entities, it is preferable to override the view-level visible time range at the view.)" .to_owned() } From 6dfb3e08dc37c878eb9aa6477d2a6caac2ef63d5 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 15 Jul 2024 09:56:49 +0200 Subject: [PATCH 08/17] Split into multiple files + cleanup --- .../src/latest_at_table.rs | 135 +++++ .../viewer/re_space_view_dataframe/src/lib.rs | 4 + .../src/space_view_class.rs | 521 ++---------------- .../re_space_view_dataframe/src/table_ui.rs | 56 ++ .../src/time_range_table.rs | 262 +++++++++ .../re_space_view_dataframe/src/utils.rs | 53 ++ 6 files changed, 545 insertions(+), 486 deletions(-) create mode 100644 crates/viewer/re_space_view_dataframe/src/latest_at_table.rs create mode 100644 crates/viewer/re_space_view_dataframe/src/table_ui.rs create mode 100644 crates/viewer/re_space_view_dataframe/src/time_range_table.rs create mode 100644 crates/viewer/re_space_view_dataframe/src/utils.rs diff --git a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs new file mode 100644 index 000000000000..991299c9bd89 --- /dev/null +++ b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs @@ -0,0 +1,135 @@ +use std::collections::BTreeSet; + +use re_data_ui::item_ui::instance_path_button; +use re_viewer_context::{UiLayout, ViewQuery, ViewerContext}; + +use crate::{ + table_ui::table_ui, + utils::{sorted_instance_paths_for, sorted_visible_entity_path}, +}; + +/// Display a "latest at" table. +/// +/// This table has entity instances as rows and components as column. That data is the result of a +/// "latest at" query based on the current timeline and time. +pub(crate) fn latest_at_table_ui( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + query: &ViewQuery<'_>, +) { + re_tracing::profile_function!(); + + // These are the entity paths whose content we must display. + let sorted_entity_paths = sorted_visible_entity_path(ctx, query); + let latest_at_query = query.latest_at_query(); + + let sorted_instance_paths: Vec<_>; + let sorted_components: BTreeSet<_>; + { + re_tracing::profile_scope!("query"); + + // Produce a sorted list of each entity with all their instance keys. This will be the rows + // of the table. + // + // Important: our semantics here differs from other built-in space views. "Out-of-bound" + // instance keys (aka instance keys from a secondary component that cannot be joined with a + // primary component) are not filtered out. Reasons: + // - Primary/secondary component distinction only makes sense with archetypes, which we + // ignore. TODO(#4466): make archetypes more explicit? + // - This space view is about showing all user data anyways. + // + // Note: this must be a `Vec<_>` because we need random access for `body.rows()`. + sorted_instance_paths = sorted_entity_paths + .iter() + .flat_map(|entity_path| { + sorted_instance_paths_for( + entity_path, + ctx.recording_store(), + &query.timeline, + &latest_at_query, + ) + }) + .collect(); + + // Produce a sorted list of all components that are present in one or more entities. These + // will be the columns of the table. + sorted_components = sorted_entity_paths + .iter() + .flat_map(|entity_path| { + ctx.recording_store() + .all_components(&query.timeline, entity_path) + .unwrap_or_default() + }) + // TODO(#4466): make showing/hiding indicators components an explicit optional + .filter(|comp| !comp.is_indicator_component()) + .collect(); + } + + // Draw the header row. + let header_ui = |mut row: egui_extras::TableRow<'_, '_>| { + row.col(|ui| { + ui.strong("Entity"); + }); + + for comp in &sorted_components { + row.col(|ui| { + ui.strong(comp.short_name()); + }); + } + }; + + // 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 row_ui = |mut row: egui_extras::TableRow<'_, '_>| { + let instance = &sorted_instance_paths[row.index()]; + + row.col(|ui| { + instance_path_button( + ctx, + &latest_at_query, + ctx.recording(), + ui, + Some(query.space_view_id), + instance, + ); + }); + + for component_name in &sorted_components { + row.col(|ui| { + let results = ctx.recording().query_caches().latest_at( + ctx.recording_store(), + &latest_at_query, + &instance.entity_path, + [*component_name], + ); + + if let Some(results) = + // This is a duplicate of the one above, but this is ok since this codes runs + // *only* for visible rows. + results.components.get(component_name) + { + ctx.component_ui_registry.ui( + ctx, + ui, + UiLayout::List, + &latest_at_query, + ctx.recording(), + &instance.entity_path, + results, + &instance.instance, + ); + } else { + ui.weak("-"); + } + }); + } + }; + + table_ui( + ui, + &sorted_components, + header_ui, + sorted_instance_paths.len(), + row_ui, + ); +} diff --git a/crates/viewer/re_space_view_dataframe/src/lib.rs b/crates/viewer/re_space_view_dataframe/src/lib.rs index 5798c5b6e90b..b3d8a9436846 100644 --- a/crates/viewer/re_space_view_dataframe/src/lib.rs +++ b/crates/viewer/re_space_view_dataframe/src/lib.rs @@ -2,7 +2,11 @@ //! //! A Space View that shows the data contained in entities in a table. +mod latest_at_table; mod space_view_class; +mod table_ui; +mod time_range_table; +mod utils; mod visualizer_system; pub use space_view_class::DataframeSpaceView; 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 17bfc5cfdfeb..b90b67a40b6a 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,23 +1,23 @@ -use crate::visualizer_system::EmptySystem; use egui::Ui; -use egui_extras::{Column, TableRow}; -use re_chunk_store::{Chunk, 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, TimeInt, Timeline}; + +use re_log_types::EntityPath; use re_space_view::view_property_ui; -use re_types::blueprint::archetypes::TableRowOrder; -use re_types::blueprint::components::{SortOrder, TableGroupBy}; -use re_types_core::datatypes::TimeRange; -use re_types_core::{ComponentName, SpaceViewClassIdentifier}; +use re_types::blueprint::{ + archetypes::TableRowOrder, + components::{SortOrder, TableGroupBy}, +}; +use re_types_core::SpaceViewClassIdentifier; use re_ui::list_item; use re_viewer_context::{ - QueryRange, SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewState, - SpaceViewSystemExecutionError, SystemExecutionOutput, UiLayout, ViewQuery, ViewerContext, + SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewState, + SpaceViewSystemExecutionError, SystemExecutionOutput, ViewQuery, ViewerContext, }; use re_viewport_blueprint::ViewProperty; -use std::collections::{BTreeMap, BTreeSet}; -use std::sync::Arc; + +use crate::{ + latest_at_table::latest_at_table_ui, time_range_table::time_range_table_ui, + visualizer_system::EmptySystem, +}; #[derive(Default)] pub struct DataframeSpaceView; @@ -118,16 +118,12 @@ for all entities, it is preferable to override the view-level visible time range 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()); + let mode = self.table_mode(query); - if is_range_query { - entity_and_time_vs_component_ui(ctx, ui, query, group_by, sort_order); - } else { - entity_and_instance_vs_component_ui(ctx, ui, query); - } + match mode { + TableMode::LatestAtTable => latest_at_table_ui(ctx, ui, query), + TableMode::TimeRangeTable => time_range_table_ui(ctx, ui, query, group_by, sort_order), + }; Ok(()) } @@ -135,472 +131,25 @@ for all entities, it is preferable to override the view-level visible time range 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" -/// (i.e. logging multiple times the same entity/component at the same timestamp) and "split -/// logging" (i.e. multiple log calls on the same [entity, time] but with different components) -/// lead to multiple rows. In other words, no joining is done here. -/// -/// Also: -/// - View entities have their query range "forced" to a range query. If set to "latest at", they -/// are converted to Rel(0)-Rel(0). -/// - Only the data logged in the query range is displayed. There is no implicit "latest at" like -/// it's done for regular views. -/// - Static data is always shown. -/// - When both static and non-static data exist for the same entity/component, the non-static data -/// is never shown (as per our data model). - -fn entity_and_time_vs_component_ui( - ctx: &ViewerContext<'_>, - ui: &mut egui::Ui, - query: &ViewQuery<'_>, - group_by: TableGroupBy, - sort_order: SortOrder, -) { - re_tracing::profile_function!(); - - // - // Produce a sorted list of all components we are interested id. - // - - // TODO(ab): add support for filtering components more narrowly. - let sorted_components: BTreeSet<_> = { - re_tracing::profile_scope!("query components"); +/// The two modes of the dataframe view. +enum TableMode { + LatestAtTable, + TimeRangeTable, +} - // Produce a sorted list of all components that are present in one or more entities. - // These will be the columns of the table. - query +impl DataframeSpaceView { + /// Determine which [`TableMode`] is currently active. + // TODO(ab): we probably want a less "implicit" way to switch from temporal vs. latest at tables. + #[allow(clippy::unused_self)] + fn table_mode(&self, query: &ViewQuery<'_>) -> TableMode { + let is_range_query = query .iter_all_data_results() - .filter(|data_result| data_result.is_visible(ctx)) - .flat_map(|data_result| { - ctx.recording_store() - .all_components(&query.timeline, &data_result.entity_path) - .unwrap_or_default() - }) - // TODO(#4466): make showing/hiding indicators components an explicit optional - .filter(|comp| !comp.is_indicator_component()) - .collect() - }; - - // - // Build the full list of rows, along with the chunk where the data is. Rows are keyed by an - // (entity, time, row_id) tuple (see function docstring). These keys are mapped to the - // corresponding chunk that contains the actual data. - // - // We build a big, monolithic iterator for all the rows. The following code builds that by - // breaking it into several functions for sanity purpose, from innermost to outermost. - // - - type RowKey = (EntityPath, TimeInt, RowId); - - #[inline] - fn map_chunk_indices_to_key_value_iter<'a>( - indices_iter: impl Iterator + 'a, - chunk: Arc, - entity_path: EntityPath, - resolved_time_range: ResolvedTimeRange, - ) -> impl Iterator)> + 'a { - indices_iter - .filter(move |(time, _)| time.is_static() || resolved_time_range.contains(*time)) - .map(move |(time, row_id)| { - let chunk = chunk.clone(); - ((entity_path.clone(), time, row_id), chunk) - }) - } - - #[inline] - fn entity_components_to_key_value_iter<'a>( - ctx: &ViewerContext<'_>, - entity_path: &'a EntityPath, - component: &'a ComponentName, - timeline: Timeline, - resolved_time_range: ResolvedTimeRange, - ) -> impl Iterator)> + 'a { - let range_query = RangeQuery::new(timeline, resolved_time_range); - - ctx.recording_store() - .range_relevant_chunks(&range_query, entity_path, *component) - .into_iter() - // This does two things: - // 1) Filter out instances where `chunk.iter_indices()` returns `None`. - // 2) Exploit the fact that the returned iterator (if any) is *not* bound to the - // lifetime of the chunk (it has an internal Arc). - .filter_map(move |chunk| { - chunk - .clone() - .iter_indices(&timeline) - .map(|iter_indices| (iter_indices, chunk)) - }) - .flat_map(move |(indices_iter, chunk)| { - map_chunk_indices_to_key_value_iter( - indices_iter, - chunk, - entity_path.clone(), - resolved_time_range, - ) - }) - } - - // all the rows! - let rows_to_chunk = query - .iter_all_data_results() - .filter(|data_result| data_result.is_visible(ctx)) - .flat_map(|data_result| { - let time_range = match &data_result.property_overrides.query_range { - QueryRange::TimeRange(time_range) => time_range.clone(), - QueryRange::LatestAt => TimeRange::AT_CURSOR, - }; - - let resolved_time_range = - ResolvedTimeRange::from_relative_time_range(&time_range, ctx.current_query().at()); - - sorted_components.iter().flat_map(move |component| { - entity_components_to_key_value_iter( - ctx, - &data_result.entity_path, - component, - query.timeline, - resolved_time_range, - ) - }) - }) - .collect::>(); - - // - // Row sorting/grouping based on view properties. - // - - 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(); - } - - // - // Drawing code. - // - - 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<'_, '_>| { - 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"); - }); - - for comp in &sorted_components { - row.col(|ui| { - ui.strong(comp.short_name()); - }); - } - }; - - 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. - let latest_at_query = query.latest_at_query(); - let row_ui = |mut row: egui_extras::TableRow<'_, '_>| { - let row_key = rows[row.index()]; - let row_chunk = &rows_to_chunk[row_key]; - let (entity_path, time, row_id) = row_key; - - 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); - }); - - for component_name in &sorted_components { - row.col(|ui| { - let content = row_chunk.cell(*row_id, component_name); + .any(|data_result| data_result.property_overrides.query_range.is_time_range()); - if let Some(content) = content { - ctx.component_ui_registry.ui_raw( - ctx, - ui, - UiLayout::List, - &latest_at_query, - ctx.recording(), - entity_path, - *component_name, - &*content, - ); - } else { - ui.weak("-"); - } - }); + if is_range_query { + TableMode::TimeRangeTable + } else { + TableMode::LatestAtTable } - }; - - table_ui(ui, &sorted_components, header_ui, rows.len(), row_ui); -} - -fn entity_and_instance_vs_component_ui( - ctx: &ViewerContext<'_>, - ui: &mut egui::Ui, - query: &ViewQuery<'_>, -) { - re_tracing::profile_function!(); - - // These are the entity paths whose content we must display. - let sorted_entity_paths = sorted_visible_entity_path(ctx, query); - let latest_at_query = query.latest_at_query(); - - let sorted_instance_paths: Vec<_>; - let sorted_components: BTreeSet<_>; - { - re_tracing::profile_scope!("query"); - - // Produce a sorted list of each entity with all their instance keys. This will be the rows - // of the table. - // - // Important: our semantics here differs from other built-in space views. "Out-of-bound" - // instance keys (aka instance keys from a secondary component that cannot be joined with a - // primary component) are not filtered out. Reasons: - // - Primary/secondary component distinction only makes sense with archetypes, which we - // ignore. TODO(#4466): make archetypes more explicit? - // - This space view is about showing all user data anyways. - // - // Note: this must be a `Vec<_>` because we need random access for `body.rows()`. - sorted_instance_paths = sorted_entity_paths - .iter() - .flat_map(|entity_path| { - sorted_instance_paths_for( - entity_path, - ctx.recording_store(), - &query.timeline, - &latest_at_query, - ) - }) - .collect(); - - // Produce a sorted list of all components that are present in one or more entities. These - // will be the columns of the table. - sorted_components = sorted_entity_paths - .iter() - .flat_map(|entity_path| { - ctx.recording_store() - .all_components(&query.timeline, entity_path) - .unwrap_or_default() - }) - // TODO(#4466): make showing/hiding indicators components an explicit optional - .filter(|comp| !comp.is_indicator_component()) - .collect(); } - - // Draw the header row. - let header_ui = |mut row: egui_extras::TableRow<'_, '_>| { - row.col(|ui| { - ui.strong("Entity"); - }); - - for comp in &sorted_components { - row.col(|ui| { - ui.strong(comp.short_name()); - }); - } - }; - - // 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 row_ui = |mut row: egui_extras::TableRow<'_, '_>| { - let instance = &sorted_instance_paths[row.index()]; - - row.col(|ui| { - instance_path_button( - ctx, - &latest_at_query, - ctx.recording(), - ui, - Some(query.space_view_id), - instance, - ); - }); - - for component_name in &sorted_components { - row.col(|ui| { - let results = ctx.recording().query_caches().latest_at( - ctx.recording_store(), - &latest_at_query, - &instance.entity_path, - [*component_name], - ); - - if let Some(results) = - // This is a duplicate of the one above, but this is ok since this codes runs - // *only* for visible rows. - results.components.get(component_name) - { - ctx.component_ui_registry.ui( - ctx, - ui, - UiLayout::List, - &latest_at_query, - ctx.recording(), - &instance.entity_path, - results, - &instance.instance, - ); - } else { - ui.weak("-"); - } - }); - } - }; - - table_ui( - ui, - &sorted_components, - header_ui, - sorted_instance_paths.len(), - row_ui, - ); -} - -// ------------------------------------------------------------------------------------------------- -// Utilities - -/// Display a nicely configured table with the provided header ui, row ui, and row count. -fn table_ui( - ui: &mut egui::Ui, - sorted_components: &BTreeSet, - header_ui: impl FnOnce(egui_extras::TableRow<'_, '_>), - row_count: usize, - row_ui: impl FnMut(TableRow<'_, '_>), -) { - re_tracing::profile_function!(); - - egui::ScrollArea::horizontal() - .auto_shrink([false, false]) - .show(ui, |ui| { - ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend); - - egui::Frame { - inner_margin: egui::Margin::same(5.0), - ..Default::default() - } - .show(ui, |ui| { - egui_extras::TableBuilder::new(ui) - .columns( - Column::auto_with_initial_suggestion(200.0).clip(true), - 3 + sorted_components.len(), - ) - .resizable(true) - .vscroll(true) - //TODO(ab): remove when https://github.com/emilk/egui/pull/4817 is merged/released - .max_scroll_height(f32::INFINITY) - .auto_shrink([false, false]) - .striped(true) - .header(re_ui::DesignTokens::table_line_height(), header_ui) - .body(|body| { - body.rows(re_ui::DesignTokens::table_line_height(), row_count, row_ui); - }); - }); - }); -} - -fn row_id_ui(ui: &mut egui::Ui, row_id: &RowId) { - let s = row_id.to_string(); - let split_pos = s.char_indices().nth_back(5); - - ui.label(match split_pos { - Some((pos, _)) => &s[pos..], - None => &s, - }) - .on_hover_text(s); -} - -/// Returns a sorted list of all entities that are visible in the view. -fn sorted_visible_entity_path( - ctx: &ViewerContext<'_>, - query: &ViewQuery<'_>, -) -> BTreeSet { - query - .iter_all_data_results() - .filter(|data_result| data_result.is_visible(ctx)) - .map(|data_result| &data_result.entity_path) - .cloned() - .collect() -} - -/// Returns a sorted, deduplicated iterator of all instance paths for a given entity. -fn sorted_instance_paths_for<'a>( - entity_path: &'a EntityPath, - store: &'a ChunkStore, - timeline: &'a Timeline, - latest_at_query: &'a LatestAtQuery, -) -> impl Iterator + 'a { - store - .all_components(timeline, entity_path) - .unwrap_or_default() - .into_iter() - .filter(|component_name| !component_name.is_indicator_component()) - .flat_map(|component_name| { - let num_instances = store - .latest_at_relevant_chunks(latest_at_query, entity_path, component_name) - .into_iter() - .filter_map(|chunk| { - let (data_time, row_id, batch) = chunk - .latest_at(latest_at_query, component_name) - .iter_rows(timeline, &component_name) - .next()?; - batch.map(|batch| (data_time, row_id, batch)) - }) - .max_by_key(|(data_time, row_id, _)| (*data_time, *row_id)) - .map_or(0, |(_, _, batch)| batch.len()); - (0..num_instances).map(|i| Instance::from(i as u64)) - }) - .collect::>() // dedup and sort - .into_iter() - .map(|instance| InstancePath::instance(entity_path.clone(), instance)) } diff --git a/crates/viewer/re_space_view_dataframe/src/table_ui.rs b/crates/viewer/re_space_view_dataframe/src/table_ui.rs new file mode 100644 index 000000000000..e92b51655bb6 --- /dev/null +++ b/crates/viewer/re_space_view_dataframe/src/table_ui.rs @@ -0,0 +1,56 @@ +use std::collections::BTreeSet; + +use egui_extras::{Column, TableRow}; + +use re_chunk_store::RowId; +use re_types_core::ComponentName; + +/// Display a nicely configured table with the provided header ui, row ui, and row count. +pub(crate) fn table_ui( + ui: &mut egui::Ui, + sorted_components: &BTreeSet, + header_ui: impl FnOnce(egui_extras::TableRow<'_, '_>), + row_count: usize, + row_ui: impl FnMut(TableRow<'_, '_>), +) { + re_tracing::profile_function!(); + + egui::ScrollArea::horizontal() + .auto_shrink([false, false]) + .show(ui, |ui| { + ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend); + + egui::Frame { + inner_margin: egui::Margin::same(5.0), + ..Default::default() + } + .show(ui, |ui| { + egui_extras::TableBuilder::new(ui) + .columns( + Column::auto_with_initial_suggestion(200.0).clip(true), + 3 + sorted_components.len(), + ) + .resizable(true) + .vscroll(true) + //TODO(ab): remove when https://github.com/emilk/egui/pull/4817 is merged/released + .max_scroll_height(f32::INFINITY) + .auto_shrink([false, false]) + .striped(true) + .header(re_ui::DesignTokens::table_line_height(), header_ui) + .body(|body| { + body.rows(re_ui::DesignTokens::table_line_height(), row_count, row_ui); + }); + }); + }); +} + +pub(crate) fn row_id_ui(ui: &mut egui::Ui, row_id: &RowId) { + let s = row_id.to_string(); + let split_pos = s.char_indices().nth_back(5); + + ui.label(match split_pos { + Some((pos, _)) => &s[pos..], + None => &s, + }) + .on_hover_text(s); +} diff --git a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs new file mode 100644 index 000000000000..636995a961da --- /dev/null +++ b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs @@ -0,0 +1,262 @@ +use std::collections::{BTreeMap, BTreeSet}; +use std::sync::Arc; + +use re_chunk_store::{Chunk, RangeQuery, RowId}; +use re_data_ui::item_ui::entity_path_button; +use re_log_types::{EntityPath, ResolvedTimeRange, TimeInt, Timeline}; +use re_types::blueprint::components::{SortOrder, TableGroupBy}; +use re_types_core::datatypes::TimeRange; +use re_types_core::ComponentName; +use re_viewer_context::{QueryRange, UiLayout, ViewQuery, ViewerContext}; + +use crate::table_ui::{row_id_ui, table_ui}; + +/// 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" +/// (i.e. logging multiple times the same entity/component at the same timestamp) and "split +/// logging" (i.e. multiple log calls on the same [entity, time] but with different components) +/// lead to multiple rows. In other words, no joining is done here. +/// +/// Also: +/// - View entities have their query range "forced" to a range query. If set to "latest at", they +/// are converted to Rel(0)-Rel(0). +/// - Only the data logged in the query range is displayed. There is no implicit "latest at" like +/// it's done for regular views. +/// - Static data is always shown. +/// - When both static and non-static data exist for the same entity/component, the non-static data +/// is never shown (as per our data model). + +pub(crate) fn time_range_table_ui( + ctx: &ViewerContext<'_>, + ui: &mut egui::Ui, + query: &ViewQuery<'_>, + group_by: TableGroupBy, + sort_order: SortOrder, +) { + re_tracing::profile_function!(); + + // + // Produce a sorted list of all components we are interested id. + // + + // TODO(ab): add support for filtering components more narrowly. + let sorted_components: BTreeSet<_> = { + re_tracing::profile_scope!("query components"); + + // Produce a sorted list of all components that are present in one or more entities. + // These will be the columns of the table. + query + .iter_all_data_results() + .filter(|data_result| data_result.is_visible(ctx)) + .flat_map(|data_result| { + ctx.recording_store() + .all_components(&query.timeline, &data_result.entity_path) + .unwrap_or_default() + }) + // TODO(#4466): make showing/hiding indicators components an explicit optional + .filter(|comp| !comp.is_indicator_component()) + .collect() + }; + + // + // Build the full list of rows, along with the chunk where the data is. Rows are keyed by an + // (entity, time, row_id) tuple (see function docstring). These keys are mapped to the + // corresponding chunk that contains the actual data. + // + // We build a big, monolithic iterator for all the rows. The following code builds that by + // breaking it into several functions for sanity purpose, from innermost to outermost. + // + + type RowKey = (EntityPath, TimeInt, RowId); + + #[inline] + fn map_chunk_indices_to_key_value_iter<'a>( + indices_iter: impl Iterator + 'a, + chunk: Arc, + entity_path: EntityPath, + resolved_time_range: ResolvedTimeRange, + ) -> impl Iterator)> + 'a { + indices_iter + .filter(move |(time, _)| time.is_static() || resolved_time_range.contains(*time)) + .map(move |(time, row_id)| { + let chunk = chunk.clone(); + ((entity_path.clone(), time, row_id), chunk) + }) + } + + #[inline] + fn entity_components_to_key_value_iter<'a>( + ctx: &ViewerContext<'_>, + entity_path: &'a EntityPath, + component: &'a ComponentName, + timeline: Timeline, + resolved_time_range: ResolvedTimeRange, + ) -> impl Iterator)> + 'a { + let range_query = RangeQuery::new(timeline, resolved_time_range); + + ctx.recording_store() + .range_relevant_chunks(&range_query, entity_path, *component) + .into_iter() + // This does two things: + // 1) Filter out instances where `chunk.iter_indices()` returns `None`. + // 2) Exploit the fact that the returned iterator (if any) is *not* bound to the + // lifetime of the chunk (it has an internal Arc). + .filter_map(move |chunk| { + chunk + .clone() + .iter_indices(&timeline) + .map(|iter_indices| (iter_indices, chunk)) + }) + .flat_map(move |(indices_iter, chunk)| { + map_chunk_indices_to_key_value_iter( + indices_iter, + chunk, + entity_path.clone(), + resolved_time_range, + ) + }) + } + + // all the rows! + let rows_to_chunk = query + .iter_all_data_results() + .filter(|data_result| data_result.is_visible(ctx)) + .flat_map(|data_result| { + let time_range = match &data_result.property_overrides.query_range { + QueryRange::TimeRange(time_range) => time_range.clone(), + QueryRange::LatestAt => TimeRange::AT_CURSOR, + }; + + let resolved_time_range = + ResolvedTimeRange::from_relative_time_range(&time_range, ctx.current_query().at()); + + sorted_components.iter().flat_map(move |component| { + entity_components_to_key_value_iter( + ctx, + &data_result.entity_path, + component, + query.timeline, + resolved_time_range, + ) + }) + }) + .collect::>(); + + // + // Row sorting/grouping based on view properties. + // + + 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(); + } + + // + // Drawing code. + // + + 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<'_, '_>| { + 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"); + }); + + for comp in &sorted_components { + row.col(|ui| { + ui.strong(comp.short_name()); + }); + } + }; + + 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. + let latest_at_query = query.latest_at_query(); + let row_ui = |mut row: egui_extras::TableRow<'_, '_>| { + let row_key = rows[row.index()]; + let row_chunk = &rows_to_chunk[row_key]; + let (entity_path, time, row_id) = row_key; + + 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); + }); + + for component_name in &sorted_components { + row.col(|ui| { + let content = row_chunk.cell(*row_id, component_name); + + if let Some(content) = content { + ctx.component_ui_registry.ui_raw( + ctx, + ui, + UiLayout::List, + &latest_at_query, + ctx.recording(), + entity_path, + *component_name, + &*content, + ); + } else { + ui.weak("-"); + } + }); + } + }; + + table_ui(ui, &sorted_components, header_ui, rows.len(), row_ui); +} diff --git a/crates/viewer/re_space_view_dataframe/src/utils.rs b/crates/viewer/re_space_view_dataframe/src/utils.rs new file mode 100644 index 000000000000..afcb2358cee2 --- /dev/null +++ b/crates/viewer/re_space_view_dataframe/src/utils.rs @@ -0,0 +1,53 @@ +use std::collections::BTreeSet; + +use re_chunk_store::{ChunkStore, LatestAtQuery}; +use re_entity_db::InstancePath; +use re_log_types::{EntityPath, Instance, Timeline}; +use re_viewer_context::{ViewQuery, ViewerContext}; + +/// Returns a sorted list of all entities that are visible in the view. +pub(crate) fn sorted_visible_entity_path( + ctx: &ViewerContext<'_>, + query: &ViewQuery<'_>, +) -> BTreeSet { + query + .iter_all_data_results() + .filter(|data_result| data_result.is_visible(ctx)) + .map(|data_result| &data_result.entity_path) + .cloned() + .collect() +} + +/// Returns a sorted, deduplicated iterator of all instance paths for a given entity. +pub(crate) fn sorted_instance_paths_for<'a>( + entity_path: &'a EntityPath, + store: &'a ChunkStore, + timeline: &'a Timeline, + latest_at_query: &'a LatestAtQuery, +) -> impl Iterator + 'a { + re_tracing::profile_function!(); + + store + .all_components(timeline, entity_path) + .unwrap_or_default() + .into_iter() + .filter(|component_name| !component_name.is_indicator_component()) + .flat_map(|component_name| { + let num_instances = store + .latest_at_relevant_chunks(latest_at_query, entity_path, component_name) + .into_iter() + .filter_map(|chunk| { + let (data_time, row_id, batch) = chunk + .latest_at(latest_at_query, component_name) + .iter_rows(timeline, &component_name) + .next()?; + batch.map(|batch| (data_time, row_id, batch)) + }) + .max_by_key(|(data_time, row_id, _)| (*data_time, *row_id)) + .map_or(0, |(_, _, batch)| batch.len()); + (0..num_instances).map(|i| Instance::from(i as u64)) + }) + .collect::>() // dedup and sort + .into_iter() + .map(|instance| InstancePath::instance(entity_path.clone(), instance)) +} From 6964030e44759445862694fc32733d4e3e2d07b1 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 15 Jul 2024 10:15:24 +0200 Subject: [PATCH 09/17] Make time clickable --- .../src/time_range_table.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs index 636995a961da..f0acd38e45fa 100644 --- a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs @@ -206,12 +206,17 @@ pub(crate) fn time_range_table_ui( }; let time_ui = |ui: &mut egui::Ui, time: &TimeInt| { - ui.label( - query - .timeline - .typ() - .format(*time, ctx.app_options.time_zone), - ); + if ui + .button( + query + .timeline + .typ() + .format(*time, ctx.app_options.time_zone), + ) + .clicked() + { + ctx.rec_cfg.time_ctrl.write().set_time(*time); + } }; // Draw a single line of the table. This is called for each _visible_ row. From fb79c25ff40b9e805fb850dd5da625b4246d1751 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 15 Jul 2024 10:37:34 +0200 Subject: [PATCH 10/17] fix lint --- crates/viewer/re_space_view_dataframe/src/space_view_class.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b90b67a40b6a..a854bb5aad58 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 @@ -50,7 +50,7 @@ panel. A row is shown for each entity instance. The _time range_ mode, the view displays all the data logged within the time range set for each view entity. In this mode, each row corresponds to an entity and time pair. Rows are further split -if multiple `rr.log()` calls were made for the same entity/time. Static data is also displayed. +if multiple `rr.log()` calls were made for the same entity/time. Static data is also displayed. The view switches to _time range_ mode as soon as a single one of its entities has its visible time range set to _Override_. Each entity may have its own time range setting. (To set the same time range From 395282e94868013c04889fd5aa595932f5d5a6ee Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 15 Jul 2024 14:21:24 +0200 Subject: [PATCH 11/17] Renamed group by -> sort key --- .../re_types/definitions/rerun/blueprint.fbs | 2 +- .../archetypes/range_table_settings.fbs | 6 +-- .../{table_group_by.fbs => sort_key.fbs} | 2 +- .../blueprint/archetypes/table_row_order.rs | 50 +++++++++---------- .../src/blueprint/components/.gitattributes | 2 +- .../re_types/src/blueprint/components/mod.rs | 4 +- .../{table_group_by.rs => sort_key.rs} | 20 ++++---- crates/viewer/re_edit_ui/src/lib.rs | 5 +- .../src/space_view_class.rs | 6 +-- .../src/time_range_table.rs | 26 +++++----- .../src/blueprint/validation_gen/mod.rs | 4 +- crates/viewer/re_viewer/src/reflection/mod.rs | 21 ++++---- .../blueprint/archetypes/table_row_order.cpp | 4 +- .../blueprint/archetypes/table_row_order.hpp | 16 +++--- rerun_cpp/src/rerun/blueprint/components.hpp | 2 +- .../rerun/blueprint/components/.gitattributes | 4 +- .../{table_group_by.cpp => sort_key.cpp} | 26 +++++----- .../{table_group_by.hpp => sort_key.hpp} | 14 +++--- .../blueprint/archetypes/table_row_order.py | 20 ++++---- .../rerun/blueprint/components/.gitattributes | 2 +- .../rerun/blueprint/components/__init__.py | 12 ++--- .../{table_group_by.py => sort_key.py} | 38 +++++++------- 22 files changed, 141 insertions(+), 145 deletions(-) rename crates/store/re_types/definitions/rerun/blueprint/components/{table_group_by.fbs => sort_key.fbs} (93%) rename crates/store/re_types/src/blueprint/components/{table_group_by.rs => sort_key.rs} (90%) rename rerun_cpp/src/rerun/blueprint/components/{table_group_by.cpp => sort_key.cpp} (73%) rename rerun_cpp/src/rerun/blueprint/components/{table_group_by.hpp => sort_key.hpp} (80%) rename rerun_py/rerun_sdk/rerun/blueprint/components/{table_group_by.py => sort_key.py} (59%) diff --git a/crates/store/re_types/definitions/rerun/blueprint.fbs b/crates/store/re_types/definitions/rerun/blueprint.fbs index 63055f1639f1..e523a67a423e 100644 --- a/crates/store/re_types/definitions/rerun/blueprint.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint.fbs @@ -17,11 +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_key.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"; 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 index abc3ccbec5fd..d9e4b20fea86 100644 --- 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 @@ -15,9 +15,9 @@ table TableRowOrder ( ) { // --- Optional --- - /// The type of the background. - group_by: rerun.blueprint.components.TableGroupBy ("attr.rerun.component_optional", nullable, order: 1000); + /// The primary sort key. + sort_key: rerun.blueprint.components.SortKey ("attr.rerun.component_optional", nullable, order: 1000); - /// Color used for the `SolidColor` background type. + /// The sort order. sort_order: rerun.blueprint.components.SortOrder ("attr.rerun.component_optional", nullable, order: 2000); } diff --git a/crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs b/crates/store/re_types/definitions/rerun/blueprint/components/sort_key.fbs similarity index 93% rename from crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs rename to crates/store/re_types/definitions/rerun/blueprint/components/sort_key.fbs index e0a1eb76e981..7c55b5de44bf 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/components/table_group_by.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/components/sort_key.fbs @@ -9,7 +9,7 @@ namespace rerun.blueprint.components; /// Primary element by which to group by in a temporal data table. -enum TableGroupBy: byte ( +enum SortKey: byte ( "attr.rerun.scope": "blueprint" ) { /// Group by entity. 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 index b88418a6d384..3c7d668d52d6 100644 --- a/crates/store/re_types/src/blueprint/archetypes/table_row_order.rs +++ b/crates/store/re_types/src/blueprint/archetypes/table_row_order.rs @@ -21,22 +21,22 @@ 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, + /// The primary sort key. + pub sort_key: Option, - /// Color used for the `SolidColor` background type. + /// The sort order. 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() + self.sort_key.heap_size_bytes() + self.sort_order.heap_size_bytes() } #[inline] fn is_pod() -> bool { - >::is_pod() + >::is_pod() && >::is_pod() } } @@ -50,7 +50,7 @@ static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = once_cell::sync::Lazy::new(|| { [ - "rerun.blueprint.components.TableGroupBy".into(), + "rerun.blueprint.components.SortKey".into(), "rerun.blueprint.components.SortOrder".into(), ] }); @@ -59,7 +59,7 @@ 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.SortKey".into(), "rerun.blueprint.components.SortOrder".into(), ] }); @@ -121,16 +121,16 @@ impl ::re_types_core::Archetype for TableRowOrder { .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_key = if let Some(array) = arrays_by_name.get("rerun.blueprint.components.SortKey") + { + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.TableRowOrder#sort_key")? + .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) @@ -142,7 +142,7 @@ impl ::re_types_core::Archetype for TableRowOrder { None }; Ok(Self { - group_by, + sort_key, sort_order, }) } @@ -154,7 +154,7 @@ impl ::re_types_core::AsComponents for TableRowOrder { use ::re_types_core::Archetype as _; [ Some(Self::indicator()), - self.group_by + self.sort_key .as_ref() .map(|comp| (comp as &dyn ComponentBatch).into()), self.sort_order @@ -174,22 +174,22 @@ impl TableRowOrder { #[inline] pub fn new() -> Self { Self { - group_by: None, + sort_key: None, sort_order: None, } } - /// The type of the background. + /// The primary sort key. #[inline] - pub fn with_group_by( + pub fn with_sort_key( mut self, - group_by: impl Into, + sort_key: impl Into, ) -> Self { - self.group_by = Some(group_by.into()); + self.sort_key = Some(sort_key.into()); self } - /// Color used for the `SolidColor` background type. + /// The sort order. #[inline] pub fn with_sort_order( mut self, diff --git a/crates/store/re_types/src/blueprint/components/.gitattributes b/crates/store/re_types/src/blueprint/components/.gitattributes index 249397ddf0c7..653e7df988ad 100644 --- a/crates/store/re_types/src/blueprint/components/.gitattributes +++ b/crates/store/re_types/src/blueprint/components/.gitattributes @@ -12,10 +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_key.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 06ecd4230c45..000478b2b5f0 100644 --- a/crates/store/re_types/src/blueprint/components/mod.rs +++ b/crates/store/re_types/src/blueprint/components/mod.rs @@ -13,12 +13,12 @@ mod panel_state; mod panel_state_ext; mod query_expression; mod row_share; +mod sort_key; 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; @@ -40,10 +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_key::SortKey; 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/table_group_by.rs b/crates/store/re_types/src/blueprint/components/sort_key.rs similarity index 90% rename from crates/store/re_types/src/blueprint/components/table_group_by.rs rename to crates/store/re_types/src/blueprint/components/sort_key.rs index 68233f10a75b..4e809b109d55 100644 --- a/crates/store/re_types/src/blueprint/components/table_group_by.rs +++ b/crates/store/re_types/src/blueprint/components/sort_key.rs @@ -1,5 +1,5 @@ // 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". +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/sort_key.fbs". #![allow(unused_imports)] #![allow(unused_parens)] @@ -20,7 +20,7 @@ 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 { +pub enum SortKey { /// Group by entity. #[default] Entity = 1, @@ -29,7 +29,7 @@ pub enum TableGroupBy { Time = 2, } -impl ::re_types_core::reflection::Enum for TableGroupBy { +impl ::re_types_core::reflection::Enum for SortKey { #[inline] fn variants() -> &'static [Self] { &[Self::Entity, Self::Time] @@ -44,7 +44,7 @@ impl ::re_types_core::reflection::Enum for TableGroupBy { } } -impl ::re_types_core::SizeBytes for TableGroupBy { +impl ::re_types_core::SizeBytes for SortKey { #[inline] fn heap_size_bytes(&self) -> u64 { 0 @@ -56,7 +56,7 @@ impl ::re_types_core::SizeBytes for TableGroupBy { } } -impl std::fmt::Display for TableGroupBy { +impl std::fmt::Display for SortKey { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Entity => write!(f, "Entity"), @@ -65,14 +65,14 @@ impl std::fmt::Display for TableGroupBy { } } -::re_types_core::macros::impl_into_cow!(TableGroupBy); +::re_types_core::macros::impl_into_cow!(SortKey); -impl ::re_types_core::Loggable for TableGroupBy { +impl ::re_types_core::Loggable for SortKey { type Name = ::re_types_core::ComponentName; #[inline] fn name() -> Self::Name { - "rerun.blueprint.components.TableGroupBy".into() + "rerun.blueprint.components.SortKey".into() } #[inline] @@ -142,7 +142,7 @@ impl ::re_types_core::Loggable for TableGroupBy { let actual = arrow_data.data_type().clone(); DeserializationError::datatype_mismatch(expected, actual) }) - .with_context("rerun.blueprint.components.TableGroupBy")?; + .with_context("rerun.blueprint.components.SortKey")?; let arrow_data_types = arrow_data.types(); arrow_data_types .iter() @@ -157,7 +157,7 @@ impl ::re_types_core::Loggable for TableGroupBy { )), }) .collect::>>() - .with_context("rerun.blueprint.components.TableGroupBy")? + .with_context("rerun.blueprint.components.SortKey")? }) } } diff --git a/crates/viewer/re_edit_ui/src/lib.rs b/crates/viewer/re_edit_ui/src/lib.rs index 2f42e654a776..12c33a7b27d9 100644 --- a/crates/viewer/re_edit_ui/src/lib.rs +++ b/crates/viewer/re_edit_ui/src/lib.rs @@ -15,7 +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::{SortKey, SortOrder}; use re_types::{ blueprint::components::{BackgroundKind, Corner2D, LockRangeDuringZoom, ViewFit, Visible}, components::{ @@ -78,9 +78,8 @@ 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_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/src/space_view_class.rs b/crates/viewer/re_space_view_dataframe/src/space_view_class.rs index a854bb5aad58..72066ba02e97 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 @@ -4,7 +4,7 @@ use re_log_types::EntityPath; use re_space_view::view_property_ui; use re_types::blueprint::{ archetypes::TableRowOrder, - components::{SortOrder, TableGroupBy}, + components::{SortKey, SortOrder}, }; use re_types_core::SpaceViewClassIdentifier; use re_ui::list_item; @@ -115,14 +115,14 @@ for all entities, it is preferable to override the view-level visible time range ctx.blueprint_query, query.space_view_id, ); - let group_by = row_order.component_or_fallback::(ctx, self, state)?; + let sort_key = row_order.component_or_fallback::(ctx, self, state)?; let sort_order = row_order.component_or_fallback::(ctx, self, state)?; let mode = self.table_mode(query); match mode { TableMode::LatestAtTable => latest_at_table_ui(ctx, ui, query), - TableMode::TimeRangeTable => time_range_table_ui(ctx, ui, query, group_by, sort_order), + TableMode::TimeRangeTable => time_range_table_ui(ctx, ui, query, sort_key, sort_order), }; Ok(()) diff --git a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs index f0acd38e45fa..6ea671a57132 100644 --- a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use re_chunk_store::{Chunk, RangeQuery, RowId}; use re_data_ui::item_ui::entity_path_button; use re_log_types::{EntityPath, ResolvedTimeRange, TimeInt, Timeline}; -use re_types::blueprint::components::{SortOrder, TableGroupBy}; +use re_types::blueprint::components::{SortKey, SortOrder}; use re_types_core::datatypes::TimeRange; use re_types_core::ComponentName; use re_viewer_context::{QueryRange, UiLayout, ViewQuery, ViewerContext}; @@ -31,7 +31,7 @@ pub(crate) fn time_range_table_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, query: &ViewQuery<'_>, - group_by: TableGroupBy, + sort_key: SortKey, sort_order: SortOrder, ) { re_tracing::profile_function!(); @@ -144,15 +144,15 @@ pub(crate) fn time_range_table_ui( .collect::>(); // - // Row sorting/grouping based on view properties. + // Row sorting based on view properties. // 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)), + // apply sort key + match sort_key { + SortKey::Entity => {} // already correctly sorted + SortKey::Time => rows.sort_by_key(|(entity_path, time, _)| (*time, entity_path)), }; if sort_order == SortOrder::Descending { rows.reverse(); @@ -171,12 +171,12 @@ pub(crate) fn time_range_table_ui( // Draw the header row. let header_ui = |mut row: egui_extras::TableRow<'_, '_>| { - match group_by { - TableGroupBy::Entity => { + match sort_key { + SortKey::Entity => { row.col(entity_header); row.col(time_header); } - TableGroupBy::Time => { + SortKey::Time => { row.col(time_header); row.col(entity_header); } @@ -226,12 +226,12 @@ pub(crate) fn time_range_table_ui( let row_chunk = &rows_to_chunk[row_key]; let (entity_path, time, row_id) = row_key; - match group_by { - TableGroupBy::Entity => { + match sort_key { + SortKey::Entity => { row.col(|ui| entity_ui(ui, entity_path)); row.col(|ui| time_ui(ui, time)); } - TableGroupBy::Time => { + SortKey::Time => { row.col(|ui| time_ui(ui, time)); row.col(|ui| entity_ui(ui, entity_path)); } 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 3b285ea98be6..81d265eac828 100644 --- a/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs +++ b/crates/viewer/re_viewer/src/blueprint/validation_gen/mod.rs @@ -11,10 +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::SortKey; 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; @@ -50,11 +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) && validate_component::(blueprint) diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 09baec388123..e21e0599c93c 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: "Primary element by which to group by in a temporal data table.", + placeholder: Some(SortKey::default().to_arrow()?), + }, + ), ( ::name(), ComponentReflection { @@ -174,13 +181,6 @@ 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 { @@ -634,12 +634,11 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { 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.", }, + "rerun.blueprint.components.SortKey".into(), display_name : + "Sort key", docstring_md : "The primary sort key.", }, ArchetypeFieldReflection { component_name : "rerun.blueprint.components.SortOrder".into(), display_name : - "Sort order", docstring_md : - "Color used for the `SolidColor` background type.", }, + "Sort order", docstring_md : "The sort order.", }, ], }, ), diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.cpp index 09492f06d985..b6fe7f396dab 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.cpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.cpp @@ -16,8 +16,8 @@ namespace rerun { std::vector cells; cells.reserve(3); - if (archetype.group_by.has_value()) { - auto result = DataCell::from_loggable(archetype.group_by.value()); + if (archetype.sort_key.has_value()) { + auto result = DataCell::from_loggable(archetype.sort_key.value()); RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp index 891176bc18d2..d6ddf6156283 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp @@ -3,8 +3,8 @@ #pragma once +#include "../../blueprint/components/sort_key.hpp" #include "../../blueprint/components/sort_order.hpp" -#include "../../blueprint/components/table_group_by.hpp" #include "../../collection.hpp" #include "../../compiler_utils.hpp" #include "../../data_cell.hpp" @@ -19,10 +19,10 @@ 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; + /// The primary sort key. + std::optional sort_key; - /// Color used for the `SolidColor` background type. + /// The sort order. std::optional sort_order; public: @@ -36,14 +36,14 @@ namespace rerun::blueprint::archetypes { 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); + /// The primary sort key. + TableRowOrder with_sort_key(rerun::blueprint::components::SortKey _sort_key) && { + sort_key = std::move(_sort_key); // 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. + /// The sort order. 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 diff --git a/rerun_cpp/src/rerun/blueprint/components.hpp b/rerun_cpp/src/rerun/blueprint/components.hpp index 6d72c740fbf2..bcbb0d44b2ff 100644 --- a/rerun_cpp/src/rerun/blueprint/components.hpp +++ b/rerun_cpp/src/rerun/blueprint/components.hpp @@ -18,11 +18,11 @@ #include "blueprint/components/query_expression.hpp" #include "blueprint/components/root_container.hpp" #include "blueprint/components/row_share.hpp" +#include "blueprint/components/sort_key.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 1afaab8ac7bc..189ad84f442b 100644 --- a/rerun_cpp/src/rerun/blueprint/components/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/components/.gitattributes @@ -21,13 +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_key.cpp linguist-generated=true +sort_key.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/table_group_by.cpp b/rerun_cpp/src/rerun/blueprint/components/sort_key.cpp similarity index 73% rename from rerun_cpp/src/rerun/blueprint/components/table_group_by.cpp rename to rerun_cpp/src/rerun/blueprint/components/sort_key.cpp index 6cf091ead3ce..f488500c1803 100644 --- a/rerun_cpp/src/rerun/blueprint/components/table_group_by.cpp +++ b/rerun_cpp/src/rerun/blueprint/components/sort_key.cpp @@ -1,14 +1,14 @@ // 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". +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/sort_key.fbs". -#include "table_group_by.hpp" +#include "sort_key.hpp" #include #include namespace rerun { const std::shared_ptr& - Loggable::arrow_datatype() { + Loggable::arrow_datatype() { static const auto datatype = arrow::sparse_union({ arrow::field("_null_markers", arrow::null(), true, nullptr), arrow::field("Entity", arrow::null(), true), @@ -17,8 +17,8 @@ namespace rerun { return datatype; } - Result> Loggable::to_arrow( - const blueprint::components::TableGroupBy* instances, size_t num_instances + Result> Loggable::to_arrow( + const blueprint::components::SortKey* instances, size_t num_instances ) { // TODO(andreas): Allow configuring the memory pool. arrow::MemoryPool* pool = arrow::default_memory_pool(); @@ -26,21 +26,19 @@ namespace rerun { 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 - ) - ); + 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, + rerun::Error Loggable::fill_arrow_array_builder( + arrow::SparseUnionBuilder* builder, const blueprint::components::SortKey* elements, size_t num_elements ) { if (builder == nullptr) { diff --git a/rerun_cpp/src/rerun/blueprint/components/table_group_by.hpp b/rerun_cpp/src/rerun/blueprint/components/sort_key.hpp similarity index 80% rename from rerun_cpp/src/rerun/blueprint/components/table_group_by.hpp rename to rerun_cpp/src/rerun/blueprint/components/sort_key.hpp index 580ac1cc04d0..4437765fddf0 100644 --- a/rerun_cpp/src/rerun/blueprint/components/table_group_by.hpp +++ b/rerun_cpp/src/rerun/blueprint/components/sort_key.hpp @@ -1,5 +1,5 @@ // 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". +// Based on "crates/store/re_types/definitions/rerun/blueprint/components/sort_key.fbs". #pragma once @@ -16,7 +16,7 @@ namespace arrow { namespace rerun::blueprint::components { /// **Component**: Primary element by which to group by in a temporal data table. - enum class TableGroupBy : uint8_t { + enum class SortKey : uint8_t { /// Group by entity. Entity = 1, @@ -32,20 +32,20 @@ namespace rerun { /// \private template <> - struct Loggable { - static constexpr const char Name[] = "rerun.blueprint.components.TableGroupBy"; + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.SortKey"; /// 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. + /// Serializes an array of `rerun::blueprint:: components::SortKey` into an arrow array. static Result> to_arrow( - const blueprint::components::TableGroupBy* instances, size_t num_instances + const blueprint::components::SortKey* 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, + arrow::SparseUnionBuilder* builder, const blueprint::components::SortKey* elements, size_t num_elements ); }; 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 index 12b301bd09ac..95fa1f474ca0 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/table_row_order.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/table_row_order.py @@ -25,7 +25,7 @@ class TableRowOrder(Archetype): def __init__( self: Any, *, - group_by: blueprint_components.TableGroupByLike | None = None, + sort_key: blueprint_components.SortKeyLike | None = None, sort_order: blueprint_components.SortOrderLike | None = None, ): """ @@ -33,23 +33,23 @@ def __init__( Parameters ---------- - group_by: - The type of the background. + sort_key: + The primary sort key. sort_order: - Color used for the `SolidColor` background type. + The sort order. """ # 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) + self.__attrs_init__(sort_key=sort_key, 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_key=None, # type: ignore[arg-type] sort_order=None, # type: ignore[arg-type] ) @@ -60,12 +60,12 @@ def _clear(cls) -> TableRowOrder: inst.__attrs_clear__() return inst - group_by: blueprint_components.TableGroupByBatch | None = field( + sort_key: blueprint_components.SortKeyBatch | None = field( metadata={"component": "optional"}, default=None, - converter=blueprint_components.TableGroupByBatch._optional, # type: ignore[misc] + converter=blueprint_components.SortKeyBatch._optional, # type: ignore[misc] ) - # The type of the background. + # The primary sort key. # # (Docstring intentionally commented out to hide this field from the docs) @@ -74,7 +74,7 @@ def _clear(cls) -> TableRowOrder: default=None, converter=blueprint_components.SortOrderBatch._optional, # type: ignore[misc] ) - # Color used for the `SolidColor` background type. + # The sort order. # # (Docstring intentionally commented out to hide this field from the docs) diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes index 93184d1eccce..ca7cc8880260 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes @@ -18,11 +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_key.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 3307a07114ed..ac06fd41efa7 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py @@ -30,11 +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_key import SortKey, SortKeyArrayLike, SortKeyBatch, SortKeyLike, SortKeyType 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, @@ -108,6 +108,11 @@ "RowShare", "RowShareBatch", "RowShareType", + "SortKey", + "SortKeyArrayLike", + "SortKeyBatch", + "SortKeyLike", + "SortKeyType", "SortOrder", "SortOrderArrayLike", "SortOrderBatch", @@ -122,11 +127,6 @@ "SpaceViewOrigin", "SpaceViewOriginBatch", "SpaceViewOriginType", - "TableGroupBy", - "TableGroupByArrayLike", - "TableGroupByBatch", - "TableGroupByLike", - "TableGroupByType", "TensorDimensionIndexSlider", "TensorDimensionIndexSliderBatch", "TensorDimensionIndexSliderType", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/table_group_by.py b/rerun_py/rerun_sdk/rerun/blueprint/components/sort_key.py similarity index 59% rename from rerun_py/rerun_sdk/rerun/blueprint/components/table_group_by.py rename to rerun_py/rerun_sdk/rerun/blueprint/components/sort_key.py index 1136d14a3bce..b4da9b031608 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/table_group_by.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/sort_key.py @@ -1,7 +1,7 @@ # 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". +# Based on "crates/store/re_types/definitions/rerun/blueprint/components/sort_key.fbs". -# You can extend this class by creating a "TableGroupByExt" class in "table_group_by_ext.py". +# You can extend this class by creating a "SortKeyExt" class in "sort_key_ext.py". from __future__ import annotations @@ -15,13 +15,13 @@ ComponentBatchMixin, ) -__all__ = ["TableGroupBy", "TableGroupByArrayLike", "TableGroupByBatch", "TableGroupByLike", "TableGroupByType"] +__all__ = ["SortKey", "SortKeyArrayLike", "SortKeyBatch", "SortKeyLike", "SortKeyType"] from enum import Enum -class TableGroupBy(Enum): +class SortKey(Enum): """**Component**: Primary element by which to group by in a temporal data table.""" Entity = 1 @@ -31,12 +31,12 @@ class TableGroupBy(Enum): """Group by instance.""" -TableGroupByLike = Union[TableGroupBy, Literal["entity", "time"]] -TableGroupByArrayLike = Union[TableGroupByLike, Sequence[TableGroupByLike]] +SortKeyLike = Union[SortKey, Literal["entity", "time"]] +SortKeyArrayLike = Union[SortKeyLike, Sequence[SortKeyLike]] -class TableGroupByType(BaseExtensionType): - _TYPE_NAME: str = "rerun.blueprint.components.TableGroupBy" +class SortKeyType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.components.SortKey" def __init__(self) -> None: pa.ExtensionType.__init__( @@ -50,12 +50,12 @@ def __init__(self) -> None: ) -class TableGroupByBatch(BaseBatch[TableGroupByArrayLike], ComponentBatchMixin): - _ARROW_TYPE = TableGroupByType() +class SortKeyBatch(BaseBatch[SortKeyArrayLike], ComponentBatchMixin): + _ARROW_TYPE = SortKeyType() @staticmethod - def _native_to_pa_array(data: TableGroupByArrayLike, data_type: pa.DataType) -> pa.Array: - if isinstance(data, (TableGroupBy, int, str)): + def _native_to_pa_array(data: SortKeyArrayLike, data_type: pa.DataType) -> pa.Array: + if isinstance(data, (SortKey, int, str)): data = [data] types: list[int] = [] @@ -63,21 +63,21 @@ def _native_to_pa_array(data: TableGroupByArrayLike, data_type: pa.DataType) -> for value in data: if value is None: types.append(0) - elif isinstance(value, TableGroupBy): + elif isinstance(value, SortKey): 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 + if hasattr(SortKey, value): + types.append(SortKey[value].value) # fast path elif value.lower() == "entity": - types.append(TableGroupBy.Entity.value) + types.append(SortKey.Entity.value) elif value.lower() == "time": - types.append(TableGroupBy.Time.value) + types.append(SortKey.Time.value) else: - raise ValueError(f"Unknown TableGroupBy kind: {value}") + raise ValueError(f"Unknown SortKey kind: {value}") else: - raise ValueError(f"Unknown TableGroupBy kind: {value}") + raise ValueError(f"Unknown SortKey kind: {value}") buffers = [ None, From aff65cd2b0dbb07f6caece4b44d2b013fcf159c3 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 15 Jul 2024 14:27:23 +0200 Subject: [PATCH 12/17] Review comments + fix column count bug --- .../re_space_view_dataframe/src/latest_at_table.rs | 1 + .../re_space_view_dataframe/src/space_view_class.rs | 4 ++-- crates/viewer/re_space_view_dataframe/src/table_ui.rs | 5 ++++- .../re_space_view_dataframe/src/time_range_table.rs | 9 ++++++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs index 991299c9bd89..9090d9250418 100644 --- a/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/latest_at_table.rs @@ -128,6 +128,7 @@ pub(crate) fn latest_at_table_ui( table_ui( ui, &sorted_components, + 1, // entity column header_ui, sorted_instance_paths.len(), row_ui, 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 72066ba02e97..70d082ddf17a 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 @@ -48,13 +48,13 @@ The Dataframe view operates in two modes: the _latest at_ mode and the _time ran In the _latest at_ mode, the view displays the latest data for the timeline and time set in the time panel. A row is shown for each entity instance. -The _time range_ mode, the view displays all the data logged within the time range set for each +In the _time range_ mode, the view displays all the data logged within the time range set for each view entity. In this mode, each row corresponds to an entity and time pair. Rows are further split if multiple `rr.log()` calls were made for the same entity/time. Static data is also displayed. The view switches to _time range_ mode as soon as a single one of its entities has its visible time range set to _Override_. Each entity may have its own time range setting. (To set the same time range -for all entities, it is preferable to override the view-level visible time range at the view.)" +for all entities, it is preferable to override the view-level visible time range.)" .to_owned() } diff --git a/crates/viewer/re_space_view_dataframe/src/table_ui.rs b/crates/viewer/re_space_view_dataframe/src/table_ui.rs index e92b51655bb6..9735c0fa0509 100644 --- a/crates/viewer/re_space_view_dataframe/src/table_ui.rs +++ b/crates/viewer/re_space_view_dataframe/src/table_ui.rs @@ -6,9 +6,12 @@ use re_chunk_store::RowId; use re_types_core::ComponentName; /// Display a nicely configured table with the provided header ui, row ui, and row count. +/// +/// The `extra_columns` are hom many more columns there are in addition to the components. pub(crate) fn table_ui( ui: &mut egui::Ui, sorted_components: &BTreeSet, + extra_columns: usize, header_ui: impl FnOnce(egui_extras::TableRow<'_, '_>), row_count: usize, row_ui: impl FnMut(TableRow<'_, '_>), @@ -28,7 +31,7 @@ pub(crate) fn table_ui( egui_extras::TableBuilder::new(ui) .columns( Column::auto_with_initial_suggestion(200.0).clip(true), - 3 + sorted_components.len(), + extra_columns + sorted_components.len(), ) .resizable(true) .vscroll(true) diff --git a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs index 6ea671a57132..f14518c398b5 100644 --- a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs @@ -263,5 +263,12 @@ pub(crate) fn time_range_table_ui( } }; - table_ui(ui, &sorted_components, header_ui, rows.len(), row_ui); + table_ui( + ui, + &sorted_components, + 3, // time, entity, row id + header_ui, + rows.len(), + row_ui, + ); } From 9658a37710982fdfc161fbdf8b65faed651fba9c Mon Sep 17 00:00:00 2001 From: Antoine Beyeler <49431240+abey79@users.noreply.github.com> Date: Mon, 15 Jul 2024 14:29:27 +0200 Subject: [PATCH 13/17] Update crates/viewer/re_viewer_context/src/query_range.rs Co-authored-by: Clement Rey --- crates/viewer/re_viewer_context/src/query_range.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/viewer/re_viewer_context/src/query_range.rs b/crates/viewer/re_viewer_context/src/query_range.rs index 6db79b699ec7..601896df6b18 100644 --- a/crates/viewer/re_viewer_context/src/query_range.rs +++ b/crates/viewer/re_viewer_context/src/query_range.rs @@ -14,6 +14,7 @@ impl QueryRange { matches!(self, Self::LatestAt) } + #[inline] pub fn is_time_range(&self) -> bool { matches!(self, Self::TimeRange(_)) } From fce974596f473fdb8c248f240e4f3fac9e1c6e2f Mon Sep 17 00:00:00 2001 From: Antoine Beyeler <49431240+abey79@users.noreply.github.com> Date: Mon, 15 Jul 2024 14:29:37 +0200 Subject: [PATCH 14/17] Update crates/viewer/re_viewer_context/src/query_range.rs Co-authored-by: Clement Rey --- crates/viewer/re_viewer_context/src/query_range.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/viewer/re_viewer_context/src/query_range.rs b/crates/viewer/re_viewer_context/src/query_range.rs index 601896df6b18..1dd49ac69102 100644 --- a/crates/viewer/re_viewer_context/src/query_range.rs +++ b/crates/viewer/re_viewer_context/src/query_range.rs @@ -10,6 +10,7 @@ pub enum QueryRange { } impl QueryRange { + #[inline] pub fn is_latest_at(&self) -> bool { matches!(self, Self::LatestAt) } From 9275eb10f1adeb8002dcbd883b820e725ef33083 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 15 Jul 2024 14:42:37 +0200 Subject: [PATCH 15/17] Apply range query on chunk --- crates/viewer/re_space_view_dataframe/src/time_range_table.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs index f14518c398b5..501cfb1316fe 100644 --- a/crates/viewer/re_space_view_dataframe/src/time_range_table.rs +++ b/crates/viewer/re_space_view_dataframe/src/time_range_table.rs @@ -26,7 +26,6 @@ use crate::table_ui::{row_id_ui, table_ui}; /// - Static data is always shown. /// - When both static and non-static data exist for the same entity/component, the non-static data /// is never shown (as per our data model). - pub(crate) fn time_range_table_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, @@ -103,6 +102,9 @@ pub(crate) fn time_range_table_ui( // 2) Exploit the fact that the returned iterator (if any) is *not* bound to the // lifetime of the chunk (it has an internal Arc). .filter_map(move |chunk| { + //TODO(ab, cmc): remove this line when a range-aware, iter_indices API is available. + let chunk = Arc::new(chunk.range(&range_query, *component)); + chunk .clone() .iter_indices(&timeline) From 96373402bc828624c21e728ad7e263941ea24de5 Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 15 Jul 2024 14:52:23 +0200 Subject: [PATCH 16/17] More renaming in codegen --- .../re_types/definitions/rerun/blueprint.fbs | 2 +- ...able_settings.fbs => range_table_sort.fbs} | 2 +- .../src/blueprint/archetypes/.gitattributes | 2 +- .../re_types/src/blueprint/archetypes/mod.rs | 4 +- ...table_row_order.rs => range_table_sort.rs} | 38 +++++++++---------- .../src/space_view_class.rs | 6 +-- crates/viewer/re_viewer/src/reflection/mod.rs | 30 +++++++-------- rerun_cpp/src/rerun/blueprint/archetypes.hpp | 2 +- .../rerun/blueprint/archetypes/.gitattributes | 4 +- ...ble_row_order.cpp => range_table_sort.cpp} | 10 ++--- ...ble_row_order.hpp => range_table_sort.hpp} | 18 ++++----- .../rerun/blueprint/archetypes/.gitattributes | 2 +- .../rerun/blueprint/archetypes/__init__.py | 4 +- ...table_row_order.py => range_table_sort.py} | 16 ++++---- 14 files changed, 70 insertions(+), 70 deletions(-) rename crates/store/re_types/definitions/rerun/blueprint/archetypes/{range_table_settings.fbs => range_table_sort.fbs} (96%) rename crates/store/re_types/src/blueprint/archetypes/{table_row_order.rs => range_table_sort.rs} (82%) rename rerun_cpp/src/rerun/blueprint/archetypes/{table_row_order.cpp => range_table_sort.cpp} (83%) rename rerun_cpp/src/rerun/blueprint/archetypes/{table_row_order.hpp => range_table_sort.hpp} (78%) rename rerun_py/rerun_sdk/rerun/blueprint/archetypes/{table_row_order.py => range_table_sort.py} (84%) diff --git a/crates/store/re_types/definitions/rerun/blueprint.fbs b/crates/store/re_types/definitions/rerun/blueprint.fbs index e523a67a423e..48d564c0bb8e 100644 --- a/crates/store/re_types/definitions/rerun/blueprint.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint.fbs @@ -43,7 +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/range_table_sort.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_sort.fbs similarity index 96% rename from crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_settings.fbs rename to crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_sort.fbs index d9e4b20fea86..c15aa22f940f 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_settings.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_sort.fbs @@ -8,7 +8,7 @@ namespace rerun.blueprint.archetypes; /// Configuration for the sorting of the rows of a time range table. -table TableRowOrder ( +table RangeTableSort ( "attr.rerun.scope": "blueprint", "attr.rust.derive": "Copy", "attr.rust.generate_field_info" diff --git a/crates/store/re_types/src/blueprint/archetypes/.gitattributes b/crates/store/re_types/src/blueprint/archetypes/.gitattributes index 91ddfedffbf6..9934c12dbc75 100644 --- a/crates/store/re_types/src/blueprint/archetypes/.gitattributes +++ b/crates/store/re_types/src/blueprint/archetypes/.gitattributes @@ -4,10 +4,10 @@ background.rs linguist-generated=true mod.rs linguist-generated=true plot_legend.rs linguist-generated=true +range_table_sort.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 2a38af4fdc26..7a1ac644b9c6 100644 --- a/crates/store/re_types/src/blueprint/archetypes/mod.rs +++ b/crates/store/re_types/src/blueprint/archetypes/mod.rs @@ -2,10 +2,10 @@ mod background; mod plot_legend; +mod range_table_sort; 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; @@ -15,10 +15,10 @@ mod visual_bounds2d; pub use self::background::Background; pub use self::plot_legend::PlotLegend; +pub use self::range_table_sort::RangeTableSort; 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/range_table_sort.rs similarity index 82% rename from crates/store/re_types/src/blueprint/archetypes/table_row_order.rs rename to crates/store/re_types/src/blueprint/archetypes/range_table_sort.rs index 3c7d668d52d6..1f2b715a6930 100644 --- a/crates/store/re_types/src/blueprint/archetypes/table_row_order.rs +++ b/crates/store/re_types/src/blueprint/archetypes/range_table_sort.rs @@ -1,5 +1,5 @@ // 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". +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_sort.fbs". #![allow(unused_imports)] #![allow(unused_parens)] @@ -20,7 +20,7 @@ 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 { +pub struct RangeTableSort { /// The primary sort key. pub sort_key: Option, @@ -28,7 +28,7 @@ pub struct TableRowOrder { pub sort_order: Option, } -impl ::re_types_core::SizeBytes for TableRowOrder { +impl ::re_types_core::SizeBytes for RangeTableSort { #[inline] fn heap_size_bytes(&self) -> u64 { self.sort_key.heap_size_bytes() + self.sort_order.heap_size_bytes() @@ -45,7 +45,7 @@ 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()]); + once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.RangeTableSortIndicator".into()]); static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = once_cell::sync::Lazy::new(|| { @@ -58,36 +58,36 @@ static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 3usize]> = once_cell::sync::Lazy::new(|| { [ - "rerun.blueprint.components.TableRowOrderIndicator".into(), + "rerun.blueprint.components.RangeTableSortIndicator".into(), "rerun.blueprint.components.SortKey".into(), "rerun.blueprint.components.SortOrder".into(), ] }); -impl TableRowOrder { +impl RangeTableSort { /// 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; +/// Indicator component for the [`RangeTableSort`] [`::re_types_core::Archetype`] +pub type RangeTableSortIndicator = ::re_types_core::GenericIndicatorComponent; -impl ::re_types_core::Archetype for TableRowOrder { - type Indicator = TableRowOrderIndicator; +impl ::re_types_core::Archetype for RangeTableSort { + type Indicator = RangeTableSortIndicator; #[inline] fn name() -> ::re_types_core::ArchetypeName { - "rerun.blueprint.archetypes.TableRowOrder".into() + "rerun.blueprint.archetypes.RangeTableSort".into() } #[inline] fn display_name() -> &'static str { - "Table row order" + "Range table sort" } #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { - static INDICATOR: TableRowOrderIndicator = TableRowOrderIndicator::DEFAULT; + static INDICATOR: RangeTableSortIndicator = RangeTableSortIndicator::DEFAULT; MaybeOwnedComponentBatch::Ref(&INDICATOR) } @@ -124,7 +124,7 @@ impl ::re_types_core::Archetype for TableRowOrder { let sort_key = if let Some(array) = arrays_by_name.get("rerun.blueprint.components.SortKey") { ::from_arrow_opt(&**array) - .with_context("rerun.blueprint.archetypes.TableRowOrder#sort_key")? + .with_context("rerun.blueprint.archetypes.RangeTableSort#sort_key")? .into_iter() .next() .flatten() @@ -134,7 +134,7 @@ impl ::re_types_core::Archetype for TableRowOrder { 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")? + .with_context("rerun.blueprint.archetypes.RangeTableSort#sort_order")? .into_iter() .next() .flatten() @@ -148,7 +148,7 @@ impl ::re_types_core::Archetype for TableRowOrder { } } -impl ::re_types_core::AsComponents for TableRowOrder { +impl ::re_types_core::AsComponents for RangeTableSort { fn as_component_batches(&self) -> Vec> { re_tracing::profile_function!(); use ::re_types_core::Archetype as _; @@ -167,10 +167,10 @@ impl ::re_types_core::AsComponents for TableRowOrder { } } -impl ::re_types_core::ArchetypeReflectionMarker for TableRowOrder {} +impl ::re_types_core::ArchetypeReflectionMarker for RangeTableSort {} -impl TableRowOrder { - /// Create a new `TableRowOrder`. +impl RangeTableSort { + /// Create a new `RangeTableSort`. #[inline] pub fn new() -> Self { Self { 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 70d082ddf17a..35f9dca1d392 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 @@ -3,7 +3,7 @@ use egui::Ui; use re_log_types::EntityPath; use re_space_view::view_property_ui; use re_types::blueprint::{ - archetypes::TableRowOrder, + archetypes::RangeTableSort, components::{SortKey, SortOrder}, }; use re_types_core::SpaceViewClassIdentifier; @@ -94,7 +94,7 @@ for all entities, it is preferable to override the view-level visible time range 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); + view_property_ui::(ctx, ui, space_view_id, self, state); }); Ok(()) @@ -110,7 +110,7 @@ for all entities, it is preferable to override the view-level visible time range ) -> Result<(), SpaceViewSystemExecutionError> { re_tracing::profile_function!(); - let row_order = ViewProperty::from_archetype::( + let row_order = ViewProperty::from_archetype::( ctx.blueprint_db(), ctx.blueprint_query, query.space_view_id, diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index e21e0599c93c..3a7a3c1e4688 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -609,6 +609,21 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { ], }, ), + ( + ArchetypeName::new("rerun.blueprint.archetypes.RangeTableSort"), + ArchetypeReflection { + display_name: "Range table sort", + docstring_md: "Configuration for the sorting of the rows of a time range table.", + fields: vec![ + ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.SortKey".into(), display_name : + "Sort key", docstring_md : "The primary sort key.", }, + ArchetypeFieldReflection { component_name : + "rerun.blueprint.components.SortOrder".into(), display_name : + "Sort order", docstring_md : "The sort order.", }, + ], + }, + ), ( ArchetypeName::new("rerun.blueprint.archetypes.ScalarAxis"), ArchetypeReflection { @@ -627,21 +642,6 @@ 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.SortKey".into(), display_name : - "Sort key", docstring_md : "The primary sort key.", }, - ArchetypeFieldReflection { component_name : - "rerun.blueprint.components.SortOrder".into(), display_name : - "Sort order", docstring_md : "The sort order.", }, - ], - }, - ), ( 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 03f21ca4bdff..814a88aff6a8 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes.hpp @@ -6,10 +6,10 @@ #include "blueprint/archetypes/container_blueprint.hpp" #include "blueprint/archetypes/panel_blueprint.hpp" #include "blueprint/archetypes/plot_legend.hpp" +#include "blueprint/archetypes/range_table_sort.hpp" #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 b190995becbc..6e0a948e2f17 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes @@ -9,14 +9,14 @@ panel_blueprint.cpp linguist-generated=true panel_blueprint.hpp linguist-generated=true plot_legend.cpp linguist-generated=true plot_legend.hpp linguist-generated=true +range_table_sort.cpp linguist-generated=true +range_table_sort.hpp linguist-generated=true scalar_axis.cpp linguist-generated=true scalar_axis.hpp linguist-generated=true 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/range_table_sort.cpp similarity index 83% rename from rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.cpp rename to rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.cpp index b6fe7f396dab..8f2cc34c9061 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.cpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.cpp @@ -1,7 +1,7 @@ // 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". +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_sort.fbs". -#include "table_row_order.hpp" +#include "range_table_sort.hpp" #include "../../collection_adapter_builtins.hpp" @@ -9,8 +9,8 @@ namespace rerun::blueprint::archetypes {} namespace rerun { - Result> AsComponents::serialize( - const blueprint::archetypes::TableRowOrder& archetype + Result> AsComponents::serialize( + const blueprint::archetypes::RangeTableSort& archetype ) { using namespace blueprint::archetypes; std::vector cells; @@ -27,7 +27,7 @@ namespace rerun { cells.push_back(std::move(result.value)); } { - auto indicator = TableRowOrder::IndicatorComponent(); + auto indicator = RangeTableSort::IndicatorComponent(); auto result = DataCell::from_loggable(indicator); RR_RETURN_NOT_OK(result.error); cells.emplace_back(std::move(result.value)); diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.hpp similarity index 78% rename from rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp rename to rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.hpp index d6ddf6156283..34390b314daa 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/table_row_order.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.hpp @@ -1,5 +1,5 @@ // 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". +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_sort.fbs". #pragma once @@ -18,7 +18,7 @@ namespace rerun::blueprint::archetypes { /// **Archetype**: Configuration for the sorting of the rows of a time range table. - struct TableRowOrder { + struct RangeTableSort { /// The primary sort key. std::optional sort_key; @@ -27,24 +27,24 @@ namespace rerun::blueprint::archetypes { public: static constexpr const char IndicatorComponentName[] = - "rerun.blueprint.components.TableRowOrderIndicator"; + "rerun.blueprint.components.RangeTableSortIndicator"; /// 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; + RangeTableSort() = default; + RangeTableSort(RangeTableSort&& other) = default; /// The primary sort key. - TableRowOrder with_sort_key(rerun::blueprint::components::SortKey _sort_key) && { + RangeTableSort with_sort_key(rerun::blueprint::components::SortKey _sort_key) && { sort_key = std::move(_sort_key); // See: https://github.com/rerun-io/rerun/issues/4027 RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } /// The sort order. - TableRowOrder with_sort_order(rerun::blueprint::components::SortOrder _sort_order) && { + RangeTableSort 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);) @@ -60,10 +60,10 @@ namespace rerun { /// \private template <> - struct AsComponents { + struct AsComponents { /// Serialize all set component batches. static Result> serialize( - const blueprint::archetypes::TableRowOrder& archetype + const blueprint::archetypes::RangeTableSort& archetype ); }; } // namespace rerun diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes index e9b7ed7aca7c..9fe49eef26da 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes @@ -6,10 +6,10 @@ background.py linguist-generated=true container_blueprint.py linguist-generated=true panel_blueprint.py linguist-generated=true plot_legend.py linguist-generated=true +range_table_sort.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 7e0f853a0515..ee6b1fd8b526 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py @@ -6,10 +6,10 @@ from .container_blueprint import ContainerBlueprint from .panel_blueprint import PanelBlueprint from .plot_legend import PlotLegend +from .range_table_sort import RangeTableSort 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 @@ -22,10 +22,10 @@ "ContainerBlueprint", "PanelBlueprint", "PlotLegend", + "RangeTableSort", "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/range_table_sort.py similarity index 84% rename from rerun_py/rerun_sdk/rerun/blueprint/archetypes/table_row_order.py rename to rerun_py/rerun_sdk/rerun/blueprint/archetypes/range_table_sort.py index 95fa1f474ca0..3e52b9c159f5 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/table_row_order.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/range_table_sort.py @@ -1,7 +1,7 @@ # 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". +# Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_sort.fbs". -# You can extend this class by creating a "TableRowOrderExt" class in "table_row_order_ext.py". +# You can extend this class by creating a "RangeTableSortExt" class in "range_table_sort_ext.py". from __future__ import annotations @@ -15,11 +15,11 @@ from ...blueprint import components as blueprint_components from ...error_utils import catch_and_log_exceptions -__all__ = ["TableRowOrder"] +__all__ = ["RangeTableSort"] @define(str=False, repr=False, init=False) -class TableRowOrder(Archetype): +class RangeTableSort(Archetype): """**Archetype**: Configuration for the sorting of the rows of a time range table.""" def __init__( @@ -29,7 +29,7 @@ def __init__( sort_order: blueprint_components.SortOrderLike | None = None, ): """ - Create a new instance of the TableRowOrder archetype. + Create a new instance of the RangeTableSort archetype. Parameters ---------- @@ -40,7 +40,7 @@ def __init__( """ - # You can define your own __init__ function as a member of TableRowOrderExt in table_row_order_ext.py + # You can define your own __init__ function as a member of RangeTableSortExt in range_table_sort_ext.py with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(sort_key=sort_key, sort_order=sort_order) return @@ -54,8 +54,8 @@ def __attrs_clear__(self) -> None: ) @classmethod - def _clear(cls) -> TableRowOrder: - """Produce an empty TableRowOrder, bypassing `__init__`.""" + def _clear(cls) -> RangeTableSort: + """Produce an empty RangeTableSort, bypassing `__init__`.""" inst = cls.__new__(cls) inst.__attrs_clear__() return inst From 3df02c75e61b6aa2128b895aae1e61dd868f77ec Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 15 Jul 2024 14:56:05 +0200 Subject: [PATCH 17/17] Even moar renaming --- .../re_types/definitions/rerun/blueprint.fbs | 2 +- ...e_table_sort.fbs => range_table_order.fbs} | 2 +- .../src/blueprint/archetypes/.gitattributes | 2 +- .../re_types/src/blueprint/archetypes/mod.rs | 4 +- ...nge_table_sort.rs => range_table_order.rs} | 38 +++++++++---------- .../src/space_view_class.rs | 6 +-- crates/viewer/re_viewer/src/reflection/mod.rs | 4 +- rerun_cpp/src/rerun/blueprint/archetypes.hpp | 2 +- .../rerun/blueprint/archetypes/.gitattributes | 4 +- ...e_table_sort.cpp => range_table_order.cpp} | 10 ++--- ...e_table_sort.hpp => range_table_order.hpp} | 18 ++++----- .../rerun/blueprint/archetypes/.gitattributes | 2 +- .../rerun/blueprint/archetypes/__init__.py | 4 +- ...nge_table_sort.py => range_table_order.py} | 16 ++++---- 14 files changed, 57 insertions(+), 57 deletions(-) rename crates/store/re_types/definitions/rerun/blueprint/archetypes/{range_table_sort.fbs => range_table_order.fbs} (96%) rename crates/store/re_types/src/blueprint/archetypes/{range_table_sort.rs => range_table_order.rs} (85%) rename rerun_cpp/src/rerun/blueprint/archetypes/{range_table_sort.cpp => range_table_order.cpp} (83%) rename rerun_cpp/src/rerun/blueprint/archetypes/{range_table_sort.hpp => range_table_order.hpp} (77%) rename rerun_py/rerun_sdk/rerun/blueprint/archetypes/{range_table_sort.py => range_table_order.py} (84%) diff --git a/crates/store/re_types/definitions/rerun/blueprint.fbs b/crates/store/re_types/definitions/rerun/blueprint.fbs index 48d564c0bb8e..9a9ef17b3e15 100644 --- a/crates/store/re_types/definitions/rerun/blueprint.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint.fbs @@ -43,7 +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_sort.fbs"; +include "./blueprint/archetypes/range_table_order.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_sort.fbs b/crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_order.fbs similarity index 96% rename from crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_sort.fbs rename to crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_order.fbs index c15aa22f940f..7cdc8f0f377d 100644 --- a/crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_sort.fbs +++ b/crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_order.fbs @@ -8,7 +8,7 @@ namespace rerun.blueprint.archetypes; /// Configuration for the sorting of the rows of a time range table. -table RangeTableSort ( +table RangeTableOrder ( "attr.rerun.scope": "blueprint", "attr.rust.derive": "Copy", "attr.rust.generate_field_info" diff --git a/crates/store/re_types/src/blueprint/archetypes/.gitattributes b/crates/store/re_types/src/blueprint/archetypes/.gitattributes index 9934c12dbc75..ba0fa4bab5b8 100644 --- a/crates/store/re_types/src/blueprint/archetypes/.gitattributes +++ b/crates/store/re_types/src/blueprint/archetypes/.gitattributes @@ -4,7 +4,7 @@ background.rs linguist-generated=true mod.rs linguist-generated=true plot_legend.rs linguist-generated=true -range_table_sort.rs linguist-generated=true +range_table_order.rs linguist-generated=true scalar_axis.rs linguist-generated=true space_view_blueprint.rs linguist-generated=true space_view_contents.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 7a1ac644b9c6..dd60566e9a65 100644 --- a/crates/store/re_types/src/blueprint/archetypes/mod.rs +++ b/crates/store/re_types/src/blueprint/archetypes/mod.rs @@ -2,7 +2,7 @@ mod background; mod plot_legend; -mod range_table_sort; +mod range_table_order; mod scalar_axis; mod space_view_blueprint; mod space_view_contents; @@ -15,7 +15,7 @@ mod visual_bounds2d; pub use self::background::Background; pub use self::plot_legend::PlotLegend; -pub use self::range_table_sort::RangeTableSort; +pub use self::range_table_order::RangeTableOrder; pub use self::scalar_axis::ScalarAxis; pub use self::space_view_blueprint::SpaceViewBlueprint; pub use self::space_view_contents::SpaceViewContents; diff --git a/crates/store/re_types/src/blueprint/archetypes/range_table_sort.rs b/crates/store/re_types/src/blueprint/archetypes/range_table_order.rs similarity index 85% rename from crates/store/re_types/src/blueprint/archetypes/range_table_sort.rs rename to crates/store/re_types/src/blueprint/archetypes/range_table_order.rs index 1f2b715a6930..f153d095270e 100644 --- a/crates/store/re_types/src/blueprint/archetypes/range_table_sort.rs +++ b/crates/store/re_types/src/blueprint/archetypes/range_table_order.rs @@ -1,5 +1,5 @@ // 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_sort.fbs". +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_order.fbs". #![allow(unused_imports)] #![allow(unused_parens)] @@ -20,7 +20,7 @@ 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 RangeTableSort { +pub struct RangeTableOrder { /// The primary sort key. pub sort_key: Option, @@ -28,7 +28,7 @@ pub struct RangeTableSort { pub sort_order: Option, } -impl ::re_types_core::SizeBytes for RangeTableSort { +impl ::re_types_core::SizeBytes for RangeTableOrder { #[inline] fn heap_size_bytes(&self) -> u64 { self.sort_key.heap_size_bytes() + self.sort_order.heap_size_bytes() @@ -45,7 +45,7 @@ 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.RangeTableSortIndicator".into()]); + once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.RangeTableOrderIndicator".into()]); static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = once_cell::sync::Lazy::new(|| { @@ -58,36 +58,36 @@ static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 3usize]> = once_cell::sync::Lazy::new(|| { [ - "rerun.blueprint.components.RangeTableSortIndicator".into(), + "rerun.blueprint.components.RangeTableOrderIndicator".into(), "rerun.blueprint.components.SortKey".into(), "rerun.blueprint.components.SortOrder".into(), ] }); -impl RangeTableSort { +impl RangeTableOrder { /// The total number of components in the archetype: 0 required, 1 recommended, 2 optional pub const NUM_COMPONENTS: usize = 3usize; } -/// Indicator component for the [`RangeTableSort`] [`::re_types_core::Archetype`] -pub type RangeTableSortIndicator = ::re_types_core::GenericIndicatorComponent; +/// Indicator component for the [`RangeTableOrder`] [`::re_types_core::Archetype`] +pub type RangeTableOrderIndicator = ::re_types_core::GenericIndicatorComponent; -impl ::re_types_core::Archetype for RangeTableSort { - type Indicator = RangeTableSortIndicator; +impl ::re_types_core::Archetype for RangeTableOrder { + type Indicator = RangeTableOrderIndicator; #[inline] fn name() -> ::re_types_core::ArchetypeName { - "rerun.blueprint.archetypes.RangeTableSort".into() + "rerun.blueprint.archetypes.RangeTableOrder".into() } #[inline] fn display_name() -> &'static str { - "Range table sort" + "Range table order" } #[inline] fn indicator() -> MaybeOwnedComponentBatch<'static> { - static INDICATOR: RangeTableSortIndicator = RangeTableSortIndicator::DEFAULT; + static INDICATOR: RangeTableOrderIndicator = RangeTableOrderIndicator::DEFAULT; MaybeOwnedComponentBatch::Ref(&INDICATOR) } @@ -124,7 +124,7 @@ impl ::re_types_core::Archetype for RangeTableSort { let sort_key = if let Some(array) = arrays_by_name.get("rerun.blueprint.components.SortKey") { ::from_arrow_opt(&**array) - .with_context("rerun.blueprint.archetypes.RangeTableSort#sort_key")? + .with_context("rerun.blueprint.archetypes.RangeTableOrder#sort_key")? .into_iter() .next() .flatten() @@ -134,7 +134,7 @@ impl ::re_types_core::Archetype for RangeTableSort { let sort_order = if let Some(array) = arrays_by_name.get("rerun.blueprint.components.SortOrder") { ::from_arrow_opt(&**array) - .with_context("rerun.blueprint.archetypes.RangeTableSort#sort_order")? + .with_context("rerun.blueprint.archetypes.RangeTableOrder#sort_order")? .into_iter() .next() .flatten() @@ -148,7 +148,7 @@ impl ::re_types_core::Archetype for RangeTableSort { } } -impl ::re_types_core::AsComponents for RangeTableSort { +impl ::re_types_core::AsComponents for RangeTableOrder { fn as_component_batches(&self) -> Vec> { re_tracing::profile_function!(); use ::re_types_core::Archetype as _; @@ -167,10 +167,10 @@ impl ::re_types_core::AsComponents for RangeTableSort { } } -impl ::re_types_core::ArchetypeReflectionMarker for RangeTableSort {} +impl ::re_types_core::ArchetypeReflectionMarker for RangeTableOrder {} -impl RangeTableSort { - /// Create a new `RangeTableSort`. +impl RangeTableOrder { + /// Create a new `RangeTableOrder`. #[inline] pub fn new() -> Self { Self { 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 35f9dca1d392..f7cdd171e237 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 @@ -3,7 +3,7 @@ use egui::Ui; use re_log_types::EntityPath; use re_space_view::view_property_ui; use re_types::blueprint::{ - archetypes::RangeTableSort, + archetypes::RangeTableOrder, components::{SortKey, SortOrder}, }; use re_types_core::SpaceViewClassIdentifier; @@ -94,7 +94,7 @@ for all entities, it is preferable to override the view-level visible time range 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); + view_property_ui::(ctx, ui, space_view_id, self, state); }); Ok(()) @@ -110,7 +110,7 @@ for all entities, it is preferable to override the view-level visible time range ) -> Result<(), SpaceViewSystemExecutionError> { re_tracing::profile_function!(); - let row_order = ViewProperty::from_archetype::( + let row_order = ViewProperty::from_archetype::( ctx.blueprint_db(), ctx.blueprint_query, query.space_view_id, diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 3a7a3c1e4688..8e641ef4f81c 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -610,9 +610,9 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { }, ), ( - ArchetypeName::new("rerun.blueprint.archetypes.RangeTableSort"), + ArchetypeName::new("rerun.blueprint.archetypes.RangeTableOrder"), ArchetypeReflection { - display_name: "Range table sort", + display_name: "Range table order", docstring_md: "Configuration for the sorting of the rows of a time range table.", fields: vec![ ArchetypeFieldReflection { component_name : diff --git a/rerun_cpp/src/rerun/blueprint/archetypes.hpp b/rerun_cpp/src/rerun/blueprint/archetypes.hpp index 814a88aff6a8..fec6bca89b58 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes.hpp @@ -6,7 +6,7 @@ #include "blueprint/archetypes/container_blueprint.hpp" #include "blueprint/archetypes/panel_blueprint.hpp" #include "blueprint/archetypes/plot_legend.hpp" -#include "blueprint/archetypes/range_table_sort.hpp" +#include "blueprint/archetypes/range_table_order.hpp" #include "blueprint/archetypes/scalar_axis.hpp" #include "blueprint/archetypes/space_view_blueprint.hpp" #include "blueprint/archetypes/space_view_contents.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes index 6e0a948e2f17..9e6c38e48b63 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes @@ -9,8 +9,8 @@ panel_blueprint.cpp linguist-generated=true panel_blueprint.hpp linguist-generated=true plot_legend.cpp linguist-generated=true plot_legend.hpp linguist-generated=true -range_table_sort.cpp linguist-generated=true -range_table_sort.hpp linguist-generated=true +range_table_order.cpp linguist-generated=true +range_table_order.hpp linguist-generated=true scalar_axis.cpp linguist-generated=true scalar_axis.hpp linguist-generated=true space_view_blueprint.cpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/range_table_order.cpp similarity index 83% rename from rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.cpp rename to rerun_cpp/src/rerun/blueprint/archetypes/range_table_order.cpp index 8f2cc34c9061..ab6d81ed94cd 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.cpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/range_table_order.cpp @@ -1,7 +1,7 @@ // 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_sort.fbs". +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_order.fbs". -#include "range_table_sort.hpp" +#include "range_table_order.hpp" #include "../../collection_adapter_builtins.hpp" @@ -9,8 +9,8 @@ namespace rerun::blueprint::archetypes {} namespace rerun { - Result> AsComponents::serialize( - const blueprint::archetypes::RangeTableSort& archetype + Result> AsComponents::serialize( + const blueprint::archetypes::RangeTableOrder& archetype ) { using namespace blueprint::archetypes; std::vector cells; @@ -27,7 +27,7 @@ namespace rerun { cells.push_back(std::move(result.value)); } { - auto indicator = RangeTableSort::IndicatorComponent(); + auto indicator = RangeTableOrder::IndicatorComponent(); auto result = DataCell::from_loggable(indicator); RR_RETURN_NOT_OK(result.error); cells.emplace_back(std::move(result.value)); diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/range_table_order.hpp similarity index 77% rename from rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.hpp rename to rerun_cpp/src/rerun/blueprint/archetypes/range_table_order.hpp index 34390b314daa..6df4f71f285b 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/range_table_sort.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes/range_table_order.hpp @@ -1,5 +1,5 @@ // 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_sort.fbs". +// Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_order.fbs". #pragma once @@ -18,7 +18,7 @@ namespace rerun::blueprint::archetypes { /// **Archetype**: Configuration for the sorting of the rows of a time range table. - struct RangeTableSort { + struct RangeTableOrder { /// The primary sort key. std::optional sort_key; @@ -27,24 +27,24 @@ namespace rerun::blueprint::archetypes { public: static constexpr const char IndicatorComponentName[] = - "rerun.blueprint.components.RangeTableSortIndicator"; + "rerun.blueprint.components.RangeTableOrderIndicator"; /// Indicator component, used to identify the archetype when converting to a list of components. using IndicatorComponent = rerun::components::IndicatorComponent; public: - RangeTableSort() = default; - RangeTableSort(RangeTableSort&& other) = default; + RangeTableOrder() = default; + RangeTableOrder(RangeTableOrder&& other) = default; /// The primary sort key. - RangeTableSort with_sort_key(rerun::blueprint::components::SortKey _sort_key) && { + RangeTableOrder with_sort_key(rerun::blueprint::components::SortKey _sort_key) && { sort_key = std::move(_sort_key); // See: https://github.com/rerun-io/rerun/issues/4027 RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } /// The sort order. - RangeTableSort with_sort_order(rerun::blueprint::components::SortOrder _sort_order) && { + RangeTableOrder 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);) @@ -60,10 +60,10 @@ namespace rerun { /// \private template <> - struct AsComponents { + struct AsComponents { /// Serialize all set component batches. static Result> serialize( - const blueprint::archetypes::RangeTableSort& archetype + const blueprint::archetypes::RangeTableOrder& archetype ); }; } // namespace rerun diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes index 9fe49eef26da..1ca2967b2015 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes @@ -6,7 +6,7 @@ background.py linguist-generated=true container_blueprint.py linguist-generated=true panel_blueprint.py linguist-generated=true plot_legend.py linguist-generated=true -range_table_sort.py linguist-generated=true +range_table_order.py linguist-generated=true scalar_axis.py linguist-generated=true space_view_blueprint.py linguist-generated=true space_view_contents.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 ee6b1fd8b526..1af293c74ee6 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py @@ -6,7 +6,7 @@ from .container_blueprint import ContainerBlueprint from .panel_blueprint import PanelBlueprint from .plot_legend import PlotLegend -from .range_table_sort import RangeTableSort +from .range_table_order import RangeTableOrder from .scalar_axis import ScalarAxis from .space_view_blueprint import SpaceViewBlueprint from .space_view_contents import SpaceViewContents @@ -22,7 +22,7 @@ "ContainerBlueprint", "PanelBlueprint", "PlotLegend", - "RangeTableSort", + "RangeTableOrder", "ScalarAxis", "SpaceViewBlueprint", "SpaceViewContents", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/range_table_sort.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/range_table_order.py similarity index 84% rename from rerun_py/rerun_sdk/rerun/blueprint/archetypes/range_table_sort.py rename to rerun_py/rerun_sdk/rerun/blueprint/archetypes/range_table_order.py index 3e52b9c159f5..a1eb712e951a 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/range_table_sort.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/range_table_order.py @@ -1,7 +1,7 @@ # 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_sort.fbs". +# Based on "crates/store/re_types/definitions/rerun/blueprint/archetypes/range_table_order.fbs". -# You can extend this class by creating a "RangeTableSortExt" class in "range_table_sort_ext.py". +# You can extend this class by creating a "RangeTableOrderExt" class in "range_table_order_ext.py". from __future__ import annotations @@ -15,11 +15,11 @@ from ...blueprint import components as blueprint_components from ...error_utils import catch_and_log_exceptions -__all__ = ["RangeTableSort"] +__all__ = ["RangeTableOrder"] @define(str=False, repr=False, init=False) -class RangeTableSort(Archetype): +class RangeTableOrder(Archetype): """**Archetype**: Configuration for the sorting of the rows of a time range table.""" def __init__( @@ -29,7 +29,7 @@ def __init__( sort_order: blueprint_components.SortOrderLike | None = None, ): """ - Create a new instance of the RangeTableSort archetype. + Create a new instance of the RangeTableOrder archetype. Parameters ---------- @@ -40,7 +40,7 @@ def __init__( """ - # You can define your own __init__ function as a member of RangeTableSortExt in range_table_sort_ext.py + # You can define your own __init__ function as a member of RangeTableOrderExt in range_table_order_ext.py with catch_and_log_exceptions(context=self.__class__.__name__): self.__attrs_init__(sort_key=sort_key, sort_order=sort_order) return @@ -54,8 +54,8 @@ def __attrs_clear__(self) -> None: ) @classmethod - def _clear(cls) -> RangeTableSort: - """Produce an empty RangeTableSort, bypassing `__init__`.""" + def _clear(cls) -> RangeTableOrder: + """Produce an empty RangeTableOrder, bypassing `__init__`.""" inst = cls.__new__(cls) inst.__attrs_clear__() return inst