Skip to content

Commit

Permalink
Use 7 day avg. for training/muscle set volume
Browse files Browse the repository at this point in the history
  • Loading branch information
senier committed Nov 21, 2024
1 parent 1b5f2c2 commit dc8c616
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 119 deletions.
7 changes: 6 additions & 1 deletion frontend/src/ui/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ pub fn plot_line_with_dots(color: usize) -> Vec<PlotType> {
[PlotType::Line(color, 2), PlotType::Circle(color, 2)].to_vec()
}

pub fn plot_line(color: usize) -> Vec<PlotType> {
[PlotType::Line(color, 2)].to_vec()
}

#[derive(Default)]
pub struct PlotParams {
pub y_min_opt: Option<f32>,
Expand Down Expand Up @@ -1133,7 +1137,8 @@ pub fn centered_moving_grouping(
.filter_map(|d| grouped.get(&d))
.copied()
.collect::<Vec<_>>(),
).map(|result| (center, result))
)
.map(|result| (center, result))
})
.collect::<Vec<_>>()
}
Expand Down
93 changes: 11 additions & 82 deletions frontend/src/ui/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ pub fn init(url: Url, _orders: &mut impl Orders<Msg>) -> Model {
short_term_load: Vec::new(),
long_term_load: Vec::new(),
avg_rpe_per_week: Vec::new(),
total_set_volume_per_week: Vec::new(),
stimulus_for_each_muscle_per_week: BTreeMap::new(),
},
settings,
ongoing_training_session,
Expand Down Expand Up @@ -275,8 +273,6 @@ pub struct TrainingStats {
pub short_term_load: Vec<(NaiveDate, f32)>,
pub long_term_load: Vec<(NaiveDate, f32)>,
pub avg_rpe_per_week: Vec<(NaiveDate, f32)>,
pub total_set_volume_per_week: Vec<(NaiveDate, f32)>,
pub stimulus_for_each_muscle_per_week: BTreeMap<u8, Vec<(NaiveDate, u32)>>,
}

impl TrainingStats {
Expand All @@ -297,7 +293,6 @@ impl TrainingStats {
self.short_term_load.clear();
self.long_term_load.clear();
self.avg_rpe_per_week.clear();
self.total_set_volume_per_week.clear();
}
}

Expand Down Expand Up @@ -875,21 +870,13 @@ pub fn calculate_cycle_stats(cycles: &[&Cycle]) -> CycleStats {
}
}

fn calculate_training_stats(
training_sessions: &[&TrainingSession],
exercises: &BTreeMap<u32, Exercise>,
) -> TrainingStats {
fn calculate_training_stats(training_sessions: &[&TrainingSession]) -> TrainingStats {
let short_term_load = calculate_weighted_sum_of_load(training_sessions, 7);
let long_term_load = calculate_average_weighted_sum_of_load(&short_term_load, 28);
TrainingStats {
short_term_load,
long_term_load,
total_set_volume_per_week: calculate_total_set_volume_per_week(training_sessions),
avg_rpe_per_week: calculate_avg_rpe_per_week(training_sessions),
stimulus_for_each_muscle_per_week: calculate_stimulus_for_each_muscle_per_week(
training_sessions,
exercises,
),
}
}

Expand Down Expand Up @@ -951,21 +938,6 @@ fn calculate_average_weighted_sum_of_load(
.collect::<Vec<_>>()
}

fn calculate_total_set_volume_per_week(
training_sessions: &[&TrainingSession],
) -> Vec<(NaiveDate, f32)> {
let mut result: BTreeMap<NaiveDate, f32> = training_session_weeks(training_sessions);

#[allow(clippy::cast_precision_loss)]
for t in training_sessions {
result
.entry(t.date.week(Weekday::Mon).last_day())
.and_modify(|e| *e += t.set_volume() as f32);
}

result.into_iter().collect()
}

fn calculate_avg_rpe_per_week(training_sessions: &[&TrainingSession]) -> Vec<(NaiveDate, f32)> {
let mut result: BTreeMap<NaiveDate, Vec<f32>> = training_session_weeks(training_sessions);

Expand Down Expand Up @@ -993,39 +965,6 @@ fn calculate_avg_rpe_per_week(training_sessions: &[&TrainingSession]) -> Vec<(Na
.collect()
}

fn calculate_stimulus_for_each_muscle_per_week(
training_sessions: &[&TrainingSession],
exercises: &BTreeMap<u32, Exercise>,
) -> BTreeMap<u8, Vec<(NaiveDate, u32)>> {
let mut result: BTreeMap<u8, BTreeMap<NaiveDate, u32>> = BTreeMap::new();

for m in domain::Muscle::iter() {
result.insert(
domain::Muscle::id(*m),
training_session_weeks(training_sessions),
);
}

for t in training_sessions {
for (id, stimulus) in t.stimulus_per_muscle(exercises) {
if let Some(stimulus_per_week) = result.get_mut(&id) {
stimulus_per_week
.entry(t.date.week(Weekday::Mon).last_day())
.and_modify(|s| *s += stimulus);
} else {
error!(format!(
"failed to access stimulus per week for muscle with id {id}"
));
}
}
}

result
.into_iter()
.map(|(id, stimulus_per_week)| (id, stimulus_per_week.into_iter().collect()))
.collect()
}

fn training_session_weeks<T: Default>(
training_sessions: &[&TrainingSession],
) -> BTreeMap<NaiveDate, T> {
Expand Down Expand Up @@ -1759,10 +1698,8 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
}
Msg::ExerciseReplaced(Ok(exercise)) => {
model.exercises.insert(exercise.id, exercise);
model.training_stats = calculate_training_stats(
&model.training_sessions.values().collect::<Vec<_>>(),
&model.exercises,
);
model.training_stats =
calculate_training_stats(&model.training_sessions.values().collect::<Vec<_>>());
orders.notify(Event::ExerciseReplacedOk);
}
Msg::ExerciseReplaced(Err(message)) => {
Expand Down Expand Up @@ -1917,10 +1854,8 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
let training_sessions = training_sessions.into_iter().map(|t| (t.id, t)).collect();
if model.training_sessions != training_sessions {
model.training_sessions = training_sessions;
model.training_stats = calculate_training_stats(
&model.training_sessions.values().collect::<Vec<_>>(),
&model.exercises,
);
model.training_stats =
calculate_training_stats(&model.training_sessions.values().collect::<Vec<_>>());
orders.notify(Event::DataChanged);
}
model.loading_training_sessions = false;
Expand Down Expand Up @@ -1951,10 +1886,8 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
model
.training_sessions
.insert(training_session.id, training_session);
model.training_stats = calculate_training_stats(
&model.training_sessions.values().collect::<Vec<_>>(),
&model.exercises,
);
model.training_stats =
calculate_training_stats(&model.training_sessions.values().collect::<Vec<_>>());
orders.notify(Event::TrainingSessionCreatedOk);
}
Msg::TrainingSessionCreated(Err(message)) => {
Expand Down Expand Up @@ -1985,10 +1918,8 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
model
.training_sessions
.insert(training_session.id, training_session);
model.training_stats = calculate_training_stats(
&model.training_sessions.values().collect::<Vec<_>>(),
&model.exercises,
);
model.training_stats =
calculate_training_stats(&model.training_sessions.values().collect::<Vec<_>>());
orders.notify(Event::TrainingSessionModifiedOk);
}
Msg::TrainingSessionModified(Err(message)) => {
Expand All @@ -2011,10 +1942,8 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
}
Msg::TrainingSessionDeleted(Ok(id)) => {
model.training_sessions.remove(&id);
model.training_stats = calculate_training_stats(
&model.training_sessions.values().collect::<Vec<_>>(),
&model.exercises,
);
model.training_stats =
calculate_training_stats(&model.training_sessions.values().collect::<Vec<_>>());
orders.notify(Event::TrainingSessionDeletedOk);
}
Msg::TrainingSessionDeleted(Err(message)) => {
Expand Down
39 changes: 18 additions & 21 deletions frontend/src/ui/page/muscles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,24 +69,21 @@ pub fn view(model: &Model, data_model: &data::Model) -> Node<Msg> {
Msg::ChangeInterval
),
domain::Muscle::iter().map(|m| {
let set_volume = data_model
.training_stats
.stimulus_for_each_muscle_per_week
.get(&domain::Muscle::id(*m))
.map(|stimulus_per_muscle| {
stimulus_per_muscle
.iter()
.filter(|(date, _)| {
*date >= model.interval.first
&& *date <= model.interval.last.week(Weekday::Mon).last_day()
})
.map(
#[allow(clippy::cast_precision_loss)]
|(date, stimulus)| (*date, *stimulus as f32 / 100.0),
)
.collect()
})
.unwrap_or_default();
#[allow(clippy::cast_precision_loss)]
let set_volume = common::centered_moving_total(
&data_model
.training_sessions
.iter()
.filter_map(|(_, s)| {
s.stimulus_per_muscle(&data_model.exercises)
.get(&domain::Muscle::id(*m))
.map(|stimulus| (s.date, *stimulus as f32 / 100.))
})
.collect::<Vec<_>>(),
&model.interval,
3,
);

div![
common::view_title(&span![domain::Muscle::name(*m)], 1),
div![
Expand All @@ -96,12 +93,12 @@ pub fn view(model: &Model, data_model: &data::Model) -> Node<Msg> {
domain::Muscle::description(*m)
],
common::view_chart(
&[("Set volume (weekly total)", common::COLOR_SET_VOLUME)],
&[("Set volume (7 day total)", common::COLOR_SET_VOLUME)],
common::plot_chart(
&[common::PlotData {
values: set_volume,
plots: common::plot_line_with_dots(common::COLOR_SET_VOLUME),
params: common::PlotParams::primary_range(0., 10.),
plots: common::plot_line(common::COLOR_SET_VOLUME),
params: common::PlotParams::default(),
}],
model.interval.first,
model.interval.last,
Expand Down
31 changes: 16 additions & 15 deletions frontend/src/ui/page/training.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,17 @@ pub fn view(model: &Model, data_model: &data::Model) -> Node<Msg> {
.filter(|(date, _)| *date >= model.interval.first && *date <= model.interval.last)
.copied()
.collect::<Vec<_>>();
let total_set_volume_per_week = data_model
.training_stats
.total_set_volume_per_week
.iter()
.filter(|(date, _)| {
*date >= model.interval.first
&& *date <= model.interval.last.week(Weekday::Mon).last_day()
})
.copied()
.collect::<Vec<_>>();
#[allow(clippy::cast_precision_loss)]
let total_set_volume_7day_avg = common::centered_moving_average(
&data_model
.training_sessions
.values()
.map(|s| (s.date, s.set_volume() as f32))
.collect::<Vec<_>>(),
&model.interval,
3,
);

let avg_rpe_per_week = data_model
.training_stats
.avg_rpe_per_week
Expand Down Expand Up @@ -325,7 +326,7 @@ pub fn view(model: &Model, data_model: &data::Model) -> Node<Msg> {
view_charts(
short_term_load,
long_term_load,
total_set_volume_per_week,
total_set_volume_7day_avg,
avg_rpe_per_week,
&model.interval,
data_model.theme(),
Expand Down Expand Up @@ -506,7 +507,7 @@ fn view_training_sessions_dialog(
pub fn view_charts<Ms>(
short_term_load: Vec<(NaiveDate, f32)>,
long_term_load: Vec<(NaiveDate, f32)>,
total_set_volume_per_week: Vec<(NaiveDate, f32)>,
total_set_volume_average: Vec<(NaiveDate, f32)>,
avg_rpe_per_week: Vec<(NaiveDate, f32)>,
interval: &common::Interval,
theme: &data::Theme,
Expand Down Expand Up @@ -558,11 +559,11 @@ pub fn view_charts<Ms>(
false,
),
common::view_chart(
&[("Set volume (weekly total)", common::COLOR_SET_VOLUME)],
&[("Set volume (7 day total)", common::COLOR_SET_VOLUME)],
common::plot_chart(
&[common::PlotData {
values: total_set_volume_per_week,
plots: common::plot_line_with_dots(common::COLOR_SET_VOLUME),
values: total_set_volume_average,
plots: [common::PlotType::Line(common::COLOR_SET_VOLUME, 2)].to_vec(),
params: common::PlotParams::primary_range(0., 10.),
}],
interval.first,
Expand Down

0 comments on commit dc8c616

Please sign in to comment.