From b21c0c122f5c07b7fb097aebf9873fadc68f7069 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 18 Nov 2017 17:03:18 -0700 Subject: [PATCH 1/2] manual workout form - datetime is 48 years off --- rowers/dataprep.py | 43 ++++++++++++++++++++ rowers/templates/manualadd.html | 38 +++++++++++++++++ rowers/templates/rankings.html | 15 ++++++- rowers/urls.py | 1 + rowers/views.py | 72 +++++++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 rowers/templates/manualadd.html diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 45cfd3d4..f5e70a66 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -555,6 +555,49 @@ def fetchcp(rower,theworkouts,table='cpdata'): return [],[],avgpower2 +# create a new workout from manually entered data +def create_row_df(distance,duration,startdatetime): + + print startdatetime + + nr_strokes = int(distance/10.) + + unixstarttime = arrow.get(startdatetime).timestamp + + print unixstarttime,'aap' + + totalseconds = duration.hour*3600. + totalseconds += duration.minute*60. + totalseconds += duration.second + totalseconds += duration.microsecond/1.e6 + + + spm = 60.*nr_strokes/totalseconds + + step = totalseconds/float(nr_strokes) + + elapsed = np.arange(0,totalseconds+step,step) + + dstep = distance/float(nr_strokes) + + d = np.arange(0,distance+dstep,dstep) + + unixtime = unixstarttime + elapsed + + print unixtime + + pace = 500.*totalseconds/distance + + df = pd.DataFrame({ + 'TimeStamp (sec)': unixtime, + ' Horizontal (meters)': d, + ' Cadence (stokes/min)': spm, + ' Stroke500mPace (sec/500m)':pace, + ' ElapsedTime (sec)':elapsed, + }) + + return df + # Processes painsled CSV file to database diff --git a/rowers/templates/manualadd.html b/rowers/templates/manualadd.html new file mode 100644 index 00000000..60540df9 --- /dev/null +++ b/rowers/templates/manualadd.html @@ -0,0 +1,38 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} +{% load tz %} + + +{% get_current_timezone as TIME_ZONE %} + +{% block content %} +
+

Add Workout Manually

+
+ {% if form.errors %} +

+ Please correct the error{{ form.errors|pluralize }} below. +

+ {% endif %} + +
+ + {{ form.as_table }} +
+ {% csrf_token %} +
+ +
+
+
+ +
+

 

+ +
+
+ + +{% endblock %} diff --git a/rowers/templates/rankings.html b/rowers/templates/rankings.html index e5625f95..741f5a41 100644 --- a/rowers/templates/rankings.html +++ b/rowers/templates/rankings.html @@ -72,7 +72,7 @@

The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.

-

This page will evolve and try to give you guidance on where to improve.

+

Use this form to select a different date range:

@@ -138,6 +138,19 @@

No ranking workouts found

{% endif %} +

Missing your best pieces? Upload stroke data of any Concept2 + ranking piece and they will be automatically added to this page.

+

Don't have stroke data for official Concept2 ranking pieces? + The PRO membership ranking piece functionality + allows you to include your best non ranking pieces and even use + parts of workouts for improved calculation accuracy. +

+ +

Want to add race results but you don't have stroke data? + Click here.

+ +

Scroll down for the chart and pace predictions for ranking pieces.

+
diff --git a/rowers/urls.py b/rowers/urls.py index b31c2be7..46406980 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -126,6 +126,7 @@ urlpatterns = [ url(r'^list-workouts/team/(?P\d+)/$',views.workouts_view), url(r'^list-workouts/(?P\w+.*)/(?P\w+.*)$',views.workouts_view), url(r'^list-workouts/$',views.workouts_view), + url(r'^addmanual/$',views.addmanual_view), url(r'^team-compare-select/team/(?P\d+)/(?P\w+.*)/(?P\w+.*)$',views.team_comparison_select), url(r'^team-compare-select/team/(?P\d+)/$',views.team_comparison_select), url(r'^team-compare-select/(?P\w+.*)/(?P\w+.*)$',views.team_comparison_select), diff --git a/rowers/views.py b/rowers/views.py index 13c9cee9..3f9a38c5 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -3096,6 +3096,78 @@ def histo(request,theuser=0, 'teams':get_my_teams(request.user), }) +# add a workout manually +@login_required() +def addmanual_view(request): + r = Rower.objects.get(user=request.user) + + if request.method == 'POST': + # Form was submitted + form = WorkoutForm(request.POST) + if form.is_valid(): + # Get values from form + name = form.cleaned_data['name'] + date = form.cleaned_data['date'] + starttime = form.cleaned_data['starttime'] + workouttype = form.cleaned_data['workouttype'] + duration = form.cleaned_data['duration'] + distance = form.cleaned_data['distance'] + notes = form.cleaned_data['notes'] + thetimezone = form.cleaned_data['timezone'] + try: + boattype = request.POST['boattype'] + except KeyError: + boattype = '1x' + try: + privacy = request.POST['privacy'] + except KeyError: + privacy = 'visible' + try: + rankingpiece = form.cleaned_data['rankingpiece'] + except KeyError: + rankingpiece =- Workout.objects.get(id=id).rankingpiece + + startdatetime = (str(date) + ' ' + str(starttime)) + startdatetime = datetime.datetime.strptime(startdatetime, + "%Y-%m-%d %H:%M:%S") + startdatetime = timezone.make_aware(startdatetime) + startdatetime = startdatetime.astimezone( + pytz.timezone(thetimezone) + ) + + df = dataprep.create_row_df(distance,duration,startdatetime) + + id,message = dataprep.new_workout_from_df(r,df, + title = name, + parent = None, + ) + + if message: + messages.error(request,message) + + if id: + w = Workout.objects.get(id=id) + w.rankingpiece = rankingpiece + w.notes = notes + w.save() + messages.info(request,'New workout created') + + + initial = { + 'workouttype':'rower', + 'date':datetime.date.today(), + 'starttime':timezone.now(), + 'timezone':r.defaulttimezone, + 'duration':datetime.timedelta(minutes=2), + 'distance':500, + + } + form = WorkoutForm(initial=initial) + + return render(request,'manualadd.html', + {'form':form, + }) + # Show ranking distances including predicted paces @login_required() def rankings_view(request,theuser=0, From ec287cc4b5cb42f9ee5c57e4858a18425b7bd81a Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 18 Nov 2017 17:38:01 -0700 Subject: [PATCH 2/2] manually adding ranking pieces works --- rowers/dataprep.py | 36 +++++++++++++++++++++++++++++------- rowers/views.py | 14 +++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index f5e70a66..f99a9468 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -556,16 +556,15 @@ def fetchcp(rower,theworkouts,table='cpdata'): # create a new workout from manually entered data -def create_row_df(distance,duration,startdatetime): +def create_row_df(r,distance,duration,startdatetime, + title = 'Manually added workout',notes='', + workouttype='rower'): - print startdatetime nr_strokes = int(distance/10.) unixstarttime = arrow.get(startdatetime).timestamp - print unixstarttime,'aap' - totalseconds = duration.hour*3600. totalseconds += duration.minute*60. totalseconds += duration.second @@ -584,19 +583,42 @@ def create_row_df(distance,duration,startdatetime): unixtime = unixstarttime + elapsed - print unixtime - pace = 500.*totalseconds/distance + if workouttype in ['rower','slides','dynamic']: + velo = distance/totalseconds + power = 2.8*velo**3 + else: + power = 0 + df = pd.DataFrame({ 'TimeStamp (sec)': unixtime, ' Horizontal (meters)': d, ' Cadence (stokes/min)': spm, ' Stroke500mPace (sec/500m)':pace, ' ElapsedTime (sec)':elapsed, + ' Power (watts)':power, }) - return df + timestr = strftime("%Y%m%d-%H%M%S") + + csvfilename = 'media/df_' + timestr + '.csv' + df[' ElapsedTime (sec)'] = df['TimeStamp (sec)'] + + row = rrdata(df=df) + + row.write_csv(csvfilename, gzip = True) + + id, message = save_workout_database(csvfilename, r, + title=title, + notes=notes, + dosmooth=False, + workouttype=workouttype, + consistencychecks=False, + totaltime=totalseconds) + + return (id, message) + # Processes painsled CSV file to database diff --git a/rowers/views.py b/rowers/views.py index 3f9a38c5..58cbdee0 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -3135,12 +3135,16 @@ def addmanual_view(request): pytz.timezone(thetimezone) ) - df = dataprep.create_row_df(distance,duration,startdatetime) - id,message = dataprep.new_workout_from_df(r,df, - title = name, - parent = None, - ) + print name + id,message = dataprep.create_row_df(r, + distance, + duration,startdatetime, + title = name, + notes=notes, + workouttype=workouttype) + + if message: messages.error(request,message)