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')
|
queuehigh = django_rq.get_queue('default')
|
||||||
|
|
||||||
from rowsandall_app.settings import SITE_URL
|
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 import mytypes
|
||||||
|
|
||||||
from rowers.database import *
|
from rowers.database import *
|
||||||
@@ -1016,6 +1016,53 @@ def fetchcperg(rower,theworkouts):
|
|||||||
|
|
||||||
return cpdf
|
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'):
|
def fetchcp(rower,theworkouts,table='cpdata'):
|
||||||
# get all power data from database (plus workoutid)
|
# get all power data from database (plus workoutid)
|
||||||
@@ -1434,7 +1481,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
|||||||
|
|
||||||
isbreakthrough = False
|
isbreakthrough = False
|
||||||
ishard = False
|
ishard = False
|
||||||
if workouttype == 'water':
|
if workouttype in rowtypes:
|
||||||
df = getsmallrowdata_db(['power', 'workoutid', 'time'], ids=[w.id])
|
df = getsmallrowdata_db(['power', 'workoutid', 'time'], ids=[w.id])
|
||||||
try:
|
try:
|
||||||
powermean = df['power'].mean()
|
powermean = df['power'].mean()
|
||||||
@@ -1448,15 +1495,26 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
|||||||
logarr = datautils.getlogarr(maxt)
|
logarr = datautils.getlogarr(maxt)
|
||||||
dfgrouped = df.groupby(['workoutid'])
|
dfgrouped = df.groupby(['workoutid'])
|
||||||
delta, cpvalues, avgpower = datautils.getcp(dfgrouped, logarr)
|
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(
|
if workouttype in otwtypes:
|
||||||
delta, cpvalues, r.p0, r.p1, r.p2, r.p3, r.cpratio)
|
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:
|
else:
|
||||||
res = 0
|
res = 0
|
||||||
res2 = 0
|
res2 = 0
|
||||||
if res:
|
if res:
|
||||||
isbreakthrough = True
|
isbreakthrough = True
|
||||||
res = datautils.updatecp(delta, cpvalues, r)
|
res = datautils.updatecp(delta, cpvalues, r,workouttype=workouttype)
|
||||||
if res2 and not isbreakthrough:
|
if res2 and not isbreakthrough:
|
||||||
ishard = True
|
ishard = True
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,24 @@ import numpy as np
|
|||||||
from scipy.interpolate import griddata
|
from scipy.interpolate import griddata
|
||||||
from scipy import optimize
|
from scipy import optimize
|
||||||
|
|
||||||
|
from rowers.mytypes import otwtypes,otetypes,rowtypes
|
||||||
|
|
||||||
#p0 = [500,350,10,8000]
|
#p0 = [500,350,10,8000]
|
||||||
p0 = [190,200,33,16000]
|
p0 = [190,200,33,16000]
|
||||||
|
|
||||||
def updatecp(delta,cpvalues,r):
|
def updatecp(delta,cpvalues,r,workouttype='water'):
|
||||||
cp2 = r.p0/(1+delta/r.p2)
|
if workouttype in otwtypes:
|
||||||
cp2 += r.p1/(1+delta/r.p3)
|
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)
|
delta = delta.append(delta)
|
||||||
cp = cpvalues.append(cp2)
|
cp = cpvalues.append(cp2)
|
||||||
@@ -31,11 +43,18 @@ def updatecp(delta,cpvalues,r):
|
|||||||
res = cpfit(powerdf)
|
res = cpfit(powerdf)
|
||||||
p1 = res[0]
|
p1 = res[0]
|
||||||
|
|
||||||
r.p0 = p1[0]
|
if workouttype in otwtypes:
|
||||||
r.p1 = p1[1]
|
r.p0 = p1[0]
|
||||||
r.p2 = p1[2]
|
r.p1 = p1[1]
|
||||||
r.p3 = p1[3]
|
r.p2 = p1[2]
|
||||||
r.cpratio = res[3]
|
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()
|
r.save()
|
||||||
|
|
||||||
@@ -89,7 +108,10 @@ def cpfit(powerdf):
|
|||||||
|
|
||||||
def getlogarr(maxt):
|
def getlogarr(maxt):
|
||||||
maxlog10 = np.log10(maxt-5)
|
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 = []
|
res = []
|
||||||
for la in logarr:
|
for la in logarr:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1036,7 +1036,7 @@ analysischoices = (
|
|||||||
('flexall','Cumulative Flex Chart'),
|
('flexall','Cumulative Flex Chart'),
|
||||||
('stats','Statistics'),
|
('stats','Statistics'),
|
||||||
('compare','Compare'),
|
('compare','Compare'),
|
||||||
('cp','CP Chart')
|
('cp','CP chart'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2985,6 +2985,13 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
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)
|
@receiver(models.signals.post_delete,sender=Workout)
|
||||||
def update_duplicates_on_delete(sender, instance, **kwargs):
|
def update_duplicates_on_delete(sender, instance, **kwargs):
|
||||||
if instance.id:
|
if instance.id:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% load rowerfilters %}
|
{% load rowerfilters %}
|
||||||
|
|
||||||
{% block title %}Workouts{% endblock %}
|
{% block title %}Analysis{% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<script>
|
<script>
|
||||||
@@ -16,14 +16,14 @@
|
|||||||
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|
||||||
// Get the form fields and hidden div
|
// Get the form fields and hidden div
|
||||||
var modality = $("#id_modality");
|
var modality = $("#id_modality");
|
||||||
var hidden = $("#id_waterboattype");
|
var hidden = $("#id_waterboattype");
|
||||||
|
|
||||||
|
|
||||||
// Hide the fields.
|
// 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.
|
// enabled.
|
||||||
|
|
||||||
hidden.hide();
|
hidden.hide();
|
||||||
@@ -32,8 +32,8 @@
|
|||||||
hidden.show();
|
hidden.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Setup an event listener for when the state of the
|
// Setup an event listener for when the state of the
|
||||||
// checkbox changes.
|
// checkbox changes.
|
||||||
modality.change(function() {
|
modality.change(function() {
|
||||||
// Check to see if the checkbox is checked.
|
// Check to see if the checkbox is checked.
|
||||||
@@ -48,10 +48,10 @@
|
|||||||
// Make sure that the hidden fields are indeed
|
// Make sure that the hidden fields are indeed
|
||||||
// hidden.
|
// hidden.
|
||||||
hidden.hide();
|
hidden.hide();
|
||||||
|
|
||||||
// You may also want to clear the value of the
|
// You may also want to clear the value of the
|
||||||
// hidden fields here. Just in case somebody
|
// hidden fields here. Just in case somebody
|
||||||
// shows the fields, enters data to them and then
|
// shows the fields, enters data to them and then
|
||||||
// unticks the checkbox.
|
// unticks the checkbox.
|
||||||
//
|
//
|
||||||
// This would do the job:
|
// This would do the job:
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
<script>
|
<script>
|
||||||
// script for chart options form
|
// script for chart options form
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|
||||||
// Get the form fields and hidden div
|
// Get the form fields and hidden div
|
||||||
var functionfield = $("#id_function");
|
var functionfield = $("#id_function");
|
||||||
var plotfield = $("#id_plotfield").parent().parent();
|
var plotfield = $("#id_plotfield").parent().parent();
|
||||||
@@ -82,14 +82,16 @@
|
|||||||
var spmmax = $("#id_spmmax").parent().parent();
|
var spmmax = $("#id_spmmax").parent().parent();
|
||||||
var workmin = $("#id_workmin").parent().parent();
|
var workmin = $("#id_workmin").parent().parent();
|
||||||
var workmax = $("#id_workmax").parent().parent();
|
var workmax = $("#id_workmax").parent().parent();
|
||||||
|
|
||||||
var xaxis = $("#id_xaxis").parent().parent();
|
var xaxis = $("#id_xaxis").parent().parent();
|
||||||
var yaxis1 = $("#id_yaxis1").parent().parent();
|
var yaxis1 = $("#id_yaxis1").parent().parent();
|
||||||
var yaxis2 = $("#id_yaxis2").parent().parent();
|
var yaxis2 = $("#id_yaxis2").parent().parent();
|
||||||
var plottype = $("#id_plottype").parent().parent();
|
var plottype = $("#id_plottype").parent().parent();
|
||||||
|
|
||||||
|
var reststrokes = $("#id_includereststrokes").parent().parent();
|
||||||
|
|
||||||
// Hide the fields.
|
// 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.
|
// enabled.
|
||||||
plotfield.hide();
|
plotfield.hide();
|
||||||
x_param.hide();
|
x_param.hide();
|
||||||
@@ -102,6 +104,11 @@
|
|||||||
yaxis1.hide();
|
yaxis1.hide();
|
||||||
yaxis2.hide();
|
yaxis2.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
|
reststrokes.hide();
|
||||||
|
workmin.hide();
|
||||||
|
workmax.hide();
|
||||||
|
spmmin.hide();
|
||||||
|
spmmax.hide();
|
||||||
|
|
||||||
if (functionfield.val() == 'boxplot') {
|
if (functionfield.val() == 'boxplot') {
|
||||||
plotfield.show();
|
plotfield.show();
|
||||||
@@ -136,8 +143,8 @@
|
|||||||
plottype.show();
|
plottype.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Setup an event listener for when the state of the
|
// Setup an event listener for when the state of the
|
||||||
// checkbox changes.
|
// checkbox changes.
|
||||||
functionfield.change(function() {
|
functionfield.change(function() {
|
||||||
// Check to see if the checkbox is checked.
|
// Check to see if the checkbox is checked.
|
||||||
@@ -161,6 +168,7 @@
|
|||||||
yaxis1.hide();
|
yaxis1.hide();
|
||||||
yaxis2.hide();
|
yaxis2.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
|
reststrokes.show();
|
||||||
}
|
}
|
||||||
else if (Value=='histo') {
|
else if (Value=='histo') {
|
||||||
plotfield.show();
|
plotfield.show();
|
||||||
@@ -178,6 +186,7 @@
|
|||||||
yaxis1.hide();
|
yaxis1.hide();
|
||||||
yaxis2.hide();
|
yaxis2.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
|
reststrokes.show();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (Value=='trendflex') {
|
else if (Value=='trendflex') {
|
||||||
@@ -196,6 +205,7 @@
|
|||||||
yaxis1.hide();
|
yaxis1.hide();
|
||||||
yaxis2.hide();
|
yaxis2.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
|
reststrokes.show();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (Value=='flexall') {
|
else if (Value=='flexall') {
|
||||||
@@ -214,6 +224,7 @@
|
|||||||
binsize.hide();
|
binsize.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
errorbars.hide();
|
errorbars.hide();
|
||||||
|
reststrokes.show();
|
||||||
}
|
}
|
||||||
else if (Value=='stats') {
|
else if (Value=='stats') {
|
||||||
xaxis.hide();
|
xaxis.hide();
|
||||||
@@ -227,6 +238,7 @@
|
|||||||
binsize.hide();
|
binsize.hide();
|
||||||
errorbars.hide();
|
errorbars.hide();
|
||||||
plottype.hide();
|
plottype.hide();
|
||||||
|
reststrokes.show();
|
||||||
}
|
}
|
||||||
else if (Value=='compare') {
|
else if (Value=='compare') {
|
||||||
xaxis.show();
|
xaxis.show();
|
||||||
@@ -244,10 +256,29 @@
|
|||||||
binsize.hide();
|
binsize.hide();
|
||||||
plottype.show();
|
plottype.show();
|
||||||
errorbars.hide();
|
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>
|
</script>
|
||||||
|
|
||||||
<div id="id_css_res">
|
<div id="id_css_res">
|
||||||
@@ -285,9 +316,9 @@
|
|||||||
<input type="submit" value="GO"></input>
|
<input type="submit" value="GO"></input>
|
||||||
</form>
|
</form>
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
|
|
||||||
{% if workouts %}
|
{% if workouts %}
|
||||||
|
|
||||||
<input type="checkbox" onClick="toggle(this)" /> Toggle All<br/>
|
<input type="checkbox" onClick="toggle(this)" /> Toggle All<br/>
|
||||||
<table width="100%" class="listtable">
|
<table width="100%" class="listtable">
|
||||||
{{ form.as_table }}
|
{{ form.as_table }}
|
||||||
|
|||||||
@@ -500,6 +500,60 @@ def histodata(workouts, options):
|
|||||||
|
|
||||||
return(script,div)
|
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):
|
def statsdata(workouts, options):
|
||||||
includereststrokes = options['includereststrokes']
|
includereststrokes = options['includereststrokes']
|
||||||
spmmin = options['spmmin']
|
spmmin = options['spmmin']
|
||||||
@@ -726,7 +780,7 @@ def analysis_view_data(request,userid=0):
|
|||||||
elif function == 'compare':
|
elif function == 'compare':
|
||||||
script,div = comparisondata(workouts,options)
|
script,div = comparisondata(workouts,options)
|
||||||
elif function == 'cp':
|
elif function == 'cp':
|
||||||
script, div = cpdata(workouts,options)
|
script, div = cpdata(workouts, options)
|
||||||
else:
|
else:
|
||||||
script = ''
|
script = ''
|
||||||
div = 'Unknown analysis functions'
|
div = 'Unknown analysis functions'
|
||||||
|
|||||||
Reference in New Issue
Block a user