WIP: Add graphs to workouts list view that show reps/weight, still need to refactor logic and dont display unless plot button(Need to add) is checked

This commit is contained in:
Peter Stockings
2023-04-02 22:36:30 +10:00
parent b128b7fb24
commit c4bd430eaf
3 changed files with 83 additions and 1 deletions

28
app.py
View File

@@ -5,7 +5,7 @@ from flask import Flask, render_template, redirect, request, url_for
import jinja_partials import jinja_partials
from decorators import validate_person, validate_topset, validate_workout from decorators import validate_person, validate_topset, validate_workout
from db import DataBase from db import DataBase
from utils import get_people_and_exercise_rep_maxes, convert_str_to_date, get_earliest_and_latest_workout_date, filter_workout_topsets, get_exercise_ids_from_workouts, first_and_last_visible_days_in_month from utils import flatten, get_people_and_exercise_rep_maxes, convert_str_to_date, get_earliest_and_latest_workout_date, filter_workout_topsets, get_exercise_ids_from_workouts, first_and_last_visible_days_in_month
from flask_htmx import HTMX from flask_htmx import HTMX
import minify_html import minify_html
from urllib.parse import urlparse, unquote, quote from urllib.parse import urlparse, unquote, quote
@@ -100,6 +100,32 @@ def get_person(person_id):
filtered_exercises = filter( filtered_exercises = filter(
lambda e: e['ExerciseId'] in active_exercise_ids, person['Exercises']) lambda e: e['ExerciseId'] in active_exercise_ids, person['Exercises'])
person['FilteredExercises'] = list(filtered_exercises) person['FilteredExercises'] = list(filtered_exercises)
# New feature to plot reps and weights over time
topsets_with_start_date = flatten([(p['StartDate'], p['TopSets'])
for p in person['Workouts']])
topsets = flatten([[{**t, 'StartDate': start_date} for t in topsets]
for (start_date, topsets) in topsets_with_start_date])
exercise_graph_view_models = []
for exercise_id in active_exercise_ids:
topsets_for_exercise = [
t for t in topsets if t['ExerciseId'] == exercise_id]
if topsets_for_exercise:
repitions = [t['Repetitions'] for t in topsets_for_exercise]
weights = [t['Weight'] for t in topsets_for_exercise]
start_dates = [t['StartDate'].strftime(
"%Y-%m-%d") for t in topsets_for_exercise]
exercise_view_model = {
'ExerciseId': exercise_id,
'ExerciseName': topsets_for_exercise[0]['ExerciseName'],
'Repititions': repitions[::-1],
'Weights': weights[::-1],
'StartDates': start_dates[::-1]
}
exercise_graph_view_models.append(exercise_view_model)
person['ExerciseGraphs'] = exercise_graph_view_models
if htmx: if htmx:
return render_template('partials/page/person.html', return render_template('partials/page/person.html',
person=person, selected_exercise_ids=active_exercise_ids, max_date=max_date, min_date=min_date, tags=tags), 200, {"HX-Trigger": "updatedPeople"} person=person, selected_exercise_ids=active_exercise_ids, max_date=max_date, min_date=min_date, tags=tags), 200, {"HX-Trigger": "updatedPeople"}

View File

@@ -162,9 +162,52 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="mt-4 mb-4 w-full grid grid-cols-1 2xl:grid-cols-2 gap-4">
{% for exercise_graph in person['ExerciseGraphs'] %}
<div class="bg-white shadow rounded-lg p-4 sm:p-6 xl:p-8 ">
<div class="flex flex-col items-center">
<div class="flex-shrink-0">
<span class="text-2xl sm:text-3xl leading-none font-bold text-gray-900">{{
exercise_graph['ExerciseName'] }}</span>
</div>
<div id="e-{{ exercise_graph['ExerciseId'] }}"></div>
<script>
Plotly.newPlot("e-{{ exercise_graph['ExerciseId'] }}", [
{
x: {{ exercise_graph['StartDates'] | replace('"', "'") | safe }},
y: {{ exercise_graph['Repititions'] | replace('"', "'") | safe }},
name: 'Reps',
type: 'scatter'
},
{
x: {{ exercise_graph['StartDates'] | replace('"', "'") | safe }},
y: {{ exercise_graph['Weights'] | replace('"', "'") | safe }},
name: 'Weight',
yaxis: 'y2',
type: 'scatter'
}
],
{
title: '{{ exercise_graph['ExerciseName'] }}}',
margin: { t: 0 },
xaxis: { type: 'date', showgrid: false },
yaxis: { title: 'Reps', showgrid: false },
yaxis2: {
title: 'Weight',
overlaying: 'y',
side: 'right', showgrid: false
}
}, config);
</script>
</div>
</div>
{% endfor %}
</div>
{{ render_partial('partials/stats.html', stats=person['Stats']) }} {{ render_partial('partials/stats.html', stats=person['Stats']) }}
<button <button

View File

@@ -170,3 +170,16 @@ def first_and_last_visible_days_in_month(first_day_of_month, last_day_of_month):
end_date = last_day_of_month + \ end_date = last_day_of_month + \
timedelta(days=end[last_day_of_month.weekday()]) timedelta(days=end[last_day_of_month.weekday()])
return (start_date, end_date) return (start_date, end_date)
def flatten(lst):
"""
Flatten a list of lists.
"""
result = []
for item in lst:
if isinstance(item, list):
result.extend(flatten(item))
else:
result.append(item)
return result