Skip to content

Commit

Permalink
background markers now require a pair
Browse files Browse the repository at this point in the history
	modified:   src/egui_plot_stuff/egui_line.rs
	modified:   src/histoer/histo1d/histogram1d.rs
	modified:   src/histoer/histo1d/keybinds.rs
	modified:   src/histoer/histo1d/markers.rs
	modified:   src/histoer/histo1d/peak_finder.rs
	modified:   src/histogram_scripter/custom_scripts.rs
  • Loading branch information
alconley committed Feb 3, 2025
1 parent a4c5253 commit 802e42e
Show file tree
Hide file tree
Showing 6 changed files with 346 additions and 142 deletions.
9 changes: 9 additions & 0 deletions src/egui_plot_stuff/egui_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct EguiLine {
pub color: Color32,
pub reference_fill: bool,
pub fill: f32,
pub fill_alpha: f32,

#[serde(skip)]
pub style: Option<LineStyle>,
Expand All @@ -41,6 +42,7 @@ impl Default for EguiLine {
color: Color32::from_rgb(120, 47, 64),
reference_fill: false,
fill: 0.0,
fill_alpha: 0.3,
style: Some(LineStyle::Solid),
style_length: 15.0,
points: vec![],
Expand Down Expand Up @@ -108,6 +110,7 @@ impl EguiLine {

if self.reference_fill {
line = line.fill(self.fill);
line = line.fill_alpha(self.fill_alpha);
}

if self.style.is_some() {
Expand Down Expand Up @@ -144,6 +147,12 @@ impl EguiLine {
.speed(1.0)
.prefix("Fill Reference: "),
);
ui.add(
DragValue::new(&mut self.fill_alpha)
.speed(0.01)
.range(0.0..=1.0)
.prefix("Fill Alpha: "),
);
}
});

Expand Down
112 changes: 105 additions & 7 deletions src/histoer/histo1d/histogram1d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,28 +119,68 @@ impl Histogram {
})
}

// pub fn fit_background(&mut self) {
// log::info!("Fitting background for histogram: {}", self.name);
// self.fits.temp_fit = None;

// let marker_positions = self.plot_settings.markers.get_background_marker_positions();
// if marker_positions.len() < 2 {
// log::error!("Need to set at least two background markers to fit the histogram");
// return;
// }

// let (x_data, y_data): (Vec<f64>, Vec<f64>) = marker_positions
// .iter()
// .filter_map(|&pos| self.get_bin_count_and_center(pos))
// .unzip();

// let mut fitter = Fitter::new(Data {
// x: x_data,
// y: y_data,
// });

// fitter.background_model = self.fits.settings.background_model.clone();

// fitter.fit_background();

// fitter.name = format!("{} Temp Fit", self.name);
// fitter.set_name(self.name.clone());

// self.fits.temp_fit = Some(fitter);
// }

pub fn fit_background(&mut self) {
log::info!("Fitting background for histogram: {}", self.name);
self.fits.temp_fit = None;

let marker_positions = self.plot_settings.markers.get_background_marker_positions();
if marker_positions.len() < 2 {
log::error!("Need to set at least two background markers to fit the histogram");
if marker_positions.is_empty() {
log::error!("Need to set at least one background marker pair to fit the histogram");
return;
}

let (x_data, y_data): (Vec<f64>, Vec<f64>) = marker_positions
.iter()
.filter_map(|&pos| self.get_bin_count_and_center(pos))
.unzip();
let mut x_data = Vec::new();
let mut y_data = Vec::new();

for (start_x, end_x) in marker_positions {
let bin_centers = self.get_bin_centers_between(start_x, end_x);
let bin_counts = self.get_bin_counts_between(start_x, end_x);

x_data.extend(bin_centers);
y_data.extend(bin_counts);
}

if x_data.is_empty() || y_data.is_empty() {
log::error!("No valid data points found between background markers.");
return;
}

let mut fitter = Fitter::new(Data {
x: x_data,
y: y_data,
});

fitter.background_model = self.fits.settings.background_model.clone();

fitter.fit_background();

fitter.name = format!("{} Temp Fit", self.name);
Expand Down Expand Up @@ -214,6 +254,58 @@ impl Histogram {
self.fits.temp_fit = Some(fitter);
}

pub fn update_background_pair_lines(&mut self) {
// Extract bin edges and counts **before** modifying anything
let bin_edges = self.get_bin_edges();
let bin_counts = self.bins.clone();

// Extract immutable background marker positions first
let marker_positions: Vec<(f64, f64)> = self
.plot_settings
.markers
.background_markers
.iter()
.map(|bg_pair| (bg_pair.start.x_value, bg_pair.end.x_value))
.collect();

// Compute bin indices based on marker positions **before** modifying anything
let bin_indices: Vec<(usize, usize)> = marker_positions
.iter()
.map(|&(start_x, end_x)| {
let start_bin = self.get_bin_index(start_x).unwrap_or(0);
let end_bin = self
.get_bin_index(end_x)
.unwrap_or(self.bins.len().saturating_sub(1));
(start_bin, end_bin)
})
.collect();

// Now, modify `background_markers` without conflicting borrows
for (bg_pair, &(start_bin, end_bin)) in self
.plot_settings
.markers
.background_markers
.iter_mut()
.zip(bin_indices.iter())
{
bg_pair.histogram_line.points.clear(); // Clear previous points

// Collect the **actual bin edges** and counts in the correct range
for i in start_bin..=end_bin {
if i < bin_edges.len() - 1 {
// Ensure no out-of-bounds access
let x_start = bin_edges[i]; // Start of the bin
let x_end = bin_edges[i + 1]; // End of the bin
let y = bin_counts[i] as f64; // Bin count

// Add both edges of the bin to the histogram line
bg_pair.histogram_line.points.push([x_start, y]);
bg_pair.histogram_line.points.push([x_end, y]);
}
}
}
}

pub fn draw(&mut self, plot_ui: &mut egui_plot::PlotUi) {
// update the histogram and fit lines with the log setting and draw
let log_y = self.plot_settings.egui_settings.log_y;
Expand All @@ -229,6 +321,12 @@ impl Histogram {
self.show_stats(plot_ui);

self.plot_settings.markers.draw_all_markers(plot_ui);
self.update_background_pair_lines();
for bg_pair in &mut self.plot_settings.markers.background_markers {
bg_pair.histogram_line.log_x = log_x;
bg_pair.histogram_line.log_y = log_y;
}

// Check if markers are being dragged
if self.plot_settings.markers.is_dragging() {
// Disable dragging if a marker is being dragged
Expand Down
5 changes: 4 additions & 1 deletion src/histoer/histo1d/keybinds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ impl Histogram {
}

if ui.input(|i| i.key_pressed(egui::Key::B)) {
// self.plot_settings
// .markers
// .add_background_marker(cursor_position.x);
self.plot_settings
.markers
.add_background_marker(cursor_position.x);
.add_background_pair(cursor_position.x, self.bin_width);
}

if ui.input(|i| i.key_pressed(egui::Key::R)) {
Expand Down
129 changes: 112 additions & 17 deletions src/histoer/histo1d/markers.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::egui_plot_stuff::egui_vertical_line::EguiVerticalLine;
use crate::egui_plot_stuff::{egui_line::EguiLine, egui_vertical_line::EguiVerticalLine};
use egui_plot::{PlotPoint, PlotUi};

#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct FitMarkers {
pub region_markers: Vec<EguiVerticalLine>,
pub peak_markers: Vec<EguiVerticalLine>,
pub background_markers: Vec<EguiVerticalLine>,
pub background_markers: Vec<BackgroundPair>,

#[serde(skip)]
pub cursor_position: Option<PlotPoint>,
Expand All @@ -14,6 +14,81 @@ pub struct FitMarkers {
pub manual_marker_position: f64,
}

#[derive(Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct BackgroundPair {
pub start: EguiVerticalLine,
pub end: EguiVerticalLine,
pub histogram_line: EguiLine,
}

impl BackgroundPair {
pub fn is_dragging(&self) -> bool {
self.start.is_dragging || self.end.is_dragging
}

pub fn new(start: EguiVerticalLine, end: EguiVerticalLine) -> Self {
let mut line = EguiLine::new(egui::Color32::from_rgb(0, 200, 0));
line.name = "Background Pair".to_string();
line.reference_fill = true;
line.fill = 0.0;
line.width = 0.0;
line.fill_alpha = 0.05;

line.points.push([start.x_value, 0.0]);
line.points.push([end.x_value, 0.0]);

Self {
start,
end,
histogram_line: line,
}
}

pub fn average_x(&self) -> f64 {
(self.start.x_value + self.end.x_value) / 2.0
}

pub fn draw(&mut self, plot_ui: &mut PlotUi) {
self.start.draw(plot_ui);
self.end.draw(plot_ui);
self.histogram_line.draw(plot_ui);
}

pub fn interactive_dragging(&mut self, plot_response: &egui_plot::PlotResponse<()>) {
self.start.interactive_dragging(plot_response);
self.end.interactive_dragging(plot_response);
}

/// Updates the `histogram_line` to match the histogram bins within this background pair
pub fn update_histogram_line(&mut self, bin_edges: &[f64], bin_counts: &[u32]) {
let start_x = self.start.x_value;
let end_x = self.end.x_value;

let mut line_points = Vec::new();

for (i, &edge) in bin_edges.iter().enumerate() {
if edge >= start_x && edge <= end_x {
let y_value = if i < bin_counts.len() {
bin_counts[i] as f64
} else {
0.0
};
line_points.push([edge, y_value]);
}
}

// Ensure the last point is included at the end marker
if let Some(last_edge) = bin_edges.last() {
if *last_edge <= end_x {
let last_count = *bin_counts.last().unwrap_or(&0) as f64;
line_points.push([*last_edge, last_count]);
}
}

self.histogram_line.points = line_points;
}
}

impl FitMarkers {
pub fn new() -> Self {
Self::default()
Expand All @@ -22,7 +97,7 @@ impl FitMarkers {
pub fn is_dragging(&self) -> bool {
self.region_markers.iter().any(|m| m.is_dragging)
|| self.peak_markers.iter().any(|m| m.is_dragging)
|| self.background_markers.iter().any(|m| m.is_dragging)
|| self.background_markers.iter().any(|m| m.is_dragging())
}

pub fn add_region_marker(&mut self, x: f64) {
Expand Down Expand Up @@ -51,15 +126,21 @@ impl FitMarkers {
.sort_by(|a, b| a.x_value.partial_cmp(&b.x_value).unwrap());
}

pub fn add_background_marker(&mut self, x: f64) {
let mut marker = EguiVerticalLine::new(x, egui::Color32::from_rgb(0, 200, 0));
pub fn add_background_pair(&mut self, x: f64, bin_width: f64) {
let mut marker_start = EguiVerticalLine::new(x, egui::Color32::from_rgb(0, 200, 0));
let mut marker_end = EguiVerticalLine::new(x, egui::Color32::from_rgb(0, 200, 0));

marker.width = 0.5;
marker.name = format!("Background Marker (x={:.2})", x);
marker_start.width = 0.5;
marker_end.width = 0.5;

self.background_markers.push(marker);
self.background_markers
.sort_by(|a, b| a.x_value.partial_cmp(&b.x_value).unwrap());
marker_start.name = format!("Background Pair {} Start", self.background_markers.len());
marker_end.name = format!("Background Pair {} End", self.background_markers.len());

marker_start.x_value = x;
marker_end.x_value = x + bin_width;

let markers = BackgroundPair::new(marker_start, marker_end);
self.background_markers.push(markers);
}

pub fn clear_region_markers(&mut self) {
Expand All @@ -86,10 +167,16 @@ impl FitMarkers {

all_markers.extend(self.region_markers.iter().map(|x| (x.x_value, "region")));
all_markers.extend(self.peak_markers.iter().map(|x| (x.x_value, "peak")));
// all_markers.extend(
// self.background_markers
// .iter()
// .map(|x| (x.x_value, "background")),
// );

all_markers.extend(
self.background_markers
.iter()
.map(|x| (x.x_value, "background")),
.map(|x| (x.average_x(), "background")),
);

if let Some(&(closest_marker, marker_type)) =
Expand All @@ -103,7 +190,9 @@ impl FitMarkers {
"region" => Self::delete_marker(&mut self.region_markers, closest_marker),
"peak" => Self::delete_marker(&mut self.peak_markers, closest_marker),
"background" => {
Self::delete_marker(&mut self.background_markers, closest_marker)
// Self::delete_marker(&mut self.background_markers, closest_marker)
self.background_markers
.retain(|x| x.average_x() != closest_marker);
}
_ => {}
}
Expand All @@ -123,8 +212,12 @@ impl FitMarkers {
Self::get_marker_positions(&self.peak_markers)
}

pub fn get_background_marker_positions(&self) -> Vec<f64> {
Self::get_marker_positions(&self.background_markers)
pub fn get_background_marker_positions(&self) -> Vec<(f64, f64)> {
// Self::get_marker_positions(&self.background_markers)
self.background_markers
.iter()
.map(|m| (m.start.x_value, m.end.x_value))
.collect()
}

pub fn remove_peak_markers_outside_region(&mut self) {
Expand Down Expand Up @@ -184,7 +277,7 @@ impl FitMarkers {
ui.separator();

if ui.button("Background").clicked() {
self.add_background_marker(self.manual_marker_position);
self.add_background_pair(self.manual_marker_position, 1.0);
}

ui.separator();
Expand Down Expand Up @@ -233,8 +326,10 @@ impl FitMarkers {
marker.menu_button(ui);
}

for marker in &mut self.background_markers {
marker.menu_button(ui);
for pair in &mut self.background_markers {
pair.start.menu_button(ui);
pair.end.menu_button(ui);
pair.histogram_line.menu_button(ui);
}
});
});
Expand Down
Loading

0 comments on commit 802e42e

Please sign in to comment.