Skip to content

Instantly share code, notes, and snippets.

@kmcallister
Created July 28, 2019 17:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kmcallister/19c9898fea0d76156fa2f1925ace2164 to your computer and use it in GitHub Desktop.
Save kmcallister/19c9898fea0d76156fa2f1925ace2164 to your computer and use it in GitHub Desktop.
Weight tracking scripts
#!/bin/sh
#set -e
./ewma.py < log > smoothed
echo
./progress.py "$@" < smoothed
echo
gnuplot < weight-graph.gpl
#./maintain.py < log
#echo
./rate.py < smoothed > rate
gnuplot < rate-graph.gpl
cp log backup/$(tail -n 1 log | awk '{print $1}')
#!/usr/bin/python
import sys
import argparse
import time
import datetime
argparser = argparse.ArgumentParser()
argparser.add_argument('--verbose', '-v', action='store_true')
argparser.add_argument('--alpha', '-a', type=float, default=0.1)
args = argparser.parse_args()
if args.alpha < 0.0 or args.alpha > 1.0:
raise ValueError, "you suck"
ewma = 0.0
def update(weight):
global ewma
ewma = args.alpha*weight + (1.0 - args.alpha)*ewma
last_ordinal = None
last_weight = None
for ln in sys.stdin:
date, weight = ln.split()
date = datetime.datetime.strptime(date, '%Y-%m-%d')
weight = float(weight)
ordinal = date.toordinal()
if args.verbose:
print (date.toordinal(), weight)
if last_ordinal is None:
last_ordinal = ordinal
last_weight = weight
ewma = weight
else:
last_ordinal += 1
while last_ordinal < ordinal:
if args.verbose:
print 'Missing day, using', last_weight
update(last_weight)
last_ordinal += 1
if args.verbose:
print 'Update with', weight
update(weight)
last_weight = weight
print date.strftime('%Y-%m-%d'), ewma
#!/usr/bin/env python
import datetime
import sys
import math
import argparse
import numpy
from scipy import stats
goal = 234
window = 30
points = []
confidence = 0.05
for ln in sys.stdin:
date, weight = ln.split()
date = datetime.datetime.strptime(date, '%Y-%m-%d')
weight = float(weight)
points.append((date, weight))
points = points[-window:]
weights = [p[1] for p in points]
minw, maxw, avgw = (min(weights), max(weights), numpy.average(weights))
t_stat, p_value = stats.ttest_1samp(weights, goal)
print 'Target: %6.2f lbs' % (goal,)
print 'Range: %6.2f lbs' % (maxw-minw,)
print 'Std deviation: %6.2f lbs' % (numpy.std(weights),)
print 'Min/avg/max: %6.2f / %6.2f / %6.2f' % (minw, avgw, maxw)
print 'Deltas: %6.2f / %6.2f / %6.2f' % (minw-goal, avgw-goal, maxw-goal)
print
print 'Verdict: ', 'Maintaining!' if p_value > confidence else 'Not maintaining', '(p = %.2f)' % (p_value,)
#!/usr/bin/env python
import datetime
import sys
import math
import argparse
from scipy import stats
argparser = argparse.ArgumentParser()
argparser.add_argument('--reddit', '-r', action='store_true')
args = argparser.parse_args()
parse_date = lambda s: datetime.datetime.strptime(s, "%Y-%m-%d")
goal = 225
goal_date = parse_date("2019-06-01")
window = 30
height = 1.91 # meters
kg_per_lb = 0.453592
points = []
def parse(ln):
date, weight = ln.split()
date = datetime.datetime.strptime(date, '%Y-%m-%d')
weight = float(weight)
return (date, weight)
lines = list(sys.stdin)
start_date, start = parse(lines[0])
points = map(parse, lines)
num_points = len(points)
num_decrease = sum(1 for p, q in zip(points, points[1:]) if p[1] > q[1])
points = points[-window:]
first = points[0]
last = points[-1]
reg_x = [p[0].toordinal() for p in points]
reg_y = [p[1] for p in points]
slope, intercept, r_value, p_value, stderr = stats.linregress(reg_x, reg_y)
#rate = (first[1] - last[1]) / (last[0] - first[0]).days
rate = -slope
if rate <= 0.0:
print "Sorry, you're getting fatter at %.2f lb/wk (r^2 = %.2f)" % (-7.0*rate, r_value**2.0)
sys.exit(1)
def output_stat(label, value):
if args.reddit:
print '**' + label + '**|' + value.lstrip()
else:
print (label + ':').ljust(17) + value
done = start - last[1]
days_done = (last[0] - start_date).days
remainder = last[1] - goal
remaining_time = datetime.timedelta(days = remainder / rate)
finish_date = last[0] + remaining_time
margin = (goal_date - finish_date).days + 1
required_rate = remainder / (goal_date - last[0]).days
excess_rate = rate - required_rate
def project(date):
projection = last[1] - (rate * (parse_date(date) - last[0]).days)
print 'Weight on %s: %6.2f lbs = %6.2f lbs lost' % (date, projection, start - projection)
if args.reddit:
print 'Stat|Value'
print ':-|:-'
output_stat('Current weight', '%6.2f lbs' % (last[1],))
#output_stat('BMI', '%6.2f' % ((kg_per_lb * last[1]) / (height ** 2.0),))
output_stat('Lost so far', '%6.2f lbs = %5.2f%% of starting weight' % (done, 100.0 * done / start))
output_stat('Remaining', '%6.2f lbs = %5.2f%% of current weight' % (remainder, 100.0 * remainder / last[1]))
output_stat('Progress', '%6.2f %%' % (done / (start - goal) * 100.0,))
output_stat('Required rate', '%6.2f lbs / wk' % (7.0 * required_rate,))
output_stat('Actual rate', '%6.2f lbs / wk = %.2f%% per week (r^2 = %4.2f)' % (7.0*rate, 100*7.0*rate / last[1], r_value**2.0))
#output_stat('Excess rate', '%6.2f lbs / wk' % (7.0*excess_rate,))
output_stat('Deficit', ' %4d kcal / day' % (rate*3500,))
#output_stat('Excess deficit', ' %4d kcal/day' % (excess_rate*3500,))
output_stat('All-time rate', '%6.2f lbs / wk' % (7.0 * done / days_done,))
output_stat('Average drops', '%6.2f %% of the time (%d out of %d points)' % (100.0 * num_decrease / float(num_points), num_decrease, num_points))
print
print 'Goal will be reached on %s' % (finish_date.strftime('%Y-%m-%d'),),
if margin > 0:
print '(%d days early)' % (margin,)
else:
print '(%d days late)' % (-margin,)
if args.reddit:
print
print days_done, 'days done, only', remaining_time.days, 'left to go! Keep it up, you\'re doing great!'
print
project('2019-06-01')
with open('regression_line', 'w') as f:
line_out = lambda pt: f.write(pt[0].strftime('%Y-%m-%d') + ' ' + str(intercept + slope*pt[0].toordinal()) + '\n')
line_out(points[0])
line_out(points[-1])
set title "Weight loss rate"
set ylabel "Pounds per week"
#set y2label "r^2"
set term png size 1400,900
set output "rate-graph.png"
set timefmt "%Y-%m-%d"
set xdata time
set format x "%b\n%d"
#set xrange ["2018-02-18":]
plot "rate" using 1:2 with lines lw 3 title "Rate", \
#"rate" using 1:3 with lines lw 1 title "r^2" axes x1y2
#!/usr/bin/env python
import datetime
import sys
import math
import argparse
from scipy import stats
window = 14
points = []
for ln in sys.stdin:
date, weight = ln.split()
date = datetime.datetime.strptime(date, '%Y-%m-%d')
weight = float(weight)
points.append((date, weight))
points = points[-window:]
if len(points) < window:
continue
reg_x = [p[0].toordinal() for p in points]
reg_y = [p[1] for p in points]
slope, intercept, r_value, p_value, stderr = stats.linregress(reg_x, reg_y)
print date.strftime("%Y-%m-%d"), -7.0*slope, r_value**2.0
set title "Weight loss progress"
set ylabel "Weight (lbs)"
set term png size 1400,900
set output "weight-graph.png"
set timefmt "%Y-%m-%d"
set xdata time
set format x "%b\n%d"
#set xrange ["2018-08-01":]
#set yrange [240:290]
plot "log" using 1:2 with linespoints pointtype 6 title "Daily weight", \
"smoothed" using 1:2 with lines lw 3 title "Moving average", \
"regression_line" using 1:2 title "Trend line" with lines lw 2 lt rgb "#c01f1f", \
# "raw_line" using 1:2 title "Raw trend line" with lines lw 2 lt rgb "blue"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment