Skip to content

Instantly share code, notes, and snippets.

@kenprice
Last active January 1, 2019 09:13
Show Gist options
  • Save kenprice/d9a4c1c2cba5a7ae5465cce8ce8ad48f to your computer and use it in GitHub Desktop.
Save kenprice/d9a4c1c2cba5a7ae5465cce8ce8ad48f to your computer and use it in GitHub Desktop.
fitnotes-graph
# Given FitNotes CSV export, plot estimated 1RM
#
# Usage: fitnotes_graph.py <FILE>
# <FILE> is exported csv
# Assumes format:
# ['Date', 'Exercise', 'Category', 'Weight (lbs)', 'Reps', 'Distance',
# 'Distance Unit', 'Time', 'Comment']
import csv
from datetime import datetime
from dateutil.relativedelta import relativedelta
import itertools
import matplotlib.pyplot as plt
import os
import sys
filepath = sys.argv[1]
# Structure
# categories = {
# "Legs": {
# "Standing Calf Raise": [ ... ], ...
# }, ...
# }
categories = {}
# 1RM Estimate Table:
brzycki = dict(((1, .100), (2, .95), (3, .90), (4, .88), (5, .86), (6, .83), \
(7, .80), (8, .78), (9, .76), (10, .75), (11, .72), (12, .70)))
# Populate categories of exercises
with open(filepath) as f:
fitnotes = csv.reader(f, delimiter=',')
for i, row in enumerate(fitnotes):
if i == 0:
continue
date, exercise, category, weight, reps, distance, dunit, \
time, comment = row
# Skip exercises with no weights (like ab crunches)
if float(weight) == 0.0:
continue
if category not in categories:
categories[category] = {}
exercises = categories[category]
if exercise not in exercises:
exercises[exercise] = []
reps = int(reps)
one_rm = None
# Compute 1RM estimate using brzycki table
if reps in brzycki:
one_rm = int(float(weight) / brzycki[reps])
else:
# Approx. 1RM beyond 12 reps by using value for 12 reps
one_rm = int(float(weight) / brzycki[12])
date = datetime.strptime(date, "%Y-%m-%d")
# If there's already an exercise recorded for same date,
# then keep best rep (want unique dates for each exercise)
# Assumes CSV file is sorted by date
if len(exercises[exercise]) > 0 and \
exercises[exercise][-1][0] == date:
if reps > exercises[exercise][-1][2]:
exercises[exercise].pop()
exercises[exercise].append( \
(date, weight, reps, one_rm))
else:
exercises[exercise].append( \
(date, weight, reps, one_rm))
def saveExercisePlot(category, exercise):
print(category, exercise)
x = [item[0] for item in categories[category][exercise]]
y = [item[3] for item in categories[category][exercise]]
plt.plot(x, y, linestyle='--')
plt.gcf().autofmt_xdate()
def datespan(startDate, endDate, delta):
currentDate = startDate
while currentDate < endDate:
yield currentDate
currentDate += delta
month_delta = relativedelta(months=+1)
x_month = []
y_month = []
# Kind of a brute-force way to chunk data by month - want to get
# best 1RM by month
for x_date in datespan(x[0], x[-1] + month_delta, delta=month_delta):
print (x_date)
best_1rm = 0
best_date = None
for item in categories[category][exercise]:
if item[3] is None:
continue
if item[0].month == x_date.month and item[0].year == x_date.year:
if best_1rm < item[3]:
best_1rm = item[3]
best_date = item[0]
if best_date is not None:
x_month.append(best_date)
y_month.append(best_1rm)
if len(x_month) > 0:
plt.plot(x_month, y_month, marker='o')
category_name = ''.join(e for e in category if e.isalnum())
if not os.path.exists("out/" + category_name):
os.makedirs("out/" + category_name)
exercise_name = ''.join(e for e in exercise if e.isalnum())
plt.savefig("out/" + category_name + "/" + exercise_name + ".png")
plt.gcf().clear()
if not os.path.exists("out"):
os.makedirs("out")
for c_key in categories.keys():
for e_key in categories[c_key].keys():
saveExercisePlot(c_key, e_key)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment