Private
Public Access
1
0

option to use power zones

This commit is contained in:
Sander Roosendaal
2021-05-30 17:20:27 +02:00
parent 8966dfec92
commit 9f0d4121e3
5 changed files with 138 additions and 29 deletions

View File

@@ -58,6 +58,24 @@ class FlexibleDecimalField(forms.DecimalField):
value = value.replace('.', '').replace(',', '.') value = value.replace('.', '').replace(',', '.')
return super(FlexibleDecimalField, self).to_python(value) 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): class InstantPlanSelectForm(forms.Form):
datechoices = ( datechoices = (
('startdate','start date'), ('startdate','start date'),

View File

@@ -715,13 +715,14 @@ def interactive_activitychart2(workouts,startdate,enddate,stack='type',toolbar_l
dd = w.date.strftime('%m/%d') dd = w.date.strftime('%m/%d')
dd2 = w.date.strftime('%Y/%m/%d') dd2 = w.date.strftime('%Y/%m/%d')
dd3 = w.date.strftime('%Y/%m') dd3 = w.date.strftime('%Y/%m')
du = w.duration.hour*60+w.duration.minute du = w.duration.hour*60+w.duration.minute
trimp = w.trimp trimp = w.trimp
rscore = w.rscore rscore = w.rscore
if rscore == 0: # pragma: no cover if rscore == 0: # pragma: no cover
rscore = w.hrtss rscore = w.hrtss
if totaldays<30: # pragma: no cover if totaldays<=30: # pragma: no cover
dates.append(dd) dates.append(dd)
dates_sorting.append(dd2) dates_sorting.append(dd2)
else: else:
@@ -759,7 +760,7 @@ def interactive_activitychart2(workouts,startdate,enddate,stack='type',toolbar_l
dd = d.strftime('%d') dd = d.strftime('%d')
if totaldays<30: if totaldays<=30:
dates.append(d.strftime('%m/%d')) dates.append(d.strftime('%m/%d'))
dates_sorting.append(d.strftime('%Y/%m/%d')) dates_sorting.append(d.strftime('%Y/%m/%d'))
else: else:
@@ -6558,7 +6559,7 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0):
return [script,div] return [script,div]
def get_zones_report(rower,startdate,enddate): def get_zones_report(rower,startdate,enddate,trainingzones='hr'):
duration = enddate-startdate duration = enddate-startdate
totaldays = duration.total_seconds()/(24*3600) totaldays = duration.total_seconds()/(24*3600)
@@ -6592,90 +6593,141 @@ def get_zones_report(rower,startdate,enddate):
#totalmeters,totalhours, totalminutes, totalseconds = get_totals(workouts) #totalmeters,totalhours, totalminutes, totalseconds = get_totals(workouts)
hrzones = rower.hrzones hrzones = rower.hrzones
powerzones = rower.powerzones
for w in workouts: for w in workouts:
dd = w.date.strftime('%m/%d') dd = w.date.strftime('%m/%d')
dd2 = w.date.strftime('%Y/%m/%d') dd2 = w.date.strftime('%Y/%m/%d')
dd3 = w.date.strftime('%Y/%m') 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) qryw = 'workoutid == {workoutid}'.format(workoutid=w.id)
qry = 'hr < {ut2}'.format(ut2=rower.ut2) 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) timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if totaldays<30: if totaldays<=30:
dates.append(dd) dates.append(dd)
dates_sorting.append(dd2) dates_sorting.append(dd2)
elif totaldays<=121:
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover else: # pragma: no cover
dates.append(dd3) dates.append(dd3)
dates_sorting.append(dd3) dates_sorting.append(dd3)
minutes.append(timeinzone) minutes.append(timeinzone)
hours.append(timeinzone/60.) hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append('<{ut2}'.format(ut2=hrzones[1])) zones.append('<{ut2}'.format(ut2=hrzones[1]))
else:
zones.append('<{ut2}'.format(ut2=powerzones[1]))
#print(w,dd,timeinzone,'<UT2') #print(w,dd,timeinzone,'<UT2')
qry = '{ut2} <= hr < {ut1}'.format(ut1=rower.ut1,ut2=rower.ut2) qry = '{ut2} <= hr < {ut1}'.format(ut1=rower.ut1,ut2=rower.ut2)
if trainingzones == 'power':
qry = '{ut2} <= power < {ut2}'.format(ut1=rower.pw_ut1,ut2=rower.pw_ut2)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3) timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if totaldays<30: if totaldays<=30:
dates.append(dd) dates.append(dd)
dates_sorting.append(dd2) dates_sorting.append(dd2)
elif totaldays<=121:
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover else: # pragma: no cover
dates.append(dd3) dates.append(dd3)
dates_sorting.append(dd3) dates_sorting.append(dd3)
minutes.append(timeinzone) minutes.append(timeinzone)
hours.append(timeinzone/60.) hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append(hrzones[1]) zones.append(hrzones[1])
else:
zones.append(powerzones[1])
#print(w,dd,timeinzone,'UT2') #print(w,dd,timeinzone,'UT2')
qry = '{ut1} <= hr < {at}'.format(ut1=rower.ut1,at=rower.at) qry = '{ut1} <= hr < {at}'.format(ut1=rower.ut1,at=rower.at)
if trainingzones == 'power':
qry = '{ut1} <= power < {at}'.format(ut1=rower.pw_ut1,at=rower.pw_at)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3) timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if totaldays<30: if totaldays<=30:
dates.append(dd) dates.append(dd)
dates_sorting.append(dd2) dates_sorting.append(dd2)
elif totaldays<=121:
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover else: # pragma: no cover
dates.append(dd3) dates.append(dd3)
dates_sorting.append(dd3) dates_sorting.append(dd3)
minutes.append(timeinzone) minutes.append(timeinzone)
hours.append(timeinzone/60.) hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append(hrzones[2]) zones.append(hrzones[2])
else:
zones.append(powerzones[2])
#print(w,dd,timeinzone,'UT1') #print(w,dd,timeinzone,'UT1')
qry = '{at} <= hr < {tr}'.format(at=rower.at,tr=rower.tr) qry = '{at} <= hr < {tr}'.format(at=rower.at,tr=rower.tr)
if trainingzones == 'power':
qry = '{at} <= power < {tr}'.format(at=rower.pw_at,tr=rower.pw_tr)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3) timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if totaldays<30: if totaldays<=30:
dates.append(dd) dates.append(dd)
dates_sorting.append(dd2) dates_sorting.append(dd2)
elif totaldays<=121:
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover else: # pragma: no cover
dates.append(dd3) dates.append(dd3)
dates_sorting.append(dd3) dates_sorting.append(dd3)
minutes.append(timeinzone) minutes.append(timeinzone)
hours.append(timeinzone/60.) hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append(hrzones[3]) zones.append(hrzones[3])
else:
zones.append(powerzones[3])
#print(w,dd,timeinzone,'AT') #print(w,dd,timeinzone,'AT')
qry = '{tr} <= hr < {an}'.format(tr=rower.tr,an=rower.an) qry = '{tr} <= hr < {an}'.format(tr=rower.tr,an=rower.an)
if trainingzones == 'power':
qry = '{tr} <= power < {an}'.format(tr=rower.pw_tr,an=rower.pw_an)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3) timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if totaldays<30: if totaldays<=30:
dates.append(dd) dates.append(dd)
dates_sorting.append(dd2) dates_sorting.append(dd2)
elif totaldays<=121:
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover else: # pragma: no cover
dates.append(dd3) dates.append(dd3)
dates_sorting.append(dd3) dates_sorting.append(dd3)
minutes.append(timeinzone) minutes.append(timeinzone)
hours.append(timeinzone/60.) hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append(hrzones[4]) zones.append(hrzones[4])
else:
zones.append(powerzones[4])
#print(w,dd,timeinzone,'TR') #print(w,dd,timeinzone,'TR')
qry = 'hr >= {an}'.format(an=rower.an) qry = 'hr >= {an}'.format(an=rower.an)
if trainingzones == 'power':
qry = 'power >= {an}'.format(an=rower.pw_an)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3) timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if totaldays<30: if totaldays<=30:
dates.append(dd) dates.append(dd)
dates_sorting.append(dd2) dates_sorting.append(dd2)
elif totaldays<=121:
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover else: # pragma: no cover
dates.append(dd3) dates.append(dd3)
dates_sorting.append(dd3) dates_sorting.append(dd3)
minutes.append(timeinzone) minutes.append(timeinzone)
hours.append(timeinzone/60.) hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append(hrzones[5]) zones.append(hrzones[5])
else:
zones.append(powerzones[5])
#print(w,dd,timeinzone,'AN') #print(w,dd,timeinzone,'AN')
try: try:
@@ -6690,19 +6742,28 @@ def get_zones_report(rower,startdate,enddate):
while d<=enddate: while d<=enddate:
dd = d.strftime('%d') dd = d.strftime('%d')
if totaldays < 30: if totaldays <= 30:
dates.append(d.strftime('%m/%d')) dates.append(d.strftime('%m/%d'))
dates_sorting.append(d.strftime('%Y/%m/%d')) dates_sorting.append(d.strftime('%Y/%m/%d'))
elif totaldays<=121:
dd4 = arrow.get(d).isocalendar()[1]
dates.append(dd4)
dates_sorting.append(dd4)
else: else:
dates.append(d.strftime('%Y/%m')) dates.append(d.strftime('%Y/%m'))
dates_sorting.append(d.strftime('%Y/%m')) dates_sorting.append(d.strftime('%Y/%m'))
minutes.append(0) minutes.append(0)
hours.append(0) hours.append(0)
if trainingzones == 'hr':
zones.append(hrzones[1]) zones.append(hrzones[1])
else:
zones.append(powerzones[1])
d += datetime.timedelta(days=1) d += datetime.timedelta(days=1)
# this should be renamed with rower zones # this should be renamed with rower zones
data = { data = {
'date':dates, 'date':dates,
@@ -6716,7 +6777,7 @@ def get_zones_report(rower,startdate,enddate):
return data return data
def interactive_zoneschart(rower,data,startdate,enddate): def interactive_zoneschart(rower,data,startdate,enddate,trainingzones='hr'):
duration = enddate-startdate duration = enddate-startdate
totaldays = duration.total_seconds()/(24*3600) totaldays = duration.total_seconds()/(24*3600)
@@ -6724,6 +6785,7 @@ def interactive_zoneschart(rower,data,startdate,enddate):
colors = ['gray','yellow','lime','blue','purple','red'] colors = ['gray','yellow','lime','blue','purple','red']
hrzones = rower.hrzones hrzones = rower.hrzones
powerzones = rower.powerzones
color_map = { color_map = {
@@ -6734,6 +6796,15 @@ def interactive_zoneschart(rower,data,startdate,enddate):
hrzones[4]:'purple', hrzones[4]:'purple',
hrzones[5]:'red', hrzones[5]:'red',
} }
if trainingzones == 'power':
color_map = {
'<{ut2}'.format(ut2=powerzones[1]):'gray',
powerzones[1]:'lime',
powerzones[2]:'yellow',
powerzones[3]:'blue',
powerzones[4]:'purple',
powerzones[5]:'red',
}
zones_order = [ zones_order = [
'<{ut2}'.format(ut2=hrzones[1]), '<{ut2}'.format(ut2=hrzones[1]),
@@ -6744,8 +6815,19 @@ def interactive_zoneschart(rower,data,startdate,enddate):
hrzones[5] hrzones[5]
] ]
if trainingzones == 'power':
zones_order = [
'<{ut2}'.format(ut2=powerzones[1]),
powerzones[1],
powerzones[2],
powerzones[3],
powerzones[4],
powerzones[5]
]
df = pd.DataFrame(data) df = pd.DataFrame(data)
if totaldays >= 30: if totaldays > 30:
df.drop('minutes',inplace=True,axis='columns') df.drop('minutes',inplace=True,axis='columns')
else: else:
df.drop('hours',inplace=True,axis='columns') df.drop('hours',inplace=True,axis='columns')
@@ -6754,6 +6836,7 @@ def interactive_zoneschart(rower,data,startdate,enddate):
source = ColumnDataSource(df) source = ColumnDataSource(df)
df.sort_values('date_sorting',inplace=True) df.sort_values('date_sorting',inplace=True)
df.drop('date_sorting',inplace=True,axis='columns')
hv.extension('bokeh') hv.extension('bokeh')
@@ -6763,18 +6846,24 @@ def interactive_zoneschart(rower,data,startdate,enddate):
#bars = table.to.bars(['date','zones'],['minutes']) #bars = table.to.bars(['date','zones'],['minutes'])
bars.opts( bars.opts(
opts.Bars(cmap=color_map,show_legend=True,stacked=True, 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', legend_position='bottom',
show_frame=False) show_frame=False)
) )
p = hv.render(bars) 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"), d1 = startdate.strftime("%Y-%m-%d"),
d2 = enddate.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_width=550
p.plot_height=350 p.plot_height=350
p.toolbar_location = 'above' p.toolbar_location = 'above'

View File

@@ -33,7 +33,7 @@
<table> <table>
{{ form.as_table }} {{ form.as_table }}
</table> </table>
<input class="button" type="submit" value="Select Dates"> <input class="button" type="submit" value="Submit">
</form> </form>
</p> </p>
</li> </li>

View File

@@ -1065,18 +1065,19 @@ def trainingzones_view(request,userid=0,mode='rower',
enddate = timezone.now() enddate = timezone.now()
startdate = enddate-datetime.timedelta(days=365) startdate = enddate-datetime.timedelta(days=365)
form = DateRangeForm() form = TrainingZonesForm()
zones = 'hr'
if request.method == 'POST': if request.method == 'POST':
form = DateRangeForm(request.POST) form = TrainingZonesForm(request.POST)
if form.is_valid(): if form.is_valid():
startdate = form.cleaned_data['startdate'] startdate = form.cleaned_data['startdate']
enddate = form.cleaned_data['enddate'] 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,trainingzones=zones)
script, div = interactive_zoneschart(r,data,startdate,enddate)
breadcrumbs = [ breadcrumbs = [
{ {

View File

@@ -77,7 +77,8 @@ from rowers.forms import (
VideoAnalysisCreateForm,WorkoutSingleSelectForm, VideoAnalysisCreateForm,WorkoutSingleSelectForm,
VideoAnalysisMetricsForm,SurveyForm,HistorySelectForm, VideoAnalysisMetricsForm,SurveyForm,HistorySelectForm,
StravaChartForm,FitnessFitForm,PerformanceManagerForm, StravaChartForm,FitnessFitForm,PerformanceManagerForm,
TrainingPlanBillingForm,InstantPlanSelectForm TrainingPlanBillingForm,InstantPlanSelectForm,
TrainingZonesForm,
) )
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy