Private
Public Access
1
0
Files
rowsandall/rowers/interactiveplots.py
2021-01-11 20:43:37 +01:00

6612 lines
194 KiB
Python

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import colorsys
from rowers.models import (
Workout, User, Rower, WorkoutForm,RowerForm,
GraphImage,GeoPolygon,GeoCourse,GeoPoint,
)
from rowers.tasks import handle_setcp
from rowingdata import rower as rrower
from rowingdata import main as rmain
from rowingdata import cumcpdata,histodata
from rowingdata import rowingdata as rrdata
from math import pi,log2
from django.utils import timezone
from rowingdata import make_cumvalues
from bokeh.palettes import Dark2_8 as palette
from bokeh.palettes import Set1_4 as palette2
from bokeh.models.glyphs import MultiLine
import itertools
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation, Band
import arrow
from rowers.utils import myqueue, totaltime_sec_to_string
import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')
from bokeh.resources import CDN,INLINE
from bokeh.embed import components
from bokeh.layouts import layout,widgetbox
from bokeh.palettes import Category20c,Category10
from bokeh.layouts import row as layoutrow
from bokeh.layouts import column as layoutcolumn
from bokeh.models import (
LinearAxis,LogAxis,Range1d,DatetimeTickFormatter,HoverTool,Axis,PrintfTickFormatter
)
#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.transform import cumsum
from bokeh.models.glyphs import ImageURL
from bokeh.models import OpenURL, TapTool
from rowers.opaque import encoder
#from bokeh.models.widgets import Slider, Select, TextInput
from bokeh.core.properties import value
from collections import OrderedDict
from django.conf import settings
from rowers.courses import (
course_coord_center,course_coord_maxmin,
polygon_coord_center
)
from rowers import mytypes
from rowers.models import course_spline
import datetime
import math
import numpy as np
import pandas as pd
import holoviews as hv
from holoviews import opts
from pytz import timezone as tz,utc
from django.utils.timezone import get_current_timezone
from django.utils.timezone import activate
from django.utils import timezone
activate(settings.TIME_ZONE)
thetimezone = get_current_timezone()
from scipy.stats import linregress,percentileofscore
from scipy.spatial import ConvexHull,Delaunay
from scipy import optimize
from scipy.signal import savgol_filter
from scipy.interpolate import griddata
import rowers.stravastuff as stravastuff
from rowers.metrics import rowingmetrics,metricsdicts
from rowers.dataprep import rdata
import rowers.dataprep as dataprep
import rowers.metrics as metrics
import rowers.c2stuff as c2stuff
from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima,get_yaxminima,get_yaxmaxima
from rowers.utils import lbstoN
from rowers.datautils import p0,rpetotss
import rowers.datautils as datautils
from pandas.core.groupby.groupby import DataError
def workoutname(id):
try:
w = Workout.objects.get(id=id)
except Workout.DoesNotExist:
return ''
return str(w)
def all_goldmedalstandards(workouts,startdate,enddate):
dates = []
testpowers = []
testduration = []
ids = []
for w in workouts:
goldmedalstandard, goldmedalseconds = dataprep.workout_goldmedalstandard(w)
if goldmedalseconds > 60:
dates.append(arrow.get(w.date).datetime)
testpowers.append(goldmedalstandard)
testduration.append(goldmedalseconds)
ids.append(w.id)
return dates,testpowers,testduration,ids
def errorbar(fig, x, y, source=ColumnDataSource(),
xerr=False, yerr=False, color='black',
point_kwargs={}, error_kwargs={}):
xvalues = source.data[x]
yvalues = source.data[y]
xerrvalues = source.data['xerror']
yerrvalues = source.data['yerror']
try:
colorvalues = source.data['color']
except KeyError:
colorvalues = ["#%02x%02x%02x" % (255,0,0) for x in xvalues]
try:
a = xvalues[0]+1
if xerr:
x_err_x = []
x_err_y = []
err_color = []
for px, py, err, color in zip(xvalues, yvalues, xerrvalues, colorvalues):
x_err_x.append((px - err, px + err))
x_err_y.append((py, py))
(r, g, b) = tuple(int(color[i:i+2],16) for i in (1, 3, 5))
h,s,v = colorsys.rgb_to_hsv(r/255., g/255., b/255.)
v = v*0.8
r, g, b = colorsys.hsv_to_rgb(h, s, v)
color2 = "#%02x%02x%02x" % (int(255.*r), int(255.*g), int(255*b))
err_color.append(color2)
fig.multi_line(x_err_x, x_err_y, color=err_color,
name='xerr',
**error_kwargs)
except TypeError:
pass
try:
a = yvalues[0]+1
if yerr:
y_err_x = []
y_err_y = []
err_color = []
for px, py, err, color in zip(xvalues, yvalues, yerrvalues, colorvalues):
y_err_x.append((px, px))
y_err_y.append((py - err, py + err))
(r, g, b) = tuple(int(color[i:i+2],16) for i in (1, 3, 5))
h,s,v = colorsys.rgb_to_hsv(r/255., g/255., b/255.)
v = v*0.8
r, g, b = colorsys.hsv_to_rgb(h, s, v)
color2 = "#%02x%02x%02x" % (int(255.*r), int(255.*g), int(255*b))
err_color.append(color2)
fig.multi_line(y_err_x, y_err_y, color=err_color,
name='yerr',**error_kwargs)
except TypeError:
pass
fig.circle(x, y, source=source, name='data',color=color,
**point_kwargs)
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
from math import pi
def interactive_hr_piechart(df,rower,title,totalseconds=0):
if df.empty:
return "","Not enough data to make a chart"
df.sort_values(by='hr',inplace=True)
df['timehr'] = df['deltat']*df['hr']
sumtimehr = df['deltat'].sum()
if totalseconds == 0:
totalseconds = sumtimehr
qry = 'hr < {ut2}'.format(ut2=rower.ut2)
qrydata = df.query(qry)
frac_lut2 = totalseconds*qrydata['deltat'].sum()/sumtimehr
qry = '{ut2} <= hr < {ut1}'.format(ut1=rower.ut1,ut2=rower.ut2)
frac_ut2 = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr
qry = '{ut1} <= hr < {at}'.format(ut1=rower.ut1,at=rower.at)
frac_ut1 = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr
qry = '{at} <= hr < {tr}'.format(at=rower.at,tr=rower.tr)
frac_at = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr
qry = '{tr} <= hr < {an}'.format(tr=rower.tr,an=rower.an)
frac_tr = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr
qry = 'hr >= {an}'.format(an=rower.an)
frac_an = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr
datadict = {
'<ut2':frac_lut2,
'ut2': frac_ut2,
'ut1': frac_ut1,
'at': frac_at,
'tr': frac_tr,
'an': frac_an,
}
colors = ['gray','yellow','lime','blue','purple','red']
data = pd.Series(datadict).reset_index(name='value').rename(columns={'index':'zone'})
data['angle'] = data['value']/data['value'].sum() * 2*pi
data['color'] = colors
data['zone'] = ['<ut2','ut2','ut1','at','tr','an']
data['totaltime'] = pd.Series([pretty_timedelta(v) for v in data['value']])
size=350
TOOLS = 'save,hover'
z = figure(title="HR "+title, x_range=(-0.5,1), plot_height=375,
tools=TOOLS,toolbar_location=None,tooltips="@zone: @totaltime",
)
z.wedge(x=0,y=1, radius=0.4,
start_angle=cumsum('angle',include_zero=True), end_angle=cumsum('angle'),
line_color='white',fill_color='color',source=data,legend_group='zone')
z.axis.axis_label = None
z.axis.visible = False
z.grid.grid_line_color = None
z.outline_line_color = None
z.toolbar_location = 'right'
return components(z)
def pretty_timedelta(secs):
hours, remainder = divmod(secs,3600)
minutes, seconds = divmod(remainder,60)
return '{}:{:02}:{:02}'.format(int(hours),int(minutes),int(seconds))
def mapcolors(x):
try:
return mytypes.color_map[x]
except KeyError:
return mytypes.colors[-1]
def interactive_workouttype_piechart(workouts):
if len(workouts) == 0:
return "","Not enough workouts to make a chart"
datadict = {}
for w in workouts:
try:
# label = mytypes.workouttypes_ordered[w.workouttype]
label = w.workouttype
except KeyError:
label = w.workouttype
try:
datadict[label] += 60*(60*w.duration.hour+w.duration.minute)+w.duration.second
except KeyError:
datadict[label] = 60*(60*w.duration.hour+w.duration.minute)+w.duration.second
data = pd.Series(datadict).reset_index(name='value').rename(columns={'index':'type'})
data['angle'] = data['value']/data['value'].sum() * 2*pi
data = pd.DataFrame(data)
data['color'] = data['type'].apply(lambda x:mapcolors(x))
data['totaltime'] = data['value'].apply(lambda x:pretty_timedelta(x))
try:
data['type'] = data['type'].apply(lambda x:mytypes.workouttypes_ordered[x])
except KeyError:
pass
p = figure(plot_height=350, title="Types", toolbar_location=None,
tools="hover,save", tooltips="@type: @totaltime", x_range=(-0.5, 1.0))
p.wedge(x=0, y=1, radius=0.4,
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
line_color="white", fill_color='color', source=data,legend_group='type', )
p.axis.axis_label=None
p.axis.visible=False
p.grid.grid_line_color = None
p.outline_line_color = None
p.toolbar_location = 'right'
return components(p)
def interactive_boxchart(datadf,fieldname,extratitle='',
spmmin=0,spmmax=0,workmin=0,workmax=0):
if datadf.empty:
return '','It looks like there are no data matching your filter'
columns = datadf.columns
if not fieldname in columns:
return '','It looks like there are no data matching your filter'
if not 'date' in columns:
return '','Not enough data'
tooltips = [
('Value', '@'+fieldname),
]
hover = HoverTool(tooltips=tooltips)
TOOLS = [hover]
hv.extension('bokeh')
try:
boxwhiskers = hv.BoxWhisker(datadf,'date',fieldname)
boxwhiskers.opts(tools=TOOLS,outlier_color='white')
except DataError:
return "","Invalid Data"
plot = hv.render(boxwhiskers)
yrange1 = Range1d(start=yaxminima[fieldname],end=yaxmaxima[fieldname])
plot.y_range = yrange1
plot.sizing_mode = 'stretch_both'
plot.xaxis.axis_label = 'Date'
plot.yaxis.axis_label = axlabels[fieldname]
plot.xaxis.formatter = DatetimeTickFormatter(
days=["%d %B %Y"],
months=["%d %B %Y"],
years=["%d %B %Y"],
)
if fieldname == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
plot.xaxis.major_label_orientation = pi/4
plot.plot_width=920
plot.plot_height=600
slidertext = 'SPM: {:.0f}-{:.0f}, WpS: {:.0f}-{:.0f}'.format(
spmmin,spmmax,workmin,workmax
)
sliderlabel = Label(x=50,y=20,x_units='screen',y_units='screen',
text=slidertext,
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black',text_font_size='10pt',
)
plot.add_layout(sliderlabel)
script, div = components(plot)
return script,div
def interactive_planchart(data,startdate,enddate):
source = ColumnDataSource(data)
hv.extension('bokeh')
yaxmaximum = data['executed'].max()
if data['planned'].max() > yaxmaximum:
yaxmaximum = data['planned'].max()
if yaxmaximum == 0:
yaxmaximum = 250
yrange1 = Range1d(start=0,end=1.1*yaxmaximum)
tidy_df = data.melt(id_vars=['startdate'],value_vars=['executed','planned'])
bars = hv.Bars(tidy_df,['startdate','variable'],['value'])
bars.opts(
opts.Bars(show_legend=True,tools=['tap','hover'],legend_position='bottom',show_frame=True))
p = hv.render(bars)
p.plot_width=550
p.plot_height=350
p.y_range = yrange1
p.toolbar_location = 'above'
p.sizing_mode = 'stretch_both'
script,div = components(p)
return script,div
def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_location=None,
yaxis='trimp'):
dates = []
dates_sorting = []
types = []
rowers = []
durations = []
rscores = []
trimps = []
links = []
rowersinitials = {}
seen = ['seen']
idseen = []
startdate = datetime.datetime(year=startdate.year,month=startdate.month,day=startdate.day)
enddate = datetime.datetime(year=enddate.year,month=enddate.month,day=enddate.day)
duration = enddate-startdate
totaldays = duration.total_seconds()/(24*3600)
for w in workouts:
aantal=1
initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]
if w.user.id not in idseen:
while initials in seen:
aantal += 1
initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]
seen.append(initials)
idseen.append(w.user.id)
rowersinitials[w.user.id] = initials
for w in workouts:
dd = w.date.strftime('%m/%d')
dd2 = w.date.strftime('%Y/%m/%d')
dd3 = w.date.strftime('%Y/%m')
du = w.duration.hour*60+w.duration.minute
rscore = w.rscore
trimp = w.trimp
if rscore == 0:
rscore = w.hrtss
if totaldays<30:
dates.append(dd)
dates_sorting.append(dd2)
else:
dates.append(dd3)
dates_sorting.append(dd3)
durations.append(du)
rscores.append(rscore)
trimps.append(trimp)
links.append(
"{siteurl}/rowers/workout/{code}/".format(
siteurl = settings.SITE_URL,
code = encoder.encode_hex(w.id)
)
)
types.append(w.workouttype)
try:
rowers.append(rowersinitials[w.user.id])
except IndexError:
rowers.append(str(w.user))
try:
d = utc.localize(startdate)
except (ValueError,AttributeError):
d = startdate
try:
enddate = utc.localize(enddate)
except (ValueError,AttributeError):
pass
# add dates with no activity
while d<=enddate:
dd = d.strftime('%d')
if totaldays<30:
dates.append(d.strftime('%m/%d'))
dates_sorting.append(d.strftime('%Y/%m/%d'))
else:
dates.append(d.strftime('%Y/%m'))
dates_sorting.append(d.strftime('%Y/%m'))
durations.append(0)
rscores.append(0)
trimps.append(0)
links.append('')
types.append('rower')
try:
rowers.append(rowers[0])
except IndexError:
try:
rowers.append(str(workouts[0].user))
except IndexError:
rowers.append(' ')
d += datetime.timedelta(days=1)
thedict = {
'date':dates,
'date_sorting':dates_sorting,
'duration':durations,
'trimp':trimps,
'rscore':rscores,
'type':types,
'rower':rowers,
'link':links,
}
dim_expr = hv.dim('type').categorize(mytypes.color_map)
df = pd.DataFrame(thedict)
source = ColumnDataSource(df)
df.sort_values('date_sorting',inplace=True)
#clrs = hv.Cycle(df['colors'].values)
hv.extension('bokeh')
if stack == 'type':
table = hv.Table(df,[('date','Date'),('type','Workout Type')],
[('duration','Minutes'),('rscore','rScore'),('trimp','TRIMP'),('link','link')])
else:
table = hv.Table(df,[('date','Date'),('rower','Rower')],
[('duration','Minutes'),('rscore','rScore'),('trimp','TRIMP'),('link','link')])
bars=table.to.bars(['date',stack],[yaxis])
if stack == 'type':
bars.opts(
opts.Bars(cmap=mytypes.color_map, show_legend=True, stacked=True,
tools=['tap','hover'], width=550, xrotation=45,padding=(0,(0,.1)),
legend_position='bottom',show_frame=True))
else:
bars.opts(
opts.Bars(cmap='Category10', show_legend=True, stacked=True,
tools=['tap','hover'], width=550, xrotation=45,padding=(0,(0,.1)),
legend_position='bottom',show_frame=True))
p = hv.render(bars)
p.title.text = 'Activity {d1} to {d2}'.format(
d1 = startdate.strftime("%Y-%m-%d"),
d2 = enddate.strftime("%Y-%m-%d"),
)
p.plot_width=550
p.plot_height=350
p.toolbar_location = toolbar_location
p.y_range.start = 0
p.sizing_mode = 'stretch_both'
url = "http://rowsandall.com/rowers/workout/@duration/"
taptool = p.select(type=TapTool)
callback = CustomJS(args={'links':df.link}, code="""
var index = cb_data.source.selected['1d'].indices[0];
console.log(links);
console.log(index);
console.log(links[index]);
window.location.href = links[index]
""")
taptool.js_on_event('tap',callback)
script,div = components(p)
return script,div
def interactive_activitychart2(workouts,startdate,enddate,stack='type',toolbar_location=None,
yaxis='duration'):
dates = []
dates_sorting = []
types = []
rowers = []
durations = []
rscores = []
trimps = []
links = []
rowersinitials = {}
seen = ['seen']
idseen = []
startdate = datetime.datetime(year=startdate.year,month=startdate.month,day=startdate.day)
enddate = datetime.datetime(year=enddate.year,month=enddate.month,day=enddate.day)
duration = enddate-startdate
totaldays = duration.total_seconds()/(24*3600)
for w in workouts:
aantal=1
initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]
if w.user.id not in idseen:
while initials in seen:
aantal += 1
initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]
seen.append(initials)
idseen.append(w.user.id)
rowersinitials[w.user.id] = initials
for w in workouts:
dd = w.date.strftime('%m/%d')
dd2 = w.date.strftime('%Y/%m/%d')
dd3 = w.date.strftime('%Y/%m')
du = w.duration.hour*60+w.duration.minute
trimp = w.trimp
rscore = w.rscore
if rscore == 0:
rscore = w.hrtss
if totaldays<30:
dates.append(dd)
dates_sorting.append(dd2)
else:
dates.append(dd3)
dates_sorting.append(dd3)
durations.append(du)
trimps.append(trimp)
rscores.append(rscore)
links.append(
"{siteurl}/rowers/workout/{code}/".format(
siteurl = settings.SITE_URL,
code = encoder.encode_hex(w.id)
)
)
types.append(w.workouttype)
try:
rowers.append(rowersinitials[w.user.id])
except IndexError:
rowers.append(str(w.user))
try:
d = utc.localize(startdate)
except (ValueError,AttributeError):
d = startdate
try:
enddate = utc.localize(enddate)
except (ValueError,AttributeError):
pass
# add dates with no activity
while d<=enddate:
dd = d.strftime('%d')
if totaldays<30:
dates.append(d.strftime('%m/%d'))
dates_sorting.append(d.strftime('%Y/%m/%d'))
else:
dates.append(d.strftime('%Y/%m'))
dates_sorting.append(d.strftime('%Y/%m'))
durations.append(0)
trimps.append(0)
rscores.append(0)
links.append('')
types.append('rower')
try:
rowers.append(rowers[0])
except IndexError:
try:
rowers.append(str(workouts[0].user))
except IndexError:
rowers.append(' ')
d += datetime.timedelta(days=1)
thedict = {
'date':dates,
'date_sorting':dates_sorting,
'duration':durations,
'trimp':trimps,
'rscore':rscores,
'type':types,
'rower':rowers,
'link':links,
}
dim_expr = hv.dim('type').categorize(mytypes.color_map)
df = pd.DataFrame(thedict)
df['color'] = df['type'].apply(lambda x:mapcolors(x))
df.sort_values('date_sorting',inplace=True)
#clrs = hv.Cycle(df['colors'].values)
source = ColumnDataSource(df)
hv.extension('bokeh')
table = hv.Table(df,[('date','Date'),('type','Workout Type')],
[('duration','Minutes'),('trimp','TRIMP'),('rscore','rScore'),('link','link')])
bars=table.to.bars(['date',stack],[yaxis])
bars.opts(
opts.Bars(cmap=mytypes.color_map, show_legend=True, stacked=True,
tools=['tap','hover'], width=550, xrotation=45,padding=(0,(0,.1)),
legend_position='bottom',show_frame=True))
p = hv.render(bars)
p.title.text = 'Activity {d1} to {d2}'.format(
d1 = startdate.strftime("%Y-%m-%d"),
d2 = enddate.strftime("%Y-%m-%d"),
)
p.plot_width=550
p.plot_height=350
p.toolbar_location = toolbar_location
p.sizing_mode = 'stretch_both'
p.y_range.start = 0
url = "http://rowsandall.com/rowers/workout/@duration/"
taptool = p.select(type=TapTool)
callback = CustomJS(args={'links':df.link}, code="""
var index = cb_data.source.selected['1d'].indices[0];
console.log(links);
console.log(index);
console.log(links[index]);
window.location.href = links[index]
""")
taptool.js_on_event('tap',callback)
script,div = components(p)
return script,div
def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,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,
workstrokesonly=workstrokesonly)
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","",""
# quick linear regression
# peakforce = slope*peakforceangle + intercept
try:
slope, intercept, r,p,stderr = linregress(rowdata['peakforceangle'],rowdata['peakforce'])
except KeyError:
slope = 0
intercept = 0
try:
covariancematrix = np.cov(rowdata['peakforceangle'],y=rowdata['peakforce'])
eig_vals, eig_vecs = np.linalg.eig(covariancematrix)
a = rowdata['peakforceangle']-rowdata['peakforceangle'].median()
F = rowdata['peakforce']-rowdata['peakforce'].median()
Rinv = eig_vecs
R = np.linalg.inv(Rinv)
x = R[0,0]*a+R[0,1]*F
y = R[1,0]*a+R[1,1]*F
x05 = x.quantile(q=0.01)
x25 = x.quantile(q=0.15)
x75 = x.quantile(q=0.85)
x95 = x.quantile(q=0.99)
y05 = y.quantile(q=0.01)
y25 = y.quantile(q=0.15)
y75 = y.quantile(q=0.85)
y95 = y.quantile(q=0.99)
a25 = Rinv[0,0]*x25 + rowdata['peakforceangle'].median()
F25 = Rinv[1,0]*x25 + rowdata['peakforce'].median()
a25b = Rinv[0,1]*y25 + rowdata['peakforceangle'].median()
F25b = Rinv[1,1]*y25 + rowdata['peakforce'].median()
a75 = Rinv[0,0]*x75 + rowdata['peakforceangle'].median()
F75 = Rinv[1,0]*x75 + rowdata['peakforce'].median()
a75b = Rinv[0,1]*y75 + rowdata['peakforceangle'].median()
F75b = Rinv[1,1]*y75 + rowdata['peakforce'].median()
a05 = Rinv[0,0]*x05 + rowdata['peakforceangle'].median()
F05 = Rinv[1,0]*x05 + rowdata['peakforce'].median()
a05b = Rinv[0,1]*y05 + rowdata['peakforceangle'].median()
F05b = Rinv[1,1]*y05 + rowdata['peakforce'].median()
a95 = Rinv[0,0]*x95 + rowdata['peakforceangle'].median()
F95 = Rinv[1,0]*x95 + rowdata['peakforce'].median()
a95b = Rinv[0,1]*y95 + rowdata['peakforceangle'].median()
F95b = Rinv[1,1]*y95 + rowdata['peakforce'].median()
except KeyError:
a25 = 0
F25 = 0
a25b = 0
F25b = 0
a75 = 0
F75 = 0
a75b = 0
F75b = 0
a05 = 0
F05 = 0
a05b = 0
F05b = 0
a95 = 0
F95 = 0
a95b = 0
F95b = 0
try:
catchav = rowdata['catch'].median()
catch25 = rowdata['catch'].quantile(q=0.25)
catch75 = rowdata['catch'].quantile(q=0.75)
catch05 = rowdata['catch'].quantile(q=0.05)
catch95 = rowdata['catch'].quantile(q=0.95)
except KeyError:
catchav = 0
catch25 = 0
catch75 = 0
catch05 = 0
catch95 = 0
try:
finishav = rowdata['finish'].median()
finish25 = rowdata['finish'].quantile(q=0.25)
finish75 = rowdata['finish'].quantile(q=0.75)
finish05 = rowdata['finish'].quantile(q=0.05)
finish95 = rowdata['finish'].quantile(q=0.95)
except KeyError:
finishav = 0
finish25 = 0
finish75 = 0
finish05 = 0
finish95 = 0
try:
washav = (rowdata['finish']-rowdata['wash']).median()
wash25 = (rowdata['finish']-rowdata['wash']).quantile(q=0.25)
wash75 = (rowdata['finish']-rowdata['wash']).quantile(q=0.75)
wash05 = (rowdata['finish']-rowdata['wash']).quantile(q=0.05)
wash95 = (rowdata['finish']-rowdata['wash']).quantile(q=0.95)
except KeyError:
washav = 0
wash25 = 0
wash75 = 0
wash05 = 0
wash95 = 0
try:
slipav = (rowdata['slip']+rowdata['catch']).median()
slip25 = (rowdata['slip']+rowdata['catch']).quantile(q=0.25)
slip75 = (rowdata['slip']+rowdata['catch']).quantile(q=0.75)
slip05 = (rowdata['slip']+rowdata['catch']).quantile(q=0.05)
slip95 = (rowdata['slip']+rowdata['catch']).quantile(q=0.95)
except KeyError:
slipav = 0
slip25 = 0
slip75 = 0
slip05 = 0
slip95 = 0
try:
peakforceav = rowdata['peakforce'].median()
peakforce25 = rowdata['peakforce'].quantile(q=0.25)
peakforce75 = rowdata['peakforce'].quantile(q=0.75)
peakforce05 = rowdata['peakforce'].quantile(q=0.05)
peakforce95 = rowdata['peakforce'].quantile(q=0.95)
except KeyError:
peakforceav = 0
peakforce25 = 0
peakforce75 = 0
peakforce05 = 0
peakforce95 = 0
try:
averageforceav = rowdata['averageforce'].median()
except KeyError:
averageforceav = 0
try:
peakforceangleav = rowdata['peakforceangle'].median()
peakforceangle05 = rowdata['peakforceangle'].quantile(q=0.05)
peakforceangle25 = rowdata['peakforceangle'].quantile(q=0.25)
peakforceangle75 = rowdata['peakforceangle'].quantile(q=0.75)
peakforceangle95 = rowdata['peakforceangle'].quantile(q=0.95)
except KeyError:
peakforceangleav = 0
peakforceangle25 = 0
peakforceangle75 = 0
peakforceangle05 = 0
peakforceangle95 = 0
#thresholdforce /= 4.45 # N to lbs
thresholdforce = 100 if 'x' in boattype else 200
points2575 = [
(catch25,0), #0
(slip25,thresholdforce), #1
(a75,F75),#4
(a25b,F25b), #9
(a25,F25), #2
(wash75,thresholdforce), #5
(finish75,0), #6
(finish25,0), #7
(wash25,thresholdforce), #8
(a75b,F75b), #3
(slip75,thresholdforce), #10
(catch75,0), #11
]
points0595 = [
(catch05,0), #0
(slip05,thresholdforce), #1
(a95,F95),#4
(a05b,F05b), #9
(a05,F05), #2
(wash95,thresholdforce), #5
(finish95,0), #6
(finish05,0), #7
(wash05,thresholdforce), #8
(a95b,F95b), #3
(slip95,thresholdforce), #10
(catch95,0), #11
]
angles2575 = []
forces2575 = []
for x,y in points2575:
angles2575.append(x)
forces2575.append(y)
angles0595 = []
forces0595 = []
for x,y in points0595:
angles0595.append(x)
forces0595.append(y)
x = [catchav,
slipav,
peakforceangleav,
washav,
finishav]
y = [0,thresholdforce,
peakforceav,
thresholdforce,0]
source = ColumnDataSource(
data = dict(
x = x,
y = y,
))
sourceslipwash = ColumnDataSource(
data = dict(
xslip = [slipav,washav],
yslip = [thresholdforce,thresholdforce]
)
)
sourcetrend = ColumnDataSource(
data = dict(
x = [peakforceangle25,peakforceangle75],
y = [peakforce25,peakforce75]
)
)
sourcefit = ColumnDataSource(
data = dict(
x = np.array([peakforceangle25,peakforceangle75]),
y = slope*np.array([peakforceangle25,peakforceangle75])+intercept
)
)
source2 = ColumnDataSource(
rowdata
)
if plottype == 'scatter':
try:
sourcepoints = ColumnDataSource(
data = dict(
peakforceangle = rowdata['peakforceangle'],
peakforce = rowdata['peakforce']
)
)
except KeyError:
sourcepoints = ColumnDataSource(
data = dict(
peakforceangle = [],
peakforce = []
)
)
else:
sourcepoints = ColumnDataSource(
data = dict(
peakforceangle = [],
peakforce = []
))
sourcerange = ColumnDataSource(
data = dict(
x2575 = angles2575,
y2575 = forces2575,
x0595 = angles0595,
y0595 = forces0595,
)
)
plot = Figure(tools=TOOLS,
toolbar_sticky=False,toolbar_location="above",plot_width=800,plot_height=600)
plot.sizing_mode = 'stretch_both'
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.image_url([watermarkurl],watermarkx,watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
avf = Span(location=averageforceav,dimension='width',line_color='blue',
line_dash=[6,6],line_width=2)
plot.patch('x0595','y0595',source=sourcerange,color="red",alpha=0.05)
plot.patch('x2575','y2575',source=sourcerange,color="red",alpha=0.2)
plot.line('x','y',source=source,color="red")
plot.circle('xslip','yslip',source=sourceslipwash,color="red")
plot.circle('peakforceangle','peakforce',source=sourcepoints,color='black',alpha=0.1)
if plottype == 'line':
multilinedatax = []
multilinedatay = []
for i in range(len(rowdata)):
try:
x = [
rowdata['catch'].values[i],
rowdata['slip'].values[i]+rowdata['catch'].values[i],
rowdata['peakforceangle'].values[i],
rowdata['finish'].values[i]-rowdata['wash'].values[i],
rowdata['finish'].values[i]
]
y = [
0,
thresholdforce,
rowdata['peakforce'].values[i],
thresholdforce,
0]
except KeyError:
x = [0,0]
y = [0,0]
multilinedatax.append(x)
multilinedatay.append(y)
sourcemultiline = ColumnDataSource(dict(
x=multilinedatax,
y=multilinedatay,
))
sourcemultiline2 = ColumnDataSource(dict(
x=multilinedatax,
y=multilinedatay,
))
glyph = MultiLine(xs='x',ys='y',line_color='black',line_alpha=0.05)
plot.add_glyph(sourcemultiline,glyph)
else:
sourcemultiline = ColumnDataSource(dict(
x=[],y=[]))
sourcemultiline2 = ColumnDataSource(dict(
x=[],y=[]))
plot.line('x','y',source=source,color="red")
plot.add_layout(avf)
peakflabel = Label(x=760,y=460,x_units='screen',y_units='screen',
text="Fpeak: {peakforceav:6.2f}".format(peakforceav=peakforceav),
background_fill_alpha=.7,
background_fill_color='white',
text_color='blue',
)
avflabel = Label(x=770,y=430,x_units='screen',y_units='screen',
text="Favg: {averageforceav:6.2f}".format(averageforceav=averageforceav),
background_fill_alpha=.7,
background_fill_color='white',
text_color='blue',
)
catchlabel = Label(x=765,y=400,x_units='screen',y_units='screen',
text="Catch: {catchav:6.2f}".format(catchav=catchav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='red',
)
peakforceanglelabel = Label(x=725,y=370,x_units='screen',y_units='screen',
text="Peak angle: {peakforceangleav:6.2f}".format(peakforceangleav=peakforceangleav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='red',
)
finishlabel = Label(x=760,y=340,x_units='screen',y_units='screen',
text="Finish: {finishav:6.2f}".format(finishav=finishav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='red',
)
sliplabel = Label(x=775,y=310,x_units='screen',y_units='screen',
text="Slip: {slipav:6.2f}".format(slipav=slipav-catchav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='red',
)
washlabel = Label(x=765,y=280,x_units='screen',y_units='screen',
text="Wash: {washav:6.2f}".format(washav=finishav-washav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='red',
)
lengthlabel = Label(x=755,y=250, x_units='screen',y_units='screen',
text="Length: {length:6.2f}".format(length=finishav-catchav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='green'
)
efflengthlabel = Label(x=690,y=220, x_units='screen',y_units='screen',
text="Effective Length: {length:6.2f}".format(length=washav-slipav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='green'
)
annolabel = Label(x=50,y=450,x_units='screen',y_units='screen',
text='',
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black',
)
sliderlabel = Label(x=10,y=470,x_units='screen',y_units='screen',
text='',
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black',text_font_size='10pt',
)
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.add_layout(annolabel)
plot.add_layout(sliderlabel)
plot.add_layout(lengthlabel)
plot.add_layout(efflengthlabel)
plot.xaxis.axis_label = "Angle"
plot.yaxis.axis_label = "Force (N)"
plot.title.text = theworkouts[0].name
plot.title.text_font_size=value("1.0em")
yrange1 = Range1d(start=0,end=900)
plot.y_range = yrange1
xrange1 = Range1d(start=yaxmaxima['catch'],end=yaxmaxima['finish'])
plot.x_range = xrange1
callback = CustomJS(args = dict(
source=source,
source2=source2,
sourceslipwash=sourceslipwash,
sourcepoints=sourcepoints,
avf=avf,
avflabel=avflabel,
catchlabel=catchlabel,
finishlabel=finishlabel,
sliplabel=sliplabel,
washlabel=washlabel,
peakflabel=peakflabel,
peakforceanglelabel=peakforceanglelabel,
annolabel=annolabel,
sliderlabel=sliderlabel,
lengthlabel=lengthlabel,
efflengthlabel=efflengthlabel,
plottype=plottype,
sourcemultiline=sourcemultiline,
sourcemultiline2=sourcemultiline2
), code="""
var data = source.data
var data2 = source2.data
var dataslipwash = sourceslipwash.data
var datapoints = sourcepoints.data
var multilines = sourcemultiline.data
var multilines2 = sourcemultiline2.data
var plottype = plottype
var multilinesx = multilines2['x']
var multilinesy = multilines2['y']
var x = data['x']
var y = data['y']
var xslip = dataslipwash['xslip']
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 peakforcepoints = datapoints['peakforce']
var peakforceanglepoints = datapoints['peakforceangle']
var annotation = annotation.value
var minspm = minspm.value
var maxspm = maxspm.value
var mindist = mindist.value
var maxdist = maxdist.value
var minwork = minwork.value
var maxwork = maxwork.value
sliderlabel.text = 'SPM: '+minspm.toFixed(0)+'-'+maxspm.toFixed(0)
sliderlabel.text += ', Dist: '+mindist.toFixed(0)+'-'+maxdist.toFixed(0)
sliderlabel.text += ', WpS: '+minwork.toFixed(0)+'-'+maxwork.toFixed(0)
var catchav = 0
var finishav = 0
var slipav = 0
var washav = 0
var peakforceangleav = 0
var averageforceav = 0
var peakforceav = 0
var count = 0
datapoints['peakforceangle'] = []
datapoints['peakforce'] = []
multilines['x'] = []
multilines['y'] = []
for (var 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) {
if (plottype=='scatter') {
datapoints['peakforceangle'].push(peakforceangle[i])
datapoints['peakforce'].push(peakforce[i])
}
if (plottype=='line') {
multilines['x'].push(multilinesx[i])
multilines['y'].push(multilinesy[i])
}
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]
dataslipwash['xslip'] = [catchav+slipav,finishav-washav]
dataslipwash['yslip'] = [thresholdforce,thresholdforce]
var length = finishav-catchav
var efflength = length-slipav-washav
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)
annolabel.text = annotation
lengthlabel.text = 'Length: '+length.toFixed(2)
efflengthlabel.text = 'Effective Length: '+efflength.toFixed(2)
console.log(count);
console.log(multilines['x'].length);
console.log(multilines['y'].length);
// source.trigger('change');
source.change.emit();
sourceslipwash.change.emit()
sourcepoints.change.emit();
sourcemultiline.change.emit();
""")
annotation = TextInput(width=140, title="Type your plot notes here", value="")
annotation.js_on_change('value',callback)
callback.args["annotation"] = annotation
slider_spm_min = Slider(width=140, start=15.0, end=55,value=15.0, step=.1,
title="Min SPM")
slider_spm_min.js_on_change('value',callback)
callback.args["minspm"] = slider_spm_min
slider_spm_max = Slider(width=140, start=15.0, end=55,value=55.0, step=.1,
title="Max SPM")
slider_spm_max.js_on_change('value',callback)
callback.args["maxspm"] = slider_spm_max
slider_work_min = Slider(width=140, start=0, end=1500,value=0, step=10,
title="Min Work per Stroke")
slider_work_min.js_on_change('value',callback)
callback.args["minwork"] = slider_work_min
slider_work_max = Slider(width=140, start=0, end=1500,value=1500, step=10,
title="Max Work per Stroke")
slider_work_max.js_on_change('value',callback)
callback.args["maxwork"] = slider_work_max
distmax = 100+100*int(rowdata['distance'].max()/100.)
slider_dist_min = Slider(width=140, start=0,end=distmax,value=0,step=50,
title="Min Distance")
slider_dist_min.js_on_change('value',callback)
callback.args["mindist"] = slider_dist_min
slider_dist_max = Slider(width=140, start=0,end=distmax,value=distmax,
step=50,
title="Max Distance")
slider_dist_max.js_on_change('value',callback)
callback.args["maxdist"] = slider_dist_max
annotation.sizing_mode = 'fixed'
slider_spm_min.sizing_mode = 'fixed'
slider_spm_max.sizing_mode = 'fixed'
slider_work_min.sizing_mode = 'fixed'
slider_work_max.sizing_mode = 'fixed'
slider_dist_min.sizing_mode = 'fixed'
slider_dist_max.sizing_mode = 'fixed'
thesliders = layoutcolumn([annotation,
slider_spm_min,
slider_spm_max,
slider_dist_min,
slider_dist_max,
slider_work_min,
slider_work_max,
]
)
thesliders.sizing_mode = 'fixed'
layout = layoutrow([thesliders,
plot])
layout.sizing_mode = 'stretch_both'
script, div = components(layout)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
return [script,div,js_resources,css_resources]
def getfatigues(
fatigues,fitnesses,dates,testpower,testduration,
impulses,
startdate,enddate,user,metricchoice,kfatigue,kfitness):
fatigue = 0
fitness = 0
impulses = []
for f in fatigues:
impulses.append(0)
lambda_a = 2/(kfatigue+1)
lambda_c = 2/(kfitness+1)
nrdays = (enddate-startdate).days
for i in range(nrdays+1):
date = startdate+datetime.timedelta(days=i)
ws = Workout.objects.filter(user=user.rower,date=date,duplicate=False)
weight = 0
for w in ws:
if getattr(w,metricchoice) > 0:
weight += getattr(w,metricchoice)
if getattr(w,metricchoice) <= 0:
if metricchoice == 'rscore' and w.hrtss > 0:
weight+= w.hrtss
else:
trimp,hrtss = dataprep.workout_trimp(w)
rscore,normp = dataprep.workout_rscore(w)
if w.rpe and w.rpe > 0:
dd = 3600*w.duration.hour+60*w.duration.minute+w.duration.second
dd = dd/3600
weight += rpetotss[w.rpe]*dd
impulses.append(weight)
fatigue = (1-lambda_a)*fatigue+weight*lambda_a
fitness = (1-lambda_c)*fitness+weight*lambda_c
fatigues.append(fatigue)
fitnesses.append(fitness)
dates.append(arrow.get(date).datetime)
testpower.append(np.nan)
testduration.append(np.nan)
return fatigues,fitnesses,dates,testpower,testduration,impulses
def goldmedalscorechart(user,startdate=None,enddate=None):
# to avoid data mess later on
startdate = arrow.get(startdate).datetime.replace(hour=0,minute=0,second=0,microsecond=0)
enddate = enddate+datetime.timedelta(days=1)
enddate = arrow.get(enddate).datetime.replace(hour=0,minute=0,second=0,microsecond=0)
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
# marker workouts
workouts = Workout.objects.filter(user=user.rower,date__gte=startdate,
date__lte=enddate,
workouttype__in=mytypes.rowtypes,
duplicate=False).order_by('date')
markerworkouts = workouts.filter(rankingpiece=True)
outids = [w.id for w in markerworkouts]
dates = [arrow.get(w.date).datetime for w in markerworkouts]
testpower = [w.goldmedalstandard if w.rankingpiece else np.nan for w in markerworkouts]
testduration = [w.goldmedalseconds if w.rankingpiece else 0 for w in markerworkouts]
df = pd.DataFrame({
'id':outids,
'date':dates,
'testpower':testpower,
'testduration':testduration,
})
df.sort_values(['date'],inplace=True)
mask = df['testpower'].isnull()
dates = df.mask(mask)['date'].dropna().values
testpower = df.mask(mask)['testpower'].dropna().values
ids = df.mask(mask)['id'].dropna().values
outids = df.mask(mask)['id'].dropna().unique()
# all workouts
alldates,alltestpower,allduration,allids = all_goldmedalstandards(workouts,startdate,enddate)
nrdays = (enddate-startdate).days
td = []
markerscore = []
score = []
markerduration = []
duration = []
workoutid = []
previous = 0
for i in range(len(dates)):
id = ids[i]
w = Workout.objects.get(id=id)
dd = str(dates[i])
#td.append(arrow.get(dd).datetime)
td.append(arrow.get(w.date).datetime)
markerscore.append(testpower[i])
markerduration.append(testduration[i])
score.append(testpower[i])
duration.append(testduration[i])
workoutid.append(id)
for i in range(len(alldates)):
td.append(arrow.get(alldates[i]).datetime)
markerscore.append(np.nan)
score.append(alltestpower[i])
markerduration.append(np.nan)
duration.append(allduration[i])
workoutid.append(allids[i])
for i in range(nrdays+1):
td.append(arrow.get(startdate+datetime.timedelta(days=i)).datetime)
markerscore.append(np.nan)
score.append(np.nan)
markerduration.append(np.nan)
duration.append(np.nan)
workoutid.append(0)
df = pd.DataFrame({
'markerscore':markerscore,
'markerduration':markerduration,
'score':score,
'duration':duration,
'date':td,
'id':workoutid,
})
df['url'] = df['id'].apply(lambda x:settings.SITE_URL+'/rowers/workout/{id}/'.format(id=encoder.encode_hex(x)))
df['workout'] = df['id'].apply(lambda x:workoutname(x))
df.sort_values(['date'],inplace=True)
# find index values where score is max
idx = df.groupby(['date'])['score'].transform(max) == df['score']
df = df[idx]
source = ColumnDataSource(
data = dict(
markerscore = df['markerscore'],
score = df['score'],
markerduration = df['markerduration'].apply(lambda x:totaltime_sec_to_string(x,shorten=True)),
duration = df['duration'].apply(lambda x:totaltime_sec_to_string(x,shorten=True)),
date = df['date'],
fdate = df['date'].map(lambda x: x.strftime('%d-%m-%Y')),
url = df['url'],
workout = df['workout']
)
)
plot = Figure(tools=TOOLS,x_axis_type='datetime',
plot_width=900,plot_height=600,
toolbar_location='above',
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.image_url([watermarkurl],watermarkx,watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
plot.xaxis.axis_label = 'Date'
plot.yaxis.axis_label = 'Gold Medal Score'
plot.circle('date','score',source=source,fill_color='blue',
size=10,
legend_label='Workouts')
plot.circle('date','markerscore',source=source,fill_color='red',
size=10,
legend_label='Marker Workouts')
plot.legend.location = "bottom_left"
plot.x_range = Range1d(
startdate,enddate+datetime.timedelta(days=5),
)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Marker','@markerscore{int}'),
('Test', '@markerduration'),
('Score','@score{int}'),
('Duration', '@duration'),
('Date','@fdate'),
('Workout','@workout')
])
taptool = plot.select(type=TapTool)
taptool.callback = OpenURL(url='@url')
script, div = components(plot)
return script, div,outids
def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
metricchoice='trimp',doform=False,dofatigue=False,
showtests=False):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
TOOLS2 = 'box_zoom,hover'
# to avoid data mess later on
startdate = arrow.get(startdate).datetime.replace(hour=0,minute=0,second=0,microsecond=0)
enddate = enddate+datetime.timedelta(days=1)
enddate = arrow.get(enddate).datetime.replace(hour=0,minute=0,second=0,microsecond=0)
modelchoice = 'coggan'
p0 = 0
k1 = 1
k2 = 1
dates = []
testpower = []
fatigues = []
fitnesses = []
testduration = []
impulses = []
outids = []
workouts = Workout.objects.filter(user=user.rower,date__gte=startdate,
date__lte=enddate,
workouttype__in=mytypes.rowtypes,
duplicate=False).order_by('date')
markerworkouts = workouts.filter(rankingpiece=True)
outids = [w.id for w in markerworkouts]
dates = [arrow.get(w.date).datetime for w in workouts]
testpower = [w.goldmedalstandard if w.rankingpiece else np.nan for w in workouts]
impulses = [np.nan for w in workouts]
testduration = [w.goldmedalseconds if w.rankingpiece else 0 for w in workouts]
fitnesses = [np.nan for w in workouts]
fatigues = [np.nan for w in workouts]
fatigues,fitnesses,dates,testpower,testduration,impulses = getfatigues(fatigues,
fitnesses,
dates,
testpower,testduration,
impulses,
startdate,enddate,
user,metricchoice,
kfatigue,kfitness)
df = pd.DataFrame({
'date':dates,
'testpower':testpower,
'testduration': testduration,
'fatigue':fatigues,
'fitness':fitnesses,
'impulse':impulses,
})
endfitness = fitnesses[-2]
endfatigue = fatigues[-2]
endform = endfitness-endfatigue
if modelchoice == 'banister':
df['fatigue'] = k2*df['fatigue']
df['fitness'] = p0+k1*df['fitness']
df['form'] = df['fitness']-df['fatigue']
df.sort_values(['date'],inplace=True)
df = df.groupby(['date']).max()
df['date'] = df.index.values
#for row in df.iterrows():
# print(row)
source = ColumnDataSource(
data = dict(
testpower = df['testpower'],
testduration = df['testduration'].apply(lambda x:totaltime_sec_to_string(x,shorten=True)),
date = df['date'],
fdate = df['date'].map(lambda x: x.strftime('%d-%m-%Y')),
fitness = df['fitness'],
fatigue = df['fatigue'],
form = df['form'],
impulse = df['impulse']
)
)
plot = Figure(tools=TOOLS,x_axis_type='datetime',
plot_width=900,plot_height=300,
toolbar_location="above",
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.image_url([watermarkurl],watermarkx,watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
if modelchoice == 'banister':
fitlabel = 'PTE (fitness)'
fatiguelabel = 'NTE (fatigue)'
formlabel = 'Performance'
rightaxlabel = 'Performance'
if dofatigue:
yaxlabel = 'PTE/NTE'
else:
yaxlabel = 'PTE'
else:
fitlabel = 'Fitness'
fatiguelabel = 'Fatigue'
formlabel = 'Freshness'
rightaxlabel = 'Freshness'
if dofatigue:
yaxlabel = 'Fitness/Fatigue'
else:
yaxlabel = 'Fitness'
#if showtests:
# plot.circle('date','testpower',source=source,fill_color='green',size=10,
# legend_label='Your best workouts')
plot.xaxis.axis_label = None
plot.yaxis.axis_label = yaxlabel
y2rangemin = df.loc[:,['form']].min().min()
y2rangemax = df.loc[:,['form']].max().max()
#if dofatigue and showtests:
# y1rangemin = df.loc[:,['testpower','fitness','fatigue']].min().min()
# y1rangemax = df.loc[:,['testpower','fitness','fatigue']].max().max()*1.02
#elif showtests:
# y1rangemin = df.loc[:,['testpower','fitness']].min().min()
# y1rangemax = df.loc[:,['testpower','fitness']].max().max()*1.02
if dofatigue:
y1rangemin = df.loc[:,['fitness','fatigue']].min().min()
y1rangemax = df.loc[:,['fitness','fatigue']].max().max()*1.02
else:
y1rangemin = df.loc[:,['fitness']].min().min()
y1rangemax = df.loc[:,['fitness']].max().max()*1.02
if doform:
plot.extra_y_ranges["yax2"] = Range1d(start=y2rangemin,end=y2rangemax)
plot.add_layout(LinearAxis(y_range_name="yax2",axis_label=rightaxlabel),"right")
plot.line('date','fitness',source=source,color='blue',
legend_label=fitlabel)
band = Band(base='date', upper='fitness', source=source, level='underlay',
fill_alpha=0.2, fill_color='blue')
plot.add_layout(band)
if dofatigue:
plot.line('date','fatigue',source=source,color='red',
legend_label=fatiguelabel)
if doform:
plot.line('date','form',source=source,color='green',
legend_label=formlabel,y_range_name="yax2")
plot.legend.location = "top_left"
plot.sizing_mode = 'scale_both'
#plot.y_range = Range1d(0,1.5*max(df['testpower']))
startdate = datetime.datetime.combine(startdate,datetime.datetime.min.time())
enddate = datetime.datetime.combine(enddate,datetime.datetime.min.time())
xrange = Range1d(
startdate,enddate,
)
plot.x_range = xrange
plot.y_range = Range1d(
start=0,end=y1rangemax,
)
plot.title.text = 'Performance Manager '+user.first_name
hover = plot.select(dict(type=HoverTool))
linked_crosshair = CrosshairTool(dimensions='height')
hover.tooltips = OrderedDict([
#(legend_label,'@testpower'),
('Date','@fdate'),
(fitlabel,'@fitness{int}'),
(fatiguelabel,'@fatigue{int}'),
(formlabel,'@form{int}'),
('Impulse','@impulse{int}')
])
if showtests:
hover.tooltips = OrderedDict([
#(legend_label,'@testpower'),
('Date','@fdate'),
(fitlabel,'@fitness{int}'),
(fatiguelabel,'@fatigue{int}'),
(formlabel,'@form{int}'),
('Impulse','@impulse{int}'),
('Gold Medal Score','@testpower{int}'),
('Test', '@testduration'),
])
plot2 = Figure(tools=TOOLS2,x_axis_type='datetime',
plot_width=900,plot_height=150,
toolbar_location=None,
toolbar_sticky=False)
plot2.x_range = xrange
plot2.y_range = Range1d(0,df['impulse'].max())
plot2.vbar(x = df['date'], top = df['impulse'],color='gray')
plot2.vbar(x = df['date'], top = 0*df['testpower']+df['impulse'], color='red')
plot2.sizing_mode = 'scale_both'
plot2.yaxis.axis_label = 'Impulse'
plot2.xaxis.axis_label = 'Date'
plot.add_tools(linked_crosshair)
plot2.add_tools(linked_crosshair)
layout = layoutcolumn([plot,plot2])
layout.sizing_mode = 'stretch_both'
try:
script,div = components(layout)
except Exception as e:
df.dropna(inplace=True,axis=0,how='any')
return (
'',
'Something went wrong with the chart ({nrworkouts} workouts, {nrdata} datapoints, error {e})'.format(
nrworkouts = workouts.count(),
nrdata = len(df),
e = e,
),0,0,0,[]
)
return [script,div,endfitness,endfatigue,endform,outids]
def interactive_histoall(theworkouts,histoparam,includereststrokes,
spmmin=0,spmmax=55,
workmin=0,workmax=1500):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
ids = [int(w.id) for w in theworkouts]
workstrokesonly = not includereststrokes
rowdata = dataprep.getsmallrowdata_db([histoparam],ids=ids,doclean=True,workstrokesonly=workstrokesonly)
rowdata.dropna(axis=0,how='any',inplace=True)
rowdata = dataprep.filter_df(rowdata,'spm',spmmin,largerthan=True)
rowdata = dataprep.filter_df(rowdata,'spm',spmmax,largerthan=False)
rowdata = dataprep.filter_df(rowdata,'driveenergy',workmin,largerthan=True)
rowdata = dataprep.filter_df(rowdata,'driveenergy',workmax,largerthan=False)
if rowdata.empty:
return "","No Valid Data Available"
try:
histopwr = rowdata[histoparam].values
except KeyError:
return "","No data"
if len(histopwr) == 0:
return "","No valid data available"
# throw out nans
histopwr = histopwr[~np.isinf(histopwr)]
histopwr = histopwr[histopwr > yaxminima[histoparam]]
histopwr = histopwr[histopwr < yaxmaxima[histoparam]]
plot = Figure(tools=TOOLS,plot_width=900,
toolbar_sticky=False,
toolbar_location="above"
)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.image_url([watermarkurl],watermarkx,watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
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 = axlabels[histoparam]
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([
(axlabels[histoparam],'@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')
plot.sizing_mode = 'stretch_both'
annolabel = Label(x=50,y=450,x_units='screen',y_units='screen',
text='',
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black',
)
plot.add_layout(annolabel)
callback = CustomJS(args = dict(
annolabel=annolabel,
), code="""
var annotation = annotation.value
annolabel.text = annotation
""")
annotation = TextInput(width=140, title="Type your plot notes here", value="")
annotation.js_on_change('value',callback)
callback.args["annotation"] = annotation
layout = layoutcolumn([annotation,plot])
try:
script, div = components(layout)
except ValueError:
script = ''
div = ''
return [script,div]
def course_map(course):
latmean,lonmean,coordinates = course_coord_center(course)
lat_min, lat_max, long_min, long_max = course_coord_maxmin(course)
coordinates = course_spline(coordinates)
scoordinates = "["
for index,row in coordinates.iterrows():
scoordinates += """[{x},{y}],
""".format(
x=row['latitude'],
y=row['longitude']
)
scoordinates +="]"
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
plabels = ''
for p in polygons:
coords = polygon_coord_center(p)
plabels += """
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
marker.bindPopup("<b>{name}</b>");
""".format(
latbegin = coords[0],
longbegin = coords[1],
name = p.name
)
pcoordinates = """[
"""
for p in polygons:
pcoordinates += """[
["""
points = GeoPoint.objects.filter(polygon=p).order_by("order_in_poly")
for pt in points:
pcoordinates += "[{x},{y}],".format(
x = pt.latitude,
y = pt.longitude
)
# remove last comma
pcoordinates = pcoordinates[:-1]
pcoordinates += """]
],
"""
pcoordinates += """
]"""
script = """
<script>
var streets = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/streets-v11',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
),
satellite = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/satellite-v9',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
),
outdoors = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/outdoors-v11',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
);
var mymap = L.map('map_canvas', {{
center: [{latmean}, {lonmean}],
zoom: 13,
layers: [outdoors]
}}).setView([{latmean},{lonmean}], 13);
var navionics = new JNC.Leaflet.NavionicsOverlay({{
navKey: 'Navionics_webapi_03205',
chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
isTransparent: true,
zIndex: 1
}});
var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';
//create two TileLayer
var nautical=new L.TileLayer(osmUrl,{{
maxZoom:18}});
L.control.layers({{
"Streets": streets,
"Satellite": satellite,
"Outdoors": outdoors,
"Nautical": nautical,
}},{{
"Navionics":navionics,
}}).addTo(mymap);
var latlongs = {scoordinates}
var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap)
mymap.fitBounds(polyline.getBounds())
var platlongs = {pcoordinates}
var polygons = L.polygon(platlongs, {{color:'blue'}}).addTo(mymap)
{plabels}
</script>
""".format(
latmean=latmean,
lonmean=lonmean,
scoordinates=scoordinates,
pcoordinates=pcoordinates,
plabels = plabels
)
div = """
<div id="map_canvas" style="width: 100%; height: 400px; margin:0; padding:0;grid-gap:0;"></div>
"""
return script,div
def leaflet_chart(lat,lon,name=""):
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
# Throw out 0,0
df = pd.DataFrame({
'lat':lat,
'lon':lon
})
df = df.replace(0,np.nan)
df = df.loc[(df!=0).any(axis=1)]
df.fillna(method='bfill',axis=0,inplace=True)
df.fillna(method='ffill',axis=0,inplace=True)
lat = df['lat']
lon = df['lon']
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
latmean = lat.mean()
lonmean = lon.mean()
latbegin = lat[lat.index[0]]
longbegin = lon[lon.index[0]]
latend = lat[lat.index[-1]]
longend = lon[lon.index[-1]]
coordinates = zip(lat,lon)
scoordinates = "["
for x,y in coordinates:
scoordinates += """[{x},{y}],
""".format(
x=x,
y=y
)
scoordinates += "]"
script = """
<script>
var streets = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/streets-v11',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
),
satellite = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/satellite-v9',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
),
outdoors = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/outdoors-v11',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
);
var mymap = L.map('map_canvas', {{
center: [{latmean}, {lonmean}],
zoom: 13,
layers: [streets, satellite]
}}).setView([{latmean},{lonmean}], 13);
var navionics = new JNC.Leaflet.NavionicsOverlay({{
navKey: 'Navionics_webapi_03205',
chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
isTransparent: true,
zIndex: 1
}});
var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';
//create two TileLayer
var nautical=new L.TileLayer(osmUrl,{{
maxZoom:18}});
L.control.layers({{
"Streets": streets,
"Satellite": satellite,
"Outdoors": outdoors,
"Nautical": nautical,
}},{{
"Navionics":navionics,
}}).addTo(mymap);
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
marker.bindPopup("<b>Start</b>");
var emarker = new L.marker([{latend}, {longend}]).addTo(mymap);
emarker.bindPopup("<b>End</b>");
var latlongs = {scoordinates}
var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap)
mymap.fitBounds(polyline.getBounds())
</script>
""".format(
latmean=latmean,
lonmean=lonmean,
latbegin = latbegin,
latend=latend,
longbegin=longbegin,
longend=longend,
scoordinates=scoordinates,
)
div = """
<div id="map_canvas" style="width: 100%; height: 400px;"><p>&nbsp;</p></div>
"""
return script,div
def leaflet_chart_compare(course,workoutids,labeldict={},startenddict={}):
data = []
for id in workoutids:
if id != 0 and id is not None:
try:
w = Workout.objects.get(id=id)
rowdata = rdata(w.csvfilename)
time = rowdata.df['TimeStamp (sec)']
df = pd.DataFrame({
'workoutid':id,
'lat':rowdata.df[' latitude'],
'lon':rowdata.df[' longitude'],
'time':time-time[0],
})
data.append(df)
except (Workout.DoesNotExist,KeyError):
pass
df = pd.concat(data,axis=0)
latmean,lonmean,coordinates = course_coord_center(course)
lat_min, lat_max, long_min, long_max = course_coord_maxmin(course)
coordinates = course_spline(coordinates)
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
plabels = ''
for p in polygons:
coords = polygon_coord_center(p)
plabels += """
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
marker.bindPopup("<b>{name}</b>");
""".format(
latbegin = coords[0],
longbegin = coords[1],
name = p.name
)
pcoordinates = """[
"""
for p in polygons:
pcoordinates += """[
["""
points = GeoPoint.objects.filter(polygon=p).order_by("order_in_poly")
for pt in points:
pcoordinates += "[{x},{y}],".format(
x = pt.latitude,
y = pt.longitude
)
# remove last comma
pcoordinates = pcoordinates[:-1]
pcoordinates += """]
],
"""
pcoordinates += """
]"""
# Throw out 0,0
df = df.replace(0,np.nan)
df = df.loc[(df!=0).any(axis=1)]
df.fillna(method='bfill',axis=0,inplace=True)
df.fillna(method='ffill',axis=0,inplace=True)
lat = df['lat']
lon = df['lon']
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
latbegin = lat.values[0]
longbegin = lon.values[0]
latend = lat.values[-1]
longend = lon.values[-1]
colors = itertools.cycle(palette)
try:
items = itertools.izip(workoutids,colors)
except AttributeError:
items = zip(workoutids,colors)
script = """
<script>
var streets = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/streets-v11',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
),
satellite = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/satellite-v9',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
),
outdoors = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/outdoors-v11',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
);
var navionics = new JNC.Leaflet.NavionicsOverlay({{
navKey: 'Navionics_webapi_03205',
chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
isTransparent: true,
zIndex: 1
}});
var mymap = L.map('map_canvas', {{
center: [{latmean}, {lonmean}],
zoom: 13,
layers: [outdoors]
}}).setView([{latmean},{lonmean}], 13);
var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';
//create two TileLayer
var nautical=new L.TileLayer(osmUrl,{{
maxZoom:18}});
L.control.layers({{
"Streets": streets,
"Satellite": satellite,
"Outdoors": outdoors,
"Nautical": nautical,
}},{{
"Navionics":navionics,
}}).addTo(mymap);
var platlongs = {pcoordinates}
var polygons = L.polygon(platlongs, {{color:'blue'}}).addTo(mymap)
{plabels}
""".format(
latmean=latmean,
lonmean=lonmean,
latbegin = latbegin,
latend=latend,
longbegin=longbegin,
longend=longend,
pcoordinates=pcoordinates,
plabels=plabels,
)
for id,color in items:
group = df[df['workoutid']==int(id)].copy()
try:
startsecond,endsecond = startenddict[id]
except KeyError:
startsecond = 0
endsecond = 0
try:
label = labeldict[id]
except KeyError:
label = str(id)
group.sort_values(by='time',ascending=True,inplace=True)
group.dropna(axis=0,how='any',inplace=True)
if endsecond > 0:
group['time'] = group['time'] - startsecond
mask = group['time'] < 0
group.mask(mask,inplace=True)
mask = group['time'] > (endsecond-startsecond)
group.mask(mask,inplace=True)
lat = group['lat'].dropna()
lon = group['lon'].dropna()
coordinates = zip(lat,lon)
scoordinates = "["
for x,y in coordinates:
scoordinates += """[{x},{y}],
""".format(x=x,y=y)
scoordinates += "]"
if not group.empty:
script += """
var latlongs = {scoordinates}
var polyline = L.polyline(latlongs, {{color:'{color}'}}).addTo(mymap)
polyline.bindPopup("<b>{label}</b>",{{ autoPan: false, autoClose: false }}).openPopup()
polyline.on('mouseover',function(ev) {{
ev.target.openPopup();
}});
polyline.on('dblclick', function (e) {{
mymap.removeLayer(this);
}});
mymap.fitBounds(polyline.getBounds())
""".format(
scoordinates=scoordinates,
color=color,
label=label,
id=id,
)
script += """
</script>
"""
div = """
<div id="map_canvas" style="width: 100%; height: 100%; min-height: 100vh"><p>&nbsp;</p></div>
"""
return script,div
def leaflet_chart2(lat,lon,name=""):
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
# Throw out 0,0
df = pd.DataFrame({
'lat':lat,
'lon':lon
})
df = df.replace(0,np.nan)
df = df.loc[(df!=0).any(axis=1)]
df.fillna(method='bfill',axis=0,inplace=True)
df.fillna(method='ffill',axis=0,inplace=True)
lat = df['lat']
lon = df['lon']
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
latmean = lat.mean()
lonmean = lon.mean()
latbegin = lat[lat.index[0]]
longbegin = lon[lon.index[0]]
latend = lat[lat.index[-1]]
longend = lon[lon.index[-1]]
coordinates = zip(lat,lon)
scoordinates = "["
for x,y in coordinates:
scoordinates += """[{x},{y}],
""".format(
x=x,
y=y
)
scoordinates += "]"
script = """
<script>
var streets = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/streets-v11',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
),
satellite = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/satellite-v9',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
),
outdoors = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/outdoors-v11',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
);
var mymap = L.map('map_canvas', {{
center: [{latmean}, {lonmean}],
zoom: 13,
layers: [streets, satellite]
}}).setView([{latmean},{lonmean}], 13);
var navionics = new JNC.Leaflet.NavionicsOverlay({{
navKey: 'Navionics_webapi_03205',
chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
isTransparent: true,
zIndex: 1
}});
var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';
//create two TileLayer
var nautical=new L.TileLayer(osmUrl,{{
maxZoom:18}});
L.control.layers({{
"Streets": streets,
"Satellite": satellite,
"Outdoors": outdoors,
"Nautical": nautical,
}},{{
"Navionics":navionics,
}}).addTo(mymap);
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
marker.bindPopup("<b>Start</b>");
var emarker = new L.marker([{latend}, {longend}]).addTo(mymap);
emarker.bindPopup("<b>End</b>");
var latlongs = {scoordinates}
var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap)
mymap.fitBounds(polyline.getBounds())
</script>
""".format(
latmean=latmean,
lonmean=lonmean,
latbegin = latbegin,
latend=latend,
longbegin=longbegin,
longend=longend,
scoordinates=scoordinates,
)
div = """
<div id="map_canvas" style="width: 100%; height: 100%; min-height: 100vh"><p>&nbsp;</p></div>
"""
return script,div
def leaflet_chart_video(lat,lon,name=""):
if not len(lat) or not len(lon):
return [0,"invalid coordinate data"]
# Throw out 0,0
df = pd.DataFrame({
'lat':lat,
'lon':lon
})
df = df.replace(0,np.nan)
df = df.loc[(df!=0).any(axis=1)]
df.fillna(method='bfill',axis=0,inplace=True)
df.fillna(method='ffill',axis=0,inplace=True)
lat = df['lat']
lon = df['lon']
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
latmean = lat.mean()
lonmean = lon.mean()
latbegin = lat[lat.index[0]]
longbegin = lon[lon.index[0]]
latend = lat[lat.index[-1]]
longend = lon[lon.index[-1]]
coordinates = zip(lat,lon)
scoordinates = "["
for x,y in coordinates:
scoordinates += """[{x},{y}],
""".format(
x=x,
y=y
)
scoordinates += "]"
script = """
var streets = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/streets-v11',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
),
satellite = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/satellite-v9',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
),
outdoors = L.tileLayer(
'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
tileSize: 512,
maxZoom: 18,
zoomOffset: -1,
id: 'mapbox/outdoors-v11',
accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
);
var mymap = L.map('map_canvas', {{
center: [{latmean}, {lonmean}],
zoom: 13,
layers: [streets, satellite]
}}).setView([{latmean},{lonmean}], 13);
var navionics = new JNC.Leaflet.NavionicsOverlay({{
navKey: 'Navionics_webapi_03205',
chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
isTransparent: true,
zIndex: 1
}});
var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';
//create two TileLayer
var nautical=new L.TileLayer(osmUrl,{{
maxZoom:18}});
L.control.layers({{
"Streets": streets,
"Satellite": satellite,
"Outdoors": outdoors,
"Nautical": nautical,
}},{{
"Navionics":navionics,
}},
{{
position:'topleft'
}}).addTo(mymap);
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
marker.bindPopup("<b>Start</b>");
var latlongs = {scoordinates}
var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap)
mymap.fitBounds(polyline.getBounds())
""".format(
latmean=latmean,
lonmean=lonmean,
latbegin = latbegin,
latend=latend,
longbegin=longbegin,
longend=longend,
scoordinates=scoordinates,
)
div = """
<div id="map_canvas" style="width: 640px; height: 390px;"><p>&nbsp;</p></div>
"""
return script,div
def interactive_agegroupcpchart(age,normalized=False):
durations = [1,4,30,60]
distances = [100,500,1000,2000,5000,6000,10000,21097,42195]
fhduration = []
fhpower = []
for distance in distances:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='female',
distance=distance,
weightcategory='hwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try:
duration = distance/velo
fhduration.append(duration)
fhpower.append(worldclasspower)
except ZeroDivisionError:
pass
for duration in durations:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='female',
duration=duration,
weightcategory='hwt'
)
try:
velo = (worldclasspower/2.8)**(1./3.)
distance = int(60*duration*velo)
fhduration.append(60.*duration)
fhpower.append(worldclasspower)
except ValueError:
pass
flduration = []
flpower = []
for distance in distances:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='female',
distance=distance,
weightcategory='lwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try:
duration = distance/velo
flduration.append(duration)
flpower.append(worldclasspower)
except ZeroDivisionError:
pass
for duration in durations:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='female',
duration=duration,
weightcategory='lwt'
)
try:
velo = (worldclasspower/2.8)**(1./3.)
distance = int(60*duration*velo)
flduration.append(60.*duration)
flpower.append(worldclasspower)
except ValueError:
pass
mlduration = []
mlpower = []
for distance in distances:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='male',
distance=distance,
weightcategory='lwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try:
duration = distance/velo
mlduration.append(duration)
mlpower.append(worldclasspower)
except ZeroDivisionError:
pass
for duration in durations:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='male',
duration=duration,
weightcategory='lwt'
)
try:
velo = (worldclasspower/2.8)**(1./3.)
distance = int(60*duration*velo)
mlduration.append(60.*duration)
mlpower.append(worldclasspower)
except ValueError:
pass
mhduration = []
mhpower = []
for distance in distances:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='male',
distance=distance,
weightcategory='hwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try:
duration = distance/velo
mhduration.append(duration)
mhpower.append(worldclasspower)
except ZeroDivisionError:
pass
for duration in durations:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='male',
duration=duration,
weightcategory='hwt'
)
try:
velo = (worldclasspower/2.8)**(1./3.)
distance = int(60*duration*velo)
mhduration.append(60.*duration)
mhpower.append(worldclasspower)
except ValueError:
pass
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]
# fitting WC data to three parameter CP model
if len(fhduration)>=4:
p1fh, success = optimize.leastsq(errfunc, p0[:],
args = (fhduration,fhpower))
else:
p1fh = None
# fitting WC data to three parameter CP model
if len(flduration)>=4:
p1fl, success = optimize.leastsq(errfunc, p0[:],
args = (flduration,flpower))
else:
p1fl = None
# fitting WC data to three parameter CP model
if len(mlduration)>=4:
p1ml, success = optimize.leastsq(errfunc, p0[:],
args = (mlduration,mlpower))
else:
p1ml = None
if len(mhduration)>=4:
p1mh, success = optimize.leastsq(errfunc, p0[:],
args = (mhduration,mhpower))
else:
p1mh = None
fitt = pd.Series(10**(4*np.arange(100)/100.))
fitpowerfh = fitfunc(p1fh,fitt)
fitpowerfl = fitfunc(p1fl,fitt)
fitpowerml = fitfunc(p1ml,fitt)
fitpowermh = fitfunc(p1mh,fitt)
if normalized:
facfh = fitfunc(p1fh,60)
facfl = fitfunc(p1fl,60)
facml = fitfunc(p1ml,60)
facmh = fitfunc(p1mh,60)
fitpowerfh /= facfh
fitpowerfl /= facfl
fitpowermh /= facmh
fitpowerml /= facml
fhpower /= facfh
flpower /= facfl
mlpower /= facml
mhpower /= facmh
source = ColumnDataSource(
data = dict(
duration = fitt,
fitpowerfh = fitpowerfh,
fitpowerfl = fitpowerfl,
fitpowerml = fitpowerml,
fitpowermh = fitpowermh,
flduration = flduration,
flpower = flpower,
fhduration = fhduration,
fhpower = fhpower,
mlduration = mlduration,
mlpower = mlpower,
mhduration = mhduration,
mhpower = mhpower,
)
)
x_axis_type = 'log'
y_axis_type = 'linear'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
plot = Figure(plot_width=900,x_axis_type=x_axis_type,
tools=TOOLS)
plot.sizing_mode = 'stretch_both'
plot.line('duration','fitpowerfh',source=source,
legend_label='Female HW',color='blue')
plot.line('duration','fitpowerfl',source=source,
legend_label='Female LW',color='red')
plot.line('duration','fitpowerml',source=source,
legend_label='Male LW',color='green')
plot.line('duration','fitpowermh',source=source,
legend_label='Male HW',color='orange')
plot.circle('flduration','flpower',source=source,
fill_color='red',size=15)
plot.circle('fhduration','fhpower',source=source,
fill_color='blue',size=15)
plot.circle('mlduration','mlpower',source=source,
fill_color='green',size=15)
plot.circle('mhduration','mhpower',source=source,
fill_color='orange',size=15)
plot.title.text = 'age '+str(age)
plot.xaxis.axis_label = "Duration (seconds)"
if normalized:
plot.yaxis.axis_label = "Power (normalized)"
else:
plot.yaxis.axis_label = "Power (W)"
script,div = components(plot)
return script,div
def interactive_otwcpchart(powerdf,promember=0,rowername="",r=None,cpfit='data',
title='',type='water'):
powerdf = powerdf[~(powerdf == 0).any(axis=1)]
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
x_axis_type = 'log'
y_axis_type = 'linear'
deltas = powerdf['Delta'].apply(lambda x: timedeltaconv(x))
powerdf['ftime'] = niceformat(deltas)
powerdf['Deltaminutes'] = powerdf['Delta']/60.
source = ColumnDataSource(
data = powerdf
)
# there is no Paul's law for OTW
thesecs = powerdf['Delta']
theavpower = powerdf['CP']
p1,fitt,fitpower,ratio = datautils.cpfit(powerdf)
if cpfit == 'automatic' and r is not None:
if type == 'water':
p1 = [r.p0,r.p1,r.p2,r.p3]
ratio = r.cpratio
elif type == 'erg' :
p1 = [r.ep0,r.ep1,r.ep2,r.ep3]
ratio = r.ecpratio
fitfunc = lambda pars,x: abs(pars[0])/(1+(x/abs(pars[2]))) + abs(pars[1])/(1+(x/abs(pars[3])))
fitpower = fitfunc(p1,fitt)
message = ""
#if len(fitpower[fitpower<0]) > 0:
# message = "CP model fit didn't give correct results"
deltas = fitt.apply(lambda x: timedeltaconv(x))
ftime = niceformat(deltas)
workouts = powerdf['workout']
urls = powerdf['url']
sourcecomplex = ColumnDataSource(
data = dict(
CP = fitpower,
CPmax = ratio*fitpower,
duration = fitt/60.,
ftime = ftime,
workout = workouts,
url = urls,
)
)
# making the plot
plot = Figure(tools=TOOLS,x_axis_type=x_axis_type,
plot_width=900,
toolbar_location="above",
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_both'
plot.image_url([watermarkurl],1.8*max(thesecs),watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
y_range_name = "watermark",
)
plot.circle('Deltaminutes','CP',source=source,fill_color='red',size=15,
legend_label='Power Data')
plot.xaxis.axis_label = "Duration (minutes)"
plot.yaxis.axis_label = "Power (W)"
plot.y_range = Range1d(0,1.5*max(theavpower))
plot.x_range = Range1d(0.5*min(thesecs)/60.,2*max(thesecs)/60.)
plot.legend.orientation = "vertical"
if not title:
title = "Critical Power for "+rowername
plot.title.text = title
xaxis = plot.select(dict(type=Axis, layout="below"))[0]
xaxis.formatter = PrintfTickFormatter()
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Duration ','@ftime'),
('Power (W)','@CP{int}'),
('Power (W) upper','@CPmax{int}'),
('Workout','@workout'),
])
hover.mode = 'mouse'
taptool = plot.select(type=TapTool)
taptool.callback = OpenURL(url='@url')
plot.line('duration','CP',source=sourcecomplex,legend_label="CP Model",
color='green')
plot.line('duration','CPmax',source=sourcecomplex,legend_label="CP Model",
color='red')
script, div = components(plot)
return [script,div,p1,ratio,message]
def interactive_agegroup_plot(df,distance=2000,duration=None,
sex='male',weightcategory='hwt'):
if df.empty:
return '',''
age = df['age']
power = df['power']
name = df['name']
season = df['season']
if duration:
duration2 = int(duration/60.)
plottitle = sex+' '+weightcategory+' %s min' % duration2
else:
plottitle = sex+' '+weightcategory+' %s m' % distance
# poly_coefficients = np.polyfit(age,power,6)
age2 = np.linspace(11,95)
# poly_vals = np.polyval(poly_coefficients,age2)
# poly_vals = 0.5*(np.abs(poly_vals)+poly_vals)
fitfunc = lambda pars, x: np.abs(pars[0])*(1-x/max(120,pars[1]))-np.abs(pars[2])*np.exp(-x/np.abs(pars[3]))+np.abs(pars[4])*(np.sin(np.pi*x/max(50,pars[5])))
errfunc = lambda pars, x,y: fitfunc(pars,x)-y
p0age = [700,120,700,10,100,100]
p1, success = optimize.leastsq(errfunc,p0age[:],
args = (age,power))
expo_vals = fitfunc(p1, age2)
expo_vals = 0.5*(np.abs(expo_vals)+expo_vals)
source = ColumnDataSource(
data = dict(
age = age,
power = power,
age2 = age2,
expo_vals = expo_vals,
season = season,
name=name,
)
)
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
plot = Figure(tools=TOOLS,plot_width=900)
plot.sizing_mode='stretch_both'
plot.circle('age','power',source=source,fill_color='red',size=15,
legend_label='World Record')
plot.line(age2,expo_vals)
plot.xaxis.axis_label = "Age"
plot.yaxis.axis_label = "Concept2 power"
plot.title.text = plottitle
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Name ','@name'),
('Season ','@season'),
])
hover.mode = 'mouse'
script,div = components(plot)
return script,div
def interactive_cpchart(rower,thedistances,thesecs,theavpower,
theworkouts,promember=0,
wcpower=[],wcdurations=[]):
message = 0
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,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),
)
)
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]
wcpower = pd.Series(wcpower)
wcdurations = pd.Series(wcdurations)
# fitting WC data to three parameter CP model
if len(wcdurations)>=4:
p1wc, success = optimize.leastsq(errfunc, p0[:],
args = (wcdurations,wcpower))
else:
p1wc = None
# fitting the data to three parameter CP model
success = 0
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]]
success = 0
# Get stayer score
if success == 1:
power1min = fitfunc(p1,60.)
power4min = fitfunc(p1,240.)
power6min = fitfunc(p1,360.)
power30min = fitfunc(p1,1800.)
power1h = fitfunc(p1,3600.)
power10sec = fitfunc(p1,10.)
r10sec4min = 100.*power10sec/power4min
r1h4min = 100.*power1h/power4min
r1min6min = 100.*power1min/power6min
r30min6min = 100.*power30min/power6min
combined = r1h4min-0.2*(r10sec4min-100)
combined2 = r30min6min-1.5*(r1min6min-100)
dataset = pd.read_csv('static/stats/combined_set.csv')
dataset2 = pd.read_csv('static/stats/combined_set6min.csv')
stayerscore = int(percentileofscore(dataset['combined'],combined))
stayerscore2 = int(percentileofscore(dataset2['combined'],combined2))
else:
stayerscore = None
stayerscore2 = None
fitt = pd.Series(10**(4*np.arange(100)/100.))
fitpower = fitfunc(p1,fitt)
if p1wc is not None:
fitpowerwc = 0.95*fitfunc(p1wc,fitt)
fitpowerexcellent = 0.7*fitfunc(p1wc,fitt)
fitpowergood = 0.6*fitfunc(p1wc,fitt)
fitpowerfair = 0.5*fitfunc(p1wc,fitt)
fitpoweraverage = 0.4*fitfunc(p1wc,fitt)
else:
fitpowerwc = 0*fitpower
fitpowerexcellent = 0*fitpower
fitpowergood = 0*fitpower
fitpowerfair = 0*fitpower
fitpoweraverage = 0*fitpower
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,
fitpowerwc = fitpowerwc,
fitpowerexcellent = fitpowerexcellent,
fitpowergood = fitpowergood,
fitpowerfair = fitpowerfair,
fitpoweraverage = fitpoweraverage,
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)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_both'
plot.image_url([watermarkurl],1.8*max(thesecs),watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
y_range_name = "watermark",
)
plot.circle('duration','power',source=source,fill_color='red',size=15,
legend_label='Power')
plot.xaxis.axis_label = "Duration (seconds)"
plot.yaxis.axis_label = "Power (W)"
if stayerscore is not None:
plot.add_layout(
Label(x=100,y=100,x_units='screen',y_units='screen',
text='Stayer Score '+str(stayerscore)+'%',
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black')
)
# plot.add_layout(
# Label(x=100,y=120,x_units='screen',y_units='screen',
# text='Stayer Score (6min) '+str(stayerscore2)+'%',
# background_fill_alpha=0.7,
# background_fill_color='white',
# text_color='black')
# )
cpdata = dataprep.fetchcperg(rower, theworkouts)
if cpdata.empty:
message = 'Calculations are running in the background. Please refresh this page to see updated results'
return ['','',paulslope,paulintercept,p1,message,p1wc]
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_label = '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_label="Paul's Law")
plot.line('duration','power',source=sourcecomplex,legend_label="CP Model",
color='green')
if p1wc is not None:
plot.line('duration','fitpowerwc',source=sourcecomplex,
legend_label="World Class",
color='Maroon',line_dash='dotted')
plot.line('duration','fitpowerexcellent',source=sourcecomplex,
legend_label="90% percentile",
color='Purple',line_dash='dotted')
plot.line('duration','fitpowergood',source=sourcecomplex,
legend_label="75% percentile",
color='Olive',line_dash='dotted')
plot.line('duration','fitpowerfair',source=sourcecomplex,
legend_label="50% percentile",
color='Gray',line_dash='dotted')
plot.line('duration','fitpoweraverage',source=sourcecomplex,
legend_label="25% percentile",
color='SkyBlue',line_dash='dotted')
script, div = components(plot)
return [script,div,paulslope,paulintercept,p1,message,p1wc]
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
try:
dist = rowdata.df.loc[:,'cum_dist']
except KeyError:
return ['','No Data Found']
try:
vwind = rowdata.df.loc[:,'vwind']
winddirection = rowdata.df.loc[:,'winddirection']
bearing = rowdata.df.loc[:,'bearing']
except KeyError:
rowdata.add_wind(0,0)
rowdata.add_bearing()
vwind = rowdata.df.loc[:,'vwind']
winddirection = rowdata.df.loc[:,'winddirection']
bearing = rowdata.df.loc[:,'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,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_label="Wind Speed (m/s)")
plot.line('dist','tw',source=source,legend_label="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.sizing_mode = 'stretch_both'
plot.extra_y_ranges = {"winddirection": Range1d(start=0,end=360)}
plot.line('dist','winddirection',source=source,
legend_label='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"
try:
dist = rowdata.df.loc[:,'cum_dist']
except KeyError:
return ['','No Data found']
try:
vstream = rowdata.df.loc[:,'vstream']
except KeyError:
rowdata.add_stream(0)
vstream = rowdata.df.loc[:,'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,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_label="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)
plot.sizing_mode = 'stretch_both'
script, div = components(plot)
return [script,div]
def interactive_chart(id=0,promember=0,intervaldata = {}):
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
columns = ['time','pace','hr','fpace','ftime','spm']
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:
# try:
# datadf.sort_values(by='time',ascending=True,inplace=True)
# except KeyError:
# return "","No valid data available"
try:
spm = datadf['spm']
except KeyError:
datadf['spm'] = 0
try:
pace = datadf['pace']
except KeyError:
datadf['pace'] = 0
source = ColumnDataSource(
datadf
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
plot_width=400,
plot_height=400,
toolbar_sticky=False,
tools=TOOLS)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.image_url([watermarkurl],0.01,0.99,
0.5*watermarkw,0.5*watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor='top_left',
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
plot.line('time','pace',source=source,legend_label="Pace",name="pace")
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.sizing_mode = 'stretch_both'
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)
plot.extra_y_ranges["spmax"] = Range1d(start=10,end=45)
plot.line('time','spm',source=source,color="red",
y_range_name="spmax", legend_label="Stroke Rate",name="spm")
plot.add_layout(LinearAxis(y_range_name="spmax",axis_label="SPM"),'right')
plot.legend.location = "bottom_right"
# add shaded bar chart areas
if intervaldata != {}:
intervaldf = pd.DataFrame(intervaldata)
intervaldf['itime'] = intervaldf['itime']*1.e3
intervaldf['time'] = intervaldf['itime'].cumsum()
intervaldf['time'] = intervaldf['time'].shift(1)
intervaldf.loc[:,'time'].iloc[0] = 0
intervaldf['time_r'] = intervaldf['time'] +intervaldf['itime']
intervaldf['value'] = 100
mask = intervaldf['itype'] == 3
intervaldf.loc[mask,'value'] = 0
intervaldf['bottom'] = 10
intervalsource = ColumnDataSource(
intervaldf
)
plot.quad(left='time',top='value',bottom='bottom',
right='time_r',source=intervalsource,color='mediumvioletred',
y_range_name='spmax',fill_alpha=0.2,line_alpha=0.2)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Pace','@fpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
])
hover.mode = 'mouse'
hover.names = ["spm","pace"]
script, div = components(plot)
return [script,div]
def interactive_chart_video(videodata):
try:
spm = videodata['spm']
except KeyError:
return "","No SPM data"
time = range(len(spm))
data = zip(time,spm)
data2 = "["
for t,s in data:
data2 += "{x: %s, y: %s}, " % (t,s)
data2 = data2[:-2] + "]"
markerpoint = {
'x': time[0],
'y': spm[0],
'r': 10,
}
div = """
<canvas id="myChart">
</canvas>
"""
script = """
var ctx = document.getElementById("myChart").getContext('2d');
var data = %s
var myChart = new Chart(ctx, {
type: 'scatter',
label: 'SPM',
animationSteps: 10,
options: {
legend: {
display: false,
},
animation: {
duration: 100,
},
scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Stroke Rate'
}
}],
xAxes: [{
scaleLabel: {
type: 'linear',
display: true,
labelString: 'Time (seconds)'
}
}],
}
},
data:
{
datasets: [
{
type: 'bubble',
label: 'now',
data: [ %s ],
backgroundColor: '#36a2eb',
},
{
label: 'spm',
data: data,
backgroundColor: "#ff0000",
borderColor: "#ff0000",
fill: false,
borderDash: [0, 0],
pointRadius: 1,
pointHoverRadius: 1,
showLine: true,
tension: 0,
},
]
},
});
var marker = {
datapoint: %s ,
setLatLng: function (LatLng) {
var lat = LatLng.lat;
var lng = LatLng.lng;
this.datapoint = {
'x': lat,
'y': lng,
'r': 10,
}
myChart.data.datasets[0].data[0] = this.datapoint;
myChart.update();
}
}
marker.setLatLng({
'lat': data[0]['x'],
'lng': data[0]['y']
})
""" % (data2, markerpoint, markerpoint)
return [script,div]
def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
ploterrorbars=False,
title=None,binsize=1,colorlegend=[],
spmmin=0,spmmax=0,workmin=0,workmax=0):
if datadf.empty:
return ['','<p>No non-zero data in selection</p>']
if xparam == 'workoutid':
xparamname = 'Workout'
else:
xparamname = axlabels[xparam]
if yparam == 'workoutid':
yparamname = 'Workout'
else:
yparamname = axlabels[yparam]
if groupby == 'workoutid':
groupname = 'Workout'
elif groupby == 'date':
groupname = 'Date'
else:
groupname = axlabels[groupby]
if title==None:
title = '{y} vs {x} grouped by {gr}'.format(
x = xparamname,
y = yparamname,
gr = groupname,
)
if xparam == 'cumdist':
res = make_cumvalues(datadf[xparam])
datadf[xparam] = res[0]
if xparam=='distance':
xaxmax = datadf[xparam].max()
xaxmin = datadf[xparam].min()
elif xparam=='time':
tseconds = datadf.loc[:,'time']
xaxmax = tseconds.max()
xaxmin = 0
elif xparam == 'workoutid':
xaxmax = datadf[xparam].max()-5
xaxmin = datadf[xparam].min()+5
else:
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
if yparam=='distance':
yaxmax = datadf[yparam].max()
yaxmin = datadf[yparam].min()
elif yparam=='time':
tseconds = datadf.loc[:,'time']
yaxmax = tseconds.max()
yaxmin = 0
elif yparam == 'workoutid':
yaxmax = datadf[yparam].max()-5
yaxmin = datadf[yparam].min()+5
else:
yaxmax = yaxmaxima[yparam]
yaxmin = yaxminima[yparam]
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam == 'pace':
y_axis_type = 'datetime'
datadf.index.names = ['index']
source = ColumnDataSource(
datadf,
)
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap'
if groupby != 'date':
hover = HoverTool(names=['data'],
tooltips = [
(groupby,'@groupval{1.1}'),
(xparamname,'@x{1.1}'),
(yparamname,'@y')
])
else:
hover = HoverTool(names=['data'],
tooltips = [
(groupby,'@groupval'),
(xparamname,'@x{1.1}'),
(yparamname,'@y')
,
])
hover.mode = 'mouse'
TOOLS = [SaveTool(),PanTool(),BoxZoomTool(),WheelZoomTool(),
ResetTool(),TapTool(),hover]
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
toolbar_location="above",
toolbar_sticky=False,plot_width=920)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.title.text = title
plot.title.text_font_size=value("1.0em")
plot.sizing_mode = 'stretch_both'
plot.image_url([watermarkurl],watermarkx,watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
errorbar(plot,xparam,yparam,source=source,
xerr=ploterrorbars,
yerr=ploterrorbars,
point_kwargs={
'line_color':"#969696",
'size':"groupsize",
'fill_color':"color",
'fill_alpha':1.0,
},
)
for nr, gvalue, color in colorlegend:
box = BoxAnnotation(bottom=75+20*nr,left=50,top=95+20*nr,
right=70,
bottom_units='screen',
top_units='screen',
left_units='screen',
right_units='screen',
fill_color=color,
fill_alpha=1.0,
line_color=color)
legendlabel = Label(x=71,y=78+20*nr,x_units='screen',
y_units='screen',
text = "{gvalue:3.0f}".format(gvalue=gvalue),
background_fill_alpha=1.0,
text_color='black',
text_font_size="0.7em")
plot.add_layout(box)
plot.add_layout(legendlabel)
if colorlegend:
legendlabel = Label(x=322,y=250,x_units='screen',
y_units='screen',
text = 'group legend',
text_color='black',
text_font_size="0.7em",
angle=90,
angle_units='deg')
if xparam == 'workoutid':
plot.xaxis.axis_label = 'Workout'
else:
plot.xaxis.axis_label = axlabels[xparam]
if yparam == 'workoutid':
plot.xaxis.axis_label = 'Workout'
else:
plot.yaxis.axis_label = axlabels[yparam]
binlabel = Label(x=50,y=50,x_units='screen',
y_units='screen',
text="Bin size {binsize:3.1f}".format(binsize=binsize),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black',text_font_size='10pt',
)
slidertext = 'SPM: {:.0f}-{:.0f}, WpS: {:.0f}-{:.0f}'.format(
spmmin,spmmax,workmin,workmax
)
sliderlabel = Label(x=50,y=20,x_units='screen',y_units='screen',
text=slidertext,
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black',text_font_size='10pt',
)
plot.add_layout(binlabel)
plot.add_layout(sliderlabel)
yrange1 = Range1d(start=yaxmin,end=yaxmax)
plot.y_range = yrange1
xrange1 = Range1d(start=xaxmin,end=xaxmax)
plot.x_range = xrange1
if yparam == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
script,div = components(plot)
return [script,div]
def interactive_cum_flex_chart2(theworkouts,promember=0,
xparam='spm',
yparam1='power',
yparam2='spm',
workstrokesonly=False):
# 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=True,
workstrokesonly=workstrokesonly)
try:
tests = datadf[yparam2]
except KeyError:
yparam2 = 'None'
try:
tests = datadf[yparam1]
except KeyError:
yparam1 = 'None'
datadf.dropna(axis=1,how='all',inplace=True)
datadf.dropna(axis=0,how='any',inplace=True)
# test if we have drive energy
nowork = 1
try:
test = datadf['driveenergy'].mean()
nowork = 0
except KeyError:
datadf['driveenergy'] = 500.
# test if we have power
nopower = 1
try:
test = datadf['power'].mean()
nopower = 0
except KeyError:
datadf['power'] = 50.
yparamname1 = axlabels[yparam1]
if yparam2 != 'None':
yparamname2 = axlabels[yparam2]
# check if dataframe not empty
if datadf.empty:
return ['','<p>No non-zero data in selection</p>','','']
try:
datadf['x1'] = datadf.loc[:,xparam]
except KeyError:
try:
datadf['x1'] = datadf['distance']
except KeyError:
try:
datadf['x1'] = datadf['time']
except KeyError:
return ['','<p>No non-zero data in selection</p>','','']
try:
datadf['y1'] = datadf.loc[:,yparam1]
except KeyError:
try:
datadf['y1'] = datadf['pace']
except KeyError:
return ['','<p>No non-zero data in selection</p>','','']
if yparam2 != 'None':
try:
datadf['y2'] = datadf.loc[:,yparam2]
except KeyError:
datadf['y2'] = datadf['y1']
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'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
y1mean = datadf.loc[:,'pace'].mean()
datadf['xname'] = axlabels[xparam]
datadf['yname1'] = axlabels[yparam1]
if yparam2 != 'None':
datadf['yname2'] = axlabels[yparam2]
else:
datadf['yname2'] = axlabels[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,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)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'stretch_both'
plot.image_url([watermarkurl],watermarkx,watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
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=50,y=80,x_units='screen',y_units='screen',
text=axlabels[xparam]+": {x1mean:6.2f}".format(x1mean=x1mean),
background_fill_alpha=.7,
background_fill_color='white',
text_color='green',
)
sliderlabel = Label(x=10,y=470,x_units='screen',y_units='screen',
text='',
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black',text_font_size='10pt',
)
plot.add_layout(x1means)
plot.add_layout(xlabel)
plot.add_layout(y1means)
plot.add_layout(sliderlabel)
y1label = Label(x=50,y=50,x_units='screen',y_units='screen',
text=axlabels[yparam1]+": {y1mean:6.2f}".format(y1mean=y1mean),
background_fill_alpha=.7,
background_fill_color='white',
text_color='blue',
)
if yparam1 != 'time' and yparam1 != 'pace':
plot.add_layout(y1label)
y2label = y1label
plot.circle('x1','y1',source=source2,fill_alpha=0.3,line_color=None,
legend_label=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 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
plot.circle('x1','y2',color="red",y_range_name="yax2",
legend_label=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=50,y=20,x_units='screen',y_units='screen',
text=axlabels[yparam2]+": {y2mean:6.2f}".format(y2mean=y2mean),
background_fill_alpha=.7,
background_fill_color='white',
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,
sliderlabel=sliderlabel,
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 index1 = data['index']
var distance1 = data['distance']
var power1 = data['power']
var driveenergy1 = data['driveenergy']
var xname = data['xname']
var yname1 = data['yname1']
var yname2 = data['yname2']
var workoutid1 = data['workoutid']
var minspm = minspm.value
var maxspm = maxspm.value
var mindist = mindist.value
var maxdist = maxdist.value
var minwork = minwork.value
var maxwork = maxwork.value
sliderlabel.text = 'SPM: '+minspm.toFixed(0)+'-'+maxspm.toFixed(0)
sliderlabel.text += ', Dist: '+mindist.toFixed(0)+'-'+maxdist.toFixed(0)
sliderlabel.text += ', WpS: '+minwork.toFixed(0)+'-'+maxwork.toFixed(0)
var xm = 0
var ym1 = 0
var ym2 = 0
data2['x1'] = []
data2['y1'] = []
data2['y2'] = []
data2['distance'] = []
data2['power'] = []
data2['x1mean'] = []
data2['y1mean'] = []
data2['y2mean'] = []
data2['driveenergy'] = []
data2['workoutid'] = []
data2['xname'] = []
data2['yname1'] = []
data2['yname2'] = []
data2['spm'] = []
for (var 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['driveenergy'].push(driveenergy1[i])
data2['distance'].push(distance1[i])
data2['power'].push(power1[i])
data2['workoutid'].push(0)
data2['xname'].push(0)
data2['yname1'].push(0)
data2['yname2'].push(0)
xm += x1[i]
ym1 += y1[i]
ym2 += y2[i]
}
}
}
}
xm /= data2['x1'].length
ym1 /= data2['x1'].length
ym2 /= data2['x1'].length
for (var i=0; i<data2['x1'].length; i++) {
data2['x1mean'].push(xm)
data2['y1mean'].push(ym1)
data2['y2mean'].push(ym2)
}
x1means.location = xm
y1means.location = ym1
y2means.location = ym2
y1label.text = yname1[0]+': '+(ym1).toFixed(2)
y2label.text = yname2[0]+': '+(ym2).toFixed(2)
xlabel.text = xname[0]+': '+(xm).toFixed(2)
source2.change.emit();
""")
slider_spm_min = Slider(width=140, start=15.0, end=55,value=15.0, step=.1,
title="Min SPM")
slider_spm_min.js_on_change('value',callback)
callback.args["minspm"] = slider_spm_min
slider_spm_max = Slider(width=140, start=15.0, end=55,value=55.0, step=.1,
title="Max SPM")
slider_spm_max.js_on_change('value',callback)
callback.args["maxspm"] = slider_spm_max
slider_work_min = Slider(width=140, start=0.0, end=1500,value=0.0, step=10,
title="Min Work per Stroke")
slider_work_min.js_on_change('value',callback)
callback.args["minwork"] = slider_work_min
slider_work_max = Slider(width=140, start=0.0, end=1500,value=1500.0, step=10,
title="Max Work per Stroke")
slider_work_max.js_on_change('value',callback)
callback.args["maxwork"] = slider_work_max
try:
distmax = 100+100*int(datadf['distance'].max()/100.)
except KeyError:
distmax = 1000.
slider_dist_min = Slider(width=140, start=0,end=distmax,value=0,step=50,
title="Min Distance")
slider_dist_min.js_on_change('value',callback)
callback.args["mindist"] = slider_dist_min
slider_dist_max = Slider(width=140, start=0,end=distmax,value=distmax,
step=50,
title="Max Distance")
slider_dist_max.js_on_change('value',callback)
callback.args["maxdist"] = slider_dist_max
slider_spm_min.sizing_mode = 'fixed'
slider_spm_max.sizing_mode = 'fixed'
slider_work_min.sizing_mode = 'fixed'
slider_work_max.sizing_mode = 'fixed'
slider_dist_min.sizing_mode = 'fixed'
slider_dist_max.sizing_mode = 'fixed'
thesliders = layoutcolumn([slider_spm_min,
slider_spm_max,
slider_dist_min,
slider_dist_max,
slider_work_min,
slider_work_max,
],
)
thesliders.sizing_mode = 'fixed'
layout = layoutrow([thesliders,
plot])
layout.sizing_mode = 'stretch_both'
script, div = components(layout)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
return [script,div,js_resources,css_resources]
def interactive_flexchart_stacked(id,r,xparam='time',
yparam1='pace',
yparam2='power',
yparam3='hr',
yparam4='spm',
mode='erg'):
columns = [xparam,yparam1,yparam2,yparam3,yparam4,
'ftime','distance','fpace',
'power','hr','spm','driveenergy',
'time','pace','workoutstate']
comment = None
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True,
workstrokesonly=False)
if r.usersmooth > 1:
for column in columns:
try:
if metricsdicts[column]['maysmooth']:
nrsteps = int(log2(r.usersmooth))
for i in range(nrsteps):
rowdata[column] = stravastuff.ewmovingaverage(rowdata[column],5)
except KeyError:
pass
if len(rowdata)<2:
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],
doclean=False,
workstrokesonly=False)
row = Workout.objects.get(id=id)
if rowdata.empty:
return "","No valid data",'','',comment
try:
tseconds = rowdata.loc[:,'time']
except KeyError:
return '','No time data - cannot make flex plot','','',comment
try:
rowdata['x1'] = rowdata.loc[:,xparam]
rowmin = rowdata[xparam].min()
except KeyError:
rowdata['x1'] = 0*rowdata.loc[:,'time']
try:
rowdata['y1'] = rowdata.loc[:,yparam1]
rowmin = rowdata[yparam1].min()
except KeyError:
rowdata['y1'] = 0*rowdata.loc[:,'time']
rowdata[yparam1] = rowdata['y1']
try:
rowdata['y2'] = rowdata.loc[:,yparam2]
rowmin = rowdata[yparam2].min()
except KeyError:
rowdata['y2'] = 0*rowdata.loc[:,'time']
rowdata[yparam2] = rowdata['y2']
try:
rowdata['y3'] = rowdata.loc[:,yparam3]
rowmin = rowdata[yparam3].min()
except KeyError:
rowdata['y3'] = 0*rowdata.loc[:,'time']
rowdata[yparam3] = rowdata['y3']
try:
rowdata['y4'] = rowdata.loc[:,yparam4]
rowmin = rowdata[yparam4].min()
except KeyError:
rowdata['y4'] = 0*rowdata.loc[:,'time']
rowdata[yparam4] = rowdata['y4']
if xparam=='time':
xaxmax = tseconds.max()
xaxmin = tseconds.min()
elif xparam=='distance' or xparam=='cumdist':
xaxmax = rowdata['x1'].max()
xaxmin = rowdata['x1'].min()
else:
try:
xaxmax = get_yaxmaxima(r,xparam,mode)
xaxmin = get_yaxminima(r,xparam,mode)
except KeyError:
xaxmax = rowdata['x1'].max()
xaxmin = rowdata['x1'].min()
x_axis_type = 'linear'
y1_axis_type = 'linear'
y2_axis_type = 'linear'
y3_axis_type = 'linear'
y4_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y1_axis_type = 'datetime'
if yparam2 == 'pace':
y2_axis_type = 'datetime'
if yparam3 == 'pace':
y3_axis_type = 'datetime'
if yparam4 == 'pace':
y4_axis_type = 'datetime'
try:
rowdata['xname'] = axlabels[xparam]
except KeyError:
rowdata['xname'] = xparam
try:
rowdata['yname1'] = axlabels[yparam1]
except KeyError:
rowdata['yname1'] = yparam1
try:
rowdata['yname2'] = axlabels[yparam2]
except KeyError:
rowdata['yname2'] = yparam2
try:
rowdata['yname3'] = axlabels[yparam3]
except KeyError:
rowdata['yname3'] = yparam3
try:
rowdata['yname4'] = axlabels[yparam4]
except KeyError:
rowdata['yname4'] = yparam4
# prepare data
source = ColumnDataSource(
rowdata
)
TOOLS = 'box_zoom,wheel_zoom,reset,tap,hover'
TOOLS2 = 'box_zoom,hover'
plot1 = Figure(x_axis_type=x_axis_type,y_axis_type=y1_axis_type,plot_width=920,plot_height=150,
tools=TOOLS,toolbar_location='above')
plot2 = Figure(x_axis_type=x_axis_type,y_axis_type=y2_axis_type,plot_width=920,plot_height=150,
tools=TOOLS2,toolbar_location=None)
plot3 = Figure(x_axis_type=x_axis_type,y_axis_type=y3_axis_type,plot_width=920,plot_height=150,
tools=TOOLS2,toolbar_location=None)
plot4 = Figure(x_axis_type=x_axis_type,y_axis_type=y4_axis_type,plot_width=920,plot_height=150,
tools=TOOLS2,toolbar_location=None)
plot1.xaxis.visible=False
plot2.xaxis.visible=False
plot3.xaxis.visible=False
plot1.sizing_mode = 'stretch_both'
plot2.sizing_mode = 'stretch_both'
plot3.sizing_mode = 'stretch_both'
plot4.sizing_mode = 'stretch_both'
linked_crosshair = CrosshairTool(dimensions="height")
plot1.add_tools(linked_crosshair)
plot2.add_tools(linked_crosshair)
plot3.add_tools(linked_crosshair)
plot4.add_tools(linked_crosshair)
try:
xaxlabel = axlabels[xparam]
except KeyError:
xaxlabel = xparam
try:
yax1label = axlabels[yparam1]
except KeyError:
yax1label = yparam1
plot1.yaxis.axis_label = yax1label
try:
xaxlabel = axlabels[xparam]
except KeyError:
xaxlabel = xparam
try:
yax2label = axlabels[yparam2]
except KeyError:
yax2label = yparam2
plot2.yaxis.axis_label = yax2label
try:
xaxlabel = axlabels[xparam]
except KeyError:
xaxlabel = xparam
try:
yax3label = axlabels[yparam3]
except KeyError:
yax3label = yparam3
plot3.yaxis.axis_label = yax3label
try:
xaxlabel = axlabels[xparam]
except KeyError:
xaxlabel = xparam
try:
yax4label = axlabels[yparam4]
except KeyError:
yax4label = yparam4
try:
xaxlabel = axlabels[xparam]
except KeyError:
xaxlabel = xparam
plot4.yaxis.axis_label = yax4label
plot4.xaxis.axis_label = xaxlabel
xrange1 = Range1d(start=xaxmin,end=xaxmax)
plot1.x_range = xrange1
plot2.x_range = xrange1
plot3.x_range = xrange1
plot4.x_range = xrange1
if xparam == 'time':
plot4.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
hover1 = plot1.select(dict(type=HoverTool))
hover2 = plot2.select(dict(type=HoverTool))
hover3 = plot3.select(dict(type=HoverTool))
hover4 = plot4.select(dict(type=HoverTool))
if yparam1 == 'pace':
y1tooltip = '@fpace'
elif yparam1 != 'None':
y1tooltip = '@{yparam1}'.format(yparam1=yparam1)
if metricsdicts[yparam1]['numtype'] == 'integer' or yparam1 == 'power':
y1tooltip+='{int}'
else:
y1tooltip+='{0.00}'
else:
y1tooltip = ''
comment = 'The metric in the first chart is only accessible with a Pro plan or higher'
if yparam2 == 'pace':
y2tooltip = '@fpace'
elif yparam2 != 'None':
y2tooltip = '@{yparam2}'.format(yparam2=yparam2)
if metricsdicts[yparam2]['numtype'] == 'integer' or yparam2 == 'power':
y2tooltip+='{int}'
else:
y2tooltip+='{0.00}'
else:
y2tooltip = ''
comment = 'The metric in the second chart is only accessible with a Pro plan or higher'
if yparam3 == 'pace':
y3tooltip = '@fpace'
elif yparam3 != 'None':
y3tooltip = '@{yparam3}'.format(yparam3=yparam3)
if metricsdicts[yparam3]['numtype'] == 'integer' or yparam3 == 'power':
y3tooltip+='{int}'
else:
y3tooltip+='{0.00}'
else:
y3tooltip = ''
comment = 'The metric in the third chart is only accessible with a Pro plan or higher'
if yparam4 == 'pace':
y4tooltip = '@fpace'
elif yparam4 != 'None':
y4tooltip = '@{yparam4}'.format(yparam4=yparam4)
if metricsdicts[yparam4]['numtype'] == 'integer' or yparam4 == 'power':
y4tooltip+='{int}'
else:
y4tooltip+='{0.00}'
else:
y4tooltip = ''
comment = 'The metric in the fourth chart is only accessible with a Pro plan or higher'
if yparam1 != 'None':
hover1.tooltips = OrderedDict([
('Time','@ftime'),
('Distance','@distance{int}'),
(axlabels[yparam1],y1tooltip),
(axlabels[yparam2],y2tooltip),
(axlabels[yparam3],y3tooltip),
(axlabels[yparam4],y4tooltip),
])
if yparam2 != 'None':
hover2.tooltips = OrderedDict([
('Time','@ftime'),
('Distance','@distance{int}'),
(axlabels[yparam1],y1tooltip),
(axlabels[yparam2],y2tooltip),
(axlabels[yparam3],y3tooltip),
(axlabels[yparam4],y4tooltip),
])
if yparam3 != 'None':
hover3.tooltips = OrderedDict([
('Time','@ftime'),
('Distance','@distance{int}'),
(axlabels[yparam1],y1tooltip),
(axlabels[yparam2],y2tooltip),
(axlabels[yparam3],y3tooltip),
(axlabels[yparam4],y4tooltip),
])
if yparam4 != 'None':
hover4.tooltips = OrderedDict([
('Time','@ftime'),
('Distance','@distance{int}'),
(axlabels[yparam1],y1tooltip),
(axlabels[yparam2],y2tooltip),
(axlabels[yparam3],y3tooltip),
(axlabels[yparam4],y4tooltip),
])
hover1.mode = 'vline'
hover2.mode = 'vline'
hover3.mode = 'vline'
hover4.mode = 'vline'
y1min = get_yaxminima(r,yparam1,mode)
y2min = get_yaxminima(r,yparam2,mode)
y3min = get_yaxminima(r,yparam3,mode)
y4min = get_yaxminima(r,yparam4,mode)
y1max = get_yaxmaxima(r,yparam1,mode)
y2max = get_yaxmaxima(r,yparam2,mode)
y3max = get_yaxmaxima(r,yparam3,mode)
y4max = get_yaxmaxima(r,yparam4,mode)
plot1.y_range = Range1d(start=y1min,end=y1max)
plot2.y_range = Range1d(start=y2min,end=y2max)
plot3.y_range = Range1d(start=y3min,end=y3max)
plot4.y_range = Range1d(start=y4min,end=y4max)
if yparam1 == 'pace':
plot1.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
plot1.y_range = Range1d(y1min,y1max)
if yparam2 == 'pace':
plot2.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
plot2.y_range = Range1d(y2min,y2max)
if yparam3 == 'pace':
plot3.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
plot3.y_range = Range1d(y3min,y3max)
if yparam4 == 'pace':
plot4.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
plot4.y_range = Range1d(y4min,y4max)
plot1.line('x1','y1',source=source,color=palette2[1])
plot2.line('x1','y2',source=source,color=palette2[3])
plot3.line('x1','y3',source=source,color=palette2[0])
plot4.line('x1','y4',source=source,color=palette2[2])
layout = layoutcolumn([
plot1,
plot2,
plot3,
plot4,
])
layout.sizing_mode = 'stretch_both'
script, div = components(layout)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
return script,div,js_resources,css_resources,comment
def interactive_flex_chart2(id,r,promember=0,
xparam='time',
yparam1='pace',
yparam2='hr',
plottype='line',
workstrokesonly=False,
mode='rower'):
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
#rowdata,row = dataprep.getrowdata_db(id=id)
columns = [xparam,yparam1,yparam2,
'ftime','distance','fpace',
'power','hr','spm','driveenergy',
'time','pace','workoutstate']
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True,
workstrokesonly=workstrokesonly)
if r.usersmooth > 1:
for column in columns:
try:
if metricsdicts[column]['maysmooth']:
nrsteps = int(log2(r.usersmooth))
for i in range(nrsteps):
rowdata[column] = stravastuff.ewmovingaverage(rowdata[column],5)
except KeyError:
pass
if len(rowdata)<2:
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True,
workstrokesonly=False)
workstrokesonly=False
if len(rowdata)<2:
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],
doclean=False,
workstrokesonly=False)
workstrokesonly=False
try:
tests = rowdata[yparam2]
except KeyError:
yparam2 = 'None'
try:
tests = rowdata[yparam1]
except KeyError:
yparam1 = 'None'
# test if we have drive energy
nowork = 1
try:
test = rowdata['driveenergy'].mean()
nowork = 0
except KeyError:
rowdata['driveenergy'] = 500.
# test if we have power
nopower = 1
try:
test = rowdata['power'].mean()
nopower = 0
except KeyError:
rowdata['power'] = 50.
# replace nans
rowdata.fillna(value=0,inplace=True)
row = Workout.objects.get(id=id)
if rowdata.empty:
return "","No valid data",'','',workstrokesonly
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:
tseconds = rowdata.loc[:,'time']
except KeyError:
return '','No time data - cannot make flex plot','','',workstrokesonly
try:
rowdata['x1'] = rowdata.loc[:,xparam]
rowmin = rowdata[xparam].min()
except KeyError:
rowdata['x1'] = 0*rowdata.loc[:,'time']
try:
rowdata['y1'] = rowdata.loc[:,yparam1]
rowmin = rowdata[yparam1].min()
except KeyError:
rowdata['y1'] = 0*rowdata.loc[:,'time']
rowdata[yparam1] = rowdata['y1']
if yparam2 != 'None':
try:
rowdata['y2'] = rowdata.loc[:,yparam2]
rowmin = rowdata[yparam2].min()
except KeyError:
rowdata['y2'] = 0*rowdata.loc[:,'time']
rowdata[yparam2] = rowdata['y2']
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:
try:
xaxmax = get_yaxmaxima(r,xparam,mode)
xaxmin = get_yaxminima(r,xparam,mode)
except KeyError:
xaxmax = rowdata['x1'].max()
xaxmin = rowdata['x1'].min()
# 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'
try:
y1mean = rowdata.loc[:,'pace'].mean()
except KeyError:
y1mean = 0
try:
rowdata['xname'] = axlabels[xparam]
except KeyError:
rowdata['xname'] = xparam
try:
rowdata['yname1'] = axlabels[yparam1]
except KeyError:
rowdata['yname1'] = yparam1
if yparam2 != 'None':
try:
rowdata['yname2'] = axlabels[yparam2]
except KeyError:
rowdata['yname2'] = yparam2
else:
rowdata['yname2'] = rowdata['yname1']
# 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,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,plot_width=800,plot_height=600,
)
plot.sizing_mode = 'stretch_both'
#plot.width_policy = 'max'
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'stretch_both'
plot.image_url([watermarkurl],watermarkx,watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
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
try:
xlabeltext = axlabels[xparam]+": {x1mean:6.2f}".format(
x1mean=x1mean
)
except KeyError:
xlabeltext = xparam+": {x1mean:6.2f}".format(x1mean=x1mean)
xlabel = Label(x=50,y=80,x_units='screen',y_units='screen',
text=xlabeltext,
background_fill_alpha=.7,
background_fill_color='white',
text_color='green',
)
annolabel = Label(x=50,y=450,x_units='screen',y_units='screen',
text='',
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black',
)
sliderlabel = Label(x=10,y=470,x_units='screen',y_units='screen',
text='',
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black',text_font_size='10pt',
)
if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
plot.add_layout(x1means)
plot.add_layout(xlabel)
plot.add_layout(y1means)
plot.add_layout(annolabel)
plot.add_layout(sliderlabel)
try:
yaxlabel = axlabels[yparam1]
except KeyError:
yaxlabel = str(yparam1)+' '
try:
xaxlabel = axlabels[xparam]
except KeyError:
xaxlabel = xparam
y1label = Label(x=50,y=50,x_units='screen',y_units='screen',
text=yaxlabel+": {y1mean:6.2f}".format(y1mean=y1mean),
background_fill_alpha=.7,
background_fill_color='white',
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_label="Constant Power")
if plottype=='line':
plot.line('x1','y1',source=source2,legend_label=yaxlabel)
elif plottype=='scatter':
plot.scatter('x1','y1',source=source2,legend_label=yaxlabel,fill_alpha=0.4,
line_color=None)
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.sizing_mode = 'stretch_both'
plot.xaxis.axis_label = xaxlabel
plot.yaxis.axis_label = yaxlabel
try:
yrange1 = Range1d(start=get_yaxminima(r,yparam1,mode),
end=get_yaxmaxima(r,yparam1,mode))
except KeyError:
yrange1 = Range1d(start=rowdata[yparam1].min(),
end=rowdata[yparam1].max())
plot.y_range = yrange1
if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
try:
xrange1 = Range1d(start=get_yaxminima(r,xparam,mode),
end=get_yaxmaxima(r,xparam,mode))
except KeyError:
xrange1 = Range1d(start=rowdata[xparam].min(),
end=rowdata[xparam].max())
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':
try:
yrange2 = Range1d(start=get_yaxminima(r,yparam2,mode),
end=get_yaxmaxima(r,yparam2,mode))
except KeyError:
yrange2 = Range1d(start=rowdata[yparam2].min(),
end=rowdata[yparam2].max())
plot.extra_y_ranges["yax2"] = yrange2
#= {"yax2": yrange2}
try:
axlegend = axlabels[yparam2]
except KeyError:
axlegend = str(yparam2)+' '
if plottype=='line':
plot.line('x1','y2',color="red",y_range_name="yax2",
legend_label=axlegend,
source=source2)
elif plottype=='scatter':
plot.scatter('x1','y2',source=source2,legend_label=axlegend,
fill_alpha=0.4,
line_color=None,color="red",y_range_name="yax2")
plot.add_layout(LinearAxis(y_range_name="yax2",
axis_label=axlegend),'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=50,y=20,x_units='screen',y_units='screen',
text=axlegend+": {y2mean:6.2f}".format(y2mean=y2mean),
background_fill_alpha=.7,
background_fill_color='white',
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,
annolabel=annolabel,
sliderlabel=sliderlabel,
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 ftime1 = data['ftime']
var pace1 = data['pace']
var hr1 = data['hr']
var fpace1 = data['fpace']
var distance1 = data['distance']
var power1 = data['power']
var driveenergy1 = data['driveenergy']
var xname = data['xname']
var yname1 = data['yname1']
var yname2 = data['yname2']
var workoutid1 = data['workoutid']
var workoutstate1 = data['workoutstate']
var annotation = annotation.value
var minspm = minspm.value
var maxspm = maxspm.value
var mindist = mindist.value
var maxdist = maxdist.value
var minwork = minwork.value
var maxwork = maxwork.value
sliderlabel.text = 'SPM: '+minspm.toFixed(0)+'-'+maxspm.toFixed(0)
sliderlabel.text += ', Dist: '+mindist.toFixed(0)+'-'+maxdist.toFixed(0)
sliderlabel.text += ', WpS: '+minwork.toFixed(0)+'-'+maxwork.toFixed(0)
var xm = 0
var ym1 = 0
var ym2 = 0
data2['x1'] = []
data2['y1'] = []
data2['y2'] = []
data2['spm'] = []
data2['time'] = []
data2['ftime'] = []
data2['pace'] = []
data2['hr'] = []
data2['fpace'] = []
data2['distance'] = []
data2['power'] = []
data2['x1mean'] = []
data2['y1mean'] = []
data2['y2mean'] = []
data2['driveenergy'] = []
data2['workoutid'] = []
data2['workoutstate'] = []
data2['xname'] = []
data2['yname1'] = []
data2['yname2'] = []
for (var 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['ftime'].push(ftime1[i])
data2['fpace'].push(fpace1[i])
data2['driveenergy'].push(driveenergy1[i])
data2['pace'].push(pace1[i])
data2['hr'].push(hr1[i])
data2['distance'].push(distance1[i])
data2['power'].push(power1[i])
data2['workoutid'].push(0)
data2['workoutstate'].push(0)
data2['xname'].push(0)
data2['yname1'].push(0)
data2['yname2'].push(0)
xm += x1[i]
ym1 += y1[i]
ym2 += y2[i]
}
}
}
}
xm /= data2['x1'].length
ym1 /= data2['x1'].length
ym2 /= data2['x1'].length
for (var i=0; i<data2['x1'].length; i++) {
data2['x1mean'].push(xm)
data2['y1mean'].push(ym1)
data2['y2mean'].push(ym2)
}
x1means.location = xm
y1means.location = ym1
y2means.location = ym2
y1label.text = yname1[0]+': '+ym1.toFixed(2)
y2label.text = yname2[0]+': '+ym2.toFixed(2)
xlabel.text = xname[0]+': '+xm.toFixed(2)
annolabel.text = annotation
source2.change.emit();
""")
annotation = TextInput(width=140, title="Type your plot notes here", value="")
annotation.js_on_change('value',callback)
callback.args["annotation"] = annotation
slider_spm_min = Slider(width=140, start=15.0, end=55,value=15.0, step=.1,
title="Min SPM")
slider_spm_min.js_on_change('value',callback)
callback.args["minspm"] = slider_spm_min
slider_spm_max = Slider(width=140, start=15.0, end=55,value=55.0, step=.1,
title="Max SPM")
slider_spm_max.js_on_change('value',callback)
callback.args["maxspm"] = slider_spm_max
slider_work_min = Slider(width=140, start=0.0, end=1500,value=0.0, step=10,
title="Min Work per Stroke")
slider_work_min.js_on_change('value',callback)
callback.args["minwork"] = slider_work_min
slider_work_max = Slider(width=140, start=0.0, end=1500,value=1500.0, step=10,
title="Max Work per Stroke")
slider_work_max.js_on_change('value',callback)
callback.args["maxwork"] = slider_work_max
try:
distmax = 100+100*int(rowdata['distance'].max()/100.)
except (KeyError,ValueError):
distmax = 100
slider_dist_min = Slider(width=140, start=0,end=distmax,value=0,step=50,
title="Min Distance")
slider_dist_min.js_on_change('value',callback)
callback.args["mindist"] = slider_dist_min
slider_dist_max = Slider(width=140, start=0,end=distmax,value=distmax,
step=50,
title="Max Distance")
slider_dist_max.js_on_change('value',callback)
callback.args["maxdist"] = slider_dist_max
annotation.sizing_mode = 'fixed'
slider_spm_min.sizing_mode = 'fixed'
slider_spm_max.sizing_mode = 'fixed'
slider_work_min.sizing_mode = 'fixed'
slider_work_max.sizing_mode = 'fixed'
slider_dist_min.sizing_mode = 'fixed'
slider_dist_max.sizing_mode = 'fixed'
thesliders = layoutcolumn([
annotation,
slider_spm_min,
slider_spm_max,
slider_dist_min,
slider_dist_max,
slider_work_min,
slider_work_max,
])
thesliders.sizing_mode = 'fixed'
layout = layoutrow([thesliders,
plot])
# layout.sizing_mode = 'stretch_both'
layout.sizing_mode = 'stretch_both'
script, div = components(layout)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
return [script,div,js_resources,css_resources,workstrokesonly]
def thumbnails_set(r,id,favorites):
charts = []
columns = [f.xparam for f in favorites]
columns += [f.yparam1 for f in favorites]
columns += [f.yparam2 for f in favorites]
columns += ['time']
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True)
rowdata.dropna(axis=1,how='all',inplace=True)
if rowdata.empty:
try:
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=False,
workstrokesonly=False)
except:
return [
{'script':"",
'div':"",
'notes':""
}]
if rowdata.empty:
return [
{'script':"",
'div':"",
'notes':""
}]
# else:
# try:
# rowdata.sort_values(by='time',ascending=True,inplace=True)
# except KeyError:
# pass
l = len(rowdata)
maxlength = 50
if l > maxlength:
try:
bins = np.linspace(rowdata['time'].min(),rowdata['time'].max(),maxlength)
groups = rowdata.groupby(np.digitize(rowdata['time'],bins))
rowdata = groups.mean()
except KeyError:
pass
for f in favorites:
workstrokesonly = not f.reststrokes
script,div = thumbnail_flex_chart(
rowdata,
id=id,
xparam=f.xparam,
yparam1=f.yparam1,
yparam2=f.yparam2,
plottype=f.plottype,
)
charts.append({
'script':script,
'div':div,
'notes':f.notes})
return charts
def thumbnail_flex_chart(rowdata,id=0,promember=0,
xparam='time',
yparam1='pace',
yparam2='hr',
plottype='line',
workstrokesonly=False):
try:
tests = rowdata[yparam2]
except KeyError:
yparam2 = 'None'
try:
tests = rowdata[yparam1]
except KeyError:
yparam1 = 'None'
try:
tseconds = rowdata.loc[:,'time']
except KeyError:
return '','No time data - cannot make flex plot'
try:
rowdata['x1'] = rowdata.loc[:,xparam]
except KeyError:
rowdata['x1'] = 0*rowdata.loc[:,'time']
try:
rowdata['y1'] = rowdata.loc[:,yparam1]
except KeyError:
rowdata['y1'] = 0*rowdata.loc[:,'time']
if yparam2 != 'None':
try:
rowdata['y2'] = rowdata.loc[:,yparam2]
except KeyError:
rowdata['y2'] = 0*rowdata.loc[:,'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]
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
y1mean = rowdata.loc[:,'pace'].mean()
rowdata['xname'] = axlabels[xparam]
try:
rowdata['yname1'] = axlabels[yparam1]
except KeyError:
rowdata['yname1'] = axlabels[xparam]
if yparam2 != 'None':
rowdata['yname2'] = axlabels[yparam2]
else:
rowdata['yname2'] = axlabels[yparam1]
# prepare data
source = ColumnDataSource(
rowdata
)
sizing_mode = 'fixed' # 'stretch_both' also looks nice with this example
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
plot_width=200,plot_height=150,
)
# plot.sizing_mode = 'stretch_both'
plot.sizing_mode = 'fixed'
plot.toolbar.logo = None
plot.toolbar_location = None
#plot.yaxis.visible = False
plot.xaxis.axis_label_text_font_size = "7pt"
plot.yaxis.axis_label_text_font_size = "7pt"
plot.xaxis.major_label_text_font_size = "7pt"
plot.yaxis.major_label_text_font_size = "7pt"
if plottype=='line':
plot.line('x1','y1',source=source)
elif plottype=='scatter':
plot.scatter('x1','y1',source=source,fill_alpha=0.4,
line_color=None)
try:
plot.xaxis.axis_label = axlabels[xparam]
except KeyError:
plot.xaxis.axis_label = 'X'
try:
plot.yaxis.axis_label = axlabels[yparam1]
except KeyError:
plot.yaxis.axis_label = 'Y'
try:
yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
except KeyError:
yrange1 = Range1d(start=yparam1.min(), end=yparam1.max())
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
#= {"yax2": yrange2}
if plottype=='line':
plot.line('x1','y2',color="red",y_range_name="yax2",
source=source)
elif plottype=='scatter':
plot.scatter('x1','y2',source=source,
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],
major_label_text_font_size="7pt",
axis_label_text_font_size="7pt",
),'right',
)
script, div = components(plot)
return [script,div]
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,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)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'stretch_both'
plot.image_url([watermarkurl],0.01,0.99,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor='top_left',
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
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_label="<UT2")
plot.quad(left='time',top='hr_ut1',bottom='hr_bottom',
right='x_right',source=source,color="tan",
y_range_name="hr", legend_label="UT2")
plot.quad(left='time',top='hr_at',bottom='hr_bottom',
right='x_right',source=source,color="green",
y_range_name="hr", legend_label="UT1")
plot.quad(left='time',top='hr_tr',bottom='hr_bottom',
right='x_right',source=source,color="blue",
y_range_name="hr", legend_label="AT")
plot.quad(left='time',top='hr_an',bottom='hr_bottom',
right='x_right',source=source,color="violet",
y_range_name="hr", legend_label="TR")
plot.quad(left='time',top='hr_max',bottom='hr_bottom',
right='x_right',source=source,color="red",
y_range_name="hr", legend_label="AN")
plot.add_layout(LinearAxis(y_range_name="hr",axis_label="HR"),'right')
plot.line('time','pace',source=source,legend_label="Pace",color="black")
script, div = components(plot)
return [script,div]
def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line',
promember=0,workstrokesonly=True,
labeldict=None,startenddict={}):
message = ''
errormessage = ''
columns = [xparam,yparam,
'ftime','distance','fpace',
'power','hr','spm',
'time','pace','workoutstate',
'workoutid']
compute = False
doclean = False
if workstrokesonly:
compute = True
doclean = True
datadf = dataprep.getsmallrowdata_db(columns,ids=ids,doclean=doclean,compute=compute,
workstrokesonly=workstrokesonly)
datadf.dropna(axis=1,how='all',inplace=True)
datadf.dropna(axis=0,how='any',inplace=True)
nrworkouts = len(ids)
try:
tseconds = datadf.loc[:,'time']
except KeyError:
try:
tseconds = datadf.loc[:,xparam]
except:
return ['','<p>A chart data error occurred</p>','','A chart data error occurred']
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>','','No non-zero data in selection']
if xparam != 'distance' and xparam != 'time' and xparam != 'cumdist':
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
elif xparam == 'time' and not startenddict:
xaxmax = tseconds.max()
xaxmin = tseconds.min()
elif xparam == 'time' and startenddict:
deltas = [pair[1]-pair[0] for key,pair in startenddict.items()]
xaxmin = 0
xaxmax = pd.Series(deltas).max()*1000.
if xaxmax == 0:
xaxmax = tseconds.max()
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,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,plot_height=500,
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'stretch_both'
plot.image_url([watermarkurl],0.05,0.9,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor='top_left',
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
colors = itertools.cycle(palette)
cntr = 0
l1 = []
try:
items = itertools.izip(ids,colors)
except AttributeError:
items = zip(ids,colors)
for id,color in items:
group = datadf[datadf['workoutid']==int(id)].copy()
try:
startsecond,endsecond = startenddict[id]
except KeyError:
startsecond = 0
endsecond = 0
group.sort_values(by='time',ascending=True,inplace=True)
if endsecond > 0:
group['time'] = group['time'] - 1.e3*startsecond
mask = group['time'] < 0
group.mask(mask,inplace=True)
mask = group['time'] > 1.e3*(endsecond-startsecond)
group.mask(mask,inplace=True)
if xparam == 'cumdist':
group['cumdist'] = group['cumdist'] - group['cumdist'].min()
res = make_cumvalues(group[xparam])
group[xparam] = res[0]
elif xparam == 'distance':
group['distance'] = group['distance'] - group['distance'].min()
try:
group['x'] = group[xparam]
except KeyError:
group['x'] = group['time']
errormessage = xparam+' has no values. Plot invalid'
try:
group['y'] = group[yparam]
except KeyError:
group['y'] = 0.0*group['x']
ymean = group['y'].mean()
f = group['time'].diff().mean()
if f != 0 and not np.isnan(f):
windowsize = 2* (int(20000./(f))) + 1
else:
windowsize = 1
if windowsize > 3 and windowsize < len(group['y']):
try:
group['y'] = savgol_filter(group['y'],windowsize,3)
except ValueError:
pass
ylabel = Label(x=100,y=60+nrworkouts*20-20*cntr,
x_units='screen',y_units='screen',
text=axlabels[yparam]+": {ymean:6.2f}".format(ymean=ymean),
background_fill_alpha=.7,
background_fill_color='white',
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:
try:
legend_label=labeldict[id]
except KeyError:
legend = str(id)
else:
legend_label=str(id)
if plottype=='line':
l1.append(plot.line('x','y',source=source,color=color,legend_label=legend_label,line_width=2))
else:
l1.append(plot.scatter('x','y',source=source,color=color,legend_label=legend_label,
fill_alpha=0.4,line_color=None))
plot.add_tools(HoverTool(renderers=[l1[cntr]],tooltips=TIPS))
cntr += 1
plot.legend.location='top_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,message,errormessage]
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,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)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_both'
plot.image_url([watermarkurl],watermarkx,watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
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_label="Pace",color="black")
plot.line('time','nowindpace',source=source,legend_label="Corrected Pace",color="red")
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Pace','@fpace'),
('Corrected Pace','@fnowindpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
])
hover.mode = 'mouse'
try:
script, div = components(plot)
except:
script = ''
div = ''
return [script,div]