added age records to ote-bests
This commit is contained in:
@@ -1101,7 +1101,8 @@ def interactive_agegroup_plot(df):
|
||||
return script,div
|
||||
|
||||
def interactive_cpchart(rower,thedistances,thesecs,theavpower,
|
||||
theworkouts,promember=0):
|
||||
theworkouts,promember=0,
|
||||
wcpower=[],wcdurations=[]):
|
||||
|
||||
message = 0
|
||||
# plot tools
|
||||
@@ -1167,11 +1168,23 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
|
||||
)
|
||||
|
||||
|
||||
# fitting the data to three parameter CP model
|
||||
fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3]))
|
||||
errfunc = lambda pars,x,y: fitfunc(pars,x)-y
|
||||
|
||||
|
||||
p0 = [500,350,10,8000]
|
||||
wcpower = pd.Series(wcpower)
|
||||
wcdurations = pd.Series(wcdurations)
|
||||
|
||||
# fitting WC data to three parameter CP model
|
||||
if len(wcdurations)>=4:
|
||||
p1wc, success = optimize.leastsq(errfunc, p0[:],
|
||||
args = (wcdurations,wcpower))
|
||||
else:
|
||||
p1wc = None
|
||||
|
||||
# fitting the data to three parameter CP model
|
||||
|
||||
|
||||
|
||||
p1 = p0
|
||||
if len(thesecs)>=4:
|
||||
@@ -1184,6 +1197,21 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
|
||||
fitt = pd.Series(10**(4*np.arange(100)/100.))
|
||||
|
||||
fitpower = fitfunc(p1,fitt)
|
||||
if p1wc is not None:
|
||||
fitpowerwc = 0.95*fitfunc(p1wc,fitt)
|
||||
fitpowerexcellent = 0.7*fitfunc(p1wc,fitt)
|
||||
fitpowergood = 0.6*fitfunc(p1wc,fitt)
|
||||
fitpowerfair = 0.5*fitfunc(p1wc,fitt)
|
||||
fitpoweraverage = 0.4*fitfunc(p1wc,fitt)
|
||||
|
||||
else:
|
||||
fitpowerwc = 0*fitpower
|
||||
fitpowerexcellent = 0*fitpower
|
||||
fitpowergood = 0*fitpower
|
||||
fitpowerfair = 0*fitpower
|
||||
fitpoweraverage = 0*fitpower
|
||||
|
||||
|
||||
|
||||
message = ""
|
||||
if len(fitpower[fitpower<0]) > 0:
|
||||
@@ -1203,6 +1231,11 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
|
||||
),
|
||||
spm = 0*fitpower,
|
||||
power = fitpower,
|
||||
fitpowerwc = fitpowerwc,
|
||||
fitpowerexcellent = fitpowerexcellent,
|
||||
fitpowergood = fitpowergood,
|
||||
fitpowerfair = fitpowerfair,
|
||||
fitpoweraverage = fitpoweraverage,
|
||||
fpace = nicepaceformat(fitp2),
|
||||
)
|
||||
)
|
||||
@@ -1281,6 +1314,25 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
|
||||
plot.line('duration','power',source=sourcepaul,legend="Paul's Law")
|
||||
plot.line('duration','power',source=sourcecomplex,legend="CP Model",
|
||||
color='green')
|
||||
plot.line('duration','fitpowerwc',source=sourcecomplex,
|
||||
legend="World Class",
|
||||
color='Maroon',line_dash='dotted')
|
||||
|
||||
plot.line('duration','fitpowerexcellent',source=sourcecomplex,
|
||||
legend="Excellent",
|
||||
color='Purple',line_dash='dotted')
|
||||
|
||||
plot.line('duration','fitpowergood',source=sourcecomplex,
|
||||
legend="Good",
|
||||
color='Olive',line_dash='dotted')
|
||||
|
||||
plot.line('duration','fitpowerfair',source=sourcecomplex,
|
||||
legend="Fair",
|
||||
color='Gray',line_dash='dotted')
|
||||
|
||||
plot.line('duration','fitpoweraverage',source=sourcecomplex,
|
||||
legend="Average",
|
||||
color='SkyBlue',line_dash='dotted')
|
||||
|
||||
|
||||
script, div = components(plot)
|
||||
|
||||
@@ -319,12 +319,26 @@ def calc_trimp(df,sex,hrmax,hrmin):
|
||||
|
||||
return trimp
|
||||
|
||||
def getagegroup2k(age,sex='male',weightcategory='hwt'):
|
||||
df = pd.DataFrame(
|
||||
list(
|
||||
C2WorldClassAgePerformance.objects.filter(
|
||||
sex=sex,
|
||||
weightcategory=weightcategory
|
||||
def getagegrouprecord(age,sex='male',weightcategory='hwt',
|
||||
distance=2000,duration=None):
|
||||
if not duration:
|
||||
df = pd.DataFrame(
|
||||
list(
|
||||
C2WorldClassAgePerformance.objects.filter(
|
||||
distance=distance,
|
||||
sex=sex,
|
||||
weightcategory=weightcategory
|
||||
).values()
|
||||
)
|
||||
)
|
||||
else:
|
||||
duration=60*int(duration)
|
||||
df = pd.DataFrame(
|
||||
list(
|
||||
C2WorldClassAgePerformance.objects.filter(
|
||||
duration=duration,
|
||||
sex=sex,
|
||||
weightcategory=weightcategory
|
||||
).values()
|
||||
)
|
||||
)
|
||||
|
||||
1
rowers/templates/.#rankings.html
Normal file
1
rowers/templates/.#rankings.html
Normal file
@@ -0,0 +1 @@
|
||||
E408191@CZ27LT9RCGN72.12348:1512983261
|
||||
@@ -160,6 +160,15 @@
|
||||
|
||||
{{ the_div|safe }}
|
||||
|
||||
<p>The dashed lines are based on the Concept2 rankings for your age, gender
|
||||
and weight category. World class means within 5% of World Record in terms
|
||||
of power. Excellent, Good, and Fair indicate the power levels of the top
|
||||
10%, 25% and 50% of the Concept2 rankings. Average is taken
|
||||
as being in the top 75%, given that the Concept2 rankings probably
|
||||
represent the more competitive sub-group of all people who erg.
|
||||
Please note that this is a prediction for people of exactly your age,
|
||||
and your actual place in the Concept2 Ranking may be different.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="predictions" class="grid_12 alpha">
|
||||
@@ -259,9 +268,7 @@
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if worldclasspower %}
|
||||
World class 2k for your age, weight is {{ worldclasspower }} Watt
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -165,6 +165,12 @@ urlpatterns = [
|
||||
url(r'^ote-bests/(?P<deltadays>\d+)$',views.rankings_view),
|
||||
url(r'^ote-bests/$',views.rankings_view),
|
||||
url(r'^(?P<theuser>\d+)/ote-bests/$',views.rankings_view),
|
||||
url(r'^(?P<theuser>\d+)/ote-bests2/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.rankings_view),
|
||||
url(r'^(?P<theuser>\d+)/ote-bests2/(?P<deltadays>\d+)$',views.rankings_view2),
|
||||
url(r'^ote-bests2/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.rankings_view2),
|
||||
url(r'^ote-bests2/(?P<deltadays>\d+)$',views.rankings_view2),
|
||||
url(r'^ote-bests2/$',views.rankings_view2),
|
||||
url(r'^(?P<theuser>\d+)/ote-bests2/$',views.rankings_view2),
|
||||
url(r'^(?P<theuser>\d+)/otw-bests/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.otwrankings_view),
|
||||
url(r'^(?P<theuser>\d+)/otw-bests/(?P<deltadays>\d+)$',views.otwrankings_view),
|
||||
url(r'^otw-bests/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.otwrankings_view),
|
||||
|
||||
340
rowers/views.py
340
rowers/views.py
@@ -3223,7 +3223,7 @@ def rankings_view(request,theuser=0,
|
||||
r = getrower(request.user)
|
||||
if r.birthdate:
|
||||
age = calculate_age(r.birthdate)
|
||||
worldclasspower = int(metrics.getagegroup2k(
|
||||
worldclasspower = int(metrics.getagegrouprecord(
|
||||
age,
|
||||
sex=r.sex,
|
||||
weightcategory=r.weightcategory
|
||||
@@ -3507,6 +3507,344 @@ def rankings_view(request,theuser=0,
|
||||
'teams':get_my_teams(request.user),
|
||||
})
|
||||
|
||||
# Show ranking distances including predicted paces
|
||||
@login_required()
|
||||
def rankings_view2(request,theuser=0,
|
||||
startdate=timezone.now()-datetime.timedelta(days=365),
|
||||
enddate=timezone.now(),
|
||||
deltadays=-1,
|
||||
startdatestring="",
|
||||
enddatestring=""):
|
||||
|
||||
if deltadays>0:
|
||||
startdate = enddate-datetime.timedelta(days=int(deltadays))
|
||||
|
||||
if startdatestring != "":
|
||||
startdate = iso8601.parse_date(startdatestring)
|
||||
|
||||
if enddatestring != "":
|
||||
enddate = iso8601.parse_date(enddatestring)
|
||||
|
||||
if enddate < startdate:
|
||||
s = enddate
|
||||
enddate = startdate
|
||||
startdate = s
|
||||
|
||||
if theuser == 0:
|
||||
theuser = request.user.id
|
||||
|
||||
promember=0
|
||||
if not request.user.is_anonymous():
|
||||
r = getrower(request.user)
|
||||
wcdurations = []
|
||||
wcpower = []
|
||||
|
||||
if r.birthdate:
|
||||
age = calculate_age(r.birthdate)
|
||||
durations = [1,4,30,60]
|
||||
distances = [100,500,1000,2000,5000,6000,10000,21097,42195]
|
||||
print r.weightcategory,r.sex,age,'aap'
|
||||
for distance in distances:
|
||||
worldclasspower = metrics.getagegrouprecord(
|
||||
age,
|
||||
sex=r.sex,
|
||||
distance=distance,
|
||||
weightcategory=r.weightcategory
|
||||
)
|
||||
velo = (worldclasspower/2.8)**(1./3.)
|
||||
duration = distance/velo
|
||||
wcdurations.append(duration)
|
||||
wcpower.append(worldclasspower)
|
||||
for duration in durations:
|
||||
worldclasspower = metrics.getagegrouprecord(
|
||||
age,
|
||||
sex=r.sex,
|
||||
duration=duration,
|
||||
weightcategory=r.weightcategory
|
||||
)
|
||||
wcdurations.append(60.*duration)
|
||||
velo = (worldclasspower/2.8)**(1./3.)
|
||||
distance = int(60*duration*velo)
|
||||
wcpower.append(worldclasspower)
|
||||
else:
|
||||
worldclasspower = None
|
||||
|
||||
result = request.user.is_authenticated() and ispromember(request.user)
|
||||
if result:
|
||||
promember=1
|
||||
|
||||
# get all indoor rows in date range
|
||||
|
||||
# process form
|
||||
if request.method == 'POST' and "daterange" in request.POST:
|
||||
dateform = DateRangeForm(request.POST)
|
||||
deltaform = DeltaDaysForm(request.POST)
|
||||
if dateform.is_valid():
|
||||
startdate = dateform.cleaned_data['startdate']
|
||||
enddate = dateform.cleaned_data['enddate']
|
||||
if startdate > enddate:
|
||||
s = enddate
|
||||
enddate = startdate
|
||||
startdate = s
|
||||
elif request.method == 'POST' and "datedelta" in request.POST:
|
||||
deltaform = DeltaDaysForm(request.POST)
|
||||
if deltaform.is_valid():
|
||||
deltadays = deltaform.cleaned_data['deltadays']
|
||||
if deltadays:
|
||||
enddate = timezone.now()
|
||||
startdate = enddate-datetime.timedelta(days=deltadays)
|
||||
if startdate > enddate:
|
||||
s = enddate
|
||||
enddate = startdate
|
||||
startdate = s
|
||||
dateform = DateRangeForm(initial={
|
||||
'startdate': startdate,
|
||||
'enddate': enddate,
|
||||
})
|
||||
else:
|
||||
dateform = DateRangeForm()
|
||||
deltaform = DeltaDaysForm()
|
||||
|
||||
else:
|
||||
dateform = DateRangeForm(initial={
|
||||
'startdate': startdate,
|
||||
'enddate': enddate,
|
||||
})
|
||||
deltaform = DeltaDaysForm()
|
||||
|
||||
# get all 2k (if any) - this rower, in date range
|
||||
try:
|
||||
r = getrower(theuser)
|
||||
except Rower.DoesNotExist:
|
||||
allergworkouts = []
|
||||
r=0
|
||||
|
||||
|
||||
try:
|
||||
uu = User.objects.get(id=theuser)
|
||||
except User.DoesNotExist:
|
||||
uu = ''
|
||||
|
||||
|
||||
# test to fix bug
|
||||
startdate = datetime.datetime.combine(startdate,datetime.time())
|
||||
enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
|
||||
enddate = enddate+datetime.timedelta(days=1)
|
||||
|
||||
rankingdistances = [100,500,1000,2000,5000,6000,10000,21097,42195,100000]
|
||||
rankingdurations = []
|
||||
rankingdurations.append(datetime.time(minute=1))
|
||||
rankingdurations.append(datetime.time(minute=4))
|
||||
rankingdurations.append(datetime.time(minute=30))
|
||||
rankingdurations.append(datetime.time(hour=1,minute=15))
|
||||
rankingdurations.append(datetime.time(hour=1))
|
||||
|
||||
thedistances = []
|
||||
theworkouts = []
|
||||
thesecs = []
|
||||
|
||||
|
||||
|
||||
rankingdistances.sort()
|
||||
rankingdurations.sort()
|
||||
|
||||
for rankingdistance in rankingdistances:
|
||||
|
||||
workouts = Workout.objects.filter(user=r,distance=rankingdistance,
|
||||
workouttype__in=['rower','dynamic','slides'],
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate).order_by('duration')
|
||||
if workouts:
|
||||
thedistances.append(rankingdistance)
|
||||
theworkouts.append(workouts[0])
|
||||
|
||||
timesecs = 3600*workouts[0].duration.hour
|
||||
timesecs += 60*workouts[0].duration.minute
|
||||
timesecs += workouts[0].duration.second
|
||||
timesecs += 1.e-6*workouts[0].duration.microsecond
|
||||
|
||||
thesecs.append(timesecs)
|
||||
|
||||
for rankingduration in rankingdurations:
|
||||
|
||||
workouts = Workout.objects.filter(user=r,duration=rankingduration,
|
||||
workouttype='rower',
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate).order_by('-distance')
|
||||
if workouts:
|
||||
thedistances.append(workouts[0].distance)
|
||||
theworkouts.append(workouts[0])
|
||||
|
||||
timesecs = 3600*workouts[0].duration.hour
|
||||
timesecs += 60*workouts[0].duration.minute
|
||||
timesecs += workouts[0].duration.second
|
||||
timesecs += 1.e-5*workouts[0].duration.microsecond
|
||||
|
||||
thesecs.append(timesecs)
|
||||
|
||||
thedistances = np.array(thedistances)
|
||||
thesecs = np.array(thesecs)
|
||||
|
||||
thevelos = thedistances/thesecs
|
||||
theavpower = 2.8*(thevelos**3)
|
||||
|
||||
|
||||
# create interactive plot
|
||||
if len(thedistances) !=0 :
|
||||
res = interactive_cpchart(
|
||||
r,thedistances,thesecs,theavpower,
|
||||
theworkouts,promember=promember,
|
||||
wcdurations=wcdurations,wcpower=wcpower
|
||||
)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
paulslope = res[2]
|
||||
paulintercept = res[3]
|
||||
p1 = res[4]
|
||||
message = res[5]
|
||||
else:
|
||||
script = ''
|
||||
div = '<p>No ranking pieces found.</p>'
|
||||
paulslope = 1
|
||||
paulintercept = 1
|
||||
p1 = [1,1,1,1]
|
||||
message = ""
|
||||
|
||||
|
||||
if request.method == 'POST' and "piece" in request.POST:
|
||||
form = PredictedPieceForm(request.POST)
|
||||
if form.is_valid():
|
||||
value = form.cleaned_data['value']
|
||||
hourvalue,value = divmod(value,60)
|
||||
if hourvalue >= 24:
|
||||
hourvalue = 23
|
||||
pieceunit = form.cleaned_data['pieceunit']
|
||||
if pieceunit == 'd':
|
||||
rankingdistances.append(value)
|
||||
else:
|
||||
rankingdurations.append(datetime.time(minute=int(value),hour=int(hourvalue)))
|
||||
else:
|
||||
form = PredictedPieceForm()
|
||||
|
||||
rankingdistances.sort()
|
||||
rankingdurations.sort()
|
||||
|
||||
|
||||
predictions = []
|
||||
cpredictions = []
|
||||
|
||||
|
||||
for rankingdistance in rankingdistances:
|
||||
# Paul's model
|
||||
p = paulslope*np.log10(rankingdistance)+paulintercept
|
||||
velo = 500./p
|
||||
t = rankingdistance/velo
|
||||
pwr = 2.8*(velo**3)
|
||||
a = {'distance':rankingdistance,
|
||||
'duration':timedeltaconv(t),
|
||||
'pace':timedeltaconv(p),
|
||||
'power':int(pwr)}
|
||||
predictions.append(a)
|
||||
|
||||
# CP model -
|
||||
pwr2 = p1[0]/(1+t/p1[2])
|
||||
pwr2 += p1[1]/(1+t/p1[3])
|
||||
|
||||
if pwr2 <= 0:
|
||||
pwr2 = 50.
|
||||
|
||||
velo2 = (pwr2/2.8)**(1./3.)
|
||||
|
||||
if np.isnan(velo2) or velo2 <= 0:
|
||||
velo2 = 1.0
|
||||
|
||||
t2 = rankingdistance/velo2
|
||||
|
||||
pwr3 = p1[0]/(1+t2/p1[2])
|
||||
pwr3 += p1[1]/(1+t2/p1[3])
|
||||
|
||||
if pwr3 <= 0:
|
||||
pwr3 = 50.
|
||||
|
||||
velo3 = (pwr3/2.8)**(1./3.)
|
||||
if np.isnan(velo3) or velo3 <= 0:
|
||||
velo3 = 1.0
|
||||
|
||||
t3 = rankingdistance/velo3
|
||||
p3 = 500./velo3
|
||||
|
||||
a = {'distance':rankingdistance,
|
||||
'duration':timedeltaconv(t3),
|
||||
'pace':timedeltaconv(p3),
|
||||
'power':int(pwr3)}
|
||||
cpredictions.append(a)
|
||||
|
||||
|
||||
|
||||
|
||||
for rankingduration in rankingdurations:
|
||||
t = 3600.*rankingduration.hour
|
||||
t += 60.*rankingduration.minute
|
||||
t += rankingduration.second
|
||||
t += rankingduration.microsecond/1.e6
|
||||
|
||||
# Paul's model
|
||||
ratio = paulintercept/paulslope
|
||||
|
||||
u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/paulslope
|
||||
|
||||
d = 500*t*np.log(10.)
|
||||
d = d/(paulslope*lambertw(u))
|
||||
d = d.real
|
||||
|
||||
velo = d/t
|
||||
p = 500./velo
|
||||
pwr = 2.8*(velo**3)
|
||||
a = {'distance':int(d),
|
||||
'duration':timedeltaconv(t),
|
||||
'pace':timedeltaconv(p),
|
||||
'power':int(pwr)}
|
||||
predictions.append(a)
|
||||
|
||||
# CP model
|
||||
pwr = p1[0]/(1+t/p1[2])
|
||||
pwr += p1[1]/(1+t/p1[3])
|
||||
|
||||
if pwr <= 0:
|
||||
pwr = 50.
|
||||
|
||||
velo = (pwr/2.8)**(1./3.)
|
||||
|
||||
if np.isnan(velo) or velo <=0:
|
||||
velo = 1.0
|
||||
|
||||
d = t*velo
|
||||
p = 500./velo
|
||||
a = {'distance':int(d),
|
||||
'duration':timedeltaconv(t),
|
||||
'pace':timedeltaconv(p),
|
||||
'power':int(pwr)}
|
||||
cpredictions.append(a)
|
||||
|
||||
|
||||
messages.error(request,message)
|
||||
return render(request, 'rankings.html',
|
||||
{'rankingworkouts':theworkouts,
|
||||
'interactiveplot':script,
|
||||
'the_div':div,
|
||||
'predictions':predictions,
|
||||
'cpredictions':cpredictions,
|
||||
'nrdata':len(thedistances),
|
||||
'form':form,
|
||||
'dateform':dateform,
|
||||
'deltaform':deltaform,
|
||||
'id': theuser,
|
||||
'theuser':uu,
|
||||
'startdate':startdate,
|
||||
'enddate':enddate,
|
||||
'teams':get_my_teams(request.user),
|
||||
})
|
||||
|
||||
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
||||
def workout_update_cp_view(request,id=0):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user