diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index a960987c..c339fc82 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -403,71 +403,100 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): if rowdata.empty: return "","No Valid Data Available","","" + + # quick linear regression + # peakforce = slope*peakforceangle + intercept + slope, intercept, r,p,stderr = linregress(rowdata['peakforceangle'],rowdata['peakforce']) + theta = np.arctan(slope) + + a = rowdata['peakforceangle']-rowdata['peakforceangle'].mean() + F = rowdata['peakforce']-rowdata['peakforce'].mean() + + R = np.array([[np.cos(theta),np.sin(theta)], + [-np.sin(theta),np.cos(theta)]]) + Rinv = np.array([[np.cos(theta),np.sin(theta)], + [-np.sin(theta),np.cos(theta)]]) + + x = R[0,0]*a+R[0,1]*F + y = R[1,0]*a+R[1,1]*F + + + x05 = x.quantile(q=0.05) + x25 = x.quantile(q=0.25) + x75 = x.quantile(q=0.75) + x95 = x.quantile(q=0.95) + + y05 = y.quantile(q=0.05) + y25 = y.quantile(q=0.25) + y75 = y.quantile(q=0.75) + y95 = y.quantile(q=0.95) + try: catchav = rowdata['catch'].mean() catch25 = rowdata['catch'].quantile(q=0.25) catch75 = rowdata['catch'].quantile(q=0.75) - catch01 = rowdata['catch'].quantile(q=0.05) + catch05 = rowdata['catch'].quantile(q=0.05) catch99 = rowdata['catch'].quantile(q=0.95) except KeyError: catchav = 0 catch25 = 0 catch75 = 0 - catch01 = 0 + catch05 = 0 catch99 = 0 try: finishav = rowdata['finish'].mean() finish25 = rowdata['finish'].quantile(q=0.25) finish75 = rowdata['finish'].quantile(q=0.75) - finish01 = rowdata['finish'].quantile(q=0.05) + finish05 = rowdata['finish'].quantile(q=0.05) finish99 = rowdata['finish'].quantile(q=0.95) except KeyError: finishav = 0 finish25 = 0 finish75 = 0 - finish01 = 0 + finish05 = 0 finish99 = 0 try: washav = (rowdata['finish']-rowdata['wash']).mean() wash25 = (rowdata['finish']-rowdata['wash']).quantile(q=0.25) wash75 = (rowdata['finish']-rowdata['wash']).quantile(q=0.75) - wash01 = (rowdata['finish']-rowdata['wash']).quantile(q=0.05) + wash05 = (rowdata['finish']-rowdata['wash']).quantile(q=0.05) wash99 = (rowdata['finish']-rowdata['wash']).quantile(q=0.95) except KeyError: washav = 0 wash25 = 0 wash75 = 0 - wash01 = 0 + wash05 = 0 wash99 = 0 try: slipav = (rowdata['slip']+rowdata['catch']).mean() slip25 = (rowdata['slip']+rowdata['catch']).quantile(q=0.25) slip75 = (rowdata['slip']+rowdata['catch']).quantile(q=0.75) - slip01 = (rowdata['slip']+rowdata['catch']).quantile(q=0.05) + slip05 = (rowdata['slip']+rowdata['catch']).quantile(q=0.05) slip99 = (rowdata['slip']+rowdata['catch']).quantile(q=0.95) except KeyError: slipav = 0 slip25 = 0 slip75 = 0 - slip01 = 0 + slip05 = 0 slip99 = 0 try: peakforceav = rowdata['peakforce'].mean() peakforce25 = rowdata['peakforce'].quantile(q=0.25) peakforce75 = rowdata['peakforce'].quantile(q=0.75) - peakforce01 = rowdata['peakforce'].quantile(q=0.05) + peakforce05 = rowdata['peakforce'].quantile(q=0.05) peakforce99 = rowdata['peakforce'].quantile(q=0.95) except KeyError: peakforceav = 0 peakforce25 = 0 peakforce75 = 0 - peakforce01 = 0 + peakforce05 = 0 peakforce99 = 0 + try: averageforceav = rowdata['averageforce'].mean() except KeyError: @@ -475,17 +504,18 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): try: peakforceangleav = rowdata['peakforceangle'].mean() + peakforceangle05 = rowdata['peakforceangle'].quantile(q=0.05) peakforceangle25 = rowdata['peakforceangle'].quantile(q=0.25) peakforceangle75 = rowdata['peakforceangle'].quantile(q=0.75) - peakforceangle01 = rowdata['peakforceangle'].quantile(q=0.05) peakforceangle99 = rowdata['peakforceangle'].quantile(q=0.95) except KeyError: peakforceangleav = 0 peakforceangle25 = 0 peakforceangle75 = 0 - peakforceangle01 = 0 + peakforceangle05 = 0 peakforceangle99 = 0 - + + x = [catchav, slipav, peakforceangleav, @@ -524,24 +554,24 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): - x0199 = [catch01, - slip01, + x0599 = [catch05, + slip05, peakforceangleav, wash99, finish99, - finish01, - wash01, + finish05, + wash05, peakforceangleav, slip99] - y0199 = [0, + y0599 = [0, thresholdforce, peakforce99, thresholdforce, 0, 0, thresholdforce, - peakforce01, + peakforce05, 0] @@ -555,8 +585,8 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): data = dict( x2575=x2575, y2575=y2575, - x0199=x0199, - y0199=y0199, + x0599=x0599, + y0599=y0599, )) sourceslipwash = ColumnDataSource( @@ -566,11 +596,31 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): ) ) + sourcetrend = ColumnDataSource( + data = dict( + x = [peakforceangle25,peakforceangle75], + y = [peakforce25,peakforce75] + ) + ) + + sourcefit = ColumnDataSource( + data = dict( + x = rowdata['peakforceangle'], + y = slope*rowdata['peakforceangle']+intercept + ) + ) source2 = ColumnDataSource( rowdata ) + sourcepoints = ColumnDataSource( + data = dict( + peakforceangle = rowdata['peakforceangle'], + peakforce = rowdata['peakforce'] + ) + ) + plot = Figure(tools=TOOLS, toolbar_sticky=False,toolbar_location="above") @@ -609,6 +659,11 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): plot.line('x','y',source=source,color="red") plot.circle('xslip','yslip',source=sourceslipwash,color="red") + plot.circle('peakforceangle','peakforce',source=sourcepoints,color='cyan') + plot.line('x','y',source=source,color="red") + plot.line('x','y',source=sourcetrend,color="blue") + plot.line('x','y',source=sourcefit,color="green") + plot.add_layout(avf) peakflabel = Label(x=355,y=430,x_units='screen',y_units='screen', @@ -700,6 +755,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): source=source, source2=source2, sourceslipwash=sourceslipwash, + sourcepoints=sourcepoints, avf=avf, avflabel=avflabel, catchlabel=catchlabel, @@ -714,6 +770,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): var data = source.data var data2 = source2.data var dataslipwash = sourceslipwash.data + var datapoints = sourcepoints.data var x = data['x'] var y = data['y'] @@ -755,11 +812,15 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): var peakforceav = 0 var count = 0 + datapoints['peakforceangle'] = [] + datapoints['peakforce'] = [] for (i=0; i=minspm && spm1[i]<=maxspm) { if (distance1[i]>=mindist && distance1[i]<=maxdist) { if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) { + datapoints['peakforceangle'].push(peakforceangle[i]) + datapoints['peakforce'].push(peakforce[i]) catchav += c[i] finishav += finish[i] slipav += slip[i] @@ -800,6 +861,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): // source.trigger('change'); source.change.emit(); sourceslipwash.change.emit() + sourcepoints.change.emit(); """) annotation = TextInput(title="Type your plot notes here", value="", diff --git a/rowers/metrics.py b/rowers/metrics.py index 2f5c12b9..1e7d55b1 100644 --- a/rowers/metrics.py +++ b/rowers/metrics.py @@ -285,7 +285,7 @@ axesnew = [ (name,d['verbose_name'],d['ax_min'],d['ax_max'],d['type']) for name,d in rowingmetrics ] -axes = tuple(axesnew+[('None','None',0,1,'basic')]) +axes = tuple(axesnew+[('None','',0,1,'basic')]) axlabels = {ax[0]:ax[1] for ax in axes}