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 = """