From 965d06376550ef6663d36556eed8f6cec752f111 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Fri, 19 Jan 2024 12:49:14 -0500 Subject: [PATCH] Introduce a TimeSeries archetype and use it to control the plot legend (#4867) ### What This is the basic pattern we expect to see for all of these view-configuration type tasks: - Add a new archetype / component - Add logic to the TimeSeries space-view-class implementation that both reads and writes the components directly from the blueprint store. This generally seems to be much easier to think about than dealing with the EntityProperties struct as this was handled previously as it's exclusively a contact between the TimeSeries archetype and the TimeSeriesSpaceView implementation. Open question: - Should we suffix all our view archetypes with something like `TimeSeriesView`? Needs https://github.com/rerun-io/rerun/pull/4609 to land first since I developed there before rebasing to main. Will be nice to come back and clean this up again once https://github.com/rerun-io/rerun/issues/3384 is done. ### Checklist * [x] I have read and agree to [Contributor Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and the [Code of Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md) * [x] I've included a screenshot or gif (if applicable) * [x] I have tested the web demo (if applicable): * Using newly built examples: [app.rerun.io](https://app.rerun.io/pr/4867/index.html) * Using examples from latest `main` build: [app.rerun.io](https://app.rerun.io/pr/4867/index.html?manifest_url=https://app.rerun.io/version/main/examples_manifest.json) * Using full set of examples from `nightly` build: [app.rerun.io](https://app.rerun.io/pr/4867/index.html?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json) * [x] The PR title and labels are set such as to maximize their usefulness for the next release's CHANGELOG - [PR Build Summary](https://build.rerun.io/pr/4867) - [Docs preview](https://rerun.io/preview/d76ed7714f29407bc1d4a62779bfa2894a10fa90/docs) - [Examples preview](https://rerun.io/preview/d76ed7714f29407bc1d4a62779bfa2894a10fa90/examples) - [Recent benchmark results](https://build.rerun.io/graphs/crates.html) - [Wasm size tracking](https://build.rerun.io/graphs/sizes.html) --- Cargo.lock | 2 + crates/re_space_view_time_series/Cargo.toml | 3 +- .../src/space_view_class.rs | 85 +++--- crates/re_types/Cargo.toml | 6 +- .../re_types/definitions/rerun/blueprint.fbs | 5 + .../blueprint/archetypes/time_series.fbs | 24 ++ .../rerun/blueprint/components/legend.fbs | 18 ++ .../rerun/blueprint/datatypes/legend.fbs | 39 +++ .../src/blueprint/archetypes/.gitattributes | 1 + .../re_types/src/blueprint/archetypes/mod.rs | 2 + .../src/blueprint/archetypes/time_series.rs | 154 ++++++++++ .../src/blueprint/components/.gitattributes | 1 + .../src/blueprint/components/legend.rs | 144 ++++++++++ .../src/blueprint/components/legend_ext.rs | 54 ++++ .../re_types/src/blueprint/components/mod.rs | 3 + .../src/blueprint/datatypes/.gitattributes | 5 + .../src/blueprint/datatypes/legend.rs | 269 ++++++++++++++++++ .../re_types/src/blueprint/datatypes/mod.rs | 5 + crates/re_types/src/blueprint/mod.rs | 1 + .../src/blueprint/validation_gen/mod.rs | 2 + rerun_cpp/src/rerun/blueprint/.gitattributes | 1 + rerun_cpp/src/rerun/blueprint/archetypes.hpp | 1 + .../rerun/blueprint/archetypes/.gitattributes | 2 + .../blueprint/archetypes/time_series.cpp | 33 +++ .../blueprint/archetypes/time_series.hpp | 57 ++++ rerun_cpp/src/rerun/blueprint/components.hpp | 1 + .../rerun/blueprint/components/.gitattributes | 2 + .../src/rerun/blueprint/components/legend.cpp | 56 ++++ .../src/rerun/blueprint/components/legend.hpp | 63 ++++ rerun_cpp/src/rerun/blueprint/datatypes.hpp | 5 + .../rerun/blueprint/datatypes/.gitattributes | 5 + .../src/rerun/blueprint/datatypes/legend.cpp | 78 +++++ .../src/rerun/blueprint/datatypes/legend.hpp | 61 ++++ .../rerun/blueprint/archetypes/.gitattributes | 1 + .../rerun/blueprint/archetypes/__init__.py | 3 +- .../rerun/blueprint/archetypes/time_series.py | 61 ++++ .../rerun/blueprint/components/.gitattributes | 1 + .../rerun/blueprint/components/__init__.py | 4 + .../rerun/blueprint/components/legend.py | 28 ++ .../rerun/blueprint/datatypes/.gitattributes | 5 + .../rerun/blueprint/datatypes/__init__.py | 7 + .../rerun/blueprint/datatypes/legend.py | 91 ++++++ 42 files changed, 1353 insertions(+), 36 deletions(-) create mode 100644 crates/re_types/definitions/rerun/blueprint/archetypes/time_series.fbs create mode 100644 crates/re_types/definitions/rerun/blueprint/components/legend.fbs create mode 100644 crates/re_types/definitions/rerun/blueprint/datatypes/legend.fbs create mode 100644 crates/re_types/src/blueprint/archetypes/time_series.rs create mode 100644 crates/re_types/src/blueprint/components/legend.rs create mode 100644 crates/re_types/src/blueprint/components/legend_ext.rs create mode 100644 crates/re_types/src/blueprint/datatypes/.gitattributes create mode 100644 crates/re_types/src/blueprint/datatypes/legend.rs create mode 100644 crates/re_types/src/blueprint/datatypes/mod.rs create mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/time_series.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/archetypes/time_series.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/legend.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/components/legend.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes.hpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/legend.cpp create mode 100644 rerun_cpp/src/rerun/blueprint/datatypes/legend.hpp create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/archetypes/time_series.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/components/legend.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py create mode 100644 rerun_py/rerun_sdk/rerun/blueprint/datatypes/legend.py diff --git a/Cargo.lock b/Cargo.lock index 764f15808700..2dbbd8ea897b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5137,6 +5137,7 @@ dependencies = [ "re_data_store", "re_format", "re_log_types", + "re_query", "re_query_cache", "re_renderer", "re_space_view", @@ -5207,6 +5208,7 @@ dependencies = [ "bytemuck", "document-features", "ecolor", + "egui_plot", "glam", "half 2.3.1", "image", diff --git a/crates/re_space_view_time_series/Cargo.toml b/crates/re_space_view_time_series/Cargo.toml index 703b7a44c591..f3d4cb9ac562 100644 --- a/crates/re_space_view_time_series/Cargo.toml +++ b/crates/re_space_view_time_series/Cargo.toml @@ -19,11 +19,12 @@ all-features = true re_data_store.workspace = true re_format.workspace = true re_log_types.workspace = true +re_query.workspace = true re_query_cache.workspace = true re_renderer.workspace = true re_space_view.workspace = true re_tracing.workspace = true -re_types.workspace = true +re_types = { workspace = true, features = ["egui_plot"] } re_ui.workspace = true re_viewer_context.workspace = true diff --git a/crates/re_space_view_time_series/src/space_view_class.rs b/crates/re_space_view_time_series/src/space_view_class.rs index e2da0f966768..cf96a1b1d7c8 100644 --- a/crates/re_space_view_time_series/src/space_view_class.rs +++ b/crates/re_space_view_time_series/src/space_view_class.rs @@ -3,10 +3,9 @@ use egui_plot::{Legend, Line, Plot, Points}; use re_data_store::TimeType; use re_format::next_grid_tick_magnitude_ns; use re_log_types::{EntityPath, TimeZone}; +use re_query::query_archetype; use re_space_view::controls; -use re_viewer_context::external::re_entity_db::{ - EditableAutoValue, EntityProperties, LegendCorner, -}; +use re_viewer_context::external::re_entity_db::EntityProperties; use re_viewer_context::{ SpaceViewClass, SpaceViewClassRegistryError, SpaceViewId, SpaceViewState, SpaceViewSystemExecutionError, SystemExecutionOutput, ViewQuery, ViewerContext, @@ -39,6 +38,8 @@ impl SpaceViewState for TimeSeriesSpaceViewState { #[derive(Default)] pub struct TimeSeriesSpaceView; +const DEFAULT_LEGEND_CORNER: egui_plot::Corner = egui_plot::Corner::RightBottom; + impl SpaceViewClass for TimeSeriesSpaceView { type State = TimeSeriesSpaceViewState; @@ -99,54 +100,71 @@ impl SpaceViewClass for TimeSeriesSpaceView { ui: &mut egui::Ui, _state: &mut Self::State, _space_origin: &EntityPath, - _space_view_id: SpaceViewId, - root_entity_properties: &mut EntityProperties, + space_view_id: SpaceViewId, + _root_entity_properties: &mut EntityProperties, ) { + let re_types::blueprint::archetypes::TimeSeries { legend } = query_archetype( + ctx.store_context.blueprint.store(), + ctx.blueprint_query, + &space_view_id.as_entity_path(), + ) + .and_then(|arch| arch.to_archetype()) + .unwrap_or_default(); + ctx.re_ui .selection_grid(ui, "time_series_selection_ui") .show(ui, |ui| { ctx.re_ui.grid_left_hand_label(ui, "Legend"); ui.vertical(|ui| { - let mut selected = *root_entity_properties.show_legend.get(); - if ctx.re_ui.checkbox(ui, &mut selected, "Visible").changed() { - root_entity_properties.show_legend = - EditableAutoValue::UserEdited(selected); - } + let mut edit_legend = legend.clone(); - let mut corner = root_entity_properties - .legend_location - .unwrap_or(LegendCorner::RightBottom); + ctx.re_ui + .checkbox(ui, &mut edit_legend.0.visible, "Visible"); + + let mut corner = legend.corner().unwrap_or(DEFAULT_LEGEND_CORNER); egui::ComboBox::from_id_source("legend_corner") - .selected_text(corner.to_string()) + .selected_text(re_types::blueprint::components::Legend::to_str(corner)) .show_ui(ui, |ui| { ui.style_mut().wrap = Some(false); ui.set_min_width(64.0); ui.selectable_value( &mut corner, - LegendCorner::LeftTop, - LegendCorner::LeftTop.to_string(), + egui_plot::Corner::LeftTop, + re_types::blueprint::components::Legend::to_str( + egui_plot::Corner::LeftTop, + ), ); ui.selectable_value( &mut corner, - LegendCorner::RightTop, - LegendCorner::RightTop.to_string(), + egui_plot::Corner::RightTop, + re_types::blueprint::components::Legend::to_str( + egui_plot::Corner::RightTop, + ), ); ui.selectable_value( &mut corner, - LegendCorner::LeftBottom, - LegendCorner::LeftBottom.to_string(), + egui_plot::Corner::LeftBottom, + re_types::blueprint::components::Legend::to_str( + egui_plot::Corner::LeftBottom, + ), ); ui.selectable_value( &mut corner, - LegendCorner::RightBottom, - LegendCorner::RightBottom.to_string(), + egui_plot::Corner::RightBottom, + re_types::blueprint::components::Legend::to_str( + egui_plot::Corner::RightBottom, + ), ); }); - root_entity_properties.legend_location = Some(corner); + edit_legend.set_corner(corner); + + if legend != edit_legend { + ctx.save_blueprint_component(&space_view_id.as_entity_path(), edit_legend); + } }); ui.end_row(); }); @@ -157,12 +175,20 @@ impl SpaceViewClass for TimeSeriesSpaceView { ctx: &ViewerContext<'_>, ui: &mut egui::Ui, state: &mut Self::State, - root_entity_properties: &EntityProperties, + _root_entity_properties: &EntityProperties, _query: &ViewQuery<'_>, system_output: SystemExecutionOutput, ) -> Result<(), SpaceViewSystemExecutionError> { re_tracing::profile_function!(); + let re_types::blueprint::archetypes::TimeSeries { legend } = query_archetype( + ctx.store_context.blueprint.store(), + ctx.blueprint_query, + &_query.space_view_id.as_entity_path(), + ) + .and_then(|arch| arch.to_archetype()) + .unwrap_or_default(); + let (current_time, time_type, timeline) = { // Avoid holding the lock for long let time_ctrl = ctx.rec_cfg.time_ctrl.read(); @@ -219,15 +245,8 @@ impl SpaceViewClass for TimeSeriesSpaceView { ) }); - if *root_entity_properties.show_legend { - plot = plot.legend( - Legend::default().position( - root_entity_properties - .legend_location - .unwrap_or(LegendCorner::RightBottom) - .into(), - ), - ); + if legend.visible { + plot = plot.legend(Legend::default().position(DEFAULT_LEGEND_CORNER)); } if timeline.typ() == TimeType::Time { diff --git a/crates/re_types/Cargo.toml b/crates/re_types/Cargo.toml index 996de8cf2b1f..6d32e54cfbc8 100644 --- a/crates/re_types/Cargo.toml +++ b/crates/re_types/Cargo.toml @@ -23,7 +23,7 @@ features = ["all"] default = [] ## All features except `testing`. -all = ["ecolor", "glam", "image", "mint", "serde"] +all = ["ecolor", "egui_plot", "glam", "image", "mint", "serde"] ## Enables the `datagen` module, which exposes a number of tools for generating random data for ## tests and benchmarks. @@ -32,6 +32,9 @@ datagen = ["dep:rand"] ## Enable color conversions. ecolor = ["dep:ecolor"] +## Enable conversions to plot primitives +egui_plot = ["dep:egui_plot"] + ## Add support for some math operations using [`glam`](https://crates.io/crates/glam/). glam = ["dep:glam"] @@ -76,6 +79,7 @@ uuid = { workspace = true, features = ["serde", "v4", "js"] } # External (optional) ecolor = { workspace = true, optional = true } +egui_plot = { workspace = true, optional = true } glam = { workspace = true, optional = true } image = { workspace = true, optional = true, default-features = false } mint = { workspace = true, optional = true } diff --git a/crates/re_types/definitions/rerun/blueprint.fbs b/crates/re_types/definitions/rerun/blueprint.fbs index 24c9168abfad..7b545e76e361 100644 --- a/crates/re_types/definitions/rerun/blueprint.fbs +++ b/crates/re_types/definitions/rerun/blueprint.fbs @@ -20,6 +20,11 @@ include "./blueprint/components/space_view_origin.fbs"; include "./blueprint/components/viewport_layout.fbs"; include "./blueprint/components/visible.fbs"; +include "./blueprint/datatypes/legend.fbs"; +include "./blueprint/components/legend.fbs"; + include "./blueprint/archetypes/container_blueprint.fbs"; include "./blueprint/archetypes/space_view_blueprint.fbs"; include "./blueprint/archetypes/viewport_blueprint.fbs"; + +include "./blueprint/archetypes/time_series.fbs"; diff --git a/crates/re_types/definitions/rerun/blueprint/archetypes/time_series.fbs b/crates/re_types/definitions/rerun/blueprint/archetypes/time_series.fbs new file mode 100644 index 000000000000..3edbf7e29b0a --- /dev/null +++ b/crates/re_types/definitions/rerun/blueprint/archetypes/time_series.fbs @@ -0,0 +1,24 @@ +include "fbs/attributes.fbs"; +include "rust/attributes.fbs"; + +include "rerun/datatypes.fbs"; + +namespace rerun.blueprint.archetypes; + +// --- + +/// The configuration options for a `TimeSeries` `SpaceView`. +table TimeSeries ( + "attr.docs.unreleased", + "attr.rerun.scope": "blueprint", + "attr.rust.derive": "Default" +) { + // --- Required --- + + /// Configuration information for the legend + // TODO(jleibs): This should be optional, but we need at least one required component + legend: rerun.blueprint.components.Legend ("attr.rerun.component_required", order: 1000); + + // --- Optional --- + +} diff --git a/crates/re_types/definitions/rerun/blueprint/components/legend.fbs b/crates/re_types/definitions/rerun/blueprint/components/legend.fbs new file mode 100644 index 000000000000..9fd55cf86259 --- /dev/null +++ b/crates/re_types/definitions/rerun/blueprint/components/legend.fbs @@ -0,0 +1,18 @@ +include "arrow/attributes.fbs"; +include "python/attributes.fbs"; +include "rust/attributes.fbs"; + +include "rerun/datatypes.fbs"; +include "rerun/attributes.fbs"; + +namespace rerun.blueprint.components; + +// --- + +/// Configuration for the legend of a plot. +table Legend ( + "attr.rerun.scope": "blueprint", + "attr.rust.derive": "PartialEq, Eq, PartialOrd, Ord" +) { + legend: rerun.blueprint.datatypes.Legend (order: 100); +} diff --git a/crates/re_types/definitions/rerun/blueprint/datatypes/legend.fbs b/crates/re_types/definitions/rerun/blueprint/datatypes/legend.fbs new file mode 100644 index 000000000000..6fc13e79b057 --- /dev/null +++ b/crates/re_types/definitions/rerun/blueprint/datatypes/legend.fbs @@ -0,0 +1,39 @@ +include "arrow/attributes.fbs"; +include "python/attributes.fbs"; +include "rust/attributes.fbs"; + +include "rerun/datatypes.fbs"; +include "rerun/attributes.fbs"; + +namespace rerun.blueprint.datatypes; + + +// TODO(#3384) +/* +enum LegendPosition: byte { + LeftTop = 1, + RightTop = 2, + LeftBottom = 3, + RightBottom = 4 +} +*/ + +// --- + +/// Configuration for the legend of a plot. +table Legend ( + "attr.rerun.scope": "blueprint", + "attr.rust.derive": "PartialEq, Eq, PartialOrd, Ord" +) { + /// Whether or not the legend should be displayed. + visible: bool (order: 100); + + /// Where should the legend be located. + /// + /// Allowed values: + /// - LeftTop = 1, + /// - RightTop = 2, + /// - LeftBottom = 3, + /// - RightBottom = 4 + location: ubyte (order: 200, nullable); +} diff --git a/crates/re_types/src/blueprint/archetypes/.gitattributes b/crates/re_types/src/blueprint/archetypes/.gitattributes index 11b286e6bcd1..5ab3bb584068 100644 --- a/crates/re_types/src/blueprint/archetypes/.gitattributes +++ b/crates/re_types/src/blueprint/archetypes/.gitattributes @@ -3,3 +3,4 @@ .gitattributes linguist-generated=true mod.rs linguist-generated=true space_view_blueprint.rs linguist-generated=true +time_series.rs linguist-generated=true diff --git a/crates/re_types/src/blueprint/archetypes/mod.rs b/crates/re_types/src/blueprint/archetypes/mod.rs index 9c012ed3f33b..995392a4b935 100644 --- a/crates/re_types/src/blueprint/archetypes/mod.rs +++ b/crates/re_types/src/blueprint/archetypes/mod.rs @@ -1,5 +1,7 @@ // DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/rust/api.rs mod space_view_blueprint; +mod time_series; pub use self::space_view_blueprint::SpaceViewBlueprint; +pub use self::time_series::TimeSeries; diff --git a/crates/re_types/src/blueprint/archetypes/time_series.rs b/crates/re_types/src/blueprint/archetypes/time_series.rs new file mode 100644 index 000000000000..6eb02477c29a --- /dev/null +++ b/crates/re_types/src/blueprint/archetypes/time_series.rs @@ -0,0 +1,154 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/re_types/definitions/rerun/blueprint/archetypes/time_series.fbs". + +#![allow(trivial_numeric_casts)] +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::iter_on_single_items)] +#![allow(clippy::map_flatten)] +#![allow(clippy::match_wildcard_for_single_variants)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] +#![allow(clippy::unnecessary_cast)] + +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**: The configuration options for a `TimeSeries` `SpaceView`. +#[derive(Clone, Debug, Default)] +pub struct TimeSeries { + /// Configuration information for the legend + pub legend: crate::blueprint::components::Legend, +} + +impl ::re_types_core::SizeBytes for TimeSeries { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.legend.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() + } +} + +static REQUIRED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.Legend".into()]); + +static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.blueprint.components.TimeSeriesIndicator".into()]); + +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.components.InstanceKey".into()]); + +static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 3usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.blueprint.components.Legend".into(), + "rerun.blueprint.components.TimeSeriesIndicator".into(), + "rerun.components.InstanceKey".into(), + ] + }); + +impl TimeSeries { + pub const NUM_COMPONENTS: usize = 3usize; +} + +/// Indicator component for the [`TimeSeries`] [`::re_types_core::Archetype`] +pub type TimeSeriesIndicator = ::re_types_core::GenericIndicatorComponent; + +impl ::re_types_core::Archetype for TimeSeries { + type Indicator = TimeSeriesIndicator; + + #[inline] + fn name() -> ::re_types_core::ArchetypeName { + "rerun.blueprint.archetypes.TimeSeries".into() + } + + #[inline] + fn indicator() -> MaybeOwnedComponentBatch<'static> { + static INDICATOR: TimeSeriesIndicator = TimeSeriesIndicator::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 legend = { + let array = arrays_by_name + .get("rerun.blueprint.components.Legend") + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.archetypes.TimeSeries#legend")?; + ::from_arrow_opt(&**array) + .with_context("rerun.blueprint.archetypes.TimeSeries#legend")? + .into_iter() + .next() + .flatten() + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.archetypes.TimeSeries#legend")? + }; + Ok(Self { legend }) + } +} + +impl ::re_types_core::AsComponents for TimeSeries { + fn as_component_batches(&self) -> Vec> { + re_tracing::profile_function!(); + use ::re_types_core::Archetype as _; + [ + Some(Self::indicator()), + Some((&self.legend as &dyn ComponentBatch).into()), + ] + .into_iter() + .flatten() + .collect() + } + + #[inline] + fn num_instances(&self) -> usize { + 1 + } +} + +impl TimeSeries { + pub fn new(legend: impl Into) -> Self { + Self { + legend: legend.into(), + } + } +} diff --git a/crates/re_types/src/blueprint/components/.gitattributes b/crates/re_types/src/blueprint/components/.gitattributes index e7f762809697..c44c19a94136 100644 --- a/crates/re_types/src/blueprint/components/.gitattributes +++ b/crates/re_types/src/blueprint/components/.gitattributes @@ -6,6 +6,7 @@ column_shares.rs linguist-generated=true entities_determined_by_user.rs linguist-generated=true included_contents.rs linguist-generated=true included_queries.rs linguist-generated=true +legend.rs linguist-generated=true mod.rs linguist-generated=true name.rs linguist-generated=true row_shares.rs linguist-generated=true diff --git a/crates/re_types/src/blueprint/components/legend.rs b/crates/re_types/src/blueprint/components/legend.rs new file mode 100644 index 000000000000..ada2b3dd8d26 --- /dev/null +++ b/crates/re_types/src/blueprint/components/legend.rs @@ -0,0 +1,144 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/re_types/definitions/rerun/blueprint/components/legend.fbs". + +#![allow(trivial_numeric_casts)] +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::iter_on_single_items)] +#![allow(clippy::map_flatten)] +#![allow(clippy::match_wildcard_for_single_variants)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] +#![allow(clippy::unnecessary_cast)] + +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**: Configuration for the legend of a plot. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Legend(pub crate::blueprint::datatypes::Legend); + +impl ::re_types_core::SizeBytes for Legend { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.0.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() + } +} + +impl> From for Legend { + fn from(v: T) -> Self { + Self(v.into()) + } +} + +impl std::borrow::Borrow for Legend { + #[inline] + fn borrow(&self) -> &crate::blueprint::datatypes::Legend { + &self.0 + } +} + +impl std::ops::Deref for Legend { + type Target = crate::blueprint::datatypes::Legend; + + #[inline] + fn deref(&self) -> &crate::blueprint::datatypes::Legend { + &self.0 + } +} + +::re_types_core::macros::impl_into_cow!(Legend); + +impl ::re_types_core::Loggable for Legend { + type Name = ::re_types_core::ComponentName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.components.Legend".into() + } + + #[allow(clippy::wildcard_imports)] + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + use arrow2::datatypes::*; + DataType::Struct(vec![ + Field { + name: "visible".to_owned(), + data_type: DataType::Boolean, + is_nullable: false, + metadata: [].into(), + }, + Field { + name: "location".to_owned(), + data_type: DataType::UInt8, + is_nullable: true, + metadata: [].into(), + }, + ]) + } + + #[allow(clippy::wildcard_imports)] + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + let (somes, data0): (Vec<_>, Vec<_>) = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + let datum = datum.map(|datum| { + let Self(data0) = datum.into_owned(); + data0 + }); + (datum.is_some(), datum) + }) + .unzip(); + let data0_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + { + _ = data0_bitmap; + crate::blueprint::datatypes::Legend::to_arrow_opt(data0)? + } + }) + } + + #[allow(clippy::wildcard_imports)] + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, buffer::*, datatypes::*}; + Ok( + crate::blueprint::datatypes::Legend::from_arrow_opt(arrow_data) + .with_context("rerun.blueprint.components.Legend#legend")? + .into_iter() + .map(|v| v.ok_or_else(DeserializationError::missing_data)) + .map(|res| res.map(|v| Some(Self(v)))) + .collect::>>>() + .with_context("rerun.blueprint.components.Legend#legend") + .with_context("rerun.blueprint.components.Legend")?, + ) + } +} diff --git a/crates/re_types/src/blueprint/components/legend_ext.rs b/crates/re_types/src/blueprint/components/legend_ext.rs new file mode 100644 index 000000000000..8afd6cf9482d --- /dev/null +++ b/crates/re_types/src/blueprint/components/legend_ext.rs @@ -0,0 +1,54 @@ +use super::Legend; + +impl Default for Legend { + fn default() -> Self { + Self(crate::blueprint::datatypes::Legend { + visible: true, + location: None, + }) + } +} + +#[cfg(feature = "egui_plot")] +fn egui_to_u8(corner: egui_plot::Corner) -> u8 { + match corner { + egui_plot::Corner::LeftTop => 1, + egui_plot::Corner::RightTop => 2, + egui_plot::Corner::LeftBottom => 3, + egui_plot::Corner::RightBottom => 4, + } +} + +#[cfg(feature = "egui_plot")] +fn u8_to_egui(corner: u8) -> Option { + match corner { + 1 => Some(egui_plot::Corner::LeftTop), + 2 => Some(egui_plot::Corner::RightTop), + 3 => Some(egui_plot::Corner::LeftBottom), + 4 => Some(egui_plot::Corner::RightBottom), + _ => { + re_log::warn_once!("Unknown legend corner value: {}", corner); + None + } + } +} + +#[cfg(feature = "egui_plot")] +impl Legend { + pub fn corner(&self) -> Option { + self.0.location.and_then(u8_to_egui) + } + + pub fn set_corner(&mut self, corner: egui_plot::Corner) { + self.0.location = Some(egui_to_u8(corner)); + } + + pub fn to_str(corner: egui_plot::Corner) -> &'static str { + match corner { + egui_plot::Corner::LeftTop => "Left Top", + egui_plot::Corner::RightTop => "Right Top", + egui_plot::Corner::LeftBottom => "Left Bottom", + egui_plot::Corner::RightBottom => "Right Bottom", + } + } +} diff --git a/crates/re_types/src/blueprint/components/mod.rs b/crates/re_types/src/blueprint/components/mod.rs index 6b305423499e..7d70d29c2497 100644 --- a/crates/re_types/src/blueprint/components/mod.rs +++ b/crates/re_types/src/blueprint/components/mod.rs @@ -5,6 +5,8 @@ mod column_shares; mod entities_determined_by_user; mod included_contents; mod included_queries; +mod legend; +mod legend_ext; mod name; mod name_ext; mod row_shares; @@ -18,6 +20,7 @@ pub use self::column_shares::ColumnShares; pub use self::entities_determined_by_user::EntitiesDeterminedByUser; pub use self::included_contents::IncludedContents; pub use self::included_queries::IncludedQueries; +pub use self::legend::Legend; pub use self::name::Name; pub use self::row_shares::RowShares; pub use self::space_view_class::SpaceViewClass; diff --git a/crates/re_types/src/blueprint/datatypes/.gitattributes b/crates/re_types/src/blueprint/datatypes/.gitattributes new file mode 100644 index 000000000000..f8cc2be56035 --- /dev/null +++ b/crates/re_types/src/blueprint/datatypes/.gitattributes @@ -0,0 +1,5 @@ +# DO NOT EDIT! This file is generated by crates/re_types_builder/src/lib.rs + +.gitattributes linguist-generated=true +legend.rs linguist-generated=true +mod.rs linguist-generated=true diff --git a/crates/re_types/src/blueprint/datatypes/legend.rs b/crates/re_types/src/blueprint/datatypes/legend.rs new file mode 100644 index 000000000000..b3f947bd003e --- /dev/null +++ b/crates/re_types/src/blueprint/datatypes/legend.rs @@ -0,0 +1,269 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/rust/api.rs +// Based on "crates/re_types/definitions/rerun/blueprint/datatypes/legend.fbs". + +#![allow(trivial_numeric_casts)] +#![allow(unused_imports)] +#![allow(unused_parens)] +#![allow(clippy::clone_on_copy)] +#![allow(clippy::iter_on_single_items)] +#![allow(clippy::map_flatten)] +#![allow(clippy::match_wildcard_for_single_variants)] +#![allow(clippy::needless_question_mark)] +#![allow(clippy::new_without_default)] +#![allow(clippy::redundant_closure)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::too_many_lines)] +#![allow(clippy::unnecessary_cast)] + +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}; + +/// **Datatype**: Configuration for the legend of a plot. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Legend { + /// Whether or not the legend should be displayed. + pub visible: bool, + + /// Where should the legend be located. + /// + /// Allowed values: + /// - LeftTop = 1, + /// - RightTop = 2, + /// - LeftBottom = 3, + /// - RightBottom = 4 + pub location: Option, +} + +impl ::re_types_core::SizeBytes for Legend { + #[inline] + fn heap_size_bytes(&self) -> u64 { + self.visible.heap_size_bytes() + self.location.heap_size_bytes() + } + + #[inline] + fn is_pod() -> bool { + ::is_pod() && >::is_pod() + } +} + +::re_types_core::macros::impl_into_cow!(Legend); + +impl ::re_types_core::Loggable for Legend { + type Name = ::re_types_core::DatatypeName; + + #[inline] + fn name() -> Self::Name { + "rerun.blueprint.datatypes.Legend".into() + } + + #[allow(clippy::wildcard_imports)] + #[inline] + fn arrow_datatype() -> arrow2::datatypes::DataType { + use arrow2::datatypes::*; + DataType::Struct(vec![ + Field { + name: "visible".to_owned(), + data_type: DataType::Boolean, + is_nullable: false, + metadata: [].into(), + }, + Field { + name: "location".to_owned(), + data_type: DataType::UInt8, + is_nullable: true, + metadata: [].into(), + }, + ]) + } + + #[allow(clippy::wildcard_imports)] + fn to_arrow_opt<'a>( + data: impl IntoIterator>>>, + ) -> SerializationResult> + where + Self: Clone + 'a, + { + use ::re_types_core::{Loggable as _, ResultExt as _}; + use arrow2::{array::*, datatypes::*}; + Ok({ + let (somes, data): (Vec<_>, Vec<_>) = data + .into_iter() + .map(|datum| { + let datum: Option<::std::borrow::Cow<'a, Self>> = datum.map(Into::into); + (datum.is_some(), datum) + }) + .unzip(); + let bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + StructArray::new( + ::arrow_datatype(), + vec![ + { + let (somes, visible): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum.as_ref().map(|datum| { + let Self { visible, .. } = &**datum; + visible.clone() + }); + (datum.is_some(), datum) + }) + .unzip(); + let visible_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + BooleanArray::new( + DataType::Boolean, + visible.into_iter().map(|v| v.unwrap_or_default()).collect(), + visible_bitmap, + ) + .boxed() + }, + { + let (somes, location): (Vec<_>, Vec<_>) = data + .iter() + .map(|datum| { + let datum = datum + .as_ref() + .map(|datum| { + let Self { location, .. } = &**datum; + location.clone() + }) + .flatten(); + (datum.is_some(), datum) + }) + .unzip(); + let location_bitmap: Option = { + let any_nones = somes.iter().any(|some| !*some); + any_nones.then(|| somes.into()) + }; + PrimitiveArray::new( + DataType::UInt8, + location + .into_iter() + .map(|v| v.unwrap_or_default()) + .collect(), + location_bitmap, + ) + .boxed() + }, + ], + bitmap, + ) + .boxed() + }) + } + + #[allow(clippy::wildcard_imports)] + fn from_arrow_opt( + arrow_data: &dyn arrow2::array::Array, + ) -> DeserializationResult>> + where + Self: Sized, + { + 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(|| { + DeserializationError::datatype_mismatch( + DataType::Struct(vec![ + Field { + name: "visible".to_owned(), + data_type: DataType::Boolean, + is_nullable: false, + metadata: [].into(), + }, + Field { + name: "location".to_owned(), + data_type: DataType::UInt8, + is_nullable: true, + metadata: [].into(), + }, + ]), + arrow_data.data_type().clone(), + ) + }) + .with_context("rerun.blueprint.datatypes.Legend")?; + if arrow_data.is_empty() { + Vec::new() + } else { + let (arrow_data_fields, arrow_data_arrays) = + (arrow_data.fields(), arrow_data.values()); + let arrays_by_name: ::std::collections::HashMap<_, _> = arrow_data_fields + .iter() + .map(|field| field.name.as_str()) + .zip(arrow_data_arrays) + .collect(); + let visible = { + if !arrays_by_name.contains_key("visible") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "visible", + )) + .with_context("rerun.blueprint.datatypes.Legend"); + } + let arrow_data = &**arrays_by_name["visible"]; + arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + DeserializationError::datatype_mismatch( + DataType::Boolean, + arrow_data.data_type().clone(), + ) + }) + .with_context("rerun.blueprint.datatypes.Legend#visible")? + .into_iter() + }; + let location = { + if !arrays_by_name.contains_key("location") { + return Err(DeserializationError::missing_struct_field( + Self::arrow_datatype(), + "location", + )) + .with_context("rerun.blueprint.datatypes.Legend"); + } + let arrow_data = &**arrays_by_name["location"]; + arrow_data + .as_any() + .downcast_ref::() + .ok_or_else(|| { + DeserializationError::datatype_mismatch( + DataType::UInt8, + arrow_data.data_type().clone(), + ) + }) + .with_context("rerun.blueprint.datatypes.Legend#location")? + .into_iter() + .map(|opt| opt.copied()) + }; + arrow2::bitmap::utils::ZipValidity::new_with_validity( + ::itertools::izip!(visible, location), + arrow_data.validity(), + ) + .map(|opt| { + opt.map(|(visible, location)| { + Ok(Self { + visible: visible + .ok_or_else(DeserializationError::missing_data) + .with_context("rerun.blueprint.datatypes.Legend#visible")?, + location, + }) + }) + .transpose() + }) + .collect::>>() + .with_context("rerun.blueprint.datatypes.Legend")? + } + }) + } +} diff --git a/crates/re_types/src/blueprint/datatypes/mod.rs b/crates/re_types/src/blueprint/datatypes/mod.rs new file mode 100644 index 000000000000..af61829b13e1 --- /dev/null +++ b/crates/re_types/src/blueprint/datatypes/mod.rs @@ -0,0 +1,5 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/rust/api.rs + +mod legend; + +pub use self::legend::Legend; diff --git a/crates/re_types/src/blueprint/mod.rs b/crates/re_types/src/blueprint/mod.rs index ef5235cbb6a6..928ed41f1340 100644 --- a/crates/re_types/src/blueprint/mod.rs +++ b/crates/re_types/src/blueprint/mod.rs @@ -1,2 +1,3 @@ pub mod archetypes; pub mod components; +pub mod datatypes; diff --git a/crates/re_viewer/src/blueprint/validation_gen/mod.rs b/crates/re_viewer/src/blueprint/validation_gen/mod.rs index acac706fa25a..32dd7dde00e1 100644 --- a/crates/re_viewer/src/blueprint/validation_gen/mod.rs +++ b/crates/re_viewer/src/blueprint/validation_gen/mod.rs @@ -9,6 +9,7 @@ pub use re_types::blueprint::components::ColumnShares; pub use re_types::blueprint::components::EntitiesDeterminedByUser; pub use re_types::blueprint::components::IncludedContents; pub use re_types::blueprint::components::IncludedQueries; +pub use re_types::blueprint::components::Legend; pub use re_types::blueprint::components::Name; pub use re_types::blueprint::components::RowShares; pub use re_types::blueprint::components::SpaceViewClass; @@ -38,6 +39,7 @@ 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) diff --git a/rerun_cpp/src/rerun/blueprint/.gitattributes b/rerun_cpp/src/rerun/blueprint/.gitattributes index 0661cd67c5ea..435e1f8fe40d 100644 --- a/rerun_cpp/src/rerun/blueprint/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/.gitattributes @@ -3,3 +3,4 @@ .gitattributes linguist-generated=true archetypes.hpp linguist-generated=true components.hpp linguist-generated=true +datatypes.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/archetypes.hpp b/rerun_cpp/src/rerun/blueprint/archetypes.hpp index 2fa36ec2f74e..0e592c623991 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes.hpp +++ b/rerun_cpp/src/rerun/blueprint/archetypes.hpp @@ -4,4 +4,5 @@ #include "blueprint/archetypes/container_blueprint.hpp" #include "blueprint/archetypes/space_view_blueprint.hpp" +#include "blueprint/archetypes/time_series.hpp" #include "blueprint/archetypes/viewport_blueprint.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes index 754c9696a8f4..f5a5daaf2bf6 100644 --- a/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/archetypes/.gitattributes @@ -5,5 +5,7 @@ container_blueprint.cpp linguist-generated=true container_blueprint.hpp linguist-generated=true space_view_blueprint.cpp linguist-generated=true space_view_blueprint.hpp linguist-generated=true +time_series.cpp linguist-generated=true +time_series.hpp linguist-generated=true viewport_blueprint.cpp linguist-generated=true viewport_blueprint.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/archetypes/time_series.cpp b/rerun_cpp/src/rerun/blueprint/archetypes/time_series.cpp new file mode 100644 index 000000000000..a2047a633726 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/archetypes/time_series.cpp @@ -0,0 +1,33 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/re_types/definitions/rerun/blueprint/archetypes/time_series.fbs". + +#include "time_series.hpp" + +#include "../../collection_adapter_builtins.hpp" + +namespace rerun::blueprint::archetypes {} + +namespace rerun { + + Result> AsComponents::serialize( + const blueprint::archetypes::TimeSeries& archetype + ) { + using namespace blueprint::archetypes; + std::vector cells; + cells.reserve(2); + + { + auto result = DataCell::from_loggable(archetype.legend); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + { + auto indicator = TimeSeries::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/time_series.hpp b/rerun_cpp/src/rerun/blueprint/archetypes/time_series.hpp new file mode 100644 index 000000000000..2ffa1231241f --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/archetypes/time_series.hpp @@ -0,0 +1,57 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/re_types/definitions/rerun/blueprint/archetypes/time_series.fbs". + +#pragma once + +#include "../../blueprint/components/legend.hpp" +#include "../../collection.hpp" +#include "../../data_cell.hpp" +#include "../../indicator_component.hpp" +#include "../../result.hpp" + +#include +#include +#include + +namespace rerun::blueprint::archetypes { + /// **Archetype**: The configuration options for a `TimeSeries` `SpaceView`. + struct TimeSeries { + /// Configuration information for the legend + rerun::blueprint::components::Legend legend; + + public: + static constexpr const char IndicatorComponentName[] = + "rerun.blueprint.components.TimeSeriesIndicator"; + + /// Indicator component, used to identify the archetype when converting to a list of components. + using IndicatorComponent = rerun::components::IndicatorComponent; + + public: + TimeSeries() = default; + TimeSeries(TimeSeries&& other) = default; + + explicit TimeSeries(rerun::blueprint::components::Legend _legend) + : legend(std::move(_legend)) {} + + /// Returns the number of primary instances of this archetype. + size_t num_instances() const { + return 1; + } + }; + +} // 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::TimeSeries& archetype + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components.hpp b/rerun_cpp/src/rerun/blueprint/components.hpp index a827e756119f..0c43d757e0d8 100644 --- a/rerun_cpp/src/rerun/blueprint/components.hpp +++ b/rerun_cpp/src/rerun/blueprint/components.hpp @@ -13,6 +13,7 @@ #include "blueprint/components/included_contents.hpp" #include "blueprint/components/included_queries.hpp" #include "blueprint/components/included_space_views.hpp" +#include "blueprint/components/legend.hpp" #include "blueprint/components/name.hpp" #include "blueprint/components/panel_view.hpp" #include "blueprint/components/query_expressions.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/components/.gitattributes b/rerun_cpp/src/rerun/blueprint/components/.gitattributes index 5b70d6e9a060..b93e6ca0593e 100644 --- a/rerun_cpp/src/rerun/blueprint/components/.gitattributes +++ b/rerun_cpp/src/rerun/blueprint/components/.gitattributes @@ -23,6 +23,8 @@ included_queries.cpp linguist-generated=true included_queries.hpp linguist-generated=true included_space_views.cpp linguist-generated=true included_space_views.hpp linguist-generated=true +legend.cpp linguist-generated=true +legend.hpp linguist-generated=true name.cpp linguist-generated=true name.hpp linguist-generated=true panel_view.cpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/components/legend.cpp b/rerun_cpp/src/rerun/blueprint/components/legend.cpp new file mode 100644 index 000000000000..2d6ab2803149 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/legend.cpp @@ -0,0 +1,56 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/re_types/definitions/rerun/blueprint/components/legend.fbs". + +#include "legend.hpp" + +#include "../../blueprint/datatypes/legend.hpp" + +#include +#include + +namespace rerun::blueprint::components {} + +namespace rerun { + const std::shared_ptr& Loggable::arrow_datatype( + ) { + static const auto datatype = + Loggable::arrow_datatype(); + return datatype; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::components::Legend* elements, + size_t num_elements + ) { + static_assert( + sizeof(rerun::blueprint::datatypes::Legend) == sizeof(blueprint::components::Legend) + ); + RR_RETURN_NOT_OK(Loggable::fill_arrow_array_builder( + builder, + reinterpret_cast(elements), + num_elements + )); + + return Error::ok(); + } + + Result> Loggable::to_arrow( + const blueprint::components::Legend* 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; + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/components/legend.hpp b/rerun_cpp/src/rerun/blueprint/components/legend.hpp new file mode 100644 index 000000000000..00c113c643da --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/components/legend.hpp @@ -0,0 +1,63 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/re_types/definitions/rerun/blueprint/components/legend.fbs". + +#pragma once + +#include "../../blueprint/datatypes/legend.hpp" +#include "../../result.hpp" + +#include +#include + +namespace arrow { + class Array; + class DataType; + class StructBuilder; +} // namespace arrow + +namespace rerun::blueprint::components { + /// **Component**: Configuration for the legend of a plot. + struct Legend { + rerun::blueprint::datatypes::Legend legend; + + public: + Legend() = default; + + Legend(rerun::blueprint::datatypes::Legend legend_) : legend(legend_) {} + + Legend& operator=(rerun::blueprint::datatypes::Legend legend_) { + legend = legend_; + return *this; + } + + /// Cast to the underlying Legend datatype + operator rerun::blueprint::datatypes::Legend() const { + return legend; + } + }; +} // namespace rerun::blueprint::components + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.components.Legend"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::components::Legend* elements, + size_t num_elements + ); + + /// Serializes an array of `rerun::blueprint:: components::Legend` into an arrow array. + static Result> to_arrow( + const blueprint::components::Legend* instances, size_t num_instances + ); + }; +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/datatypes.hpp b/rerun_cpp/src/rerun/blueprint/datatypes.hpp new file mode 100644 index 000000000000..9647dd422476 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes.hpp @@ -0,0 +1,5 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs + +#pragma once + +#include "blueprint/datatypes/legend.hpp" diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes b/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes new file mode 100644 index 000000000000..da03d4b96e87 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/.gitattributes @@ -0,0 +1,5 @@ +# DO NOT EDIT! This file is generated by crates/re_types_builder/src/lib.rs + +.gitattributes linguist-generated=true +legend.cpp linguist-generated=true +legend.hpp linguist-generated=true diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/legend.cpp b/rerun_cpp/src/rerun/blueprint/datatypes/legend.cpp new file mode 100644 index 000000000000..948dd620e8bc --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/legend.cpp @@ -0,0 +1,78 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/re_types/definitions/rerun/blueprint/datatypes/legend.fbs". + +#include "legend.hpp" + +#include +#include + +namespace rerun::blueprint::datatypes {} + +namespace rerun { + const std::shared_ptr& Loggable::arrow_datatype( + ) { + static const auto datatype = arrow::struct_({ + arrow::field("visible", arrow::boolean(), false), + arrow::field("location", arrow::uint8(), true), + }); + return datatype; + } + + rerun::Error Loggable::fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::datatypes::Legend* 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." + ); + } + + { + auto field_builder = static_cast(builder->field_builder(0)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + ARROW_RETURN_NOT_OK(field_builder->Append(elements[elem_idx].visible)); + } + } + { + auto field_builder = static_cast(builder->field_builder(1)); + ARROW_RETURN_NOT_OK(field_builder->Reserve(static_cast(num_elements))); + for (size_t elem_idx = 0; elem_idx < num_elements; elem_idx += 1) { + const auto& element = elements[elem_idx]; + if (element.location.has_value()) { + ARROW_RETURN_NOT_OK(field_builder->Append(element.location.value())); + } else { + ARROW_RETURN_NOT_OK(field_builder->AppendNull()); + } + } + } + ARROW_RETURN_NOT_OK(builder->AppendValues(static_cast(num_elements), nullptr)); + + return Error::ok(); + } + + Result> Loggable::to_arrow( + const blueprint::datatypes::Legend* 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; + } +} // namespace rerun diff --git a/rerun_cpp/src/rerun/blueprint/datatypes/legend.hpp b/rerun_cpp/src/rerun/blueprint/datatypes/legend.hpp new file mode 100644 index 000000000000..b8efd53df620 --- /dev/null +++ b/rerun_cpp/src/rerun/blueprint/datatypes/legend.hpp @@ -0,0 +1,61 @@ +// DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/cpp/mod.rs +// Based on "crates/re_types/definitions/rerun/blueprint/datatypes/legend.fbs". + +#pragma once + +#include "../../result.hpp" + +#include +#include +#include + +namespace arrow { + class Array; + class DataType; + class StructBuilder; +} // namespace arrow + +namespace rerun::blueprint::datatypes { + /// **Datatype**: Configuration for the legend of a plot. + struct Legend { + /// Whether or not the legend should be displayed. + bool visible; + + /// Where should the legend be located. + /// + /// Allowed values: + /// - LeftTop = 1, + /// - RightTop = 2, + /// - LeftBottom = 3, + /// - RightBottom = 4 + std::optional location; + + public: + Legend() = default; + }; +} // namespace rerun::blueprint::datatypes + +namespace rerun { + template + struct Loggable; + + /// \private + template <> + struct Loggable { + static constexpr const char Name[] = "rerun.blueprint.datatypes.Legend"; + + /// Returns the arrow data type this type corresponds to. + static const std::shared_ptr& arrow_datatype(); + + /// Fills an arrow array builder with an array of this type. + static rerun::Error fill_arrow_array_builder( + arrow::StructBuilder* builder, const blueprint::datatypes::Legend* elements, + size_t num_elements + ); + + /// Serializes an array of `rerun::blueprint:: datatypes::Legend` into an arrow array. + static Result> to_arrow( + const blueprint::datatypes::Legend* instances, size_t num_instances + ); + }; +} // namespace rerun diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes index 06050cb8aaf6..5bfdc50d9ab8 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/.gitattributes @@ -4,4 +4,5 @@ __init__.py linguist-generated=true container_blueprint.py linguist-generated=true space_view_blueprint.py linguist-generated=true +time_series.py linguist-generated=true viewport_blueprint.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 bbf0b2babe16..f66f7da38eea 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/__init__.py @@ -4,6 +4,7 @@ from .container_blueprint import ContainerBlueprint from .space_view_blueprint import SpaceViewBlueprint +from .time_series import TimeSeries from .viewport_blueprint import ViewportBlueprint -__all__ = ["ContainerBlueprint", "SpaceViewBlueprint", "ViewportBlueprint"] +__all__ = ["ContainerBlueprint", "SpaceViewBlueprint", "TimeSeries", "ViewportBlueprint"] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/archetypes/time_series.py b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/time_series.py new file mode 100644 index 000000000000..f7b037f403d0 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/archetypes/time_series.py @@ -0,0 +1,61 @@ +# DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/python.rs +# Based on "crates/re_types/definitions/rerun/blueprint/archetypes/time_series.fbs". + +# You can extend this class by creating a "TimeSeriesExt" class in "time_series_ext.py". + +from __future__ import annotations + +from typing import Any + +from attrs import define, field + +from ..._baseclasses import Archetype +from ...error_utils import catch_and_log_exceptions +from .. import components, datatypes + +__all__ = ["TimeSeries"] + + +@define(str=False, repr=False, init=False) +class TimeSeries(Archetype): + """**Archetype**: The configuration options for a `TimeSeries` `SpaceView`.""" + + def __init__(self: Any, legend: datatypes.LegendLike): + """ + Create a new instance of the TimeSeries archetype. + + Parameters + ---------- + legend: + Configuration information for the legend + """ + + # You can define your own __init__ function as a member of TimeSeriesExt in time_series_ext.py + with catch_and_log_exceptions(context=self.__class__.__name__): + self.__attrs_init__(legend=legend) + return + self.__attrs_clear__() + + def __attrs_clear__(self) -> None: + """Convenience method for calling `__attrs_init__` with all `None`s.""" + self.__attrs_init__( + legend=None, # type: ignore[arg-type] + ) + + @classmethod + def _clear(cls) -> TimeSeries: + """Produce an empty TimeSeries, bypassing `__init__`.""" + inst = cls.__new__(cls) + inst.__attrs_clear__() + return inst + + legend: components.LegendBatch = field( + metadata={"component": "required"}, + converter=components.LegendBatch._required, # type: ignore[misc] + ) + # Configuration information for the legend + # + # (Docstring intentionally commented out to hide this field from the docs) + + __str__ = Archetype.__str__ + __repr__ = Archetype.__repr__ diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes index be4c516ac230..62b753c03a50 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/.gitattributes @@ -13,6 +13,7 @@ grid_columns.py linguist-generated=true included_contents.py linguist-generated=true included_queries.py linguist-generated=true included_space_views.py linguist-generated=true +legend.py linguist-generated=true name.py linguist-generated=true panel_view.py linguist-generated=true query_expressions.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 f8b71604a5ae..630065f31da8 100644 --- a/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/__init__.py @@ -55,6 +55,7 @@ IncludedSpaceViewsLike, IncludedSpaceViewsType, ) +from .legend import Legend, LegendBatch, LegendType from .name import Name, NameArrayLike, NameBatch, NameLike, NameType from .panel_view import PanelView, PanelViewArrayLike, PanelViewBatch, PanelViewLike, PanelViewType from .query_expressions import ( @@ -138,6 +139,9 @@ "IncludedSpaceViewsBatch", "IncludedSpaceViewsLike", "IncludedSpaceViewsType", + "Legend", + "LegendBatch", + "LegendType", "Name", "NameArrayLike", "NameBatch", diff --git a/rerun_py/rerun_sdk/rerun/blueprint/components/legend.py b/rerun_py/rerun_sdk/rerun/blueprint/components/legend.py new file mode 100644 index 000000000000..fd9f962292dd --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/components/legend.py @@ -0,0 +1,28 @@ +# DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/python.rs +# Based on "crates/re_types/definitions/rerun/blueprint/components/legend.fbs". + +# You can extend this class by creating a "LegendExt" class in "legend_ext.py". + +from __future__ import annotations + +from ..._baseclasses import ComponentBatchMixin +from .. import datatypes + +__all__ = ["Legend", "LegendBatch", "LegendType"] + + +class Legend(datatypes.Legend): + """**Component**: Configuration for the legend of a plot.""" + + # You can define your own __init__ function as a member of LegendExt in legend_ext.py + + # Note: there are no fields here because Legend delegates to datatypes.Legend + pass + + +class LegendType(datatypes.LegendType): + _TYPE_NAME: str = "rerun.blueprint.components.Legend" + + +class LegendBatch(datatypes.LegendBatch, ComponentBatchMixin): + _ARROW_TYPE = LegendType() diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes new file mode 100644 index 000000000000..d7d100d86518 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/.gitattributes @@ -0,0 +1,5 @@ +# DO NOT EDIT! This file is generated by crates/re_types_builder/src/lib.rs + +.gitattributes linguist-generated=true +__init__.py linguist-generated=true +legend.py linguist-generated=true diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py new file mode 100644 index 000000000000..e18ca0758275 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/__init__.py @@ -0,0 +1,7 @@ +# DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/python.rs + +from __future__ import annotations + +from .legend import Legend, LegendArrayLike, LegendBatch, LegendLike, LegendType + +__all__ = ["Legend", "LegendArrayLike", "LegendBatch", "LegendLike", "LegendType"] diff --git a/rerun_py/rerun_sdk/rerun/blueprint/datatypes/legend.py b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/legend.py new file mode 100644 index 000000000000..6b7be3057241 --- /dev/null +++ b/rerun_py/rerun_sdk/rerun/blueprint/datatypes/legend.py @@ -0,0 +1,91 @@ +# DO NOT EDIT! This file was auto-generated by crates/re_types_builder/src/codegen/python.rs +# Based on "crates/re_types/definitions/rerun/blueprint/datatypes/legend.fbs". + +# You can extend this class by creating a "LegendExt" class in "legend_ext.py". + +from __future__ import annotations + +from typing import Any, Sequence, Union + +import pyarrow as pa +from attrs import define, field + +from ..._baseclasses import BaseBatch, BaseExtensionType +from ..._converters import ( + int_or_none, +) + +__all__ = ["Legend", "LegendArrayLike", "LegendBatch", "LegendLike", "LegendType"] + + +@define(init=False) +class Legend: + """**Datatype**: Configuration for the legend of a plot.""" + + def __init__(self: Any, visible: bool, location: int | None = None): + """ + Create a new instance of the Legend datatype. + + Parameters + ---------- + visible: + Whether or not the legend should be displayed. + location: + Where should the legend be located. + + Allowed values: + - LeftTop = 1, + - RightTop = 2, + - LeftBottom = 3, + - RightBottom = 4 + """ + + # You can define your own __init__ function as a member of LegendExt in legend_ext.py + self.__attrs_init__(visible=visible, location=location) + + visible: bool = field(converter=bool) + # Whether or not the legend should be displayed. + # + # (Docstring intentionally commented out to hide this field from the docs) + + location: int | None = field(default=None, converter=int_or_none) + # Where should the legend be located. + # + # Allowed values: + # - LeftTop = 1, + # - RightTop = 2, + # - LeftBottom = 3, + # - RightBottom = 4 + # + # (Docstring intentionally commented out to hide this field from the docs) + + +LegendLike = Legend +LegendArrayLike = Union[ + Legend, + Sequence[LegendLike], +] + + +class LegendType(BaseExtensionType): + _TYPE_NAME: str = "rerun.blueprint.datatypes.Legend" + + def __init__(self) -> None: + pa.ExtensionType.__init__( + self, + pa.struct( + [ + pa.field("visible", pa.bool_(), nullable=False, metadata={}), + pa.field("location", pa.uint8(), nullable=True, metadata={}), + ] + ), + self._TYPE_NAME, + ) + + +class LegendBatch(BaseBatch[LegendArrayLike]): + _ARROW_TYPE = LegendType() + + @staticmethod + def _native_to_pa_array(data: LegendArrayLike, data_type: pa.DataType) -> pa.Array: + raise NotImplementedError # You need to implement native_to_pa_array_override in legend_ext.py