diff --git a/rowers/alerts.py b/rowers/alerts.py index f33bd3f9..6e9fcd12 100644 --- a/rowers/alerts.py +++ b/rowers/alerts.py @@ -169,6 +169,10 @@ def alert_get_stats(alert,nperiod=0): percentage = int(100.*nr_strokes_qualifying/nr_strokes) else: percentage = 0 + + median_q = df2[alert.measured.metric].median() + median = df[alert.measured.metric].median() + std = df[alert.measured.metric].std() return { 'workouts':len(workouts), @@ -177,7 +181,10 @@ def alert_get_stats(alert,nperiod=0): 'nr_strokes':nr_strokes, 'nr_strokes_qualifying':nr_strokes_qualifying, 'percentage': percentage, - 'nperiod':nperiod, + 'nperiod':nperiod, + 'median':median, + 'median_q':median_q, + 'standard_dev':std, } # run alert report diff --git a/rowers/models.py b/rowers/models.py index f9d2ae9f..3028d064 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -881,9 +881,12 @@ class Rower(models.Model): def save(self, *args, **kwargs): try: for group in self.coachinggroups.all(): - coach = Rower.objects.get(mycoachgroup=group) - if coach.rowerplan == 'freecoach': - self.coachinggroups.remove(group) + try: + coach = Rower.objects.get(mycoachgroup=group) + if coach.rowerplan == 'freecoach': + self.coachinggroups.remove(group) + except Rower.DoesNotExist: + pass except ValueError: pass @@ -1093,6 +1096,11 @@ class Alert(models.Model): return stri + def metricname(self): + metricdict = {key:value for (key,value) in parchoicesy1} + + return metricdict[self.measured.metric] + def description(self): metricdict = {key:value for (key,value) in parchoicesy1} @@ -1115,6 +1123,24 @@ class Alert(models.Model): return description + def shortdescription(self): + metricdict = {key:value for (key,value) in parchoicesy1} + + if self.measured.condition == 'between': + description = '{value1} < {metric} < {value2}'.format( + metric = self.measured.metric, + value1 = self.measured.value1, + value2 = self.measured.value2, + ) + else: + description = '{metric} {condition} {value1}'.format( + metric = self.measured.metric, + value1 = self.measured.value1, + condition = self.measured.condition + ) + + return description + class AlertEditForm(ModelForm): class Meta: diff --git a/rowers/templates/alert_stats.html b/rowers/templates/alert_stats.html index fb950332..400a8dd3 100644 --- a/rowers/templates/alert_stats.html +++ b/rowers/templates/alert_stats.html @@ -1,5 +1,6 @@ {% extends "newbase.html" %} {% load staticfiles %} +{% load rowerfilters %} {% block title %}Metric Alert{% endblock %} @@ -13,19 +14,33 @@

    - +
  • + {{ stats|lookuplong:'startdate' }} - {{ stats|lookuplong:'enddate' }} +
  • +
  • -

    Alert

    +

    {{ alert.name }}

    {{ alert }}

    {{ alert.description }}

    This is a page under construction. Currently with minimal information

  • - {% for key, value in stats.items %} -
  • -

    {{ key }}

    -

    {{ value }}

    +
  • +

    Score

    +
    +

    {{ stats|lookup:'percentage' }}%

    +
  • +
  • +

    Data set

    +
    +

    {{ stats|lookup:'workouts' }} workouts

    +

    {{ stats|lookup:'nr_strokes_qualifying' }} strokes out of {{ stats|lookup:'nr_strokes' }}

    +
  • +
  • +

    Statistics

    +
    +

    Median {{ alert.metricname }}: {{ stats|lookup:'median'|sigdig }}

    +

    Median {{ alert.metricname }}: {{ stats|lookup:'median_q'|sigdig }} ({{ alert.shortdescription }})

  • - {% endfor %}
diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index e3ee8050..d7f9dd4a 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -4,6 +4,7 @@ from time import strftime from django.utils import timezone import dateutil.parser import json +import math import datetime import re register = template.Library() @@ -37,6 +38,25 @@ from django.template.defaultfilters import stringfilter from six import string_types +@register.filter +def sigdig(value, digits = 3): + try: + order = int(math.floor(math.log10(math.fabs(value)))) + except (ValueError,TypeError): + return value + + # return integers as is + if value % 1 == 0: + return value + + places = digits - order - 1 + if places > 0: + fmtstr = "%%.%df" % (places) + else: + fmtstr = "%.0f" + return fmtstr % (round(value, places)) + + @register.filter(is_safe=True, needs_autoescape=True) @stringfilter def urlshorten(value, limit,autoescape=None): @@ -278,18 +298,26 @@ def jsdict(dict,key): s = dict.get(key) return mark_safe(json.dumps(s)) + + @register.filter def lookup(dict, key): - s = dict.get(key) - + try: + s = dict.get(key) + except KeyError: + return None + if isinstance(s,string_types) and len(s) > 22: s = s[:22] return s @register.filter def lookuplong(dict, key): - s = dict.get(key) - + try: + s = dict.get(key) + except KeyError: + return None + return s @register.filter diff --git a/rowers/tests/testdata/testdata.csv.gz b/rowers/tests/testdata/testdata.csv.gz index 9941ccb4..784c98fe 100644 Binary files a/rowers/tests/testdata/testdata.csv.gz and b/rowers/tests/testdata/testdata.csv.gz differ diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index c8d68209..6bb2801c 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -4328,7 +4328,8 @@ def alerts_view(request,userid=0): for alert in alerts: stats.append(alert_get_stats(alert)) - + + breadcrumbs = [ { 'url':'/rowers/analysis',