From 9f0d4121e378c2e35a63f2dd32945eeb7ab7f055 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 30 May 2021 17:20:27 +0200 Subject: [PATCH] option to use power zones --- rowers/forms.py | 18 ++++ rowers/interactiveplots.py | 131 +++++++++++++++++++++++----- rowers/templates/trainingzones.html | 2 +- rowers/views/analysisviews.py | 13 +-- rowers/views/statements.py | 3 +- 5 files changed, 138 insertions(+), 29 deletions(-) diff --git a/rowers/forms.py b/rowers/forms.py index 76d00219..2661e1a3 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -58,6 +58,24 @@ class FlexibleDecimalField(forms.DecimalField): value = value.replace('.', '').replace(',', '.') return super(FlexibleDecimalField, self).to_python(value) +class TrainingZonesForm(forms.Form): + zoneschoices = ( + ('power','Power Zones'), + ('hr','Heart Rate Zones') + ) + + zones = forms.ChoiceField(initial='hr',label='Training Zones',choices=zoneschoices) + startdate = forms.DateField( + initial=timezone.now()-datetime.timedelta(days=365), + widget=AdminDateWidget(), #format='%Y-%m-%d'), + label='Start Date') + enddate = forms.DateField( + initial=timezone.now(), + # widget=SelectDateWidget(years=range(1990,2050)), + widget=AdminDateWidget(), #format='%Y-%m-%d'), + label='End Date') + + class InstantPlanSelectForm(forms.Form): datechoices = ( ('startdate','start date'), diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 5ef7b657..28fac76e 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -715,13 +715,14 @@ def interactive_activitychart2(workouts,startdate,enddate,stack='type',toolbar_l dd = w.date.strftime('%m/%d') dd2 = w.date.strftime('%Y/%m/%d') dd3 = w.date.strftime('%Y/%m') + du = w.duration.hour*60+w.duration.minute trimp = w.trimp rscore = w.rscore if rscore == 0: # pragma: no cover rscore = w.hrtss - if totaldays<30: # pragma: no cover + if totaldays<=30: # pragma: no cover dates.append(dd) dates_sorting.append(dd2) else: @@ -759,7 +760,7 @@ def interactive_activitychart2(workouts,startdate,enddate,stack='type',toolbar_l dd = d.strftime('%d') - if totaldays<30: + if totaldays<=30: dates.append(d.strftime('%m/%d')) dates_sorting.append(d.strftime('%Y/%m/%d')) else: @@ -6558,7 +6559,7 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0): return [script,div] -def get_zones_report(rower,startdate,enddate): +def get_zones_report(rower,startdate,enddate,trainingzones='hr'): duration = enddate-startdate totaldays = duration.total_seconds()/(24*3600) @@ -6592,90 +6593,141 @@ def get_zones_report(rower,startdate,enddate): #totalmeters,totalhours, totalminutes, totalseconds = get_totals(workouts) hrzones = rower.hrzones + powerzones = rower.powerzones for w in workouts: dd = w.date.strftime('%m/%d') dd2 = w.date.strftime('%Y/%m/%d') dd3 = w.date.strftime('%Y/%m') + dd4 = arrow.get(w.date).isocalendar()[1] + #print(w.date,arrow.get(w.date),arrow.get(w.date).isocalendar()) qryw = 'workoutid == {workoutid}'.format(workoutid=w.id) qry = 'hr < {ut2}'.format(ut2=rower.ut2) + if trainingzones == 'power': + qry = 'power < {ut2}'.format(ut2=rower.pw_ut2) timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3) - if totaldays<30: + if totaldays<=30: dates.append(dd) dates_sorting.append(dd2) + elif totaldays<=121: + dates.append(dd4) + dates_sorting.append(dd4) else: # pragma: no cover dates.append(dd3) dates_sorting.append(dd3) minutes.append(timeinzone) hours.append(timeinzone/60.) - zones.append('<{ut2}'.format(ut2=hrzones[1])) + if trainingzones == 'hr': + zones.append('<{ut2}'.format(ut2=hrzones[1])) + else: + zones.append('<{ut2}'.format(ut2=powerzones[1])) #print(w,dd,timeinzone,'= 30: + if totaldays > 30: df.drop('minutes',inplace=True,axis='columns') else: df.drop('hours',inplace=True,axis='columns') @@ -6754,6 +6836,7 @@ def interactive_zoneschart(rower,data,startdate,enddate): source = ColumnDataSource(df) df.sort_values('date_sorting',inplace=True) + df.drop('date_sorting',inplace=True,axis='columns') hv.extension('bokeh') @@ -6763,18 +6846,24 @@ def interactive_zoneschart(rower,data,startdate,enddate): #bars = table.to.bars(['date','zones'],['minutes']) bars.opts( opts.Bars(cmap=color_map,show_legend=True,stacked=True, - tools=['tap','hover'],width=550,xrotation=45,padding=(0,(0,.1)), + tools=['tap','hover'],width=550,padding=(0,(0,.1)), legend_position='bottom', show_frame=False) ) p = hv.render(bars) - p.title.text = 'Activity {d1} to {d2}'.format( + p.title.text = 'Activity {d1} to {d2} for {r}'.format( d1 = startdate.strftime("%Y-%m-%d"), d2 = enddate.strftime("%Y-%m-%d"), + r = str(rower), ) + if totaldays >= 30: + p.xaxis.axis_label = 'Week' + if totaldays >= 121: + p.xaxis.axis_label = 'Month' + p.plot_width=550 p.plot_height=350 p.toolbar_location = 'above' diff --git a/rowers/templates/trainingzones.html b/rowers/templates/trainingzones.html index 35265ff9..9c0075d5 100644 --- a/rowers/templates/trainingzones.html +++ b/rowers/templates/trainingzones.html @@ -33,7 +33,7 @@ {{ form.as_table }}
- +

diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 356950a9..9a90f306 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -1065,18 +1065,19 @@ def trainingzones_view(request,userid=0,mode='rower', enddate = timezone.now() startdate = enddate-datetime.timedelta(days=365) - form = DateRangeForm() + form = TrainingZonesForm() + zones = 'hr' if request.method == 'POST': - form = DateRangeForm(request.POST) + form = TrainingZonesForm(request.POST) if form.is_valid(): startdate = form.cleaned_data['startdate'] enddate = form.cleaned_data['enddate'] + zones = form.cleaned_data['zones'] + + data = get_zones_report(r,startdate,enddate,trainingzones=zones) - data = get_zones_report(r,startdate,enddate) - - - script, div = interactive_zoneschart(r,data,startdate,enddate) + script, div = interactive_zoneschart(r,data,startdate,enddate,trainingzones=zones) breadcrumbs = [ { diff --git a/rowers/views/statements.py b/rowers/views/statements.py index 5d9daa8d..b3d39580 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -77,7 +77,8 @@ from rowers.forms import ( VideoAnalysisCreateForm,WorkoutSingleSelectForm, VideoAnalysisMetricsForm,SurveyForm,HistorySelectForm, StravaChartForm,FitnessFitForm,PerformanceManagerForm, - TrainingPlanBillingForm,InstantPlanSelectForm + TrainingPlanBillingForm,InstantPlanSelectForm, + TrainingZonesForm, ) from django.urls import reverse, reverse_lazy