diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 5b30d4c4..c2e921db 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -232,6 +232,40 @@ def interactive_boxchart(datadf,fieldname,extratitle='', return script,div + +def interactive_planchart(data,startdate,enddate): + source = ColumnDataSource(data) + + hv.extension('bokeh') + + + yaxmaximum = data['executed'].max() + if data['planned'].max() > yaxmaximum: + yaxmaximum = data['planned'].max() + + if yaxmaximum == 0: + yaxmaximum = 250 + + yrange1 = Range1d(start=0,end=1.1*yaxmaximum) + + + tidy_df = data.melt(id_vars=['startdate'],value_vars=['executed','planned']) + bars = hv.Bars(tidy_df,['startdate','variable'],['value']) + bars.opts( + opts.Bars(show_legend=True,tools=['tap','hover'],legend_position='bottom',show_frame=True)) + + p = hv.render(bars) + + p.plot_width=550 + p.plot_height=350 + p.y_range = yrange1 + p.toolbar_location = 'above' + p.sizing_mode = 'scale_width' + + script,div = components(p) + + return script,div + def interactive_activitychart(workouts,startdate,enddate,stack='type'): dates = [] @@ -352,7 +386,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'): p.plot_width=550 p.plot_height=350 - p.toolbar_location = None + p.toolbar_location = 'above' p.sizing_mode = 'scale_width' url = "http://rowsandall.com/rowers/workout/@duration/" taptool = p.select(type=TapTool) diff --git a/rowers/models.py b/rowers/models.py index e3e23ada..0c69aecc 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -1981,7 +1981,7 @@ class TrainingMicroCycle(models.Model): if self.startdate < self.plan.startdate: self.startdate = self.plan.startdate - othercycles = TrainingMicroCycle.objects.filter( + othercycles = TrainingMicroCycle.objects.filter( plan=self.plan).exclude(pk=self.pk).order_by("-startdate") for othercycle in othercycles: diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index f3c33b4e..a3f8f1a7 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -22,11 +22,14 @@ queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') queuehigh = django_rq.get_queue('low') +import pandas as pd + from rowers.models import ( Rower, Workout,Team, GeoCourse, TrainingMicroCycle,TrainingMesoCycle,TrainingMacroCycle, TrainingPlan,PlannedSession,VirtualRaceResult,CourseTestResult, - get_course_timezone, IndoorVirtualRaceResult,VirtualRace + get_course_timezone, IndoorVirtualRaceResult,VirtualRace,createmacrofillers, + createmesofillers,createmicrofillers, ) from rowers.courses import get_time_course @@ -47,6 +50,212 @@ from rowers.tasks import ( ) from rowers.utils import totaltime_sec_to_string +def checkscores(r,macrocycles): + for m in macrocycles: + createmesofillers(m) + m.plantime = 0 + m.actualtime = 0 + m.plandistance = 0 + m.actualdistance = 0 + m.planrscore = 0 + m.actualrscore = 0 + m.plantrimp = 0 + m.actualtrimp = 0 + + + mesocycles = TrainingMesoCycle.objects.filter( + plan=m, + type='userdefined').order_by("startdate") + + for me in mesocycles: + me.plantime = 0 + me.actualtime = 0 + me.plandistance = 0 + me.actualdistance = 0 + me.planrscore = 0 + me.actualrscore = 0 + me.plantrimp = 0 + me.actualtrimp = 0 + + microcycles = TrainingMicroCycle.objects.filter( + plan=me, + type='userdefined').order_by("startdate") + + for mm in microcycles: + sps = get_sessions(r,startdate=mm.startdate,enddate=mm.enddate) + + # sps = PlannedSession.objects.filter( + # rower = r, + # startdate__lte=mm.enddate, + # enddate__gte=mm.startdate) + + + mm.plantime = 0 + mm.actualtime = 0 + mm.plandistance = 0 + mm.actualdistance = 0 + mm.planrscore = 0 + mm.actualrscore = 0 + mm.plantrimp = 0 + mm.actualtrimp = 0 + + + if mm.type == 'userdefined': + for ps in sps: + ratio, status, cdate = is_session_complete(r,ps) + if ps.sessionmode == 'time': + mm.plantime += ps.sessionvalue + mm.actualtime += int(ps.sessionvalue*ratio) + elif ps.sessionmode == 'distance' and ps.sessiontype != 'race': + mm.plandistance += ps.sessionvalue + mm.actualdistance += int(ps.sessionvalue*ratio) + elif ps.sessionmode == 'rScore': + mm.planrscore += ps.sessionvalue + mm.actualrscore += int(ps.sessionvalue*ratio) + elif ps.sessionmode == 'TRIMP': + mm.plantrimp += ps.sessionvalue + mm.actualtrimp += int(ps.sessionvalue*ratio) + + mm.save() + + me.plantime += mm.plantime + me.actualtime += mm.actualtime + me.plandistance += mm.plandistance + me.actualdistance += mm.actualdistance + me.planrscore += mm.planrscore + me.actualrscore += mm.actualrscore + me.plantrimp += mm.plantrimp + me.actualtrimp += mm.actualtrimp + + if me.type == 'userdefined': + me.save() + + m.plantime += me.plantime + m.actualtime += me.actualtime + m.plandistance += me.plandistance + m.actualdistance += me.actualdistance + m.planrscore += me.planrscore + m.actualrscore += me.actualrscore + m.plantrimp += me.plantrimp + m.actualtrimp += me.actualtrimp + + + + if m.type == 'userdefined': + m.save() + + +def get_execution_report(rower,startdate,enddate,plan=None): + if plan: + macros = TrainingMacroCycle.objects.filter(plan=plan).order_by("startdate") + checkscores(rower,macros) + mesos = TrainingMesoCycle.objects.filter(plan__in=macros).order_by("startdate") + micros = TrainingMicroCycle.objects.filter(plan__in=mesos).order_by("startdate") + micros = micros.exclude(enddate__lte=startdate).exclude(startdate__gte=enddate) + else: + plans = TrainingPlan.objects.filter(startdate__lte=startdate,enddate__gte=startdate) + plans2 = TrainingPlan.objects.filter(enddate__lte=enddate,startdate__lte=enddate) + plans = plans | plans2 + + plans = plans.exclude(status=False).order_by("-enddate") + + if not plans: + # make week cycles here + # get monday before startdate + startdate += timedelta(days=1-startdate.isoweekday()) + startdate = startdate-timedelta(days=7) + micros = [] + while startdate <= enddate: + micro = type('micros',(object,), + { + 'startdate':startdate, + 'enddate':startdate+timedelta(days=7) + }) + micros.append(micro) + startdate += timedelta(days=7) + else: + plan = plans[0] + macros = TrainingMacroCycle.objects.filter(plan=plan).order_by("startdate") + checkscores(rower,macros) + mesos = TrainingMesoCycle.objects.filter(plan__in=macros).order_by("startdate") + micros = TrainingMicroCycle.objects.filter(plan__in=mesos).order_by("startdate") + + # we've got micros, now get sessions + startdates = [] + planned = [] + executed = [] + + for mm in micros: + plannedscore = 0 + actualscore = 0 + sps = get_sessions(rower,startdate=mm.startdate,enddate=mm.enddate) + unmatchedworkouts = Workout.objects.filter( + user=rower, + plannedsession=None, + date__gte=mm.startdate,date__lte=mm.enddate).exclude(duplicate=True) + for w in unmatchedworkouts: + if w.rscore != 0: + actualscore += w.rscore + elif w.hrtss != 0: + actualscore += w.hrtss + else: + minutes = w.duration.hour*60+w.duration.minute + actualscore += minutes + for ps in sps: + ratio, status, cdate = is_session_complete(rower,ps) + if ps.sessionmode == 'rscore': + plannedscore += ps.sessionvalue + actualscore += ratio*ps.sessionvalue + else: + ws = Workout.objects.filter(user=rower,plannedsession=ps) + if not ws: + if ps.sessionmode == 'time': + plannedscore += ps.sessionvalue + elif ps.sessionmode == 'distance': + plannedscore += 60. + elif ps.sessionmode == 'TRIMP': + plannedscore += ps.sessionvalue/2. + + for w in ws: + if w.rscore != 0: + if ratio > 0: + plannedscore += w.rscore/ratio + actualscore += w.rscore + else: + plannedscore += 60 + actualscore += 0 + elif w.hrtss != 0: + if ratio > 0: + plannedscore += w.hrtss/ratio + actualscore += w.hrtss + else: + plannedscore += 60 + actualscore += 0 + else: + minutes = w.duration.hour*60+w.duration.minute + if ratio > 0: + plannedscore += minutes/ratio + else: + plannedscore += 60 + + actualscore += minutes + + actualscore = int(actualscore) + plannedscore = int(plannedscore) + + startdates += [mm.startdate] + planned += [plannedscore] + executed += [actualscore] + + + data = pd.DataFrame({ + 'startdate':startdates, + 'planned':planned, + 'executed':executed, + }) + + return(data,'ok') + def get_indoorraces(workout): races1 = VirtualRace.objects.filter( sessiontype='indoorrace', diff --git a/rowers/stravastuff.py b/rowers/stravastuff.py index 0ea6ab5c..6c75da2c 100644 --- a/rowers/stravastuff.py +++ b/rowers/stravastuff.py @@ -441,7 +441,7 @@ def handle_stravaexport(f2,workoutname,stravatoken,description='', client = stravalib.Client(access_token=stravatoken) act = client.upload_activity(f2,'tcx.gz',name=workoutname) - + try: res = act.wait(poll_interval=5.0,timeout=30) message = 'Workout successfully synchronized to Strava' diff --git a/rowers/templates/course_edit_view.html b/rowers/templates/course_edit_view.html index 436a07a7..797a2924 100644 --- a/rowers/templates/course_edit_view.html +++ b/rowers/templates/course_edit_view.html @@ -1,6 +1,13 @@ {% extends "newbase.html" %} {% load staticfiles %} {% load rowerfilters %} +{% load leaflet_tags %} + +{% block meta %} +{% leaflet_js %} +{% leaflet_css %} +{% endblock %} + {% block scripts %} {% include "monitorjobs.html" %} {% endblock %} @@ -8,6 +15,7 @@ {% block title %}{{ course.name }} {% endblock %} {% block og_title %}{{ course.name }} {% endblock %} {% block main %} +

{{ course.name }}