Skip to content

Commit

Permalink
Improved tensor view settings
Browse files Browse the repository at this point in the history
  • Loading branch information
Wumpf committed Feb 3, 2023
1 parent 767d341 commit 33fd7b0
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 123 deletions.
75 changes: 62 additions & 13 deletions crates/re_viewer/src/ui/data_ui/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@ use re_log_types::{
ClassicTensor,
};

use crate::misc::{caches::TensorImageView, ViewerContext};
use crate::misc::{
caches::{TensorImageView, TensorStats},
ViewerContext,
};

use super::{DataUi, UiVerbosity};

pub fn format_tensor_shape(shape: &[re_log_types::component_types::TensorDimension]) -> String {
pub fn format_tensor_shape_single_line(
shape: &[re_log_types::component_types::TensorDimension],
) -> String {
format!("[{}]", shape.iter().join(", "))
}

Expand All @@ -35,6 +40,7 @@ impl DataUi for ClassicTensor {
_query: &re_arrow_store::LatestAtQuery,
) {
let tensor_view = ctx.cache.image.get_view(self, ctx.render_ctx);
let tensor_stats = ctx.cache.tensor_stats.get(&self.id());

match verbosity {
UiVerbosity::Small | UiVerbosity::MaxHeight(_) => {
Expand All @@ -55,16 +61,16 @@ impl DataUi for ClassicTensor {
ui.label(format!(
"{} x {}",
self.dtype(),
format_tensor_shape(self.shape())
format_tensor_shape_single_line(self.shape())
))
.on_hover_ui(|ui| tensor_dtype_and_shape_ui(ui, self));
.on_hover_ui(|ui| tensor_dtype_and_shape_ui(ctx.re_ui, ui, self, tensor_stats));
});
}

UiVerbosity::All | UiVerbosity::Reduced => {
ui.vertical(|ui| {
ui.set_min_width(100.0);
tensor_dtype_and_shape_ui(ui, self);
tensor_dtype_and_shape_ui(ctx.re_ui, ui, self, tensor_stats);

if let Some(retained_img) = tensor_view.retained_img {
let max_size = ui
Expand Down Expand Up @@ -105,17 +111,60 @@ impl DataUi for ClassicTensor {
}
}

pub fn tensor_dtype_and_shape_ui(ui: &mut egui::Ui, tensor: &ClassicTensor) {
pub fn tensor_dtype_and_shape_ui_grid_contents(
re_ui: &re_ui::ReUi,
ui: &mut egui::Ui,
tensor: &ClassicTensor,
tensor_stats: Option<&TensorStats>,
) {
re_ui
.grid_left_hand_label(ui, "Data type")
.on_hover_text("Data type used for all individual elements within the tensor.");
ui.label(tensor.dtype().to_string());
ui.end_row();

re_ui
.grid_left_hand_label(ui, "Shape")
.on_hover_text("Extent of every dimension.");
ui.vertical(|ui| {
// For unnamed tensor dimension more than a single line usually doesn't make sense!
// But what if some are named and some are not?
// -> If more than 1 is named, make it a column!
if tensor.shape().iter().filter(|d| d.name.is_some()).count() > 1 {
for dim in tensor.shape() {
ui.label(dim.to_string());
}
} else {
ui.label(format_tensor_shape_single_line(tensor.shape()));
}
});
ui.end_row();

if let Some(TensorStats {
range: Some((min, max)),
}) = tensor_stats
{
ui.label("Data range")
.on_hover_text("All values of the tensor range within these bounds.");
ui.monospace(format!(
"[{} - {}]",
re_format::format_f64(*min),
re_format::format_f64(*max)
));
ui.end_row();
}
}

pub fn tensor_dtype_and_shape_ui(
re_ui: &re_ui::ReUi,
ui: &mut egui::Ui,
tensor: &ClassicTensor,
tensor_stats: Option<&TensorStats>,
) {
egui::Grid::new("tensor_dtype_and_shape_ui")
.num_columns(2)
.show(ui, |ui| {
ui.label("Data type:");
ui.label(tensor.dtype().to_string());
ui.end_row();

ui.label("Shape:");
ui.label(format_tensor_shape(tensor.shape()));
ui.end_row();
tensor_dtype_and_shape_ui_grid_contents(re_ui, ui, tensor, tensor_stats);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ pub fn dimension_mapping_ui(

ui.vertical(|ui| {
ui.vertical(|ui| {
ui.strong("Image:");
ui.strong("Image");
egui::Grid::new("imagegrid").num_columns(2).show(ui, |ui| {
tensor_dimension_ui(
ui,
Expand Down Expand Up @@ -229,7 +229,7 @@ pub fn dimension_mapping_ui(
ui.add_space(4.0);

ui.vertical(|ui| {
ui.strong("Selectors:");
ui.strong("Selectors");
// Use Grid instead of Vertical layout to match styling of the parallel Grid for
egui::Grid::new("selectiongrid")
.num_columns(2)
Expand Down
193 changes: 85 additions & 108 deletions crates/re_viewer/src/ui/view_tensor/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use ndarray::{Axis, Ix2};
use re_log_types::{component_types, ClassicTensor, TensorDataType};
use re_tensor_ops::dimension_mapping::{DimensionMapping, DimensionSelector};

use crate::ui::data_ui::image::tensor_dtype_and_shape_ui_grid_contents;

use super::dimension_mapping_ui;

// ---
Expand Down Expand Up @@ -44,38 +46,39 @@ impl ViewTensorState {
}

pub(crate) fn ui(&mut self, ctx: &mut crate::misc::ViewerContext<'_>, ui: &mut egui::Ui) {
if let Some(tensor) = &self.tensor {
egui::CollapsingHeader::new("Dimension Mapping")
.default_open(true)
.show(ui, |ui| {
crate::ui::data_ui::image::tensor_dtype_and_shape_ui(ui, tensor);
ui.add_space(12.0);

let default_mapping = DimensionMapping::create(tensor.shape());
if ui
.add_enabled(
self.dimension_mapping != default_mapping,
egui::Button::new("Reset mapping"),
)
.on_disabled_hover_text("The default is already set up.")
.on_hover_text("Reset dimension mapping to the default.")
.clicked()
{
self.dimension_mapping = DimensionMapping::create(tensor.shape());
}

dimension_mapping_ui(
ctx.re_ui,
ui,
&mut self.dimension_mapping,
tensor.shape(),
);
});
}
let Some(tensor) = &self.tensor else {
ui.label("No Tensor shown in this Space View.");
return;
};

self.texture_settings.show(ui);
ctx.re_ui
.selection_grid(ui, "tensor_selection_ui")
.show(ui, |ui| {
tensor_dtype_and_shape_ui_grid_contents(
ctx.re_ui,
ui,
tensor,
Some(ctx.cache.tensor_stats(tensor)),
);
self.texture_settings.ui(ctx.re_ui, ui);
self.color_mapping.ui(ctx.re_ui, ui);
});
color_mapping_ui(ctx, ui, &mut self.color_mapping, self.tensor.as_ref());
ui.separator();
ui.strong("Dimension Mapping");
dimension_mapping_ui(ctx.re_ui, ui, &mut self.dimension_mapping, tensor.shape());
let default_mapping = DimensionMapping::create(tensor.shape());
if ui
.add_enabled(
self.dimension_mapping != default_mapping,
egui::Button::new("Reset mapping"),
)
.on_disabled_hover_text("The default is already set up.")
.on_hover_text("Reset dimension mapping to the default.")
.clicked()
{
self.dimension_mapping = DimensionMapping::create(tensor.shape());
}
}
}

Expand Down Expand Up @@ -374,53 +377,27 @@ impl ColorMapping {
}
}
}
}

fn color_mapping_ui(
ctx: &mut crate::misc::ViewerContext<'_>,
ui: &mut egui::Ui,
color_mapping: &mut ColorMapping,
tensor: Option<&ClassicTensor>,
) {
ui.group(|ui| {
ui.strong("Color map");
fn ui(&mut self, re_ui: &re_ui::ReUi, ui: &mut egui::Ui) {
let ColorMapping { map, gamma } = self;

re_ui.grid_left_hand_label(ui, "Color map");
egui::ComboBox::from_id_source("color map select")
.selected_text(color_mapping.map.to_string())
.selected_text(map.to_string())
.show_ui(ui, |ui| {
ui.style_mut().wrap = Some(false);
ui.selectable_value(
&mut color_mapping.map,
ColorMap::Greyscale,
ColorMap::Greyscale.to_string(),
);
ui.selectable_value(
&mut color_mapping.map,
ColorMap::Virdis,
ColorMap::Virdis.to_string(),
);
ui.selectable_value(
&mut color_mapping.map,
ColorMap::Turbo,
ColorMap::Turbo.to_string(),
);
ui.selectable_value(map, ColorMap::Greyscale, ColorMap::Greyscale.to_string());
ui.selectable_value(map, ColorMap::Virdis, ColorMap::Virdis.to_string());
ui.selectable_value(map, ColorMap::Turbo, ColorMap::Turbo.to_string());
});
ui.end_row();

let mut brightness = 1.0 / color_mapping.gamma;
ui.add(
egui::Slider::new(&mut brightness, 0.1..=10.0)
.logarithmic(true)
.text("Brightness"),
);
color_mapping.gamma = 1.0 / brightness;

if let Some(tensor) = &tensor {
let tensor_stats = ctx.cache.tensor_stats(tensor);
if let Some((min, max)) = tensor_stats.range {
ui.monospace(format!("Data range: [{min} - {max}]"));
}
}
});
re_ui.grid_left_hand_label(ui, "Brightness");
let mut brightness = 1.0 / *gamma;
ui.add(egui::Slider::new(&mut brightness, 0.1..=10.0).logarithmic(true));
*gamma = 1.0 / brightness;
ui.end_row();
}
}

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -519,52 +496,52 @@ impl TextureSettings {

// ui
impl TextureSettings {
fn show(&mut self, ui: &mut egui::Ui) {
fn ui(&mut self, re_ui: &re_ui::ReUi, ui: &mut egui::Ui) {
let TextureSettings {
keep_aspect_ratio,
scaling,
options,
} = self;

re_ui.grid_left_hand_label(ui, "Scale");
ui.vertical(|ui| {
egui::ComboBox::from_id_source("texture_scaling")
.selected_text(scaling.to_string())
.show_ui(ui, |ui| {
ui.style_mut().wrap = Some(false);
ui.set_min_width(64.0);

let mut selectable_value =
|ui: &mut egui::Ui, e| ui.selectable_value(scaling, e, e.to_string());
selectable_value(ui, TextureScaling::Original);
selectable_value(ui, TextureScaling::Fill);
});
if *scaling == TextureScaling::Fill {
ui.checkbox(keep_aspect_ratio, "Keep aspect ratio");
}
});
ui.end_row();

re_ui.grid_left_hand_label(ui, "Filtering");
fn tf_to_string(tf: egui::TextureFilter) -> &'static str {
match tf {
egui::TextureFilter::Nearest => "Nearest",
egui::TextureFilter::Linear => "Linear",
}
}
egui::ComboBox::from_id_source("texture_filter")
.selected_text(tf_to_string(options.magnification))
.show_ui(ui, |ui| {
ui.style_mut().wrap = Some(false);
ui.set_min_width(64.0);

ui.group(|ui| {
egui::Grid::new("texture_settings").show(ui, |ui| {
ui.label("Scale:");
egui::ComboBox::from_id_source("texture_scaling")
.selected_text(self.scaling.to_string())
.show_ui(ui, |ui| {
ui.style_mut().wrap = Some(false);
ui.set_min_width(64.0);

let mut selectable_value = |ui: &mut egui::Ui, e| {
ui.selectable_value(&mut self.scaling, e, e.to_string())
};
selectable_value(ui, TextureScaling::Original);
selectable_value(ui, TextureScaling::Fill);
});

if self.scaling == TextureScaling::Fill {
ui.checkbox(&mut self.keep_aspect_ratio, "Keep aspect ratio");
}
ui.end_row();

ui.label("Filter:")
.on_hover_text("Texture magnification filter");
egui::ComboBox::from_id_source("texture_filter")
.selected_text(tf_to_string(self.options.magnification))
.show_ui(ui, |ui| {
ui.style_mut().wrap = Some(false);
ui.set_min_width(64.0);

let mut selectable_value = |ui: &mut egui::Ui, e| {
ui.selectable_value(&mut self.options.magnification, e, tf_to_string(e))
};
selectable_value(ui, egui::TextureFilter::Linear);
selectable_value(ui, egui::TextureFilter::Nearest);
});
ui.end_row();
let mut selectable_value = |ui: &mut egui::Ui, e| {
ui.selectable_value(&mut options.magnification, e, tf_to_string(e))
};
selectable_value(ui, egui::TextureFilter::Linear);
selectable_value(ui, egui::TextureFilter::Nearest);
});
});
ui.end_row();
}
}

Expand Down

0 comments on commit 33fd7b0

Please sign in to comment.