Private
Public Access
1
0

does Alternative OTE ranking

added an OTE ranking piece calculator based on manually added ranking
instead of automatically detected ranking
This commit is contained in:
Sander Roosendaal
2017-10-26 22:53:02 +02:00
parent 0f5c49de62
commit 29243516ae
8 changed files with 295 additions and 18 deletions

1
rowers/.#views.py Normal file
View File

@@ -0,0 +1 @@
E408191@CZ27LT9RCGN72.344848:1509049169

View File

@@ -473,21 +473,37 @@ def updatecpdata_sql(rower_id,delta,cp,table='cpdata',distance=[]):
engine.dispose()
def runcpupdate(rower):
def runcpupdate(rower,type='water'):
startdate = timezone.now()-datetime.timedelta(days=365)
enddate = timezone.now()+datetime.timedelta(days=5)
theworkouts = Workout.objects.filter(user=rower,rankingpiece=True,
workouttype='water',
startdatetime__gte=startdate,
startdatetime__lte=enddate)
if type == 'water':
theworkouts = Workout.objects.filter(
user=rower,rankingpiece=True,
workouttype='water',
startdatetime__gte=startdate,
startdatetime__lte=enddate
)
table = 'cpdata'
else:
theworkouts = Workout.objects.filter(
user=rower,rankingpiece=True,
workouttype__in=[
'rower',
'dynamic',
'slides'
],
startdatetime__gte=startdate,
startdatetime__lte=enddate
)
table = 'cpergdata'
theids = [w.id for w in theworkouts]
if settings.DEBUG:
res = handle_updatecp.delay(rower.id,theids,debug=True)
res = handle_updatecp.delay(rower.id,theids,debug=True,table=table)
else:
res = queue.enqueue(handle_updatecp,rower.id,theids)
res = queue.enqueue(handle_updatecp,rower.id,theids,table=table)
def fetchcperg(rower,theworkouts):
theids = [int(w.id) for w in theworkouts]
@@ -502,24 +518,29 @@ def fetchcperg(rower,theworkouts):
return cpdf
def fetchcp(rower,theworkouts):
def fetchcp(rower,theworkouts,table='cpdata'):
# get all power data from database (plus workoutid)
theids = [int(w.id) for w in theworkouts]
columns = ['power','workoutid','time']
df = getsmallrowdata_db(columns,ids=theids)
if df.empty:
avgpower2 = {}
for id in theids:
avgpower2[id] = 0
return pd.Series([]),pd.Series([]),avgpower2
dfgrouped = df.groupby(['workoutid'])
avgpower2 = dict(dfgrouped.mean()['power'].astype(int))
cpdf = getcpdata_sql(rower.id)
cpdf = getcpdata_sql(rower.id,table=table)
if not cpdf.empty:
return cpdf['delta'],cpdf['cp'],avgpower2
else:
if settings.DEBUG:
res = handle_updatecp.delay(rower.id,theids,debug=True)
res = handle_updatecp.delay(rower.id,theids,debug=True,table=table)
else:
res = queue.enqueue(handle_updatecp,rower.id,theids)
res = queue.enqueue(handle_updatecp,rower.id,theids,table=table)
return [],[],avgpower2

View File

@@ -653,6 +653,20 @@ class cpdata(models.Model):
index_together = ['user']
app_label = 'rowers'
# Storing data for the OTW CP chart
class cpergdata(models.Model):
delta = models.IntegerField(default=0)
cp = models.FloatField(default=0)
user = models.IntegerField(default=0)
class Meta:
db_table = 'cpergdata'
index_together = ['user']
app_label = 'rowers'
# Storing data for the OTW CP chart
class ergcpdata(models.Model):
delta = models.IntegerField(default=0)

View File

@@ -420,7 +420,7 @@ def handle_updateergcp(rower_id,workoutfilenames,debug=False):
@app.task
def handle_updatecp(rower_id,workoutids,debug=False):
def handle_updatecp(rower_id,workoutids,debug=False,table='cpdata'):
columns = ['power','workoutid','time']
df = getsmallrowdata_db(columns,ids=workoutids,debug=debug)
dfgrouped = df.groupby(['workoutid'])
@@ -435,7 +435,7 @@ def handle_updatecp(rower_id,workoutids,debug=False):
delta,cpvalue,avgpower = datautils.getcp(dfgrouped,logarr)
updatecpdata_sql(rower_id,delta,cpvalue,debug=debug)
updatecpdata_sql(rower_id,delta,cpvalue,debug=debug,table=table)
return 1

View File

@@ -92,7 +92,7 @@
{% endif %}
</p>
<p>
Analyse power vs piece duration to make predictions.
Analyse power vs piece duration to make predictions. For On-The-Water rowing.
</p>
</div>
<div class="grid_2">
@@ -120,6 +120,20 @@
</p>
</div>
</div>
<div class="grid_6 prefix_6 alpha">
<div class="grid_2 suffix_4 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
<a class="button blue small" href="/rowers/ote-ranking">OTE Ranking Pieces</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">OTE Ranking Pieces</a>
{% endif %}
</p>
<p>
Analyse power vs piece duration to make predictions, for erg pieces.
</p>
</div>
</div>
</div>

View File

@@ -196,8 +196,8 @@
minutes
</div>
<div class="grid_2 omega">
<input name="piece" class="button green"
formaction="/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
<input name="piece" class="button green"
action=""
type="submit" value="Add">
</form>
</div>

View File

@@ -150,7 +150,12 @@ urlpatterns = [
url(r'^otw-bests/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.otwrankings_view),
url(r'^otw-bests/(?P<deltadays>\d+)$',views.otwrankings_view),
url(r'^otw-bests/$',views.otwrankings_view),
url(r'^(?P<theuser>\d+)/otw-bests/$',views.otwrankings_view),
url(r'^(?P<theuser>\d+)/ote-ranking/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.oterankings_view),
url(r'^(?P<theuser>\d+)/ote-ranking/(?P<deltadays>\d+)$',views.oterankings_view),
url(r'^ote-ranking/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.oterankings_view),
url(r'^ote-ranking/(?P<deltadays>\d+)$',views.oterankings_view),
url(r'^ote-ranking/$',views.oterankings_view),
url(r'^(?P<theuser>\d+)/ote-ranking/$',views.oterankings_view),
url(r'^(?P<theuser>\d+)/flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.cum_flex),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.cum_flex),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)$',views.cum_flex),

View File

@@ -3091,6 +3091,228 @@ def otwrankings_view(request,theuser=0,
powerdf.drop_duplicates(subset='Delta',keep='first',inplace=True)
# create interactive plot
if len(powerdf) !=0 :
res = interactive_otwcpchart(powerdf,promember=promember)
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]
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)
clean = form.is_valid()
value = form.cleaned_data['value']
hourvalue,value = divmod(value,60)
hourvalue = int(hourvalue)
minutevalue = int(value)
value = int(60*(value-minutevalue))
if hourvalue >= 24:
hourvalue = 23
rankingdurations.append(datetime.time(minute=minutevalue,
hour=hourvalue,
second=value))
else:
form = PredictedPieceForm()
cpredictions = []
for rankingduration in rankingdurations:
t = 3600.*rankingduration.hour
t += 60.*rankingduration.minute
t += rankingduration.second
t += rankingduration.microsecond/1.e6
# CP model
pwr = p1[0]/(1+t/p1[2])
pwr += p1[1]/(1+t/p1[3])
if pwr <= 0:
pwr = 50.
if not np.isnan(pwr):
try:
pwr2 = pwr*ratio
except:
pwr2 = pwr
a = {
'duration':timedeltaconv(t),
'power':int(pwr),
'upper':int(pwr2)}
cpredictions.append(a)
del form.fields["pieceunit"]
messages.error(request,message)
return render(request, 'otwrankings.html',
{'rankingworkouts':theworkouts,
'interactiveplot':script,
'the_div':div,
'cpredictions':cpredictions,
'avgpower':avgpower,
'form':form,
'dateform':dateform,
'deltaform':deltaform,
'id': theuser,
'theuser':uu,
'startdate':startdate,
'enddate':enddate,
'teams':get_my_teams(request.user),
})
# Show ranking distances including predicted paces
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def oterankings_view(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 = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and ispromember(request.user)
if result:
promember=1
# get all OTW 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 = Rower.objects.get(user=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)
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))
rankingdurations.append(datetime.time(hour=1,minute=15))
thedistances = []
theworkouts = []
thesecs = []
theworkouts = Workout.objects.filter(user=r,rankingpiece=True,
workouttype__in=[
'rower',
'dynamic',
'slides'
],
startdatetime__gte=startdate,
startdatetime__lte=enddate)
delta,cpvalue,avgpower = dataprep.fetchcp(
r,theworkouts,table='cpergdata'
)
powerdf = pd.DataFrame({
'Delta':delta,
'CP':cpvalue,
})
if powerdf.empty:
messages.info(request,'Your calculations are running in the background. Please reload this page.')
powerdf = powerdf[powerdf['CP']>0]
powerdf.dropna(axis=0,inplace=True)
powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True)
powerdf.drop_duplicates(subset='Delta',keep='first',inplace=True)
# create interactive plot
if len(powerdf) !=0 :
res = interactive_otwcpchart(powerdf,promember=promember)
@@ -6630,7 +6852,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
successmessage = "Changes saved"
if rankingpiece:
dataprep.runcpupdate(row.user)
dataprep.runcpupdate(row.user,type=row.workouttype)
messages.info(request,successmessage)
url = reverse(workout_edit_view,