Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions math_explorer_gui/src/tabs/clinical_trials/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::tabs::ExplorerTab;
use eframe::egui;

pub mod randomization;
pub mod sample_size;
pub mod survival;

use randomization::RandomizationTool;
use sample_size::SampleSizeCalculatorTool;
use survival::SurvivalAnalysisTool;

Expand All @@ -27,6 +29,7 @@ impl Default for ClinicalTrialsTab {
tools: vec![
Box::new(SurvivalAnalysisTool::default()),
Box::new(SampleSizeCalculatorTool::default()),
Box::new(RandomizationTool::default()),
],
selected_tool_index: 0,
}
Expand Down
132 changes: 132 additions & 0 deletions math_explorer_gui/src/tabs/clinical_trials/randomization.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use crate::tabs::clinical_trials::ClinicalTrialsTool;
use eframe::egui;
use math_explorer::applied::clinical_trials::design::{
AllocationStrategy, BlockRandomizer, Group, SimpleRandomizer,
};
use rand::thread_rng;

#[derive(PartialEq)]
enum RandomizationType {
Simple,
Block,
}

pub struct RandomizationTool {
randomization_type: RandomizationType,
n_subjects: usize,
block_size: usize,
assignments: Vec<Group>,
error_message: Option<String>,
}

impl Default for RandomizationTool {
fn default() -> Self {
Self {
randomization_type: RandomizationType::Simple,
n_subjects: 10,
block_size: 4,
assignments: Vec::new(),
error_message: None,
}
}
}

impl ClinicalTrialsTool for RandomizationTool {
fn name(&self) -> &'static str {
"Randomization"
}

fn show(&mut self, ctx: &egui::Context) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Interactive Subject Allocation");

ui.add_space(10.0);

ui.horizontal(|ui| {
ui.label("Randomization Type:");
ui.radio_value(
&mut self.randomization_type,
RandomizationType::Simple,
"Simple",
);
ui.radio_value(
&mut self.randomization_type,
RandomizationType::Block,
"Block",
);
});

ui.add_space(5.0);

ui.horizontal(|ui| {
ui.label("Number of Subjects:");
ui.add(egui::DragValue::new(&mut self.n_subjects).range(1..=1000));
});

if self.randomization_type == RandomizationType::Block {
ui.horizontal(|ui| {
ui.label("Block Size:");
ui.add(egui::DragValue::new(&mut self.block_size).range(2..=100));
});
}

ui.add_space(10.0);

if ui.button("Allocate Subjects").clicked() {
self.error_message = None;
self.assignments.clear();

let mut rng = thread_rng();

match self.randomization_type {
RandomizationType::Simple => {
let randomizer = SimpleRandomizer;
match randomizer.assign(&mut rng, self.n_subjects) {
Ok(assignments) => self.assignments = assignments,
Err(e) => self.error_message = Some(e.to_string()),
}
}
RandomizationType::Block => match BlockRandomizer::new(self.block_size) {
Ok(randomizer) => match randomizer.assign(&mut rng, self.n_subjects) {
Ok(assignments) => self.assignments = assignments,
Err(e) => self.error_message = Some(e.to_string()),
},
Err(e) => self.error_message = Some(e.to_string()),
},
}
}

ui.add_space(10.0);

if let Some(ref err) = self.error_message {
ui.colored_label(egui::Color32::RED, format!("Error: {}", err));
} else if !self.assignments.is_empty() {
ui.heading("Assignments:");

let mut treatment_count = 0;
let mut control_count = 0;
for group in &self.assignments {
match group {
Group::Treatment => treatment_count += 1,
Group::Control => control_count += 1,
}
}

ui.label(format!("Total Treatment: {}", treatment_count));
ui.label(format!("Total Control: {}", control_count));

egui::ScrollArea::vertical()
.max_height(300.0)
.show(ui, |ui| {
for (i, group) in self.assignments.iter().enumerate() {
let group_str = match group {
Group::Treatment => "Treatment",
Group::Control => "Control",
};
ui.label(format!("Subject {}: {}", i + 1, group_str));
}
});
}
});
}
}
4 changes: 2 additions & 2 deletions todo_gui.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ This document outlines the roadmap for integrating the various modules of the `m
* [x] **Capacity Fade:** Plot capacity vs. cycle number based on depth of discharge (DoD) and temperature.
* [ ] **Lifetime Estimator:** Calculator for expected battery life under specific usage profiles.

### 4.2 Clinical Trials
### 4.2 Clinical Trials - **[Implemented]**
* **Module:** `applied::clinical_trials`
* **Features:**
* [x] **Survival Curves:** Kaplan-Meier plot generator.
* [x] **Sample Size Calculator:** Form inputs for $\alpha$, $\beta$, and effect size.
* [ ] **Randomization:** Interactive subject allocation tool.
* [x] **Randomization:** Interactive subject allocation tool.

### 4.3 Favoritism (Satirical)
* **Module:** `applied::favoritism`
Expand Down
Loading