🏡 Blamechance's Digital Cottage

Search

Search IconIcon to open search

Fitness Dashboard README

Last updated Feb 29, 2024 Edit Source

# Fitness Dashboard

# Video Demo:

https://youtu.be/Np4lORlm-Y0

# Concept:

My friends and I have been using the FitNotes mobile app to recording our weightlifting training data for years now, but the app is mostly for personal use, and so the information is not easily shared or visible to each other.

Features include:

In future, I plan to add more functions to supplement our fitness journeys, such as a TDEE calculator and a Bulk/Cut Diet Planning Calculator.

# Directories:

The significant items in the root directory of the project are:

# app_core:

This folder contains blueprints and .py helper files that make up the majority of the processing logic of the project.

all_user_data: ser file submissions, and the subsequent processed file results are saved in separate folders here, split as per:

blueprints: This folder contains the 2 main submission processing logic .py files. The logic flow will be explained further down below.

# flask_session:

This is from a flask module to enable the facilitating of user sessions, through client-side cookie interaction.

# static:

This directory contains the main styles.css file, as well as favicons for the site.

# templates:

Here is contained all the HTML pages for the website, as accessible through the navbar. layout.html is the template which is used by the other pages, to extend the consistent elements to (navbar, JavaScript code linking etc).

# requirements.txt:

This is where all the modules were captured to, with pip freeze.

# Logic/Implementation Explanation:

# User Accounts Database:

# Shared Submission Functions:

validateCSV():

/upload:

# Weight Data Submission:

# Basic Logic Flow

  1. When the form incheckin.html is submitted with the weight log field, the onsubmit="" function will first be called, to validate whether the user indeed attached a CSV file, and that it is not empty.

  2. If these conditions are present, then the form proceeds to make an asynchronous ajax call to the /upload flask route, which runs further file validation functionality server-side.

    • If the file is as expected, then process_weight_log() will be called to produce the processed JSON data for site functions, using the input file.
  3. The client window will then wait to receive either a success or error/failed screen, to represent whether the submission is valid, uploaded and ready for viewing on the site; or whether it was invalid and subsequently disposed of.

# Functions:

/process_weight_log:

# Training Data Submissions:

# Basic Logic Flow:

Similar to weight submissions, the process_training_log() function is called as part of the submission form’s action, after passing the basic onsubmit() empty file check.

  1. Each row is iterated over using panda’s .iterrows() to first:

    • Produce a dict containing all the training data – this is eventually saved as it’s own All-Training-Data-user-timestamp JSON file.
    • All NaN datatypes due to empty fields are applied with the N/A string instead, for compatible representation with tabulator.
  2. If a processed weight JSON file is available for the user (found for user within .../w_log_archive) , it will also make use of that data to create strength index values (calling calculate_SI()) and append it to the dataframe.

    • This is a custom formula which takes into account the user’s weight, and the rep range of the exercises set to develop a relative strength index score.
    • Weight records recorded within +/- 3 days of the date the exercises was executed are averaged to a single value, and then utilised for formula purposes.
    • The intention, is to allow users to compare strength feats, even if the context of data contains varying reps, bodyweight and exercise weight.
    • If no weight data is available, the strength index field for that row will be left blank.
    • The algorithim is a basic O(n), if x in y test between all weight entries and all exercise entries.
  3. A second iteration is made over the dict created in step 1, now filtering/copying relevant records into two other dicts:

    • These are used to preload different table data on the dashboard.
    • Algorithm is also O(n), though a single pass will be used to produce the required 2 output results.
    • Highest Weight PR dict:
      • Tracks the highest weight lifted, for each exercise. Substitutes heavier records during iterations to come to a single dict containing only the heaviest lifts of each exercise (Personal bests).
    • Strength Index PR dict:
      • Similar implementation as above, but instead tracks strength index scores.
  4. Each of these 3 data structures are then output and saved as JSON files, to be used by the dashboard elements: Namely:

    • All-Training-Data_user_2024-02-06
    • Heaviest-PRs_user_2024-02-06
    • SI-PRs_user_2024-02-06

# Functions:

calculate_SI The Strength Index (SI) is a custom formula designed to measure the strength feat of an exercise set, reagardless of fluctuating context (bodyweight, reps executed etc).

1
[ Reps x weight ] / [ bodyweight(kg) x RR Factor* ]
Reps RangeScaling Factor
1-2 reps3.3
3-6 reps1.4
7-10 reps1 (normal)
11-15 reps0.8
16+ repsNone (don’t calculate due to obvious skewing)

# Dashboard Explanation:

# Modules:

# Data Flow:

  1. From the submission/processing functions, JSON files are ready on the server.
  2. This data is passed to the HTML template using Jinja templating.
  3. JavaScript is then used to substitute this data into the options for tabulator and chart.js
    • This allows for the client to load and switch between datasets dynamically without making server requests, after they fully load page the first time.

# Elements:

# Other Design notes:

# Metric System Measurement Support Only: