From 7616220da10bd23d3b4a5013fc15a4cba0ae7776 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 14 Dec 2017 16:35:26 +0100 Subject: [PATCH] added agegroupcp --- rowers/interactiveplots.py | 249 +++++++++++++++++++++++++++++++ rowers/templates/agegroupcp.html | 47 ++++++ rowers/urls.py | 2 + rowers/views.py | 12 ++ 4 files changed, 310 insertions(+) create mode 100644 rowers/templates/agegroupcp.html diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 9b4ccc07..9a5aa37f 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -977,6 +977,255 @@ def googlemap_chart(lat,lon,name=""): return [script,div] +def interactive_agegroupcpchart(age,normalized=False): + durations = [1,4,30,60] + distances = [100,500,1000,2000,5000,6000,10000,21097,42195] + + fhduration = [] + fhpower = [] + + for distance in distances: + worldclasspower = metrics.getagegrouprecord( + age, + sex='female', + distance=distance, + weightcategory='hwt' + ) + velo = (worldclasspower/2.8)**(1./3.) + try: + duration = distance/velo + fhduration.append(duration) + fhpower.append(worldclasspower) + except ZeroDivisionError: + pass + for duration in durations: + worldclasspower = metrics.getagegrouprecord( + age, + sex='female', + duration=duration, + weightcategory='hwt' + ) + try: + velo = (worldclasspower/2.8)**(1./3.) + distance = int(60*duration*velo) + fhduration.append(60.*duration) + fhpower.append(worldclasspower) + except ValueError: + pass + + flduration = [] + flpower = [] + + for distance in distances: + worldclasspower = metrics.getagegrouprecord( + age, + sex='female', + distance=distance, + weightcategory='lwt' + ) + velo = (worldclasspower/2.8)**(1./3.) + try: + duration = distance/velo + flduration.append(duration) + flpower.append(worldclasspower) + except ZeroDivisionError: + pass + for duration in durations: + worldclasspower = metrics.getagegrouprecord( + age, + sex='female', + duration=duration, + weightcategory='lwt' + ) + try: + velo = (worldclasspower/2.8)**(1./3.) + distance = int(60*duration*velo) + flduration.append(60.*duration) + flpower.append(worldclasspower) + except ValueError: + pass + + mlduration = [] + mlpower = [] + + for distance in distances: + worldclasspower = metrics.getagegrouprecord( + age, + sex='male', + distance=distance, + weightcategory='lwt' + ) + velo = (worldclasspower/2.8)**(1./3.) + try: + duration = distance/velo + mlduration.append(duration) + mlpower.append(worldclasspower) + except ZeroDivisionError: + pass + for duration in durations: + worldclasspower = metrics.getagegrouprecord( + age, + sex='male', + duration=duration, + weightcategory='lwt' + ) + try: + velo = (worldclasspower/2.8)**(1./3.) + distance = int(60*duration*velo) + mlduration.append(60.*duration) + mlpower.append(worldclasspower) + except ValueError: + pass + + + mhduration = [] + mhpower = [] + + for distance in distances: + worldclasspower = metrics.getagegrouprecord( + age, + sex='male', + distance=distance, + weightcategory='hwt' + ) + velo = (worldclasspower/2.8)**(1./3.) + try: + duration = distance/velo + mhduration.append(duration) + mhpower.append(worldclasspower) + except ZeroDivisionError: + pass + for duration in durations: + worldclasspower = metrics.getagegrouprecord( + age, + sex='male', + duration=duration, + weightcategory='hwt' + ) + try: + velo = (worldclasspower/2.8)**(1./3.) + distance = int(60*duration*velo) + mhduration.append(60.*duration) + mhpower.append(worldclasspower) + except ValueError: + pass + + + + 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] + + # fitting WC data to three parameter CP model + if len(fhduration)>=4: + p1fh, success = optimize.leastsq(errfunc, p0[:], + args = (fhduration,fhpower)) + else: + p1fh = None + + # fitting WC data to three parameter CP model + if len(flduration)>=4: + p1fl, success = optimize.leastsq(errfunc, p0[:], + args = (flduration,flpower)) + else: + p1fl = None + + # fitting WC data to three parameter CP model + if len(mlduration)>=4: + p1ml, success = optimize.leastsq(errfunc, p0[:], + args = (mlduration,mlpower)) + else: + p1ml = None + + if len(mhduration)>=4: + p1mh, success = optimize.leastsq(errfunc, p0[:], + args = (mhduration,mhpower)) + else: + p1mh = None + + fitt = pd.Series(10**(4*np.arange(100)/100.)) + + fitpowerfh = fitfunc(p1fh,fitt) + fitpowerfl = fitfunc(p1fl,fitt) + fitpowerml = fitfunc(p1ml,fitt) + fitpowermh = fitfunc(p1mh,fitt) + + if normalized: + facfh = fitfunc(p1fh,60) + facfl = fitfunc(p1fl,60) + facml = fitfunc(p1ml,60) + facmh = fitfunc(p1mh,60) + fitpowerfh /= facfh + fitpowerfl /= facfl + fitpowermh /= facmh + fitpowerml /= facml + fhpower /= facfh + flpower /= facfl + mlpower /= facml + mhpower /= facmh + + + + source = ColumnDataSource( + data = dict( + duration = fitt, + fitpowerfh = fitpowerfh, + fitpowerfl = fitpowerfl, + fitpowerml = fitpowerml, + fitpowermh = fitpowermh, + flduration = flduration, + flpower = flpower, + fhduration = fhduration, + fhpower = fhpower, + mlduration = mlduration, + mlpower = mlpower, + mhduration = mhduration, + mhpower = mhpower, + ) + ) + + x_axis_type = 'log' + y_axis_type = 'linear' + + plot = Figure(plot_width=900,x_axis_type=x_axis_type) + + plot.line('duration','fitpowerfh',source=source, + legend='Female HW',color='blue') + plot.line('duration','fitpowerfl',source=source, + legend='Female LW',color='red') + + plot.line('duration','fitpowerml',source=source, + legend='Male LW',color='green') + + plot.line('duration','fitpowermh',source=source, + legend='Male HW',color='orange') + + + plot.circle('flduration','flpower',source=source, + fill_color='red',size=15) + + plot.circle('fhduration','fhpower',source=source, + fill_color='blue',size=15) + + plot.circle('mlduration','mlpower',source=source, + fill_color='green',size=15) + + plot.circle('mhduration','mhpower',source=source, + fill_color='orange',size=15) + + plot.title.text = 'age '+str(age) + + plot.xaxis.axis_label = "Duration (seconds)" + if normalized: + plot.yaxis.axis_label = "Power (normalized)" + else: + plot.yaxis.axis_label = "Power (W)" + + script,div = components(plot) + + return script,div + def interactive_otwcpchart(powerdf,promember=0): powerdf = powerdf[~(powerdf == 0).any(axis=1)] diff --git a/rowers/templates/agegroupcp.html b/rowers/templates/agegroupcp.html new file mode 100644 index 00000000..2bebbe61 --- /dev/null +++ b/rowers/templates/agegroupcp.html @@ -0,0 +1,47 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Rowsandall {% endblock %} + +{% block content %} + + + + + {{ interactiveplot |safe }} + + + + + +
+ + +

Interactive Plot

+ + + {{ the_div|safe }} + +
+ +{% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index d0b07cf3..0a80c22a 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -121,6 +121,8 @@ urlpatterns = [ url(r'^400/$', TemplateView.as_view(template_name='400.html'),name='400'), url(r'^403/$', TemplateView.as_view(template_name='403.html'),name='403'), url(r'^imports/$', TemplateView.as_view(template_name='imports.html'), name='imports'), + url(r'^agegroupcp/(?P\d+)$',views.agegroupcpview), + url(r'^agegroupcp/(?P\d+)/(?P\d+)$',views.agegroupcpview), url(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/(?P\d+)m$', views.agegrouprecordview), url(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/(?P\d+)min$', diff --git a/rowers/views.py b/rowers/views.py index 19db2372..07e0d6c5 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -11287,6 +11287,18 @@ def team_members_stats_view(request,id): from rowers.models import C2WorldClassAgePerformance +def agegroupcpview(request,age,normalize=0): + script,div = interactive_agegroupcpchart(age,normalized=normalize) + + response = render(request,'agegroupcp.html', + { + 'interactiveplot':script, + 'the_div':div, + } + ) + + return response + def agegrouprecordview(request,sex='male',weightcategory='hwt', distance=2000,duration=None): if not duration: