Merge branch 'release/dataprep'
This commit is contained in:
+1235
-1235
File diff suppressed because it is too large
Load Diff
+1082
-1082
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,189 @@
|
||||
from rowers.models import Workout, User, Rower
|
||||
from rowingdata import rowingdata as rrdata
|
||||
|
||||
from rowingdata import rower as rrower
|
||||
from rowingdata import main as rmain
|
||||
|
||||
from pandas import DataFrame,Series
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
from scipy.signal import savgol_filter
|
||||
|
||||
import datetime
|
||||
|
||||
def niceformat(values):
|
||||
out = []
|
||||
for v in values:
|
||||
formattedv = strfdelta(v)
|
||||
out.append(formattedv)
|
||||
|
||||
return out
|
||||
|
||||
def strfdelta(tdelta):
|
||||
try:
|
||||
minutes,seconds = divmod(tdelta.seconds,60)
|
||||
tenths = int(tdelta.microseconds/1e5)
|
||||
except AttributeError:
|
||||
minutes,seconds = divmod(tdelta.view(np.int64),60e9)
|
||||
seconds,rest = divmod(seconds,1e9)
|
||||
tenths = int(rest/1e8)
|
||||
res = "{minutes:0>2}:{seconds:0>2}.{tenths:0>1}".format(
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
tenths=tenths,
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
def nicepaceformat(values):
|
||||
out = []
|
||||
for v in values:
|
||||
formattedv = strfdelta(v)
|
||||
out.append(formattedv)
|
||||
|
||||
|
||||
return out
|
||||
|
||||
def timedeltaconv(x):
|
||||
dt = datetime.timedelta(seconds=x)
|
||||
|
||||
return dt
|
||||
|
||||
def rdata(file,rower=rrower()):
|
||||
try:
|
||||
res = rrdata(file,rower=rower)
|
||||
except IOError:
|
||||
res = 0
|
||||
|
||||
return res
|
||||
|
||||
def getrowdata(id=0):
|
||||
|
||||
# check if valid ID exists (workout exists)
|
||||
row = Workout.objects.get(id=id)
|
||||
|
||||
f1 = row.csvfilename
|
||||
|
||||
# get user
|
||||
|
||||
r = row.user
|
||||
u = r.user
|
||||
|
||||
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||
hrut1=r.ut1,hrat=r.at,
|
||||
hrtr=r.tr,hran=r.an)
|
||||
|
||||
rowdata = rdata(f1,rower=rr)
|
||||
|
||||
return rowdata,row
|
||||
|
||||
def dataprep(rowdatadf,bands=False,barchart=False,otwpower=False):
|
||||
rowdatadf.set_index([range(len(rowdatadf))],inplace=True)
|
||||
t = rowdatadf.ix[:,'TimeStamp (sec)']
|
||||
t = pd.Series(t-rowdatadf.ix[0,'TimeStamp (sec)'])
|
||||
|
||||
row_index = rowdatadf.ix[:,' Stroke500mPace (sec/500m)'] > 3000
|
||||
rowdatadf.loc[row_index,' Stroke500mPace (sec/500m)'] = 3000.
|
||||
|
||||
p = rowdatadf.ix[:,' Stroke500mPace (sec/500m)']
|
||||
hr = rowdatadf.ix[:,' HRCur (bpm)']
|
||||
spm = rowdatadf.ix[:,' Cadence (stokes/min)']
|
||||
cumdist = rowdatadf.ix[:,'cum_dist']
|
||||
|
||||
power = rowdatadf.ix[:,' Power (watts)']
|
||||
averageforce = rowdatadf.ix[:,' AverageDriveForce (lbs)']
|
||||
drivelength = rowdatadf.ix[:,' DriveLength (meters)']
|
||||
|
||||
|
||||
peakforce = rowdatadf.ix[:,' PeakDriveForce (lbs)']
|
||||
|
||||
|
||||
f = rowdatadf['TimeStamp (sec)'].diff().mean()
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
if windowsize <= 3:
|
||||
windowsize = 5
|
||||
|
||||
if windowsize > 3:
|
||||
spm = savgol_filter(spm,windowsize,3)
|
||||
hr = savgol_filter(hr,windowsize,3)
|
||||
drivelength = savgol_filter(drivelength,windowsize,3)
|
||||
|
||||
t2 = t.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
|
||||
|
||||
|
||||
p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
|
||||
|
||||
|
||||
drivespeed = drivelength/rowdatadf[' DriveTime (ms)']*1.0e3
|
||||
driveenergy = drivelength*averageforce*4.44822
|
||||
distance = rowdatadf.ix[:,'cum_dist']
|
||||
|
||||
|
||||
|
||||
|
||||
data = DataFrame(
|
||||
dict(
|
||||
time = t2,
|
||||
timesecs = t,
|
||||
hr = hr,
|
||||
pace = p2,
|
||||
pseconds=p,
|
||||
spm = spm,
|
||||
cumdist = cumdist,
|
||||
ftime = niceformat(t2),
|
||||
fpace = nicepaceformat(p2),
|
||||
driveenergy=driveenergy,
|
||||
power=power,
|
||||
averageforce=averageforce,
|
||||
drivelength=drivelength,
|
||||
peakforce=peakforce,
|
||||
distance=distance,
|
||||
drivespeed=drivespeed,
|
||||
)
|
||||
)
|
||||
|
||||
if bands:
|
||||
# HR bands
|
||||
data['hr_ut2'] = rowdatadf.ix[:,'hr_ut2']
|
||||
data['hr_ut1'] = rowdatadf.ix[:,'hr_ut1']
|
||||
data['hr_at'] = rowdatadf.ix[:,'hr_at']
|
||||
data['hr_tr'] = rowdatadf.ix[:,'hr_tr']
|
||||
data['hr_an'] = rowdatadf.ix[:,'hr_an']
|
||||
data['hr_max'] = rowdatadf.ix[:,'hr_max']
|
||||
data['hr_bottom'] = 0.0*data['hr']
|
||||
|
||||
if barchart:
|
||||
# time increments for bar chart
|
||||
time_increments = rowdatadf.ix[:,' ElapsedTime (sec)'].diff()
|
||||
time_increments[0] = time_increments[1]
|
||||
time_increments = 0.5*time_increments+0.5*np.abs(time_increments)
|
||||
x_right = (t2+time_increments.apply(lambda x:timedeltaconv(x)))
|
||||
|
||||
data['x_right'] = x_right
|
||||
|
||||
if otwpower:
|
||||
try:
|
||||
nowindpace = rowdatadf.ix[:,'nowindpace']
|
||||
except KeyError:
|
||||
nowindpace = p
|
||||
try:
|
||||
equivergpower = rowdatadf.ix[:,'equivergpower']
|
||||
except KeyError:
|
||||
equivergpower = 0*p+50.
|
||||
|
||||
nowindpace = nowindpace.apply(lambda x: timedeltaconv(x))
|
||||
ergvelo = (equivergpower/2.8)**(1./3.)
|
||||
|
||||
ergpace = 500./ergvelo
|
||||
ergpace[ergpace == np.inf] = 240.
|
||||
ergpace = ergpace.apply(lambda x: timedeltaconv(x))
|
||||
|
||||
data['ergpace'] = ergpace
|
||||
data['nowindpace'] = nowindpace
|
||||
data['equivergpower'] = equivergpower
|
||||
data['fergpace'] = nicepaceformat(ergpace)
|
||||
data['fnowindpace'] = nicepaceformat(nowindpace)
|
||||
|
||||
return data
|
||||
+217
-1084
File diff suppressed because it is too large
Load Diff
@@ -107,6 +107,7 @@ You will be taken to the secure PayPal payment site.
|
||||
<ul>
|
||||
<li>2016-11-01 Sliders to select subsets of data on some plots</li>
|
||||
<li>2016-11-01 Emailing workouts to workouts@rowsandall.com </li>
|
||||
<li>2016-11-01 Interval Editor </li>
|
||||
<li>2016-09-30 Stroke Analysis Plot - with date range filtering</li>
|
||||
<li>2016-09-29 Improved Flex plot, Power Histogram and Ranking Pieces - with date range filtering</li>
|
||||
<li>2016-09-20 Added the Power histogram</li>
|
||||
|
||||
@@ -53,7 +53,9 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="theplot" class="grid_12 alpha flexplot">
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -61,11 +61,13 @@
|
||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/otwsetpower">OTW Power</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="theplot" class="grid_12 alpha flexplot">
|
||||
|
||||
<div>
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
|
||||
<div class="grid_12">
|
||||
<p>
|
||||
<h3>Notes</h3>
|
||||
<ul>
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
<td> {{ value }} W </td>
|
||||
{% endif %}
|
||||
{% if key == "duration" %}
|
||||
<td> {{ value |paceprint }} </td>
|
||||
<td> {{ value |deltatimeprint }} </td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
@@ -209,7 +209,7 @@
|
||||
<td> {{ value }} W </td>
|
||||
{% endif %}
|
||||
{% if key == "duration" %}
|
||||
<td> {{ value |paceprint }} </td>
|
||||
<td> {{ value |deltatimeprint }} </td>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
|
||||
@@ -6,7 +6,20 @@ register = template.Library()
|
||||
def strfdelta(tdelta):
|
||||
minutes,seconds = divmod(tdelta.seconds,60)
|
||||
tenths = int(tdelta.microseconds/1e5)
|
||||
res = "{minutes:0>2}:{seconds:0>2}.{tenths:0>1}".format(
|
||||
res = "{minutes:0>1}:{seconds:0>2}.{tenths:0>1}".format(
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
tenths=tenths,
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
def strfdeltah(tdelta):
|
||||
hours, rest = divmod(tdelta.seconds,3600)
|
||||
minutes,seconds = divmod(rest,60)
|
||||
tenths = int(tdelta.microseconds/1e5)
|
||||
res = "{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{tenths:0>1}".format(
|
||||
hours=hours,
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
tenths=tenths,
|
||||
@@ -28,6 +41,13 @@ def paceprint(d):
|
||||
else:
|
||||
return strfdelta(d)
|
||||
|
||||
@register.filter
|
||||
def deltatimeprint(d):
|
||||
if (d == None):
|
||||
return d
|
||||
else:
|
||||
return strfdeltah(d)
|
||||
|
||||
|
||||
@register.filter
|
||||
def lookup(dict, key):
|
||||
|
||||
+8
-12
@@ -229,22 +229,22 @@ class DataTest(TestCase):
|
||||
res = iplots.interactive_chart(w.id,promember=1)
|
||||
res = iplots.interactive_bar_chart(w.id)
|
||||
res = iplots.interactive_bar_chart(w.id,promember=1)
|
||||
res = iplots.interactive_flex_chart(w.id,promember=0,xparam='time',
|
||||
res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='time',
|
||||
yparam1='pace',yparam2='hr')
|
||||
res = iplots.interactive_flex_chart(w.id,promember=0,xparam='distance',
|
||||
res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='distance',
|
||||
yparam1='pace',yparam2='hr')
|
||||
res = iplots.interactive_flex_chart(w.id,promember=0,xparam='time',
|
||||
res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='time',
|
||||
yparam1='pace',yparam2='spm')
|
||||
res = iplots.interactive_flex_chart(w.id,promember=0,xparam='distance',
|
||||
res = iplots.interactive_flex_chart2(w.id,promember=0,xparam='distance',
|
||||
yparam1='pace',yparam2='spm')
|
||||
|
||||
res = iplots.interactive_flex_chart(w.id,promember=1,xparam='time',
|
||||
res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='time',
|
||||
yparam1='pace',yparam2='hr')
|
||||
res = iplots.interactive_flex_chart(w.id,promember=1,xparam='distance',
|
||||
res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='distance',
|
||||
yparam1='pace',yparam2='hr')
|
||||
res = iplots.interactive_flex_chart(w.id,promember=1,xparam='time',
|
||||
res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='time',
|
||||
yparam1='pace',yparam2='spm')
|
||||
res = iplots.interactive_flex_chart(w.id,promember=1,xparam='distance',
|
||||
res = iplots.interactive_flex_chart2(w.id,promember=1,xparam='distance',
|
||||
yparam1='pace',yparam2='spm')
|
||||
|
||||
|
||||
@@ -793,10 +793,6 @@ class subroutinetests(TestCase):
|
||||
duration="0:55:00",distance=8000,
|
||||
csvfilename=filename)
|
||||
|
||||
def test_seconds(self):
|
||||
seconds = [30.3,75.8,3900.3,104670.2]
|
||||
res = iplots.get_datetimes(seconds)
|
||||
|
||||
|
||||
def c2stuff(self):
|
||||
data = c2stuff.createc2workoutdata(self.w)
|
||||
|
||||
+1
-5
@@ -127,12 +127,8 @@ urlpatterns = [
|
||||
url(r'^register/thankyou/$', TemplateView.as_view(template_name='registerthankyou.html'), name='registerthankyou'),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<plottype>\w+)/$',views.workout_flexchart3_view),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<plottype>\w+.*)$',views.workout_flexchart3_view),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)$',views.workout_flexchart2_view),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)$',views.workout_flexchart3_view),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart$',views.workout_flexchart3_view),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart2/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<plottype>\w+)/$',views.workout_flexchart2_view),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart2/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<plottype>\w+.*)$',views.workout_flexchart2_view),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart2/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)$',views.workout_flexchart3_view),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart2$',views.workout_flexchart2_view),
|
||||
url(r'^workout/compare/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/(?P<plottype>\w+.*)$',views.workout_comparison_view2),
|
||||
url(r'^workout/compare/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/$',views.workout_comparison_view2),
|
||||
]
|
||||
|
||||
+11
-95
@@ -66,6 +66,7 @@ import mailprocessing
|
||||
from io import BytesIO
|
||||
from scipy.special import lambertw
|
||||
|
||||
from dataprep import timedeltaconv
|
||||
|
||||
LOCALTIMEZONE = tz('Etc/UTC')
|
||||
USER_LANGUAGE = 'en-US'
|
||||
@@ -1204,8 +1205,8 @@ def cum_flex(request,theuser=0,
|
||||
xparam='spm',
|
||||
yparam1='power',
|
||||
yparam2='None',
|
||||
startdate=timezone.now()-datetime.timedelta(days=30),
|
||||
enddate=timezone.now(),
|
||||
startdate=timezone.now()-datetime.timedelta(days=10),
|
||||
enddate=timezone.now()+datetime.timedelta(days=1),
|
||||
deltadays=-1,
|
||||
startdatestring="",
|
||||
enddatestring=""):
|
||||
@@ -1617,8 +1618,8 @@ def rankings_view(request,theuser=0,
|
||||
t = rankingdistance/velo
|
||||
pwr = 2.8*(velo**3)
|
||||
a = {'distance':rankingdistance,
|
||||
'duration':get_datetimes([t])[0],
|
||||
'pace':get_datetimes([p])[0],
|
||||
'duration':timedeltaconv(t),
|
||||
'pace':timedeltaconv(p),
|
||||
'power':int(pwr)}
|
||||
predictions.append(a)
|
||||
|
||||
@@ -1650,8 +1651,8 @@ def rankings_view(request,theuser=0,
|
||||
p3 = 500./velo3
|
||||
|
||||
a = {'distance':rankingdistance,
|
||||
'duration':get_datetimes([t3])[0],
|
||||
'pace':get_datetimes([p3])[0],
|
||||
'duration':timedeltaconv(t3),
|
||||
'pace':timedeltaconv(p3),
|
||||
'power':int(pwr3)}
|
||||
cpredictions.append(a)
|
||||
|
||||
@@ -1677,8 +1678,8 @@ def rankings_view(request,theuser=0,
|
||||
p = 500./velo
|
||||
pwr = 2.8*(velo**3)
|
||||
a = {'distance':int(d),
|
||||
'duration':get_datetimes([t])[0],
|
||||
'pace':get_datetimes([p])[0],
|
||||
'duration':timedeltaconv(t),
|
||||
'pace':timedeltaconv(p),
|
||||
'power':int(pwr)}
|
||||
predictions.append(a)
|
||||
|
||||
@@ -1697,8 +1698,8 @@ def rankings_view(request,theuser=0,
|
||||
d = t*velo
|
||||
p = 500./velo
|
||||
a = {'distance':int(d),
|
||||
'duration':get_datetimes([t])[0],
|
||||
'pace':get_datetimes([p])[0],
|
||||
'duration':timedeltaconv(t),
|
||||
'pace':timedeltaconv(p),
|
||||
'power':int(pwr)}
|
||||
cpredictions.append(a)
|
||||
|
||||
@@ -2344,91 +2345,6 @@ def workout_comparison_view2(request,id1=0,id2=0,xparam='distance',
|
||||
'promember':promember,
|
||||
})
|
||||
|
||||
def workout_flexchart_view(request,id=0,xparam='distance',yparam1='pace',
|
||||
yparam2='hr',
|
||||
promember=0):
|
||||
|
||||
if request.method == 'POST':
|
||||
workstrokesonly = request.POST['workstrokesonly']
|
||||
else:
|
||||
workstrokesonly = False
|
||||
|
||||
row = Workout.objects.get(id=id)
|
||||
promember=0
|
||||
mayedit=0
|
||||
if not request.user.is_anonymous():
|
||||
r = Rower.objects.get(user=request.user)
|
||||
result = request.user.is_authenticated() and r.rowerplan=='pro'
|
||||
if result:
|
||||
promember=1
|
||||
if request.user == row.user.user:
|
||||
mayedit=1
|
||||
|
||||
# create interactive plot
|
||||
res = interactive_flex_chart(id,xparam=xparam,yparam1=yparam1,
|
||||
yparam2=yparam2,
|
||||
promember=promember)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
|
||||
|
||||
return render(request,
|
||||
'flexchart.html',
|
||||
{'interactiveplot':script,
|
||||
'the_div':div,
|
||||
'id':id,
|
||||
'xparam':xparam,
|
||||
'yparam1':yparam1,
|
||||
'yparam2':yparam2,
|
||||
'mayedit':mayedit,
|
||||
})
|
||||
|
||||
def workout_flexchart2_view(request,id=0,xparam='distance',yparam1='pace',
|
||||
yparam2='hr',plottype='line',
|
||||
promember=0):
|
||||
|
||||
if request.method == 'POST':
|
||||
workstrokesonly = request.POST['workstrokesonly']
|
||||
if workstrokesonly == 'True':
|
||||
workstrokesonly = True
|
||||
else:
|
||||
workstrokesonly = False
|
||||
else:
|
||||
workstrokesonly = False
|
||||
|
||||
row = Workout.objects.get(id=id)
|
||||
promember=0
|
||||
mayedit=0
|
||||
if not request.user.is_anonymous():
|
||||
r = Rower.objects.get(user=request.user)
|
||||
result = request.user.is_authenticated() and r.rowerplan=='pro'
|
||||
if result:
|
||||
promember=1
|
||||
if request.user == row.user.user:
|
||||
mayedit=1
|
||||
|
||||
# create interactive plot
|
||||
res = interactive_flex_chart(id,xparam=xparam,yparam1=yparam1,
|
||||
yparam2=yparam2,
|
||||
promember=promember,plottype=plottype,
|
||||
workstrokesonly=workstrokesonly)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
|
||||
|
||||
return render(request,
|
||||
'flexchart2.html',
|
||||
{'interactiveplot':script,
|
||||
'the_div':div,
|
||||
'id':id,
|
||||
'xparam':xparam,
|
||||
'yparam1':yparam1,
|
||||
'yparam2':yparam2,
|
||||
'plottype':plottype,
|
||||
'mayedit':mayedit,
|
||||
'promember':promember,
|
||||
'workstrokesonly': not workstrokesonly,
|
||||
})
|
||||
|
||||
|
||||
def workout_flexchart3_view(request,id=0,xparam='distance',yparam1='pace',
|
||||
|
||||
Reference in New Issue
Block a user