Private
Public Access
1
0

Merge branch 'feature/asynchronousranking' into develop

This commit is contained in:
Sander Roosendaal
2017-10-26 18:18:24 +02:00
8 changed files with 121 additions and 42 deletions
+27 -10
View File
@@ -26,7 +26,7 @@ from rowingdata import (
MysteryParser, BoatCoachOTWParser, MysteryParser, BoatCoachOTWParser,
painsledDesktopParser, speedcoachParser, ErgStickParser, painsledDesktopParser, speedcoachParser, ErgStickParser,
SpeedCoach2Parser, FITParser, fitsummarydata, SpeedCoach2Parser, FITParser, fitsummarydata,
make_cumvalues, make_cumvalues,cumcpdata,
summarydata, get_file_type, summarydata, get_file_type,
) )
@@ -41,7 +41,7 @@ import itertools
import math import math
from tasks import ( from tasks import (
handle_sendemail_unrecognized, handle_sendemail_breakthrough, handle_sendemail_unrecognized, handle_sendemail_breakthrough,
handle_sendemail_hard, handle_updatecp handle_sendemail_hard, handle_updatecp,handle_updateergcp
) )
from django.conf import settings from django.conf import settings
@@ -426,20 +426,22 @@ def paceformatsecs(values):
return out return out
def getcpdata_sql(rower_id): def getcpdata_sql(rower_id,table='cpdata'):
engine = create_engine(database_url, echo=False) engine = create_engine(database_url, echo=False)
query = sa.text('SELECT delta,cp from cpdata WHERE user={rower_id};'.format( query = sa.text('SELECT * from {table} WHERE user={rower_id};'.format(
rower_id=rower_id rower_id=rower_id,
table=table,
)) ))
connection = engine.raw_connection() connection = engine.raw_connection()
df = pd.read_sql_query(query, engine) df = pd.read_sql_query(query, engine)
return df return df
def deletecpdata_sql(rower_id): def deletecpdata_sql(rower_id,table='cpdata'):
engine = create_engine(database_url, echo=False) engine = create_engine(database_url, echo=False)
query = sa.text('DELETE from cpdata WHERE user={rower_id};'.format( query = sa.text('DELETE from {table} WHERE user={rower_id};'.format(
rower_id=rower_id rower_id=rower_id,
table=table,
)) ))
with engine.connect() as conn, conn.begin(): with engine.connect() as conn, conn.begin():
try: try:
@@ -451,7 +453,7 @@ def deletecpdata_sql(rower_id):
def updatecpdata_sql(rower_id,delta,cp): def updatecpdata_sql(rower_id,delta,cp,table='cpdata',distance=[]):
deletecpdata_sql(rower_id) deletecpdata_sql(rower_id)
df = pd.DataFrame( df = pd.DataFrame(
{ {
@@ -461,9 +463,12 @@ def updatecpdata_sql(rower_id,delta,cp):
} }
) )
if not distance.empty:
df['distance'] = distance
engine = create_engine(database_url, echo=False) engine = create_engine(database_url, echo=False)
with engine.connect() as conn, conn.begin(): with engine.connect() as conn, conn.begin():
df.to_sql('cpdata', engine, if_exists='append', index=False) df.to_sql(table, engine, if_exists='append', index=False)
conn.close() conn.close()
engine.dispose() engine.dispose()
@@ -484,6 +489,18 @@ def runcpupdate(rower):
else: else:
res = queue.enqueue(handle_updatecp,rower.id,theids) res = queue.enqueue(handle_updatecp,rower.id,theids)
def fetchcperg(rower,theworkouts):
theids = [int(w.id) for w in theworkouts]
thefilenames = [w.csvfilename for w in theworkouts]
cpdf = getcpdata_sql(rower.id,table='ergcpdata')
if settings.DEBUG:
res = handle_updateergcp.delay(rower.id,thefilenames,debug=True)
else:
res = queue.enqueue(handle_updateergcp,rower.id,thefilenames)
return cpdf
def fetchcp(rower,theworkouts): def fetchcp(rower,theworkouts):
# get all power data from database (plus workoutid) # get all power data from database (plus workoutid)
+27 -6
View File
@@ -548,14 +548,30 @@ def read_df_sql(id,debug=False):
engine.dispose() engine.dispose()
return df return df
def deletecpdata_sql(rower_id,debug=False): def getcpdata_sql(rower_id,table='cpdata',debug=False):
if debug: if debug:
engine = create_engine(database_url_debug, echo=False) engine = create_engine(database_url_debug, echo=False)
else: else:
engine = create_engine(database_url, echo=False) engine = create_engine(database_url, echo=False)
query = sa.text('DELETE from cpdata WHERE user={rower_id};'.format( query = sa.text('SELECT * from {table} WHERE user={rower_id};'.format(
rower_id=rower_id rower_id=rower_id,
table=table,
))
connection = engine.raw_connection()
df = pd.read_sql_query(query, engine)
return df
def deletecpdata_sql(rower_id,table='cpdata',debug=False):
if debug:
engine = create_engine(database_url_debug, echo=False)
else:
engine = create_engine(database_url, echo=False)
query = sa.text('DELETE from {table} WHERE user={rower_id};'.format(
rower_id=rower_id,
table=table,
)) ))
with engine.connect() as conn, conn.begin(): with engine.connect() as conn, conn.begin():
try: try:
@@ -567,8 +583,8 @@ def deletecpdata_sql(rower_id,debug=False):
def updatecpdata_sql(rower_id,delta,cp,debug=False): def updatecpdata_sql(rower_id,delta,cp,table='cpdata',distance=pd.Series([]),debug=False):
deletecpdata_sql(rower_id,debug=debug) deletecpdata_sql(rower_id,table=table,debug=debug)
df = pd.DataFrame( df = pd.DataFrame(
{ {
'delta':delta, 'delta':delta,
@@ -577,19 +593,24 @@ def updatecpdata_sql(rower_id,delta,cp,debug=False):
} }
) )
if not distance.empty:
df['distance'] = distance
if debug: if debug:
engine = create_engine(database_url_debug, echo=False) engine = create_engine(database_url_debug, echo=False)
else: else:
engine = create_engine(database_url, echo=False) engine = create_engine(database_url, echo=False)
with engine.connect() as conn, conn.begin(): with engine.connect() as conn, conn.begin():
df.to_sql('cpdata', engine, if_exists='append', index=False) df.to_sql(table, engine, if_exists='append', index=False)
conn.close() conn.close()
engine.dispose() engine.dispose()
def smalldataprep(therows,xparam,yparam1,yparam2): def smalldataprep(therows,xparam,yparam1,yparam2):
df = pd.DataFrame() df = pd.DataFrame()
if yparam2 == 'None': if yparam2 == 'None':
+7 -2
View File
@@ -152,6 +152,11 @@ class WorkFlowMiddlePanelElement(forms.Form):
# The form to indicate additional actions to be performed immediately # The form to indicate additional actions to be performed immediately
# after a successful upload # after a successful upload
nextpages = list(landingpages)
nextpages.append(('workout_upload_view','Upload Another File'))
nextpages = tuple(nextpages)
class UploadOptionsForm(forms.Form): class UploadOptionsForm(forms.Form):
plotchoices = ( plotchoices = (
('timeplot','Time Plot'), ('timeplot','Time Plot'),
@@ -181,9 +186,9 @@ class UploadOptionsForm(forms.Form):
makeprivate = forms.BooleanField(initial=False,required=False, makeprivate = forms.BooleanField(initial=False,required=False,
label='Make Workout Private') label='Make Workout Private')
landingpage = forms.ChoiceField(choices=landingpages, landingpage = forms.ChoiceField(choices=nextpages,
initial='workout_edit_view', initial='workout_edit_view',
label='Landing Page') label='After Upload, go to')
class Meta: class Meta:
fields = ['make_plot','plottype','upload_toc2','makeprivate'] fields = ['make_plot','plottype','upload_toc2','makeprivate']
+14 -14
View File
@@ -41,6 +41,7 @@ import pandas as pd
from pytz import timezone as tz,utc from pytz import timezone as tz,utc
from django.utils.timezone import get_current_timezone from django.utils.timezone import get_current_timezone
from django.utils.timezone import activate from django.utils.timezone import activate
from django.utils import timezone
activate(settings.TIME_ZONE) activate(settings.TIME_ZONE)
thetimezone = get_current_timezone() thetimezone = get_current_timezone()
@@ -1065,10 +1066,9 @@ def interactive_otwcpchart(powerdf,promember=0):
return [script,div,p1,ratio,message] return [script,div,p1,ratio,message]
def interactive_cpchart(thedistances,thesecs,theavpower, def interactive_cpchart(rower,thedistances,thesecs,theavpower,
theworkouts,promember=0): theworkouts,promember=0):
message = 0 message = 0
# plot tools # plot tools
if (promember==1): if (promember==1):
@@ -1108,6 +1108,7 @@ def interactive_cpchart(thedistances,thesecs,theavpower,
paulslope = 5.0/np.log10(2.0) paulslope = 5.0/np.log10(2.0)
paulintercept = p[0]-paulslope*np.log10(thedistances[0]) paulintercept = p[0]-paulslope*np.log10(thedistances[0])
fitx = pd.Series(np.arange(100)*2*max(np.log10(thedistances))/100.) fitx = pd.Series(np.arange(100)*2*max(np.log10(thedistances))/100.)
fitp = paulslope*fitx+paulintercept fitp = paulslope*fitx+paulintercept
@@ -1198,16 +1199,14 @@ def interactive_cpchart(thedistances,thesecs,theavpower,
plot.xaxis.axis_label = "Duration (seconds)" plot.xaxis.axis_label = "Duration (seconds)"
plot.yaxis.axis_label = "Power (W)" plot.yaxis.axis_label = "Power (W)"
therows = []
for workout in theworkouts:
f1 = workout.csvfilename
rowdata = rdata(f1)
if rowdata != 0:
therows.append(rowdata)
cpdata = cumcpdata(therows) cpdata = dataprep.fetchcperg(rower, theworkouts)
velo = cpdata['Distance']/cpdata['Delta'] if cpdata.empty:
message = 'Calculations are running in the background. Please refresh this page to see updated results'
return ['','',paulslope,paulintercept,p1,message]
velo = cpdata['distance']/cpdata['delta']
p = 500./velo p = 500./velo
@@ -1215,12 +1214,12 @@ def interactive_cpchart(thedistances,thesecs,theavpower,
source2 = ColumnDataSource( source2 = ColumnDataSource(
data = dict( data = dict(
duration = cpdata['Delta'], duration = cpdata['delta'],
power = cpdata['CP'], power = cpdata['cp'],
tim = niceformat( tim = niceformat(
cpdata['Delta'].fillna(method='ffill').apply(lambda x: timedeltaconv(x)) cpdata['delta'].fillna(method='ffill').apply(lambda x: timedeltaconv(x))
), ),
dist = cpdata['Distance'], dist = cpdata['distance'],
pace = nicepaceformat(p2), pace = nicepaceformat(p2),
) )
) )
@@ -1252,6 +1251,7 @@ def interactive_cpchart(thedistances,thesecs,theavpower,
script, div = components(plot) script, div = components(plot)
return [script,div,paulslope,paulintercept,p1,message] return [script,div,paulslope,paulintercept,p1,message]
def interactive_windchart(id=0,promember=0): def interactive_windchart(id=0,promember=0):
+12
View File
@@ -653,6 +653,18 @@ class cpdata(models.Model):
index_together = ['user'] index_together = ['user']
app_label = 'rowers' app_label = 'rowers'
# Storing data for the OTW CP chart
class ergcpdata(models.Model):
delta = models.IntegerField(default=0)
cp = models.FloatField(default=0)
distance = models.FloatField(default=0)
user = models.IntegerField(default=0)
class Meta:
db_table = 'ergcpdata'
index_together = ['user']
app_label = 'rowers'
# A wrapper around the png files # A wrapper around the png files
class GraphImage(models.Model): class GraphImage(models.Model):
filename = models.CharField(default='',max_length=150,blank=True,null=True) filename = models.CharField(default='',max_length=150,blank=True,null=True)
+18 -1
View File
@@ -400,7 +400,24 @@ def handle_otwsetpower(f1, boattype, weightvalue,
return 1 return 1
# This function generates all the static (PNG image) plots
@app.task
def handle_updateergcp(rower_id,workoutfilenames,debug=False):
therows = []
for f1 in workoutfilenames:
rowdata = rdata(f1)
if rowdata != 0:
therows.append(rowdata)
cpdata = rowingdata.cumcpdata(therows)
cpdata.columns = cpdata.columns.str.lower()
updatecpdata_sql(rower_id,cpdata['delta'],cpdata['cp'],
table='ergcpdata',distance=cpdata['distance'],
debug=debug)
return 1
@app.task @app.task
def handle_updatecp(rower_id,workoutids,debug=False): def handle_updatecp(rower_id,workoutids,debug=False):
+1 -1
View File
@@ -177,7 +177,7 @@ urlpatterns = [
url(r'^graph/(?P<id>\d+)/deleteconfirm$',views.graph_delete_confirm_view), url(r'^graph/(?P<id>\d+)/deleteconfirm$',views.graph_delete_confirm_view),
url(r'^graph/(?P<id>\d+)/delete$',views.graph_delete_view), url(r'^graph/(?P<id>\d+)/delete$',views.graph_delete_view),
url(r'^workout/upload/team/$',views.team_workout_upload_view), url(r'^workout/upload/team/$',views.team_workout_upload_view),
url(r'^workout/upload/$',views.workout_upload_view), url(r'^workout/upload/$',views.workout_upload_view,name='workout_upload_view'),
url(r'^workout/(?P<id>\d+)/histo$',views.workout_histo_view), url(r'^workout/(?P<id>\d+)/histo$',views.workout_histo_view),
url(r'^workout/(?P<id>\d+)/task$',views.workout_test_task_view), url(r'^workout/(?P<id>\d+)/task$',views.workout_test_task_view),
url(r'^workout/(?P<id>\d+)/forcecurve$',views.workout_forcecurve_view), url(r'^workout/(?P<id>\d+)/forcecurve$',views.workout_forcecurve_view),
+13 -6
View File
@@ -2733,6 +2733,7 @@ def rankings_view(request,theuser=0,
rankingdurations.append(datetime.time(minute=1)) rankingdurations.append(datetime.time(minute=1))
rankingdurations.append(datetime.time(minute=4)) rankingdurations.append(datetime.time(minute=4))
rankingdurations.append(datetime.time(minute=30)) rankingdurations.append(datetime.time(minute=30))
rankingdurations.append(datetime.time(hour=1,minute=15))
rankingdurations.append(datetime.time(hour=1)) rankingdurations.append(datetime.time(hour=1))
thedistances = [] thedistances = []
@@ -2787,8 +2788,10 @@ def rankings_view(request,theuser=0,
# create interactive plot # create interactive plot
if len(thedistances) !=0 : if len(thedistances) !=0 :
res = interactive_cpchart(thedistances,thesecs,theavpower, res = interactive_cpchart(
theworkouts,promember=promember) r,thedistances,thesecs,theavpower,
theworkouts,promember=promember
)
script = res[0] script = res[0]
div = res[1] div = res[1]
paulslope = res[2] paulslope = res[2]
@@ -7803,10 +7806,14 @@ def workout_upload_view(request,
else: else:
messages.error(request,message) messages.error(request,message)
url = reverse(landingpage, if landingpage != 'workout_upload_view':
kwargs = { url = reverse(landingpage,
'id':w.id, kwargs = {
}) 'id':w.id,
})
else:
url = reverse(landingpage)
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
else: else:
response = render(request, response = render(request,