diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index cb226c5f..eeaa2b64 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -95,6 +95,23 @@ from scipy.signal import savgol_filter
import datetime
+def filter_df(datadf,fieldname,value,largerthan=True):
+
+ try:
+ x = datadf[fieldname]
+ except KeyError:
+ return datadf
+
+ if largerthan:
+ mask = datadf[fieldname] < value
+ else:
+ mask = datadf[fieldname] >= value
+
+ datadf.loc[mask,fieldname] = np.nan
+
+
+ return datadf
+
def clean_df_stats(datadf,workstrokesonly=True,ignorehr=True,
ignoreadvanced=False):
# clean data remove zeros and negative values
diff --git a/rowers/forms.py b/rowers/forms.py
index 69b6870f..061ec014 100644
--- a/rowers/forms.py
+++ b/rowers/forms.py
@@ -300,6 +300,18 @@ parchoices = list(sorted(formaxlabels.items(), key = lambda x:x[1]))
class BoxPlotChoiceForm(forms.Form):
yparam = forms.ChoiceField(choices=parchoices,initial='spm',
label='Metric')
+ spmmin = forms.FloatField(initial=15,
+ required=False,label = 'Min SPM')
+ spmmax = forms.FloatField(initial=55,
+ required=False,label = 'Max SPM')
+ workmin = forms.FloatField(initial=0,
+ required=False,label = 'Min Work per Stroke')
+ workmax = forms.FloatField(initial=1500,
+ required=False,label = 'Max Work per Stroke')
+
+ includereststrokes = forms.BooleanField(initial=False,
+ required=False,
+ label='Include Rest Strokes')
class ChartParamChoiceForm(forms.Form):
plotchoices = (
diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py
index 920b4677..6315340b 100644
--- a/rowers/interactiveplots.py
+++ b/rowers/interactiveplots.py
@@ -88,12 +88,19 @@ from rowers.dataprep import nicepaceformat,niceformat
from rowers.dataprep import timedeltaconv
def interactive_boxchart(datadf,fieldname,extratitle=''):
+
+ if datadf.empty:
+ return '','It looks like there are no data matching your filter'
+
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,resize'
+
plot = BoxPlot(datadf, values=fieldname, label='date',
legend=False,
title=axlabels[fieldname]+' '+extratitle,
outliers=False,
tools=TOOLS,
+ toolbar_location="above",
+ toolbar_sticky=False,
x_mapper_type='datetime')
yrange1 = Range1d(start=yaxminima[fieldname],end=yaxmaxima[fieldname])
@@ -133,12 +140,12 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
plot.xaxis.major_label_orientation = pi/4
-
+
script, div = components(plot)
-
return script,div
+
def interactive_forcecurve(theworkouts,workstrokesonly=False):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
diff --git a/rowers/templates/boxplot.html b/rowers/templates/boxplot.html
index 45b14144..bbb5ebd7 100644
--- a/rowers/templates/boxplot.html
+++ b/rowers/templates/boxplot.html
@@ -34,28 +34,35 @@
-
-
Box Chart
-
-
-
-
-
-
- {{ the_div|safe }}
+
Box Chart
+
+
+ {{ the_div|safe }}
+
+
+
+
+
+
+ You can use the form above to change the metric or filter the data.
+ Set Min SPM and Max SPM to select only strokes in a certain range of
+ stroke rates.
+ Set Work per Stroke to a minimum value to remove "paddle" strokes or turns.
+
+
diff --git a/rowers/views.py b/rowers/views.py
index 82cb4450..ece0cf1e 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -3043,6 +3043,15 @@ def boxplot_view(request,userid=0,
cd = form.cleaned_data
workouts = cd['workouts']
plotfield = chartform.cleaned_data['yparam']
+ includereststrokes = chartform.cleaned_data['includereststrokes']
+ request.session['includereststrokes'] = includereststrokes
+ workstrokesonly = not includereststrokes
+
+ spmmin = chartform.cleaned_data['spmmin']
+ spmmax = chartform.cleaned_data['spmmax']
+ workmin = chartform.cleaned_data['workmin']
+ workmax = chartform.cleaned_data['workmax']
+
ids = [int(w.id) for w in workouts]
request.session['ids'] = ids
@@ -3058,12 +3067,25 @@ def boxplot_view(request,userid=0,
fieldlist,fielddict = dataprep.getstatsfields()
- fieldlist = [plotfield,'workoutid']
+ fieldlist = [plotfield,'workoutid','spm','driveenergy',
+ 'workoutstate']
# prepare data frame
datadf = dataprep.read_cols_df_sql(ids,fieldlist)
datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)
+
+ datadf = dataprep.filter_df(datadf,'spm',spmmin,
+ largerthan=True)
+ datadf = dataprep.filter_df(datadf,'spm',spmmax,
+ largerthan=False)
+ datadf = dataprep.filter_df(datadf,'driveenergy',workmin,
+ largerthan=True)
+ datadf = dataprep.filter_df(datadf,'driveneergy',workmax,
+ largerthan=False)
+
+ datadf.dropna(axis=0,how='any',inplace=True)
+
datadf['workoutid'].replace(datemapping,inplace=True)
datadf.rename(columns={"workoutid":"date"},inplace=True)
datadf = datadf.sort_values(['date'])
@@ -3093,6 +3115,13 @@ def boxplot_view(request,userid=0,
chartform = BoxPlotChoiceForm(request.POST)
if chartform.is_valid():
plotfield = chartform.cleaned_data['yparam']
+ includereststrokes = chartform.cleaned_data['includereststrokes']
+ spmmin = chartform.cleaned_data['spmmin']
+ spmmax = chartform.cleaned_data['spmmax']
+ workmin = chartform.cleaned_data['workmin']
+ workmax = chartform.cleaned_data['workmax']
+ request.session['includereststrokes'] = includereststrokes
+ workstrokesonly = not includereststrokes
ids = request.session['ids']
request.session['ids'] = ids
workouts = [Workout.objects.get(id=id) for id in ids]
@@ -3106,12 +3135,31 @@ def boxplot_view(request,userid=0,
}
fieldlist,fielddict = dataprep.getstatsfields()
- fieldlist = [plotfield,'workoutid']
+ fieldlist = [plotfield,'workoutid','spm','driveenergy',
+ 'workoutstate']
# prepare data frame
datadf = dataprep.read_cols_df_sql(ids,fieldlist)
+
+ # dummy values for drive energy
+ mask = datadf['driveenergy'] == 0
+ datadf.loc[mask,'driveenergy'] = 450
- datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)
+ datadf = dataprep.clean_df_stats(datadf,
+ workstrokesonly=workstrokesonly)
+
+
+ datadf = dataprep.filter_df(datadf,'spm',spmmin,
+ largerthan=True)
+ datadf = dataprep.filter_df(datadf,'spm',spmmax,
+ largerthan=False)
+ datadf = dataprep.filter_df(datadf,'driveenergy',workmin,
+ largerthan=True)
+ datadf = dataprep.filter_df(datadf,'driveneergy',workmax,
+ largerthan=False)
+
+ datadf.dropna(axis=0,how='any',inplace=True)
+
datadf['workoutid'].replace(datemapping,inplace=True)
datadf.rename(columns={"workoutid":"date"},inplace=True)
datadf = datadf.sort_values(['date'])
@@ -3136,7 +3184,7 @@ def boxplot_view(request,userid=0,
else:
return HttpResponse("invalid form")
else:
- url = reverse(workouts_view)
+ url = reverse(user_boxplot_select)
return HttpResponseRedirect(url)
# List Workouts