From 939a3e27c03fbd4714484bd6ef94051131df6bca Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 7 Dec 2020 08:54:50 +0100 Subject: [PATCH] adding gold medal durations --- rowers/dataprep.py | 26 +++++++++++++++++--------- rowers/forms.py | 2 +- rowers/interactiveplots.py | 23 +++++++++++++---------- rowers/models.py | 1 + rowers/utils.py | 31 ++++++++++++++++++++++++------- rowers/views/analysisviews.py | 8 ++++---- rowers/views/workoutviews.py | 12 ++++++++++-- 7 files changed, 70 insertions(+), 33 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index d916934b..12a7acea 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1028,13 +1028,17 @@ from scipy import optimize def workout_goldmedalstandard(workout): if workout.goldmedalstandard > 0: - return workout.goldmedalstandard - goldmedalstandard,goldmedalduration = fitscore(workout.user,workout) - workout.goldmedalstandard = goldmedalstandard - workout.save() - return goldmedalstandard + return workout.goldmedalstandard,workout.goldmedalseconds + if workout.workouttype in rowtypes: + goldmedalstandard,goldmedalseconds = calculate_goldmedalstandard(workout.user,workout) + workout.goldmedalstandard = goldmedalstandard + workout.goldmedalseconds = goldmedalseconds + workout.save() + return goldmedalstandard, goldmedalseconds + else: + return 0,0 -def fitscore(rower,workout): +def calculate_goldmedalstandard(rower,workout): cpfile = 'media/cpdata_{id}.parquet.gz'.format(id=workout.id) try: df = pd.read_parquet(cpfile) @@ -1100,7 +1104,7 @@ def fitscore(rower,workout): try: indexmax = scores.idxmax() - delta = df.loc[indexmax,'delta'] + delta = int(df.loc[indexmax,'delta']) maxvalue = scores.max() except (ValueError,TypeError): indexmax = 0 @@ -1168,8 +1172,9 @@ def setcp(workout,background=False): 'id':workout.id, }) df.to_parquet(filename,engine='fastparquet',compression='GZIP') - goldmedalstandard, goldmedalduration = fitscore(workout.user,workout) + goldmedalstandard, goldmedalduration = calculate_goldmedalstandard(workout.user,workout) workout.goldmedalstandard = goldmedalstandard + workout.goldmedalduration = goldmedalduration workout.save() return df,delta,cpvalues @@ -2601,7 +2606,10 @@ def read_df_sql(id): rowdata,row = getrowdata(id=id) if rowdata and len(rowdata.df): data = dataprep(rowdata.df,id=id,bands=True,otwpower=True,barchart=True) - df = pd.read_parquet(f) + try: + df = pd.read_parquet(f) + except OSError: + df = data else: df = pd.DataFrame() diff --git a/rowers/forms.py b/rowers/forms.py index 6d074114..5266bdc4 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -768,7 +768,7 @@ class FitnessFitForm(forms.Form): fitnesstest = forms.IntegerField(required=True,initial=20, label='Test Duration (minutes)') - usefitscore = forms.BooleanField(required=False,initial=False, + usegoldmedalstandard = forms.BooleanField(required=False,initial=False, label='Use best performance against world class') kfitness = forms.IntegerField(initial=42,required=True, diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 14711cc9..1ed3e6ad 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -102,27 +102,30 @@ import rowers.datautils as datautils from pandas.core.groupby.groupby import DataError -def get_fitscore(workouts,kfitness): +def build_goldmedalstandards(workouts,kfitness): dates = [] testpower = [] fatigues = [] fitnesses = [] + data = [] - fitscores = [] + goldmedalstandards = [] + goldmedaldurations = [] ids = [] for w in workouts: - fitscore,fitnesstestsecs = dataprep.fitscore(w.user,w) + goldmedalstandard,goldmedalseconds = dataprep.workout_goldmedalstandard(w) ids.append(w.id) - fitscores.append(fitscore) + goldmedalstandards.append(goldmedalstandard) + goldmedaldurations.append(goldmedalseconds) - df = pd.DataFrame({'workout':ids,'fitscore':fitscores}) + df = pd.DataFrame({'workout':ids,'goldmedalstandard':goldmedalstandards}) for w in workouts: ids = [w.id for w in workouts.filter(date__gte=w.date-datetime.timedelta(days=kfitness), date__lte=w.date)] powerdf = df[df['workout'].isin(ids)] - powertest = powerdf['fitscore'].max() + powertest = powerdf['goldmedalstandard'].max() dates.append(datetime.datetime.combine(w.date,datetime.datetime.min.time())) testpower.append(powertest) @@ -1918,7 +1921,7 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None, metricchoice='rscore', k1=1,k2=1,p0=100, modelchoice='tsb', - usefitscore=False): + usegoldmedalstandard=False): TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' @@ -1929,12 +1932,12 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None, fitnesstestsecs = fitnesstest*60 df = pd.DataFrame() - if not usefitscore: + if not usegoldmedalstandard: dates,testpower,fatigues,fitnesses = get_testpower( workouts,fitnesstestsecs,kfitness ) else: - dates,testpower,fatigues,fitnesses = get_fitscore( + dates,testpower,fatigues,fitnesses = build_goldmedalstandards( workouts,kfitness ) # create CP data @@ -2051,7 +2054,7 @@ def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None, formlabel = 'TSB' rightaxlabel = 'Coggan CTL/ATL/TSB' - if usefitscore: + if usegoldmedalstandard: legend_label = 'Test Score' yaxlabel = 'Test Score' else: diff --git a/rowers/models.py b/rowers/models.py index 8a6663a3..aa31934e 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2953,6 +2953,7 @@ class Workout(models.Model): normv = models.FloatField(default=-1,blank=True) normw = models.FloatField(default=-1,blank=True) goldmedalstandard = models.FloatField(default=-1,blank=True,verbose_name='Gold Medal Standard') + goldmedalseconds = models.IntegerField(default=0,blank=True,verbose_name='Gold Medal Seconds') rpe = models.IntegerField(default=0,blank=True,choices=rpechoices, verbose_name='Rate of Perceived Exertion') diff --git a/rowers/utils.py b/rowers/utils.py index 6e7b45a2..954a611a 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -376,7 +376,7 @@ def wavg(group, avg_name, weight_name): except ZeroDivisionError: return d.mean() -def totaltime_sec_to_string(totaltime): +def totaltime_sec_to_string(totaltime,shorten=False): hours = int(totaltime / 3600.) if hours > 23: message = 'Warning: The workout duration was longer than 23 hours. ' @@ -400,12 +400,29 @@ def totaltime_sec_to_string(totaltime): if not message: message = 'Warning: there is something wrong with the workout duration' - duration = "{hours:02d}:{minutes:02d}:{seconds:02d}.{tenths}".format( - hours=hours, - minutes=minutes, - seconds=seconds, - tenths=tenths - ) + duration = "" + if not shorten: + duration = "{hours:02d}:{minutes:02d}:{seconds:02d}.{tenths}".format( + hours=hours, + minutes=minutes, + seconds=seconds, + tenths=tenths + ) + else: + if hours != 0: + duration = "{hours}:{minutes:02d}:{seconds:02d}".format( + hours=hours, + minutes=minutes, + seconds=seconds, + tenths=tenths + ) + else: + duration = "{minutes}:{seconds:02d}".format( + hours=hours, + minutes=minutes, + seconds=seconds, + tenths=tenths + ) return duration diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 5ccc4562..477d7147 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -1561,7 +1561,7 @@ def performancemanager_view(request,userid=0,mode='rower', fitnesstest = 20 metricchoice = 'trimp' modelchoice = 'tsb' - usefitscore = False + usegoldmedalstandard = False doform = therower.showfresh dofatigue = therower.showfit @@ -1647,7 +1647,7 @@ def fitness_from_cp_view(request,userid=0,mode='rower', fitnesstest = 20 metricchoice = 'trimp' modelchoice = 'tsb' - usefitscore = False + usegoldmedalstandard = False # temp fit parameters k1 = 1 @@ -1669,7 +1669,7 @@ def fitness_from_cp_view(request,userid=0,mode='rower', k2 = form.cleaned_data['k2'] p0 = form.cleaned_data['p0'] modelchoice = form.cleaned_data['modelchoice'] - usefitscore = form.cleaned_data['usefitscore'] + usegoldmedalstandard = form.cleaned_data['usegoldmedalstandard'] else: form = FitnessFitForm() @@ -1694,7 +1694,7 @@ def fitness_from_cp_view(request,userid=0,mode='rower', metricchoice=metricchoice, k1=k1,k2=k2,p0=p0, modelchoice=modelchoice, - usefitscore=usefitscore, + usegoldmedalstandard=usegoldmedalstandard, ) breadcrumbs = [ diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index ac877885..0b004435 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -12,6 +12,7 @@ import rowers.mytypes as mytypes import numpy from rowers.mailprocessing import send_confirm import rowers.uploads as uploads +import rowers.utils as utils from urllib.parse import urlparse, parse_qs from json.decoder import JSONDecodeError @@ -3497,8 +3498,8 @@ def workout_stats_view(request,id=0,message="",successmessage=""): # Normalized power & TSS tss,normp = dataprep.workout_rscore(w) - goldmedalstandard = dataprep.workout_goldmedalstandard(w) - + goldmedalstandard,goldmedalseconds = dataprep.workout_goldmedalstandard(w) + if not np.isnan(goldmedalstandard) and goldmedalstandard > 0: otherstats['goldmedalstandard'] = { @@ -3507,6 +3508,13 @@ def workout_stats_view(request,id=0,message="",successmessage=""): 'unit': '%', } + if not np.isnan(goldmedalseconds) and goldmedalseconds > 0: + otherstats['goldmedalseconds'] = { + 'verbose_name': 'Gold Medal Standard Duration', + 'value': utils.totaltime_sec_to_string(goldmedalseconds,shorten=True), + 'unit': '', + } + if not np.isnan(tss) and tss != 0: otherstats['tss'] = {