Private
Public Access
1
0
Files
rowsandall/rowers/interactiveplots.py
2016-10-31 15:36:12 +01:00

2466 lines
62 KiB
Python

from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage
from rowingdata import rower as rrower
from rowingdata import main as rmain
from rowingdata import cumcpdata,histodata
from rowingdata import rowingdata as rrdata
from rowingdata import TCXParser,RowProParser,ErgDataParser
from rowingdata import painsledDesktopParser,speedcoachParser,ErgStickParser
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
from bokeh.models import CustomJS,Slider
from bokeh.charts import Histogram
from bokeh.resources import CDN,INLINE
from bokeh.embed import components
from bokeh.layouts import layout,widgetbox
from bokeh.layouts import row as layoutrow
from bokeh.layouts import column as layoutcolumn
from bokeh.models import LinearAxis,LogAxis,Range1d,DatetimeTickFormatter,HoverTool
from bokeh.io import output_file, show
from bokeh.models import (
GMapPlot, GMapOptions, ColumnDataSource, Circle,
DataRange1d, PanTool, WheelZoomTool, BoxSelectTool,
SaveTool, ResizeTool, ResetTool, TapTool,CrosshairTool,BoxZoomTool,
Span,
)
#from bokeh.models.widgets import Slider, Select, TextInput
from bokeh.core.properties import value
from collections import OrderedDict
from django.conf import settings
import datetime
import math
import numpy as np
import pandas as pd
from pytz import timezone as tz,utc
from django.utils.timezone import get_current_timezone
from django.utils.timezone import activate
activate(settings.TIME_ZONE)
thetimezone = get_current_timezone()
from scipy.stats import linregress
from scipy import optimize
from scipy.signal import savgol_filter
import stravastuff
def rdata(file,rower=rrower()):
try:
res = rrdata(file,rower=rower)
except IOError:
res = 0
return res
def tailwind(bearing,vwind,winddir):
""" Calculates head-on head/tailwind in direction of rowing
positive numbers are tail wind
"""
b = np.radians(bearing)
w = np.radians(winddir)
vtail = -vwind*np.cos(w-b)
return vtail
def niceformat(values):
out = []
for v in values:
formattedv = v.strftime("%H:%M:%S")
out.append(formattedv)
return out
def nicepaceformat(values):
out = []
for v in values:
formattedv = v.strftime("%M:%S.%f")
out.append(formattedv[:-5])
return out
def get_datetimes(seconds,tzinfo=0):
out = []
for second in seconds:
if (second<=0) or (second>1e9):
days = 0
hours = 0
minutes=0
sec=0
microsecond = 0
elif math.isnan(second):
days = 0
hours = 0
minutes=0
sec=0
microsecond = 0
else:
days = int(second/(24.*3600.)) % (24*3600)
hours = int((second-24.*3600.*days)/3600.) % 24
minutes = int((second-3600.*(hours+24.*days))/60.) % 60
sec = int(second-3600.*(hours+24.*days)-60.*minutes) % 60
microsecond = int(1.0e6*(second-3600.*(hours+24.*days)-60.*minutes-sec))
dt = datetime.datetime(2016,5,1,hours,minutes,sec,microsecond)
if tzinfo:
dt = thetimezone.localize(dt, is_dst=True)
# this is ugly
# dt = dt+datetime.timedelta(hours=1)
out.append(dt)
return out
def interactive_histoall(theworkouts):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
therows = []
for workout in theworkouts:
f1 = workout.csvfilename
rowdata = rdata(f1)
if rowdata != 0:
therows.append(rowdata)
histopwr = histodata(therows)
# throw out nans
histopwr = histopwr[~np.isinf(histopwr)]
histopwr = histopwr[histopwr > 25]
plot = Figure(tools=TOOLS,plot_width=900,
toolbar_sticky=False,
toolbar_location="above"
)
hist,edges = np.histogram(histopwr,bins=150)
histsum = np.cumsum(hist)
histsum = 100.*histsum/max(histsum)
hist_norm = 100.*hist/float(hist.sum())
source = ColumnDataSource(
data = dict(
left = edges[:-1],
right = edges[1:],
histsum = histsum,
hist_norm = hist_norm,
)
)
# 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 = "Power (W)"
plot.yaxis.axis_label = "% of strokes"
plot.y_range = Range1d(0,1.05*max(hist_norm))
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Power(W)','@left{int}'),
('% of strokes','@hist_norm'),
('Cumulative %','@histsum{int}'),
])
hover.mode = 'mouse'
plot.extra_y_ranges = {"fraction": Range1d(start=0,end=105)}
plot.line('right','histsum',source=source,color="red",
y_range_name="fraction")
plot.add_layout(LinearAxis(y_range_name="fraction",
axis_label="Cumulative % of strokes"),'right')
script, div = components(plot)
return [script,div]
def googlemap_chart(lat,lon,name=""):
# plot tools
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
map_options = GMapOptions(lat = lat.mean(),lng=lon.mean(),
map_type="roadmap",zoom=11)
plot = GMapPlot(
x_range=DataRange1d(), y_range=DataRange1d(),
map_options=map_options,
api_key = "AIzaSyAgu1w9QSthaGPMLp8y9JedPoMc9sfEgJ8",
plot_width=400,plot_height=400,
toolbar_sticky=False,
)
source = ColumnDataSource(
data = dict(
lat=lat,
lon=lon,
)
)
circle = Circle(x="lon",y="lat",size=5,fill_color="blue",
fill_alpha=0.2,line_color=None)
plot.add_glyph(source,circle)
plot.add_tools(PanTool(), WheelZoomTool(),
SaveTool(), ResizeTool(), ResetTool(),
TapTool(),CrosshairTool(),
)
plot.title.text = name
plot.title.text_font="1.0em"
script, div = components(plot)
return [script,div]
def interactive_cpchart(thedistances,thesecs,theavpower,
theworkouts,promember=0):
message = 0
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
x_axis_type = 'log'
y_axis_type = 'linear'
velo = thedistances/thesecs
p = 500./velo
p2 = get_datetimes(p)
source = ColumnDataSource(
data = dict(
dist = thedistances,
duration = thesecs,
spm = 0*theavpower,
tim = niceformat(get_datetimes(thesecs,tzinfo=1)),
power = theavpower,
pace = nicepaceformat(p2),
)
)
# fitting the data to Paul
if len(thedistances)>=2:
paulslope, paulintercept,r,p,stderr = linregress(np.log10(thedistances),p)
else:
paulslope = 5.0/np.log10(2.0)
paulintercept = p[0]-paulslope*np.log10(thedistances[0])
fitx = np.arange(100)*2*max(np.log10(thedistances))/100.
fitp = paulslope*fitx+paulintercept
fitvelo = 500./fitp
fitpower = 2.8*(fitvelo**3)
fitt = 10**fitx/fitvelo
fitp2 = get_datetimes(fitp)
sourcepaul = ColumnDataSource(
data = dict(
dist = 10**fitx,
duration = fitt,
power = fitpower,
spm = 0*fitpower,
tim = niceformat(get_datetimes(fitt,tzinfo=1)),
pace = nicepaceformat(fitp2),
)
)
# fitting the data to simple CP model
# simpleslope, simpleintercept,r,p,stderr = linregress(1./thesecs,theavpower)
# fitx = 1.e-4+np.arange(10000)/10000.
# fitpower = simpleslope*fitx+simpleintercept
# fitvelo = (fitpower/2.8)**(1./3.)
# fitt = 1./fitx
# fitdist = fitt*fitvelo
# fitp = 500./fitvelo
# fitp2 = get_datetimes(fitp)
# sourcesimple = ColumnDataSource(
# data = dict(
# dist = fitdist,
# duration = fitt,
# power = fitpower,
# tim = niceformat(get_datetimes(fitt)),
# pace = nicepaceformat(fitp2),
# )
# )
# fitting the data to three parameter CP model
fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3]))
errfunc = lambda pars,x,y: fitfunc(pars,x)-y
p0 = [500,350,10,8000]
p1 = p0
if len(thesecs)>=4:
p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower))
else:
factor = fitfunc(p0,thesecs.mean())/theavpower.mean()
p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]]
fitt = 10**(4*np.arange(100)/100.)
fitpower = fitfunc(p1,fitt)
message = ""
if len(fitpower[fitpower<0]) > 0:
message = "CP model fit didn't give correct results"
fitvelo = (fitpower/2.8)**(1./3.)
fitdist = fitt*fitvelo
fitp = 500./fitvelo
fitp2 = get_datetimes(fitp)
sourcecomplex = ColumnDataSource(
data = dict(
dist = fitdist,
duration = fitt,
tim = niceformat(get_datetimes(fitt,tzinfo=1)),
spm = 0*fitpower,
power = fitpower,
pace = nicepaceformat(fitp2),
)
)
# making the plot
plot = Figure(tools=TOOLS,x_axis_type=x_axis_type,
plot_width=900,
toolbar_location="above",
toolbar_sticky=False)
plot.circle('duration','power',source=source,fill_color='red',size=15,
legend='Power')
plot.xaxis.axis_label = "Duration (seconds)"
plot.yaxis.axis_label = "Power (W)"
therows = []
for workout in theworkouts:
f1 = workout.csvfilename
rowdata = rdata(f1)
if rowdata != 0:
therows.append(rowdata)
cpdata = cumcpdata(therows)
velo = cpdata['Distance']/cpdata['Delta']
p = 500./velo
p2 = get_datetimes(p)
source2 = ColumnDataSource(
data = dict(
duration = cpdata['Delta'],
power = cpdata['CP'],
tim = niceformat(get_datetimes(cpdata['Delta'],tzinfo=1)),
dist = cpdata['Distance'],
pace = nicepaceformat(p2),
)
)
plot.circle('duration','power',source=source2,
fill_color='blue',size=3,
legend = 'Power from segments')
# for workout in theworkouts:
# f1 = workout.csvfilename
# rowdata = rdata(f1)
# cpdata = rowdata.getcp()
# source2 = ColumnDataSource(
# data = dict(
# duration = cpdata['Delta'],
# power = cpdata['CP'],
# dist = cpdata['Distance'],
# )
# )
# plot.circle('duration','power',source=source2,fill_color='blue',size=3)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Duration ','@tim'),
('Power (W)','@power{int}'),
('Distance (m)','@dist{int}'),
('Pace (/500m)','@pace'),
])
hover.mode = 'mouse'
plot.y_range = Range1d(0,1.5*max(theavpower))
plot.x_range = Range1d(1,2*max(thesecs))
plot.legend.orientation = "vertical"
# plot.extra_y_ranges = {"distance": Range1d(start=0,
# end=1.1*max(thedistances))}
# plot.circle('duration','dist',source=source,fill_color='white',size=15,
# legend='Distance',
# y_range_name="distance")
# plot.line('duration','dist',source=sourcepaul,y_range_name="distance")
# plot.line('duration','dist',source=sourcesimple,legend="Simple CP model",
# color='red',y_range_name="distance")
# plot.line('duration','dist',source=sourcecomplex,legend="Simple CP model",
# color='green',y_range_name="distance")
# plot.add_layout(LinearAxis(y_range_name="distance",
# axis_label="Distance (m)"),'right')
plot.line('duration','power',source=sourcepaul,legend="Paul's Law")
# plot.line('duration','power',source=sourcesimple,legend="Simple CP model",
# color='red')
plot.line('duration','power',source=sourcecomplex,legend="CP Model",
color='green')
script, div = components(plot)
return [script,div,paulslope,paulintercept,p1,message]
def interactive_windchart(id=0,promember=0):
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
f1 = row.csvfilename
# create interactive plot
plot = Figure(plot_width=400,plot_height=300)
# get user
# u = User.objects.get(id=row.user.id)
r = row.user
u = r.user
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return 0
dist = rowdata.df.ix[:,'cum_dist']
try:
vwind = rowdata.df.ix[:,'vwind']
winddirection = rowdata.df.ix[:,'winddirection']
bearing = rowdata.df.ix[:,'bearing']
except KeyError:
rowdata.add_wind(0,0)
rowdata.add_bearing()
vwind = rowdata.df.ix[:,'vwind']
winddirection = rowdata.df.ix[:,'winddirection']
bearing = rowdata.df.ix[:,'winddirection']
rowdata.write_csv(f1)
winddirection = winddirection % 360
winddirection = (winddirection + 360) % 360
tw = tailwind(bearing,vwind,1.0*winddirection)
source = ColumnDataSource(
data = dict(
dist=dist,
vwind=vwind,
tw=tw,
winddirection=winddirection,
)
)
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
# making the plot
plot = Figure(tools=TOOLS,plot_width=400,height=500,
# toolbar_location="below",
toolbar_sticky=False,
)
plot.line('dist','vwind',source=source,legend="Wind Speed (m/s)")
plot.line('dist','tw',source=source,legend="Tail (+)/Head (-) Wind (m/s)",color='black')
plot.title.text = row.name
# plot.title.text_font_size=value("1.0em")
plot.title.text_font="1.0em"
plot.xaxis.axis_label = "Distance (m)"
plot.yaxis.axis_label = "Wind Speed (m/s)"
plot.y_range = Range1d(-7,7)
plot.extra_y_ranges = {"winddirection": Range1d(start=0,end=360)}
plot.line('dist','winddirection',source=source,
legend='Wind Direction',color="red",
y_range_name="winddirection")
plot.add_layout(LinearAxis(y_range_name="winddirection",axis_label="Wind Direction (degree)"),'right')
script, div = components(plot)
return [script,div]
def interactive_streamchart(id=0,promember=0):
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
f1 = row.csvfilename
# create interactive plot
plot = Figure(plot_width=400,
)
# get user
# u = User.objects.get(id=row.user.id)
r = row.user
u = r.user
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return "","CSV Data File Not Found"
dist = rowdata.df.ix[:,'cum_dist']
try:
vstream = rowdata.df.ix[:,'vstream']
except KeyError:
rowdata.add_stream(0)
vstream = rowdata.df.ix[:,'vstream']
rowdata.write_csv(f1)
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
# making the plot
plot = Figure(tools=TOOLS,plot_width=400,height=500,
# toolbar_location="below",
toolbar_sticky=False,
)
plot.line(dist,vstream,legend="River Stream Velocity (m/s)")
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.xaxis.axis_label = "Distance (m)"
plot.yaxis.axis_label = "River Current (m/s)"
plot.y_range = Range1d(-2,2)
script, div = components(plot)
return [script,div]
def interactive_chart(id=0,promember=0):
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
f1 = row.csvfilename
# create interactive plot
# get user
# u = User.objects.get(id=row.user.id)
r = row.user
u = r.user
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return "","CSV Data File Not Found"
t = rowdata.df.ix[:,'TimeStamp (sec)']
t = t-rowdata.df.ix[0,'TimeStamp (sec)']
row_index = rowdata.df.ix[:,' Stroke500mPace (sec/500m)'] > 3000
rowdata.df.loc[row_index,' Stroke500mPace (sec/500m)'] = 3000.
p = rowdata.df.ix[:,' Stroke500mPace (sec/500m)']
hr = rowdata.df.ix[:,' HRCur (bpm)']
spm = rowdata.df.ix[:,' Cadence (stokes/min)']
cumdist = rowdata.df.ix[:,'cum_dist']
f = rowdata.df['TimeStamp (sec)'].diff().mean()
windowsize = 2*(int(10./(f)))+1
if windowsize <= 3:
windowsize = 5
if windowsize > 3:
spm = savgol_filter(spm,windowsize,3)
t2 = get_datetimes(t,tzinfo=1)
# p[p>3000] = 3000.
p2 = get_datetimes(p)
source = ColumnDataSource(
data = dict(
x=t2,
y=hr,
y2=p2,
tf = niceformat(t2),
pace = nicepaceformat(p2),
heartrate = hr,
spm=spm,
spmc=np.rint(10*spm)/10.,
cumdist=cumdist,
)
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
plot_width=400,
plot_height=400,
toolbar_sticky=False,
# toolbar_location="below",
tools=TOOLS)
# plot.line(t2,p2,legend="Pace")
plot.line('x','y2',source=source,legend="Pace")
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.xaxis.axis_label = "Time"
plot.yaxis.axis_label = "Pace (/500m)"
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,2,30)
if row.workouttype == 'water':
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,3,30)
plot.y_range = Range1d(ymin,ymax)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@tf'),
('Pace','@pace'),
('HR','@heartrate'),
('SPM','@spmc{1.1}'),
('Distance','@cumdist{1.1}'),
])
hover.mode = 'mouse'
plot.extra_y_ranges = {"hr": Range1d(start=100,end=200)}
# plot.line(t2,hr,color="red",y_range_name="hr",legend="Heart Rate")
plot.line('x','y',source=source,color="red",
y_range_name="hr", legend="Heart Rate")
plot.add_layout(LinearAxis(y_range_name="hr",axis_label="HR"),'right')
plot.legend.location = "bottom_right"
script, div = components(plot)
return [script,div]
def interactive_cum_flex_chart(theworkouts,promember=0,
xparam='spm',
yparam1='power',
yparam2='hr',
):
therows = []
for workout in theworkouts:
f1 = workout.csvfilename
rowdata = rdata(f1)
if rowdata != 0:
therows.append(rowdata.df)
thedata = pd.concat(therows)
csvcolumns = {
'time': 'TimeStamp (sec)',
'distance': 'cum_dist',
'hr': ' HRCur (bpm)',
'spm': ' Cadence (stokes/min)',
'pace': ' Stroke500mPace (sec/500m)',
'power': ' Power (watts)',
'averageforce': ' AverageDriveForce (lbs)',
'drivelength': ' DriveLength (meters)',
'peakforce': ' PeakDriveForce (lbs)',
'driveenergy': 'driveenergy',
'drivespeed': 'drivespeed',
}
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)',
'driveenergy': 'Work per Stroke (J)',
'drivespeed': 'Drive Speed (m/s)',
'None': '',
}
yparamname1 = axlabels[yparam1]
yparamname2 = axlabels[yparam2]
yaxminima = {
'hr':100,
'spm':15,
'pace': datetime.datetime(2016,5,1,0,3,30),
'power': 0,
'averageforce': 0,
'peakforce': 0,
'drivelength':0.5,
'driveenergy': 0,
'drivespeed': 0,
}
yaxmaxima = {
'hr':200,
'spm':45,
'pace':datetime.datetime(2016,5,1,0,1,30),
'power': 600,
'averageforce':200,
'peakforce':400,
'drivelength':2.0,
'driveenergy': 1000,
'drivespeed':4,
}
thedata['driveenergy'] = thedata[' DriveLength (meters)']*thedata[' AverageDriveForce (lbs)']*4.44822
# throw out zeros from dataframe
thedata = thedata[thedata[csvcolumns[yparam1]] > 0]
thedata = thedata[thedata[csvcolumns[xparam]] > 0]
if yparam2 != 'None':
thedata = thedata[thedata[csvcolumns[yparam2]] > 0]
# check if dataframe not empty
if thedata.empty:
return ['','<p>No non-zero data in selection</p>','','']
spm = thedata.ix[:,csvcolumns['spm']]
f = thedata['TimeStamp (sec)'].diff().mean()
if not np.isnan(f):
windowsize = 2*(int(10./(f)))+1
else:
windowsize = 5
if windowsize <= 3:
windowsize = 5
if windowsize > 3:
spm = savgol_filter(spm,windowsize,3)
thedata[' Cadence (stokes/min)'] = spm
drivelength = thedata[' DriveLength (meters)']
if windowsize > 3:
drivelength = savgol_filter(drivelength,windowsize,3)
thedata[' DriveLength (meters)'] = drivelength
thedata['drivespeed'] = drivelength/thedata[' DriveTime (ms)']*1.0e3
x1 = thedata.ix[:,csvcolumns[xparam]]
y1 = thedata.ix[:,csvcolumns[yparam1]]
if yparam2 != 'None':
y2 = thedata.ix[:,csvcolumns[yparam2]]
else:
y2 = y1
if xparam=='time':
xaxmax = x1.max()
xaxmin = x1.min()
xaxmax = get_datetimes([xaxmax],tzinfo=1)[0]
xaxmin = get_datetimes([xaxmin],tzinfo=1)[0]
x1 = get_datetimes(x1,tzinfo=1)
elif xparam=='distance':
xaxmax = x1.max()
xaxmin = x1.min()
else:
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
# average values
if xparam != 'time':
x1mean = x1.mean()
else:
x1mean = 0
y1mean = y1.mean()
y2mean = y2.mean()
if xparam != 'time':
xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.
else:
xvals = np.arange(100)
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
y1 = get_datetimes(y1)
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,2,30)
time = thedata.ix[:,csvcolumns['time']]
hr = thedata.ix[:,csvcolumns['hr']]
if windowsize > 3:
hr = savgol_filter(hr,windowsize,3)
pace = thedata.ix[:,csvcolumns['pace']]
distance = thedata.ix[:,csvcolumns['distance']]
power = thedata.ix[:,csvcolumns['power']]
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,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
if (xparam != 'time') and (xparam != 'distance'):
plot.add_layout(x1means)
plot.add_layout(y1means)
source = ColumnDataSource(
data = dict(
x1=x1,
y1=y1,
y2=y2,
time=niceformat(get_datetimes(time,tzinfo=1)),
pace=nicepaceformat(get_datetimes(pace)),
hr = hr,
spm = spm,
spmc=np.rint(10*spm)/10.,
distance=distance,
power=power,
)
)
source2 = ColumnDataSource(
data = dict(
x1=x1,
y1=y1,
y2=y2,
time=niceformat(get_datetimes(time,tzinfo=1)),
pace=nicepaceformat(get_datetimes(pace)),
hr = hr,
spm = spm,
spmc=np.rint(10*spm)/10.,
distance=distance,
power=power,
)
)
# plot.circle('x1','y1',source=source,legend=yparam1,size=3)
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
if (xparam != 'time') and (xparam != 'distance'):
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
plot.x_range = xrange1
if xparam == 'time':
xrange1 = Range1d(start=xaxmin,end=xaxmax)
plot.x_range = xrange1
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
if yparam1 == 'pace':
plot.y_range = Range1d(ymin,ymax)
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
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)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@time'),
('Pace','@pace'),
('HR','@hr'),
('SPM','@spmc{1.1}'),
('Power','@power{int}'),
])
hover.mode = 'mouse'
callback = CustomJS(args = dict(source=source,source2=source2,
x1means=x1means,
y1means=y1means,
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 time1 = data['time']
var pace1 = data['pace']
var hr1 = data['hr']
var spmc1 = data['spmc']
var distance1 = data['distance']
var power1 = data['power']
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['time'] = []
data2['pace'] = []
data2['hr'] = []
data2['spmc'] = []
data2['distance'] = []
data2['power'] = []
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['time'].push(time1[i])
data2['pace'].push(pace1[i])
data2['hr'].push(hr1[i])
data2['spmc'].push(spmc1[i])
data2['distance'].push(distance1[i])
data2['power'].push(power1[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
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(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_flex_chart(id=0,promember=0,
xparam='time',
yparam1='pace',
yparam2='hr',
plottype='line',
workstrokesonly=False):
csvcolumns = {
'time': 'TimeStamp (sec)',
'distance': 'cum_dist',
'hr': ' HRCur (bpm)',
'spm': ' Cadence (stokes/min)',
'pace': ' Stroke500mPace (sec/500m)',
'power': ' Power (watts)',
'averageforce': ' AverageDriveForce (lbs)',
'drivelength': ' DriveLength (meters)',
'peakforce': ' PeakDriveForce (lbs)',
'driveenergy': 'driveenergy',
'drivespeed': 'drivespeed',
}
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)',
'driveenergy': 'Work per Stroke (J)',
'drivespeed': 'Drive Speed (m/s)',
'None': '',
}
yaxminima = {
'hr':100,
'spm':15,
'pace': datetime.datetime(2016,5,1,0,3,30),
'power': 0,
'averageforce': 0,
'peakforce': 0,
'drivelength':0.5,
'driveenergy': 0,
'drivespeed': 0,
}
yaxmaxima = {
'hr':200,
'spm':45,
'pace':datetime.datetime(2016,5,1,0,1,30),
'power': 600,
'averageforce':200,
'peakforce':400,
'drivelength':2.0,
'driveenergy': 1000,
'drivespeed':4,
}
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
f1 = row.csvfilename
r = row.user
u = r.user
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return "","CSV Data File Not Found"
workoutstateswork = [1,4,5,8,9,6,7]
workoutstatesrest = [3]
workoutstatetransition = [0,2,10,11,12,13]
if workstrokesonly:
try:
rowdata.df = rowdata.df[~rowdata.df[' WorkoutState'].isin(workoutstatesrest)]
except KeyError:
pass
rowdata.df['driveenergy'] = rowdata.df[' DriveLength (meters)']*rowdata.df[' AverageDriveForce (lbs)']*4.44822
f = rowdata.df['TimeStamp (sec)'].diff().mean()
windowsize = 2*(int(10./(f)))+1
if windowsize <= 3:
windowsize = 5
spm = rowdata.df.ix[:,csvcolumns['spm']]
hr = rowdata.df.ix[:,csvcolumns['hr']]
if windowsize > 3:
spm = savgol_filter(spm,windowsize,3)
hr = savgol_filter(hr,windowsize,3)
rowdata.df[' Cadence (stokes/min)'] = spm
rowdata.df[' HRCur (bpm)'] = hr
drivelength = rowdata.df[' DriveLength (meters)']
if windowsize > 3:
drivelength = savgol_filter(drivelength,windowsize,3)
rowdata.df[' DriveLength (meters)'] = drivelength
rowdata.df['drivespeed'] = drivelength/rowdata.df[' DriveTime (ms)']*1.0e3
# get user
# u = User.objects.get(id=row.user.id)
x1 = rowdata.df.ix[:,csvcolumns[xparam]]
y1 = rowdata.df.ix[:,csvcolumns[yparam1]]
if yparam2 != 'None':
y2 = rowdata.df.ix[:,csvcolumns[yparam2]]
else:
y2 = y1
if xparam=='time':
xaxmax = x1.max()
xaxmin = x1.min()
xaxmax = get_datetimes([xaxmax],tzinfo=1)[0]
xaxmin = get_datetimes([xaxmin],tzinfo=1)[0]
x1 = get_datetimes(x1,tzinfo=1)
if xparam=='distance':
xaxmax = x1.max()
xaxmin = x1.min()
# average values
y1mean = y1.median()+0.0*np.arange(100)
y2mean = y2.median()+0.0*np.arange(100)
if xparam != 'time':
x1mean = x1.median()+0.0*np.arange(100)
else:
x1mean = 0+0.0*np.arange(100)
if xparam != 'time' and xparam != 'distance' and yparam1 != 'pace':
xvals = yaxminima[xparam]+np.arange(100)*(yaxmaxima[xparam]-yaxminima[xparam])/100.
y1vals = yaxminima[yparam1]+np.arange(100)*(yaxmaxima[yparam1]-yaxminima[yparam1])/100.
else:
xvals = np.arange(100)
y1vals = np.arange(100)
# constant power plot
if yparam1 == 'driveenergy':
if xparam == 'spm':
yconstantpower = y1.median()*x1.median()/xvals
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
y1 = get_datetimes(y1)
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,2,30)
if row.workouttype == 'water':
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,3,30)
time = rowdata.df.ix[:,csvcolumns['time']]
time = time-time[time.index[0]]
hr = rowdata.df.ix[:,csvcolumns['hr']]
pace = rowdata.df.ix[:,csvcolumns['pace']]
distance = rowdata.df.ix[:,csvcolumns['distance']]
power = rowdata.df.ix[:,csvcolumns['power']]
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,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_sticky=False,
plot_width=900,
)
source = ColumnDataSource(
data = dict(
x1=x1,
y1=y1,
y2=y2,
time=niceformat(get_datetimes(time,tzinfo=1)),
pace=nicepaceformat(get_datetimes(pace)),
hr = hr,
spm = spm,
spmc=np.rint(10*spm)/10.,
distance=distance,
power=power,
xvals=xvals,
y1mean=y1mean,
x1mean=x1mean,
y1vals=y1vals,
)
)
# average values
plot.line('xvals','y1mean',color="black",source=source)
plot.line('x1mean','y1vals',color="black",source=source)
if yparam1 == 'driveenergy':
if xparam == 'spm':
plot.line(xvals,yconstantpower,color="green",legend="Constant Power")
if plottype=='line':
plot.line('x1','y1',source=source,legend=axlabels[yparam1])
elif plottype=='scatter':
# plot.circle('x1','y1',source=source,legend=yparam1,size=3)
plot.scatter('x1','y1',source=source,legend=axlabels[yparam1],fill_alpha=0.4,
line_color=None)
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.xaxis.axis_label = axlabels[xparam]
plot.yaxis.axis_label = axlabels[yparam1]
yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
plot.y_range = yrange1
if (xparam != 'time') and (xparam != 'distance'):
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
plot.x_range = xrange1
if xparam == 'time':
xrange1 = Range1d(start=xaxmin,end=xaxmax)
plot.x_range = xrange1
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
if yparam1 == 'pace':
plot.y_range = Range1d(ymin,ymax)
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
if yparam2 != 'None':
yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2])
plot.extra_y_ranges = {"yax2": yrange2}
plot.line(xvals,y2mean,color="black",y_range_name="yax2")
if plottype=='line':
plot.line('x1','y2',color="red",y_range_name="yax2",
legend=axlabels[yparam2],
source=source)
elif plottype=='scatter':
# plot.circle(x1,y2,color="red",y_range_name="yax2",legend=yparam2,
# source=source,size=3)
plot.scatter('x1','y2',source=source,legend=axlabels[yparam2]
,fill_alpha=0.4,
line_color=None,color="red",y_range_name="yax2")
plot.add_layout(LinearAxis(y_range_name="yax2",
axis_label=axlabels[yparam2]),'right')
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@time'),
('Distance','@distance{int}'),
('Pace','@pace'),
('HR','@hr'),
('SPM','@spmc{1.1}'),
('Power','@power{int}'),
])
hover.mode = 'mouse'
script, div = components(plot)
return [script,div]
def interactive_flex_chart2(id=0,promember=0,
xparam='time',
yparam1='pace',
yparam2='hr',
plottype='line',
workstrokesonly=False):
csvcolumns = {
'time': 'TimeStamp (sec)',
'distance': 'cum_dist',
'hr': ' HRCur (bpm)',
'spm': ' Cadence (stokes/min)',
'pace': ' Stroke500mPace (sec/500m)',
'power': ' Power (watts)',
'averageforce': ' AverageDriveForce (lbs)',
'drivelength': ' DriveLength (meters)',
'peakforce': ' PeakDriveForce (lbs)',
'driveenergy': 'driveenergy',
'drivespeed': 'drivespeed',
}
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)',
'driveenergy': 'Work per Stroke (J)',
'drivespeed': 'Drive Speed (m/s)',
'None': '',
}
yaxminima = {
'hr':100,
'spm':15,
'pace': datetime.datetime(2016,5,1,0,3,30),
'power': 0,
'averageforce': 0,
'peakforce': 0,
'drivelength':0.5,
'driveenergy': 0,
'drivespeed': 0,
}
yaxmaxima = {
'hr':200,
'spm':45,
'pace':datetime.datetime(2016,5,1,0,1,30),
'power': 600,
'averageforce':200,
'peakforce':400,
'drivelength':2.0,
'driveenergy': 1000,
'drivespeed':4,
}
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
f1 = row.csvfilename
r = row.user
u = r.user
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return "","CSV Data File Not Found"
workoutstateswork = [1,4,5,8,9,6,7]
workoutstatesrest = [3]
workoutstatetransition = [0,2,10,11,12,13]
if workstrokesonly:
try:
rowdata.df = rowdata.df[~rowdata.df[' WorkoutState'].isin(workoutstatesrest)]
except KeyError:
pass
rowdata.df['driveenergy'] = rowdata.df[' DriveLength (meters)']*rowdata.df[' AverageDriveForce (lbs)']*4.44822
spm = rowdata.df.ix[:,csvcolumns['spm']]
hr = rowdata.df.ix[:,csvcolumns['hr']]
f = rowdata.df['TimeStamp (sec)'].diff().mean()
windowsize = 2*(int(10./(f)))+1
if windowsize <= 3:
windowsize = 5
if windowsize > 3:
spm = savgol_filter(spm,windowsize,3)
hr = savgol_filter(hr,windowsize,3)
rowdata.df[' Cadence (stokes/min)'] = spm
rowdata.df[' HRCur (bpm)'] = hr
drivelength = rowdata.df[' DriveLength (meters)']
if windowsize > 3:
drivelength = savgol_filter(drivelength,windowsize,3)
rowdata.df[' DriveLength (meters)'] = drivelength
rowdata.df['drivespeed'] = drivelength/rowdata.df[' DriveTime (ms)']*1.0e3
# get user
# u = User.objects.get(id=row.user.id)
x1 = rowdata.df.ix[:,csvcolumns[xparam]]
y1 = rowdata.df.ix[:,csvcolumns[yparam1]]
if yparam2 != 'None':
y2 = rowdata.df.ix[:,csvcolumns[yparam2]]
else:
y2 = y1
if xparam=='time':
xaxmax = x1.max()
xaxmin = x1.min()
xaxmax = get_datetimes([xaxmax],tzinfo=1)[0]
xaxmin = get_datetimes([xaxmin],tzinfo=1)[0]
x1 = get_datetimes(x1,tzinfo=1)
elif xparam=='distance':
xaxmax = x1.max()
xaxmin = x1.min()
else:
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
# average values
if xparam != 'time':
x1mean = x1.mean()
else:
x1mean = 0
y1mean = y1.mean()
y2mean = y2.mean()
if xparam != 'time':
xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.
else:
xvals = np.arange(100)
# constant power plot
if yparam1 == 'driveenergy':
if xparam == 'spm':
yconstantpower = y1.median()*x1.median()/xvals
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
y1 = get_datetimes(y1)
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,2,30)
if row.workouttype == 'water':
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,3,30)
time = rowdata.df.ix[:,csvcolumns['time']]
time = time-time[time.index[0]]
hr = rowdata.df.ix[:,csvcolumns['hr']]
pace = rowdata.df.ix[:,csvcolumns['pace']]
distance = rowdata.df.ix[:,csvcolumns['distance']]
power = rowdata.df.ix[:,csvcolumns['power']]
# prepare data
source = ColumnDataSource(
data = dict(
x1=x1,
y1=y1,
y2=y2,
time=niceformat(get_datetimes(time,tzinfo=1)),
pace=nicepaceformat(get_datetimes(pace)),
hr = hr,
spm = spm,
spmc=np.rint(10*spm)/10.,
distance=distance,
power=power,
# xvals=xvals,
y1mean=[y1mean,y1mean],
y2mean=[y2mean,y2mean],
x1mean=[x1mean,x1mean],
)
)
# second source for filtering
source2 = ColumnDataSource(
data = dict(
x1=x1,
y1=y1,
y2=y2,
time=niceformat(get_datetimes(time,tzinfo=1)),
pace=nicepaceformat(get_datetimes(pace)),
hr = hr,
spm = spm,
spmc=np.rint(10*spm)/10.,
distance=distance,
power=power,
# xvals=xvals,
y1mean=[y1mean,y1mean],
y2mean=[y2mean,y2mean],
x1mean=[x1mean,x1mean],
)
)
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
sizing_mode = 'fixed' # 'scale_width' also looks nice with this example
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
toolbar_sticky=False,
# plot_width=900,
)
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
if (xparam != 'time') and (xparam != 'distance'):
plot.add_layout(x1means)
plot.add_layout(y1means)
# average values
if yparam1 == 'driveenergy':
if xparam == 'spm':
plot.line(xvals,yconstantpower,color="green",legend="Constant Power")
if plottype=='line':
plot.line('x1','y1',source=source2,legend=axlabels[yparam1])
elif plottype=='scatter':
# plot.circle('x1','y1',source=source2,legend=yparam1,size=3)
plot.scatter('x1','y1',source=source2,legend=axlabels[yparam1],fill_alpha=0.4,
line_color=None)
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.xaxis.axis_label = axlabels[xparam]
plot.yaxis.axis_label = axlabels[yparam1]
yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
plot.y_range = yrange1
if (xparam != 'time') and (xparam != 'distance'):
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
plot.x_range = xrange1
if xparam == 'time':
xrange1 = Range1d(start=xaxmin,end=xaxmax)
plot.x_range = xrange1
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
if yparam1 == 'pace':
plot.y_range = Range1d(ymin,ymax)
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
if yparam2 != 'None':
yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2])
plot.extra_y_ranges = {"yax2": yrange2}
if plottype=='line':
plot.line('x1','y2',color="red",y_range_name="yax2",
legend=axlabels[yparam2],
source=source2)
<<<<<<< HEAD
elif plottype=='scatter':
# plot.circle(x1,y2,color="red",y_range_name="yax2",legend=yparam2,
# source=source,size=3)
plot.scatter('x1','y2',source=source2,legend=axlabels[yparam2]
,fill_alpha=0.4,
line_color=None,color="red",y_range_name="yax2")
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)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@time'),
('Distance','@distance'),
('Pace','@pace'),
('HR','@hr'),
('SPM','@spmc{1.1}'),
('Power','@power{int}'),
])
hover.mode = 'mouse'
=======
elif plottype=='scatter':
# plot.circle(x1,y2,color="red",y_range_name="yax2",legend=yparam2,
# source=source,size=3)
plot.scatter('x1','y2',source=source2,legend=axlabels[yparam2]
,fill_alpha=0.4,
line_color=None,color="red",y_range_name="yax2")
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)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@time'),
('Distance','@distance'),
('Pace','@pace'),
('HR','@hr'),
('SPM','@spmc{1.1}'),
('Power','@power{int}'),
])
hover.mode = 'mouse'
>>>>>>> feature/sliders
callback = CustomJS(args = dict(source=source,source2=source2,
x1means=x1means,
y1means=y1means,
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 time1 = data['time']
var pace1 = data['pace']
var hr1 = data['hr']
var spmc1 = data['spmc']
var distance1 = data['distance']
var power1 = data['power']
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['time'] = []
data2['pace'] = []
data2['hr'] = []
data2['spmc'] = []
data2['distance'] = []
data2['power'] = []
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['time'].push(time1[i])
data2['pace'].push(pace1[i])
data2['hr'].push(hr1[i])
data2['spmc'].push(spmc1[i])
data2['distance'].push(distance1[i])
data2['power'].push(power1[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
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(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_bar_chart(id=0,promember=0):
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
f1 = row.csvfilename
# create interactive plot
plot = Figure(plot_width=400,plot_height=300)
# get user
# u = User.objects.get(id=row.user.id)
r = row.user
u = r.user
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return "","CSV Data File Not Found"
t = rowdata.df.ix[:,'TimeStamp (sec)']
t = t-rowdata.df.ix[0,'TimeStamp (sec)']
row_index = rowdata.df.ix[:,' Stroke500mPace (sec/500m)'] > 3000
rowdata.df.loc[row_index,' Stroke500mPace (sec/500m)'] = 3000.
p = rowdata.df.ix[:,' Stroke500mPace (sec/500m)']
hr = rowdata.df.ix[:,' HRCur (bpm)']
spm = rowdata.df.ix[:,' Cadence (stokes/min)']
f = rowdata.df['TimeStamp (sec)'].diff().mean()
windowsize = 2*(int(10./(f)))+1
if windowsize <= 3:
windowsize = 5
if windowsize > 3:
spm = savgol_filter(spm,windowsize,3)
rowdata.df[' Cadence (stokes/min)'] = spm
drivelength = rowdata.df[' DriveLength (meters)']
if windowsize > 3:
drivelength = savgol_filter(drivelength,windowsize,3)
rowdata.df[' DriveLength (meters)'] = drivelength
hr_ut2 = rowdata.df.ix[:,'hr_ut2']
hr_ut1 = rowdata.df.ix[:,'hr_ut1']
hr_at = rowdata.df.ix[:,'hr_at']
hr_tr = rowdata.df.ix[:,'hr_tr']
hr_an = rowdata.df.ix[:,'hr_an']
hr_max = rowdata.df.ix[:,'hr_max']
# time increments for bar chart
time_increments = rowdata.df.ix[:,' ElapsedTime (sec)'].diff()
time_increments[0] = time_increments[1]
time_increments = 0.5*time_increments+0.5*np.abs(time_increments)
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
t2 = get_datetimes(t,tzinfo=1)
p2 = get_datetimes(p)
source = ColumnDataSource(
data = dict(
x=t2,
x_right = get_datetimes(t+time_increments,tzinfo=1),
hr=hr,
hr_ut2=hr_ut2,
hr_ut1=hr_ut1,
hr_at=hr_at,
hr_tr=hr_tr,
hr_an=hr_an,
hr_max=hr_max,
hr_bottom = 0.0*hr,
y2=p2,
tf = niceformat(t2),
pace = nicepaceformat(p2),
heartrate = hr,
spmc=np.rint(10*spm)/10.,
spm=spm,
)
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
toolbar_sticky=False,
plot_width=920,
# toolbar_location="above",
tools=TOOLS)
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.xaxis.axis_label = "Time"
plot.yaxis.axis_label = "Pace (/500m)"
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours ="",
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"],
)
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,2,30)
if row.workouttype == 'water':
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,3,30)
plot.y_range = Range1d(ymin,ymax)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@tf'),
('Pace','@pace'),
('HR','@heartrate'),
('SPM','@spmc{1.1}'),
])
hover.mode = 'mouse'
plot.extra_y_ranges = {"hr": Range1d(start=100,end=200)}
plot.quad(left='x',top='hr_ut2',bottom='hr_bottom',
right='x_right',source=source,color="gray",
y_range_name="hr", legend="<UT2")
plot.quad(left='x',top='hr_ut1',bottom='hr_bottom',
right='x_right',source=source,color="tan",
y_range_name="hr", legend="UT2")
plot.quad(left='x',top='hr_at',bottom='hr_bottom',
right='x_right',source=source,color="green",
y_range_name="hr", legend="UT1")
plot.quad(left='x',top='hr_tr',bottom='hr_bottom',
right='x_right',source=source,color="blue",
y_range_name="hr", legend="AT")
plot.quad(left='x',top='hr_an',bottom='hr_bottom',
right='x_right',source=source,color="violet",
y_range_name="hr", legend="TR")
plot.quad(left='x',top='hr_max',bottom='hr_bottom',
right='x_right',source=source,color="red",
y_range_name="hr", legend="AN")
plot.add_layout(LinearAxis(y_range_name="hr",axis_label="HR"),'right')
plot.line('x','y2',source=source,legend="Pace",color="black")
script, div = components(plot)
return [script,div]
def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
promember=0,plottype='line'):
csvcolumns = {
'time': 'TimeStamp (sec)',
'distance': 'cum_dist',
'hr': ' HRCur (bpm)',
'spm': ' Cadence (stokes/min)',
'pace': ' Stroke500mPace (sec/500m)',
'power': ' Power (watts)',
'averageforce': ' AverageDriveForce (lbs)',
'drivelength': ' DriveLength (meters)',
'peakforce': ' PeakDriveForce (lbs)',
'driveenergy': 'driveenergy',
'drivespeed': 'drivespeed',
}
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)',
'driveenergy': 'Work per Stroke (J)',
'drivespeed': 'Drive Speed (m/s)',
}
# check if valid ID exists (workout exists)
row1 = Workout.objects.get(id=id1)
row2 = Workout.objects.get(id=id2)
f1 = row1.csvfilename
f2 = row2.csvfilename
rowdata1 = rdata(f1)
if rowdata1 == 0:
return "","CSV Data File Not Found"
rowdata2 = rdata(f2)
if rowdata2 == 0:
return "","CSV Data File Not Found"
rowdata1.df['driveenergy'] = rowdata1.df[' DriveLength (meters)']*rowdata1.df[' AverageDriveForce (lbs)']*4.44822
rowdata2.df['driveenergy'] = rowdata2.df[' DriveLength (meters)']*rowdata2.df[' AverageDriveForce (lbs)']*4.44822
spm1 = rowdata1.df.ix[:,csvcolumns['spm']]
spm2 = rowdata2.df.ix[:,csvcolumns['spm']]
f = rowdata1.df['TimeStamp (sec)'].diff().mean()
windowsize = 2*(int(10./(f)))+1
if windowsize <= 3:
windowsize = 5
if windowsize > 3:
spm1 = savgol_filter(spm1,windowsize,3)
rowdata1.df[' Cadence (stokes/min)'] = spm1
drivelength1 = rowdata1.df[' DriveLength (meters)']
if windowsize > 3:
drivelength1 = savgol_filter(drivelength1,windowsize,3)
rowdata1.df[' DriveLength (meters)'] = drivelength1
drivelength2 = rowdata2.df[' DriveLength (meters)']
if windowsize > 3:
drivelength2 = savgol_filter(drivelength2,windowsize,3)
rowdata2.df[' DriveLength (meters)'] = drivelength2
f = rowdata2.df['TimeStamp (sec)'].diff().mean()
windowsize = 2*(int(10./(f)))+1
if windowsize <= 3:
windowsize = 5
if windowsize > 3:
spm2 = savgol_filter(spm2,windowsize,3)
rowdata2.df[' Cadence (stokes/min)'] = spm2
drivelength2 = rowdata2.df[' DriveLength (meters)']
if windowsize > 3:
drivelength2 = savgol_filter(drivelength2,windowsize,3)
rowdata2.df[' DriveLength (meters)'] = drivelength2
rowdata1.df['drivespeed'] = drivelength1/rowdata1.df[' DriveTime (ms)']*1.0e3
rowdata2.df['drivespeed'] = drivelength2/rowdata2.df[' DriveTime (ms)']*1.0e3
x1 = rowdata1.df.ix[:,csvcolumns[xparam]]
x2 = rowdata2.df.ix[:,csvcolumns[xparam]]
y1 = rowdata1.df.ix[:,csvcolumns[yparam]]
y2 = rowdata2.df.ix[:,csvcolumns[yparam]]
if xparam=='time':
x1 = x1-x1[0]
x2 = x2-x2[0]
x1 = get_datetimes(x1,tzinfo=1)
x2 = get_datetimes(x2,tzinfo=1)
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam == 'pace':
y_axis_type = 'datetime'
y1 = get_datetimes(y1)
y2 = get_datetimes(y2)
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,2,30)
if row1.workouttype == 'water':
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,3,30)
time1 = rowdata1.df.ix[:,csvcolumns['time']]
time2 = rowdata2.df.ix[:,csvcolumns['time']]
time1 = time1-time1[0]
time2 = time2-time2[0]
hr1 = rowdata1.df.ix[:,csvcolumns['hr']]
hr2 = rowdata2.df.ix[:,csvcolumns['hr']]
pace1 = rowdata1.df.ix[:,csvcolumns['pace']]
pace2 = rowdata2.df.ix[:,csvcolumns['pace']]
distance1 = rowdata1.df.ix[:,csvcolumns['distance']]
distance2 = rowdata2.df.ix[:,csvcolumns['distance']]
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
source = ColumnDataSource(
data = dict(
x1=x1,
x2=x2,
y1=y1,
y2=y2,
time1=niceformat(get_datetimes(time1,tzinfo=1)),
time2=niceformat(get_datetimes(time2,tzinfo=1)),
pace1=nicepaceformat(get_datetimes(pace1)),
pace2=nicepaceformat(get_datetimes(pace2)),
hr1 = hr1,
hr2 = hr2,
spm1 = spm1,
spm2 = spm2,
spm1c=np.rint(10*spm1)/10.,
spm2c=np.rint(10*spm2)/10.,
distance1=distance1,
distance2=distance2,
)
)
# create interactive plot
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
plot_width=920,
# toolbar_location="above",
toolbar_sticky=False)
# plot.multi_line([x1,x2],[y1,y2],color=["blue","red"])
if plottype=='line':
plot.line('x1','y1',source=source,color="blue",legend=row1.name)
plot.line('x2','y2',source=source,color="red",legend=row2.name)
elif plottype=='scatter':
# plot.circle('x1','y1',source=source,color="blue",legend=row1.name,size=3)
# plot.circle('x2','y2',source=source,color="red",legend=row2.name,size=3)
plot.scatter('x1','y1',source=source,legend=row1.name,fill_alpha=0.4,
line_color=None)
plot.scatter('x2','y2',source=source,legend=row2.name,fill_alpha=0.4,
line_color=None,color="red")
# plot.scatter('x1','y1',source=source,color="blue")
# plot.scatter('x2','y2',source=source,color="red")
plot.legend.location = "bottom_right"
plot.title.text = row1.name+' vs '+row2.name
plot.title.text_font_size=value("1.2em")
plot.xaxis.axis_label = axlabels[xparam]
plot.yaxis.axis_label = axlabels[yparam]
if xparam == 'time':
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
if yparam == 'pace':
plot.y_range = Range1d(ymin,ymax)
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
#hover = [t for t in plot.tools if isinstance(t, HoverTool)][0]
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('time1','@time1'),
('time2','@time2'),
('pace1','@pace1'),
('pace2','@pace2'),
('hr1','@hr1'),
('hr2','@hr2'),
('spm1','@spm1c{1.1}'),
('spm2','@spm2c{1.1}'),
('distance1','@distance1{5}'),
('distance2','@distance2{5}'),
])
hover.mode = 'mouse'
script, div = components(plot)
return [script,div]
def interactive_otw_advanced_pace_chart(id=0,promember=0):
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
f1 = row.csvfilename
# get user
# u = User.objects.get(id=row.user.id)
r = row.user
u = r.user
rowdata = rdata(f1)
if rowdata == 0:
return "","CSV Data File Not Found"
t = rowdata.df.ix[:,'TimeStamp (sec)']
t = t-rowdata.df.ix[0,'TimeStamp (sec)']
row_index = rowdata.df.ix[:,' Stroke500mPace (sec/500m)'] > 3000
rowdata.df.loc[row_index,' Stroke500mPace (sec/500m)'] = 3000.
p = rowdata.df.ix[:,' Stroke500mPace (sec/500m)']
try:
nowindpace = rowdata.df.ix[:,'nowindpace']
except KeyError:
nowindpace = p
try:
equivergpower = rowdata.df.ix[:,'equivergpower']
except KeyError:
equivergpower = 0*p+50.
ergvelo = (equivergpower/2.8)**(1./3.)
# ergvelo = stravastuff.ewmovingaverage(ergvelo,25)
ergpace = 500./ergvelo
ergpace[ergpace == np.inf] = 240.
hr = rowdata.df.ix[:,' HRCur (bpm)']
spm = rowdata.df.ix[:,' Cadence (stokes/min)']
f = rowdata.df['TimeStamp (sec)'].diff().mean()
windowsize = 2*(int(10./(f)))+1
if windowsize <= 3:
windowsize = 5
if windowsize > 3:
spm = savgol_filter(spm,windowsize,3)
rowdata.df[' Cadence (stokes/min)'] = spm
drivelength = rowdata.df[' DriveLength (meters)']
if windowsize > 3:
drivelength = savgol_filter(drivelength,windowsize,3)
rowdata.df[' DriveLength (meters)'] = drivelength
t2 = get_datetimes(t,tzinfo=1)
p2 = get_datetimes(p)
nowindp2 = get_datetimes(nowindpace)
ergpace2 = get_datetimes(ergpace)
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
source = ColumnDataSource(
data = dict(
x=t2,
p=p2,
nowindp2 = nowindp2,
ergpace2 = ergpace2,
tf = niceformat(t2),
pace = nicepaceformat(p2),
ergpace = nicepaceformat(ergpace2),
nowindpace = nicepaceformat(nowindp2),
heartrate = hr,
spm=spm,
spmc=np.rint(10*spm)/10.,
)
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
tools=TOOLS,
plot_width=920,
toolbar_sticky=False)
plot.title.text = row.name
plot.title.text_font_size=value("1.2em")
plot.xaxis.axis_label = "Time"
plot.yaxis.axis_label = "Pace (/500m)"
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
ymax = datetime.datetime(2016,5,1,0,1,30)
ymin = datetime.datetime(2016,5,1,0,3,30)
plot.y_range = Range1d(ymin,ymax)
hover = plot.select(dict(type=HoverTool))
plot.line('x','p',source=source,legend="Pace",color="black")
plot.line('x','nowindp2',source=source,legend="Corrected Pace",color="red")
plot.line('x','ergpace2',source=source,legend="Equivalent Erg Pace",color="blue")
hover.tooltips = OrderedDict([
('Time','@tf'),
('Pace','@pace'),
('Corrected Pace','@nowindpace'),
('Equiv. Erg Pace','@ergpace'),
('HR','@heartrate'),
('SPM','@spmc{1.1}'),
])
hover.mode = 'mouse'
script, div = components(plot)
return [script,div]