adding resample function
This commit is contained in:
@@ -547,6 +547,49 @@ def df_resample(datadf):
|
||||
newdf = datadf.groupby(['timestamps']).mean()
|
||||
return newdf
|
||||
|
||||
def resample(id,r,parent,overwrite='copy'):
|
||||
data, row = getrowdata_db(id=id)
|
||||
messages = []
|
||||
|
||||
# resample
|
||||
startdatetime = row.startdatetime
|
||||
data['datetime'] = data['time'].apply(lambda x:startdatetime+datetime.timedelta(seconds=x/1000.))
|
||||
|
||||
data = data.resample('S',on='datetime').mean()
|
||||
data.interpolate(method='linear',inplace=True)
|
||||
data.reset_index(drop=True,inplace=True)
|
||||
|
||||
#data.drop('datetime',inplace=True)
|
||||
data['pace'] = data['pace'] / 1000.
|
||||
data['time'] = data['time'] / 1000.
|
||||
|
||||
if overwrite=='overwrite':
|
||||
# remove CP data
|
||||
try:
|
||||
cpfile = 'media/cpdata_{id}.parquet.gz'.format(id=parent.id)
|
||||
os.remove(cpfile)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
# save
|
||||
data.rename(columns=columndict,inplace=True)
|
||||
|
||||
starttimeunix = arrow.get(startdatetime).timestamp()
|
||||
data[' ElapsedTime (sec)'] = data['TimeStamp (sec)']
|
||||
|
||||
data['TimeStamp (sec)'] = data['TimeStamp (sec)'] + starttimeunix
|
||||
|
||||
row = rrdata(df=data)
|
||||
|
||||
row.write_csv(parent.csvfilename,gzip=True)
|
||||
|
||||
res = dataprep(row.df, id=parent.id, bands=True, barchart=True, otwpower=True, empower=True,inboard=parent.inboard)
|
||||
else:
|
||||
id, message = new_workout_from_df(r, data, title=parent.name + '(Resampled)',
|
||||
parent=parent,forceunit='N')
|
||||
messages.append(message)
|
||||
|
||||
return data, id, messages
|
||||
|
||||
|
||||
def clean_df_stats(datadf, workstrokesonly=True, ignorehr=True,
|
||||
ignoreadvanced=False):
|
||||
@@ -1239,6 +1282,7 @@ def setcp(workout,background=False,recurrance=True):
|
||||
|
||||
strokesdf = getsmallrowdata_db(['power','workoutid','time'],ids = [workout.id])
|
||||
|
||||
|
||||
try:
|
||||
if strokesdf['power'].std()==0:
|
||||
return pd.DataFrame(),pd.Series(dtype='float'),pd.Series(dtype='float')
|
||||
|
||||
@@ -285,26 +285,8 @@ def getcp(dfgrouped,logarr):
|
||||
mask = ww > 2000
|
||||
ww.loc[mask] = 0
|
||||
|
||||
|
||||
|
||||
tmax = tt.max()
|
||||
|
||||
|
||||
# if tmax > 3600000:
|
||||
# newlen = int(tmax/10000.)
|
||||
# else:
|
||||
# newlen = len(tt)
|
||||
# if newlen < len(tt):
|
||||
# newt = np.arange(newlen)*tmax/float(newlen)
|
||||
# ww = griddata(tt.values,
|
||||
# ww.values,
|
||||
# newt,method='nearest',
|
||||
# rescale=True)
|
||||
#
|
||||
# tt = pd.Series(newt)
|
||||
# ww = pd.Series(ww)
|
||||
|
||||
|
||||
try:
|
||||
avgpower[id] = int(ww.mean())
|
||||
except ValueError: # pragma: no cover
|
||||
|
||||
@@ -58,6 +58,14 @@ class FlexibleDecimalField(forms.DecimalField):
|
||||
value = value.replace('.', '').replace(',', '.')
|
||||
return super(FlexibleDecimalField, self).to_python(value)
|
||||
|
||||
class ResampleForm(forms.Form):
|
||||
resamplechoices = (
|
||||
('overwrite','Overwrite Workout'),
|
||||
('copy','Create a Duplicate Workout')
|
||||
)
|
||||
|
||||
resamplechoice = forms.ChoiceField(initial='copy',choices=resamplechoices,label='Copy behavior')
|
||||
|
||||
class TrainingZonesForm(forms.Form):
|
||||
zoneschoices = (
|
||||
('power','Power Zones'),
|
||||
|
||||
@@ -285,6 +285,12 @@
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/data/">
|
||||
<i class="fal fa-table fa-fw"></i> Explore Raw Data
|
||||
</a>
|
||||
</li>
|
||||
<li id="resample-view">
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/resample/">
|
||||
<i class="fal fa-ruler-horizontal fa-fw"></i> Resample to 1s
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="has-children" id="advanced">
|
||||
|
||||
30
rowers/templates/workout_resample.html
Normal file
30
rowers/templates/workout_resample.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{% extends "newbase.html" %}
|
||||
{% load static %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}Workout Data Resample{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<h1>Workout Data Resample for {{ workout.name }}</h1>
|
||||
|
||||
<ul class="main-content">
|
||||
<li class="grid_4">
|
||||
<p>This functionality resamples the data to 1 second intervals. This can be useful in
|
||||
case there are gaps larger than 30 seconds in the data, which prevent the creation
|
||||
of a correct CP chart.
|
||||
</p>
|
||||
<p>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{{ form.as_table }}
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% include 'menu_workout.html' %}
|
||||
{% endblock %}
|
||||
@@ -384,6 +384,8 @@ urlpatterns = [
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/stats/$',views.workout_stats_view,name='workout_stats_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/data/$',views.workout_data_view,
|
||||
name='workout_data_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/resample/$',views.workout_resample_view,
|
||||
name='workout_resample_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/(?P<column>\w+)/erase/$',views.workout_erase_column_view,
|
||||
name='workout_erase_column_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/zeropower-confirm/$',views.remove_power_confirm_view,
|
||||
|
||||
@@ -64,7 +64,7 @@ from django.contrib.auth import authenticate, login, logout
|
||||
from rowers.forms import (
|
||||
ForceCurveOptionsForm,HistoForm,TeamMessageForm,
|
||||
LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,CourseForm,
|
||||
CourseConfirmForm,
|
||||
CourseConfirmForm,ResampleForm,
|
||||
TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm,
|
||||
WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement,
|
||||
LandingPageForm,PlannedSessionSelectForm,WorkoutSessionSelectForm,
|
||||
|
||||
@@ -3131,7 +3131,54 @@ def workout_erase_column_view(request, id=0,column=''):
|
||||
|
||||
|
||||
|
||||
# resample to 1s intervals
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_resample_view(request, id=0):
|
||||
r = getrower(request.user)
|
||||
w = get_workoutuser(id, request)
|
||||
|
||||
form = ResampleForm()
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ResampleForm(request.POST)
|
||||
if form.is_valid():
|
||||
overwrite = form.cleaned_data['resamplechoice']
|
||||
datadf,id, msgs = dataprep.resample(encoder.decode_hex(id),r,w,overwrite=overwrite)
|
||||
|
||||
for message in msgs:
|
||||
messages.info(request,message)
|
||||
|
||||
|
||||
url = get_workout_default_page(request,encoder.encode_hex(id))
|
||||
|
||||
messages.info(request,'The workout has been resampled: <a href="{url}">here</a>'.format(url=url))
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url':'/rowers/list-workouts/',
|
||||
'name':'Workouts'
|
||||
},
|
||||
{
|
||||
'url':get_workout_default_page(request,id),
|
||||
'name': w.name
|
||||
},
|
||||
{
|
||||
'url':reverse('workout_resample_view',kwargs={'id':id}),
|
||||
'name': 'Resample Data'
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
return render(request,
|
||||
'workout_resample.html',
|
||||
{
|
||||
'form':form,
|
||||
'teams':get_my_teams(request.user),
|
||||
'workout': w,
|
||||
'breadcrumbs': breadcrumbs,
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
# data explorer
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
|
||||
Reference in New Issue
Block a user