adding cpoverlay (world class)
This commit is contained in:
@@ -1218,6 +1218,10 @@ class AnalysisChoiceForm(forms.Form):
|
||||
cpfit = forms.ChoiceField(choices=cpfitchoices,
|
||||
label = 'Model Fit',initial='data',required=False)
|
||||
|
||||
cpoverlay = forms.BooleanField(initial=False,
|
||||
label='Overlay World Record Performance',
|
||||
required=False)
|
||||
|
||||
piece = forms.IntegerField(initial=4,label='Ranking Piece (minutes)',
|
||||
required=False)
|
||||
|
||||
|
||||
@@ -3304,7 +3304,8 @@ def interactive_agegroupcpchart(age,normalized=False):
|
||||
|
||||
|
||||
def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data',
|
||||
title='',type='water'):
|
||||
title='',type='water',
|
||||
wcpower=[],wcdurations=[],cpoverlay=False):
|
||||
|
||||
powerdf = powerdf[~(powerdf == 0).any(axis=1)]
|
||||
# plot tools
|
||||
@@ -3356,6 +3357,34 @@ def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data',
|
||||
workouts = powerdf['workout']
|
||||
urls = powerdf['url']
|
||||
|
||||
# add world class
|
||||
wcpower = pd.Series(wcpower)
|
||||
wcdurations = pd.Series(wcdurations)
|
||||
|
||||
|
||||
# fitting WC data to three parameter CP model
|
||||
if len(wcdurations)>=4:
|
||||
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
|
||||
p1wc, success = optimize.leastsq(errfunc, p0[:],
|
||||
args = (wcdurations,wcpower))
|
||||
else:
|
||||
p1wc = None
|
||||
|
||||
if p1wc is not None and cpoverlay:
|
||||
fitpowerwc = 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
|
||||
|
||||
|
||||
sourcecomplex = ColumnDataSource(
|
||||
data = dict(
|
||||
@@ -3364,6 +3393,11 @@ def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data',
|
||||
duration = fitt/60.,
|
||||
ftime = ftime,
|
||||
workout = workouts,
|
||||
fitpowerwc = fitpowerwc,
|
||||
fitpowerexcellent = fitpowerexcellent,
|
||||
fitpowergood = fitpowergood,
|
||||
fitpowerfair = fitpowerfair,
|
||||
fitpoweraverage = fitpoweraverage,
|
||||
url = urls,
|
||||
)
|
||||
)
|
||||
@@ -3424,6 +3458,7 @@ def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data',
|
||||
('Power (W)','@CP{int}'),
|
||||
('Power (W) upper','@CPmax{int}'),
|
||||
('Workout','@workout'),
|
||||
('World Class','@fitpowerwc{int}')
|
||||
])
|
||||
|
||||
hover.mode = 'mouse'
|
||||
@@ -3437,6 +3472,27 @@ def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data',
|
||||
plot.line('duration','CPmax',source=sourcecomplex,legend_label="CP Model",
|
||||
color='red')
|
||||
|
||||
if p1wc is not None:
|
||||
plot.line('duration','fitpowerwc',source=sourcecomplex,
|
||||
legend_label="World Class",
|
||||
color='darkgoldenrod',line_dash='dotted')
|
||||
|
||||
plot.line('duration','fitpowerexcellent',source=sourcecomplex,
|
||||
legend_label="90% percentile",
|
||||
color='goldenrod',line_dash='dotted')
|
||||
|
||||
plot.line('duration','fitpowergood',source=sourcecomplex,
|
||||
legend_label="75% percentile",
|
||||
color='sandybrown',line_dash='dotted')
|
||||
|
||||
plot.line('duration','fitpowerfair',source=sourcecomplex,
|
||||
legend_label="50% percentile",
|
||||
color='rosybrown',line_dash='dotted')
|
||||
|
||||
plot.line('duration','fitpoweraverage',source=sourcecomplex,
|
||||
legend_label="25% percentile",
|
||||
color='tan',line_dash='dotted')
|
||||
|
||||
script, div = components(plot)
|
||||
|
||||
return [script,div,p1,ratio,message]
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
var reststrokes = $("#id_includereststrokes").parent().parent();
|
||||
var piece = $("#id_piece").parent().parent();
|
||||
var cpfit = $("#id_cpfit").parent().parent();
|
||||
var cpoverlay = $("#id_cpoverlay").parent().parent();
|
||||
|
||||
|
||||
// Hide the fields.
|
||||
@@ -113,6 +114,7 @@
|
||||
spmmin.hide();
|
||||
spmmax.hide();
|
||||
cpfit.hide();
|
||||
cpoverlay.hide();
|
||||
piece.hide();
|
||||
|
||||
if (functionfield.val() == 'boxplot') {
|
||||
@@ -153,6 +155,7 @@
|
||||
if (functionfield.val() == 'cp') {
|
||||
cpfit.show();
|
||||
piece.show();
|
||||
cpoverlay.show();
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +185,7 @@
|
||||
plottype.hide();
|
||||
reststrokes.show();
|
||||
cpfit.hide();
|
||||
cpoverlay.hide();
|
||||
piece.hide();
|
||||
}
|
||||
else if (Value=='histo') {
|
||||
@@ -202,6 +206,7 @@
|
||||
plottype.hide();
|
||||
reststrokes.show();
|
||||
cpfit.hide();
|
||||
cpoverlay.hide();
|
||||
piece.hide();
|
||||
|
||||
}
|
||||
@@ -223,6 +228,7 @@
|
||||
plottype.hide();
|
||||
reststrokes.show();
|
||||
cpfit.hide();
|
||||
cpoverlay.hide();
|
||||
piece.hide();
|
||||
|
||||
}
|
||||
@@ -244,6 +250,7 @@
|
||||
errorbars.hide();
|
||||
reststrokes.show();
|
||||
cpfit.hide();
|
||||
cpoverlay.hide();
|
||||
piece.hide();
|
||||
}
|
||||
else if (Value=='stats') {
|
||||
@@ -260,6 +267,7 @@
|
||||
plottype.hide();
|
||||
reststrokes.show();
|
||||
cpfit.hide();
|
||||
cpoverlay.hide();
|
||||
piece.hide();
|
||||
}
|
||||
else if (Value=='compare') {
|
||||
@@ -280,6 +288,7 @@
|
||||
errorbars.hide();
|
||||
piece.hide();
|
||||
cpfit.hide();
|
||||
cpoverlay.hide();
|
||||
reststrokes.show();
|
||||
|
||||
|
||||
@@ -302,6 +311,7 @@
|
||||
plottype.hide();
|
||||
reststrokes.hide();
|
||||
cpfit.show();
|
||||
cpoverlay.hide();
|
||||
piece.show();
|
||||
}
|
||||
});
|
||||
@@ -372,6 +382,126 @@
|
||||
<input name='optionsform' type="submit" value="Submit">
|
||||
</form>
|
||||
</li>
|
||||
{% if worldclass %}
|
||||
{% if age and sex != 'not specified' %}
|
||||
<li class="grid_4">
|
||||
<h2>World Records</h2>
|
||||
<p>The dashed lines are based on the
|
||||
<a href="https://log.concept2.com/rankings">Concept2</a>
|
||||
rankings for your age ({{ age }}), gender ({{ sex }})
|
||||
and weight category ({{ weightcategory }}). World class means within 5% of
|
||||
<a href="http://www.concept2.com/indoor-rowers/racing/records/world">
|
||||
World Record</a> in terms
|
||||
of power.
|
||||
The percentile lines are estimates of where the percentiles
|
||||
of the Concept2 rankings historically are for those of exactly
|
||||
your age, gender and weight class.
|
||||
</p>
|
||||
<p>
|
||||
For rowing on the water, the results are corrected for the expected
|
||||
difference in power between the Concept2 indoor rower and power
|
||||
values on the water.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<table width="100%" class="listtable">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/100m/">100m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/500m/">500m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/1000m/">1000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/2000m/">2000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/5000m/">5000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/6000m/">6000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/10000m/">10000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/21097m/">Half Marathon
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/42195m/">Full Marathon
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/1min/">1 minute
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/4min/">4 minutes
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/30min/">30 minutes
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/60min/">1 hour
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''):
|
||||
r = getrequestrower(request, userid=userid)
|
||||
user = r.user
|
||||
userid = user.id
|
||||
worldclass = False
|
||||
|
||||
firstworkout = None
|
||||
if id:
|
||||
@@ -71,6 +72,10 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''):
|
||||
modalities = [m[0] for m in mytypes.workouttypes_ordered.items()]
|
||||
modality = 'all'
|
||||
|
||||
try:
|
||||
worldclass = options['cpoverlay']
|
||||
except KeyError:
|
||||
worldclass = False
|
||||
|
||||
|
||||
try:
|
||||
@@ -132,6 +137,12 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''):
|
||||
|
||||
options['modalities'] = modalities
|
||||
options['waterboattype'] = waterboattype
|
||||
try:
|
||||
worldclass = options['cpoverlay']
|
||||
except KeyError:
|
||||
worldclass = False
|
||||
options['cpoverlay'] = worldclass
|
||||
|
||||
|
||||
chartform = AnalysisChoiceForm(request.POST)
|
||||
if chartform.is_valid():
|
||||
@@ -240,6 +251,10 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''):
|
||||
})
|
||||
|
||||
|
||||
if r.birthdate:
|
||||
age = calculate_age(r.birthdate)
|
||||
else:
|
||||
age = 0
|
||||
|
||||
startdatestring = startdate.strftime('%Y-%m-%d')
|
||||
enddatestring = enddate.strftime('%Y-%m-%d')
|
||||
@@ -272,6 +287,10 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0,id=''):
|
||||
'chartform':chartform,
|
||||
'searchform':searchform,
|
||||
'optionsform':optionsform,
|
||||
'worldclass':worldclass,
|
||||
'age':age,
|
||||
'sex':r.sex,
|
||||
'weightcategory':r.weightcategory,
|
||||
'teams':get_my_teams(request.user),
|
||||
})
|
||||
|
||||
@@ -519,6 +538,7 @@ def histodata(workouts, options):
|
||||
def cpdata(workouts, options):
|
||||
userid = options['userid']
|
||||
cpfit = options['cpfit']
|
||||
cpoverlay = options['cpoverlay']
|
||||
|
||||
u = User.objects.get(id=userid)
|
||||
r = u.rower
|
||||
@@ -546,6 +566,9 @@ def cpdata(workouts, options):
|
||||
|
||||
rowername = r.user.first_name+" "+r.user.last_name
|
||||
|
||||
wcdurations = []
|
||||
wcpower = []
|
||||
|
||||
if len(powerdf) !=0 :
|
||||
datefirst = pd.Series(w.date for w in workouts).min()
|
||||
datelast = pd.Series(w.date for w in workouts).max()
|
||||
@@ -561,19 +584,42 @@ def cpdata(workouts, options):
|
||||
# for Mike
|
||||
wtype = 'erg'
|
||||
|
||||
if cpoverlay:
|
||||
if r.birthdate:
|
||||
age = calculate_age(r.birthdate)
|
||||
else:
|
||||
worldclasspower = None
|
||||
age = 0
|
||||
|
||||
agerecords = CalcAgePerformance.objects.filter(
|
||||
age = age,
|
||||
sex = r.sex,
|
||||
weightcategory = r.weightcategory
|
||||
)
|
||||
|
||||
if len(agerecords) == 0:
|
||||
wcpower = []
|
||||
wcdurations = []
|
||||
else:
|
||||
wcdurations = []
|
||||
wcpower = []
|
||||
for record in agerecords:
|
||||
recordpower = record.power
|
||||
if wtype == 'water':
|
||||
recordpower = record.power*(100.-r.otwslack)/100.
|
||||
|
||||
wcdurations.append(record.duration)
|
||||
wcpower.append(recordpower)
|
||||
|
||||
res = interactive_otwcpchart(powerdf,promember=True,rowername=rowername,r=r,
|
||||
cpfit=cpfit,title=title,type=wtype)
|
||||
cpfit=cpfit,title=title,type=wtype,
|
||||
cpoverlay=cpoverlay,
|
||||
wcdurations=wcdurations,wcpower=wcpower)
|
||||
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
p1 = res[2]
|
||||
ratio = res[3]
|
||||
#r.p0 = p1[0]
|
||||
#r.p1 = p1[1]
|
||||
#r.p2 = p1[2]
|
||||
#r.p3 = p1[3]
|
||||
#r.cpratio = ratio
|
||||
#r.save()
|
||||
paulslope = 1
|
||||
paulintercept = 1
|
||||
message = res[4]
|
||||
@@ -2194,7 +2240,7 @@ def rankings_view2(request,userid=0,
|
||||
if len(agerecords) == 0:
|
||||
recalc = True
|
||||
wcpower = []
|
||||
wcduration = []
|
||||
wcdurations = []
|
||||
else:
|
||||
wcdurations = []
|
||||
wcpower = []
|
||||
|
||||
Reference in New Issue
Block a user