re_view_tensor 0.31.0-rc.2

A view dedicated to visualizing tensors with arbitrary dimensionality.
Documentation
use re_chunk_store::{LatestAtQuery, RowId};
use re_sdk_types::Archetype as _;
use re_sdk_types::archetypes::Tensor;
use re_sdk_types::components::{TensorData, ValueRange};
use re_view::latest_at_with_blueprint_resolved_data;
use re_viewer_context::{
    IdentifiedViewSystem, ViewContext, ViewContextCollection, ViewQuery, ViewSystemExecutionError,
    VisualizerExecutionOutput, VisualizerQueryInfo, VisualizerSystem, typed_fallback_for,
};

#[derive(Clone)]
pub struct TensorVisualization {
    pub tensor_row_id: RowId,
    pub tensor: TensorData,
    pub data_range: ValueRange,
}

#[derive(Default)]
pub struct TensorSystem {
    pub tensors: Vec<TensorVisualization>,
}

impl IdentifiedViewSystem for TensorSystem {
    fn identifier() -> re_viewer_context::ViewSystemIdentifier {
        "Tensor".into()
    }
}

impl VisualizerSystem for TensorSystem {
    fn visualizer_query_info(
        &self,
        _app_options: &re_viewer_context::AppOptions,
    ) -> VisualizerQueryInfo {
        VisualizerQueryInfo::single_required_component::<TensorData>(
            &Tensor::descriptor_data(),
            &Tensor::all_components(),
        )
    }

    fn execute(
        &mut self,
        ctx: &ViewContext<'_>,
        query: &ViewQuery<'_>,
        _context_systems: &ViewContextCollection,
    ) -> Result<VisualizerExecutionOutput, ViewSystemExecutionError> {
        re_tracing::profile_function!();

        let output = VisualizerExecutionOutput::default();

        for (data_result, instruction) in query.iter_visualizer_instruction_for(Self::identifier())
        {
            let timeline_query = LatestAtQuery::new(query.timeline, query.latest_at);

            let annotations = None;
            let latest_at_results = latest_at_with_blueprint_resolved_data(
                ctx,
                annotations,
                &timeline_query,
                data_result,
                Tensor::all_component_identifiers(),
                Some(instruction),
            );
            let results =
                re_view::BlueprintResolvedResults::from((timeline_query, latest_at_results));
            let results =
                re_view::VisualizerInstructionQueryResults::new(instruction, &results, &output);

            let all_tensor_chunks = results.iter_required(Tensor::descriptor_data().component);
            if all_tensor_chunks.is_empty() {
                continue;
            }

            let all_tensors_indexed = all_tensor_chunks.chunks().iter().flat_map(move |chunk| {
                chunk
                    .iter_component_indices(query.timeline)
                    .zip(chunk.iter_component::<TensorData>())
            });
            let all_ranges = results.iter_optional(Tensor::descriptor_value_range().component);

            for ((_, tensor_row_id), tensors, data_ranges) in
                re_query::range_zip_1x1(all_tensors_indexed, all_ranges.slice::<[f64; 2]>())
            {
                let Some(tensor) = tensors.first() else {
                    continue;
                };
                let data_range = data_ranges
                    .and_then(|ranges| {
                        ranges
                            .first()
                            .copied()
                            .map(|range| ValueRange(range.into()))
                    })
                    .unwrap_or_else(|| {
                        typed_fallback_for(
                            &ctx.query_context(
                                data_result,
                                query.latest_at_query(),
                                instruction.id,
                            ),
                            Tensor::descriptor_value_range().component,
                        )
                    });

                self.tensors.push(TensorVisualization {
                    tensor_row_id,
                    tensor: tensor.clone(),
                    data_range,
                });
            }
        }

        Ok(output)
    }
}