Private
Public Access
1
0
Files
rowsandall/rowers/interactiveplots.py
2021-10-25 20:37:54 +02:00

7154 lines
215 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,VirtualRaceResult
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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,strfdelta
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
hrzones = rower.hrzones
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}'.format(ut2=hrzones[1]):frac_lut2,
'{ut2}'.format(ut2=hrzones[1]): frac_ut2,
'{ut1}'.format(ut1=hrzones[2]): frac_ut1,
'{at}'.format(at=hrzones[3]): frac_at,
'{tr}'.format(tr=hrzones[4]): frac_tr,
'{an}'.format(an=hrzones[5]): 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}'.format(ut2=hrzones[1]),
'{ut2}'.format(ut2=hrzones[1]),
'{ut1}'.format(ut1=hrzones[2]),
'{at}'.format(at=hrzones[3]),
'{tr}'.format(tr=hrzones[4]),
'{an}'.format(an=hrzones[5])
]
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
return '','It looks like there are no data matching your filter'
columns = datadf.columns
if not fieldname in columns: # pragma: no cover
return '','It looks like there are no data matching your filter'
if not 'date' in columns: # pragma: no cover
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: # pragma: no cover
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': # pragma: no cover
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: # pragma: no cover
yaxmaximum = data['planned'].max()
if yaxmaximum == 0: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
rscore = w.hrtss
if totaldays<30:
dates.append(dd)
dates_sorting.append(dd2)
else: # pragma: no cover
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: # pragma: no cover
rowers.append(str(w.user))
try:
d = utc.localize(startdate)
except (ValueError,AttributeError): # pragma: no cover
d = startdate
try:
enddate = utc.localize(enddate)
except (ValueError,AttributeError): # pragma: no cover
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: # pragma: no cover
dates.append(d.strftime('%Y/%m'))
dates_sorting.append(d.strftime('%Y/%m'))
durations.append(0)
rscores.append(0)
trimps.append(0)
links.append('')
try:
types.append(types[0])
except IndexError:
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: # pragma: no cover
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: # pragma: no cover
rscore = w.hrtss
if totaldays<=30: # pragma: no cover
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: # pragma: no cover
rowers.append(str(w.user))
try:
d = utc.localize(startdate)
except (ValueError,AttributeError): # pragma: no cover
d = startdate
try:
enddate = utc.localize(enddate)
except (ValueError,AttributeError): # pragma: no cover
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)
if totaldays>30 and yaxis=='duration': # pragma: no cover
df['duration'] = df['duration']/60
elif yaxis == 'TRIMP':
df.drop('duration',inplace=True,axis='columns')
df.drop('rscore',inplace=True,axis='columns')
elif yaxis == 'rScore': # pragma: no cover
df.drop('duration',inplace=True,axis='columns')
df.drop('trimp',inplace=True,axis='columns' )
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')])
types_order = mytypes.workouttypes_ordered
#bars=table.to.bars(['date',stack],[yaxis])
bars = hv.Bars(df, kdims=['date',stack]).aggregate(function=np.sum).redim.values(types=types_order)
#print(mytypes.color_map)
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.xaxis.axis_label = 'Period'
if yaxis == 'duration':
p.yaxis.axis_label = 'Duration (min)'
if totaldays>30: # pragma: no cover
p.yaxis.axis_label = 'Duration (h)'
elif yaxis == 'TRIMP':
p.yaxis.axis_label = 'TRIMP'
else: # pragma: no cover
p.yaxis.axis_label = 'rScore'
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
peakforceav = 0
peakforce25 = 0
peakforce75 = 0
peakforce05 = 0
peakforce95 = 0
try:
averageforceav = rowdata['averageforce'].median()
except KeyError: # pragma: no cover
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: # pragma: no cover
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': # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
weight+= w.hrtss
else:
trimp,hrtss = dataprep.workout_trimp(w)
rscore,normp = dataprep.workout_rscore(w)
if w.rpe and w.rpe > 0: # pragma: no cover
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-datetime.timedelta(days=90),
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-datetime.timedelta(days=90),
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': # pragma: no cover
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
mask = df['date'] > np.datetime64(startdate)
df = df.loc[mask]
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': # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
plot.line('date','fatigue',source=source,color='red',
legend_label=fatiguelabel)
if doform: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
return "","No valid data available"
# throw out nans
histopwr = histopwr[~np.isinf(histopwr)]
if histoparam == 'catch': # pragma: no cover
histopwr = histopwr[histopwr < yaxminima[histoparam]]
histopwr = histopwr[histopwr > yaxmaxima[histoparam]]
else:
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: # pragma: no cover
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 get_map_script_course(
latmean,
lonmean,
latbegin,
latend,
longbegin,
longend,
scoordinates,
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: [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 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}
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,
pcoordinates=pcoordinates,
plabels=plabels
)
return script
def get_map_script(
latmean,
lonmean,
latbegin,
latend,
longbegin,
longend,
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,
)
return script
def leaflet_chart(lat,lon,name="",raceresult=0):
if lat.empty or lon.empty: # pragma: no cover
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: # pragma: no cover
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 += "]"
if raceresult == 0:
script = get_map_script(
latmean,
lonmean,
latbegin,
latend,
longbegin,
longend,
scoordinates,
)
else:
record = VirtualRaceResult.objects.get(id=raceresult)
course = record.course
script = get_map_script_course(
latmean,
lonmean,
latbegin,
latend,
longbegin,
longend,
scoordinates,
course,
)
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): # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
startsecond = 0
endsecond = 0
try:
label = labeldict[id]
except KeyError: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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): # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
pass
flduration = []
flpower = []
for distance in distances:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='female',
distance=distance,
weightcategory='lwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try: # pragma: no cover
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: # pragma: no cover
pass
mlduration = []
mlpower = []
for distance in distances:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='male',
distance=distance,
weightcategory='lwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try: # pragma: no cover
duration = distance/velo
mlduration.append(duration)
mlpower.append(worldclasspower)
except ZeroDivisionError:
mlduration.append(duration)
mlpower.append(np.nan)
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: # pragma: no cover
mlduration.append(60.*duration)
mlpower.append(np.nan)
mhduration = []
mhpower = []
for distance in distances:
worldclasspower = c2stuff.getagegrouprecord(
age,
sex='male',
distance=distance,
weightcategory='hwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try: # pragma: no cover
duration = distance/velo
mhduration.append(duration)
mhpower.append(worldclasspower)
except ZeroDivisionError:
mhduration.append(duration)
mhpower.append(np.nan)
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: # pragma: no cover
mhduration.append(60.*duration)
mhpower.append(np.nan)
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: # pragma: no cover
p1fh = None
# fitting WC data to three parameter CP model
if len(flduration)>=4:
p1fl, success = optimize.leastsq(errfunc, p0[:],
args = (flduration,flpower))
else: # pragma: no cover
p1fl = None
# fitting WC data to three parameter CP model
if len(mlduration)>=4:
p1ml, success = optimize.leastsq(errfunc, p0[:],
args = (mlduration,mlpower))
else: # pragma: no cover
p1ml = None
if len(mhduration)>=4:
p1mh, success = optimize.leastsq(errfunc, p0[:],
args = (mhduration,mhpower))
else: # pragma: no cover
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
sourcemh = ColumnDataSource(
data = dict(
mhduration = mhduration,
mhpower = mhpower,
)
)
sourcefl = ColumnDataSource(
data = dict(
flduration = flduration,
flpower = flpower,
)
)
sourcefh = ColumnDataSource(
data = dict(
fhduration = fhduration,
fhpower = fhpower,
)
)
sourceml = ColumnDataSource(
data = dict(
mlduration = mlduration,
mlpower = mlpower,
)
)
sourcefit = ColumnDataSource(
data = dict(
duration = fitt,
fitpowerfh = fitpowerfh,
fitpowerfl = fitpowerfl,
fitpowerml = fitpowerml,
fitpowermh = fitpowermh,
)
)
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=sourcefit,
legend_label='Female HW',color='blue')
plot.line('duration','fitpowerfl',source=sourcefit,
legend_label='Female LW',color='red')
plot.line('duration','fitpowerml',source=sourcefit,
legend_label='Male LW',color='green')
plot.line('duration','fitpowermh',source=sourcefit,
legend_label='Male HW',color='orange')
plot.circle('flduration','flpower',source=sourcefl,
fill_color='red',size=15)
plot.circle('fhduration','fhpower',source=sourcefh,
fill_color='blue',size=15)
plot.circle('mlduration','mlpower',source=sourceml,
fill_color='green',size=15)
plot.circle('mhduration','mhpower',source=sourcemh,
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',
wcpower=[],wcdurations=[],cpoverlay=False):
powerdf2 = powerdf[~(powerdf == 0).any(axis=1)].copy()
# plot tools
if (promember==1): # pragma: no cover
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 = powerdf2['Delta'].apply(lambda x: timedeltaconv(x))
powerdf2['ftime'] = deltas.apply(lambda x:strfdelta(x))
powerdf2['Deltaminutes'] = powerdf2['Delta']/60.
source = ColumnDataSource(
data = powerdf2
)
# there is no Paul's law for OTW
thesecs = powerdf2['Delta']
theavpower = powerdf2['CP']
p1,fitt,fitpower,ratio = datautils.cpfit(powerdf2)
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' : # pragma: no cover
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 = powerdf2['workout']
urls = powerdf2['url']
# add world class
wcpower = pd.Series(wcpower,dtype='float')
wcdurations = pd.Series(wcdurations,dtype='float')
# fitting WC data to three parameter CP model
if len(wcdurations)>=4: # pragma: no cover
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
p1wc, success = optimize.leastsq(errfunc, p0[:],
args = (wcdurations,wcpower))
else:
p1wc = None
if p1wc is not None and cpoverlay: # pragma: no cover
fitpowerwc = 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
sourcecomplex = ColumnDataSource(
data = dict(
CP = fitpower,
CPmax = ratio*fitpower,
duration = fitt/60.,
ftime = ftime,
# workout = workouts,
fitpowerwc = fitpowerwc,
fitpowerexcellent = fitpowerexcellent,
fitpowergood = fitpowergood,
fitpowerfair = fitpowerfair,
fitpoweraverage = fitpoweraverage,
# url = urls,
)
)
sourceannot= ColumnDataSource(
data = dict(
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'),
('World Class','@fitpowerwc{int}')
])
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')
if p1wc is not None: # pragma: no cover
plot.line('duration','fitpowerwc',source=sourcecomplex,
legend_label="Gold Medal Standard",
color='darkgoldenrod',line_dash='dotted')
plot.line('duration','fitpowerexcellent',source=sourcecomplex,
legend_label="90% percentile",
color='goldenrod',line_dash='dotted')
plot.line('duration','fitpowergood',source=sourcecomplex,
legend_label="75% percentile",
color='sandybrown',line_dash='dotted')
plot.line('duration','fitpowerfair',source=sourcecomplex,
legend_label="50% percentile",
color='rosybrown',line_dash='dotted')
plot.line('duration','fitpoweraverage',source=sourcecomplex,
legend_label="25% percentile",
color='tan',line_dash='dotted')
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: # pragma: no cover
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,
)
)
sourcefit = ColumnDataSource(
data = dict(
age2 = age2,
expo_vals = expo_vals,
)
)
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',source=sourcefit)
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: # pragma: no cover
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: # pragma: no cover
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,dtype='float')
wcdurations = pd.Series(wcdurations,dtype='float')
# fitting WC data to three parameter CP model
if len(wcdurations)>=4:
p1wc, success = optimize.leastsq(errfunc, p0[:],
args = (wcdurations,wcpower))
else: # pragma: no cover
p1wc = None
# fitting the data to three parameter CP model
success = 0
p1 = p0
if len(thesecs)>=4:
try:
p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower))
except (RuntimeError,RuntimeWarning): # pragma: no cover
factor = fitfunc(p0,thesecs.mean())/theavpower.mean()
p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]]
success = 0
else: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
fitpowerwc = 0*fitpower
fitpowerexcellent = 0*fitpower
fitpowergood = 0*fitpower
fitpowerfair = 0*fitpower
fitpoweraverage = 0*fitpower
message = ""
if len(fitpower[fitpower<0]) > 0: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
return 0
try:
dist = rowdata.df.loc[:,'cum_dist']
except KeyError:
return ['','No Data Found']
try: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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"
try:
spm = datadf['spm']
except KeyError: # pragma: no cover
datadf['spm'] = 0
try:
pace = datadf['pace']
except KeyError: # pragma: no cover
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[0,'time'] = 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: # pragma: no cover
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: # pragma: no cover
return ['','<p>No non-zero data in selection</p>']
if xparam == 'workoutid': # pragma: no cover
xparamname = 'Workout'
else:
xparamname = axlabels[xparam]
if yparam == 'workoutid': # pragma: no cover
yparamname = 'Workout'
else:
yparamname = axlabels[yparam]
if groupby == 'workoutid': # pragma: no cover
groupname = 'Workout'
elif groupby == 'date': # pragma: no cover
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': # pragma: no cover
res = make_cumvalues(datadf[xparam])
datadf[xparam] = res[0]
if xparam=='distance': # pragma: no cover
xaxmax = datadf[xparam].max()
xaxmin = datadf[xparam].min()
elif xparam=='time': # pragma: no cover
tseconds = datadf.loc[:,'time']
xaxmax = tseconds.max()
xaxmin = 0
elif xparam == 'workoutid': # pragma: no cover
xaxmax = datadf[xparam].max()-5
xaxmin = datadf[xparam].min()+5
else:
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
if yparam=='distance':# pragma: no cover
yaxmax = datadf[yparam].max()
yaxmin = datadf[yparam].min()
elif yparam=='time': # pragma: no cover
tseconds = datadf.loc[:,'time']
yaxmax = tseconds.max()
yaxmin = 0
elif yparam == 'workoutid': # pragma: no cover
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': # pragma: no cover
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: # pragma: no cover
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': # pragma: no cover
plot.xaxis.axis_label = 'Workout'
else:
plot.xaxis.axis_label = axlabels[xparam]
if yparam == 'workoutid': # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
test = datadf['driveenergy'].mean()
nowork = 0
except KeyError: # pragma: no cover
datadf['driveenergy'] = 500.
# test if we have power
nopower = 1
try: # pragma: no cover
test = datadf['power'].mean()
nopower = 0
except KeyError: # pragma: no cover
datadf['power'] = 50.
yparamname1 = axlabels[yparam1]
if yparam2 != 'None':
yparamname2 = axlabels[yparam2]
# check if dataframe not empty
if datadf.empty: # pragma: no cover
return ['','<p>No non-zero data in selection</p>','','']
try:
datadf['x1'] = datadf.loc[:,xparam]
except KeyError: # pragma: no cover
try:
datadf['x1'] = datadf['distance']
except KeyError:
try:
datadf['x1'] = datadf['time']
except KeyError: # pragma: no cover
return ['','<p>No non-zero data in selection</p>','','']
try:
datadf['y1'] = datadf.loc[:,yparam1]
except KeyError:
try:
datadf['y1'] = datadf['pace']
except KeyError: # pragma: no cover
return ['','<p>No non-zero data in selection</p>','','']
if yparam2 != 'None':
try:
datadf['y2'] = datadf.loc[:,yparam2]
except KeyError: # pragma: no cover
datadf['y2'] = datadf['y1']
else: # pragma: no cover
datadf['y2'] = datadf['y1']
if xparam=='distance': # pragma: no cover
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': # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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': # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
return '','No time data - cannot make flex plot','','',comment
try:
rowdata['x1'] = rowdata.loc[:,xparam]
rowmin = rowdata[xparam].min()
except KeyError: # pragma: no cover
rowdata['x1'] = 0*rowdata.loc[:,'time']
try:
rowdata['y1'] = rowdata.loc[:,yparam1]
rowmin = rowdata[yparam1].min()
except KeyError: # pragma: no cover
rowdata['y1'] = 0*rowdata.loc[:,'time']
rowdata[yparam1] = rowdata['y1']
try: # pragma: no cover
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: # pragma: no cover
rowdata['y3'] = 0*rowdata.loc[:,'time']
rowdata[yparam3] = rowdata['y3']
try:
rowdata['y4'] = rowdata.loc[:,yparam4]
rowmin = rowdata[yparam4].min()
except KeyError: # pragma: no cover
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': # pragma: no cover
xaxmax = rowdata['x1'].max()
xaxmin = rowdata['x1'].min()
else: # pragma: no cover
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': # pragma: no cover
y1_axis_type = 'datetime'
if yparam2 == 'pace': # pragma: no cover
y2_axis_type = 'datetime'
if yparam3 == 'pace': # pragma: no cover
y3_axis_type = 'datetime'
if yparam4 == 'pace': # pragma: no cover
y4_axis_type = 'datetime'
try:
rowdata['xname'] = axlabels[xparam]
except KeyError: # pragma: no cover
rowdata['xname'] = xparam
try:
rowdata['yname1'] = axlabels[yparam1]
except KeyError: # pragma: no cover
rowdata['yname1'] = yparam1
try:
rowdata['yname2'] = axlabels[yparam2]
except KeyError: # pragma: no cover
rowdata['yname2'] = yparam2
try:
rowdata['yname3'] = axlabels[yparam3]
except KeyError: # pragma: no cover
rowdata['yname3'] = yparam3
try:
rowdata['yname4'] = axlabels[yparam4]
except KeyError: # pragma: no cover
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)
xaxlabel = axlabels.get(xparam,xparam)
yax1label = axlabels.get(yparam1,yparam1)
plot1.yaxis.axis_label = yax1label
yax2label = axlabels.get(yparam2,yparam2)
plot2.yaxis.axis_label = yax2label
yax3label = axlabels.get(yparam3,yparam3)
plot3.yaxis.axis_label = yax3label
yax4label = axlabels.get(yparam4,yparam4)
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': # pragma: no cover
y1tooltip = '@{yparam1}'.format(yparam1=yparam1)
if metricsdicts[yparam1]['numtype'] == 'integer' or yparam1 == 'power':
y1tooltip+='{int}'
else: # pragma: no cover
y1tooltip+='{0.00}'
else: # pragma: no cover
y1tooltip = ''
comment = 'The metric in the first chart is only accessible with a Pro plan or higher'
if yparam2 == 'pace': # pragma: no cover
y2tooltip = '@fpace'
elif yparam2 != 'None':
y2tooltip = '@{yparam2}'.format(yparam2=yparam2)
if metricsdicts[yparam2]['numtype'] == 'integer' or yparam2 == 'power':
y2tooltip+='{int}'
else: # pragma: no cover
y2tooltip+='{0.00}'
else: # pragma: no cover
y2tooltip = ''
comment = 'The metric in the second chart is only accessible with a Pro plan or higher'
if yparam3 == 'pace': # pragma: no cover
y3tooltip = '@fpace'
elif yparam3 != 'None':
y3tooltip = '@{yparam3}'.format(yparam3=yparam3)
if metricsdicts[yparam3]['numtype'] == 'integer' or yparam3 == 'power':
y3tooltip+='{int}'
else: # pragma: no cover
y3tooltip+='{0.00}'
else: # pragma: no cover
y3tooltip = ''
comment = 'The metric in the third chart is only accessible with a Pro plan or higher'
if yparam4 == 'pace': # pragma: no cover
y4tooltip = '@fpace'
elif yparam4 != 'None':
y4tooltip = '@{yparam4}'.format(yparam4=yparam4)
if metricsdicts[yparam4]['numtype'] == 'integer' or yparam4 == 'power': # pragma: no cover
y4tooltip+='{int}'
else: # pragma: no cover
y4tooltip+='{0.00}'
else: # pragma: no cover
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': # pragma: no cover
plot2.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
plot2.y_range = Range1d(y2min,y2max)
if yparam3 == 'pace': # pragma: no cover
plot3.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
plot3.y_range = Range1d(y3min,y3max)
if yparam4 == 'pace': # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
yparam2 = 'None'
try:
tests = rowdata[yparam1]
except KeyError: # pragma: no cover
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: # pragma: no cover
try:
rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)]
except KeyError:
pass
try:
tseconds = rowdata.loc[:,'time']
except KeyError: # pragma: no cover
return '','No time data - cannot make flex plot','','',workstrokesonly
try:
rowdata['x1'] = rowdata.loc[:,xparam]
rowmin = rowdata[xparam].min()
except KeyError: # pragma: no cover
rowdata['x1'] = 0*rowdata.loc[:,'time']
try:
rowdata['y1'] = rowdata.loc[:,yparam1]
rowmin = rowdata[yparam1].min()
except KeyError: # pragma: no cover
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: # pragma: no cover
rowdata['y2'] = 0*rowdata.loc[:,'time']
rowdata[yparam2] = rowdata['y2']
else: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
x1mean = 0
else: # pragma: no cover
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': # pragma: no cover
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: # pragma: no cover
y1mean = 0
try:
rowdata['xname'] = axlabels[xparam]
except KeyError: # pragma: no cover
rowdata['xname'] = xparam
try:
rowdata['yname1'] = axlabels[yparam1]
except KeyError: # pragma: no cover
rowdata['yname1'] = yparam1
if yparam2 != 'None':
try:
rowdata['yname2'] = axlabels[yparam2]
except KeyError: # pragma: no cover
rowdata['yname2'] = yparam2
else: # pragma: no cover
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: # pragma: no cover
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'): # pragma: no cover
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: # pragma: no cover
yaxlabel = str(yparam1)+' '
try:
xaxlabel = axlabels[xparam]
except KeyError: # pragma: no cover
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': # pragma: no cover
plot.add_layout(y1label)
y2label = y1label
# average values
if yparam1 == 'driveenergy': # pragma: no cover
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': # pragma: no cover
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: # pragma: no cover
yrange1 = Range1d(start=rowdata[yparam1].min(),
end=rowdata[yparam1].max())
plot.y_range = yrange1
if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): # pragma: no cover
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: # pragma: no cover
yrange2 = Range1d(start=rowdata[yparam2].min(),
end=rowdata[yparam2].max())
plot.extra_y_ranges["yax2"] = yrange2
#= {"yax2": yrange2}
try:
axlegend = axlabels[yparam2]
except KeyError: # pragma: no cover
axlegend = str(yparam2)+' '
if plottype=='line':
plot.line('x1','y2',color="red",y_range_name="yax2",
legend_label=axlegend,
source=source2)
elif plottype=='scatter': # pragma: no cover
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): # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
return '','No time data - cannot make flex plot'
try:
rowdata['x1'] = rowdata.loc[:,xparam]
except KeyError: # pragma: no cover
rowdata['x1'] = 0*rowdata.loc[:,'time']
try:
rowdata['y1'] = rowdata.loc[:,yparam1]
except KeyError: # pragma: no cover
rowdata['y1'] = 0*rowdata.loc[:,'time']
if yparam2 != 'None':
try:
rowdata['y2'] = rowdata.loc[:,yparam2]
except KeyError: # pragma: no cover
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': # pragma: no cover
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': # pragma: no cover
y_axis_type = 'datetime'
y1mean = rowdata.loc[:,'pace'].mean()
rowdata['xname'] = axlabels[xparam]
try:
rowdata['yname1'] = axlabels[yparam1]
except KeyError: # pragma: no cover
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: # pragma: no cover
plot.xaxis.axis_label = 'X'
try:
plot.yaxis.axis_label = axlabels[yparam1]
except KeyError: # pragma: no cover
plot.yaxis.axis_label = 'Y'
try:
yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
except KeyError: # pragma: no cover
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': # pragma: no cover
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': # pragma: no cover
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_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: # pragma: no cover
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: # pragma: no cover
return ['','<p>No non-zero data in selection</p>','','No non-zero data in selection']
if xparam != 'distance' and xparam != 'time' and xparam != 'cumdist': # pragma: no cover
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
elif xparam == 'time' and not startenddict:
xaxmax = tseconds.max()
xaxmin = tseconds.min()
elif xparam == 'time' and startenddict: # pragma: no cover
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': # pragma: no cover
yaxmin = datadf['distance'].min()
yaxmax = datadf['distance'].max()
elif yparam == 'cumdist': # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
legend = str(id)
else: # pragma: no cover
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'): # pragma: no cover
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: # pragma: no cover
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: # pragma: no cover
script = ''
div = ''
return [script,div]
def get_zones_report(rower,startdate,enddate,trainingzones='hr',date_agg='week',
yaxis='time'):
duration = enddate-startdate
totaldays = duration.total_seconds()/(24*3600)
dates = []
dates_sorting = []
minutes = []
hours = []
zones = []
enddate = enddate + datetime.timedelta(days=1)
workouts = Workout.objects.filter(
user=rower,
startdatetime__gte=startdate,
startdatetime__lte=enddate,
duplicate=False,
).order_by("-startdatetime")
ids = [w.id for w in workouts]
columns = ['workoutid','hr','power','time']
df = dataprep.getsmallrowdata_db(columns,ids=ids)
try:
df['deltat'] = df['time'].diff().clip(lower=0).clip(upper=20*1e3)
except KeyError: # pragma: no cover
pass
df = dataprep.clean_df_stats(df,workstrokesonly=False,
ignoreadvanced=True,ignorehr=False)
#totalmeters,totalhours, totalminutes, totalseconds = get_totals(workouts)
hrzones = rower.hrzones
powerzones = rower.powerzones
for w in workouts:
dd = w.date.strftime('%m/%d')
dd2 = w.date.strftime('%Y/%m/%d')
dd3 = w.date.strftime('%Y/%m')
dd4 = '{year}/{week:02d}'.format(
week=arrow.get(w.date).isocalendar()[1],
year= w.date.strftime('%y')
)
dd4 = (w.date - datetime.timedelta(days = w.date.weekday())).strftime('%y/%m/%d')
#print(w.date,arrow.get(w.date),arrow.get(w.date).isocalendar())
qryw = 'workoutid == {workoutid}'.format(workoutid=w.id)
qry = 'hr < {ut2}'.format(ut2=rower.ut2)
if trainingzones == 'power':
qry = 'power < {ut2}'.format(ut2=rower.pw_ut2)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if date_agg == 'week':
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover
dates.append(dd3)
dates_sorting.append(dd3)
minutes.append(timeinzone)
hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append('<{ut2}'.format(ut2=hrzones[1]))
else:
zones.append('<{ut2}'.format(ut2=powerzones[1]))
#print(w,dd,timeinzone,'<UT2')
qry = '{ut2} <= hr < {ut1}'.format(ut1=rower.ut1,ut2=rower.ut2)
if trainingzones == 'power':
qry = '{ut2} <= power < {ut1}'.format(ut1=rower.pw_ut1,ut2=rower.pw_ut2)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if date_agg == 'week':
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover
dates.append(dd3)
dates_sorting.append(dd3)
minutes.append(timeinzone)
hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append(hrzones[1])
else:
zones.append(powerzones[1])
#print(w,dd,timeinzone,'UT2')
qry = '{ut1} <= hr < {at}'.format(ut1=rower.ut1,at=rower.at)
if trainingzones == 'power':
qry = '{ut1} <= power < {at}'.format(ut1=rower.pw_ut1,at=rower.pw_at)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if date_agg == 'week':
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover
dates.append(dd3)
dates_sorting.append(dd3)
minutes.append(timeinzone)
hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append(hrzones[2])
else:
zones.append(powerzones[2])
#print(w,dd,timeinzone,'UT1')
qry = '{at} <= hr < {tr}'.format(at=rower.at,tr=rower.tr)
if trainingzones == 'power':
qry = '{at} <= power < {tr}'.format(at=rower.pw_at,tr=rower.pw_tr)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if date_agg == 'week':
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover
dates.append(dd3)
dates_sorting.append(dd3)
minutes.append(timeinzone)
hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append(hrzones[3])
else:
zones.append(powerzones[3])
#print(w,dd,timeinzone,'AT')
qry = '{tr} <= hr < {an}'.format(tr=rower.tr,an=rower.an)
if trainingzones == 'power':
qry = '{tr} <= power < {an}'.format(tr=rower.pw_tr,an=rower.pw_an)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if date_agg == 'week':
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover
dates.append(dd3)
dates_sorting.append(dd3)
minutes.append(timeinzone)
hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append(hrzones[4])
else:
zones.append(powerzones[4])
#print(w,dd,timeinzone,'TR')
qry = 'hr >= {an}'.format(an=rower.an)
if trainingzones == 'power':
qry = 'power >= {an}'.format(an=rower.pw_an)
timeinzone = df.query(qry).query(qryw)['deltat'].sum()/(60*1e3)
if date_agg == 'week':
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover
dates.append(dd3)
dates_sorting.append(dd3)
minutes.append(timeinzone)
hours.append(timeinzone/60.)
if trainingzones == 'hr':
zones.append(hrzones[5])
else:
zones.append(powerzones[5])
#print(w,dd,timeinzone,'AN')
try:
d = utc.localize(startdate)
except (ValueError,AttributeError): # pragma: no cover
d = startdate
try:
enddate = utc.localize(enddate)
except (ValueError,AttributeError): # pragma: no cover
pass
while d<=enddate:
dd = d.strftime('%d')
if date_agg == 'week':
dd4 = '{year}/{week:02d}'.format(
week=arrow.get(d).isocalendar()[1],
year= d.strftime('%y')
)
dd4 = (d - datetime.timedelta(days = d.weekday())).strftime('%y/%m/%d')
dates.append(dd4)
dates_sorting.append(dd4)
else: # pragma: no cover
dates.append(d.strftime('%Y/%m'))
dates_sorting.append(d.strftime('%Y/%m'))
minutes.append(0)
hours.append(0)
if trainingzones == 'hr':
zones.append(hrzones[1])
else:
zones.append(powerzones[1])
d += datetime.timedelta(days=1)
# this should be renamed with rower zones
data = {
'date':dates,
'date_sorting':dates_sorting,
'minutes': minutes,
'zones':zones,
'hours':hours,
}
#print(pd.DataFrame(data).head())
return data
def interactive_zoneschart(rower,data,startdate,enddate,trainingzones='hr',date_agg='week',
yaxis='time'):
if startdate >= enddate:
st = startdate
startdate = enddate
enddate = st
duration = enddate-startdate
totaldays = duration.total_seconds()/(24*3600)
colors = ['gray','yellow','lime','blue','purple','red']
hrzones = rower.hrzones
powerzones = rower.powerzones
color_map = {
'<{ut2}'.format(ut2=hrzones[1]):'green',
hrzones[1]:'lime',
hrzones[2]:'yellow',
hrzones[3]:'blue',
hrzones[4]:'purple',
hrzones[5]:'red',
}
if trainingzones == 'power':
color_map = {
'<{ut2}'.format(ut2=powerzones[1]):'green',
powerzones[1]:'lime',
powerzones[2]:'yellow',
powerzones[3]:'blue',
powerzones[4]:'purple',
powerzones[5]:'red',
}
zones_order = [
'<{ut2}'.format(ut2=hrzones[1]),
hrzones[1],
hrzones[2],
hrzones[3],
hrzones[4],
hrzones[5]
]
if trainingzones == 'power':
zones_order = [
'<{ut2}'.format(ut2=powerzones[1]),
powerzones[1],
powerzones[2],
powerzones[3],
powerzones[4],
powerzones[5]
]
df = pd.DataFrame(data)
df2 = pd.DataFrame(data)
df.drop('minutes',inplace=True,axis='columns')
#df.drop('hours',inplace=True,axis='columns')
source = ColumnDataSource(df)
df.sort_values('date_sorting',inplace=True)
df.drop('date_sorting',inplace=True,axis='columns')
df['totaltime'] = 0
if df.empty: # pragma: no cover
return '','No Data Found'
if yaxis == 'percentage':
dates = list(set(df['date'].values))
for date in dates:
qry = 'date == "{d}"'.format(d=date)
totaltime = df.query(qry)['hours'].sum()
mask = df['date'] == date
df.loc[mask,'totaltime'] = totaltime
df['percentage'] = 100.*df['hours']/df['totaltime']
df.drop('hours',inplace=True,axis='columns')
df.drop('totaltime',inplace=True,axis='columns')
hv.extension('bokeh')
xrotation = 0
nrdates = len(list(set(df['date'].values)))
if nrdates > 10:
xrotation = 45
bars = hv.Bars(df, kdims = ['date','zones']).aggregate(function=np.sum).redim.values(zones=zones_order)
#bars = table.to.bars(['date','zones'],['minutes'])
bars.opts(
opts.Bars(cmap=color_map,show_legend=True,stacked=True,
tools=['tap','hover'],width=550,padding=(0,(0,.1)),
legend_position='bottom',
xrotation=xrotation,
show_frame=False)
)
p = hv.render(bars)
p.title.text = 'Activity {d1} to {d2} for {r}'.format(
d1 = startdate.strftime("%Y-%m-%d"),
d2 = enddate.strftime("%Y-%m-%d"),
r = str(rower),
)
if date_agg == 'week':
p.xaxis.axis_label = 'Week'
else: # pragma: no cover
p.xaxis.axis_label = 'Month'
if yaxis == 'percentage':
p.yaxis.axis_label = 'Percentage'
p.plot_width=550
p.plot_height=350
p.toolbar_location = 'right'
p.y_range.start = 0
p.sizing_mode = 'stretch_both'
if yaxis == 'percentage':
tidy_df = df2.groupby(['date']).sum()
source2 = ColumnDataSource(tidy_df)
y2rangemax = tidy_df.loc[:,'hours'].max()*1.1
p.extra_y_ranges["yax2"] = Range1d(start=0,end=y2rangemax)
p.line('date','hours',source=source2,y_range_name="yax2",color="black",width=5)
p.circle('date','hours',source=source2,y_range_name="yax2",color="black",size=10,
legend_label='Hours')
p.add_layout(LinearAxis(y_range_name="yax2",
axis_label='Hours'),'right')
script,div = components(p)
return script,div