diff --git a/rowers/forms.py b/rowers/forms.py index 27ecdd65..8985cf2b 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -74,27 +74,6 @@ class ResampleForm(forms.Form): class TrainingZonesForm(forms.Form): - zoneschoices = ( - ('power', 'Power Zones'), - ('hr', 'Heart Rate Zones') - ) - - datechoices = ( - ('month', 'By Month'), - ('week', 'By Week'), - ) - - yaxischoices = ( - ('time', 'Time'), - ('percentage', 'Percentage of Time') - ) - - zones = forms.ChoiceField( - initial='hr', label='Training Zones', choices=zoneschoices) - dates = forms.ChoiceField( - initial='week', label='Date Aggregation', choices=datechoices) - yaxis = forms.ChoiceField(initial='percentage', - label='Y axis', choices=yaxischoices) startdate = forms.DateField( initial=timezone.now()-datetime.timedelta(days=42), widget=AdminDateWidget(), # format='%Y-%m-%d'), diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index d5a2842a..50b3f2bf 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -2185,6 +2185,194 @@ def interactive_multiple_compare_chart(ids, xparam, yparam, plottype='line', script, div = get_chart("/compare", chart_data) return script, div, message, errormessage +def get_zones_report_pl(rower, startdate, enddate, trainingzones='hr', date_agg='week', + yaxis='time'): + + data = [] + + enddate = enddate + datetime.timedelta(days=1) + + workouts = Workout.objects.filter( + user=rower, + startdatetime__gte=startdate, + startdatetime__lte=enddate, + duplicate=False, + ).order_by("-startdatetime") + + ids = [w.id for w in workouts] + + columns = ['workoutid', 'hr', 'power', 'time'] + + df = dataprep.getsmallrowdata_pl(columns, ids=ids) + + df = df.with_columns((pl.col("time").diff().clip(0, 20*1.e3)).alias("deltat")).lazy() + hrzones = rower.hrzones + powerzones = rower.powerzones + + for w in workouts: + iswater = w.workouttype in mytypes.otwtypes + + pw_ut2 = rower.pw_ut2 + pw_ut1 = rower.pw_ut1 + pw_at = rower.pw_at + pw_tr = rower.pw_tr + pw_an = rower.pw_an + if iswater: + pw_ut2 = pw_ut2*rower.otwslack/100. + pw_ut1 = pw_ut1*rower.otwslack/100. + pw_at = pw_at*rower.otwslack/100. + pw_tr = pw_tr*rower.otwslack/100. + pw_an = pw_an*rower.otwslack/100. + + # 1 + time_ut2 = df.filter( + pl.col("workoutid") == w.id, + pl.col("hr") < rower.ut2, + ) + time_pw_ut2 = df.filter( + pl.col("workoutid") == w.id, + pl.col("power") < pw_ut2, + ) + + # 2 + time_ut1 = df.filter( + pl.col("workoutid") == w.id, + pl.col("hr") >= rower.ut2, + pl.col("hr") < rower.ut1, + ) + time_pw_ut1 = df.filter( + pl.col("workoutid") == w.id, + pl.col("power") >= pw_ut2, + pl.col("power") < pw_ut1, + ) + + #3 + time_at = df.filter( + pl.col("workoutid") == w.id, + pl.col("hr") >= rower.ut1, + pl.col("hr") < rower.at, + ) + time_pw_at = df.filter( + pl.col("workoutid") == w.id, + pl.col("power") >= pw_ut1, + pl.col("power") < pw_at, + ) + + #4 + time_tr = df.filter( + pl.col("workoutid") == w.id, + pl.col("hr") >= rower.at, + pl.col("hr") < rower.tr, + ) + time_pw_tr = df.filter( + pl.col("workoutid") == w.id, + pl.col("power") >= pw_at, + pl.col("power") < pw_tr, + ) + + #5 + time_an = df.filter( + pl.col("workoutid") == w.id, + pl.col("hr") >= rower.tr, + pl.col("hr") < rower.an, + ) + time_pw_an = df.filter( + pl.col("workoutid") == w.id, + pl.col("power") >= pw_tr, + pl.col("power") < pw_an, + ) + + time_max = df.filter( + pl.col("workoutid") == w.id, + pl.col("hr") >= rower.an, + ) + time_pw_max = df.filter( + pl.col("workoutid") == w.id, + pl.col("power") >= pw_an, + ) + + time_in_ut2 = time_ut2.collect()['deltat'].sum()/(60*1.e3) + time_in_ut2_pw = time_pw_ut2.collect()['deltat'].sum()/(60*1.e3) + + time_in_ut1 = time_ut1.collect()['deltat'].sum()/(60*1.e3) + time_in_ut1_pw = time_pw_ut1.collect()['deltat'].sum()/(60*1.e3) + + time_in_at = time_at.collect()['deltat'].sum()/(60*1.e3) + time_in_at_pw = time_pw_at.collect()['deltat'].sum()/(60*1.e3) + + time_in_tr = time_tr.collect()['deltat'].sum()/(60*1.e3) + time_in_tr_pw = time_pw_tr.collect()['deltat'].sum()/(60*1.e3) + + time_in_an = time_an.collect()['deltat'].sum()/(60*1.e3) + time_in_an_pw = time_pw_an.collect()['deltat'].sum()/(60*1.e3) + + time_in_max = time_max.collect()['deltat'].sum()/(60*1.e3) + time_in_max_pw = time_pw_max.collect()['deltat'].sum()/(60*1.e3) + + data.append({ + 'date': w.date.strftime("%Y-%m-%d"), + 'id': w.id, + 'zonename': '<{ut2}'.format(ut2=hrzones[1]), + 'time_in_zone': time_in_ut2, + 'pw_zonename': '<{ut2}'.format(ut2=powerzones[1]), + 'pw_time_in_zone': time_in_ut2_pw, + }) + + data.append({ + 'date': w.date.strftime("%Y-%m-%d"), + 'id': w.id, + 'zonename': hrzones[1], + 'time_in_zone': time_in_ut1, + 'pw_zonename': powerzones[1], + 'pw_time_in_zone': time_in_ut1_pw, + }) + + data.append({ + 'date': w.date.strftime("%Y-%m-%d"), + 'id': w.id, + 'zonename': hrzones[2], + 'time_in_zone': time_in_at, + 'pw_zonename': powerzones[2], + 'pw_time_in_zone': time_in_at_pw, + }) + + data.append({ + 'date': w.date.strftime("%Y-%m-%d"), + 'id': w.id, + 'zonename': hrzones[3], + 'time_in_zone': time_in_tr, + 'pw_zonename': powerzones[3], + 'pw_time_in_zone': time_in_tr_pw, + }) + + data.append({ + 'date': w.date.strftime("%Y-%m-%d"), + 'id': w.id, + 'zonename': hrzones[4], + 'time_in_zone': time_in_an, + 'pw_zonename': powerzones[4], + 'pw_time_in_zone': time_in_an_pw, + }) + + data.append({ + 'date': w.date.strftime("%Y-%m-%d"), + 'id': w.id, + 'zonename': hrzones[5], + 'time_in_zone': time_in_max, + 'pw_zonename': powerzones[5], + 'pw_time_in_zone': time_in_max_pw, + }) + + + chart_data = { + 'data': data, + 'hrzones': hrzones, + 'powerzones': powerzones, + } + + return chart_data + + def get_zones_report(rower, startdate, enddate, trainingzones='hr', date_agg='week', yaxis='time'): @@ -2402,6 +2590,36 @@ def get_zones_report(rower, startdate, enddate, trainingzones='hr', date_agg='we return data +def interactive_zoneschart2(rower, data, startdate, enddate, trainingzones='hr', date_agg='week', + yaxis='time'): + if startdate >= enddate: # pragma: no cover + st = startdate + startdate = enddate + enddate = st + + hrzones = data['hrzones'] + powerzones = data['powerzones'] + + data['yaxis'] = yaxis + data['title'] = 'Activity {d1} to {d2} for {r}'.format( + d1=startdate.strftime("%Y-%m-%d"), + d2=enddate.strftime("%Y-%m-%d"), + r=str(rower), + ) + + data['stackBy'] = 'time_in_zone' + data['colorBy'] = 'zonename' + if trainingzones == 'power': + data['stackBy'] = 'pw_time_in_zone' + data['colorBy'] = 'pw_zonename' + data['doReduce'] = True + data['datebin'] = date_agg + data['colors'] = ['green', 'lime', 'yellow', 'blue', 'purple', 'red'] + + script, div = get_chart("/zones", data, debug=False) + + return script, div + def interactive_zoneschart(rower, data, startdate, enddate, trainingzones='hr', date_agg='week', yaxis='time'): diff --git a/rowers/templates/trainingzones.html b/rowers/templates/trainingzones.html index 19502c31..5ff42eb8 100644 --- a/rowers/templates/trainingzones.html +++ b/rowers/templates/trainingzones.html @@ -11,17 +11,15 @@ - +