From 545cfa0dec69ea3694974203b3b7c0a6b2912f16 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Sun, 3 Jan 2021 15:57:09 +0100
Subject: [PATCH] better representation of marker workouts
---
rowers/forms.py | 2 -
rowers/interactiveplots.py | 63 ++++++++++++++++--------
rowers/models.py | 1 -
rowers/templates/performancemanager.html | 40 +++++++++++++--
rowers/templatetags/rowerfilters.py | 1 +
rowers/views/analysisviews.py | 14 +++---
6 files changed, 89 insertions(+), 32 deletions(-)
diff --git a/rowers/forms.py b/rowers/forms.py
index 763d4fdb..f2d73740 100644
--- a/rowers/forms.py
+++ b/rowers/forms.py
@@ -739,8 +739,6 @@ class PerformanceManagerForm(forms.Form):
doform = forms.BooleanField(required=False,initial=False,
label='Freshness')
- showtests = forms.BooleanField(required=False,initial=False,
- label='Show my best workouts')
class FitnessFitForm(forms.Form):
startdate = forms.DateField(
diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py
index 3ccc776d..1809be10 100644
--- a/rowers/interactiveplots.py
+++ b/rowers/interactiveplots.py
@@ -114,6 +114,15 @@ def newtestpower(x):
return x['testpower']
+def newtestpowerid(x):
+ try:
+ if np.isnan(x['testpower']):
+ return np.nan
+ except (AttributeError,TypeError):
+ return np.nan
+
+ return x['id']
+
def build_goldmedalstandards(workouts,kfitness):
dates = []
testpower = []
@@ -125,11 +134,14 @@ def build_goldmedalstandards(workouts,kfitness):
data = []
goldmedalstandards = []
goldmedaldurations = []
- ids = []
workoutdt = []
+ ids = []
+
+ outids = []
+
for w in workouts:
- goldmedalstandard,goldmedalseconds = dataprep.workout_goldmedalstandard(w)
ids.append(w.id)
+ goldmedalstandard,goldmedalseconds = dataprep.workout_goldmedalstandard(w)
if goldmedalseconds > 60:
goldmedalstandards.append(goldmedalstandard)
goldmedaldurations.append(goldmedalseconds)
@@ -170,6 +182,7 @@ def build_goldmedalstandards(workouts,kfitness):
powerdf = df[df['workout'].isin(ids)]
indexmax = powerdf['goldmedalstandard'].idxmax()
+ theid = powerdf.loc[indexmax,'workout']
powertest = powerdf['goldmedalstandard'].max()
durationtest = powerdf.loc[indexmax,'goldmedalduration']
@@ -178,15 +191,17 @@ def build_goldmedalstandards(workouts,kfitness):
if powertest > 0:
testpower.append(powertest)
testduration.append(durationtest)
+ outids.append(theid)
else:
testpower.append(np.nan)
testduration.append(np.nan)
+ outids.append(np.nan)
fatigues.append(np.nan)
fitnesses.append(np.nan)
impulses.append(np.nan)
- return dates, testpower, testduration, fatigues, fitnesses,impulses
+ return dates, testpower, testduration, fatigues, fitnesses,impulses,outids
def get_testpower(workouts,fitnesstestsecs,kfitness):
@@ -1760,6 +1775,7 @@ def getfatigues(
testduration.append(np.nan)
+
return fatigues,fitnesses,dates,testpower,testduration,impulses
def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
@@ -1787,16 +1803,19 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
testduration = []
impulses = []
+ outids = []
+
if showtests:
workouts = Workout.objects.filter(user=user.rower,date__gte=startdate,
date__lte=enddate,
workouttype__in=mytypes.rowtypes,
duplicate=False)
- dates,testpower,testduration,fatigues,fitnesses,impulses = build_goldmedalstandards(
+ dates,testpower,testduration,fatigues,fitnesses,impulses, outids = build_goldmedalstandards(
workouts,kfitness
)
df = pd.DataFrame({
+ 'id': outids,
'date':dates,
'testpower':testpower,
'testduration':testduration,
@@ -1807,11 +1826,12 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
df.sort_values(['date'],inplace=True)
df['testdup'] = df['testpower'].shift(1)
df['testpower'] = df.apply(lambda x: newtestpower(x),axis=1)
+ df['id'] = df.apply(lambda x: newtestpowerid(x),axis=1)
- try:
- df['testpower'].iloc[-1] = df['testdup'].iloc[-1]
- except IndexError:
- pass
+ #try:
+ # df['testpower'].iloc[-1] = df['testdup'].iloc[-1]
+ #except IndexError:
+ # pass
dates = [d for d in df['date']]
@@ -1820,6 +1840,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
fitnesses = df['fitness'].values.tolist()
testduration = df['testduration'].values.tolist()
impulses = df['impulse'].tolist()
+ outids = df['id'].unique()
fatigues,fitnesses,dates,testpower,testduration,impulses = getfatigues(fatigues,
fitnesses,
@@ -1859,6 +1880,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
df = df.groupby(['date']).max()
df['date'] = df.index.values
+
#for row in df.iterrows():
# print(row)
@@ -1928,9 +1950,9 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
yaxlabel = 'Fitness'
- if showtests:
- plot.circle('date','testpower',source=source,fill_color='green',size=10,
- legend_label='Your best workouts')
+ #if showtests:
+ # plot.circle('date','testpower',source=source,fill_color='green',size=10,
+ # legend_label='Your best workouts')
plot.xaxis.axis_label = None
plot.yaxis.axis_label = yaxlabel
@@ -1938,13 +1960,13 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
y2rangemin = df.loc[:,['form']].min().min()
y2rangemax = df.loc[:,['form']].max().max()
- if dofatigue and showtests:
- y1rangemin = df.loc[:,['testpower','fitness','fatigue']].min().min()
- y1rangemax = df.loc[:,['testpower','fitness','fatigue']].max().max()*1.02
- elif showtests:
- y1rangemin = df.loc[:,['testpower','fitness']].min().min()
- y1rangemax = df.loc[:,['testpower','fitness']].max().max()*1.02
- elif dofatigue:
+ #if dofatigue and showtests:
+ # y1rangemin = df.loc[:,['testpower','fitness','fatigue']].min().min()
+ # y1rangemax = df.loc[:,['testpower','fitness','fatigue']].max().max()*1.02
+ #elif showtests:
+ # y1rangemin = df.loc[:,['testpower','fitness']].min().min()
+ # y1rangemax = df.loc[:,['testpower','fitness']].max().max()*1.02
+ if dofatigue:
y1rangemin = df.loc[:,['fitness','fatigue']].min().min()
y1rangemax = df.loc[:,['fitness','fatigue']].max().max()*1.02
else:
@@ -2024,6 +2046,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
plot2.y_range = Range1d(0,df['impulse'].max())
plot2.vbar(x = df['date'], top = df['impulse'],color='gray')
+ plot2.vbar(x = df['date'], top = 0*df['testpower']+df['impulse'], color='red')
plot2.sizing_mode = 'scale_both'
plot2.yaxis.axis_label = 'Impulse'
@@ -2045,10 +2068,10 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
nrworkouts = workouts.count(),
nrdata = len(df),
e = e,
- )
+ ),0,0,0,[]
)
- return [script,div,endfitness,endfatigue,endform]
+ return [script,div,endfitness,endfatigue,endform,outids]
def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
diff --git a/rowers/models.py b/rowers/models.py
index 54ceb777..aa31934e 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -891,7 +891,6 @@ class Rower(models.Model):
kfatigue = models.IntegerField(default=7,verbose_name='Fatigue Time Decay Constant (days)')
showfit = models.BooleanField(default=False)
showfresh = models.BooleanField(default=False)
- showtests = models.BooleanField(default=False)
pw_ut2 = models.IntegerField(default=124,verbose_name="UT2 Power")
pw_ut1 = models.IntegerField(default=171,verbose_name="UT1 Power")
diff --git a/rowers/templates/performancemanager.html b/rowers/templates/performancemanager.html
index e4a8a0f3..06908470 100644
--- a/rowers/templates/performancemanager.html
+++ b/rowers/templates/performancemanager.html
@@ -113,9 +113,12 @@
make this chart shorter than a few months.
- Optionally, the chart shows you workouts that represent your best performance for that period.
- We automatically detect hard workout segments and tests and compare them to world class
- ("Gold Medal") standards for your gender, weight and age category.
+ The bottom chart shows the training impulse of each individual workout. A gray bar
+ denotes a regular workout. The red bars denote workouts that stand out in terms
+ of your power/time performance for that period. This is only available for workouts
+ where Power (Watts) is measured. How well you performed is expressed as a
+ Gold Medal Score, where 100 means you are as good as the world class
+ athletes of your gender, weight and age category.
For this chart to reflect your fitness and freshness, it is important to have all workouts on
@@ -148,6 +151,37 @@
+ {% if bestworkouts %}
+ Marker Workouts
+
+
+
+
+ | Date |
+ Workout |
+ Gold Medal Score |
+ Duration |
+
+
+
+ {% for w in bestworkouts %}
+
+ | {{ w.date }} |
+
+ {{ w.name }}
+ |
+
+ {{ w.goldmedalstandard|floatformat:"0" }} %
+ |
+
+ {{ w.goldmedalseconds|secondstotimestring }}
+ |
+
+ {% endfor %}
+
+
+
+ {% endif %}
diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py
index b6edc61f..dd33bcf1 100644
--- a/rowers/templatetags/rowerfilters.py
+++ b/rowers/templatetags/rowerfilters.py
@@ -270,6 +270,7 @@ def strfdeltah(tdelta):
return res
+@register.filter
def secondstotimestring(tdelta):
hours, rest = divmod(tdelta,3600)
minutes,seconds = divmod(rest,60)
diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py
index 787f85ad..f879150c 100644
--- a/rowers/views/analysisviews.py
+++ b/rowers/views/analysisviews.py
@@ -1567,7 +1567,6 @@ def performancemanager_view(request,userid=0,mode='rower',
usegoldmedalstandard = False
doform = therower.showfresh
dofatigue = therower.showfit
- showtests = therower.showtests
if request.method == 'POST':
form = PerformanceManagerForm(request.POST)
@@ -1577,28 +1576,30 @@ def performancemanager_view(request,userid=0,mode='rower',
metricchoice = form.cleaned_data['metricchoice']
dofatigue = form.cleaned_data['dofatigue']
doform = form.cleaned_data['doform']
- showtests = form.cleaned_data['showtests']
therower.showfresh = doform
therower.showfatigue = dofatigue
- therower.showtests = showtests
therower.save()
else:
form = PerformanceManagerForm(initial={
'doform':doform,
'dofatigue':dofatigue,
- 'showtests':showtests,
})
- script, thediv, endfitness, endfatigue, endform = performance_chart(
+ script, thediv, endfitness, endfatigue, endform, ids = performance_chart(
theuser,startdate=startdate,enddate=enddate,
kfitness = kfitness,
kfatigue = kfatigue,
metricchoice = metricchoice,
doform = doform,
dofatigue = dofatigue,
- showtests = showtests,
+ showtests = True,
)
+ ids = pd.Series(ids).dropna().values
+
+ bestworkouts = Workout.objects.filter(id__in=ids).order_by('date')
+
+
breadcrumbs = [
{
'url':'/rowers/analysis',
@@ -1634,6 +1635,7 @@ def performancemanager_view(request,userid=0,mode='rower',
'endfitness':int(endfitness),
'endfatigue':int(endfatigue),
'endform':int(endform),
+ 'bestworkouts':bestworkouts,
})