Private
Public Access
1
0

Merge branch 'release/keepdaterange'

This commit is contained in:
Sander Roosendaal
2016-11-22 11:07:09 +01:00
5 changed files with 370 additions and 38 deletions

View File

@@ -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))

View File

@@ -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 ['','<p>No non-zero data in selection</p>','','']
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<x1.length; i++) {
if (spm1[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)',

View File

@@ -39,18 +39,16 @@
<div class="grid_2 alpha dropdown">
<button class="grid_2 alpha button blue small dropbtn">X-axis</button>
<div class="dropdown-content">
<a class="button blue small alpha" href="/rowers/flexall/time/{{ yparam1 }}/{{ yparam2 }}">Time</a>
<a class="button blue small alpha" href="/rowers/flexall/distance/{{ yparam1 }}/{{ yparam2 }}">Distance</a>
{% if promember %}
<a class="button blue small alpha" href="/rowers/flexall/power/{{ yparam1 }}/{{ yparam2 }}">Power</a>
<a class="button blue small alpha" href="/rowers/flexall/hr/{{ yparam1 }}/{{ yparam2 }}">HR</a>
<a class="button blue small alpha" href="/rowers/flexall/spm/{{ yparam1 }}/{{ yparam2 }}">SPM</a>
<a class="button blue small alpha" href="/rowers/flexall/peakforce/{{ yparam1 }}/{{ yparam2 }}">Peak Force</a>
<a class="button blue small alpha" href="/rowers/flexall/averageforce/{{ yparam1 }}/{{ yparam2 }}">Average Force</a>
<a class="button blue small alpha" href="/rowers/flexall/forceratio/{{ yparam1 }}/{{ yparam2 }}">Average/Peak Force Ratio</a>
<a class="button blue small alpha" href="/rowers/flexall/drivelength/{{ yparam1 }}/{{ yparam2 }}">Drive Length</a>
<a class="button blue small alpha" href="/rowers/flexall/driveenergy/{{ yparam1 }}/{{ yparam2 }}">Work per Stroke</a>
<a class="button blue small alpha" href="/rowers/flexall/drivespeed/{{ yparam1 }}/{{ yparam2 }}">Drive Speed</a>
<a class="button blue small alpha" href="/rowers/flexall/power/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Power</a>
<a class="button blue small alpha" href="/rowers/flexall/hr/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">HR</a>
<a class="button blue small alpha" href="/rowers/flexall/spm/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">SPM</a>
<a class="button blue small alpha" href="/rowers/flexall/peakforce/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Peak Force</a>
<a class="button blue small alpha" href="/rowers/flexall/averageforce/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average Force</a>
<a class="button blue small alpha" href="/rowers/flexall/forceratio/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average/Peak Force Ratio</a>
<a class="button blue small alpha" href="/rowers/flexall/drivelength/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Length</a>
<a class="button blue small alpha" href="/rowers/flexall/driveenergy/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Work per Stroke</a>
<a class="button blue small alpha" href="/rowers/flexall/drivespeed/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Power (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">HR (Pro)</a>
@@ -69,17 +67,16 @@
<div class="grid_2 dropdown">
<button class="grid_2 alpha button blue small dropbtn">Left</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/pace/{{ yparam2 }}">Pace</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/hr/{{ yparam2 }}">HR</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/spm/{{ yparam2 }}">SPM</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/power/{{ yparam2 }}">Power</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/hr/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">HR</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/spm/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">SPM</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/power/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/peakforce/{{ yparam2 }}">Peak Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/averageforce/{{ yparam2 }}">Average Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/forceratio/{{ yparam2 }}">Average/Peak Force Ratio</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivelength/{{ yparam2 }}">Drive Length</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/driveenergy/{{ yparam2 }}">Work per Stroke</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivespeed/{{ yparam2 }}">Drive Speed</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/peakforce/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Peak Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/averageforce/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/forceratio/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average/Peak Force Ratio</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivelength/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Length</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/driveenergy/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Work per Stroke</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivespeed/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
@@ -95,16 +92,16 @@
<div class="grid_2 dropdown omega">
<button class="grid_2 alpha button blue small dropbtn">Right</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/hr">HR</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/spm">SPM</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/power">Power</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/hr/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">HR</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/spm/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">SPM</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/power/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/peakforce">Peak Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/averageforce">Average Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/forceratio">Average/Peak Force Ratio</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivelength">Drive Length</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/driveenergy">Work per Stroke</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivespeed">Drive Speed</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/peakforce/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Peak Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/averageforce/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average Force</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/forceratio/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average/Peak Force Ratio</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivelength/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Length</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/driveenergy/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Work per Stroke</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivespeed/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
@@ -114,7 +111,7 @@
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
{% endif %}
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/None">None</a>
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/None/{{startdate|date:"Y-m-d"}}/{{ enddate|date:"Y-m-d"}}">None</a>
</div>
</div>

View File

@@ -39,6 +39,7 @@ urlpatterns = [
url(r'^ote-bests/$',views.rankings_view),
url(r'^(?P<theuser>\d+)/ote-bests/$',views.rankings_view),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.cum_flex),
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)$',views.cum_flex),
url(r'^flexall/$',views.cum_flex),

View File

@@ -1308,9 +1308,10 @@ def cum_flex(request,theuser=0,
u = ''
if allergworkouts:
res = interactive_cum_flex_chart(allergworkouts,xparam=xparam,
yparam1=yparam1,yparam2=yparam2,
promember=promember)
res = interactive_cum_flex_chart2(allergworkouts,xparam=xparam,
yparam1=yparam1,
yparam2=yparam2,
promember=promember)
script = res[0]
div = res[1]
js_resources = res[2]