stats report alert
This commit is contained in:
@@ -169,6 +169,10 @@ def alert_get_stats(alert,nperiod=0):
|
|||||||
percentage = int(100.*nr_strokes_qualifying/nr_strokes)
|
percentage = int(100.*nr_strokes_qualifying/nr_strokes)
|
||||||
else:
|
else:
|
||||||
percentage = 0
|
percentage = 0
|
||||||
|
|
||||||
|
median_q = df2[alert.measured.metric].median()
|
||||||
|
median = df[alert.measured.metric].median()
|
||||||
|
std = df[alert.measured.metric].std()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'workouts':len(workouts),
|
'workouts':len(workouts),
|
||||||
@@ -177,7 +181,10 @@ def alert_get_stats(alert,nperiod=0):
|
|||||||
'nr_strokes':nr_strokes,
|
'nr_strokes':nr_strokes,
|
||||||
'nr_strokes_qualifying':nr_strokes_qualifying,
|
'nr_strokes_qualifying':nr_strokes_qualifying,
|
||||||
'percentage': percentage,
|
'percentage': percentage,
|
||||||
'nperiod':nperiod,
|
'nperiod':nperiod,
|
||||||
|
'median':median,
|
||||||
|
'median_q':median_q,
|
||||||
|
'standard_dev':std,
|
||||||
}
|
}
|
||||||
|
|
||||||
# run alert report
|
# run alert report
|
||||||
|
|||||||
@@ -881,9 +881,12 @@ class Rower(models.Model):
|
|||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
for group in self.coachinggroups.all():
|
for group in self.coachinggroups.all():
|
||||||
coach = Rower.objects.get(mycoachgroup=group)
|
try:
|
||||||
if coach.rowerplan == 'freecoach':
|
coach = Rower.objects.get(mycoachgroup=group)
|
||||||
self.coachinggroups.remove(group)
|
if coach.rowerplan == 'freecoach':
|
||||||
|
self.coachinggroups.remove(group)
|
||||||
|
except Rower.DoesNotExist:
|
||||||
|
pass
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -1093,6 +1096,11 @@ class Alert(models.Model):
|
|||||||
|
|
||||||
return stri
|
return stri
|
||||||
|
|
||||||
|
def metricname(self):
|
||||||
|
metricdict = {key:value for (key,value) in parchoicesy1}
|
||||||
|
|
||||||
|
return metricdict[self.measured.metric]
|
||||||
|
|
||||||
def description(self):
|
def description(self):
|
||||||
metricdict = {key:value for (key,value) in parchoicesy1}
|
metricdict = {key:value for (key,value) in parchoicesy1}
|
||||||
|
|
||||||
@@ -1115,6 +1123,24 @@ class Alert(models.Model):
|
|||||||
|
|
||||||
return description
|
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 AlertEditForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends "newbase.html" %}
|
{% extends "newbase.html" %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
|
||||||
{% block title %}Metric Alert{% endblock %}
|
{% block title %}Metric Alert{% endblock %}
|
||||||
|
|
||||||
@@ -13,19 +14,33 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
|
<li>
|
||||||
|
{{ stats|lookuplong:'startdate' }} - {{ stats|lookuplong:'enddate' }}
|
||||||
|
</li>
|
||||||
|
|
||||||
<li class="grid_4">
|
<li class="grid_4">
|
||||||
<h2>Alert</h2>
|
<h2>{{ alert.name }}</h2>
|
||||||
<p>{{ alert }}</p>
|
<p>{{ alert }}</p>
|
||||||
<p>{{ alert.description }}</p>
|
<p>{{ alert.description }}</p>
|
||||||
<p>This is a page under construction. Currently with minimal information</p>
|
<p>This is a page under construction. Currently with minimal information</p>
|
||||||
</li>
|
</li>
|
||||||
{% for key, value in stats.items %}
|
<li class="rounder">
|
||||||
<li>
|
<h2>Score</h2>
|
||||||
<h2>{{ key }}</h2>
|
<hr>
|
||||||
<p>{{ value }}</p>
|
<h2>{{ stats|lookup:'percentage' }}%</h2>
|
||||||
|
</li>
|
||||||
|
<li class="rounder">
|
||||||
|
<h2>Data set</h2>
|
||||||
|
<hr>
|
||||||
|
<p>{{ stats|lookup:'workouts' }} workouts</p>
|
||||||
|
<p>{{ stats|lookup:'nr_strokes_qualifying' }} strokes out of {{ stats|lookup:'nr_strokes' }}</p>
|
||||||
|
</li>
|
||||||
|
<li class="rounder">
|
||||||
|
<h2>Statistics</h2>
|
||||||
|
<hr>
|
||||||
|
<p>Median {{ alert.metricname }}: {{ stats|lookup:'median'|sigdig }}</p>
|
||||||
|
<p>Median {{ alert.metricname }}: {{ stats|lookup:'median_q'|sigdig }} ({{ alert.shortdescription }})</p>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from time import strftime
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
import dateutil.parser
|
import dateutil.parser
|
||||||
import json
|
import json
|
||||||
|
import math
|
||||||
import datetime
|
import datetime
|
||||||
import re
|
import re
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
@@ -37,6 +38,25 @@ from django.template.defaultfilters import stringfilter
|
|||||||
|
|
||||||
from six import string_types
|
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)
|
@register.filter(is_safe=True, needs_autoescape=True)
|
||||||
@stringfilter
|
@stringfilter
|
||||||
def urlshorten(value, limit,autoescape=None):
|
def urlshorten(value, limit,autoescape=None):
|
||||||
@@ -278,18 +298,26 @@ def jsdict(dict,key):
|
|||||||
s = dict.get(key)
|
s = dict.get(key)
|
||||||
return mark_safe(json.dumps(s))
|
return mark_safe(json.dumps(s))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def lookup(dict, key):
|
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:
|
if isinstance(s,string_types) and len(s) > 22:
|
||||||
s = s[:22]
|
s = s[:22]
|
||||||
return s
|
return s
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def lookuplong(dict, key):
|
def lookuplong(dict, key):
|
||||||
s = dict.get(key)
|
try:
|
||||||
|
s = dict.get(key)
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
|
|||||||
BIN
rowers/tests/testdata/testdata.csv.gz
vendored
BIN
rowers/tests/testdata/testdata.csv.gz
vendored
Binary file not shown.
@@ -4328,7 +4328,8 @@ def alerts_view(request,userid=0):
|
|||||||
|
|
||||||
for alert in alerts:
|
for alert in alerts:
|
||||||
stats.append(alert_get_stats(alert))
|
stats.append(alert_get_stats(alert))
|
||||||
|
|
||||||
|
|
||||||
breadcrumbs = [
|
breadcrumbs = [
|
||||||
{
|
{
|
||||||
'url':'/rowers/analysis',
|
'url':'/rowers/analysis',
|
||||||
|
|||||||
Reference in New Issue
Block a user