Skip to content

Commit

Permalink
modified: src/fitter/fitter.rs
Browse files Browse the repository at this point in the history
	modified:   src/fitter/gaussian.rs
	modified:   src/fitter/linear.rs
	modified:   src/histoer/histogram1d.rs
  • Loading branch information
alconley committed Jun 4, 2024
1 parent 12a214a commit e5e3c67
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 93 deletions.
109 changes: 109 additions & 0 deletions src/fitter/fitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,15 @@ impl Fitter {
}
}

pub fn fitter_stats(&self, ui: &mut egui::Ui) {
if let Some(fit) = &self.result {
match fit {
FitResult::Gaussian(fit) => fit.fit_params_ui(ui),
FitResult::Linear(fit) => fit.fit_params_ui(ui),
}
}
}

pub fn draw(
&self,
plot_ui: &mut egui_plot::PlotUi,
Expand Down Expand Up @@ -211,3 +220,103 @@ impl Fitter {
}
}
}

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct Fits {
pub temp_fit: Option<Fitter>,
pub temp_background_fit: Option<BackgroundFitter>,
pub stored_fits: Vec<Fitter>,
}

impl Fits {
pub fn new() -> Self {

Check failure on line 232 in src/fitter/fitter.rs

View workflow job for this annotation

GitHub Actions / Clippy

you should consider adding a `Default` implementation for `Fits`
Fits {
temp_fit: None,
temp_background_fit: None,
stored_fits: Vec::new(),
}
}

pub fn remove_temp_fits(&mut self) {
self.temp_fit = None;
self.temp_background_fit = None;
}

pub fn draw(&self, plot_ui: &mut egui_plot::PlotUi) {
if let Some(temp_fit) = &self.temp_fit {
temp_fit.draw(
plot_ui,
egui::Color32::from_rgb(255, 0, 255),
egui::Color32::GREEN,
egui::Color32::BLUE,
);
}

if let Some(temp_background_fit) = &self.temp_background_fit {
temp_background_fit.draw(plot_ui, egui::Color32::GREEN);
}

for fit in self.stored_fits.iter() {
fit.draw(
plot_ui,
egui::Color32::from_rgb(162, 0, 255),
egui::Color32::from_rgb(162, 0, 255),
egui::Color32::from_rgb(162, 0, 255),
);
}
}

pub fn fit_stats_grid_ui(&mut self, ui: &mut egui::Ui) {

// only show the grid if there is something to show
if self.temp_fit.is_none() && self.stored_fits.is_empty() {
return;
}

let mut to_remove = None;

// make this a scrollable grid

egui::ScrollArea::both().show(ui, |ui| {
egui::Grid::new("fit_params_grid")
.striped(true)
.show(ui, |ui| {
ui.label("Fit");
ui.label("Peak");
ui.label("Mean");
ui.label("FWHM");
ui.label("Area");
ui.end_row();

if !self.temp_fit.is_none() {

Check failure on line 291 in src/fitter/fitter.rs

View workflow job for this annotation

GitHub Actions / Clippy

this boolean expression can be simplified
ui.label("Current");

if let Some(temp_fit) = &self.temp_fit {
temp_fit.fitter_stats(ui);
}
}

if !self.stored_fits.is_empty() {
for (i, fit) in self.stored_fits.iter().enumerate() {
ui.horizontal(|ui| {
ui.label(format!("Fit {}", i));

ui.separator();

if ui.button("X").clicked() {
to_remove = Some(i);
}

ui.separator();
});
fit.fitter_stats(ui);
}
}
});
});

if let Some(index) = to_remove {
self.stored_fits.remove(index);
}
}
}
40 changes: 20 additions & 20 deletions src/fitter/gaussian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,19 @@ impl GaussianParams {
}

pub fn params_ui(&self, ui: &mut egui::Ui) {
// plan to put this in a grid layout
ui.horizontal(|ui| {
ui.label(format!("{:.4} ± {:.4}", self.mean.value, self.mean.uncertainty));
});

ui.horizontal(|ui| {
ui.label("FWHM:");
ui.label(format!("{:.4} ± {:.4}", self.fwhm.value, self.fwhm.uncertainty));
});

ui.horizontal(|ui| {
ui.label("Area:");
ui.label(format!("{:.4} ± {:.4}", self.area.value, self.area.uncertainty));
});
ui.label(format!(
"{:.2} ± {:.2}",
self.mean.value, self.mean.uncertainty
));
ui.label(format!(
"{:.2} ± {:.2}",
self.fwhm.value, self.fwhm.uncertainty
));
ui.label(format!(
"{:.2} ± {:.2}",
self.area.value, self.area.uncertainty
));
}

}

#[derive(Default, Clone, Debug, serde::Serialize, serde::Deserialize)]
Expand All @@ -90,7 +87,7 @@ pub struct GaussianFitter {
pub peak_markers: Vec<f64>,
pub fit_params: Option<Vec<GaussianParams>>,
pub fit_lines: Option<Vec<Vec<(f64, f64)>>>,
}
}

impl GaussianFitter {
pub fn new(x: Vec<f64>, y: Vec<f64>, peak_markers: Vec<f64>) -> Self {
Expand All @@ -100,7 +97,6 @@ impl GaussianFitter {
peak_markers,
fit_params: None,
fit_lines: None,

}
}

Expand Down Expand Up @@ -356,9 +352,13 @@ impl GaussianFitter {
pub fn fit_params_ui(&self, ui: &mut egui::Ui) {
if let Some(fit_params) = &self.fit_params {
for (i, params) in fit_params.iter().enumerate() {
ui.collapsing(format!("Peak {}", i), |ui| {
params.params_ui(ui);
});
if i != 0 {
ui.label("");
}

ui.label(format!("Peak {}", i));
params.params_ui(ui);
ui.end_row();
}
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/fitter/linear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ pub struct Parameters {
pub intercept: f64,
}

impl Parameters {
pub fn params_ui(&self, ui: &mut egui::Ui) {
// just display the value with 4 decimal places
ui.label(format!("Slope: {:.4}", self.slope));
ui.label(format!("Intercept: {:.4}", self.intercept));
}
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LinearFitter {
x_data: Vec<f64>,
Expand Down Expand Up @@ -143,6 +151,12 @@ impl LinearFitter {
vec![]
}
}

pub fn fit_params_ui(&self, ui: &mut egui::Ui) {
if let Some(params) = &self.fit_params {
params.params_ui(ui);
}
}
}

// Unit tests for LinearFitter
Expand Down
119 changes: 46 additions & 73 deletions src/histoer/histogram1d.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::fitter::egui_markers::EguiFitMarkers;
use crate::fitter::fitter::{BackgroundFitter, FitModel, Fitter};
use crate::fitter::fitter::{BackgroundFitter, FitModel, Fits, Fitter};

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct PlotSettings {
Expand All @@ -8,6 +8,7 @@ pub struct PlotSettings {
info: bool,
show_fit_stats: bool,
color: egui::Color32,
show_color_changer: bool,
markers: EguiFitMarkers,
show_x_value: bool,
show_y_value: bool,
Expand All @@ -30,6 +31,7 @@ impl Default for PlotSettings {
info: true,
show_fit_stats: true,
color: egui::Color32::LIGHT_BLUE,
show_color_changer: false,
markers: EguiFitMarkers::new(),
show_x_value: true,
show_y_value: true,
Expand All @@ -56,6 +58,7 @@ impl PlotSettings {
ui.checkbox(&mut self.show_fit_stats, "Show Fit Stats");
ui.menu_button("Manipulation Settings", |ui| {
ui.vertical(|ui| {
ui.checkbox(&mut self.show_color_changer, "Show Color Changer");
ui.checkbox(&mut self.show_x_value, "Show X Value");
ui.checkbox(&mut self.show_y_value, "Show Y Value");
ui.checkbox(&mut self.center_x_axis, "Center X Axis");
Expand All @@ -70,53 +73,15 @@ impl PlotSettings {
ui.checkbox(&mut self.show_background, "Show Background");
});
});
ui.color_edit_button_srgba(&mut self.color);
});
}
}

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct Fits {
pub temp_fit: Option<Fitter>,
pub temp_background_fit: Option<BackgroundFitter>,
pub stored_fits: Vec<Fitter>,
}

impl Fits {
pub fn new() -> Self {
Fits {
temp_fit: None,
temp_background_fit: None,
stored_fits: Vec::new(),
}
}

pub fn remove_temp_fits(&mut self) {
self.temp_fit = None;
self.temp_background_fit = None;
}

pub fn draw(&self, plot_ui: &mut egui_plot::PlotUi) {
if let Some(temp_fit) = &self.temp_fit {
temp_fit.draw(
plot_ui,
egui::Color32::from_rgb(255, 0, 255),
egui::Color32::GREEN,
egui::Color32::BLUE,
);
}

if let Some(temp_background_fit) = &self.temp_background_fit {
temp_background_fit.draw(plot_ui, egui::Color32::GREEN);
}

for fit in self.stored_fits.iter() {
fit.draw(
plot_ui,
egui::Color32::from_rgb(162, 0, 255),
egui::Color32::from_rgb(162, 0, 255),
egui::Color32::from_rgb(162, 0, 255),
);
pub fn above_histo_ui(&mut self, ui: &mut egui::Ui) {
if self.show_color_changer {
ui.horizontal(|ui| {
ui.label("Color: ");
ui.color_edit_button_srgba(&mut self.color);
});
}
}
}
Expand Down Expand Up @@ -415,39 +380,47 @@ impl Histogram {

self.interactive(ui);

plot.show(ui, |plot_ui| {
let plot_min_x = plot_ui.plot_bounds().min()[0];
let plot_max_x = plot_ui.plot_bounds().max()[0];

let step_line = self.egui_histogram_step(self.plot_settings.color);

if self.plot_settings.info {
let stats_entries = self.legend_entries(plot_min_x, plot_max_x);
for entry in stats_entries.iter() {
plot_ui.text(
egui_plot::Text::new(egui_plot::PlotPoint::new(0, 0), " ") // Placeholder for positioning; adjust as needed
.highlight(false)
.color(self.plot_settings.color)
.name(entry),
);
}
ui.vertical(|ui| {
self.plot_settings.above_histo_ui(ui);

if self.plot_settings.show_fit_stats {
self.fits.fit_stats_grid_ui(ui);
}

plot_ui.line(step_line);
plot.show(ui, |plot_ui| {
let plot_min_x = plot_ui.plot_bounds().min()[0];
let plot_max_x = plot_ui.plot_bounds().max()[0];

let step_line = self.egui_histogram_step(self.plot_settings.color);

if self.plot_settings.info {
let stats_entries = self.legend_entries(plot_min_x, plot_max_x);
for entry in stats_entries.iter() {
plot_ui.text(
egui_plot::Text::new(egui_plot::PlotPoint::new(0, 0), " ") // Placeholder for positioning; adjust as needed
.highlight(false)
.color(self.plot_settings.color)
.name(entry),
);
}
}

if plot_ui.response().hovered() {
self.plot_settings.cursor_position = plot_ui.pointer_coordinate();
} else {
self.plot_settings.cursor_position = None;
}
plot_ui.line(step_line);

self.plot_settings.markers.draw_markers(plot_ui);
if plot_ui.response().hovered() {
self.plot_settings.cursor_position = plot_ui.pointer_coordinate();
} else {
self.plot_settings.cursor_position = None;
}

self.fits.draw(plot_ui);
})
.response
.context_menu(|ui| {
self.plot_settings.settings_ui(ui);
self.plot_settings.markers.draw_markers(plot_ui);

self.fits.draw(plot_ui);
})
.response
.context_menu(|ui| {
self.plot_settings.settings_ui(ui);
});
});
}
}

0 comments on commit e5e3c67

Please sign in to comment.