From 9661bb2124eb897ba2166c48ecd96935b2e42280 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 21 Jun 2018 18:13:04 +0200 Subject: [PATCH 1/3] solving issue #331 --- rowers/models.py | 11 ++++++++++- rowers/views.py | 7 +++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index 9278e80b..247c42fc 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -1840,7 +1840,16 @@ class AdvancedWorkoutForm(ModelForm): class RowerExportForm(ModelForm): class Meta: model = Rower - fields = ['stravaexportas'] + fields = [ + 'stravaexportas', + 'polar_auto_import', + 'c2_auto_export', + 'mapmyfitness_auto_export', + 'runkeeper_auto_export', + 'sporttracks_auto_export', + 'strava_auto_export', + 'trainingpeaks_auto_export', + ] # Simple form to set rower's Functional Threshold Power class RowerPowerForm(ModelForm): diff --git a/rowers/views.py b/rowers/views.py index be6afc58..45406548 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -11678,8 +11678,11 @@ def rower_exportsettings_view(request): if request.method == 'POST': form = RowerExportForm(request.POST) if form.is_valid(): - stravaexportas = form.cleaned_data['stravaexportas'] - r.stravaexportas = stravaexportas + cd = form.cleaned_data + + for attr, value in cd.items(): + setattr(r, attr, value) + r.save() else: form = RowerExportForm(instance=r) From e17e5f5a866949238c5cc781b0409b28dae31067 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 21 Jun 2018 18:52:23 +0200 Subject: [PATCH 2/3] adding drive energy --- rowers/dataprep.py | 16 ++++++++++++---- rowers/forms.py | 4 +++- rowers/views.py | 33 +++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index d5c46c6b..c98edd6c 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -2332,8 +2332,16 @@ def workout_normv(w,pp=4.0): v4mean = wavg(df,'v4','deltat') normv = v4mean**(1./pp) - if np.isnan(normv): - return 500./120. - - return normv + df['w4'] = df['driveenergy']**(pp) + w4mean = wavg(df,'w4','deltat') + normw = w4mean**(1./pp) + + + if np.isnan(normv): + normv = 500./120. + + if np.isnan(normw): + normw = 0 + + return normv,normw diff --git a/rowers/forms.py b/rowers/forms.py index ae4fcc53..1ad57343 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -485,11 +485,13 @@ class MyTimeField(forms.TimeField): class PowerIntervalUpdateForm(forms.Form): selectorchoices = ( ('power','Power'), - ('pace','Pace') + ('pace','Pace'), + ('work','Work per Stroke'), ) pace = forms.DurationField(required=False,label='Pace (/500m)') power = forms.IntegerField(required=False,label='Power (W)') + work = forms.IntegerField(required=False,label='Work per Stroke (J)') selector = forms.ChoiceField(choices=selectorchoices, required=True, initial='power', diff --git a/rowers/views.py b/rowers/views.py index 45406548..63764da4 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -11293,7 +11293,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" tss,normp = dataprep.workout_rscore(row) - normv = dataprep.workout_normv(row,pp=8.0) + normv,normw = dataprep.workout_normv(row,pp=8.0) try: avpace = datetime.timedelta(seconds=int(500./normv)) @@ -11304,6 +11304,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" 'power': int(normp), 'pace': avpace, 'selector': 'power', + 'work': int(normw) } powerorpace = 'power' @@ -11337,15 +11338,21 @@ def workout_summary_edit_view(request,id,message="",successmessage="" powerorpace = request.POST['powerorpace'] value_pace = request.POST['value_pace'] value_power = request.POST['value_power'] + value_work = request.POST['value_work'] if powerorpace == 'power': power = int(value_power) pace_secs = 120.0 - else: + work = 400. + elif powerorpace == 'pace': power = 0 try: pace_secs = float(value_pace) except ValueError: pace_secs = float(value_pace.replace(',','.')) + elif powerorpace == 'work': + power = 0 + work = int(value_work) + pace_secs = 120.0 if powerorpace == 'power' and power is not None: try: @@ -11362,6 +11369,13 @@ def workout_summary_edit_view(request,id,message="",successmessage="" debug=False,smoothwindow=15.) except: messages.error(request,'Error updating pace') + elif powerorpace == 'work': + try: + rowdata.updateinterval_metric( + ' WorkPerStroke (joules)',work,mode='larger', + debug=False,smoothwindow=15.) + except: + messages.error(request,'Error updating Work per Stroke') intervalstats = rowdata.allstats() itime,idist,itype = rowdata.intervalstats_values() @@ -11386,7 +11400,8 @@ def workout_summary_edit_view(request,id,message="",successmessage="" formvalues = { 'powerorpace': powerorpace, 'value_power': power, - 'value_pace': pace_secs + 'value_pace': pace_secs, + 'value_work':work, } @@ -11429,6 +11444,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" powerorpace = cd['selector'] power = cd['power'] pace = cd['pace'] + work = cd['work'] try: pace_secs = pace.seconds+pace.microseconds/1.0e6 except AttributeError: @@ -11447,6 +11463,14 @@ def workout_summary_edit_view(request,id,message="",successmessage="" debug=False,smoothwindow=15) except: messages.error(request,'Error updating pace') + elif powerorpace == 'work': + try: + rowdata.updateinterval_metric( + 'driveenergy',work,mode='larger', + debug=False,smoothwindow=15.) + except: + messages.error(request,'Error updating Work per Stroke') + intervalstats = rowdata.allstats() itime,idist,itype = rowdata.intervalstats_values() @@ -11455,7 +11479,8 @@ def workout_summary_edit_view(request,id,message="",successmessage="" formvalues = { 'powerorpace': powerorpace, 'value_power': power, - 'value_pace': pace_secs + 'value_pace': pace_secs, + 'value_work': work, } powerupdateform = PowerIntervalUpdateForm(initial=cd) form = SummaryStringForm() From 7482c6e9e33145f5aa5b96d55a910287f73134f2 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 21 Jun 2018 21:18:51 +0200 Subject: [PATCH 3/3] improved pop ups --- rowers/interactiveplots.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index f377fc84..fc1e88c6 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -2174,7 +2174,7 @@ def interactive_chart(id=0,promember=0,intervaldata = {}): y_range_name = "watermark", ) - plot.line('time','pace',source=source,legend="Pace") + plot.line('time','pace',source=source,legend="Pace",name="pace") plot.title.text = row.name plot.title.text_font_size=value("1.0em") plot.xaxis.axis_label = "Time" @@ -2201,21 +2201,9 @@ def interactive_chart(id=0,promember=0,intervaldata = {}): plot.y_range = Range1d(1.e3*ymin,1.e3*ymax) - hover = plot.select(dict(type=HoverTool)) - - - hover.tooltips = OrderedDict([ - ('Time','@ftime'), - ('Pace','@fpace'), - ('HR','@hr{int}'), - ('SPM','@spm{1.1}'), - ]) - - hover.mode = 'mouse' - plot.extra_y_ranges["spmax"] = Range1d(start=10,end=45) plot.line('time','spm',source=source,color="red", - y_range_name="spmax", legend="Stroke Rate") + y_range_name="spmax", legend="Stroke Rate",name="spm") plot.add_layout(LinearAxis(y_range_name="spmax",axis_label="SPM"),'right') plot.legend.location = "bottom_right" @@ -2240,6 +2228,20 @@ def interactive_chart(id=0,promember=0,intervaldata = {}): right='time_r',source=intervalsource,color='mediumvioletred', y_range_name='spmax',fill_alpha=0.2,line_alpha=0.2) + + hover = plot.select(dict(type=HoverTool)) + + + hover.tooltips = OrderedDict([ + ('Time','@ftime'), + ('Pace','@fpace'), + ('HR','@hr{int}'), + ('SPM','@spm{1.1}'), + ]) + + hover.mode = 'mouse' + hover.names = ["spm","pace"] + script, div = components(plot) return [script,div]