diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 01749000..1e290073 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -79,6 +79,38 @@ def getrowdata(id=0): return rowdata,row + + +def smalldataprep(therows,xparam,yparam1,yparam2): + df = pd.DataFrame() + if yparam2 == 'None': + yparam2 = 'power' + df[xparam] = [] + df[yparam1] = [] + df[yparam2] = [] + df['distance'] = [] + df['spm'] = [] + for workout in therows: + f1 = workout.csvfilename + + try: + rowdata = dataprep(rrdata(f1).df) + + rowdata = pd.DataFrame({xparam: rowdata[xparam], + yparam1: rowdata[yparam1], + yparam2: rowdata[yparam2], + 'distance': rowdata['distance'], + 'spm': rowdata['spm'], + } + ) + df = pd.concat([df,rowdata],ignore_index=True) + except IOError: + pass + + return df + + + def dataprep(rowdatadf,bands=False,barchart=False,otwpower=False): rowdatadf.set_index([range(len(rowdatadf))],inplace=True) t = rowdatadf.ix[:,'TimeStamp (sec)'] @@ -113,7 +145,10 @@ def dataprep(rowdatadf,bands=False,barchart=False,otwpower=False): drivelength = savgol_filter(drivelength,windowsize,3) forceratio = savgol_filter(forceratio,windowsize,3) - t2 = t.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) + try: + t2 = t.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) + except TypeError: + t2 = 0*t p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index e27a6105..5e358a15 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -7,7 +7,7 @@ from rowingdata import rowingdata as rrdata from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc from bokeh.models import CustomJS,Slider -from bokeh.charts import Histogram +from bokeh.charts import Histogram,HeatMap from bokeh.resources import CDN,INLINE from bokeh.embed import components from bokeh.layouts import layout,widgetbox @@ -563,6 +563,305 @@ def interactive_chart(id=0,promember=0): return [script,div] +def interactive_cum_flex_chart2(theworkouts,promember=0, + xparam='spm', + yparam1='power', + yparam2='spm'): + + datadf = dataprep.smalldataprep(theworkouts,xparam,yparam1,yparam2) + + + axlabels = { + 'time': 'Time', + 'distance': 'Distance (m)', + 'hr': 'Heart Rate (bpm)', + 'spm': 'Stroke Rate (spm)', + 'pace': 'Pace (/500m)', + 'power': 'Power (Watt)', + 'averageforce': 'Average Drive Force (lbs)', + 'drivelength': 'Drive Length (m)', + 'peakforce': 'Peak Drive Force (lbs)', + 'forceratio': 'Average/Peak Drive Force Ratio', + 'driveenergy': 'Work per Stroke (J)', + 'drivespeed': 'Drive Speed (m/s)', + 'None': '', + } + + yparamname1 = axlabels[yparam1] + yparamname2 = axlabels[yparam2] + + yaxminima = { + 'hr':100, + 'spm':15, + 'pace': 1.0e3*210, + 'power': 0, + 'averageforce': 0, + 'peakforce': 0, + 'forceratio':0, + 'drivelength':0.5, + 'driveenergy': 0, + 'drivespeed': 0, + } + + yaxmaxima = { + 'hr':200, + 'spm':45, + 'pace':1.0e3*90, + 'power': 600, + 'averageforce':200, + 'peakforce':400, + 'forceratio':1, + 'drivelength':2.0, + 'driveenergy': 1000, + 'drivespeed':4, + } + + + + datadf = datadf[datadf[yparam1] > 0] + + + datadf = datadf[datadf[xparam] > 0] + + if yparam2 != 'None': + datadf = datadf[datadf[yparam2] > 0] + + # check if dataframe not empty + if datadf.empty: + return ['','

No non-zero data in selection

','',''] + + + datadf['x1'] = datadf.ix[:,xparam] + + datadf['y1'] = datadf.ix[:,yparam1] + if yparam2 != 'None': + datadf['y2'] = datadf.ix[:,yparam2] + else: + datadf['y2'] = datadf['y1'] + + + if xparam=='distance': + xaxmax = datadf['x1'].max() + xaxmin = datadf['x1'].min() + else: + xaxmax = yaxmaxima[xparam] + xaxmin = yaxminima[xparam] + + # average values + x1mean = datadf['x1'].mean() + + y1mean = datadf['y1'].mean() + y2mean = datadf['y2'].mean() + + + xvals = pd.Series(xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.) + + x_axis_type = 'linear' + y_axis_type = 'linear' + + datadf['xname'] = xparam + datadf['yname1'] = yparam1 + if yparam2 != 'None': + datadf['yname2'] = yparam2 + else: + datadf['yname2'] = yparam1 + + source = ColumnDataSource( + datadf + ) + + source2 = ColumnDataSource( + datadf.copy() + ) + + # Add hover to this comma-separated string and see what changes + if (promember==1): + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' + else: + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' + + plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, + tools=TOOLS, + toolbar_location="above", + toolbar_sticky=False) + + x1means = Span(location=x1mean,dimension='height',line_color='green', + line_dash=[6,6], line_width=2) + + y1means = Span(location=y1mean,dimension='width',line_color='blue', + line_dash=[6,6],line_width=2) + y2means = y1means + + xlabel = Label(x=370,y=130,x_units='screen',y_units='screen', + text=xparam+": {x1mean:6.2f}".format(x1mean=x1mean), + background_fill_alpha=.7, + text_color='green', + ) + + + plot.add_layout(x1means) + plot.add_layout(xlabel) + + plot.add_layout(y1means) + + y1label = Label(x=370,y=100,x_units='screen',y_units='screen', + text=yparam1+": {y1mean:6.2f}".format(y1mean=y1mean), + background_fill_alpha=.7, + text_color='blue', + ) + + plot.add_layout(y1label) + + y2label = y1label + plot.circle('x1','y1',source=source2,fill_alpha=0.3,line_color=None, + legend=yparamname1, + ) + + plot.xaxis.axis_label = axlabels[xparam] + plot.yaxis.axis_label = axlabels[yparam1] + + + yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1]) + plot.y_range = yrange1 + + xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) + plot.x_range = xrange1 + + + if yparam2 != 'None': + yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2]) + plot.extra_y_ranges = {"yax2": yrange2} + + plot.circle('x1','y2',color="red",y_range_name="yax2", + legend=yparamname2, + source=source2,fill_alpha=0.3,line_color=None) + + plot.add_layout(LinearAxis(y_range_name="yax2", + axis_label=axlabels[yparam2]),'right') + + y2means = Span(location=y2mean,dimension='width',line_color='red', + line_dash=[6,6],line_width=2,y_range_name="yax2") + + + plot.add_layout(y2means) + y2label = Label(x=370,y=70,x_units='screen',y_units='screen', + text=yparam2+": {y2mean:6.2f}".format(y2mean=y2mean), + background_fill_alpha=.7, + text_color='red', + ) + if yparam2 != 'pace' and yparam2 != 'time': + plot.add_layout(y2label) + + + callback = CustomJS(args = dict(source=source,source2=source2, + x1means=x1means, + y1means=y1means, + y1label=y1label, + y2label=y2label, + xlabel=xlabel, + y2means=y2means), code=""" + var data = source.data + var data2 = source2.data + var x1 = data['x1'] + var y1 = data['y1'] + var y2 = data['y2'] + var spm1 = data['spm'] + var distance1 = data['distance'] + var xname = data['xname'][0] + var yname1 = data['yname1'][0] + var yname2 = data['yname2'][0] + + var minspm = minspm.value + var maxspm = maxspm.value + var mindist = mindist.value + var maxdist = maxdist.value + var xm = 0 + var ym1 = 0 + var ym2 = 0 + + data2['x1'] = [] + data2['y1'] = [] + data2['y2'] = [] + data2['spm'] = [] + data2['distance'] = [] + data2['x1mean'] = [] + data2['y1mean'] = [] + data2['y2mean'] = [] + data2['xvals'] = [] + data2['y1vals'] = [] + data2['y2vals'] = [] + + 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] + + } + } + } + + xm /= data2['x1'].length + ym1 /= data2['x1'].length + ym2 /= data2['x1'].length + + data2['x1mean'] = [xm,xm] + data2['y1mean'] = [ym1,ym1] + data2['y2mean'] = [ym2,ym2] + 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) + + source2.trigger('change'); + """) + + 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) + callback.args["maxspm"] = slider_spm_max + + distmax = 100+100*int(datadf['distance'].max()/100.) + + slider_dist_min = Slider(start=0,end=distmax,value=0,step=1, + title="Min Distance",callback=callback) + callback.args["mindist"] = slider_dist_min + + slider_dist_max = Slider(start=0,end=distmax,value=distmax, + step=1, + title="Max Distance",callback=callback) + callback.args["maxdist"] = slider_dist_max + + layout = layoutrow([layoutcolumn([slider_spm_min, + slider_spm_max, + slider_dist_min, + slider_dist_max, + ], + ), + plot]) + + script, div = components(layout) + js_resources = INLINE.render_js() + css_resources = INLINE.render_css() + + + + return [script,div,js_resources,css_resources] + + def interactive_cum_flex_chart(theworkouts,promember=0, xparam='spm', yparam1='power', @@ -578,8 +877,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0, therows.append(rowdata.df) datadf = pd.concat(therows) - - + axlabels = { 'time': 'Time', 'distance': 'Distance (m)', diff --git a/rowers/templates/cum_flex.html b/rowers/templates/cum_flex.html index be20b214..7a43c0b9 100644 --- a/rowers/templates/cum_flex.html +++ b/rowers/templates/cum_flex.html @@ -39,18 +39,16 @@