Private
Public Access
1
0
Files
rowsandall/rowers/interactiveplots.py
2018-03-14 13:39:52 +01:00

4004 lines
115 KiB
Python

import colorsys
from rowers.models import (
Workout, User, Rower, WorkoutForm,RowerForm,
GraphImage,GeoPolygon,GeoCourse,GeoPoint
)
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
from django.utils import timezone
from bokeh.palettes import Dark2_8 as palette
import itertools
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation
from bokeh.charts import Histogram,HeatMap,Area,BoxPlot,Bar
from bokeh.charts.attributes import CatAttr
from bokeh.resources import CDN,INLINE
from bokeh.embed import components
from bokeh.layouts import layout,widgetbox
from bokeh.layouts import row as layoutrow
from bokeh.layouts import column as layoutcolumn
from bokeh.models import LinearAxis,LogAxis,Range1d,DatetimeTickFormatter,HoverTool
from bokeh.io import output_file, show, vplot
from bokeh.models import (
GMapPlot, GMapOptions, ColumnDataSource, Circle,
DataRange1d, PanTool, WheelZoomTool, BoxSelectTool,
SaveTool, ResizeTool, ResetTool, TapTool,CrosshairTool,BoxZoomTool,
Span, Label
)
from bokeh.models.glyphs import ImageURL
#from bokeh.models.widgets import Slider, Select, TextInput
from bokeh.core.properties import value
from collections import OrderedDict
from django.conf import settings
from courses import (
course_coord_center,course_coord_maxmin,
polygon_coord_center
)
import datetime
import math
import numpy as np
import pandas as pd
from pytz import timezone as tz,utc
from django.utils.timezone import get_current_timezone
from django.utils.timezone import activate
from django.utils import timezone
activate(settings.TIME_ZONE)
thetimezone = get_current_timezone()
from scipy.stats import linregress,percentileofscore
from scipy import optimize
from scipy.signal import savgol_filter
import stravastuff
from rowers.dataprep import rdata
import rowers.dataprep as dataprep
import rowers.metrics as metrics
from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima
from utils import lbstoN
import datautils
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'
def errorbar(fig, x, y, source=ColumnDataSource(),
xerr=False, yerr=False, color='black',
point_kwargs={}, error_kwargs={}):
xvalues = source.data[x]
yvalues = source.data[y]
xerrvalues = source.data['xerror']
yerrvalues = source.data['yerror']
try:
colorvalues = source.data['color']
except KeyError:
colorvalues = ["#%02x%02x%02x" % (255,0,0) for x in xvalues]
try:
a = xvalues[0]+1
if xerr:
x_err_x = []
x_err_y = []
err_color = []
for px, py, err, color in zip(xvalues, yvalues, xerrvalues, colorvalues):
x_err_x.append((px - err, px + err))
x_err_y.append((py, py))
(r, g, b) = tuple(int(color[i:i+2],16) for i in (1, 3, 5))
h,s,v = colorsys.rgb_to_hsv(r/255., g/255., b/255.)
v = v*0.8
r, g, b = colorsys.hsv_to_rgb(h, s, v)
color2 = "#%02x%02x%02x" % (int(255.*r), int(255.*g), int(255*b))
err_color.append(color2)
fig.multi_line(x_err_x, x_err_y, color=err_color,
name='xerr',
**error_kwargs)
except TypeError:
pass
try:
a = yvalues[0]+1
if yerr:
y_err_x = []
y_err_y = []
err_color = []
for px, py, err, color in zip(xvalues, yvalues, yerrvalues, colorvalues):
y_err_x.append((px, px))
y_err_y.append((py - err, py + err))
(r, g, b) = tuple(int(color[i:i+2],16) for i in (1, 3, 5))
h,s,v = colorsys.rgb_to_hsv(r/255., g/255., b/255.)
v = v*0.8
r, g, b = colorsys.hsv_to_rgb(h, s, v)
color2 = "#%02x%02x%02x" % (int(255.*r), int(255.*g), int(255*b))
err_color.append(color2)
fig.multi_line(y_err_x, y_err_y, color=err_color,
name='yerr',**error_kwargs)
except TypeError:
pass
fig.circle(x, y, source=source, name='data',color=color,
**point_kwargs)
def tailwind(bearing,vwind,winddir):
""" Calculates head-on head/tailwind in direction of rowing
positive numbers are tail wind
"""
b = np.radians(bearing)
w = np.radians(winddir)
vtail = -vwind*np.cos(w-b)
return vtail
from rowers.dataprep import nicepaceformat,niceformat
from rowers.dataprep import timedeltaconv
def interactive_boxchart(datadf,fieldname,extratitle=''):
if datadf.empty:
return '','It looks like there are no data matching your filter'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,resize,hover'
plot = BoxPlot(datadf, values=fieldname, label='date',
legend=False,
title=axlabels[fieldname]+' '+extratitle,
outliers=False,
tools=TOOLS,
toolbar_location="above",
toolbar_sticky=False,
x_mapper_type='datetime')
yrange1 = Range1d(start=yaxminima[fieldname],end=yaxmaxima[fieldname])
plot.y_range = yrange1
plot.xaxis.axis_label = 'Date'
plot.yaxis.axis_label = axlabels[fieldname]
# add watermark
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.formatter = DatetimeTickFormatter(
days=["%d %B %Y"],
months=["%d %B %Y"],
years=["%d %B %Y"],
)
if fieldname == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
plot.xaxis.major_label_orientation = pi/4
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Value','@y'),
('Date','@x'),
])
hover.mode = 'mouse'
script, div = components(plot)
return script,div
def interactive_activitychart(workouts,startdate,enddate,stack='type'):
if len(workouts) == 0:
return "",""
dates = []
dates_sorting = []
types = []
rowers = []
durations = []
for w in workouts:
if w.privacy == 'visible':
dd = w.date.strftime('%m/%d')
dd2 = w.date.strftime('%Y/%m/%d')
du = w.duration.hour*60+w.duration.minute
dates.append(dd)
dates_sorting.append(dd2)
durations.append(du)
types.append(w.workouttype)
try:
rowers.append(w.user.user.first_name[0]+w.user.user.last_name[0])
except IndexError:
rowers.append(str(w.user))
try:
d = utc.localize(startdate)
except ValueError:
d = startdate
try:
enddate = utc.localize(enddate)
except ValueError:
pass
# add dates with no activity
while d<=enddate:
dates.append(d.strftime('%m/%d'))
dates_sorting.append(d.strftime('%Y/%m/%d'))
durations.append(0)
types.append('rower')
rowers.append('Sander')
d += datetime.timedelta(days=1)
df = pd.DataFrame({
'date':dates,
'date_sorting':dates_sorting,
'duration':durations,
'type':types,
'rower':rowers,
})
df.sort_values('date_sorting',inplace=True)
p = Bar(df,values='duration',
label = CatAttr(columns=['date'], sort=False),
xlabel='Date',
ylabel='Time',
title='Activity',
stack=stack,
plot_width=350,
plot_height=250,
toolbar_location = None,
)
for legend in p.legend:
new_items = []
for legend_item in legend.items:
it = legend_item.label['value']
tot = df[df[stack]==it].duration.sum()
if tot != 0:
new_items.append(legend_item)
legend.items = new_items
p.legend.location = "top_left"
p.legend.background_fill_alpha = 0.7
p.yaxis.axis_label = 'Minutes'
script, div = components(p)
return script,div
def interactive_forcecurve(theworkouts,workstrokesonly=False):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
ids = [int(w.id) for w in theworkouts]
boattype = theworkouts[0].boattype
columns = ['catch','slip','wash','finish','averageforce',
'peakforceangle','peakforce','spm','distance',
'workoutstate','driveenergy']
rowdata = dataprep.getsmallrowdata_db(columns,ids=ids)
rowdata.dropna(axis=1,how='all',inplace=True)
rowdata.dropna(axis=0,how='any',inplace=True)
workoutstateswork = [1,4,5,8,9,6,7]
workoutstatesrest = [3]
workoutstatetransition = [0,2,10,11,12,13]
if workstrokesonly:
try:
rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)]
except KeyError:
pass
if rowdata.empty:
return "","No Valid Data Available","",""
try:
catchav = rowdata['catch'].mean()
except KeyError:
catchav = 0
try:
finishav = rowdata['finish'].mean()
except KeyError:
finishav = 0
try:
washav = rowdata['wash'].mean()
except KeyError:
washav = 0
try:
slipav = rowdata['slip'].mean()
except KeyError:
slipav = 0
try:
peakforceav = rowdata['peakforce'].mean()
except KeyError:
peakforceav = 0
try:
averageforceav = rowdata['averageforce'].mean()
except KeyError:
averageforceav = 0
try:
peakforceangleav = rowdata['peakforceangle'].mean()
except KeyError:
peakforceangleav = 0
x = [catchav,
catchav+slipav,
peakforceangleav,
finishav-washav,
finishav]
thresholdforce = 100 if 'x' in boattype else 200
#thresholdforce /= 4.45 # N to lbs
y = [0,thresholdforce,
peakforceav,
thresholdforce,0]
source = ColumnDataSource(
data = dict(
x = x,
y = y,
))
source2 = ColumnDataSource(
rowdata
)
plot = Figure(tools=TOOLS,
toolbar_sticky=False)
# add watermark
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.line('x','y',source=source,color="red")
plot.add_layout(avf)
peakflabel = Label(x=455,y=530,x_units='screen',y_units='screen',
text="Fpeak: {peakforceav:6.2f}".format(peakforceav=peakforceav),
background_fill_alpha=.7,
background_fill_color='white',
text_color='blue',
)
avflabel = Label(x=465,y=500,x_units='screen',y_units='screen',
text="Favg: {averageforceav:6.2f}".format(averageforceav=averageforceav),
background_fill_alpha=.7,
background_fill_color='white',
text_color='blue',
)
catchlabel = Label(x=460,y=470,x_units='screen',y_units='screen',
text="Catch: {catchav:6.2f}".format(catchav=catchav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='red',
)
peakforceanglelabel = Label(x=420,y=440,x_units='screen',y_units='screen',
text="Peak angle: {peakforceangleav:6.2f}".format(peakforceangleav=peakforceangleav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='red',
)
finishlabel = Label(x=455,y=410,x_units='screen',y_units='screen',
text="Finish: {finishav:6.2f}".format(finishav=finishav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='red',
)
sliplabel = Label(x=470,y=380,x_units='screen',y_units='screen',
text="Slip: {slipav:6.2f}".format(slipav=slipav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='red',
)
washlabel = Label(x=460,y=350,x_units='screen',y_units='screen',
text="Wash: {washav:6.2f}".format(washav=washav),
background_fill_alpha=0.7,
background_fill_color='white',
text_color='red',
)
plot.add_layout(peakflabel)
plot.add_layout(peakforceanglelabel)
plot.add_layout(avflabel)
plot.add_layout(catchlabel)
plot.add_layout(sliplabel)
plot.add_layout(washlabel)
plot.add_layout(finishlabel)
plot.xaxis.axis_label = "Angle"
plot.yaxis.axis_label = "Force (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,
avf=avf,
avflabel=avflabel,
catchlabel=catchlabel,
finishlabel=finishlabel,
sliplabel=sliplabel,
washlabel=washlabel,
peakflabel=peakflabel,
peakforceanglelabel=peakforceanglelabel,
), code="""
var data = source.data
var data2 = source2.data
var x = data['x']
var y = data['y']
var spm1 = data2['spm']
var distance1 = data2['distance']
var driveenergy1 = data2['driveenergy']
var thresholdforce = y[1]
var c = source2.data['catch']
var finish = data2['finish']
var slip = data2['slip']
var wash = data2['wash']
var peakforceangle = data2['peakforceangle']
var peakforce = data2['peakforce']
var averageforce = data2['averageforce']
var minspm = minspm.value
var maxspm = maxspm.value
var mindist = mindist.value
var maxdist = maxdist.value
var minwork = minwork.value
var maxwork = maxwork.value
var catchav = 0
var finishav = 0
var slipav = 0
var washav = 0
var peakforceangleav = 0
var averageforceav = 0
var peakforceav = 0
var count = 0
for (i=0; i<c.length; i++) {
if (spm1[i]>=minspm && spm1[i]<=maxspm) {
if (distance1[i]>=mindist && distance1[i]<=maxdist) {
if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
catchav += c[i]
finishav += finish[i]
slipav += slip[i]
washav += wash[i]
peakforceangleav += peakforceangle[i]
averageforceav += averageforce[i]
peakforceav += peakforce[i]
count += 1
}
}
}
}
catchav /= count
finishav /= count
slipav /= count
washav /= count
peakforceangleav /= count
peakforceav /= count
averageforceav /= count
data['x'] = [catchav,catchav+slipav,peakforceangleav,finishav-washav,finishav]
data['y'] = [0,thresholdforce,peakforceav,thresholdforce,0]
avf.location = averageforceav
avflabel.text = 'Favg: '+averageforceav.toFixed(2)
catchlabel.text = 'Catch: '+catchav.toFixed(2)
finishlabel.text = 'Finish: '+finishav.toFixed(2)
sliplabel.text = 'Slip: '+slipav.toFixed(2)
washlabel.text = 'Wash: '+washav.toFixed(2)
peakflabel.text = 'Fpeak: '+peakforceav.toFixed(2)
peakforceanglelabel.text = 'Peak angle: '+peakforceangleav.toFixed(2)
source.trigger('change');
""")
slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1,
title="Min SPM",callback=callback)
callback.args["minspm"] = slider_spm_min
slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1,
title="Max SPM",callback=callback)
callback.args["maxspm"] = slider_spm_max
slider_work_min = Slider(start=0, end=1500,value=0, step=10,
title="Min Work per Stroke",callback=callback)
callback.args["minwork"] = slider_work_min
slider_work_max = Slider(start=0, end=1500,value=1500, step=10,
title="Max Work per Stroke",callback=callback)
callback.args["maxwork"] = slider_work_max
distmax = 100+100*int(rowdata['distance'].max()/100.)
slider_dist_min = Slider(start=0,end=distmax,value=0,step=1,
title="Min Distance",callback=callback)
callback.args["mindist"] = slider_dist_min
slider_dist_max = Slider(start=0,end=distmax,value=distmax,
step=1,
title="Max Distance",callback=callback)
callback.args["maxdist"] = slider_dist_max
layout = layoutrow([layoutcolumn([slider_spm_min,
slider_spm_max,
slider_dist_min,
slider_dist_max,
slider_work_min,
slider_work_max,
],
),
plot])
script, div = components(layout)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
return [script,div,js_resources,css_resources]
def interactive_histoall(theworkouts):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
ids = [int(w.id) for w in theworkouts]
rowdata = dataprep.getsmallrowdata_db(['power'],ids=ids,doclean=True)
rowdata.dropna(axis=0,how='any',inplace=True)
if rowdata.empty:
return "","No Valid Data Available","",""
histopwr = rowdata['power'].values
if len(histopwr) == 0:
return "","No valid data available","",""
# throw out nans
histopwr = histopwr[~np.isinf(histopwr)]
histopwr = histopwr[histopwr > 25]
histopwr = histopwr[histopwr < 1000]
plot = Figure(tools=TOOLS,plot_width=900,
toolbar_sticky=False,
toolbar_location="above"
)
# add watermark
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 = "Power (W)"
plot.yaxis.axis_label = "% of strokes"
plot.y_range = Range1d(0,1.05*max(hist_norm))
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Power(W)','@left{int}'),
('% of strokes','@hist_norm'),
('Cumulative %','@histsum{int}'),
])
hover.mode = 'mouse'
plot.extra_y_ranges["fraction"] = Range1d(start=0,end=105)
plot.line('right','histsum',source=source,color="red",
y_range_name="fraction")
plot.add_layout(LinearAxis(y_range_name="fraction",
axis_label="Cumulative % of strokes"),'right')
script, div = components(plot)
return [script,div]
def course_map(course):
latmean,lonmean,coordinates = course_coord_center(course)
lat_min, lat_max, long_min, long_max = course_coord_maxmin(course)
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.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{
maxZoom: 18,
id: 'mapbox.streets'
}}),
satellite = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{
maxZoom: 18,
id: 'mapbox.satellite'
}}),
outdoors = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{
maxZoom: 18,
id: 'mapbox.outdoors'
}});
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}
</script>
""".format(
latmean=latmean,
lonmean=lonmean,
scoordinates=scoordinates,
pcoordinates=pcoordinates,
plabels = plabels
)
div = """
<div id="map_canvas" style="width: 100%; height: 400px;"><p>&nbsp;</p></div>
"""
return script,div
def leaflet_chart(lat,lon,name=""):
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
# Throw out 0,0
df = pd.DataFrame({
'lat':lat,
'lon':lon
})
df = df.replace(0,np.nan)
df = df.loc[(df!=0).any(axis=1)]
df.fillna(method='bfill',axis=0,inplace=True)
df.fillna(method='ffill',axis=0,inplace=True)
lat = df['lat']
lon = df['lon']
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
latmean = lat.mean()
lonmean = lon.mean()
latbegin = lat[lat.index[0]]
longbegin = lon[lon.index[0]]
latend = lat[lat.index[-1]]
longend = lon[lon.index[-1]]
coordinates = zip(lat,lon)
scoordinates = "["
for x,y in coordinates:
scoordinates += """[{x},{y}],
""".format(
x=x,
y=y
)
scoordinates += "]"
script = """
<script>
var streets = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{
maxZoom: 18,
id: 'mapbox.streets'
}}),
satellite = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{
maxZoom: 18,
id: 'mapbox.satellite'
}}),
outdoors = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{
maxZoom: 18,
id: 'mapbox.outdoors'
}});
var mymap = L.map('map_canvas', {{
center: [{latmean}, {lonmean}],
zoom: 13,
layers: [streets, satellite]
}}).setView([{latmean},{lonmean}], 13);
var navionics = new JNC.Leaflet.NavionicsOverlay({{
navKey: 'Navionics_webapi_03205',
chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
isTransparent: true,
zIndex: 1
}});
var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';
//create two TileLayer
var nautical=new L.TileLayer(osmUrl,{{
maxZoom:18}});
L.control.layers({{
"Streets": streets,
"Satellite": satellite,
"Outdoors": outdoors,
"Nautical": nautical,
}},{{
"Navionics":navionics,
}}).addTo(mymap);
var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
marker.bindPopup("<b>Start</b>");
var emarker = new L.marker([{latend}, {longend}]).addTo(mymap);
emarker.bindPopup("<b>End</b>");
var latlongs = {scoordinates}
var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap)
mymap.fitBounds(polyline.getBounds())
</script>
""".format(
latmean=latmean,
lonmean=lonmean,
latbegin = latbegin,
latend=latend,
longbegin=longbegin,
longend=longend,
scoordinates=scoordinates,
)
div = """
<div id="map_canvas" style="width: 100%; height: 400px;"><p>&nbsp;</p></div>
"""
return script,div
def leaflet_chart2(lat,lon,name=""):
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
# Throw out 0,0
df = pd.DataFrame({
'lat':lat,
'lon':lon
})
df = df.replace(0,np.nan)
df = df.loc[(df!=0).any(axis=1)]
df.fillna(method='bfill',axis=0,inplace=True)
df.fillna(method='ffill',axis=0,inplace=True)
lat = df['lat']
lon = df['lon']
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
latmean = lat.mean()
lonmean = lon.mean()
latbegin = lat[lat.index[0]]
longbegin = lon[lon.index[0]]
latend = lat[lat.index[-1]]
longend = lon[lon.index[-1]]
coordinates = zip(lat,lon)
scoordinates = "["
for x,y in coordinates:
scoordinates += """[{x},{y}],
""".format(
x=x,
y=y
)
scoordinates += "]"
script = """
<script>
var streets = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{
maxZoom: 18,
id: 'mapbox.streets'
}}),
satellite = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{
maxZoom: 18,
id: 'mapbox.satellite'
}}),
outdoors = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{
maxZoom: 18,
id: 'mapbox.outdoors'
}});
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 googlemap_chart(lat,lon,name=""):
if lat.empty or lon.empty:
return [0,"invalid coordinate data"]
# plot tools
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize'
map_options = GMapOptions(lat = lat.mean(),lng=lon.mean(),
map_type="roadmap",zoom=13)
plot = GMapPlot(
x_range=DataRange1d(), y_range=DataRange1d(),
map_options=map_options,
api_key = "AIzaSyAgu1w9QSthaGPMLp8y9JedPoMc9sfEgJ8",
plot_width=400,plot_height=400,
toolbar_sticky=False,
)
source = ColumnDataSource(
data = dict(
lat=lat,
lon=lon,
)
)
circle = Circle(x="lon",y="lat",size=5,fill_color="blue",
fill_alpha=0.2,line_color=None)
plot.add_glyph(source,circle)
plot.add_tools(PanTool(), WheelZoomTool(),
SaveTool(), ResizeTool(), ResetTool(),
TapTool(),CrosshairTool(),
)
plot.title.text = name
plot.title.text_font="1.0em"
script, div = components(plot)
return [script,div]
def interactive_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 = metrics.getagegrouprecord(
age,
sex='female',
distance=distance,
weightcategory='hwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try:
duration = distance/velo
fhduration.append(duration)
fhpower.append(worldclasspower)
except ZeroDivisionError:
pass
for duration in durations:
worldclasspower = metrics.getagegrouprecord(
age,
sex='female',
duration=duration,
weightcategory='hwt'
)
try:
velo = (worldclasspower/2.8)**(1./3.)
distance = int(60*duration*velo)
fhduration.append(60.*duration)
fhpower.append(worldclasspower)
except ValueError:
pass
flduration = []
flpower = []
for distance in distances:
worldclasspower = metrics.getagegrouprecord(
age,
sex='female',
distance=distance,
weightcategory='lwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try:
duration = distance/velo
flduration.append(duration)
flpower.append(worldclasspower)
except ZeroDivisionError:
pass
for duration in durations:
worldclasspower = metrics.getagegrouprecord(
age,
sex='female',
duration=duration,
weightcategory='lwt'
)
try:
velo = (worldclasspower/2.8)**(1./3.)
distance = int(60*duration*velo)
flduration.append(60.*duration)
flpower.append(worldclasspower)
except ValueError:
pass
mlduration = []
mlpower = []
for distance in distances:
worldclasspower = metrics.getagegrouprecord(
age,
sex='male',
distance=distance,
weightcategory='lwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try:
duration = distance/velo
mlduration.append(duration)
mlpower.append(worldclasspower)
except ZeroDivisionError:
pass
for duration in durations:
worldclasspower = metrics.getagegrouprecord(
age,
sex='male',
duration=duration,
weightcategory='lwt'
)
try:
velo = (worldclasspower/2.8)**(1./3.)
distance = int(60*duration*velo)
mlduration.append(60.*duration)
mlpower.append(worldclasspower)
except ValueError:
pass
mhduration = []
mhpower = []
for distance in distances:
worldclasspower = metrics.getagegrouprecord(
age,
sex='male',
distance=distance,
weightcategory='hwt'
)
velo = (worldclasspower/2.8)**(1./3.)
try:
duration = distance/velo
mhduration.append(duration)
mhpower.append(worldclasspower)
except ZeroDivisionError:
pass
for duration in durations:
worldclasspower = metrics.getagegrouprecord(
age,
sex='male',
duration=duration,
weightcategory='hwt'
)
try:
velo = (worldclasspower/2.8)**(1./3.)
distance = int(60*duration*velo)
mhduration.append(60.*duration)
mhpower.append(worldclasspower)
except ValueError:
pass
fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3]))
errfunc = lambda pars,x,y: fitfunc(pars,x)-y
p0 = [500,350,10,8000]
# fitting WC data to three parameter CP model
if len(fhduration)>=4:
p1fh, success = optimize.leastsq(errfunc, p0[:],
args = (fhduration,fhpower))
else:
p1fh = None
# fitting WC data to three parameter CP model
if len(flduration)>=4:
p1fl, success = optimize.leastsq(errfunc, p0[:],
args = (flduration,flpower))
else:
p1fl = None
# fitting WC data to three parameter CP model
if len(mlduration)>=4:
p1ml, success = optimize.leastsq(errfunc, p0[:],
args = (mlduration,mlpower))
else:
p1ml = None
if len(mhduration)>=4:
p1mh, success = optimize.leastsq(errfunc, p0[:],
args = (mhduration,mhpower))
else:
p1mh = None
fitt = pd.Series(10**(4*np.arange(100)/100.))
fitpowerfh = fitfunc(p1fh,fitt)
fitpowerfl = fitfunc(p1fl,fitt)
fitpowerml = fitfunc(p1ml,fitt)
fitpowermh = fitfunc(p1mh,fitt)
if normalized:
facfh = fitfunc(p1fh,60)
facfl = fitfunc(p1fl,60)
facml = fitfunc(p1ml,60)
facmh = fitfunc(p1mh,60)
fitpowerfh /= facfh
fitpowerfl /= facfl
fitpowermh /= facmh
fitpowerml /= facml
fhpower /= facfh
flpower /= facfl
mlpower /= facml
mhpower /= facmh
source = ColumnDataSource(
data = dict(
duration = fitt,
fitpowerfh = fitpowerfh,
fitpowerfl = fitpowerfl,
fitpowerml = fitpowerml,
fitpowermh = fitpowermh,
flduration = flduration,
flpower = flpower,
fhduration = fhduration,
fhpower = fhpower,
mlduration = mlduration,
mlpower = mlpower,
mhduration = mhduration,
mhpower = mhpower,
)
)
x_axis_type = 'log'
y_axis_type = 'linear'
plot = Figure(plot_width=900,x_axis_type=x_axis_type)
plot.line('duration','fitpowerfh',source=source,
legend='Female HW',color='blue')
plot.line('duration','fitpowerfl',source=source,
legend='Female LW',color='red')
plot.line('duration','fitpowerml',source=source,
legend='Male LW',color='green')
plot.line('duration','fitpowermh',source=source,
legend='Male HW',color='orange')
plot.circle('flduration','flpower',source=source,
fill_color='red',size=15)
plot.circle('fhduration','fhpower',source=source,
fill_color='blue',size=15)
plot.circle('mlduration','mlpower',source=source,
fill_color='green',size=15)
plot.circle('mhduration','mhpower',source=source,
fill_color='orange',size=15)
plot.title.text = 'age '+str(age)
plot.xaxis.axis_label = "Duration (seconds)"
if normalized:
plot.yaxis.axis_label = "Power (normalized)"
else:
plot.yaxis.axis_label = "Power (W)"
script,div = components(plot)
return script,div
def interactive_otwcpchart(powerdf,promember=0,rowername=""):
powerdf = powerdf[~(powerdf == 0).any(axis=1)]
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
x_axis_type = 'log'
y_axis_type = 'linear'
deltas = powerdf['Delta'].apply(lambda x: timedeltaconv(x))
powerdf['ftime'] = niceformat(deltas)
source = ColumnDataSource(
data = powerdf
)
# there is no Paul's law for OTW
thesecs = powerdf['Delta']
theavpower = powerdf['CP']
p1,fitt,fitpower,ratio = datautils.cpfit(powerdf)
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)
sourcecomplex = ColumnDataSource(
data = dict(
CP = fitpower,
CPmax = ratio*fitpower,
duration = fitt,
ftime = ftime
)
)
# making the plot
plot = Figure(tools=TOOLS,x_axis_type=x_axis_type,
plot_width=900,
toolbar_location="above",
toolbar_sticky=False)
# add watermark
plot.extra_y_ranges = {"watermark": watermarkrange}
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('Delta','CP',source=source,fill_color='red',size=15,
legend='Power Data')
plot.xaxis.axis_label = "Duration (seconds)"
plot.yaxis.axis_label = "Power (W)"
plot.y_range = Range1d(0,1.5*max(theavpower))
plot.x_range = Range1d(1,2*max(thesecs))
plot.legend.orientation = "vertical"
plot.title.text = "Critical Power for "+rowername
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Duration ','@ftime'),
('Power (W)','@CP{int}'),
('Power (W) upper','@CPmax{int}'),
])
hover.mode = 'mouse'
plot.line('duration','CP',source=sourcecomplex,legend="CP Model",
color='green')
plot.line('duration','CPmax',source=sourcecomplex,legend="CP Model",
color='red')
script, div = components(plot)
return [script,div,p1,ratio,message]
def interactive_agegroup_plot(df,distance=2000,duration=None,
sex='male',weightcategory='hwt'):
if df.empty:
return '',''
age = df['age']
power = df['power']
name = df['name']
season = df['season']
if duration:
duration2 = int(duration/60.)
plottitle = sex+' '+weightcategory+' %s min' % duration2
else:
plottitle = sex+' '+weightcategory+' %s m' % distance
# poly_coefficients = np.polyfit(age,power,6)
age2 = np.linspace(11,95)
# poly_vals = np.polyval(poly_coefficients,age2)
# poly_vals = 0.5*(np.abs(poly_vals)+poly_vals)
fitfunc = lambda pars, x: np.abs(pars[0])*(1-x/max(120,pars[1]))-np.abs(pars[2])*np.exp(-x/np.abs(pars[3]))+np.abs(pars[4])*(np.sin(np.pi*x/max(50,pars[5])))
errfunc = lambda pars, x,y: fitfunc(pars,x)-y
p0 = [700,120,700,10,100,100]
p1, success = optimize.leastsq(errfunc,p0[:],
args = (age,power))
expo_vals = fitfunc(p1, age2)
expo_vals = 0.5*(np.abs(expo_vals)+expo_vals)
source = ColumnDataSource(
data = dict(
age = age,
power = power,
age2 = age2,
expo_vals = expo_vals,
season = season,
name=name,
)
)
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
plot = Figure(tools=TOOLS,plot_width=900)
plot.circle('age','power',source=source,fill_color='red',size=15,
legend='World Record')
plot.line(age2,expo_vals)
plot.xaxis.axis_label = "Age"
plot.yaxis.axis_label = "Concept2 power"
plot.title.text = plottitle
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Name ','@name'),
('Season ','@season'),
])
hover.mode = 'mouse'
script,div = components(plot)
return script,div
def interactive_cpchart(rower,thedistances,thesecs,theavpower,
theworkouts,promember=0,
wcpower=[],wcdurations=[]):
message = 0
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
x_axis_type = 'log'
y_axis_type = 'linear'
thesecs = pd.Series(thesecs)
velo = thedistances/thesecs
p = pd.Series(500./velo)
p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
source = ColumnDataSource(
data = dict(
dist = thedistances,
duration = thesecs,
spm = 0*theavpower,
tim = niceformat(
thesecs.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
),
power = theavpower,
fpace = nicepaceformat(p2),
)
)
# fitting the data to Paul
if len(thedistances)>=2:
paulslope, paulintercept,r,p,stderr = linregress(np.log10(thedistances),p)
else:
paulslope = 5.0/np.log10(2.0)
paulintercept = p[0]-paulslope*np.log10(thedistances[0])
fitx = pd.Series(np.arange(100)*2*max(np.log10(thedistances))/100.)
fitp = paulslope*fitx+paulintercept
fitvelo = 500./fitp
fitpower = 2.8*(fitvelo**3)
fitt = 10**fitx/fitvelo
fitp2 = fitp.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
sourcepaul = ColumnDataSource(
data = dict(
dist = 10**fitx,
duration = fitt,
power = fitpower,
spm = 0*fitpower,
tim = niceformat(
fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
),
fpace = nicepaceformat(fitp2),
)
)
fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3]))
errfunc = lambda pars,x,y: fitfunc(pars,x)-y
p0 = [500,350,10,8000]
wcpower = pd.Series(wcpower)
wcdurations = pd.Series(wcdurations)
# fitting WC data to three parameter CP model
if len(wcdurations)>=4:
p1wc, success = optimize.leastsq(errfunc, p0[:],
args = (wcdurations,wcpower))
else:
p1wc = None
# fitting the data to three parameter CP model
success = 0
p1 = p0
if len(thesecs)>=4:
p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower))
else:
factor = fitfunc(p0,thesecs.mean())/theavpower.mean()
p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]]
success = 0
# Get stayer score
if success == 1:
power1min = fitfunc(p1,60.)
power4min = fitfunc(p1,240.)
power6min = fitfunc(p1,360.)
power30min = fitfunc(p1,1800.)
power1h = fitfunc(p1,3600.)
power10sec = fitfunc(p1,10.)
r10sec4min = 100.*power10sec/power4min
r1h4min = 100.*power1h/power4min
r1min6min = 100.*power1min/power6min
r30min6min = 100.*power30min/power6min
combined = r1h4min-0.2*(r10sec4min-100)
combined2 = r30min6min-1.5*(r1min6min-100)
dataset = pd.read_csv('static/stats/combined_set.csv')
dataset2 = pd.read_csv('static/stats/combined_set6min.csv')
stayerscore = int(percentileofscore(dataset['combined'],combined))
stayerscore2 = int(percentileofscore(dataset2['combined'],combined2))
else:
stayerscore = None
stayerscore2 = None
fitt = pd.Series(10**(4*np.arange(100)/100.))
fitpower = fitfunc(p1,fitt)
if p1wc is not None:
fitpowerwc = 0.95*fitfunc(p1wc,fitt)
fitpowerexcellent = 0.7*fitfunc(p1wc,fitt)
fitpowergood = 0.6*fitfunc(p1wc,fitt)
fitpowerfair = 0.5*fitfunc(p1wc,fitt)
fitpoweraverage = 0.4*fitfunc(p1wc,fitt)
else:
fitpowerwc = 0*fitpower
fitpowerexcellent = 0*fitpower
fitpowergood = 0*fitpower
fitpowerfair = 0*fitpower
fitpoweraverage = 0*fitpower
message = ""
if len(fitpower[fitpower<0]) > 0:
message = "CP model fit didn't give correct results"
fitvelo = (fitpower/2.8)**(1./3.)
fitdist = fitt*fitvelo
fitp = 500./fitvelo
fitp2 = fitp.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
sourcecomplex = ColumnDataSource(
data = dict(
dist = fitdist,
duration = fitt,
tim = niceformat(
fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
),
spm = 0*fitpower,
power = fitpower,
fitpowerwc = fitpowerwc,
fitpowerexcellent = fitpowerexcellent,
fitpowergood = fitpowergood,
fitpowerfair = fitpowerfair,
fitpoweraverage = fitpoweraverage,
fpace = nicepaceformat(fitp2),
)
)
# making the plot
plot = Figure(tools=TOOLS,x_axis_type=x_axis_type,
plot_width=900,
toolbar_location="above",
toolbar_sticky=False)
# add watermark
plot.extra_y_ranges = {"watermark": watermarkrange}
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='Power')
plot.xaxis.axis_label = "Duration (seconds)"
plot.yaxis.axis_label = "Power (W)"
if stayerscore is not None:
plot.add_layout(
Label(x=100,y=100,x_units='screen',y_units='screen',
text='Stayer Score '+str(stayerscore)+'%',
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black')
)
# plot.add_layout(
# Label(x=100,y=120,x_units='screen',y_units='screen',
# text='Stayer Score (6min) '+str(stayerscore2)+'%',
# background_fill_alpha=0.7,
# background_fill_color='white',
# text_color='black')
# )
cpdata = dataprep.fetchcperg(rower, theworkouts)
if cpdata.empty:
message = 'Calculations are running in the background. Please refresh this page to see updated results'
return ['','',paulslope,paulintercept,p1,message,p1wc]
velo = cpdata['distance']/cpdata['delta']
p = 500./velo
p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
source2 = ColumnDataSource(
data = dict(
duration = cpdata['delta'],
power = cpdata['cp'],
tim = niceformat(
cpdata['delta'].fillna(method='ffill').apply(lambda x: timedeltaconv(x))
),
dist = cpdata['distance'],
pace = nicepaceformat(p2),
)
)
plot.circle('duration','power',source=source2,
fill_color='blue',size=3,
legend = 'Power from segments')
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Duration ','@tim'),
('Power (W)','@power{int}'),
('Distance (m)','@dist{int}'),
('Pace (/500m)','@fpace'),
])
hover.mode = 'mouse'
plot.y_range = Range1d(0,1.5*max(theavpower))
plot.x_range = Range1d(1,2*max(thesecs))
plot.legend.orientation = "vertical"
plot.line('duration','power',source=sourcepaul,legend="Paul's Law")
plot.line('duration','power',source=sourcecomplex,legend="CP Model",
color='green')
if p1wc is not None:
plot.line('duration','fitpowerwc',source=sourcecomplex,
legend="World Class",
color='Maroon',line_dash='dotted')
plot.line('duration','fitpowerexcellent',source=sourcecomplex,
legend="90% percentile",
color='Purple',line_dash='dotted')
plot.line('duration','fitpowergood',source=sourcecomplex,
legend="75% percentile",
color='Olive',line_dash='dotted')
plot.line('duration','fitpowerfair',source=sourcecomplex,
legend="50% percentile",
color='Gray',line_dash='dotted')
plot.line('duration','fitpoweraverage',source=sourcecomplex,
legend="25% percentile",
color='SkyBlue',line_dash='dotted')
script, div = components(plot)
return [script,div,paulslope,paulintercept,p1,message,p1wc]
def interactive_windchart(id=0,promember=0):
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
f1 = row.csvfilename
# create interactive plot
plot = Figure(plot_width=400,plot_height=300)
# get user
# u = User.objects.get(id=row.user.id)
r = row.user
u = r.user
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an,ftp=r.ftp)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return 0
dist = rowdata.df.ix[:,'cum_dist']
try:
vwind = rowdata.df.ix[:,'vwind']
winddirection = rowdata.df.ix[:,'winddirection']
bearing = rowdata.df.ix[:,'bearing']
except KeyError:
rowdata.add_wind(0,0)
rowdata.add_bearing()
vwind = rowdata.df.ix[:,'vwind']
winddirection = rowdata.df.ix[:,'winddirection']
bearing = rowdata.df.ix[:,'winddirection']
rowdata.write_csv(f1,gzip=True)
dataprep.update_strokedata(id,rowdata.df)
winddirection = winddirection % 360
winddirection = (winddirection + 360) % 360
tw = tailwind(bearing,vwind,1.0*winddirection)
source = ColumnDataSource(
data = dict(
dist=dist,
vwind=vwind,
tw=tw,
winddirection=winddirection,
)
)
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
# making the plot
plot = Figure(tools=TOOLS,plot_width=400,height=500,
# toolbar_location="below",
toolbar_sticky=False,
)
plot.line('dist','vwind',source=source,legend="Wind Speed (m/s)")
plot.line('dist','tw',source=source,legend="Tail (+)/Head (-) Wind (m/s)",color='black')
plot.title.text = row.name
# plot.title.text_font_size=value("1.0em")
plot.title.text_font="1.0em"
plot.xaxis.axis_label = "Distance (m)"
plot.yaxis.axis_label = "Wind Speed (m/s)"
plot.y_range = Range1d(-7,7)
plot.extra_y_ranges = {"winddirection": Range1d(start=0,end=360)}
plot.line('dist','winddirection',source=source,
legend='Wind Direction',color="red",
y_range_name="winddirection")
plot.add_layout(LinearAxis(y_range_name="winddirection",axis_label="Wind Direction (degree)"),'right')
script, div = components(plot)
return [script,div]
def interactive_streamchart(id=0,promember=0):
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
f1 = row.csvfilename
# create interactive plot
plot = Figure(plot_width=400,
)
# get user
# u = User.objects.get(id=row.user.id)
r = row.user
u = r.user
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an,ftp=r.ftp)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return "","No Valid Data Available"
dist = rowdata.df.ix[:,'cum_dist']
try:
vstream = rowdata.df.ix[:,'vstream']
except KeyError:
rowdata.add_stream(0)
vstream = rowdata.df.ix[:,'vstream']
rowdata.write_csv(f1,gzip=True)
dataprep.update_strokedata(id,rowdata.df)
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
# making the plot
plot = Figure(tools=TOOLS,plot_width=400,height=500,
# toolbar_location="below",
toolbar_sticky=False,
)
plot.line(dist,vstream,legend="River Stream Velocity (m/s)")
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.xaxis.axis_label = "Distance (m)"
plot.yaxis.axis_label = "River Current (m/s)"
plot.y_range = Range1d(-2,2)
script, div = components(plot)
return [script,div]
def interactive_chart(id=0,promember=0):
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
columns = ['time','pace','hr','fpace','ftime']
datadf = dataprep.getsmallrowdata_db(columns,ids=[id])
datadf.dropna(axis=0,how='any',inplace=True)
row = Workout.objects.get(id=id)
if datadf.empty:
return "","No Valid Data Available"
else:
datadf.sort_values(by='time',ascending=True,inplace=True)
#datadf,row = dataprep.getrowdata_db(id=id)
#if datadf.empty:
#return "","No Valid Data Available"
source = ColumnDataSource(
datadf
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
plot_width=400,
plot_height=400,
toolbar_sticky=False,
tools=TOOLS)
# add watermark
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="Pace")
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.xaxis.axis_label = "Time"
plot.yaxis.axis_label = "Pace (/500m)"
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
ymax = 90.
ymin = 150.
if row.workouttype == 'water':
ymax = 90.
ymin = 210.
plot.y_range = Range1d(1.e3*ymin,1.e3*ymax)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Pace','@fpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
])
hover.mode = 'mouse'
plot.extra_y_ranges["hrax"] = Range1d(start=100,end=200)
plot.line('time','hr',source=source,color="red",
y_range_name="hrax", legend="Heart Rate")
plot.add_layout(LinearAxis(y_range_name="hrax",axis_label="HR"),'right')
plot.legend.location = "bottom_right"
script, div = components(plot)
return [script,div]
def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
ploterrorbars=False,
title=None,binsize=1,colorlegend=[]):
if datadf.empty:
return ['','<p>No non-zero data in selection</p>']
if xparam == 'workoutid':
xparamname = 'Workout'
else:
xparamname = axlabels[xparam]
if yparam == 'workoutid':
yparamname = 'Workout'
else:
yparamname = axlabels[yparam]
if groupby == 'workoutid':
groupname = 'Workout'
elif groupby == 'date':
groupname = 'Date'
else:
groupname = axlabels[groupby]
if title==None:
title = '{y} vs {x} grouped by {gr}'.format(
x = xparamname,
y = yparamname,
gr = groupname,
)
if xparam=='distance':
xaxmax = datadf[xparam].max()
xaxmin = datadf[xparam].min()
elif xparam=='time':
tseconds = datadf.ix[:,'time']
xaxmax = tseconds.max()
xaxmin = 0
elif xparam == 'workoutid':
xaxmax = datadf[xparam].max()-5
xaxmin = datadf[xparam].min()+5
else:
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
if yparam=='distance':
yaxmax = datadf[yparam].max()
yaxmin = datadf[yparam].min()
elif yparam=='time':
tseconds = datadf.ix[:,'time']
yaxmax = tseconds.max()
yaxmin = 0
elif yparam == 'workoutid':
yaxmax = datadf[yparam].max()-5
yaxmin = datadf[yparam].min()+5
else:
yaxmax = yaxmaxima[yparam]
yaxmin = yaxminima[yparam]
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam == 'pace':
y_axis_type = 'datetime'
source = ColumnDataSource(
datadf,
)
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize'
if groupby != 'date':
hover = HoverTool(names=['data'],
tooltips = [
(groupby,'@groupval{1.1}'),
(xparamname,'@x{1.1}'),
(yparamname,'@y')
])
else:
hover = HoverTool(names=['data'],
tooltips = [
(groupby,'@groupval'),
(xparamname,'@x{1.1}'),
(yparamname,'@y')
,
])
hover.mode = 'mouse'
TOOLS = [SaveTool(),PanTool(),BoxZoomTool(),WheelZoomTool(),
ResetTool(),TapTool(),ResizeTool(),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=500,plot_height=500)
# add watermark
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.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=400+20*nr,left=550,top=420+20*nr,
right=570,
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=571,y=403+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=value("0.7em"))
plot.add_layout(box)
plot.add_layout(legendlabel)
if colorlegend:
legendlabel = Label(x=372,y=300,x_units='screen',
y_units='screen',
text = 'group legend',
text_color='black',
text_font_size=value("0.7em"),
angle=90,
angle_units='deg')
if xparam == 'workoutid':
plot.xaxis.axis_label = 'Workout'
else:
plot.xaxis.axis_label = axlabels[xparam]
if yparam == 'workoutid':
plot.xaxis.axis_label = 'Workout'
else:
plot.yaxis.axis_label = axlabels[yparam]
binlabel = Label(x=100,y=100,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',
)
plot.add_layout(binlabel)
yrange1 = Range1d(start=yaxmin,end=yaxmax)
plot.y_range = yrange1
xrange1 = Range1d(start=xaxmin,end=xaxmax)
plot.x_range = xrange1
if yparam == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
script,div = components(plot)
return [script,div]
def interactive_cum_flex_chart2(theworkouts,promember=0,
xparam='spm',
yparam1='power',
yparam2='spm',
workstrokesonly=False):
# datadf = dataprep.smalldataprep(theworkouts,xparam,yparam1,yparam2)
ids = [int(w.id) for w in theworkouts]
columns = [xparam,yparam1,yparam2,'spm','driveenergy','distance']
datadf = dataprep.getsmallrowdata_db(columns,ids=ids,doclean=True,
workstrokesonly=workstrokesonly)
try:
tests = datadf[yparam2]
except KeyError:
yparam2 = 'None'
try:
tests = datadf[yparam1]
except KeyError:
yparam1 = 'None'
datadf.dropna(axis=1,how='all',inplace=True)
datadf.dropna(axis=0,how='any',inplace=True)
# test if we have drive energy
nowork = 1
try:
test = datadf['driveenergy'].mean()
nowork = 0
except KeyError:
datadf['driveenergy'] = 500.
# test if we have power
nopower = 1
try:
test = datadf['power'].mean()
nopower = 0
except KeyError:
datadf['power'] = 50.
yparamname1 = axlabels[yparam1]
if yparam2 != 'None':
yparamname2 = axlabels[yparam2]
# check if dataframe not empty
if datadf.empty:
return ['','<p>No non-zero data in selection</p>','','']
try:
datadf['x1'] = datadf.ix[:,xparam]
except KeyError:
try:
datadf['x1'] = datadf['distance']
except KeyError:
try:
datadf['x1'] = datadf['time']
except KeyError:
return ['','<p>No non-zero data in selection</p>','','']
try:
datadf['y1'] = datadf.ix[:,yparam1]
except KeyError:
try:
datadf['y1'] = datadf['pace']
except KeyError:
return ['','<p>No non-zero data in selection</p>','','']
if yparam2 != 'None':
try:
datadf['y2'] = datadf.ix[:,yparam2]
except KeyError:
datadf['y2'] = datadf['y1']
else:
datadf['y2'] = datadf['y1']
if xparam=='distance':
xaxmax = datadf['x1'].max()
xaxmin = datadf['x1'].min()
else:
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
# average values
x1mean = datadf['x1'].mean()
y1mean = datadf['y1'].mean()
y2mean = datadf['y2'].mean()
xvals = pd.Series(xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.)
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
y1mean = datadf.ix[:,'pace'].mean()
datadf['xname'] = axlabels[xparam]
datadf['yname1'] = axlabels[yparam1]
if yparam2 != 'None':
datadf['yname2'] = axlabels[yparam2]
else:
datadf['yname2'] = axlabels[yparam1]
source = ColumnDataSource(
datadf
)
source2 = ColumnDataSource(
datadf.copy()
)
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
toolbar_location="above",
toolbar_sticky=False)
# add watermark
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",
)
x1means = Span(location=x1mean,dimension='height',line_color='green',
line_dash=[6,6], line_width=2)
y1means = Span(location=y1mean,dimension='width',line_color='blue',
line_dash=[6,6],line_width=2)
y2means = y1means
xlabel = Label(x=100,y=130,x_units='screen',y_units='screen',
text=axlabels[xparam]+": {x1mean:6.2f}".format(x1mean=x1mean),
background_fill_alpha=.7,
background_fill_color='white',
text_color='green',
)
plot.add_layout(x1means)
plot.add_layout(xlabel)
plot.add_layout(y1means)
y1label = Label(x=100,y=100,x_units='screen',y_units='screen',
text=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=yparamname1,
)
plot.xaxis.axis_label = axlabels[xparam]
plot.yaxis.axis_label = axlabels[yparam1]
yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
plot.y_range = yrange1
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
plot.x_range = xrange1
if yparam1 == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
if yparam2 != 'None':
yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2])
plot.extra_y_ranges["yax2"] = yrange2
plot.circle('x1','y2',color="red",y_range_name="yax2",
legend=yparamname2,
source=source2,fill_alpha=0.3,line_color=None)
plot.add_layout(LinearAxis(y_range_name="yax2",
axis_label=axlabels[yparam2]),'right')
y2means = Span(location=y2mean,dimension='width',line_color='red',
line_dash=[6,6],line_width=2,y_range_name="yax2")
plot.add_layout(y2means)
y2label = Label(x=100,y=70,x_units='screen',y_units='screen',
text=axlabels[yparam2]+": {y2mean:6.2f}".format(y2mean=y2mean),
background_fill_alpha=.7,
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,
y2means=y2means), code="""
var data = source.data
var data2 = source2.data
var x1 = data['x1']
var y1 = data['y1']
var y2 = data['y2']
var spm1 = data['spm']
var distance1 = data['distance']
var driveenergy1 = data['driveenergy']
var xname = data['xname'][0]
var yname1 = data['yname1'][0]
var yname2 = data['yname2'][0]
var minspm = minspm.value
var maxspm = maxspm.value
var mindist = mindist.value
var maxdist = maxdist.value
var minwork = minwork.value
var maxwork = maxwork.value
var xm = 0
var ym1 = 0
var ym2 = 0
data2['x1'] = []
data2['y1'] = []
data2['y2'] = []
data2['spm'] = []
data2['distance'] = []
data2['x1mean'] = []
data2['y1mean'] = []
data2['y2mean'] = []
data2['xvals'] = []
data2['y1vals'] = []
data2['y2vals'] = []
for (i=0; i<x1.length; i++) {
if (spm1[i]>=minspm && spm1[i]<=maxspm) {
if (distance1[i]>=mindist && distance1[i]<=maxdist) {
if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
data2['x1'].push(x1[i])
data2['y1'].push(y1[i])
data2['y2'].push(y2[i])
data2['spm'].push(spm1[i])
data2['distance'].push(distance1[i])
xm += x1[i]
ym1 += y1[i]
ym2 += y2[i]
}
}
}
}
xm /= data2['x1'].length
ym1 /= data2['x1'].length
ym2 /= data2['x1'].length
data2['x1mean'] = [xm,xm]
data2['y1mean'] = [ym1,ym1]
data2['y2mean'] = [ym2,ym2]
x1means.location = xm
y1means.location = ym1
y2means.location = ym2
y1label.text = yname1+': '+(ym1).toFixed(2)
y2label.text = yname2+': '+(ym2).toFixed(2)
xlabel.text = xname+': '+(xm).toFixed(2)
source2.trigger('change');
""")
slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1,
title="Min SPM",callback=callback)
callback.args["minspm"] = slider_spm_min
slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1,
title="Max SPM",callback=callback)
callback.args["maxspm"] = slider_spm_max
slider_work_min = Slider(start=0.0, end=1500,value=0.0, step=10,
title="Min Work per Stroke",callback=callback)
callback.args["minwork"] = slider_work_min
slider_work_max = Slider(start=0.0, end=1500,value=1500.0, step=10,
title="Max Work per Stroke",callback=callback)
callback.args["maxwork"] = slider_work_max
distmax = 100+100*int(datadf['distance'].max()/100.)
slider_dist_min = Slider(start=0,end=distmax,value=0,step=1,
title="Min Distance",callback=callback)
callback.args["mindist"] = slider_dist_min
slider_dist_max = Slider(start=0,end=distmax,value=distmax,
step=1,
title="Max Distance",callback=callback)
callback.args["maxdist"] = slider_dist_max
layout = layoutrow([layoutcolumn([slider_spm_min,
slider_spm_max,
slider_dist_min,
slider_dist_max,
slider_work_min,
slider_work_max,
],
),
plot])
script, div = components(layout)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
return [script,div,js_resources,css_resources]
def interactive_flex_chart2(id=0,promember=0,
xparam='time',
yparam1='pace',
yparam2='hr',
plottype='line',
workstrokesonly=False):
#rowdata,row = dataprep.getrowdata_db(id=id)
columns = [xparam,yparam1,yparam2,
'ftime','distance','fpace',
'power','hr','spm','driveenergy',
'time','pace','workoutstate','time']
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True,
workstrokesonly=workstrokesonly)
if rowdata.empty:
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True,
workstrokesonly=False)
workstrokesonly=False
if rowdata.empty:
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],
doclean=False,
workstrokesonly=False)
workstrokesonly=False
try:
tests = rowdata[yparam2]
except KeyError:
yparam2 = 'None'
try:
tests = rowdata[yparam1]
except KeyError:
yparam1 = 'None'
# test if we have drive energy
nowork = 1
try:
test = rowdata['driveenergy'].mean()
nowork = 0
except KeyError:
rowdata['driveenergy'] = 500.
# test if we have power
nopower = 1
try:
test = rowdata['power'].mean()
nopower = 0
except KeyError:
rowdata['power'] = 50.
row = Workout.objects.get(id=id)
if rowdata.empty:
return "","No valid data",'','',workstrokesonly
else:
try:
rowdata.sort_values(by='time',ascending=True,inplace=True)
except KeyError:
pass
workoutstateswork = [1,4,5,8,9,6,7]
workoutstatesrest = [3]
workoutstatetransition = [0,2,10,11,12,13]
if workstrokesonly:
try:
rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)]
except KeyError:
pass
try:
tseconds = rowdata.ix[:,'time']
except KeyError:
return '','No time data - cannot make flex plot','','',workstrokesonly
try:
rowdata['x1'] = rowdata.ix[:,xparam]
rowmin = rowdata[xparam].min()
except KeyError:
rowdata['x1'] = 0*rowdata.ix[:,'time']
try:
rowdata['y1'] = rowdata.ix[:,yparam1]
rowmin = rowdata[yparam1].min()
except KeyError:
rowdata['y1'] = 0*rowdata.ix[:,'time']
rowdata[yparam1] = rowdata['y1']
if yparam2 != 'None':
try:
rowdata['y2'] = rowdata.ix[:,yparam2]
rowmin = rowdata[yparam2].min()
except KeyError:
rowdata['y2'] = 0*rowdata.ix[:,'time']
rowdata[yparam2] = rowdata['y2']
else:
rowdata['y2'] = rowdata['y1']
if xparam=='time':
xaxmax = tseconds.max()
xaxmin = tseconds.min()
elif xparam=='distance' or xparam=='cumdist':
xaxmax = rowdata['x1'].max()
xaxmin = rowdata['x1'].min()
else:
try:
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
except KeyError:
xaxmax = rowdata['x1'].max()
xaxmin = rowdata['x1'].min()
# average values
if xparam != 'time':
try:
x1mean = rowdata['x1'].mean()
except TypeError:
x1mean = 0
else:
x1mean = 0
y1mean = rowdata['y1'].mean()
y2mean = rowdata['y2'].mean()
if xparam != 'time':
xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.
else:
xvals = np.arange(100)
# constant power plot
if yparam1 == 'driveenergy':
if xparam == 'spm':
yconstantpower = rowdata['y1'].mean()*rowdata['x1'].mean()/xvals
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
try:
y1mean = rowdata.ix[:,'pace'].mean()
except KeyError:
y1mean = 0
try:
rowdata['xname'] = axlabels[xparam]
except KeyError:
rowdata['xname'] = xparam
try:
rowdata['yname1'] = axlabels[yparam1]
except KeyError:
rowdata['yname1'] = yparam1
if yparam2 != 'None':
try:
rowdata['yname2'] = axlabels[yparam2]
except KeyError:
rowdata['yname2'] = yparam2
else:
rowdata['yname2'] = rowdata['yname1']
# prepare data
source = ColumnDataSource(
rowdata
)
# second source for filtering
source2 = ColumnDataSource(
rowdata.copy()
)
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
sizing_mode = 'fixed' # 'scale_width' also looks nice with this example
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
toolbar_sticky=False
)
# add watermark
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",
)
x1means = Span(location=x1mean,dimension='height',line_color='green',
line_dash=[6,6], line_width=2)
y1means = Span(location=y1mean,dimension='width',line_color='blue',
line_dash=[6,6],line_width=2)
y2means = y1means
try:
xlabeltext = axlabels[xparam]+": {x1mean:6.2f}".format(
x1mean=x1mean
)
except KeyError:
xlabeltext = xparam+": {x1mean:6.2f}".format(x1mean=x1mean)
xlabel = Label(x=100,y=130,x_units='screen',y_units='screen',
text=xlabeltext,
background_fill_alpha=.7,
background_fill_color='white',
text_color='green',
)
annolabel = Label(x=100,y=500,x_units='screen',y_units='screen',
text='',
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black',
)
if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
plot.add_layout(x1means)
plot.add_layout(xlabel)
plot.add_layout(y1means)
plot.add_layout(annolabel)
try:
yaxlabel = axlabels[yparam1]
except KeyError:
yaxlabel = str(yparam1)+' '
try:
xaxlabel = axlabels[xparam]
except KeyError:
xaxlabel = xparam
y1label = Label(x=100,y=100,x_units='screen',y_units='screen',
text=yaxlabel+": {y1mean:6.2f}".format(y1mean=y1mean),
background_fill_alpha=.7,
background_fill_color='white',
text_color='blue',
)
if yparam1 != 'time' and yparam1 != 'pace':
plot.add_layout(y1label)
y2label = y1label
# average values
if yparam1 == 'driveenergy':
if xparam == 'spm':
plot.line(xvals,yconstantpower,color="green",legend="Constant Power")
if plottype=='line':
plot.line('x1','y1',source=source2,legend=yaxlabel)
elif plottype=='scatter':
plot.scatter('x1','y1',source=source2,legend=yaxlabel,fill_alpha=0.4,
line_color=None)
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.xaxis.axis_label = xaxlabel
plot.yaxis.axis_label = yaxlabel
try:
yrange1 = Range1d(start=yaxminima[yparam1],
end=yaxmaxima[yparam1])
except KeyError:
yrange1 = Range1d(start=rowdata[yparam1].min(),
end=rowdata[yparam1].max())
plot.y_range = yrange1
if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
try:
xrange1 = Range1d(start=yaxminima[xparam],
end=yaxmaxima[xparam])
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=yaxminima[yparam2],
end=yaxmaxima[yparam2])
except KeyError:
yrange2 = Range1d(start=rowdata[yparam2].min(),
end=rowdata[yparam2].max())
plot.extra_y_ranges["yax2"] = yrange2
#= {"yax2": yrange2}
try:
axlegend = axlabels[yparam2]
except KeyError:
axlegend = str(yparam2)+' '
if plottype=='line':
plot.line('x1','y2',color="red",y_range_name="yax2",
legend=axlegend,
source=source2)
elif plottype=='scatter':
plot.scatter('x1','y2',source=source2,legend=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=100,y=70,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,
y2means=y2means,
), code="""
var data = source.data
var data2 = source2.data
var x1 = data['x1']
var y1 = data['y1']
var y2 = data['y2']
var spm1 = data['spm']
var time1 = data['time']
var pace1 = data['pace']
var hr1 = data['hr']
var fpace1 = data['fpace']
var distance1 = data['distance']
var power1 = data['power']
var driveenergy1 = data['driveenergy']
var xname = data['xname'][0]
var yname1 = data['yname1'][0]
var yname2 = data['yname2'][0]
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
var xm = 0
var ym1 = 0
var ym2 = 0
data2['x1'] = []
data2['y1'] = []
data2['y2'] = []
data2['spm'] = []
data2['time'] = []
data2['pace'] = []
data2['hr'] = []
data2['fpace'] = []
data2['distance'] = []
data2['power'] = []
data2['x1mean'] = []
data2['y1mean'] = []
data2['y2mean'] = []
data2['xvals'] = []
data2['y1vals'] = []
data2['y2vals'] = []
for (i=0; i<x1.length; i++) {
if (spm1[i]>=minspm && spm1[i]<=maxspm) {
if (distance1[i]>=mindist && distance1[i]<=maxdist) {
if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
data2['x1'].push(x1[i])
data2['y1'].push(y1[i])
data2['y2'].push(y2[i])
data2['spm'].push(spm1[i])
data2['time'].push(time1[i])
data2['fpace'].push(fpace1[i])
data2['pace'].push(pace1[i])
data2['hr'].push(hr1[i])
data2['distance'].push(distance1[i])
data2['power'].push(power1[i])
xm += x1[i]
ym1 += y1[i]
ym2 += y2[i]
}
}
}
}
xm /= data2['x1'].length
ym1 /= data2['x1'].length
ym2 /= data2['x1'].length
data2['x1mean'] = [xm,xm]
data2['y1mean'] = [ym1,ym1]
data2['y2mean'] = [ym2,ym2]
x1means.location = xm
y1means.location = ym1
y2means.location = ym2
y1label.text = yname1+': '+ym1.toFixed(2)
y2label.text = yname2+': '+ym2.toFixed(2)
xlabel.text = xname+': '+xm.toFixed(2)
annolabel.text = annotation
source2.trigger('change');
""")
annotation = TextInput(title="Type your plot notes here", value="",
callback=callback)
callback.args["annotation"] = annotation
slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1,
title="Min SPM",callback=callback)
callback.args["minspm"] = slider_spm_min
slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1,
title="Max SPM",callback=callback)
callback.args["maxspm"] = slider_spm_max
slider_work_min = Slider(start=0.0, end=1500,value=0.0, step=10,
title="Min Work per Stroke",callback=callback)
callback.args["minwork"] = slider_work_min
slider_work_max = Slider(start=0.0, end=1500,value=1500.0, step=10,
title="Max Work per Stroke",callback=callback)
callback.args["maxwork"] = slider_work_max
try:
distmax = 100+100*int(rowdata['distance'].max()/100.)
except (KeyError,ValueError):
distmax = 100
slider_dist_min = Slider(start=0,end=distmax,value=0,step=1,
title="Min Distance",callback=callback)
callback.args["mindist"] = slider_dist_min
slider_dist_max = Slider(start=0,end=distmax,value=distmax,
step=1,
title="Max Distance",callback=callback)
callback.args["maxdist"] = slider_dist_max
layout = layoutrow([layoutcolumn([annotation,
slider_spm_min,
slider_spm_max,
slider_dist_min,
slider_dist_max,
slider_work_min,
slider_work_max,
],
),
plot])
script, div = components(layout)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
return [script,div,js_resources,css_resources,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']
try:
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True)
except:
return [
{'script':"",
'div':"",
'notes':""
}]
rowdata.dropna(axis=1,how='all',inplace=True)
if rowdata.empty:
try:
rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=False,
workstrokesonly=False)
except:
return [
{'script':"",
'div':"",
'notes':""
}]
if rowdata.empty:
return [
{'script':"",
'div':"",
'notes':""
}]
else:
try:
rowdata.sort_values(by='time',ascending=True,inplace=True)
except KeyError:
pass
l = len(rowdata)
maxlength = 50
if l > maxlength:
bins = np.linspace(rowdata['time'].min(),rowdata['time'].max(),maxlength)
groups = rowdata.groupby(np.digitize(rowdata['time'],bins))
rowdata = groups.mean()
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.ix[:,'time']
except KeyError:
return '','No time data - cannot make flex plot','',''
try:
rowdata['x1'] = rowdata.ix[:,xparam]
except KeyError:
rowdata['x1'] = 0*rowdata.ix[:,'time']
try:
rowdata['y1'] = rowdata.ix[:,yparam1]
except KeyError:
rowdata['y1'] = 0*rowdata.ix[:,'time']
if yparam2 != 'None':
try:
rowdata['y2'] = rowdata.ix[:,yparam2]
except KeyError:
rowdata['y2'] = 0*rowdata.ix[:,'time']
else:
rowdata['y2'] = rowdata['y1']
if xparam=='time':
xaxmax = tseconds.max()
xaxmin = tseconds.min()
elif xparam=='distance' or xparam=='cumdist':
xaxmax = rowdata['x1'].max()
xaxmin = rowdata['x1'].min()
else:
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
y1mean = rowdata.ix[:,'pace'].mean()
rowdata['xname'] = axlabels[xparam]
try:
rowdata['yname1'] = axlabels[yparam1]
except KeyError:
rowdata['yname1'] = axlabels[xparam]
if yparam2 != 'None':
rowdata['yname2'] = axlabels[yparam2]
else:
rowdata['yname2'] = axlabels[yparam1]
# prepare data
source = ColumnDataSource(
rowdata
)
sizing_mode = 'fixed' # 'scale_width' 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.toolbar.logo = None
plot.toolbar_location = None
#plot.yaxis.visible = False
plot.xaxis.axis_label_text_font_size = "7pt"
plot.yaxis.axis_label_text_font_size = "7pt"
plot.xaxis.major_label_text_font_size = "7pt"
plot.yaxis.major_label_text_font_size = "7pt"
if plottype=='line':
plot.line('x1','y1',source=source)
elif plottype=='scatter':
plot.scatter('x1','y1',source=source,fill_alpha=0.4,
line_color=None)
try:
plot.xaxis.axis_label = axlabels[xparam]
except KeyError:
plot.xaxis.axis_label = 'X'
try:
plot.yaxis.axis_label = axlabels[yparam1]
except KeyError:
plot.yaxis.axis_label = 'Y'
yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
plot.y_range = yrange1
if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
plot.x_range = xrange1
if xparam == 'time':
xrange1 = Range1d(start=xaxmin,end=xaxmax)
plot.x_range = xrange1
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
if yparam1 == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
if yparam2 != 'None':
yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2])
plot.extra_y_ranges["yax2"] = yrange2
#= {"yax2": yrange2}
if plottype=='line':
plot.line('x1','y2',color="red",y_range_name="yax2",
source=source)
elif plottype=='scatter':
plot.scatter('x1','y2',source=source,
fill_alpha=0.4,
line_color=None,color="red",y_range_name="yax2")
plot.add_layout(LinearAxis(y_range_name="yax2",
axis_label=axlabels[yparam2],
major_label_text_font_size="7pt",
axis_label_text_font_size="7pt",
),'right',
)
script, div = components(plot)
return [script,div]
def interactive_bar_chart(id=0,promember=0):
# check if valid ID exists (workout exists)
rowdata,row = dataprep.getrowdata_db(id=id)
rowdata.dropna(axis=1,how='all',inplace=True)
rowdata.dropna(axis=0,how='any',inplace=True)
if rowdata.empty:
return "","No Valid Data Available"
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
source = ColumnDataSource(
rowdata
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
toolbar_sticky=False,
plot_width=920,
tools=TOOLS)
# add watermark
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.image_url([watermarkurl],0.01,0.99,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor='top_left',
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
plot.title.text = row.name
plot.title.text_font_size=value("1.0em")
plot.xaxis.axis_label = "Time"
plot.yaxis.axis_label = "Pace (/500m)"
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours ="",
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
plot.yaxis[0].formatter = DatetimeTickFormatter(
hours = "",
seconds = ["%S"],
minutes = ["%M"],
)
ymax = 1.0e3*90
ymin = 1.0e3*180
if row.workouttype == 'water':
ymax = 1.0e3*90
ymin = 1.0e3*210
plot.y_range = Range1d(ymin,ymax)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Pace','@fpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
])
hover.mode = 'mouse'
plot.extra_y_ranges["hr"] = Range1d(start=100,end=200)
plot.quad(left='time',top='hr_ut2',bottom='hr_bottom',
right='x_right',source=source,color="gray",
y_range_name="hr", legend="<UT2")
plot.quad(left='time',top='hr_ut1',bottom='hr_bottom',
right='x_right',source=source,color="tan",
y_range_name="hr", legend="UT2")
plot.quad(left='time',top='hr_at',bottom='hr_bottom',
right='x_right',source=source,color="green",
y_range_name="hr", legend="UT1")
plot.quad(left='time',top='hr_tr',bottom='hr_bottom',
right='x_right',source=source,color="blue",
y_range_name="hr", legend="AT")
plot.quad(left='time',top='hr_an',bottom='hr_bottom',
right='x_right',source=source,color="violet",
y_range_name="hr", legend="TR")
plot.quad(left='time',top='hr_max',bottom='hr_bottom',
right='x_right',source=source,color="red",
y_range_name="hr", legend="AN")
plot.add_layout(LinearAxis(y_range_name="hr",axis_label="HR"),'right')
plot.line('time','pace',source=source,legend="Pace",color="black")
script, div = components(plot)
return [script,div]
def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line',
promember=0,
labeldict=None):
message = ''
errormessage = ''
columns = [xparam,yparam,
'ftime','distance','fpace',
'power','hr','spm',
'time','pace','workoutstate',
'workoutid']
datadf = dataprep.getsmallrowdata_db(columns,ids=ids)
datadf.dropna(axis=1,how='all',inplace=True)
datadf.dropna(axis=0,how='any',inplace=True)
nrworkouts = len(ids)
tseconds = datadf.ix[:,'time']
yparamname = axlabels[yparam]
#datadf = datadf[datadf[yparam] > 0]
#datadf = datadf[datadf[xparam] > 0]
# check if dataframe not empty
if datadf.empty:
return ['','<p>No non-zero data in selection</p>','','No non-zero data in selection']
if xparam != 'distance' and xparam != 'time' and xparam != 'cumdist':
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
elif xparam == 'time':
xaxmax = tseconds.max()
xaxmin = tseconds.min()
else:
xaxmax = datadf['distance'].max()
xaxmin = datadf['distance'].min()
if yparam == 'distance':
yaxmin = datadf['distance'].min()
yaxmax = datadf['distance'].max()
elif yparam == 'cumdist':
yaxmin = datadf['cumdist'].min()
yaxmax = datadf['cumdist'].max()
else:
yaxmin = yaxminima[yparam]
yaxmax = yaxmaxima[yparam]
x_axis_type = 'linear'
y_axis_type = 'linear'
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
if yparam == 'pace':
y_axis_type = 'datetime'
yaxmax = 90.*1e3
yaxmin = 150.*1e3
if xparam == 'time':
x_axis_type = 'datetime'
if xparam != 'time':
xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.
else:
xvals = np.arange(100)
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
toolbar_location="above",
plot_width=920,
toolbar_sticky=False)
# add watermark
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
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
for id,color in itertools.izip(ids,colors):
group = datadf[datadf['workoutid']==int(id)].copy()
group.sort_values(by='time',ascending=True,inplace=True)
try:
group['x'] = group[xparam]
except KeyError:
group['x'] = group['time']
errormessage = xparam+' has no values. Plot invalid'
try:
group['y'] = group[yparam]
except KeyError:
group['y'] = 0.0*group['x']
ymean = group['y'].mean()
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:
legend=labeldict[id]
else:
legend=str(id)
if plottype=='line':
l1 = plot.line('x','y',source=source,color=color,legend=legend)
else:
l1 = plot.scatter('x','y',source=source,color=color,legend=legend,
fill_alpha=0.4,line_color=None)
plot.add_tools(HoverTool(renderers=[l1],tooltips=TIPS))
cntr += 1
plot.legend.location='bottom_right'
plot.xaxis.axis_label = axlabels[xparam]
plot.yaxis.axis_label = axlabels[yparam]
if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
plot.x_range = xrange1
yrange1 = Range1d(start=yaxmin,end=yaxmax)
plot.y_range = yrange1
if xparam == 'time':
xrange1 = Range1d(start=xaxmin,end=xaxmax)
plot.x_range = xrange1
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
if yparam == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
script, div = components(plot)
return [script,div,message,errormessage]
def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
promember=0,plottype='line'):
columns = [xparam,yparam,
'ftime','distance','fpace',
'power','hr','spm',
'time','pace','workoutstate']
# check if valid ID exists (workout exists)
#rowdata1,row1 = dataprep.getrowdata_db(id=id1)
#rowdata2,row2 = dataprep.getrowdata_db(id=id2)
rowdata1 = dataprep.getsmallrowdata_db(columns,ids=[id1])
rowdata2 = dataprep.getsmallrowdata_db(columns,ids=[id2])
for n in ['distance','power','hr','spm','time','pace','workoutstate']:
rowdata1[n].fillna(value=0,inplace=True)
rowdata2[n].fillna(value=0,inplace=True)
rowdata1.dropna(axis=1,how='all',inplace=True)
rowdata1.dropna(axis=0,how='any',inplace=True)
rowdata2.dropna(axis=1,how='all',inplace=True)
rowdata2.dropna(axis=0,how='any',inplace=True)
row1 = Workout.objects.get(id=id1)
row2 = Workout.objects.get(id=id2)
if rowdata1.empty:
return "","No Valid Data Available"
else:
rowdata1.sort_values(by='time',ascending=True,inplace=True)
if rowdata2.empty:
return "","No Valid Data Available"
else:
rowdata2.sort_values(by='time',ascending=True,inplace=True)
try:
x1 = rowdata1.ix[:,xparam]
x2 = rowdata2.ix[:,xparam]
y1 = rowdata1.ix[:,yparam]
y2 = rowdata2.ix[:,yparam]
except KeyError:
return "","No valid Data Available"
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam == 'pace':
y_axis_type = 'datetime'
ymax = 1.0e3*90
ymin = 1.0e3*180
if row1.workouttype == 'water':
ymax = 1.0e3*90
ymin = 1.0e3*210
ftime1 = rowdata1.ix[:,'ftime']
ftime2 = rowdata2.ix[:,'ftime']
hr1 = rowdata1.ix[:,'hr']
hr2 = rowdata2.ix[:,'hr']
fpace1 = rowdata1.ix[:,'fpace']
fpace2 = rowdata2.ix[:,'fpace']
distance1 = rowdata1.ix[:,'distance']
distance2 = rowdata2.ix[:,'distance']
spm1 = rowdata1.ix[:,'spm']
spm2 = rowdata2.ix[:,'spm']
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
data1 = pd.DataFrame(
dict(
x1=x1,
y1=y1,
ftime1=ftime1,
fpace1=fpace1,
hr1 = hr1,
spm1 = spm1,
distance1=distance1,
)
).dropna()
data2 = pd.DataFrame(
dict(
x2=x2,
y2=y2,
ftime2=ftime2,
fpace2=fpace2,
hr2 = hr2,
spm2 = spm2,
distance2=distance2,
)
).dropna()
source1 = ColumnDataSource(
data1
)
source2 = ColumnDataSource(
data2
)
ymean1 = data1['y1'].mean()
ymean2 = data2['y2'].mean()
# create interactive plot
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
plot_width=920,
toolbar_sticky=False)
# add watermark
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.image_url([watermarkurl],0.05,watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor='bottom_left',
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
TIPS = OrderedDict([
('time','@ftime1'),
('pace','@fpace1'),
('hr','@hr1'),
('spm','@spm1{1.1}'),
('distance','@distance1{5}'),
])
TIPS2 = OrderedDict([
('time','@ftime2'),
('pace','@fpace2'),
('hr','@hr2'),
('spm','@spm2{1.1}'),
('distance','@distance2{5}'),
])
hover1 = plot.select(type=HoverTool)
hover1.tooltips = TIPS
hover2 = plot.select(type=HoverTool)
hover2.tooltips = TIPS2
if plottype=='line':
l1 = plot.line('x1','y1',source=source1,
color="blue",legend=row1.name,
)
l2 = plot.line('x2','y2',source=source2,
color="red",legend=row2.name,
)
elif plottype=='scatter':
l1 = plot.scatter('x1','y1',source=source1,legend=row1.name,
fill_alpha=0.4,
line_color=None)
l2 = plot.scatter('x2','y2',source=source2,legend=row2.name,
fill_alpha=0.4,
line_color=None,color="red")
plot.add_tools(HoverTool(renderers=[l1],tooltips=TIPS))
plot.add_tools(HoverTool(renderers=[l2],tooltips=TIPS2))
plot.legend.location = "bottom_right"
plot.title.text = row1.name+' vs '+row2.name
plot.title.text_font_size=value("1.2em")
plot.xaxis.axis_label = axlabels[xparam]
plot.yaxis.axis_label = axlabels[yparam]
ylabel1 = Label(x=100,y=90,x_units='screen',y_units='screen',
text=axlabels[yparam]+": {ymean1:6.2f}".format(
ymean1=ymean1
),
background_fill_alpha=.7,
background_fill_color='white',
text_color='blue'
)
ylabel2 = Label(x=100,y=110,x_units='screen',y_units='screen',
text=axlabels[yparam]+": {ymean2:6.2f}".format(
ymean2=ymean2
),
background_fill_alpha=.7,
background_fill_color='white',
text_color='red'
)
plot.add_layout(ylabel1)
plot.add_layout(ylabel2)
if xparam == 'time':
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
if yparam == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
plot.y_range = Range1d(ymin,ymax)
script, div = components(plot)
return [script,div]
def interactive_otw_advanced_pace_chart(id=0,promember=0):
# check if valid ID exists (workout exists)
rowdata,row = dataprep.getrowdata_db(id=id)
rowdata.dropna(axis=1,how='all',inplace=True)
rowdata.dropna(axis=0,how='any',inplace=True)
if rowdata.empty:
return "","No Valid Data Available"
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
source = ColumnDataSource(
rowdata
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
tools=TOOLS,
plot_width=920,
toolbar_sticky=False)
# add watermark
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.title.text = row.name
plot.title.text_font_size=value("1.2em")
plot.xaxis.axis_label = "Time"
plot.yaxis.axis_label = "Pace (/500m)"
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
ymax = 1.0e3*90
ymin = 1.0e3*210
plot.y_range = Range1d(ymin,ymax)
hover = plot.select(dict(type=HoverTool))
plot.line('time','pace',source=source,legend="Pace",color="black")
plot.line('time','nowindpace',source=source,legend="Corrected Pace",color="red")
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Pace','@fpace'),
('Corrected Pace','@fnowindpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
])
hover.mode = 'mouse'
script, div = components(plot)
return [script,div]