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=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.astimezone(tz=datetime.timezone.utc).replace(tzinfo=None)) 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("{name}"); """.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 = """ """.format( latmean=latmean, lonmean=lonmean, scoordinates=scoordinates, pcoordinates=pcoordinates, plabels = plabels ) 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("{name}"); """.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 = """ """.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 = """ """.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 = """

 

""" 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("{name}"); """.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 = """ """ 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 = """ """.format( latmean=latmean, lonmean=lonmean, latbegin = latbegin, latend=latend, longbegin=longbegin, longend=longend, scoordinates=scoordinates, ) 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: '© Mapbox © OpenStreetMap Improve this map', 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: '© Mapbox © OpenStreetMap Improve this map', 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: '© Mapbox © OpenStreetMap Improve this map', 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("Start"); 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 = """

 

""" 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 = """ """ 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 ['','

No non-zero data in selection

'] 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 ['','

No non-zero data in selection

','',''] 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 ['','

No non-zero data in selection

','',''] try: datadf['y1'] = datadf.loc[:,yparam1] except KeyError: try: datadf['y1'] = datadf['pace'] except KeyError: # pragma: no cover return ['','

No non-zero data in selection

','',''] 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=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 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=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 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 ['','

A chart data error occurred

','','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 ['','

No non-zero data in selection

','','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,'= 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