From 5da598e9c8a12b330666b3fdbad0be1eafa45216 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 1 Dec 2016 11:23:35 +0100 Subject: [PATCH 1/3] Dataprep for Empower data --- rowers/dataprep.py | 9 +++++++++ rowers/interactiveplots.py | 23 ++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 31720733..a9a17c89 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -350,6 +350,15 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True, driveenergy = rowdatadf.ix[:,'driveenergy'] drivelength = driveenergy/(averageforce*4.44822) slip = rowdatadf.ix[:,'slip'] + if windowsize > 3: + wash = savgol_filter(wash,windowsize,3) + catch = savgol_filter(catch,windowsize,3) + finish = savgol_filter(finish,windowsize,3) + peakforce = savgol_filter(peakforce,windowsize,3) + averageforce = savgol_filter(averageforce,windowsize,3) + peakforceangle = savgol_filter(peakforceangle,windowsize,3) + driveenergy = savgol_filter(driveenergy,windowsize,3) + drivelength = savgol_filter(drivelength,windowsize,3) data['wash'] = wash data['catch'] = catch data['slip'] = slip diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 12bcbecb..c476e051 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -885,6 +885,11 @@ def interactive_flex_chart2(id=0,promember=0, 'forceratio': 'Average/Peak Drive Force Ratio', 'driveenergy': 'Work per Stroke (J)', 'drivespeed': 'Drive Speed (m/s)', + 'slip': 'Slip (degrees)', + 'catch': 'Catch (degrees)', + 'finish': 'Finish (degrees)', + 'wash': 'Wash (degrees)', + 'peakforceangle': 'Peak Force Angle (degrees)', 'None': '', } @@ -899,12 +904,17 @@ def interactive_flex_chart2(id=0,promember=0, 'drivelength':0.5, 'driveenergy': 0, 'drivespeed': 0, + 'slip': 0, + 'catch': -70, + 'finish': 30, + 'wash': 0, + 'peakforceangle': -20, } yaxmaxima = { 'hr':200, 'spm':45, - 'pace': 1.0e3*90, + 'pace': 1.0e3*75, 'power': 600, 'averageforce':200, 'peakforce':400, @@ -912,9 +922,20 @@ def interactive_flex_chart2(id=0,promember=0, 'drivelength':2.0, 'driveenergy': 1000, 'drivespeed':4, + 'slip': 30, + 'catch': -30, + 'finish': 70, + 'wash': 30, + 'peakforceangle': 20, } rowdata,row = dataprep.getrowdata_db(id=id) + #columns = [xparam,yparam1,yparam2, + # 'ftime','distance','fpace', + # 'power','hr','spm', + # 'time','pace'] + #rowdata = dataprep.getsmallrowdata_db(columns,ids=[id]) + #row = Workout.objects.get(id=id) if rowdata.empty: return "","CSV Data File Not Found" From ec93030ba6a446f8a729e801d8037a6bee7e7930 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 1 Dec 2016 14:15:42 +0100 Subject: [PATCH 2/3] NK Empower tools --- rowers/dataprep.py | 1 + rowers/templates/flexchart3otw.html | 203 ++++++++++++++++++++++++++++ rowers/views.py | 49 ++++--- 3 files changed, 237 insertions(+), 16 deletions(-) create mode 100644 rowers/templates/flexchart3otw.html diff --git a/rowers/dataprep.py b/rowers/dataprep.py index a9a17c89..ad1d5ccb 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -352,6 +352,7 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True, slip = rowdatadf.ix[:,'slip'] if windowsize > 3: wash = savgol_filter(wash,windowsize,3) + slip = savgol_filter(slip,windowsize,3) catch = savgol_filter(catch,windowsize,3) finish = savgol_filter(finish,windowsize,3) peakforce = savgol_filter(peakforce,windowsize,3) diff --git a/rowers/templates/flexchart3otw.html b/rowers/templates/flexchart3otw.html new file mode 100644 index 00000000..812361c5 --- /dev/null +++ b/rowers/templates/flexchart3otw.html @@ -0,0 +1,203 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} +{% load tz %} + +{% block title %} Flexible Plot {% endblock %} + +{% localtime on %} +{% block content %} + +{{ js_res | safe }} +{{ css_res| safe }} + + + + + +{{ the_script |safe }} + + + + + + + +

 

+ +
+ + +
+ + + + + + +
+ +
+
+
+ {% csrf_token %} + {% if workstrokesonly %} + + {% else %} + + {% endif %} + +
+ If your data source allows, this will show or hide strokes taken during rest intervals. +
+
+ Line Plot +
+ +
+ +
+ +
+ + + {{ the_div|safe }} + +
+ + +{% endblock %} +{% endlocaltime %} diff --git a/rowers/views.py b/rowers/views.py index 06ec779b..0b1f0ff4 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -2606,22 +2606,39 @@ def workout_flexchart3_view(request,id=0,xparam='distance',yparam1='pace', div = res[1] js_resources = res[2] css_resources = res[3] - - return render(request, - 'flexchart3.html', - {'the_script':script, - 'the_div':div, - 'js_res': js_resources, - 'css_res':css_resources, - 'id':id, - 'xparam':xparam, - 'yparam1':yparam1, - 'yparam2':yparam2, - 'plottype':plottype, - 'mayedit':mayedit, - 'promember':promember, - 'workstrokesonly': not workstrokesonly, - }) + + if row.workouttype == 'water': + return render(request, + 'flexchart3otw.html', + {'the_script':script, + 'the_div':div, + 'js_res': js_resources, + 'css_res':css_resources, + 'id':id, + 'xparam':xparam, + 'yparam1':yparam1, + 'yparam2':yparam2, + 'plottype':plottype, + 'mayedit':mayedit, + 'promember':promember, + 'workstrokesonly': not workstrokesonly, + }) + else: + return render(request, + 'flexchart3.html', + {'the_script':script, + 'the_div':div, + 'js_res': js_resources, + 'css_res':css_resources, + 'id':id, + 'xparam':xparam, + 'yparam1':yparam1, + 'yparam2':yparam2, + 'plottype':plottype, + 'mayedit':mayedit, + 'promember':promember, + 'workstrokesonly': not workstrokesonly, + }) def testbokeh(request): From 2bef89bbb6a1b911042d239ac70c9ac94c0dcfb9 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 1 Dec 2016 14:30:52 +0100 Subject: [PATCH 3/3] Updated test suite --- rowers/templates/about_us.html | 12 +++++++++--- rowers/tests.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/rowers/templates/about_us.html b/rowers/templates/about_us.html index f12f636b..c7c998c7 100644 --- a/rowers/templates/about_us.html +++ b/rowers/templates/about_us.html @@ -94,14 +94,18 @@ and inspired by the RowPro Dan Burpee spreadsheet

Beyond the basics, rowsandall.com provides a rich tool set for OTW rowing. You can use it to estimate stroke power and to correct - for the effects of wind and current. For indoor rowing, when used - with painsled, the tools enable graphical analsis of stroke metrics + for the effects of wind and current. For indoor rowing, when + used with painsled, and OTW rowing, when used + with a NK Empower Oarlock, + the tools enable graphical analsis of stroke metrics including:

  • Peak and average force
  • drive length
  • work per stroke
  • drive and recovery time
  • +
  • catch and finish angles (OTW)
  • +
  • slip and wash (OTW)
These can be analyzed versus time, distance, stroke rate or other @@ -138,6 +142,8 @@ You will be taken to the secure PayPal payment site.

    +
  • 2016-12-01 Support for NK Empower Oarlock parameters (catch and + finish angles, slip and wash, and power as measured by the Oarlock
  • 2016-11-10 Power based Pie Charts
  • 2016-11-01 Sliders to select subsets of data on some plots
  • 2016-11-01 Emailing workouts to workouts@rowsandall.com
  • @@ -155,7 +161,7 @@ You will be taken to the secure PayPal payment site.
  • 2016-06-08 Added possibility to upload CrewNerd summary CSV file for Premium Members
  • 2016-06-08 Added workout summaries
  • 2016-06-05 Export to Strava is working
  • -
  • 2016-06-01 We're approved on the Concept2 logbook!!!! +
  • 2016-06-01 We're approved on the Concept2 logbook!!!!

diff --git a/rowers/tests.py b/rowers/tests.py index 0e0c4acd..2ee797c7 100644 --- a/rowers/tests.py +++ b/rowers/tests.py @@ -690,6 +690,37 @@ class ViewTest(TestCase): os.remove(f_to_be_deleted) + def test_upload_view_SpeedCoach2v127intervals(self): + self.c.login(username='john',password='koeinsloot') + + filename = 'C:\\python\\rowingdata\\testdata\\SpeedCoach2Link_interval.csv' + f = open(filename,'rb') + file_data = {'file': f} + + form_data = { + 'title':'test', + 'workouttype':'water', + 'notes':'aap noot mies', + 'make_plot':False, + 'upload_to_c2':False, + 'plottype':'timeplot', + 'file': f, + } + + form = DocumentsForm(form_data,file_data) + + response = self.c.post('/rowers/workout/upload/', form_data, follow=True) + f.close() + self.assertRedirects(response, expected_url='/rowers/workout/1/edit', + status_code=302,target_status_code=200) + + self.assertEqual(response.status_code, 200) + + w = Workout.objects.get(id=1) + f_to_be_deleted = w.csvfilename + os.remove(f_to_be_deleted) + + def test_upload_view_TCX_NoHR(self): self.c.login(username='john',password='koeinsloot')