Merge branch 'release/v4.6'
This commit is contained in:
+104
-7
@@ -17,6 +17,7 @@ from django.utils import timezone
|
|||||||
from time import strftime, strptime, mktime, time, daylight
|
from time import strftime, strptime, mktime, time, daylight
|
||||||
import arrow
|
import arrow
|
||||||
from django.utils.timezone import get_current_timezone
|
from django.utils.timezone import get_current_timezone
|
||||||
|
|
||||||
thetimezone = get_current_timezone()
|
thetimezone = get_current_timezone()
|
||||||
from rowingdata import (
|
from rowingdata import (
|
||||||
TCXParser, RowProParser, ErgDataParser,
|
TCXParser, RowProParser, ErgDataParser,
|
||||||
@@ -25,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,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -40,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_sendemail_hard, handle_updatecp,handle_updateergcp
|
||||||
)
|
)
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -425,6 +426,106 @@ def paceformatsecs(values):
|
|||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
def getcpdata_sql(rower_id,table='cpdata'):
|
||||||
|
engine = create_engine(database_url, echo=False)
|
||||||
|
query = sa.text('SELECT * from {table} WHERE user={rower_id};'.format(
|
||||||
|
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'):
|
||||||
|
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():
|
||||||
|
try:
|
||||||
|
result = conn.execute(query)
|
||||||
|
except:
|
||||||
|
print "Database locked"
|
||||||
|
conn.close()
|
||||||
|
engine.dispose()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def updatecpdata_sql(rower_id,delta,cp,table='cpdata',distance=[]):
|
||||||
|
deletecpdata_sql(rower_id)
|
||||||
|
df = pd.DataFrame(
|
||||||
|
{
|
||||||
|
'delta':delta,
|
||||||
|
'cp':cp,
|
||||||
|
'user':rower_id
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not distance.empty:
|
||||||
|
df['distance'] = distance
|
||||||
|
|
||||||
|
engine = create_engine(database_url, echo=False)
|
||||||
|
with engine.connect() as conn, conn.begin():
|
||||||
|
df.to_sql(table, engine, if_exists='append', index=False)
|
||||||
|
conn.close()
|
||||||
|
engine.dispose()
|
||||||
|
|
||||||
|
|
||||||
|
def runcpupdate(rower):
|
||||||
|
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)
|
||||||
|
|
||||||
|
theids = [w.id for w in theworkouts]
|
||||||
|
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
res = handle_updatecp.delay(rower.id,theids,debug=True)
|
||||||
|
else:
|
||||||
|
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):
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
dfgrouped = df.groupby(['workoutid'])
|
||||||
|
avgpower2 = dict(dfgrouped.mean()['power'].astype(int))
|
||||||
|
|
||||||
|
cpdf = getcpdata_sql(rower.id)
|
||||||
|
|
||||||
|
if not cpdf.empty:
|
||||||
|
return cpdf['delta'],cpdf['cp'],avgpower2
|
||||||
|
else:
|
||||||
|
if settings.DEBUG:
|
||||||
|
res = handle_updatecp.delay(rower.id,theids,debug=True)
|
||||||
|
else:
|
||||||
|
res = queue.enqueue(handle_updatecp,rower.id,theids)
|
||||||
|
return [],[],avgpower2
|
||||||
|
|
||||||
|
|
||||||
|
return [],[],avgpower2
|
||||||
|
|
||||||
|
|
||||||
# Processes painsled CSV file to database
|
# Processes painsled CSV file to database
|
||||||
|
|
||||||
|
|
||||||
@@ -567,11 +668,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
|||||||
|
|
||||||
if dosummary:
|
if dosummary:
|
||||||
summary = row.allstats()
|
summary = row.allstats()
|
||||||
#summary = row.summary()
|
|
||||||
#summary += '\n'
|
|
||||||
#summary += row.intervalstats()
|
|
||||||
|
|
||||||
#workoutstartdatetime = row.rowdatetime
|
|
||||||
timezone_str = 'UTC'
|
timezone_str = 'UTC'
|
||||||
try:
|
try:
|
||||||
workoutstartdatetime = timezone.make_aware(row.rowdatetime)
|
workoutstartdatetime = timezone.make_aware(row.rowdatetime)
|
||||||
@@ -649,7 +746,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
|||||||
ishard = False
|
ishard = False
|
||||||
if workouttype == 'water':
|
if workouttype == 'water':
|
||||||
df = getsmallrowdata_db(['power', 'workoutid', 'time'], ids=[w.id])
|
df = getsmallrowdata_db(['power', 'workoutid', 'time'], ids=[w.id])
|
||||||
# delta,cpvalues,avgpower = datautils.getsinglecp(row.df)
|
if df['power'].mean():
|
||||||
thesecs = totaltime
|
thesecs = totaltime
|
||||||
maxt = 1.05 * thesecs
|
maxt = 1.05 * thesecs
|
||||||
if maxt > 0:
|
if maxt > 0:
|
||||||
|
|||||||
@@ -489,9 +489,9 @@ def testdata(time,distance,pace,spm):
|
|||||||
return t1 and t2 and t3 and t4
|
return t1 and t2 and t3 and t4
|
||||||
|
|
||||||
|
|
||||||
def getsmallrowdata_db(columns,ids=[]):
|
def getsmallrowdata_db(columns,ids=[],debug=False):
|
||||||
|
|
||||||
data = read_cols_df_sql(ids,columns)
|
data = read_cols_df_sql(ids,columns,debug=debug)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@@ -548,6 +548,65 @@ def read_df_sql(id,debug=False):
|
|||||||
engine.dispose()
|
engine.dispose()
|
||||||
return df
|
return df
|
||||||
|
|
||||||
|
def getcpdata_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('SELECT * from {table} WHERE user={rower_id};'.format(
|
||||||
|
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():
|
||||||
|
try:
|
||||||
|
result = conn.execute(query)
|
||||||
|
except:
|
||||||
|
print "Database locked"
|
||||||
|
conn.close()
|
||||||
|
engine.dispose()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def updatecpdata_sql(rower_id,delta,cp,table='cpdata',distance=pd.Series([]),debug=False):
|
||||||
|
deletecpdata_sql(rower_id,table=table,debug=debug)
|
||||||
|
df = pd.DataFrame(
|
||||||
|
{
|
||||||
|
'delta':delta,
|
||||||
|
'cp':cp,
|
||||||
|
'user':rower_id
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not distance.empty:
|
||||||
|
df['distance'] = distance
|
||||||
|
|
||||||
|
if debug:
|
||||||
|
engine = create_engine(database_url_debug, echo=False)
|
||||||
|
else:
|
||||||
|
engine = create_engine(database_url, echo=False)
|
||||||
|
|
||||||
|
with engine.connect() as conn, conn.begin():
|
||||||
|
df.to_sql(table, engine, if_exists='append', index=False)
|
||||||
|
conn.close()
|
||||||
|
engine.dispose()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ def getsinglecp(df):
|
|||||||
|
|
||||||
return delta,cpvalue,avgpower
|
return delta,cpvalue,avgpower
|
||||||
|
|
||||||
|
|
||||||
def getcp(dfgrouped,logarr):
|
def getcp(dfgrouped,logarr):
|
||||||
delta = []
|
delta = []
|
||||||
cpvalue = []
|
cpvalue = []
|
||||||
@@ -206,3 +207,4 @@ def getmaxwattinterval(tt,ww,i):
|
|||||||
deltat = 0
|
deltat = 0
|
||||||
|
|
||||||
return deltat,wmax
|
return deltat,wmax
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -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
@@ -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):
|
||||||
|
|||||||
+1
-1
@@ -294,7 +294,7 @@ dropping to 8m for race pace in the single.""",
|
|||||||
'yparam1':'driveenergy',
|
'yparam1':'driveenergy',
|
||||||
'yparam2':'None',
|
'yparam2':'None',
|
||||||
'xparam':'spm',
|
'xparam':'spm',
|
||||||
'plottype':'line',
|
'plottype':'scatter',
|
||||||
'workouttype':'ote',
|
'workouttype':'ote',
|
||||||
'reststrokes':True,
|
'reststrokes':True,
|
||||||
'notes':"""This chart shows the Work per Stroke versus Stroke Rate.
|
'notes':"""This chart shows the Work per Stroke versus Stroke Rate.
|
||||||
|
|||||||
@@ -642,6 +642,29 @@ StrokeData = type(str('StrokeData'), (models.Model,),
|
|||||||
attrs
|
attrs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Storing data for the OTW CP chart
|
||||||
|
class cpdata(models.Model):
|
||||||
|
delta = models.IntegerField(default=0)
|
||||||
|
cp = models.FloatField(default=0)
|
||||||
|
user = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'cpdata'
|
||||||
|
index_together = ['user']
|
||||||
|
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)
|
||||||
|
|||||||
+38
-2
@@ -26,7 +26,7 @@ from utils import deserialize_list
|
|||||||
|
|
||||||
from rowers.dataprepnodjango import (
|
from rowers.dataprepnodjango import (
|
||||||
update_strokedata, new_workout_from_file,
|
update_strokedata, new_workout_from_file,
|
||||||
getsmallrowdata_db,
|
getsmallrowdata_db, updatecpdata_sql
|
||||||
)
|
)
|
||||||
|
|
||||||
from django.core.mail import send_mail, EmailMessage
|
from django.core.mail import send_mail, EmailMessage
|
||||||
@@ -400,8 +400,44 @@ 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
|
||||||
|
def handle_updatecp(rower_id,workoutids,debug=False):
|
||||||
|
columns = ['power','workoutid','time']
|
||||||
|
df = getsmallrowdata_db(columns,ids=workoutids,debug=debug)
|
||||||
|
dfgrouped = df.groupby(['workoutid'])
|
||||||
|
|
||||||
|
if not df.empty:
|
||||||
|
maxt = 1.05*df['time'].max()/1000.
|
||||||
|
else:
|
||||||
|
maxt = 1000.
|
||||||
|
|
||||||
|
logarr = datautils.getlogarr(maxt)
|
||||||
|
|
||||||
|
|
||||||
|
delta,cpvalue,avgpower = datautils.getcp(dfgrouped,logarr)
|
||||||
|
|
||||||
|
updatecpdata_sql(rower_id,delta,cpvalue,debug=debug)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
@app.task
|
@app.task
|
||||||
def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename):
|
def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename):
|
||||||
|
|||||||
@@ -190,6 +190,11 @@
|
|||||||
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart?favoritechart=0">></a>
|
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart?favoritechart=0">></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if favoritechartnotes %}
|
||||||
|
<div class="grid_6 prefix_6 alpha">
|
||||||
|
<p>Chart {{ favoritenr|add:1 }}:{{ favoritechartnotes }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -8,7 +8,9 @@
|
|||||||
<a href="/rowers/workout/{{ workout.id }}/flexchart?favoritechart={{ forloop.counter |add:"-1" }}">
|
<a href="/rowers/workout/{{ workout.id }}/flexchart?favoritechart={{ forloop.counter |add:"-1" }}">
|
||||||
{{ chart.div | safe }}
|
{{ chart.div | safe }}
|
||||||
</a>
|
</a>
|
||||||
|
{% if rower.showfavoritechartnotes %}
|
||||||
<span class="tooltiptext">{{ chart.notes }}</span>
|
<span class="tooltiptext">{{ chart.notes }}</span>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
+1
-1
@@ -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),
|
||||||
|
|||||||
+44
-60
@@ -98,7 +98,8 @@ from rowers.rows import handle_uploaded_file
|
|||||||
from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv
|
from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv
|
||||||
from rowers.tasks import (
|
from rowers.tasks import (
|
||||||
handle_sendemail_unrecognized,handle_sendemailnewcomment,
|
handle_sendemail_unrecognized,handle_sendemailnewcomment,
|
||||||
handle_sendemailnewresponse, handle_updatedps
|
handle_sendemailnewresponse, handle_updatedps,
|
||||||
|
handle_updatecp
|
||||||
)
|
)
|
||||||
|
|
||||||
from scipy.signal import savgol_filter
|
from scipy.signal import savgol_filter
|
||||||
@@ -576,32 +577,6 @@ def add_workout_from_strokedata(user,importid,data,strokedata,
|
|||||||
|
|
||||||
timestr = strftime("%Y%m%d-%H%M%S")
|
timestr = strftime("%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
# # auto smoothing
|
|
||||||
# pace = df[' Stroke500mPace (sec/500m)'].values
|
|
||||||
# velo = 500./pace
|
|
||||||
|
|
||||||
# f = df['TimeStamp (sec)'].diff().mean()
|
|
||||||
# windowsize = 2*(int(10./(f)))+1
|
|
||||||
# if windowsize <= 3:
|
|
||||||
# windowsize = 5
|
|
||||||
|
|
||||||
# df['originalvelo'] = velo
|
|
||||||
|
|
||||||
# if windowsize > 3 and windowsize < len(velo):
|
|
||||||
# velo2 = savgol_filter(velo,windowsize,3)
|
|
||||||
# else:
|
|
||||||
# velo2=velo
|
|
||||||
|
|
||||||
# velo3 = pd.Series(velo2)
|
|
||||||
# velo3 = velo3.replace([-np.inf,np.inf],np.nan)
|
|
||||||
# velo3 = velo3.fillna(method='ffill')
|
|
||||||
|
|
||||||
# pace2 = 500./abs(velo3)
|
|
||||||
# df[' Stroke500mPace (sec/500m)'] = pace2
|
|
||||||
|
|
||||||
# df = df.fillna(0)
|
|
||||||
|
|
||||||
# end autosmoothing
|
|
||||||
|
|
||||||
# Create CSV file name and save data to CSV file
|
# Create CSV file name and save data to CSV file
|
||||||
csvfilename ='media/Import_'+str(importid)+'.csv'
|
csvfilename ='media/Import_'+str(importid)+'.csv'
|
||||||
@@ -622,12 +597,15 @@ def add_workout_from_strokedata(user,importid,data,strokedata,
|
|||||||
totaldist = 0
|
totaldist = 0
|
||||||
totaltime = 0
|
totaltime = 0
|
||||||
|
|
||||||
id,message = dataprep.save_workout_database(csvfilename,r,
|
id,message = dataprep.save_workout_database(
|
||||||
|
csvfilename,r,
|
||||||
workouttype=workouttype,
|
workouttype=workouttype,
|
||||||
title=title,notes=comments,
|
title=title,notes=comments,
|
||||||
totaldist=totaldist,
|
totaldist=totaldist,
|
||||||
totaltime=totaltime,
|
totaltime=totaltime,
|
||||||
workoutsource=workoutsource)
|
workoutsource=workoutsource,
|
||||||
|
dosummary=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -2755,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 = []
|
||||||
@@ -2809,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]
|
||||||
@@ -2977,6 +2958,10 @@ def workout_update_cp_view(request,id=0):
|
|||||||
row.rankingpiece = True
|
row.rankingpiece = True
|
||||||
row.save()
|
row.save()
|
||||||
|
|
||||||
|
r = getrower(request.user)
|
||||||
|
|
||||||
|
dataprep.runcpupdate(r)
|
||||||
|
|
||||||
url = reverse(otwrankings_view)
|
url = reverse(otwrankings_view)
|
||||||
|
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
@@ -3078,6 +3063,7 @@ def otwrankings_view(request,theuser=0,
|
|||||||
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))
|
rankingdurations.append(datetime.time(hour=1))
|
||||||
|
rankingdurations.append(datetime.time(hour=1,minute=15))
|
||||||
|
|
||||||
thedistances = []
|
thedistances = []
|
||||||
theworkouts = []
|
theworkouts = []
|
||||||
@@ -3089,39 +3075,15 @@ def otwrankings_view(request,theuser=0,
|
|||||||
startdatetime__lte=enddate)
|
startdatetime__lte=enddate)
|
||||||
|
|
||||||
|
|
||||||
# get all power data from database (plus workoutid)
|
delta,cpvalue,avgpower = dataprep.fetchcp(r,theworkouts)
|
||||||
theids = [int(w.id) for w in theworkouts]
|
|
||||||
columns = ['power','workoutid','time']
|
|
||||||
df = dataprep.getsmallrowdata_db(columns,ids=theids)
|
|
||||||
|
|
||||||
thesecs = []
|
|
||||||
|
|
||||||
for w in theworkouts:
|
|
||||||
timesecs = 3600*w.duration.hour
|
|
||||||
timesecs += 60*w.duration.minute
|
|
||||||
timesecs += w.duration.second
|
|
||||||
timesecs += 1.e-5*w.duration.microsecond
|
|
||||||
|
|
||||||
thesecs.append(timesecs)
|
|
||||||
|
|
||||||
|
|
||||||
if len(thesecs) != 0:
|
|
||||||
maxt = 1.05*pd.Series(thesecs).max()
|
|
||||||
else:
|
|
||||||
maxt = 1000.
|
|
||||||
|
|
||||||
|
|
||||||
logarr = datautils.getlogarr(maxt)
|
|
||||||
|
|
||||||
dfgrouped = df.groupby(['workoutid'])
|
|
||||||
delta,cpvalue,avgpower = datautils.getcp(dfgrouped,logarr)
|
|
||||||
|
|
||||||
powerdf = pd.DataFrame({
|
powerdf = pd.DataFrame({
|
||||||
'Delta':delta,
|
'Delta':delta,
|
||||||
'CP':cpvalue,
|
'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 = powerdf[powerdf['CP']>0]
|
||||||
powerdf.dropna(axis=0,inplace=True)
|
powerdf.dropna(axis=0,inplace=True)
|
||||||
@@ -6079,6 +6041,7 @@ def workout_workflow_view(request,id):
|
|||||||
'mapscript':mapscript,
|
'mapscript':mapscript,
|
||||||
'mapdiv':mapdiv,
|
'mapdiv':mapdiv,
|
||||||
'statcharts':statcharts,
|
'statcharts':statcharts,
|
||||||
|
'rower':r,
|
||||||
})
|
})
|
||||||
|
|
||||||
# The famous flex chart
|
# The famous flex chart
|
||||||
@@ -6097,7 +6060,7 @@ def workout_flexchart3_view(request,*args,**kwargs):
|
|||||||
try:
|
try:
|
||||||
favoritenr = int(request.GET['favoritechart'])
|
favoritenr = int(request.GET['favoritechart'])
|
||||||
except:
|
except:
|
||||||
favoritenr = 0
|
favoritenr = -1
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -6133,7 +6096,7 @@ def workout_flexchart3_view(request,*args,**kwargs):
|
|||||||
try:
|
try:
|
||||||
t = favorites[favoritenr].xparam
|
t = favorites[favoritenr].xparam
|
||||||
except IndexError:
|
except IndexError:
|
||||||
favoritenr=0
|
favoritenr=-1
|
||||||
|
|
||||||
if 'xparam' in kwargs:
|
if 'xparam' in kwargs:
|
||||||
xparam = kwargs['xparam']
|
xparam = kwargs['xparam']
|
||||||
@@ -6163,6 +6126,13 @@ def workout_flexchart3_view(request,*args,**kwargs):
|
|||||||
else:
|
else:
|
||||||
yparam2 = 'hr'
|
yparam2 = 'hr'
|
||||||
|
|
||||||
|
print favoritenr
|
||||||
|
if favoritenr>=0 and r.showfavoritechartnotes:
|
||||||
|
favoritechartnotes = favorites[favoritenr].notes
|
||||||
|
else:
|
||||||
|
favoritechartnotes = ''
|
||||||
|
favoritenr = 0
|
||||||
|
|
||||||
if 'plottype' in kwargs:
|
if 'plottype' in kwargs:
|
||||||
plottype = kwargs['plottype']
|
plottype = kwargs['plottype']
|
||||||
else:
|
else:
|
||||||
@@ -6247,6 +6217,7 @@ def workout_flexchart3_view(request,*args,**kwargs):
|
|||||||
'yparam1':yparam1,
|
'yparam1':yparam1,
|
||||||
'yparam2':yparam2,
|
'yparam2':yparam2,
|
||||||
'plottype':plottype,
|
'plottype':plottype,
|
||||||
|
'favoritechartnotes':favoritechartnotes,
|
||||||
'mayedit':mayedit,
|
'mayedit':mayedit,
|
||||||
'promember':promember,
|
'promember':promember,
|
||||||
'axchoicesbasic':axchoicesbasic,
|
'axchoicesbasic':axchoicesbasic,
|
||||||
@@ -6275,6 +6246,7 @@ def workout_flexchart3_view(request,*args,**kwargs):
|
|||||||
'plottype':plottype,
|
'plottype':plottype,
|
||||||
'axchoicesbasic':axchoicesbasic,
|
'axchoicesbasic':axchoicesbasic,
|
||||||
'axchoicespro':axchoicespro,
|
'axchoicespro':axchoicespro,
|
||||||
|
'favoritechartnotes':favoritechartnotes,
|
||||||
'noylist':noylist,
|
'noylist':noylist,
|
||||||
'mayedit':mayedit,
|
'mayedit':mayedit,
|
||||||
'promember':promember,
|
'promember':promember,
|
||||||
@@ -6655,6 +6627,10 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
|||||||
r.write_csv(row.csvfilename,gzip=True)
|
r.write_csv(row.csvfilename,gzip=True)
|
||||||
dataprep.update_strokedata(id,r.df)
|
dataprep.update_strokedata(id,r.df)
|
||||||
successmessage = "Changes saved"
|
successmessage = "Changes saved"
|
||||||
|
|
||||||
|
if rankingpiece:
|
||||||
|
dataprep.runcpupdate(row.user)
|
||||||
|
|
||||||
messages.info(request,successmessage)
|
messages.info(request,successmessage)
|
||||||
url = reverse(workout_edit_view,
|
url = reverse(workout_edit_view,
|
||||||
kwargs = {
|
kwargs = {
|
||||||
@@ -7834,10 +7810,14 @@ def workout_upload_view(request,
|
|||||||
else:
|
else:
|
||||||
messages.error(request,message)
|
messages.error(request,message)
|
||||||
|
|
||||||
|
if landingpage != 'workout_upload_view':
|
||||||
url = reverse(landingpage,
|
url = reverse(landingpage,
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'id':w.id,
|
'id':w.id,
|
||||||
})
|
})
|
||||||
|
else:
|
||||||
|
url = reverse(landingpage)
|
||||||
|
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
else:
|
else:
|
||||||
response = render(request,
|
response = render(request,
|
||||||
@@ -8561,11 +8541,13 @@ def rower_favoritecharts_view(request):
|
|||||||
plottype = favorites_form.cleaned_data.get('plottype')
|
plottype = favorites_form.cleaned_data.get('plottype')
|
||||||
workouttype = favorites_form.cleaned_data.get('workouttype')
|
workouttype = favorites_form.cleaned_data.get('workouttype')
|
||||||
reststrokes = favorites_form.cleaned_data.get('reststrokes')
|
reststrokes = favorites_form.cleaned_data.get('reststrokes')
|
||||||
|
notes = favorites_form.cleaned_data.get('notes')
|
||||||
new_instances.append(FavoriteChart(user=r,
|
new_instances.append(FavoriteChart(user=r,
|
||||||
yparam1=yparam1,
|
yparam1=yparam1,
|
||||||
yparam2=yparam2,
|
yparam2=yparam2,
|
||||||
xparam=xparam,
|
xparam=xparam,
|
||||||
plottype=plottype,
|
plottype=plottype,
|
||||||
|
notes=notes,
|
||||||
workouttype=workouttype,
|
workouttype=workouttype,
|
||||||
reststrokes=reststrokes))
|
reststrokes=reststrokes))
|
||||||
try:
|
try:
|
||||||
@@ -8802,6 +8784,7 @@ def rower_edit_view(request,message=""):
|
|||||||
email = ucd['email']
|
email = ucd['email']
|
||||||
defaultlandingpage = cd['defaultlandingpage']
|
defaultlandingpage = cd['defaultlandingpage']
|
||||||
weightcategory = cd['weightcategory']
|
weightcategory = cd['weightcategory']
|
||||||
|
showfavoritechartnotes = cd['showfavoritechartnotes']
|
||||||
getemailnotifications = cd['getemailnotifications']
|
getemailnotifications = cd['getemailnotifications']
|
||||||
defaulttimezone=cd['defaulttimezone']
|
defaulttimezone=cd['defaulttimezone']
|
||||||
u = request.user
|
u = request.user
|
||||||
@@ -8818,6 +8801,7 @@ def rower_edit_view(request,message=""):
|
|||||||
r.weightcategory = weightcategory
|
r.weightcategory = weightcategory
|
||||||
r.getemailnotifications = getemailnotifications
|
r.getemailnotifications = getemailnotifications
|
||||||
r.defaultlandingpage = defaultlandingpage
|
r.defaultlandingpage = defaultlandingpage
|
||||||
|
r.showfavoritechartnotes = showfavoritechartnotes
|
||||||
r.save()
|
r.save()
|
||||||
form = RowerForm(instance=r)
|
form = RowerForm(instance=r)
|
||||||
powerform = RowerPowerForm(instance=r)
|
powerform = RowerPowerForm(instance=r)
|
||||||
|
|||||||
Reference in New Issue
Block a user