From f44fee0f12ecfd6294924a440627727f65981080 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Tue, 22 Aug 2017 20:15:06 +0200
Subject: [PATCH 1/4] split workout (bugs)
---
rowers/dataprep.py | 38 ++++++++++
rowers/forms.py | 15 ++++
rowers/templates/splitworkout.html | 113 +++++++++++++++++++++++++++++
rowers/urls.py | 1 +
rowers/views.py | 54 +++++++++++++-
5 files changed, 219 insertions(+), 2 deletions(-)
create mode 100644 rowers/templates/splitworkout.html
diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index 8d5f9473..b454942a 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -820,6 +820,43 @@ def new_workout_from_file(r,f2,
return (id,message,f2)
+def split_workout(r,parent,splitsecond,splitmode):
+ data,row = getrowdata_db(id=parent.id)
+
+ data['time'] = data['time']/1000.
+
+ data1 = data[data['time']<=splitsecond].copy()
+ data2 = data[data['time']>splitsecond].copy()
+
+
+ messages = []
+ ids = []
+
+ if 'keep first' in splitmode:
+ id,message = new_workout_from_df(r,data1,
+ title=parent.name+' First Part',
+ parent=parent)
+ messages.append(message)
+ ids.append(id)
+ if 'keep second' in splitmode:
+ data2['cumdist'] = data2['cumdist'] - data2['cumdist'].min()
+ data2['time'] = data2['time'] - data2['time'].min()
+ id,message = new_workout_from_df(r,data2,
+ title=parent.name+' Second Part',
+ parent=parent)
+ messages.append(message)
+ ids.append(id)
+
+ if not 'keep original' in splitmode:
+ if 'keep second' in splitmode or 'keep first' in splitmode:
+ parent.delete()
+ messages.append('Deleted Workout: '+parent.name)
+ else:
+ messages.append('That would delete your workout')
+ ids.append(parent.id)
+
+ return ids,messages
+
# Create new workout from data frame and store it in the database
# This routine should be used everywhere in views.py and mailprocessing.py
# Currently there is code duplication
@@ -853,6 +890,7 @@ def new_workout_from_df(r,df,
df.rename(columns = columndict,inplace=True)
+
starttimeunix = mktime(startdatetime.utctimetuple())
df[' ElapsedTime (sec)'] = df['TimeStamp (sec)']
df['TimeStamp (sec)'] = df['TimeStamp (sec)']+starttimeunix
diff --git a/rowers/forms.py b/rowers/forms.py
index 732097e4..59d85ebf 100644
--- a/rowers/forms.py
+++ b/rowers/forms.py
@@ -110,6 +110,21 @@ class TeamUploadOptionsForm(forms.Form):
class Meta:
fields = ['make_plot','plottype']
+# This form is used on the Workout Split page
+class WorkoutSplitForm(forms.Form):
+ splitchoices = (
+ ('keep original','Keep Original'),
+ ('keep first','Keep First Part'),
+ ('keep second','Keep Second Part'),
+ )
+ splittime = forms.TimeField(input_formats=['%H:%M:%S.%f','%H:%M:%S','%M:%S.%f'])
+ splitmode = forms.MultipleChoiceField(
+ initial=['keep original',
+ 'keep first',
+ 'keep second'],
+ label='Split Mode',
+ choices=splitchoices)
+
# This form is used on the Analysis page to add a custom distance/time
# trial and predict the pace
class PredictedPieceForm(forms.Form):
diff --git a/rowers/templates/splitworkout.html b/rowers/templates/splitworkout.html
new file mode 100644
index 00000000..3d9b1fda
--- /dev/null
+++ b/rowers/templates/splitworkout.html
@@ -0,0 +1,113 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+{% load rowerfilters %}
+{% load tz %}
+
+{% block title %}Change Workout {% endblock %}
+
+{% block content %}
+
+
+ {% if form.errors %}
+
+ Please correct the error{{ form.errors|pluralize }} below.
+
+ {% endif %}
+
+
Edit Workout Interval Data
+
+
+
+ {% localtime on %}
+
+ {% endlocaltime %}
+
Workout Split
+
Split your workout in half
+
+
+
+
+
+
+
+
+
+
+ {{ thescript |safe }}
+
+
+
+
+
+
+ {{ thediv |safe }}
+
+
+
+
+
+{% endblock %}
diff --git a/rowers/urls.py b/rowers/urls.py
index b94aafbb..80abf3e3 100644
--- a/rowers/urls.py
+++ b/rowers/urls.py
@@ -202,6 +202,7 @@ urlpatterns = [
url(r'^workout/(?P\d+)/crewnerdsummary$',views.workout_crewnerd_summary_view),
url(r'^workout/(?P\d+)/editintervals$',views.workout_summary_edit_view),
url(r'^workout/(?P\d+)/restore$',views.workout_summary_restore_view),
+ url(r'^workout/(?P\d+)/split$',views.workout_split_view),
url(r'^workout/(?P\d+)/interactiveplot$',views.workout_biginteractive_view),
url(r'^workout/(?P\d+)/view$',views.workout_view),
url(r'^workout/(?P\d+)$',views.workout_view),
diff --git a/rowers/views.py b/rowers/views.py
index 16ede869..f1be7269 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -36,7 +36,7 @@ from rowers.forms import (
RegistrationFormUniqueEmail,CNsummaryForm,UpdateWindForm,
UpdateStreamForm,WorkoutMultipleCompareForm,ChartParamChoiceForm,
FusionMetricChoiceForm,BoxPlotChoiceForm,MultiFlexChoiceForm,
- TrendFlexModalForm,
+ TrendFlexModalForm,WorkoutSplitForm,
)
from rowers.models import Workout, User, Rower, WorkoutForm,FavoriteChart
from rowers.models import (
@@ -7773,6 +7773,8 @@ def workout_delete_view(request,id=0):
messages.info(request,'Workout deleted')
try:
url = request.session['referer']
+ if 'rowers/workout/' in url:
+ url = reverse(workouts_view)
except KeyError:
url = reverse(workouts_view)
@@ -7877,7 +7879,7 @@ def graph_show_view(request,id):
raise Http404("This graph doesn't exist")
except Workout.DoesNotExist:
raise Http404("This workout doesn't exist")
-
+
# Restore original stroke data and summary
@login_required()
def workout_summary_restore_view(request,id,message="",successmessage=""):
@@ -7935,6 +7937,54 @@ def workout_summary_restore_view(request,id,message="",successmessage=""):
)
return HttpResponseRedirect(url)
+# Split a workout
+@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
+def workout_split_view(request,id=id):
+ try:
+ row = Workout.objects.get(id=id)
+ if (checkworkoutuser(request.user,row)==False):
+ raise PermissionDenied("You are not allowed to edit this workout")
+ except Workout.DoesNotExist:
+ raise Http404("Workout doesn't exist")
+
+ r = getrower(request.user)
+ if not checkworkoutuser(request.user,row):
+ raise PermissionDenied("You are not allowed to edit this workout")
+
+ if request.method == 'POST':
+ form = WorkoutSplitForm(request.POST)
+ if form.is_valid():
+ splittime = form.cleaned_data['splittime']
+ splitsecond = splittime.hour*3600
+ splitsecond += splittime.minute*60
+ splitsecond += splittime.second
+ splitsecond += splittime.microsecond/1.e6
+ splitmode = form.cleaned_data['splitmode']
+ ids,mesgs = dataprep.split_workout(r,row,splitsecond,splitmode)
+ for message in mesgs:
+ messages.info(request,message)
+
+ url = reverse(workouts_view)
+ return HttpResponseRedirect(url)
+
+ form = WorkoutSplitForm()
+
+ # create interactive plot
+ try:
+ res = interactive_chart(id,promember=1)
+ script = res[0]
+ div = res[1]
+ except ValueError:
+ pass
+
+ return render(request, 'splitworkout.html',
+ {'form':form,
+ 'workout':row,
+ 'thediv':script,
+ 'thescript':div,
+ })
+
+
# Fuse two workouts
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
def workout_fusion_view(request,id1=0,id2=1):
From 7e78abc1ef4bef2874dc1dc8adcdb6ae14aeb872 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Tue, 22 Aug 2017 22:28:09 +0200
Subject: [PATCH 2/4] split seems to be working now
---
rowers/dataprep.py | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index b454942a..9dfb3e68 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -828,7 +828,34 @@ def split_workout(r,parent,splitsecond,splitmode):
data1 = data[data['time']<=splitsecond].copy()
data2 = data[data['time']>splitsecond].copy()
+ data1 = data1.sort_values(['time'])
+ data1 = data1.interpolate(method='linear',axis=0,limit_direction='both',
+ limit=10)
+ data1.fillna(method='bfill',inplace=True)
+
+ # Some new stuff to try out
+ data1 = data1.groupby('time',axis=0).mean()
+ data1['time'] = data1.index
+ data1.reset_index(drop=True,inplace=True)
+
+ data2 = data2.sort_values(['time'])
+ data2 = data2.interpolate(method='linear',axis=0,limit_direction='both',
+ limit=10)
+ data2.fillna(method='bfill',inplace=True)
+
+ # Some new stuff to try out
+ data2 = data2.groupby('time',axis=0).mean()
+ data2['time'] = data2.index
+ data2.reset_index(drop=True,inplace=True)
+
+ data1['pace'] = data1['pace']/1000.
+ data2['pace'] = data2['pace']/1000.
+
+
+ data1.drop_duplicates(subset='time',inplace=True)
+ data2.drop_duplicates(subset='time',inplace=True)
+
messages = []
ids = []
@@ -839,8 +866,9 @@ def split_workout(r,parent,splitsecond,splitmode):
messages.append(message)
ids.append(id)
if 'keep second' in splitmode:
- data2['cumdist'] = data2['cumdist'] - data2['cumdist'].min()
- data2['time'] = data2['time'] - data2['time'].min()
+ data2['cumdist'] = data2['cumdist'] - data2.ix[0,'cumdist']
+ data2['distance'] = data2['distance'] - data2.ix[0,'distance']
+ data2['time'] = data2['time'] - data2.ix[0,'time']
id,message = new_workout_from_df(r,data2,
title=parent.name+' Second Part',
parent=parent)
@@ -893,6 +921,7 @@ def new_workout_from_df(r,df,
starttimeunix = mktime(startdatetime.utctimetuple())
df[' ElapsedTime (sec)'] = df['TimeStamp (sec)']
+ print df[' ElapsedTime (sec)'].values
df['TimeStamp (sec)'] = df['TimeStamp (sec)']+starttimeunix
row = rrdata(df=df)
From 45fe8a61810b27514cf15bde9c37b86f5cac2320 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Wed, 23 Aug 2017 09:55:26 +0200
Subject: [PATCH 3/4] workout split works
---
rowers/dataprep.py | 34 +++++++++++++---
rowers/forms.py | 18 +++++++--
rowers/templates/advancedotw.html | 16 +++++++-
rowers/templates/splitworkout.html | 64 +++++++++++++++++++-----------
rowers/views.py | 5 ++-
5 files changed, 102 insertions(+), 35 deletions(-)
diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index 9dfb3e68..d495185a 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -860,20 +860,36 @@ def split_workout(r,parent,splitsecond,splitmode):
ids = []
if 'keep first' in splitmode:
+ if 'secondprivate' in splitmode:
+ setprivate = True
+ else:
+ setprivate = False
+
id,message = new_workout_from_df(r,data1,
title=parent.name+' First Part',
- parent=parent)
+ parent=parent,
+ setprivate=setprivate)
messages.append(message)
ids.append(id)
if 'keep second' in splitmode:
data2['cumdist'] = data2['cumdist'] - data2.ix[0,'cumdist']
data2['distance'] = data2['distance'] - data2.ix[0,'distance']
data2['time'] = data2['time'] - data2.ix[0,'time']
+ if 'secondprivate' in splitmode:
+ setprivate = True
+ else:
+ setprivate = False
+
+ dt = datetime.timedelta(seconds=splitsecond)
+
id,message = new_workout_from_df(r,data2,
title=parent.name+' Second Part',
- parent=parent)
+ parent=parent,
+ setprivate=setprivate,
+ dt=dt)
messages.append(message)
ids.append(id)
+
if not 'keep original' in splitmode:
if 'keep second' in splitmode or 'keep first' in splitmode:
@@ -882,6 +898,9 @@ def split_workout(r,parent,splitsecond,splitmode):
else:
messages.append('That would delete your workout')
ids.append(parent.id)
+ elif 'originalprivate' in splitmode:
+ parent.privacy = 'hidden'
+ parent.save()
return ids,messages
@@ -890,7 +909,9 @@ def split_workout(r,parent,splitsecond,splitmode):
# Currently there is code duplication
def new_workout_from_df(r,df,
title='New Workout',
- parent=None):
+ parent=None,
+ setprivate=False,
+ dt=datetime.timedelta()):
message = None
@@ -902,7 +923,7 @@ def new_workout_from_df(r,df,
notes=parent.notes
summary=parent.summary
makeprivate=parent.privacy
- startdatetime=parent.startdatetime
+ startdatetime=parent.startdatetime+dt
else:
oarlength = 2.89
inboard = 0.88
@@ -912,6 +933,9 @@ def new_workout_from_df(r,df,
makeprivate=False
startdatetime = timezone.now()
+ if setprivate:
+ makeprivate=True
+
timestr = strftime("%Y%m%d-%H%M%S")
csvfilename ='media/df_'+timestr+'.csv'
@@ -921,7 +945,7 @@ def new_workout_from_df(r,df,
starttimeunix = mktime(startdatetime.utctimetuple())
df[' ElapsedTime (sec)'] = df['TimeStamp (sec)']
- print df[' ElapsedTime (sec)'].values
+
df['TimeStamp (sec)'] = df['TimeStamp (sec)']+starttimeunix
row = rrdata(df=df)
diff --git a/rowers/forms.py b/rowers/forms.py
index 59d85ebf..eecde602 100644
--- a/rowers/forms.py
+++ b/rowers/forms.py
@@ -116,14 +116,26 @@ class WorkoutSplitForm(forms.Form):
('keep original','Keep Original'),
('keep first','Keep First Part'),
('keep second','Keep Second Part'),
+ ('firstprivate','Set First Part Private'),
+ ('secondprivate','Set Second Part Private'),
+ ('originalprivate','Set Original Private'),
)
- splittime = forms.TimeField(input_formats=['%H:%M:%S.%f','%H:%M:%S','%M:%S.%f'])
+ splittime = forms.TimeField(input_formats=['%H:%M:%S.%f',
+ '%H:%M:%S',
+ '%H:%M:%S',
+ '%M:%S.%f',
+ '%M:%S',
+ '%M'],
+ label = 'Split Time')
splitmode = forms.MultipleChoiceField(
initial=['keep original',
'keep first',
- 'keep second'],
+ 'keep second',
+ 'firstprivate',
+ 'secondprivate'],
label='Split Mode',
- choices=splitchoices)
+ choices=splitchoices,
+ widget = forms.CheckboxSelectMultiple())
# This form is used on the Analysis page to add a custom distance/time
# trial and predict the pace
diff --git a/rowers/templates/advancedotw.html b/rowers/templates/advancedotw.html
index 3b8ac298..abbccd67 100644
--- a/rowers/templates/advancedotw.html
+++ b/rowers/templates/advancedotw.html
@@ -190,18 +190,30 @@
See (and save) the big interactive plot
-
+
+
+
+ {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
+ Split Workout
+ {% else %}
+ Split Workout
+ {% endif %}
+
+
+ Split workout into two seperate workouts
+
+
diff --git a/rowers/templates/splitworkout.html b/rowers/templates/splitworkout.html
index 3d9b1fda..a264f626 100644
--- a/rowers/templates/splitworkout.html
+++ b/rowers/templates/splitworkout.html
@@ -38,29 +38,8 @@
{% localtime on %}
-
- {% endlocaltime %}
- Workout Split
- Split your workout in half
-
+
+