Add options to filter epoch for exercise progress graphs (1M, 3M, 6M, All), however if there isnt data in a selected epoch the endpoint returns 404. Havent bothered to look into to it, probs should clean up code as well

This commit is contained in:
Peter Stockings
2024-04-03 20:31:13 +11:00
parent dae4fcbf44
commit 6dafdf71dd
4 changed files with 37 additions and 7 deletions

4
app.py
View File

@@ -413,7 +413,9 @@ def get_exercise_progress_for_user(person_id, exercise_id):
'min_date'), '%Y-%m-%d') 'min_date'), '%Y-%m-%d')
max_date = convert_str_to_date(request.args.get( max_date = convert_str_to_date(request.args.get(
'max_date'), '%Y-%m-%d') 'max_date'), '%Y-%m-%d')
exercise_progress = db.get_exercise_progress_for_user(person_id, exercise_id, min_date, max_date) epoch = request.args.get('epoch', default='All')
exercise_progress = db.get_exercise_progress_for_user(person_id, exercise_id, min_date, max_date, epoch)
if not exercise_progress: if not exercise_progress:
abort(404) abort(404)

12
db.py
View File

@@ -3,6 +3,7 @@ import psycopg2
import numpy as np import numpy as np
from psycopg2.extras import RealDictCursor from psycopg2.extras import RealDictCursor
from datetime import datetime from datetime import datetime
from dateutil.relativedelta import relativedelta
from urllib.parse import urlparse from urllib.parse import urlparse
from flask import g from flask import g
@@ -450,7 +451,14 @@ class DataBase():
'SELECT exercise_id, name FROM exercise') 'SELECT exercise_id, name FROM exercise')
return exercises return exercises
def get_exercise_progress_for_user(self, person_id, exercise_id, min_date=None, max_date=None): def get_exercise_progress_for_user(self, person_id, exercise_id, min_date=None, max_date=None, epoch='all'):
today = datetime.now()
if epoch == '1M':
min_date = today - relativedelta(months=1)
elif epoch == '3M':
min_date = today - relativedelta(months=3)
elif epoch == '6M':
min_date = today - relativedelta(months=6)
# Execute SQL query to fetch topset data for a specific person and exercise # Execute SQL query to fetch topset data for a specific person and exercise
topsets = self.execute(""" topsets = self.execute("""
SELECT SELECT
@@ -484,7 +492,7 @@ class DataBase():
start_dates = [t['start_date'] for t in topsets] start_dates = [t['start_date'] for t in topsets]
messages = [f'{t["repetitions"]} x {t["weight"]}kg ({t["estimated_1rm"]}kg E1RM) on {t["start_date"].strftime("%d %b %y")}' for t in topsets] messages = [f'{t["repetitions"]} x {t["weight"]}kg ({t["estimated_1rm"]}kg E1RM) on {t["start_date"].strftime("%d %b %y")}' for t in topsets]
exercise_progress = get_exercise_graph_model(topsets[0]['exercise_name'], estimated_1rm, repetitions, weight, start_dates, messages) exercise_progress = get_exercise_graph_model(topsets[0]['exercise_name'], estimated_1rm, repetitions, weight, start_dates, messages, epoch, person_id, exercise_id)
return exercise_progress return exercise_progress

View File

@@ -47,11 +47,24 @@
<!-- Popover content will be dynamically inserted here --> <!-- Popover content will be dynamically inserted here -->
</div> </div>
<h4 class="text-l font-semibold text-blue-400 text-center">{{ title }}</h4> <h4 class="text-l font-semibold text-blue-400 text-center">{{ title }}</h4>
<h2 class="text-xs font-semibold text-blue-200 mb-2 text-center" style='font-family: "Computer Modern Sans", sans-serif;'> <h2 class="text-xs font-semibold text-blue-200 mb-1 text-center" style='font-family: "Computer Modern Sans", sans-serif;'>
{% if best_fit_formula %} {% if best_fit_formula %}
y = {{ best_fit_formula.slope }}x {% if best_fit_formula.intercept != 0 %}+ {{ best_fit_formula.intercept }}{% endif %}, {{ best_fit_formula.kg_per_week }} kg/week, {{ best_fit_formula.kg_per_month }} kg/month y = {{ best_fit_formula.slope }}x {% if best_fit_formula.intercept != 0 %}+ {{ best_fit_formula.intercept }}{% endif %}, {{ best_fit_formula.kg_per_week }} kg/week, {{ best_fit_formula.kg_per_month }} kg/month
{% endif %} {% endif %}
</h2> </h2>
<div class="inline-flex rounded-md shadow-sm w-full items-center justify-center mb-1">
{% for epoch in epochs %}
<div
{% if selected_epoch == epoch %}
class="px-4 py-2 text-sm font-medium text-blue-700 bg-white border border-gray-200 rounded-s-lg hover:bg-gray-100 focus:z-10 focus:ring-2 focus:ring-blue-700 focus:text-blue-700 dark:bg-gray-800 dark:border-gray-700 dark:text-white dark:hover:text-white dark:hover:bg-gray-700 dark:focus:ring-blue-500 dark:focus:text-white"
{% else %}
class="px-4 py-2 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-e-lg hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-2 focus:ring-blue-700 focus:text-blue-700 dark:bg-gray-800 dark:border-gray-700 dark:text-white dark:hover:text-white dark:hover:bg-gray-700 dark:focus:ring-blue-500 dark:focus:text-white cursor-pointer"
hx-get='{{ url_for("get_exercise_progress_for_user", person_id=person_id, exercise_id=exercise_id, epoch=epoch) }}' hx-target="#svg-plot-{{ unique_id }}" hx-swap="outerHTML" hx-trigger="click"
{% endif %}>
{{ epoch}}
</div>
{% endfor %}
</div>
<svg viewBox="0 0 {{ (vb_width + 2*margin) | int }} {{ (vb_height + 2*margin) | int }}" preserveAspectRatio="none"> <svg viewBox="0 0 {{ (vb_width + 2*margin) | int }} {{ (vb_height + 2*margin) | int }}" preserveAspectRatio="none">
{% for plot in plots %} {% for plot in plots %}
<g class="{{ plot.label }}" style="fill: {{ plot.color }}; stroke: {{ plot.color }};"> <g class="{{ plot.label }}" style="fill: {{ plot.color }}; stroke: {{ plot.color }};">

View File

@@ -52,8 +52,11 @@ def get_topsets_for_person(person_topsets):
weight = [t['Weight'] for t in exercise_topsets] weight = [t['Weight'] for t in exercise_topsets]
start_dates = [t['StartDate'] for t in exercise_topsets] start_dates = [t['StartDate'] for t in exercise_topsets]
messages = [f'{t["Repetitions"]} x {t["Weight"]}kg ({t["Estimated1RM"]}kg E1RM) on {t["StartDate"].strftime("%d %b %y")}' for t in exercise_topsets] messages = [f'{t["Repetitions"]} x {t["Weight"]}kg ({t["Estimated1RM"]}kg E1RM) on {t["StartDate"].strftime("%d %b %y")}' for t in exercise_topsets]
epoch = 'All'
person_id = exercise_topsets[0]['PersonId']
exercise_id = exercise_topsets[0]['ExerciseId']
exercise_progress = get_exercise_graph_model(exercise_topsets[0]['ExerciseName'], estimated_1rm, repetitions, weight, start_dates, messages) exercise_progress = get_exercise_graph_model(exercise_topsets[0]['ExerciseName'], estimated_1rm, repetitions, weight, start_dates, messages, epoch, person_id, exercise_id)
exercises_topsets.append({ exercises_topsets.append({
'ExerciseId': e['ExerciseId'], 'ExerciseId': e['ExerciseId'],
@@ -236,7 +239,7 @@ def get_date_info(input_date, selected_view):
'end_date': last_day_of_year, 'end_date': last_day_of_year,
} }
def get_exercise_graph_model(title, estimated_1rm, repetitions, weight, start_dates, messages): def get_exercise_graph_model(title, estimated_1rm, repetitions, weight, start_dates, messages, epoch, person_id, exercise_id):
min_date, max_date = min(start_dates), max(start_dates) min_date, max_date = min(start_dates), max(start_dates)
min_e1rm, max_e1rm = min(estimated_1rm), max(estimated_1rm) min_e1rm, max_e1rm = min(estimated_1rm), max(estimated_1rm)
min_reps, max_reps = min(repetitions), max(repetitions) min_reps, max_reps = min(repetitions), max(repetitions)
@@ -318,7 +321,11 @@ def get_exercise_graph_model(title, estimated_1rm, repetitions, weight, start_da
'plots': [repetitions, weight, estimated_1rm], 'plots': [repetitions, weight, estimated_1rm],
'best_fit_points': best_fit_points, 'best_fit_points': best_fit_points,
'best_fit_formula': best_fit_formula, 'best_fit_formula': best_fit_formula,
'plot_labels': plot_labels 'plot_labels': plot_labels,
'epochs': ['1M', '3M', '6M', 'All'],
'selected_epoch': epoch,
'person_id': person_id,
'exercise_id': exercise_id
} }
def get_workout_counts(workouts, period='week'): def get_workout_counts(workouts, period='week'):