diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index 57f040e6..50397ff7 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -482,7 +482,7 @@ def clean_df_stats(datadf, workstrokesonly=True, ignorehr=True,
try:
- mask = datadf['wash'] > 1
+ mask = datadf['wash'] < 1
datadf.loc[mask, 'wash'] = np.nan
except (KeyError,TypeError):
pass
diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py
index 95c5b5ed..c4ab7eb1 100644
--- a/rowers/interactiveplots.py
+++ b/rowers/interactiveplots.py
@@ -21,7 +21,7 @@ from bokeh.models.glyphs import MultiLine
import itertools
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation
-
+
from bokeh.resources import CDN,INLINE
from bokeh.embed import components
from bokeh.layouts import layout,widgetbox
@@ -87,14 +87,14 @@ import rowers.datautils as datautils
def errorbar(fig, x, y, source=ColumnDataSource(),
- xerr=False, yerr=False, color='black',
+ xerr=False, yerr=False, color='black',
point_kwargs={}, error_kwargs={}):
xvalues = source.data[x]
yvalues = source.data[y]
-
+
xerrvalues = source.data['xerror']
yerrvalues = source.data['yerror']
try:
@@ -102,7 +102,7 @@ def errorbar(fig, x, y, source=ColumnDataSource(),
except KeyError:
colorvalues = ["#%02x%02x%02x" % (255,0,0) for x in xvalues]
-
+
try:
a = xvalues[0]+1
if xerr:
@@ -140,7 +140,7 @@ def errorbar(fig, x, y, source=ColumnDataSource(),
r, g, b = colorsys.hsv_to_rgb(h, s, v)
color2 = "#%02x%02x%02x" % (int(255.*r), int(255.*g), int(255*b))
err_color.append(color2)
-
+
fig.multi_line(y_err_x, y_err_y, color=err_color,
name='yerr',**error_kwargs)
except TypeError:
@@ -149,7 +149,7 @@ def errorbar(fig, x, y, source=ColumnDataSource(),
fig.circle(x, y, source=source, name='data',color=color,
**point_kwargs)
-
+
def tailwind(bearing,vwind,winddir):
""" Calculates head-on head/tailwind in direction of rowing
@@ -161,23 +161,23 @@ def tailwind(bearing,vwind,winddir):
w = np.radians(winddir)
vtail = -vwind*np.cos(w-b)
-
+
return vtail
from rowers.dataprep import nicepaceformat,niceformat
-from rowers.dataprep import timedeltaconv
+from rowers.dataprep import timedeltaconv
def interactive_boxchart(datadf,fieldname,extratitle='',
spmmin=0,spmmax=0,workmin=0,workmax=0):
if datadf.empty:
return '','It looks like there are no data matching your filter'
-
+
tooltips = [
('Value', '@'+fieldname),
]
-
+
hover = HoverTool(tooltips=tooltips)
TOOLS = [hover]
@@ -216,7 +216,7 @@ def interactive_boxchart(datadf,fieldname,extratitle='',
plot.plot_width=920
plot.plot_height=600
-
+
slidertext = 'SPM: {:.0f}-{:.0f}, WpS: {:.0f}-{:.0f}'.format(
spmmin,spmmax,workmin,workmax
)
@@ -228,7 +228,7 @@ def interactive_boxchart(datadf,fieldname,extratitle='',
)
plot.add_layout(sliderlabel)
-
+
script, div = components(plot)
return script,div
@@ -246,15 +246,15 @@ def interactive_planchart(data,startdate,enddate):
if yaxmaximum == 0:
yaxmaximum = 250
-
+
yrange1 = Range1d(start=0,end=1.1*yaxmaximum)
-
-
+
+
tidy_df = data.melt(id_vars=['startdate'],value_vars=['executed','planned'])
bars = hv.Bars(tidy_df,['startdate','variable'],['value'])
bars.opts(
opts.Bars(show_legend=True,tools=['tap','hover'],legend_position='bottom',show_frame=True))
-
+
p = hv.render(bars)
p.plot_width=550
@@ -268,7 +268,7 @@ def interactive_planchart(data,startdate,enddate):
return script,div
def interactive_activitychart(workouts,startdate,enddate,stack='type'):
-
+
dates = []
dates_sorting = []
types = []
@@ -283,7 +283,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
for w in workouts:
aantal=1
- initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]
+ initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]
if w.user.id not in idseen:
while initials in seen:
aantal += 1
@@ -293,7 +293,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
idseen.append(w.user.id)
rowersinitials[w.user.id] = initials
-
+
for w in workouts:
dd = w.date.strftime('%m/%d')
@@ -308,7 +308,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
code = encoder.encode_hex(w.id)
)
)
-
+
types.append(w.workouttype)
try:
rowers.append(rowersinitials[w.user.id])
@@ -330,7 +330,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
dd = d.strftime('%d')
dates.append(d.strftime('%m/%d'))
-
+
dates_sorting.append(d.strftime('%Y/%m/%d'))
durations.append(0)
links.append('')
@@ -342,7 +342,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
rowers.append(str(workouts[0].user))
except IndexError:
rowers.append(' ')
-
+
d += datetime.timedelta(days=1)
@@ -354,7 +354,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
'rower':rowers,
'link':links,
}
-
+
df = pd.DataFrame(thedict)
source = ColumnDataSource(df)
@@ -372,14 +372,14 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
bars=table.to.bars(['date',stack],['duration'])
bars.opts(
- opts.Bars(color=hv.Cycle('Category10'), show_legend=True, stacked=True,
+ opts.Bars(color=hv.Cycle('Category10'), show_legend=True, stacked=True,
tools=['tap','hover'], width=550, xrotation=45,padding=(0,(0,.1)),
legend_position='bottom',show_frame=True))
p = hv.render(bars)
-
+
p.title.text = 'Activity {d1} to {d2}'.format(
d1 = startdate.strftime("%Y-%m-%d"),
d2 = enddate.strftime("%Y-%m-%d"),
@@ -391,7 +391,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
p.sizing_mode = 'scale_width'
url = "http://rowsandall.com/rowers/workout/@duration/"
taptool = p.select(type=TapTool)
-
+
callback = CustomJS(args={'links':df.link}, code="""
@@ -401,10 +401,10 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
console.log(links[index]);
window.location.href = links[index]
""")
-
+
taptool.callback = callback
-
+
script,div = components(p)
return script,div
@@ -414,14 +414,15 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
ids = [int(w.id) for w in theworkouts]
boattype = theworkouts[0].boattype
-
+
columns = ['catch','slip','wash','finish','averageforce',
'peakforceangle','peakforce','spm','distance',
'workoutstate','driveenergy']
-
+
+
rowdata = dataprep.getsmallrowdata_db(columns,ids=ids,
workstrokesonly=workstrokesonly)
-
+
rowdata.dropna(axis=1,how='all',inplace=True)
rowdata.dropna(axis=0,how='any',inplace=True)
@@ -465,7 +466,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
x25 = x.quantile(q=0.15)
x75 = x.quantile(q=0.85)
x95 = x.quantile(q=0.99)
-
+
y05 = y.quantile(q=0.01)
y25 = y.quantile(q=0.15)
y75 = y.quantile(q=0.85)
@@ -473,55 +474,55 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
a25 = Rinv[0,0]*x25 + rowdata['peakforceangle'].median()
F25 = Rinv[1,0]*x25 + rowdata['peakforce'].median()
-
+
a25b = Rinv[0,1]*y25 + rowdata['peakforceangle'].median()
F25b = Rinv[1,1]*y25 + rowdata['peakforce'].median()
-
+
a75 = Rinv[0,0]*x75 + rowdata['peakforceangle'].median()
F75 = Rinv[1,0]*x75 + rowdata['peakforce'].median()
-
+
a75b = Rinv[0,1]*y75 + rowdata['peakforceangle'].median()
F75b = Rinv[1,1]*y75 + rowdata['peakforce'].median()
-
-
+
+
a05 = Rinv[0,0]*x05 + rowdata['peakforceangle'].median()
F05 = Rinv[1,0]*x05 + rowdata['peakforce'].median()
-
+
a05b = Rinv[0,1]*y05 + rowdata['peakforceangle'].median()
F05b = Rinv[1,1]*y05 + rowdata['peakforce'].median()
-
+
a95 = Rinv[0,0]*x95 + rowdata['peakforceangle'].median()
F95 = Rinv[1,0]*x95 + rowdata['peakforce'].median()
-
+
a95b = Rinv[0,1]*y95 + rowdata['peakforceangle'].median()
F95b = Rinv[1,1]*y95 + rowdata['peakforce'].median()
except KeyError:
a25 = 0
F25 = 0
-
+
a25b = 0
F25b = 0
-
+
a75 = 0
F75 = 0
-
+
a75b = 0
F75b = 0
-
-
+
+
a05 = 0
F05 = 0
-
+
a05b = 0
F05b = 0
-
+
a95 = 0
F95 = 0
-
+
a95b = 0
F95b = 0
-
+
try:
catchav = rowdata['catch'].median()
@@ -548,7 +549,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
finish75 = 0
finish05 = 0
finish95 = 0
-
+
try:
washav = (rowdata['finish']-rowdata['wash']).median()
wash25 = (rowdata['finish']-rowdata['wash']).quantile(q=0.25)
@@ -574,7 +575,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
slip75 = 0
slip05 = 0
slip95 = 0
-
+
try:
peakforceav = rowdata['peakforce'].median()
peakforce25 = rowdata['peakforce'].quantile(q=0.25)
@@ -588,18 +589,18 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
peakforce05 = 0
peakforce95 = 0
-
+
try:
averageforceav = rowdata['averageforce'].median()
except KeyError:
averageforceav = 0
-
+
try:
peakforceangleav = rowdata['peakforceangle'].median()
peakforceangle05 = rowdata['peakforceangle'].quantile(q=0.05)
peakforceangle25 = rowdata['peakforceangle'].quantile(q=0.25)
- peakforceangle75 = rowdata['peakforceangle'].quantile(q=0.75)
- peakforceangle95 = rowdata['peakforceangle'].quantile(q=0.95)
+ peakforceangle75 = rowdata['peakforceangle'].quantile(q=0.75)
+ peakforceangle95 = rowdata['peakforceangle'].quantile(q=0.95)
except KeyError:
peakforceangleav = 0
peakforceangle25 = 0
@@ -641,7 +642,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
]
-
+
angles2575 = []
forces2575 = []
@@ -649,7 +650,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
angles2575.append(x)
forces2575.append(y)
-
+
angles0595 = []
forces0595 = []
@@ -659,8 +660,8 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
-
-
+
+
x = [catchav,
slipav,
peakforceangleav,
@@ -672,7 +673,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
thresholdforce,0]
-
+
source = ColumnDataSource(
data = dict(
x = x,
@@ -685,7 +686,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
yslip = [thresholdforce,thresholdforce]
)
)
-
+
sourcetrend = ColumnDataSource(
data = dict(
x = [peakforceangle25,peakforceangle75],
@@ -699,7 +700,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
y = slope*np.array([peakforceangle25,peakforceangle75])+intercept
)
)
-
+
source2 = ColumnDataSource(
rowdata
)
@@ -725,7 +726,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
peakforceangle = [],
peakforce = []
))
-
+
sourcerange = ColumnDataSource(
data = dict(
@@ -743,7 +744,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
-
+
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
@@ -768,7 +769,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
avf = Span(location=averageforceav,dimension='width',line_color='blue',
line_dash=[6,6],line_width=2)
-
+
plot.patch('x0595','y0595',source=sourcerange,color="red",alpha=0.05)
plot.patch('x2575','y2575',source=sourcerange,color="red",alpha=0.2)
plot.line('x','y',source=source,color="red")
@@ -807,26 +808,26 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
x=multilinedatax,
y=multilinedatay,
))
-
+
sourcemultiline2 = ColumnDataSource(dict(
x=multilinedatax,
y=multilinedatay,
))
-
+
glyph = MultiLine(xs='x',ys='y',line_color='black',line_alpha=0.05)
plot.add_glyph(sourcemultiline,glyph)
else:
sourcemultiline = ColumnDataSource(dict(
x=[],y=[]))
-
+
sourcemultiline2 = ColumnDataSource(dict(
x=[],y=[]))
-
-
+
+
plot.line('x','y',source=source,color="red")
plot.add_layout(avf)
-
+
peakflabel = Label(x=410,y=460,x_units='screen',y_units='screen',
text="Fpeak: {peakforceav:6.2f}".format(peakforceav=peakforceav),
background_fill_alpha=.7,
@@ -903,7 +904,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
background_fill_color='white',
text_color='black',text_font_size='10pt',
)
-
+
plot.add_layout(peakflabel)
plot.add_layout(peakforceanglelabel)
@@ -959,7 +960,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
var multilinesx = multilines2['x']
var multilinesy = multilines2['y']
-
+
var x = data['x']
var y = data['y']
@@ -970,7 +971,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
var driveenergy1 = data2['driveenergy']
var thresholdforce = y[1]
-
+
var c = source2.data['catch']
var finish = data2['finish']
var slip = data2['slip']
@@ -1065,7 +1066,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
console.log(count);
console.log(multilines['x'].length);
console.log(multilines['y'].length);
-
+
// source.trigger('change');
source.change.emit();
sourceslipwash.change.emit()
@@ -1073,14 +1074,14 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
sourcemultiline.change.emit();
""")
- annotation = TextInput(title="Type your plot notes here", value="",
+ annotation = TextInput(title="Type your plot notes here", value="",
callback=callback)
callback.args["annotation"] = annotation
slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1,
title="Min SPM",callback=callback)
callback.args["minspm"] = slider_spm_min
-
+
slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1,
title="Max SPM",callback=callback)
@@ -1089,18 +1090,18 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
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=50,
title="Min Distance",callback=callback)
callback.args["mindist"] = slider_dist_min
-
+
slider_dist_max = Slider(start=0,end=distmax,value=distmax,
step=50,
title="Max Distance",callback=callback)
@@ -1123,7 +1124,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
-
+
return [script,div,js_resources,css_resources]
@@ -1139,7 +1140,7 @@ def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower',startdate=None,
if len(power4min) == 0:
return ['','']
-
+
df = pd.DataFrame(
{'power4min':power4min,
'power2k':power2k,
@@ -1157,7 +1158,7 @@ def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower',startdate=None,
df.loc[mask,'power4min'] = np.nan
df.dropna(inplace=True,axis=0,how='any')
-
+
df = df[df['power2k']>0]
try:
df = df[df['mode']==workoutmode]
@@ -1218,7 +1219,7 @@ def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower',startdate=None,
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
-
+
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
@@ -1272,7 +1273,7 @@ def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower',startdate=None,
if not enddate:
enddate = max(date)
-
+
plot.x_range = Range1d(
startdate,enddate,
)
@@ -1286,11 +1287,11 @@ def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower',startdate=None,
('Power 1 hour','@power1hr'),
('Date','@fdate'),
])
-
+
script,div = components(plot)
return [script,div]
-
+
def interactive_histoall(theworkouts,histoparam,includereststrokes,
spmmin=0,spmmax=55,
workmin=0,workmax=1500):
@@ -1318,7 +1319,7 @@ def interactive_histoall(theworkouts,histoparam,includereststrokes,
return "","No data"
if len(histopwr) == 0:
return "","No valid data available"
-
+
# throw out nans
histopwr = histopwr[~np.isinf(histopwr)]
histopwr = histopwr[histopwr > yaxminima[histoparam]]
@@ -1333,7 +1334,7 @@ def interactive_histoall(theworkouts,histoparam,includereststrokes,
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
-
+
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
@@ -1374,11 +1375,11 @@ def interactive_histoall(theworkouts,histoparam,includereststrokes,
# plot.quad(top='hist_norm',bottom=0,left=edges[:-1],right=edges[1:])
plot.quad(top='hist_norm',bottom=0,left='left',right='right',source=source)
-
+
plot.xaxis.axis_label = axlabels[histoparam]
plot.yaxis.axis_label = "% of strokes"
plot.y_range = Range1d(0,1.05*max(hist_norm))
-
+
hover = plot.select(dict(type=HoverTool))
@@ -1397,7 +1398,7 @@ def interactive_histoall(theworkouts,histoparam,includereststrokes,
axis_label="Cumulative % of strokes"),'right')
plot.sizing_mode = 'scale_width'
-
+
annolabel = Label(x=50,y=450,x_units='screen',y_units='screen',
text='',
background_fill_alpha=0.7,
@@ -1425,7 +1426,7 @@ def interactive_histoall(theworkouts,histoparam,includereststrokes,
except ValueError:
script = ''
div = ''
-
+
return [script,div]
def course_map(course):
@@ -1433,7 +1434,7 @@ def course_map(course):
lat_min, lat_max, long_min, long_max = course_coord_maxmin(course)
coordinates = course_spline(coordinates)
-
+
scoordinates = "["
for index,row in coordinates.iterrows():
@@ -1451,7 +1452,7 @@ def course_map(course):
for p in polygons:
coords = polygon_coord_center(p)
-
+
plabels += """
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
marker.bindPopup("{name}");
@@ -1461,7 +1462,7 @@ def course_map(course):
longbegin = coords[1],
name = p.name
)
-
+
pcoordinates = """[
"""
@@ -1490,8 +1491,8 @@ def course_map(course):
script = """