From ae854037f2a2dfa61ffcb3ec69da215ac27fb8fb Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 1 Mar 2017 12:04:44 +0100 Subject: [PATCH 01/12] added check if dataframe is not empty to Empower force curve --- rowers/interactiveplots.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index b8f6147e..e1fc7f60 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -154,6 +154,8 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): except KeyError: pass + if rowdata.empty: + return "","No Valid Data Available","","" catchav = rowdata['catch'].mean() finishav = rowdata['finish'].mean() @@ -348,7 +350,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1, title="Max SPM",callback=callback) callback.args["maxspm"] = slider_spm_max - + distmax = 100+100*int(rowdata['distance'].max()/100.) slider_dist_min = Slider(start=0,end=distmax,value=0,step=1, @@ -386,6 +388,9 @@ def interactive_histoall(theworkouts): rowdata = dataprep.getsmallrowdata_db(['power'],ids=ids,doclean=True) rowdata.dropna(axis=0,how='any',inplace=True) + if rowdata.empty: + return "","No Valid Data Available","","" + histopwr = rowdata['power'].values if len(histopwr) == 0: return "","No valid data available","","" From 9bf485f596ad098f366aa8007cf6c2f42d99eeaa Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 1 Mar 2017 15:00:58 +0100 Subject: [PATCH 02/12] adding oarlength and inboard --- rowers/dataprep.py | 16 ++++++++++++---- rowers/models.py | 6 ++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 646ab4fa..8365cee1 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -8,7 +8,7 @@ from rowers.tasks import handle_sendemail_unrecognized from rowingdata import rower as rrower from rowingdata import main as rmain -from rowingdata import get_file_type +from rowingdata import get_file_type,get_empower_rigging from pandas import DataFrame,Series from pytz import timezone as tz,utc @@ -326,7 +326,8 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower', dosummary=True,title='Workout', notes='',totaldist=0,totaltime=0, summary='', - makeprivate=False): + makeprivate=False, + oarlength=2.89,inboard=0.88): message = None powerperc = 100*np.array([r.pw_ut2, r.pw_ut1, @@ -446,6 +447,7 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower', csvfilename=f2,notes=notes,summary=summary, maxhr=maxhr,averagehr=averagehr, startdatetime=workoutstartdatetime, + inboard=inboard,oarlength=oarlength, privacy=privacy) @@ -463,6 +465,8 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower', return (w.id,message) def handle_nonpainsled(f2,fileformat,summary=''): + oarlength = 2.89 + inboard = 0.88 # handle RowPro: if (fileformat == 'rp'): row = RowProParser(f2) @@ -506,6 +510,7 @@ def handle_nonpainsled(f2,fileformat,summary=''): if (fileformat == 'speedcoach2'): row = SpeedCoach2Parser(f2) try: + oarlength,inboard = get_empower_rigging(f2) summary = row.allstats() except: pass @@ -534,7 +539,7 @@ def handle_nonpainsled(f2,fileformat,summary=''): except: os.remove(f_to_be_deleted+'.gz') - return (f2,summary) + return (f2,summary,oarlength,inboard) # Create new workout from file and store it in the database # This routine should be used everywhere in views.py and mailprocessing.py @@ -547,6 +552,8 @@ def new_workout_from_file(r,f2, message = None fileformat = get_file_type(f2) summary = '' + oarlength = 2.89 + inboard = 0.88 if len(fileformat)==3 and fileformat[0]=='zip': f_to_be_deleted = f2 with zipfile.ZipFile(f2) as z: @@ -590,7 +597,7 @@ def new_workout_from_file(r,f2, # handle non-Painsled by converting it to painsled compatible CSV if (fileformat != 'csv'): - f2,summary = handle_nonpainsled(f2,fileformat,summary=summary) + f2,summary,oarlength,inboard = handle_nonpainsled(f2,fileformat,summary=summary) dosummary = (fileformat != 'fit') @@ -599,6 +606,7 @@ def new_workout_from_file(r,f2, makeprivate=makeprivate, dosummary=dosummary, summary=summary, + inboard=inboard,oarlength=oarlength, title=title) return (id,message,f2) diff --git a/rowers/models.py b/rowers/models.py index c52c34ed..784a5943 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -393,6 +393,12 @@ class Workout(models.Model): maxhr = models.IntegerField(blank=True,null=True) uploadedtostrava = models.IntegerField(default=0) uploadedtosporttracks = models.IntegerField(default=0) + + # empower stuff + inboard = models.FloatField(default=0.88) + oarlength = models.FloatField(default=2.89) + + notes = models.CharField(blank=True,null=True,max_length=1000) summary = models.TextField(blank=True) privacy = models.CharField(default='visible',max_length=30, From 82c182f6570998e8383ee70f42bbcf8cc58836f4 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 1 Mar 2017 15:40:16 +0100 Subject: [PATCH 03/12] improved empower calculation of drive length --- rowers/dataprep.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 8365cee1..f0468037 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -31,7 +31,7 @@ import os import pandas as pd import numpy as np import itertools - +import math from tasks import handle_sendemail_unrecognized from django.conf import settings @@ -460,7 +460,7 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower', # put stroke data in database res = dataprep(row.df,id=w.id,bands=True, - barchart=True,otwpower=True,empower=True) + barchart=True,otwpower=True,empower=True,inboard=inboard) return (w.id,message) @@ -892,7 +892,7 @@ def smalldataprep(therows,xparam,yparam1,yparam2): # saves it to the stroke_data table in the database # Takes a rowingdata object's DataFrame as input def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True, - empower=True): + empower=True,inboard=0.88): rowdatadf.set_index([range(len(rowdatadf))],inplace=True) t = rowdatadf.ix[:,'TimeStamp (sec)'] t = pd.Series(t-rowdatadf.ix[0,'TimeStamp (sec)']) @@ -1005,7 +1005,11 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True, finish = rowdatadf.ix[:,'finish'] peakforceangle = rowdatadf.ix[:,'peakforceangle'] driveenergy = rowdatadf.ix[:,'driveenergy'] - drivelength = driveenergy/(averageforce*4.44822) + arclength = (inboard-0.05)*(np.radians(finish)-np.radians(catch)) + if arclength.mean()>0: + drivelength = arclength + else: + drivelength = driveenergy/(averageforce*4.44822) slip = rowdatadf.ix[:,'slip'] if windowsize > 3 and windowsize Date: Thu, 2 Mar 2017 11:32:53 +0100 Subject: [PATCH 04/12] work per stroke slider on flex chart --- rowers/dataprep.py | 2 +- rowers/interactiveplots.py | 65 +++++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index f0468037..c8a75af0 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -433,7 +433,7 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower', privacy = 'visible' # check for duplicate start times - ws = Workout.objects.filter(starttime=workoutstarttime, + ws = Workout.objects.filter(startdatetime=workoutstartdatetime, user=r) if (len(ws) != 0): message = "Warning: This workout probably already exists in the database" diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index e1fc7f60..89bc1cee 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -904,13 +904,13 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, yparamname2 = axlabels[yparam2] - datadf = datadf[datadf[yparam1] > 0] + #datadf = datadf[datadf[yparam1] > 0] - datadf = datadf[datadf[xparam] > 0] + #datadf = datadf[datadf[xparam] > 0] - if yparam2 != 'None': - datadf = datadf[datadf[yparam2] > 0] + #if yparam2 != 'None': + # datadf = datadf[datadf[yparam2] > 0] # check if dataframe not empty if datadf.empty: @@ -1104,9 +1104,9 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, x1means.location = xm y1means.location = ym1 y2means.location = ym2 - y1label.text = yname1+': '+ym1.toFixed(2) - y2label.text = yname2+': '+ym2.toFixed(2) - xlabel.text = xname+': '+xm.toFixed(2) + y1label.text = yname1+': '+(ym1).toFixed(2) + y2label.text = yname2+': '+(ym2).toFixed(2) + xlabel.text = xname+': '+(xm).toFixed(2) source2.trigger('change'); """) @@ -1162,7 +1162,7 @@ def interactive_flex_chart2(id=0,promember=0, #rowdata,row = dataprep.getrowdata_db(id=id) columns = [xparam,yparam1,yparam2, 'ftime','distance','fpace', - 'power','hr','spm', + 'power','hr','spm','driveenergy', 'time','pace','workoutstate'] rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True) @@ -1405,6 +1405,7 @@ def interactive_flex_chart2(id=0,promember=0, var y1 = data['y1'] var y2 = data['y2'] var spm1 = data['spm'] + var driveenergy1 = data['driveenergy'] var time1 = data['time'] var pace1 = data['pace'] var hr1 = data['hr'] @@ -1419,6 +1420,8 @@ def interactive_flex_chart2(id=0,promember=0, var maxspm = maxspm.value var mindist = mindist.value var maxdist = maxdist.value + var minwork = minwork.value + var maxwork = maxwork.value var xm = 0 var ym1 = 0 var ym2 = 0 @@ -1443,21 +1446,22 @@ def interactive_flex_chart2(id=0,promember=0, for (i=0; i=minspm && spm1[i]<=maxspm) { if (distance1[i]>=mindist && distance1[i]<=maxdist) { - data2['x1'].push(x1[i]) - data2['y1'].push(y1[i]) - data2['y2'].push(y2[i]) - data2['spm'].push(spm1[i]) - data2['time'].push(time1[i]) - data2['fpace'].push(fpace1[i]) - data2['pace'].push(pace1[i]) - data2['hr'].push(hr1[i]) - data2['distance'].push(distance1[i]) - data2['power'].push(power1[i]) - - xm += x1[i] - ym1 += y1[i] - ym2 += y2[i] + if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) { + data2['x1'].push(x1[i]) + data2['y1'].push(y1[i]) + data2['y2'].push(y2[i]) + data2['spm'].push(spm1[i]) + data2['time'].push(time1[i]) + data2['fpace'].push(fpace1[i]) + data2['pace'].push(pace1[i]) + data2['hr'].push(hr1[i]) + data2['distance'].push(distance1[i]) + data2['power'].push(power1[i]) + xm += x1[i] + ym1 += y1[i] + ym2 += y2[i] + } } } } @@ -1488,6 +1492,15 @@ def interactive_flex_chart2(id=0,promember=0, title="Max SPM",callback=callback) callback.args["maxspm"] = slider_spm_max + slider_work_min = Slider(start=0.0, end=1000,value=0.0, step=10, + title="Min Work per Stroke",callback=callback) + callback.args["minwork"] = slider_work_min + + + slider_work_max = Slider(start=0.0, end=1000,value=1000.0, step=10, + title="Max Work per Stroke",callback=callback) + callback.args["maxwork"] = slider_work_max + distmax = 100+100*int(rowdata['distance'].max()/100.) slider_dist_min = Slider(start=0,end=distmax,value=0,step=1, @@ -1500,9 +1513,11 @@ def interactive_flex_chart2(id=0,promember=0, callback.args["maxdist"] = slider_dist_max layout = layoutrow([layoutcolumn([slider_spm_min, - slider_spm_max, - slider_dist_min, - slider_dist_max, + slider_spm_max, + slider_dist_min, + slider_dist_max, + slider_work_min, + slider_work_max, ], ), plot]) From 992224731f4c785e1b4fc8ebf88524f225bd1645 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 2 Mar 2017 14:53:18 +0100 Subject: [PATCH 05/12] flex chart work per stroke slider --- rowers/dataprep.py | 20 ++++++-- rowers/interactiveplots.py | 98 +++++++++++++++++++++++++++----------- 2 files changed, 86 insertions(+), 32 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index c8a75af0..6d9a5cf3 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -102,6 +102,11 @@ def clean_df_stats(datadf,workstrokesonly=True,ignorehr=True, except KeyError: pass + try: + datadf['hr'] = datadf['hr']+10 + except KeyError: + pass + datadf=datadf.clip(lower=0) datadf.replace(to_replace=0,value=np.nan,inplace=True) @@ -116,6 +121,11 @@ def clean_df_stats(datadf,workstrokesonly=True,ignorehr=True, except KeyError: pass + try: + datadf['hr'] = datadf['hr']-10 + except KeyError: + pass + # clean data for useful ranges per column if not ignorehr: try: @@ -222,11 +232,11 @@ def clean_df_stats(datadf,workstrokesonly=True,ignorehr=True, pass - try: - mask = datadf['catch'] > -30. - datadf.loc[mask,'catch'] = np.nan - except KeyError: - pass + try: + mask = datadf['catch'] > -30. + datadf.loc[mask,'catch'] = np.nan + except KeyError: + pass workoutstateswork = [1,4,5,8,9,6,7] diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 89bc1cee..3dca55c2 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -139,9 +139,10 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): columns = ['catch','slip','wash','finish','averageforce', 'peakforceangle','peakforce','spm','distance', - 'workoutstate'] + 'workoutstate','driveenergy'] rowdata = dataprep.getsmallrowdata_db(columns,ids=ids) + rowdata.dropna(axis=1,how='all',inplace=True) rowdata.dropna(axis=0,how='any',inplace=True) workoutstateswork = [1,4,5,8,9,6,7] @@ -278,6 +279,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): var y = data['y'] var spm1 = data2['spm'] var distance1 = data2['distance'] + var driveenergy1 = data2['driveenergy'] var thresholdforce = y[1] @@ -293,6 +295,8 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): var maxspm = maxspm.value var mindist = mindist.value var maxdist = maxdist.value + var minwork = minwork.value + var maxwork = maxwork.value var catchav = 0 var finishav = 0 @@ -307,14 +311,16 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): for (i=0; i=minspm && spm1[i]<=maxspm) { if (distance1[i]>=mindist && distance1[i]<=maxdist) { - catchav += c[i] - finishav += finish[i] - slipav += slip[i] - washav += wash[i] - peakforceangleav += peakforceangle[i] - averageforceav += averageforce[i] - peakforceav += peakforce[i] - count += 1 + if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) { + catchav += c[i] + finishav += finish[i] + slipav += slip[i] + washav += wash[i] + peakforceangleav += peakforceangle[i] + averageforceav += averageforce[i] + peakforceav += peakforce[i] + count += 1 + } } } } @@ -351,6 +357,15 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): title="Max SPM",callback=callback) callback.args["maxspm"] = slider_spm_max + slider_work_min = Slider(start=0, end=1500,value=0, step=10, + title="Min Work per Stroke",callback=callback) + callback.args["minwork"] = slider_work_min + + + slider_work_max = Slider(start=0, end=1500,value=1500, step=10, + title="Max Work per Stroke",callback=callback) + callback.args["maxwork"] = slider_work_max + distmax = 100+100*int(rowdata['distance'].max()/100.) slider_dist_min = Slider(start=0,end=distmax,value=0,step=1, @@ -363,9 +378,11 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): callback.args["maxdist"] = slider_dist_max layout = layoutrow([layoutcolumn([slider_spm_min, - slider_spm_max, - slider_dist_min, - slider_dist_max, + slider_spm_max, + slider_dist_min, + slider_dist_max, + slider_work_min, + slider_work_max, ], ), plot]) @@ -897,7 +914,8 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, # datadf = dataprep.smalldataprep(theworkouts,xparam,yparam1,yparam2) ids = [int(w.id) for w in theworkouts] - datadf = dataprep.getsmallrowdata_db([xparam,yparam1,yparam2],ids=ids,doclean=False) + columns = [xparam,yparam1,yparam2,'spm','driveenergy','distance'] + datadf = dataprep.getsmallrowdata_db(columns,ids=ids,doclean=False) yparamname1 = axlabels[yparam1] if yparam2 != 'None': @@ -1053,6 +1071,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, var y2 = data['y2'] var spm1 = data['spm'] var distance1 = data['distance'] + var driveenergy1 = data['driveenergy'] var xname = data['xname'][0] var yname1 = data['yname1'][0] var yname2 = data['yname2'][0] @@ -1061,6 +1080,8 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, var maxspm = maxspm.value var mindist = mindist.value var maxdist = maxdist.value + var minwork = minwork.value + var maxwork = maxwork.value var xm = 0 var ym1 = 0 var ym2 = 0 @@ -1080,16 +1101,17 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, for (i=0; i=minspm && spm1[i]<=maxspm) { if (distance1[i]>=mindist && distance1[i]<=maxdist) { - data2['x1'].push(x1[i]) - data2['y1'].push(y1[i]) - data2['y2'].push(y2[i]) - data2['spm'].push(spm1[i]) - data2['distance'].push(distance1[i]) - - xm += x1[i] - ym1 += y1[i] - ym2 += y2[i] + if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) { + data2['x1'].push(x1[i]) + data2['y1'].push(y1[i]) + data2['y2'].push(y2[i]) + data2['spm'].push(spm1[i]) + data2['distance'].push(distance1[i]) + xm += x1[i] + ym1 += y1[i] + ym2 += y2[i] + } } } } @@ -1120,6 +1142,15 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, title="Max SPM",callback=callback) callback.args["maxspm"] = slider_spm_max + slider_work_min = Slider(start=0.0, end=1500,value=0.0, step=10, + title="Min Work per Stroke",callback=callback) + callback.args["minwork"] = slider_work_min + + + slider_work_max = Slider(start=0.0, end=1500,value=1500.0, step=10, + title="Max Work per Stroke",callback=callback) + callback.args["maxwork"] = slider_work_max + distmax = 100+100*int(datadf['distance'].max()/100.) slider_dist_min = Slider(start=0,end=distmax,value=0,step=1, @@ -1132,9 +1163,11 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, callback.args["maxdist"] = slider_dist_max layout = layoutrow([layoutcolumn([slider_spm_min, - slider_spm_max, - slider_dist_min, - slider_dist_max, + slider_spm_max, + slider_dist_min, + slider_dist_max, + slider_work_min, + slider_work_max, ], ), plot]) @@ -1166,7 +1199,9 @@ def interactive_flex_chart2(id=0,promember=0, 'time','pace','workoutstate'] rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True) + rowdata.dropna(axis=1,how='all',inplace=True) + rowdata.dropna(axis=0,how='any',inplace=True) row = Workout.objects.get(id=id) if rowdata.empty: @@ -1492,12 +1527,12 @@ def interactive_flex_chart2(id=0,promember=0, title="Max SPM",callback=callback) callback.args["maxspm"] = slider_spm_max - slider_work_min = Slider(start=0.0, end=1000,value=0.0, step=10, + slider_work_min = Slider(start=0.0, end=1500,value=0.0, step=10, title="Min Work per Stroke",callback=callback) callback.args["minwork"] = slider_work_min - slider_work_max = Slider(start=0.0, end=1000,value=1000.0, step=10, + slider_work_max = Slider(start=0.0, end=1500,value=1500.0, step=10, title="Max Work per Stroke",callback=callback) callback.args["maxwork"] = slider_work_max @@ -1532,7 +1567,9 @@ def interactive_flex_chart2(id=0,promember=0, def interactive_bar_chart(id=0,promember=0): # check if valid ID exists (workout exists) rowdata,row = dataprep.getrowdata_db(id=id) + rowdata.dropna(axis=1,how='all',inplace=True) rowdata.dropna(axis=0,how='any',inplace=True) + if rowdata.empty: return "","No Valid Data Available" @@ -1630,7 +1667,9 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', 'workoutid'] datadf = dataprep.getsmallrowdata_db(columns,ids=ids) + datadf.dropna(axis=1,how='all',inplace=True) datadf.dropna(axis=0,how='any',inplace=True) + tseconds = datadf.ix[:,'time'] yparamname = axlabels[yparam] @@ -1792,8 +1831,11 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm', rowdata1[n].fillna(value=0,inplace=True) rowdata2[n].fillna(value=0,inplace=True) + rowdata1.dropna(axis=1,how='all',inplace=True) rowdata1.dropna(axis=0,how='any',inplace=True) + rowdata2.dropna(axis=1,how='all',inplace=True) rowdata2.dropna(axis=0,how='any',inplace=True) + row1 = Workout.objects.get(id=id1) row2 = Workout.objects.get(id=id2) @@ -1963,7 +2005,9 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm', def interactive_otw_advanced_pace_chart(id=0,promember=0): # check if valid ID exists (workout exists) rowdata,row = dataprep.getrowdata_db(id=id) + rowdata.dropna(axis=1,how='all',inplace=True) rowdata.dropna(axis=0,how='any',inplace=True) + if rowdata.empty: return "","No Valid Data Available" From 866a4123b427e0410554d456a19c20d0917f136c Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 2 Mar 2017 20:52:10 +0100 Subject: [PATCH 06/12] images on comment page --- rowers/views.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/rowers/views.py b/rowers/views.py index a025f86e..67715fb1 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -3692,13 +3692,27 @@ def workout_comment_view(request,id=0): return HttpResponseRedirect(url) form = WorkoutCommentForm() - - return render(request, - 'workout_comments.html', - {'workout':w, - 'comments':comments, - 'form':form, - }) + + g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") + + if (len(g)<=3): + return render(request, + 'workout_comments.html', + {'workout':w, + 'graphs1':g[0:3], + 'comments':comments, + 'form':form, + }) + else: + return render(request, + 'workout_comments.html', + {'workout':w, + 'graphs1':g[0:3], + 'graphs1':g[3:6], + 'comments':comments, + 'form':form, + }) + # The basic edit page @login_required() From 12ecd3d4e914e7fc9c4a0e33725bd54b8f616ab9 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 3 Mar 2017 08:23:05 +0100 Subject: [PATCH 07/12] added link back to workout on graph page --- rowers/templates/show_graph.html | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/rowers/templates/show_graph.html b/rowers/templates/show_graph.html index 1ce9ddfd..0b9897b0 100644 --- a/rowers/templates/show_graph.html +++ b/rowers/templates/show_graph.html @@ -6,10 +6,21 @@ {% block content %}

{{ workout.name }}

-
+
+{% if user.is_authenticated and user == rower.user %} +

+ Edit Workout +

+{% else %} +

+ See Workout +

+{% endif %} +
+
{% if user.is_authenticated and user == rower.user %}

- Delete + Delete Chart

{% else %}

 

From 5e5cc36da06b940ee3453d2d87aff6258afd2165 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 3 Mar 2017 15:41:51 +0100 Subject: [PATCH 08/12] added effective drive length --- rowers/dataprep.py | 5 ++ rowers/forms.py | 2 +- rowers/interactiveplots.py | 93 +++++++------------ rowers/models.py | 4 +- rowers/templates/developers.html | 8 +- rowers/templates/flexchart3otw.html | 134 +++++++++------------------- rowers/views.py | 27 ++++-- 7 files changed, 109 insertions(+), 164 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 6d9a5cf3..1e36ace9 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1020,7 +1020,10 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True, drivelength = arclength else: drivelength = driveenergy/(averageforce*4.44822) + slip = rowdatadf.ix[:,'slip'] + totalangle = finish-catch + effectiveangle = finish-wash-catch-slip if windowsize > 3 and windowsize
  • Advantages
      -
    • It may take up to five minutes for the workout to show up - on the site.
    • +
    • It's a simple process, which can be automated.
  • Disadvantages
      -
    • It's a simple process, which can be automated.
    • +
    • It may take up to five minutes for the workout to show up + on the site.
  • @@ -86,7 +86,7 @@
  • The API is not stable and not fully tested yet.
  • You need to register your app with us. We can revoke your permissions if you misuse them.
  • -
  • The first time user must grant permissions to your app.
  • +
  • The user user must grant permissions to your app.
  • You need to manage authorization tokens.
  • diff --git a/rowers/templates/flexchart3otw.html b/rowers/templates/flexchart3otw.html index 4697f3a7..923edcbb 100644 --- a/rowers/templates/flexchart3otw.html +++ b/rowers/templates/flexchart3otw.html @@ -51,41 +51,19 @@ @@ -93,38 +71,23 @@
    -