diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 8d5f9473..e2e040d2 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -91,7 +91,7 @@ columndict = { 'finish':'finish', 'peakforceangle':'peakforceangle', 'wash':'wash', - 'slip':'wash', + 'slip':'slip', 'workoutstate':' WorkoutState', } @@ -107,13 +107,17 @@ def get_latlon(id): rowdata = rdata(w.csvfilename) try: - latitude = rowdata.df.ix[:,' latitude'] - longitude = rowdata.df.ix[:,' longitude'] - except KeyError: - latitude = 0*rowdata.df.ix[:,'TimeStamp (sec)'] - latitude = 0*rowdata.df.ix[:,'TimeStamp (sec)'] - - return [latitude,longitude] + try: + latitude = rowdata.df.ix[:,' latitude'] + longitude = rowdata.df.ix[:,' longitude'] + except KeyError: + latitude = 0*rowdata.df.ix[:,'TimeStamp (sec)'] + longitude = 0*rowdata.df.ix[:,'TimeStamp (sec)'] + return [latitude,longitude] + except AttributeError: + return [pd.Series([]),pd.Series([])] + + return [pd.Series([]),pd.Series([])] def get_workouts(ids,userid): goodids = [] @@ -820,12 +824,102 @@ 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) + latitude,longitude = get_latlon(parent.id) + if not latitude.empty and not longitude.empty: + data[' latitude'] = latitude + data[' longitude'] = longitude + + data['time'] = data['time']/1000. + + 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 = [] + + 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, + 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, + 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: + parent.delete() + messages.append('Deleted Workout: '+parent.name) + else: + messages.append('That would delete your workout') + ids.append(parent.id) + elif 'originalprivate' in splitmode: + parent.privacy = 'hidden' + parent.save() + + 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 def new_workout_from_df(r,df, title='New Workout', - parent=None): + parent=None, + setprivate=False, + dt=datetime.timedelta()): message = None @@ -837,7 +931,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 @@ -847,14 +941,19 @@ 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' df.rename(columns = columndict,inplace=True) + starttimeunix = mktime(startdatetime.utctimetuple()) df[' ElapsedTime (sec)'] = df['TimeStamp (sec)'] + df['TimeStamp (sec)'] = df['TimeStamp (sec)']+starttimeunix row = rrdata(df=df) diff --git a/rowers/forms.py b/rowers/forms.py index 732097e4..eecde602 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -110,6 +110,33 @@ 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'), + ('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', + '%H:%M:%S', + '%M:%S.%f', + '%M:%S', + '%M'], + label = 'Split Time') + splitmode = forms.MultipleChoiceField( + initial=['keep original', + 'keep first', + 'keep second', + 'firstprivate', + 'secondprivate'], + label='Split Mode', + choices=splitchoices, + widget = forms.CheckboxSelectMultiple()) + # 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/advancededit.html b/rowers/templates/advancededit.html index 6db5b03c..55de324b 100644 --- a/rowers/templates/advancededit.html +++ b/rowers/templates/advancededit.html @@ -133,18 +133,30 @@ Plot the Power Histogram of this workout
-{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} Sensor Fusion {% else %} - Dist Metrics Plot + Sensor Fusion {% endif %}
Merge data from another source into this workout
+ {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + Split Workout + {% else %} + Split Workout + {% endif %} +
++ Split workout into two seperate workouts +
+{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} Sensor Fusion {% else %} - Dist Metrics Plot + Sensor Fusion {% endif %}
Merge data from another source into this workout
+ {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + Split Workout + {% else %} + Split Workout + {% endif %} +
++ Split workout into two seperate workouts +
++ Please correct the error{{ form.errors|pluralize }} below. +
+ {% endif %} + ++ Edit +
++ Export + +
++ Advanced +
+ Advanced Functionality (More interactive Charts) + ++
+ +Split your workout in half at the given time using the form above. + Use the chart on + the right to find the point where you want to split.
+Use any of the following formats: +
Warning: If you deselect, "Keep Original", the original workout + cannot be restored afterwards.
+ +| Date/Time: | {{ workout.startdatetime }} | +|
|---|---|---|
| Distance: | {{ workout.distance }}m | +|
| Duration: | {{ workout.duration |durationprint:"%H:%M:%S.%f" }} | +|
| Public link to this workout | ++ https://rowsandall.com/rowers/workout/{{ workout.id }} + | + |
| Public link to interactive chart | ++ https://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot + | + |