Private
Public Access
1
0
Files
rowsandall/rowers/interactiveplots.py
Sander Roosendaal d670cdf0f7 Merge tag 'v1.55' into develop
fixed flex chart bug
2017-03-12 22:21:26 +01:00

2061 lines
56 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 django.utils import timezone
from bokeh.palettes import Dark2_8 as palette
import itertools
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
from bokeh.models import CustomJS,Slider
from bokeh.charts import Histogram,HeatMap
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, vplot
from bokeh.models import (
GMapPlot, GMapOptions, ColumnDataSource, Circle,
DataRange1d, PanTool, WheelZoomTool, BoxSelectTool,
SaveTool, ResizeTool, ResetTool, TapTool,CrosshairTool,BoxZoomTool,
Span, Label
)
#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
from rowers.dataprep import rdata
import rowers.dataprep as dataprep
axes = (
('time','Time',0,1e5,'basic'),
('distance', 'Distance (m)',0,1e5,'basic'),
('cumdist', 'Cumulative Distance (m)',0,1e5,'basic'),
('hr','Heart Rate (bpm)',100,200,'basic'),
('spm', 'Stroke Rate (spm)',15,45,'basic'),
('pace', 'Pace (/500m)',1.0e3*210,1.0e3*75,'basic'),
('power', 'Power (Watt)',0,600,'basic'),
('averageforce', 'Average Drive Force (lbs)',0,200,'pro'),
('drivelength', 'Drive Length (m)',0.5,2.0,'pro'),
('peakforce', 'Peak Drive Force (lbs)',0,400,'pro'),
('forceratio', 'Average/Peak Force Ratio',0,1,'pro'),
('driveenergy', 'Work per Stroke (J)',0,1000,'pro'),
('drivespeed', 'Drive Speed (m/s)',0,4,'pro'),
('slip', 'Slip (degrees)',0,20,'pro'),
('catch', 'Catch (degrees)',-40,-75,'pro'),
('finish', 'Finish (degrees)',20,55,'pro'),
('wash', 'Wash (degrees)',0,30,'pro'),
('peakforceangle', 'Peak Force Angle (degrees)',-20,20,'pro'),
('totalangle', 'Drive Length (deg)',40,140,'pro'),
('effectiveangle', 'Effective Drive Length (deg)',40,140,'pro'),
('rhythm', 'Stroke Rhythm (%)',20,55,'pro'),
('None', 'None',0,1,'basic'),
)
axlabels = {ax[0]:ax[1] for ax in axes}
yaxminima = {ax[0]:ax[2] for ax in axes}
yaxmaxima = {ax[0]:ax[3] for ax in axes}
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
from rowers.dataprep import nicepaceformat,niceformat
from rowers.dataprep import timedeltaconv
def interactive_forcecurve(theworkouts,workstrokesonly=False):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
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)
rowdata.dropna(axis=1,how='all',inplace=True)
rowdata.dropna(axis=0,how='any',inplace=True)
workoutstateswork = [1,4,5,8,9,6,7]
workoutstatesrest = [3]
workoutstatetransition = [0,2,10,11,12,13]
if workstrokesonly:
try:
rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)]
except KeyError:
pass
if rowdata.empty:
return "","No Valid Data Available","",""
catchav = rowdata['catch'].mean()
finishav = rowdata['finish'].mean()
washav = rowdata['wash'].mean()
slipav = rowdata['slip'].mean()
peakforceav = rowdata['peakforce'].mean()
averageforceav = rowdata['averageforce'].mean()
peakforceangleav = rowdata['peakforceangle'].mean()
x = [catchav,
catchav+slipav,
peakforceangleav,
finishav-washav,
finishav]
thresholdforce = 100 if 'x' in boattype else 200
thresholdforce /= 4.45 # N to lbs
y = [0,thresholdforce,
peakforceav,
thresholdforce,0]
source = ColumnDataSource(
data = dict(
x = x,
y = y,
))
source2 = ColumnDataSource(
rowdata
)
plot = Figure(tools=TOOLS,
toolbar_sticky=False)
avf = Span(location=averageforceav,dimension='width',line_color='blue',
line_dash=[6,6],line_width=2)
plot.line('x','y',source=source,color="red")
plot.add_layout(avf)
peakflabel = Label(x=455,y=530,x_units='screen',y_units='screen',
text="Fpeak: {peakforceav:6.2f}".format(peakforceav=peakforceav),
background_fill_alpha=.7,
text_color='blue',
)
avflabel = Label(x=465,y=500,x_units='screen',y_units='screen',
text="Favg: {averageforceav:6.2f}".format(averageforceav=averageforceav),
background_fill_alpha=.7,
text_color='blue',
)
catchlabel = Label(x=460,y=470,x_units='screen',y_units='screen',
text="Catch: {catchav:6.2f}".format(catchav=catchav),
background_fill_alpha=0.7,
text_color='red',
)
peakforceanglelabel = Label(x=420,y=440,x_units='screen',y_units='screen',
text="Peak angle: {peakforceangleav:6.2f}".format(peakforceangleav=peakforceangleav),
background_fill_alpha=0.7,
text_color='red',
)
finishlabel = Label(x=455,y=410,x_units='screen',y_units='screen',
text="Finish: {finishav:6.2f}".format(finishav=finishav),
background_fill_alpha=0.7,
text_color='red',
)
sliplabel = Label(x=470,y=380,x_units='screen',y_units='screen',
text="Slip: {slipav:6.2f}".format(slipav=slipav),
background_fill_alpha=0.7,
text_color='red',
)
washlabel = Label(x=460,y=350,x_units='screen',y_units='screen',
text="Wash: {washav:6.2f}".format(washav=washav),
background_fill_alpha=0.7,
text_color='red',
)
plot.add_layout(peakflabel)
plot.add_layout(peakforceanglelabel)
plot.add_layout(avflabel)
plot.add_layout(catchlabel)
plot.add_layout(sliplabel)
plot.add_layout(washlabel)
plot.add_layout(finishlabel)
plot.xaxis.axis_label = "Angle"
plot.yaxis.axis_label = "Force (lbs)"
plot.title.text = theworkouts[0].name
plot.title.text_font_size=value("1.0em")
yrange1 = Range1d(start=0,end=200)
plot.y_range = yrange1
xrange1 = Range1d(start=yaxmaxima['catch'],end=yaxmaxima['finish'])
plot.x_range = xrange1
callback = CustomJS(args = dict(
source=source,
source2=source2,
avf=avf,
avflabel=avflabel,
catchlabel=catchlabel,
finishlabel=finishlabel,
sliplabel=sliplabel,
washlabel=washlabel,
peakflabel=peakflabel,
peakforceanglelabel=peakforceanglelabel,
), code="""
var data = source.data
var data2 = source2.data
var x = data['x']
var y = data['y']
var spm1 = data2['spm']
var distance1 = data2['distance']
var driveenergy1 = data2['driveenergy']
var thresholdforce = y[1]
var c = source2.data['catch']
var finish = data2['finish']
var slip = data2['slip']
var wash = data2['wash']
var peakforceangle = data2['peakforceangle']
var peakforce = data2['peakforce']
var averageforce = data2['averageforce']
var minspm = minspm.value
var maxspm = maxspm.value
var mindist = mindist.value
var maxdist = maxdist.value
var minwork = minwork.value
var maxwork = maxwork.value
var catchav = 0
var finishav = 0
var slipav = 0
var washav = 0
var peakforceangleav = 0
var averageforceav = 0
var peakforceav = 0
var count = 0
for (i=0; i<c.length; i++) {
if (spm1[i]>=minspm && spm1[i]<=maxspm) {
if (distance1[i]>=mindist && distance1[i]<=maxdist) {
if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
catchav += c[i]
finishav += finish[i]
slipav += slip[i]
washav += wash[i]
peakforceangleav += peakforceangle[i]
averageforceav += averageforce[i]
peakforceav += peakforce[i]
count += 1
}
}
}
}
catchav /= count
finishav /= count
slipav /= count
washav /= count
peakforceangleav /= count
peakforceav /= count
averageforceav /= count
data['x'] = [catchav,catchav+slipav,peakforceangleav,finishav-washav,finishav]
data['y'] = [0,thresholdforce,peakforceav,thresholdforce,0]
avf.location = averageforceav
avflabel.text = 'Favg: '+averageforceav.toFixed(2)
catchlabel.text = 'Catch: '+catchav.toFixed(2)
finishlabel.text = 'Finish: '+finishav.toFixed(2)
sliplabel.text = 'Slip: '+slipav.toFixed(2)
washlabel.text = 'Wash: '+washav.toFixed(2)
peakflabel.text = 'Fpeak: '+peakforceav.toFixed(2)
peakforceanglelabel.text = 'Peak angle: '+peakforceangleav.toFixed(2)
source.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
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=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,
slider_work_min,
slider_work_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_histoall(theworkouts):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
ids = [int(w.id) for w in theworkouts]
rowdata = dataprep.getsmallrowdata_db(['power'],ids=ids,doclean=True)
rowdata.dropna(axis=0,how='any',inplace=True)
if rowdata.empty:
return "","No Valid Data Available","",""
histopwr = rowdata['power'].values
if len(histopwr) == 0:
return "","No valid data available","",""
# throw out nans
histopwr = histopwr[~np.isinf(histopwr)]
histopwr = histopwr[histopwr > 25]
histopwr = histopwr[histopwr < 1000]
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'
map_options = GMapOptions(lat = lat.mean(),lng=lon.mean(),
map_type="roadmap",zoom=13)
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'
thesecs = pd.Series(thesecs)
velo = thedistances/thesecs
p = pd.Series(500./velo)
p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
source = ColumnDataSource(
data = dict(
dist = thedistances,
duration = thesecs,
spm = 0*theavpower,
tim = niceformat(
thesecs.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
),
power = theavpower,
fpace = 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 = pd.Series(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 = fitp.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
sourcepaul = ColumnDataSource(
data = dict(
dist = 10**fitx,
duration = fitt,
power = fitpower,
spm = 0*fitpower,
tim = niceformat(
fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
),
fpace = 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 = pd.Series(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 = fitp.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
sourcecomplex = ColumnDataSource(
data = dict(
dist = fitdist,
duration = fitt,
tim = niceformat(
fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
),
spm = 0*fitpower,
power = fitpower,
fpace = 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 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
source2 = ColumnDataSource(
data = dict(
duration = cpdata['Delta'],
power = cpdata['CP'],
tim = niceformat(
cpdata['Delta'].fillna(method='ffill').apply(lambda x: timedeltaconv(x))
),
dist = cpdata['Distance'],
pace = nicepaceformat(p2),
)
)
plot.circle('duration','power',source=source2,
fill_color='blue',size=3,
legend = 'Power from segments')
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Duration ','@tim'),
('Power (W)','@power{int}'),
('Distance (m)','@dist{int}'),
('Pace (/500m)','@fpace'),
])
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.line('duration','power',source=sourcepaul,legend="Paul's Law")
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,ftp=r.ftp)
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,gzip=True)
dataprep.update_strokedata(id,rowdata.df)
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,ftp=r.ftp)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return "","No Valid Data Available"
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,gzip=True)
dataprep.update_strokedata(id,rowdata.df)
# 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'
columns = ['time','pace','hr','fpace','ftime']
datadf = dataprep.getsmallrowdata_db(columns,ids=[id])
datadf.dropna(axis=0,how='any',inplace=True)
row = Workout.objects.get(id=id)
if datadf.empty:
return "","No Valid Data Available"
else:
datadf.sort_values(by='time',ascending=True,inplace=True)
#datadf,row = dataprep.getrowdata_db(id=id)
#if datadf.empty:
#return "","No Valid Data Available"
source = ColumnDataSource(
datadf
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
plot_width=400,
plot_height=400,
toolbar_sticky=False,
tools=TOOLS)
plot.line('time','pace',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 = 90.
ymin = 150.
if row.workouttype == 'water':
ymax = 90.
ymin = 210.
plot.y_range = Range1d(1.e3*ymin,1.e3*ymax)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Pace','@fpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
])
hover.mode = 'mouse'
plot.extra_y_ranges = {"hrax": Range1d(start=100,end=200)}
plot.line('time','hr',source=source,color="red",
y_range_name="hrax", legend="Heart Rate")
plot.add_layout(LinearAxis(y_range_name="hrax",axis_label="HR"),'right')
plot.legend.location = "bottom_right"
script, div = components(plot)
return [script,div]
def interactive_cum_flex_chart2(theworkouts,promember=0,
xparam='spm',
yparam1='power',
yparam2='spm'):
# datadf = dataprep.smalldataprep(theworkouts,xparam,yparam1,yparam2)
ids = [int(w.id) for w in theworkouts]
columns = [xparam,yparam1,yparam2,'spm','driveenergy','distance']
datadf = dataprep.getsmallrowdata_db(columns,ids=ids,doclean=False)
yparamname1 = axlabels[yparam1]
if yparam2 != 'None':
yparamname2 = axlabels[yparam2]
#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,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=100,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=100,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=100,y=70,x_units='screen',y_units='screen',
text=axlabels[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 driveenergy1 = data['driveenergy']
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 minwork = minwork.value
var maxwork = maxwork.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) {
if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
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
slider_work_min = Slider(start=0.0, end=1500,value=0.0, step=10,
title="Min Work per Stroke",callback=callback)
callback.args["minwork"] = slider_work_min
slider_work_max = Slider(start=0.0, end=1500,value=1500.0, step=10,
title="Max Work per Stroke",callback=callback)
callback.args["maxwork"] = slider_work_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,
slider_work_min,
slider_work_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_chart2(id=0,promember=0,
xparam='time',
yparam1='pace',
yparam2='hr',
plottype='line',
workstrokesonly=False):
#rowdata,row = dataprep.getrowdata_db(id=id)
columns = [xparam,yparam1,yparam2,
'ftime','distance','fpace',
'power','hr','spm','driveenergy',
'time','pace','workoutstate','time']
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True,
workstrokesonly=workstrokesonly)
rowdata.dropna(axis=1,how='all',inplace=True)
rowdata.dropna(axis=0,how='any',inplace=True)
row = Workout.objects.get(id=id)
if rowdata.empty:
return "","No valid data"
else:
rowdata.sort_values(by='time',ascending=True,inplace=True)
workoutstateswork = [1,4,5,8,9,6,7]
workoutstatesrest = [3]
workoutstatetransition = [0,2,10,11,12,13]
if workstrokesonly:
try:
rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)]
except KeyError:
pass
try:
rowdata['x1'] = rowdata.ix[:,xparam]
except KeyError:
rowdata['x1'] = 0*rowdata.ix[:,'time']
try:
rowdata['y1'] = rowdata.ix[:,yparam1]
except KeyError:
rowdata['y1'] = 0*rowdata.ix[:,'time']
tseconds = rowdata.ix[:,'time']
if yparam2 != 'None':
try:
rowdata['y2'] = rowdata.ix[:,yparam2]
except KeyError:
rowdata['y2'] = 0*rowdata.ix[:,'time']
else:
rowdata['y2'] = rowdata['y1']
if xparam=='time':
xaxmax = tseconds.max()
xaxmin = tseconds.min()
elif xparam=='distance' or xparam=='cumdist':
xaxmax = rowdata['x1'].max()
xaxmin = rowdata['x1'].min()
else:
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
# average values
if xparam != 'time':
try:
x1mean = rowdata['x1'].mean()
except TypeError:
x1mean = 0
else:
x1mean = 0
y1mean = rowdata['y1'].mean()
y2mean = rowdata['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 = rowdata['y1'].mean()*rowdata['x1'].mean()/xvals
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
y1mean = rowdata.ix[:,'pace'].mean()
rowdata['xname'] = xparam
rowdata['yname1'] = yparam1
if yparam2 != 'None':
rowdata['yname2'] = yparam2
else:
rowdata['yname2'] = yparam1
# prepare data
source = ColumnDataSource(
rowdata
)
# second source for filtering
source2 = ColumnDataSource(
rowdata.copy()
)
# 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
)
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=100,y=130,x_units='screen',y_units='screen',
text=axlabels[xparam]+": {x1mean:6.2f}".format(x1mean=x1mean),
background_fill_alpha=.7,
text_color='green',
)
if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
plot.add_layout(x1means)
plot.add_layout(xlabel)
plot.add_layout(y1means)
y1label = Label(x=100,y=100,x_units='screen',y_units='screen',
text=axlabels[yparam1]+": {y1mean:6.2f}".format(y1mean=y1mean),
background_fill_alpha=.7,
text_color='blue',
)
if yparam1 != 'time' and yparam1 != 'pace':
plot.add_layout(y1label)
y2label = y1label
# 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.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') and (xparam != 'cumdist'):
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.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)
elif plottype=='scatter':
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)
y2label = Label(x=100,y=70,x_units='screen',y_units='screen',
text=axlabels[yparam2]+": {y2mean:6.2f}".format(y2mean=y2mean),
background_fill_alpha=.7,
text_color='red',
)
if yparam2 != 'pace' and yparam2 != 'time':
plot.add_layout(y2label)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Distance','@distance{int}'),
('Pace','@fpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
('Power','@power{int}'),
])
hover.mode = 'mouse'
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 driveenergy1 = data['driveenergy']
var time1 = data['time']
var pace1 = data['pace']
var hr1 = data['hr']
var fpace1 = data['fpace']
var distance1 = data['distance']
var power1 = data['power']
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 minwork = minwork.value
var maxwork = maxwork.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['fpace'] = []
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) {
if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
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['fpace'].push(fpace1[i])
data2['pace'].push(pace1[i])
data2['hr'].push(hr1[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
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
slider_work_min = Slider(start=0.0, end=1500,value=0.0, step=10,
title="Min Work per Stroke",callback=callback)
callback.args["minwork"] = slider_work_min
slider_work_max = Slider(start=0.0, end=1500,value=1500.0, 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=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,
slider_work_min,
slider_work_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)
rowdata,row = dataprep.getrowdata_db(id=id)
rowdata.dropna(axis=1,how='all',inplace=True)
rowdata.dropna(axis=0,how='any',inplace=True)
if rowdata.empty:
return "","No Valid Data Available"
# 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(
rowdata
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
toolbar_sticky=False,
plot_width=920,
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(
hours = "",
seconds = ["%S"],
minutes = ["%M"],
)
ymax = 1.0e3*90
ymin = 1.0e3*180
if row.workouttype == 'water':
ymax = 1.0e3*90
ymin = 1.0e3*210
plot.y_range = Range1d(ymin,ymax)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Pace','@fpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
])
hover.mode = 'mouse'
plot.extra_y_ranges = {"hr": Range1d(start=100,end=200)}
plot.quad(left='time',top='hr_ut2',bottom='hr_bottom',
right='x_right',source=source,color="gray",
y_range_name="hr", legend="<UT2")
plot.quad(left='time',top='hr_ut1',bottom='hr_bottom',
right='x_right',source=source,color="tan",
y_range_name="hr", legend="UT2")
plot.quad(left='time',top='hr_at',bottom='hr_bottom',
right='x_right',source=source,color="green",
y_range_name="hr", legend="UT1")
plot.quad(left='time',top='hr_tr',bottom='hr_bottom',
right='x_right',source=source,color="blue",
y_range_name="hr", legend="AT")
plot.quad(left='time',top='hr_an',bottom='hr_bottom',
right='x_right',source=source,color="violet",
y_range_name="hr", legend="TR")
plot.quad(left='time',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('time','pace',source=source,legend="Pace",color="black")
script, div = components(plot)
return [script,div]
def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line',
promember=0,
labeldict=None):
columns = [xparam,yparam,
'ftime','distance','fpace',
'power','hr','spm',
'time','pace','workoutstate',
'workoutid']
datadf = dataprep.getsmallrowdata_db(columns,ids=ids)
datadf.dropna(axis=1,how='all',inplace=True)
datadf.dropna(axis=0,how='any',inplace=True)
tseconds = datadf.ix[:,'time']
yparamname = axlabels[yparam]
#datadf = datadf[datadf[yparam] > 0]
#datadf = datadf[datadf[xparam] > 0]
# check if dataframe not empty
if datadf.empty:
return ['','<p>No non-zero data in selection</p>','','']
if xparam != 'distance' and xparam != 'time' and xparam != 'cumdist':
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
elif xparam == 'time':
xaxmax = tseconds.max()
xaxmin = tseconds.min()
else:
xaxmax = datadf['distance'].max()
xaxmin = datadf['distance'].min()
if yparam == 'distance':
yaxmin = datadf['distance'].min()
yaxmax = datadf['distance'].max()
elif yparam == 'cumdist':
yaxmin = datadf['cumdist'].min()
yaxmax = datadf['cumdist'].max()
else:
yaxmin = yaxminima[yparam]
yaxmax = yaxmaxima[yparam]
x_axis_type = 'linear'
y_axis_type = 'linear'
# 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,crosshair'
if yparam == 'pace':
y_axis_type = 'datetime'
yaxmax = 90.*1e3
yaxmin = 150.*1e3
if xparam == 'time':
x_axis_type = 'datetime'
if xparam != 'time':
xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.
else:
xvals = np.arange(100)
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
toolbar_location="above",
plot_width=920,
toolbar_sticky=False)
colors = itertools.cycle(palette)
cntr = 0
for id,color in itertools.izip(ids,colors):
group = datadf[datadf['workoutid']==int(id)].copy()
group.sort_values(by='time',ascending=True,inplace=True)
group['x'] = group[xparam]
try:
group['y'] = group[yparam]
except KeyError:
group['y'] = 0.0*group['x']
ymean = group['y'].mean()
ylabel = Label(x=100,y=70+20*cntr,
x_units='screen',y_units='screen',
text=axlabels[yparam]+": {ymean:6.2f}".format(ymean=ymean),
background_fill_alpha=.7,
text_color=color,
)
if yparam != 'time' and yparam != 'pace':
plot.add_layout(ylabel)
source = ColumnDataSource(
group
)
TIPS = OrderedDict([
('time','@ftime'),
('pace','@fpace'),
('hr','@hr'),
('spm','@spm{1.1}'),
('distance','@distance{5}'),
])
hover = plot.select(type=HoverTool)
hover.tooltips = TIPS
if labeldict:
legend=labeldict[id]
else:
legend=str(id)
if plottype=='line':
l1 = plot.line('x','y',source=source,color=color,legend=legend)
else:
l1 = plot.scatter('x','y',source=source,color=color,legend=legend,
fill_alpha=0.4,line_color=None)
plot.add_tools(HoverTool(renderers=[l1],tooltips=TIPS))
cntr += 1
plot.legend.location='bottom_right'
plot.xaxis.axis_label = axlabels[xparam]
plot.yaxis.axis_label = axlabels[yparam]
if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
plot.x_range = xrange1
yrange1 = Range1d(start=yaxmin,end=yaxmax)
plot.y_range = yrange1
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 yparam == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
script, div = components(plot)
return [script,div]
def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
promember=0,plottype='line'):
columns = [xparam,yparam,
'ftime','distance','fpace',
'power','hr','spm',
'time','pace','workoutstate']
# check if valid ID exists (workout exists)
#rowdata1,row1 = dataprep.getrowdata_db(id=id1)
#rowdata2,row2 = dataprep.getrowdata_db(id=id2)
rowdata1 = dataprep.getsmallrowdata_db(columns,ids=[id1])
rowdata2 = dataprep.getsmallrowdata_db(columns,ids=[id2])
for n in ['distance','power','hr','spm','time','pace','workoutstate']:
rowdata1[n].fillna(value=0,inplace=True)
rowdata2[n].fillna(value=0,inplace=True)
rowdata1.dropna(axis=1,how='all',inplace=True)
rowdata1.dropna(axis=0,how='any',inplace=True)
rowdata2.dropna(axis=1,how='all',inplace=True)
rowdata2.dropna(axis=0,how='any',inplace=True)
row1 = Workout.objects.get(id=id1)
row2 = Workout.objects.get(id=id2)
if rowdata1.empty:
return "","No Valid Data Available"
else:
rowdata1.sort_values(by='time',ascending=True,inplace=True)
if rowdata2.empty:
return "","No Valid Data Available"
else:
rowdata2.sort_values(by='time',ascending=True,inplace=True)
try:
x1 = rowdata1.ix[:,xparam]
x2 = rowdata2.ix[:,xparam]
y1 = rowdata1.ix[:,yparam]
y2 = rowdata2.ix[:,yparam]
except KeyError:
return "","No valid Data Available"
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam == 'pace':
y_axis_type = 'datetime'
ymax = 1.0e3*90
ymin = 1.0e3*180
if row1.workouttype == 'water':
ymax = 1.0e3*90
ymin = 1.0e3*210
ftime1 = rowdata1.ix[:,'ftime']
ftime2 = rowdata2.ix[:,'ftime']
hr1 = rowdata1.ix[:,'hr']
hr2 = rowdata2.ix[:,'hr']
fpace1 = rowdata1.ix[:,'fpace']
fpace2 = rowdata2.ix[:,'fpace']
distance1 = rowdata1.ix[:,'distance']
distance2 = rowdata2.ix[:,'distance']
spm1 = rowdata1.ix[:,'spm']
spm2 = rowdata2.ix[:,'spm']
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'
data1 = pd.DataFrame(
dict(
x1=x1,
y1=y1,
ftime1=ftime1,
fpace1=fpace1,
hr1 = hr1,
spm1 = spm1,
distance1=distance1,
)
).dropna()
data2 = pd.DataFrame(
dict(
x2=x2,
y2=y2,
ftime2=ftime2,
fpace2=fpace2,
hr2 = hr2,
spm2 = spm2,
distance2=distance2,
)
).dropna()
source1 = ColumnDataSource(
data1
)
source2 = ColumnDataSource(
data2
)
# create interactive plot
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
plot_width=920,
toolbar_sticky=False)
TIPS = OrderedDict([
('time','@ftime1'),
('pace','@fpace1'),
('hr','@hr1'),
('spm','@spm1{1.1}'),
('distance','@distance1{5}'),
])
TIPS2 = OrderedDict([
('time','@ftime2'),
('pace','@fpace2'),
('hr','@hr2'),
('spm','@spm2{1.1}'),
('distance','@distance2{5}'),
])
hover1 = plot.select(type=HoverTool)
hover1.tooltips = TIPS
hover2 = plot.select(type=HoverTool)
hover2.tooltips = TIPS2
if plottype=='line':
l1 = plot.line('x1','y1',source=source1,
color="blue",legend=row1.name,
)
l2 = plot.line('x2','y2',source=source2,
color="red",legend=row2.name,
)
elif plottype=='scatter':
l1 = plot.scatter('x1','y1',source=source1,legend=row1.name,
fill_alpha=0.4,
line_color=None)
l2 = plot.scatter('x2','y2',source=source2,legend=row2.name,
fill_alpha=0.4,
line_color=None,color="red")
plot.add_tools(HoverTool(renderers=[l1],tooltips=TIPS))
plot.add_tools(HoverTool(renderers=[l2],tooltips=TIPS2))
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.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
plot.y_range = Range1d(ymin,ymax)
script, div = components(plot)
return [script,div]
def interactive_otw_advanced_pace_chart(id=0,promember=0):
# check if valid ID exists (workout exists)
rowdata,row = dataprep.getrowdata_db(id=id)
rowdata.dropna(axis=1,how='all',inplace=True)
rowdata.dropna(axis=0,how='any',inplace=True)
if rowdata.empty:
return "","No Valid Data Available"
# 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(
rowdata
)
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 = 1.0e3*90
ymin = 1.0e3*210
plot.y_range = Range1d(ymin,ymax)
hover = plot.select(dict(type=HoverTool))
plot.line('time','pace',source=source,legend="Pace",color="black")
plot.line('time','nowindpace',source=source,legend="Corrected Pace",color="red")
plot.line('time','ergpace',source=source,legend="Equivalent Erg Pace",color="blue")
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Pace','@fpace'),
('Corrected Pace','@fnowindpace'),
('Equiv. Erg Pace','@fergpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
])
hover.mode = 'mouse'
script, div = components(plot)
return [script,div]