Merge branch 'feature/cp2' into develop
This commit is contained in:
@@ -96,7 +96,7 @@ queuelow = django_rq.get_queue('low')
|
||||
queuehigh = django_rq.get_queue('default')
|
||||
|
||||
from rowsandall_app.settings import SITE_URL
|
||||
from rowers.mytypes import otwtypes,otetypes
|
||||
from rowers.mytypes import otwtypes,otetypes,rowtypes
|
||||
from rowers import mytypes
|
||||
|
||||
from rowers.database import *
|
||||
@@ -1016,6 +1016,53 @@ def fetchcperg(rower,theworkouts):
|
||||
|
||||
return cpdf
|
||||
|
||||
def fetchcp_new(rower,workouts):
|
||||
|
||||
data = []
|
||||
for workout in workouts:
|
||||
cpfile = 'media/cpdata_{id}.parquet.gz'.format(id=workout.id)
|
||||
try:
|
||||
df = pd.read_parquet(cpfile)
|
||||
data.append(df)
|
||||
except OSError:
|
||||
# CP data file doesn't exist yet. has to be created
|
||||
strokesdf = getsmallrowdata_db(['power','workoutid','time'],ids = [workout.id])
|
||||
if not strokesdf.empty:
|
||||
totaltime = strokesdf['time'].max()
|
||||
try:
|
||||
powermean = strokesdf['power'].mean()
|
||||
except KeyError:
|
||||
powermean = 0
|
||||
|
||||
if powermean != 0:
|
||||
thesecs = totaltime
|
||||
maxt = 1.05 * thesecs
|
||||
|
||||
if maxt > 0:
|
||||
logarr = datautils.getlogarr(maxt)
|
||||
dfgrouped = strokesdf.groupby(['workoutid'])
|
||||
delta, cpvalues, avgpower = datautils.getcp(dfgrouped, logarr)
|
||||
filename = 'media/cpdata_{id}.parquet.gz'.format(id=workout.id)
|
||||
df = pd.DataFrame({
|
||||
'delta':delta,
|
||||
'cp':cpvalues,
|
||||
'id':workout.id,
|
||||
})
|
||||
df.to_parquet(filename,engine='fastparquet',compression='GZIP')
|
||||
data.append(df)
|
||||
|
||||
|
||||
if len(data) == 0:
|
||||
return pd.Series(),pd.Series(),0
|
||||
if len(data)>1:
|
||||
df = pd.concat(data,axis=0)
|
||||
|
||||
df = df.groupby(['delta']).max()
|
||||
|
||||
|
||||
df = df.sort_values(['delta']).reset_index()
|
||||
|
||||
return df['delta'],df['cp'],0
|
||||
|
||||
def fetchcp(rower,theworkouts,table='cpdata'):
|
||||
# get all power data from database (plus workoutid)
|
||||
@@ -1434,7 +1481,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
|
||||
isbreakthrough = False
|
||||
ishard = False
|
||||
if workouttype == 'water':
|
||||
if workouttype in rowtypes:
|
||||
df = getsmallrowdata_db(['power', 'workoutid', 'time'], ids=[w.id])
|
||||
try:
|
||||
powermean = df['power'].mean()
|
||||
@@ -1448,15 +1495,26 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
logarr = datautils.getlogarr(maxt)
|
||||
dfgrouped = df.groupby(['workoutid'])
|
||||
delta, cpvalues, avgpower = datautils.getcp(dfgrouped, logarr)
|
||||
filename = 'media/cpdata_{id}.parquet.gz'.format(id=w.id)
|
||||
cpdf = pd.DataFrame({
|
||||
'delta':delta,
|
||||
'cp':cpvalues,
|
||||
'id':w.id,
|
||||
})
|
||||
cpdf.to_parquet(filename,engine='fastparquet',compression='GZIP')
|
||||
|
||||
res, btvalues, res2 = utils.isbreakthrough(
|
||||
delta, cpvalues, r.p0, r.p1, r.p2, r.p3, r.cpratio)
|
||||
if workouttype in otwtypes:
|
||||
res, btvalues, res2 = utils.isbreakthrough(
|
||||
delta, cpvalues, r.p0, r.p1, r.p2, r.p3, r.cpratio)
|
||||
elif workouttype in otetypes:
|
||||
res, btvalues, res2 = utils.isbreakthrough(
|
||||
delta, cpvalues, r.ep0, r.ep1, r.ep2, r.ep3, r.ecpratio)
|
||||
else:
|
||||
res = 0
|
||||
res2 = 0
|
||||
if res:
|
||||
isbreakthrough = True
|
||||
res = datautils.updatecp(delta, cpvalues, r)
|
||||
res = datautils.updatecp(delta, cpvalues, r,workouttype=workouttype)
|
||||
if res2 and not isbreakthrough:
|
||||
ishard = True
|
||||
|
||||
|
||||
@@ -8,12 +8,24 @@ import numpy as np
|
||||
from scipy.interpolate import griddata
|
||||
from scipy import optimize
|
||||
|
||||
from rowers.mytypes import otwtypes,otetypes,rowtypes
|
||||
|
||||
#p0 = [500,350,10,8000]
|
||||
p0 = [190,200,33,16000]
|
||||
|
||||
def updatecp(delta,cpvalues,r):
|
||||
cp2 = r.p0/(1+delta/r.p2)
|
||||
cp2 += r.p1/(1+delta/r.p3)
|
||||
def updatecp(delta,cpvalues,r,workouttype='water'):
|
||||
if workouttype in otwtypes:
|
||||
p0 = r.p0
|
||||
p1 = r.p1
|
||||
p2 = r.p2
|
||||
p3 = r.p3
|
||||
else:
|
||||
p0 = r.ep0
|
||||
p1 = r.ep1
|
||||
p2 = r.ep2
|
||||
p3 = r.ep3
|
||||
cp2 = p0/(1+delta/p2)
|
||||
cp2 += p1/(1+delta/p3)
|
||||
|
||||
delta = delta.append(delta)
|
||||
cp = cpvalues.append(cp2)
|
||||
@@ -31,11 +43,18 @@ def updatecp(delta,cpvalues,r):
|
||||
res = cpfit(powerdf)
|
||||
p1 = res[0]
|
||||
|
||||
r.p0 = p1[0]
|
||||
r.p1 = p1[1]
|
||||
r.p2 = p1[2]
|
||||
r.p3 = p1[3]
|
||||
r.cpratio = res[3]
|
||||
if workouttype in otwtypes:
|
||||
r.p0 = p1[0]
|
||||
r.p1 = p1[1]
|
||||
r.p2 = p1[2]
|
||||
r.p3 = p1[3]
|
||||
r.cpratio = res[3]
|
||||
else:
|
||||
r.ep0 = p1[0]
|
||||
r.ep1 = p1[1]
|
||||
r.ep2 = p1[2]
|
||||
r.ep3 = p1[3]
|
||||
r.ecpratio = res[3]
|
||||
|
||||
r.save()
|
||||
|
||||
@@ -89,7 +108,10 @@ def cpfit(powerdf):
|
||||
|
||||
def getlogarr(maxt):
|
||||
maxlog10 = np.log10(maxt-5)
|
||||
logarr = np.arange(50)*maxlog10/50.
|
||||
#print(maxlog10,round(maxlog10))
|
||||
aantal = 10*round(maxlog10)
|
||||
logarr = np.arange(aantal+1)/10.
|
||||
|
||||
res = []
|
||||
for la in logarr:
|
||||
try:
|
||||
|
||||
@@ -1036,7 +1036,7 @@ analysischoices = (
|
||||
('flexall','Cumulative Flex Chart'),
|
||||
('stats','Statistics'),
|
||||
('compare','Compare'),
|
||||
('cp','CP Chart')
|
||||
('cp','CP chart'),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -2985,6 +2985,13 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
# remove parquet file
|
||||
try:
|
||||
dirname = 'media/cpdata_{id}.parquet.gz'.format(id=instance.id)
|
||||
os.remove(dirname)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
@receiver(models.signals.post_delete,sender=Workout)
|
||||
def update_duplicates_on_delete(sender, instance, **kwargs):
|
||||
if instance.id:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}Workouts{% endblock %}
|
||||
{% block title %}Analysis{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<script>
|
||||
@@ -16,14 +16,14 @@
|
||||
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
|
||||
|
||||
// Get the form fields and hidden div
|
||||
var modality = $("#id_modality");
|
||||
var hidden = $("#id_waterboattype");
|
||||
|
||||
|
||||
|
||||
// Hide the fields.
|
||||
// Use JS to do this in case the user doesn't have JS
|
||||
// Use JS to do this in case the user doesn't have JS
|
||||
// enabled.
|
||||
|
||||
hidden.hide();
|
||||
@@ -32,8 +32,8 @@
|
||||
hidden.show();
|
||||
}
|
||||
|
||||
|
||||
// Setup an event listener for when the state of the
|
||||
|
||||
// Setup an event listener for when the state of the
|
||||
// checkbox changes.
|
||||
modality.change(function() {
|
||||
// Check to see if the checkbox is checked.
|
||||
@@ -48,10 +48,10 @@
|
||||
// Make sure that the hidden fields are indeed
|
||||
// hidden.
|
||||
hidden.hide();
|
||||
|
||||
// You may also want to clear the value of the
|
||||
// hidden fields here. Just in case somebody
|
||||
// shows the fields, enters data to them and then
|
||||
|
||||
// You may also want to clear the value of the
|
||||
// hidden fields here. Just in case somebody
|
||||
// shows the fields, enters data to them and then
|
||||
// unticks the checkbox.
|
||||
//
|
||||
// This would do the job:
|
||||
@@ -67,7 +67,7 @@
|
||||
<script>
|
||||
// script for chart options form
|
||||
$(function() {
|
||||
|
||||
|
||||
// Get the form fields and hidden div
|
||||
var functionfield = $("#id_function");
|
||||
var plotfield = $("#id_plotfield").parent().parent();
|
||||
@@ -82,14 +82,16 @@
|
||||
var spmmax = $("#id_spmmax").parent().parent();
|
||||
var workmin = $("#id_workmin").parent().parent();
|
||||
var workmax = $("#id_workmax").parent().parent();
|
||||
|
||||
var xaxis = $("#id_xaxis").parent().parent();
|
||||
var yaxis1 = $("#id_yaxis1").parent().parent();
|
||||
var yaxis2 = $("#id_yaxis2").parent().parent();
|
||||
var plottype = $("#id_plottype").parent().parent();
|
||||
|
||||
var xaxis = $("#id_xaxis").parent().parent();
|
||||
var yaxis1 = $("#id_yaxis1").parent().parent();
|
||||
var yaxis2 = $("#id_yaxis2").parent().parent();
|
||||
var plottype = $("#id_plottype").parent().parent();
|
||||
|
||||
var reststrokes = $("#id_includereststrokes").parent().parent();
|
||||
|
||||
// Hide the fields.
|
||||
// Use JS to do this in case the user doesn't have JS
|
||||
// Use JS to do this in case the user doesn't have JS
|
||||
// enabled.
|
||||
plotfield.hide();
|
||||
x_param.hide();
|
||||
@@ -102,6 +104,11 @@
|
||||
yaxis1.hide();
|
||||
yaxis2.hide();
|
||||
plottype.hide();
|
||||
reststrokes.hide();
|
||||
workmin.hide();
|
||||
workmax.hide();
|
||||
spmmin.hide();
|
||||
spmmax.hide();
|
||||
|
||||
if (functionfield.val() == 'boxplot') {
|
||||
plotfield.show();
|
||||
@@ -136,8 +143,8 @@
|
||||
plottype.show();
|
||||
}
|
||||
|
||||
|
||||
// Setup an event listener for when the state of the
|
||||
|
||||
// Setup an event listener for when the state of the
|
||||
// checkbox changes.
|
||||
functionfield.change(function() {
|
||||
// Check to see if the checkbox is checked.
|
||||
@@ -161,6 +168,7 @@
|
||||
yaxis1.hide();
|
||||
yaxis2.hide();
|
||||
plottype.hide();
|
||||
reststrokes.show();
|
||||
}
|
||||
else if (Value=='histo') {
|
||||
plotfield.show();
|
||||
@@ -178,6 +186,7 @@
|
||||
yaxis1.hide();
|
||||
yaxis2.hide();
|
||||
plottype.hide();
|
||||
reststrokes.show();
|
||||
|
||||
}
|
||||
else if (Value=='trendflex') {
|
||||
@@ -196,6 +205,7 @@
|
||||
yaxis1.hide();
|
||||
yaxis2.hide();
|
||||
plottype.hide();
|
||||
reststrokes.show();
|
||||
|
||||
}
|
||||
else if (Value=='flexall') {
|
||||
@@ -214,6 +224,7 @@
|
||||
binsize.hide();
|
||||
plottype.hide();
|
||||
errorbars.hide();
|
||||
reststrokes.show();
|
||||
}
|
||||
else if (Value=='stats') {
|
||||
xaxis.hide();
|
||||
@@ -227,6 +238,7 @@
|
||||
binsize.hide();
|
||||
errorbars.hide();
|
||||
plottype.hide();
|
||||
reststrokes.show();
|
||||
}
|
||||
else if (Value=='compare') {
|
||||
xaxis.show();
|
||||
@@ -244,10 +256,29 @@
|
||||
binsize.hide();
|
||||
plottype.show();
|
||||
errorbars.hide();
|
||||
reststrokes.show();
|
||||
}
|
||||
else if (Value=='cp') {
|
||||
plotfield.hide();
|
||||
spmmin.hide();
|
||||
spmmax.hide();
|
||||
workmin.hide();
|
||||
workmax.hide();
|
||||
x_param.hide();
|
||||
y_param.hide();
|
||||
groupby.hide();
|
||||
palette.hide();
|
||||
binsize.hide();
|
||||
errorbars.hide();
|
||||
xaxis.hide();
|
||||
yaxis1.hide();
|
||||
yaxis2.hide();
|
||||
plottype.hide();
|
||||
reststrokes.hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div id="id_css_res">
|
||||
@@ -285,9 +316,9 @@
|
||||
<input type="submit" value="GO"></input>
|
||||
</form>
|
||||
<form enctype="multipart/form-data" action="" method="post">
|
||||
|
||||
|
||||
{% if workouts %}
|
||||
|
||||
|
||||
<input type="checkbox" onClick="toggle(this)" /> Toggle All<br/>
|
||||
<table width="100%" class="listtable">
|
||||
{{ form.as_table }}
|
||||
|
||||
@@ -500,6 +500,60 @@ def histodata(workouts, options):
|
||||
|
||||
return(script,div)
|
||||
|
||||
def cpdata(workouts, options):
|
||||
userid = options['userid']
|
||||
|
||||
|
||||
u = User.objects.get(id=userid)
|
||||
r = u.rower
|
||||
|
||||
|
||||
ids = [w.id for w in workouts]
|
||||
delta, cpvalue, avgpower = dataprep.fetchcp_new(r,workouts)
|
||||
powerdf = pd.DataFrame({
|
||||
'Delta':delta,
|
||||
'CP':cpvalue,
|
||||
})
|
||||
|
||||
|
||||
if powerdf.empty:
|
||||
return('','<p>No valid data found</p>')
|
||||
|
||||
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)
|
||||
|
||||
rowername = r.user.first_name+" "+r.user.last_name
|
||||
|
||||
if len(powerdf) !=0 :
|
||||
res = interactive_otwcpchart(powerdf,promember=True,rowername=rowername)
|
||||
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 = ""
|
||||
|
||||
scripta = script.split('\n')[2:-1]
|
||||
script = ''.join(scripta)
|
||||
|
||||
return (script,div)
|
||||
|
||||
def statsdata(workouts, options):
|
||||
includereststrokes = options['includereststrokes']
|
||||
spmmin = options['spmmin']
|
||||
@@ -726,7 +780,7 @@ def analysis_view_data(request,userid=0):
|
||||
elif function == 'compare':
|
||||
script,div = comparisondata(workouts,options)
|
||||
elif function == 'cp':
|
||||
script, div = cpdata(workouts,options)
|
||||
script, div = cpdata(workouts, options)
|
||||
else:
|
||||
script = ''
|
||||
div = 'Unknown analysis functions'
|
||||
|
||||
Reference in New Issue
Block a user