Refactor exercise progress
This commit is contained in:
37
app.py
37
app.py
@@ -1,7 +1,7 @@
|
|||||||
from datetime import datetime, date, timedelta
|
from datetime import datetime, date, timedelta
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
import os
|
import os
|
||||||
from flask import Flask, render_template, redirect, request, url_for
|
from flask import Flask, abort, render_template, redirect, request, url_for
|
||||||
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||||
import jinja_partials
|
import jinja_partials
|
||||||
from jinja2_fragments import render_block
|
from jinja2_fragments import render_block
|
||||||
@@ -432,37 +432,12 @@ def calculate_relative_positions(start_dates):
|
|||||||
|
|
||||||
@ app.route("/person/<int:person_id>/exercise/<int:exercise_id>/sparkline", methods=['GET'])
|
@ app.route("/person/<int:person_id>/exercise/<int:exercise_id>/sparkline", methods=['GET'])
|
||||||
def get_exercise_progress_for_user(person_id, exercise_id):
|
def get_exercise_progress_for_user(person_id, exercise_id):
|
||||||
width = request.args.get('width', 300, type=int)
|
exercise_progress = db.get_exercise_progress_for_user(person_id, exercise_id)
|
||||||
height = request.args.get('height', 100, type=int)
|
|
||||||
(estimated_1rm, start_dates, messages) = db.get_exercise_progress_for_user(person_id, exercise_id)
|
|
||||||
|
|
||||||
# Calculate vb_width
|
if not exercise_progress:
|
||||||
min_date = min(start_dates)
|
abort(404)
|
||||||
max_date = max(start_dates)
|
|
||||||
date_range = (max_date - min_date).days # e.g., 30 days
|
return render_template('partials/sparkline.html', **exercise_progress)
|
||||||
vb_width = date_range # This can be scaled if needed
|
|
||||||
|
|
||||||
# Calculate vb_height
|
|
||||||
min_value = min(estimated_1rm)
|
|
||||||
max_value = max(estimated_1rm)
|
|
||||||
value_range = max_value - min_value # e.g., 100
|
|
||||||
vb_height = value_range # This can be scaled if needed
|
|
||||||
|
|
||||||
# Scaling factors (optional, for design)
|
|
||||||
width_scaling_factor = 200 / vb_width # e.g., if you want 200px width
|
|
||||||
height_scaling_factor = 75 / vb_height # e.g., if you want 100px height
|
|
||||||
|
|
||||||
# Apply scaling
|
|
||||||
vb_width *= width_scaling_factor
|
|
||||||
vb_height *= height_scaling_factor
|
|
||||||
|
|
||||||
# Scale estimated_1rm between 0 and vb_height
|
|
||||||
estimated_1rm = [((value - min_value) / value_range) * vb_height for value in estimated_1rm]
|
|
||||||
|
|
||||||
relative_positions = calculate_relative_positions(start_dates)
|
|
||||||
data_points = list(zip(estimated_1rm, relative_positions, messages))
|
|
||||||
|
|
||||||
return render_template('partials/sparkline.html', title="GHR", vb_width=vb_width, vb_height=vb_height, data_points=data_points)
|
|
||||||
|
|
||||||
|
|
||||||
@app.teardown_appcontext
|
@app.teardown_appcontext
|
||||||
|
|||||||
57
db.py
57
db.py
@@ -462,16 +462,13 @@ class DataBase():
|
|||||||
exercises = self.execute(
|
exercises = self.execute(
|
||||||
'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):
|
def get_exercise_progress_for_user(self, person_id, exercise_id):
|
||||||
|
# Execute SQL query to fetch topset data for a specific person and exercise
|
||||||
topsets = self.execute("""
|
topsets = self.execute("""
|
||||||
SELECT
|
SELECT
|
||||||
T.topset_id,
|
T.topset_id, E.name AS exercise_name, W.person_id, T.workout_id,
|
||||||
E.name AS exercise_name,
|
T.repetitions, T.weight,
|
||||||
W.person_id,
|
|
||||||
T.workout_id,
|
|
||||||
T.repetitions,
|
|
||||||
T.weight,
|
|
||||||
ROUND((100 * T.weight::NUMERIC::INTEGER) / (101.3 - 2.67123 * T.repetitions), 0)::NUMERIC::INTEGER AS estimated_1rm,
|
ROUND((100 * T.weight::NUMERIC::INTEGER) / (101.3 - 2.67123 * T.repetitions), 0)::NUMERIC::INTEGER AS estimated_1rm,
|
||||||
W.start_date
|
W.start_date
|
||||||
FROM
|
FROM
|
||||||
@@ -481,15 +478,41 @@ class DataBase():
|
|||||||
JOIN
|
JOIN
|
||||||
workout W ON T.workout_id = W.workout_id
|
workout W ON T.workout_id = W.workout_id
|
||||||
WHERE
|
WHERE
|
||||||
W.person_id = %s AND
|
W.person_id = %s AND E.exercise_id = %s
|
||||||
E.exercise_id = %s
|
|
||||||
ORDER BY
|
ORDER BY
|
||||||
W.start_date;""", [person_id, exercise_id])
|
W.start_date;
|
||||||
# Get a list of all estimated_1rm values
|
""", [person_id, exercise_id])
|
||||||
estimated_1rm = [t['estimated_1rm'] for t in topsets]
|
|
||||||
# Get a list of all start_dates
|
|
||||||
start_dates = [t['start_date'] for t in topsets]
|
|
||||||
# Create a list of messages with the structure 'estimated_1rm kg on start_date' with start_date formatted as 'dd/mm/yyyy'
|
|
||||||
messages = [f'{t["repetitions"]} x {t["weight"]}kg ({t["estimated_1rm"]}kg E1RM) on {t["start_date"].strftime("%d/%m/%Y")}' for t in topsets]
|
|
||||||
|
|
||||||
return (estimated_1rm, start_dates, messages)
|
# Return None if no topsets found
|
||||||
|
if not topsets:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Extracting values and calculating value ranges for SVG dimensions
|
||||||
|
estimated_1rm = [t['estimated_1rm'] for t in topsets]
|
||||||
|
start_dates = [t['start_date'] for t in topsets]
|
||||||
|
min_date, max_date = min(start_dates), max(start_dates)
|
||||||
|
min_value, max_value = min(estimated_1rm), max(estimated_1rm)
|
||||||
|
|
||||||
|
# Calculate viewBox dimensions
|
||||||
|
date_range = max_date - min_date
|
||||||
|
value_range = max_value - min_value
|
||||||
|
vb_width, vb_height = date_range.days, value_range
|
||||||
|
vb_width *= 200 / vb_width # Scale to 200px width
|
||||||
|
vb_height *= 75 / vb_height # Scale to 75px height
|
||||||
|
|
||||||
|
# Scale estimated_1rm values for SVG plotting
|
||||||
|
estimated_1rm_scaled = [((value - min_value) / value_range) * vb_height for value in estimated_1rm]
|
||||||
|
total_span = date_range.days or 1
|
||||||
|
relative_positions = [(date - min_date).days / total_span for date in start_dates]
|
||||||
|
|
||||||
|
# Create messages and zip data for SVG plotting
|
||||||
|
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]
|
||||||
|
data_points = zip(estimated_1rm_scaled, relative_positions, messages)
|
||||||
|
|
||||||
|
# Return exercise data with SVG dimensions and data points
|
||||||
|
return {
|
||||||
|
'exercise_name': topsets[0]['exercise_name'],
|
||||||
|
'vb_width': vb_width,
|
||||||
|
'vb_height': vb_height,
|
||||||
|
'data_points': list(data_points)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user