automating the stats
This commit is contained in:
@@ -280,6 +280,7 @@ class Workout(models.Model):
|
|||||||
('slides','Indoor Rower on Slides'),
|
('slides','Indoor Rower on Slides'),
|
||||||
('paddle','Paddle Adapter'),
|
('paddle','Paddle Adapter'),
|
||||||
('snow','On-snow'),
|
('snow','On-snow'),
|
||||||
|
('other','Other'),
|
||||||
)
|
)
|
||||||
|
|
||||||
boattypes = (
|
boattypes = (
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="grid_12 alpha">
|
<div class="grid_12 alpha">
|
||||||
<h1>Workout Statistics</h1>
|
<h1>Workout Statistics for {{ workout.name }}</h1>
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
<p>
|
<p>
|
||||||
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
|
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
|
||||||
@@ -38,7 +38,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid_6 alpha">
|
<div class="grid_6 alpha">
|
||||||
<h2>Stroke Rate</h2>
|
{% if stats %}
|
||||||
|
{% for key, value in stats.items %}
|
||||||
|
<h2>{{ key }}</h2>
|
||||||
<table width="100%" class="listtable">
|
<table width="100%" class="listtable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -48,80 +50,24 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Mean</td><td>{{ stats.spm.mean|floatformat:-2 }}</td>
|
<td>Mean</td><td>{{ value.mean|floatformat:-2 }}</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td>Minimum</td><td>{{ stats.spm.min|floatformat:-2 }}</td>
|
<td>Minimum</td><td>{{ value.min|floatformat:-2 }}</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td>25%</td><td>{{ stats.spm.firstq|floatformat:-2 }}</td>
|
<td>25%</td><td>{{ value.firstq|floatformat:-2 }}</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td>Median</td><td>{{ stats.spm.median|floatformat:-2 }}</td>
|
<td>Median</td><td>{{ value.median|floatformat:-2 }}</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td>75%</td><td>{{ stats.spm.thirdq|floatformat:-2 }}</td>
|
<td>75%</td><td>{{ value.thirdq|floatformat:-2 }}</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td>Maximum</td><td>{{ stats.spm.max|floatformat:-2 }}</td>
|
<td>Maximum</td><td>{{ value.max|floatformat:-2 }}</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<td>Standard Deviation</td><td>{{ stats.spm.std|floatformat:-2 }}</td>
|
<td>Standard Deviation</td><td>{{ value.std|floatformat:-2 }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
{% endfor %}
|
||||||
<div class="grid_6 alpha">
|
{% endif %}
|
||||||
<h2>Heart Rate</h2>
|
|
||||||
<table width="100%" class="listtable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Metric</th>
|
|
||||||
<th>Value</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>Mean</td><td>{{ stats.hr.mean|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>Minimum</td><td>{{ stats.hr.min|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>25%</td><td>{{ stats.hr.firstq|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>Median</td><td>{{ stats.hr.median|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>75%</td><td>{{ stats.hr.thirdq|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>Maximum</td><td>{{ stats.hr.max|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>Standard Deviation</td><td>{{ stats.hr.std|floatformat:-2 }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="grid_6 omega">
|
|
||||||
<div class="grid_6 alpha">
|
|
||||||
<h2>Power</h2>
|
|
||||||
<table width="100%" class="listtable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Metric</th>
|
|
||||||
<th>Value</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>Mean</td><td>{{ stats.power.mean|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>Minimum</td><td>{{ stats.power.min|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>25%</td><td>{{ stats.power.firstq|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>Median</td><td>{{ stats.power.median|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>75%</td><td>{{ stats.power.thirdq|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>Maximum</td><td>{{ stats.power.max|floatformat:-2 }}</td>
|
|
||||||
</tr><tr>
|
|
||||||
<td>Standard Deviation</td><td>{{ stats.power.std|floatformat:-2 }}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ from rowers.forms import SummaryStringForm,IntervalUpdateForm,StrokeDataForm
|
|||||||
from rowers.models import Workout, User, Rower, WorkoutForm,FavoriteChart
|
from rowers.models import Workout, User, Rower, WorkoutForm,FavoriteChart
|
||||||
from rowers.models import (
|
from rowers.models import (
|
||||||
RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
|
RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
|
||||||
RowerPowerZonesForm,AccountRowerForm,UserForm,
|
RowerPowerZonesForm,AccountRowerForm,UserForm,StrokeData,
|
||||||
)
|
)
|
||||||
from rowers.models import FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement
|
from rowers.models import FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement
|
||||||
from django.forms.formsets import formset_factory
|
from django.forms.formsets import formset_factory
|
||||||
@@ -2611,15 +2611,15 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
|
|||||||
workstrokesonly = True
|
workstrokesonly = True
|
||||||
if request.method == 'POST' and 'workstrokesonly' in request.POST:
|
if request.method == 'POST' and 'workstrokesonly' in request.POST:
|
||||||
workstrokesonly = request.POST['workstrokesonly']
|
workstrokesonly = request.POST['workstrokesonly']
|
||||||
|
|
||||||
|
|
||||||
|
# prepare data frame
|
||||||
datadf,row = dataprep.getrowdata_db(id=id)
|
datadf,row = dataprep.getrowdata_db(id=id)
|
||||||
if (checkworkoutuser(request.user,row)==False):
|
if (checkworkoutuser(request.user,row)==False):
|
||||||
message = "You are not allowed to see the stats of this workout"
|
message = "You are not allowed to see the stats of this workout"
|
||||||
url = reverse(workouts_view,args=[str(message)])
|
url = reverse(workouts_view,args=[str(message)])
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
columns = ['hr','spm','power','workoutstate']
|
|
||||||
datadf = dataprep.getsmallrowdata_db(columns,ids=[id])
|
|
||||||
|
|
||||||
if datadf.empty:
|
if datadf.empty:
|
||||||
return HttpResponse("CSV data file not found")
|
return HttpResponse("CSV data file not found")
|
||||||
@@ -2634,45 +2634,45 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
workstrokesonly = True
|
workstrokesonly = True
|
||||||
|
|
||||||
# Create stats
|
# Create stats
|
||||||
stats = {}
|
|
||||||
# SPM
|
|
||||||
spmdict = {
|
|
||||||
'mean':datadf['spm'].mean(),
|
|
||||||
'max': datadf['spm'].max(),
|
|
||||||
'min': datadf['spm'].min(),
|
|
||||||
'std': datadf['spm'].std(),
|
|
||||||
'median': datadf['spm'].median(),
|
|
||||||
'firstq':datadf['spm'].quantile(q=0.25),
|
|
||||||
'thirdq':datadf['spm'].quantile(q=0.75),
|
|
||||||
stats = {}
|
stats = {}
|
||||||
|
|
||||||
|
# Get field names and remove those that are not useful in stats
|
||||||
|
fieldnames = StrokeData._meta.get_all_field_names()
|
||||||
|
fieldnames.remove('workoutid')
|
||||||
|
fieldnames.remove('ergpace')
|
||||||
|
fieldnames.remove('hr_an')
|
||||||
|
fieldnames.remove('hr_tr')
|
||||||
|
fieldnames.remove('hr_at')
|
||||||
|
fieldnames.remove('hr_ut2')
|
||||||
|
fieldnames.remove('hr_ut1')
|
||||||
|
fieldnames.remove('time')
|
||||||
|
fieldnames.remove('distance')
|
||||||
|
fieldnames.remove('nowindpace')
|
||||||
|
fieldnames.remove('fnowindpace')
|
||||||
|
fieldnames.remove('fergpace')
|
||||||
|
fieldnames.remove('equivergpower')
|
||||||
|
fieldnames.remove('workoutstate')
|
||||||
|
fieldnames.remove('fpace')
|
||||||
|
fieldnames.remove('id')
|
||||||
|
fieldnames.remove('ftime')
|
||||||
|
fieldnames.remove('x_right')
|
||||||
|
fieldnames.remove('hr_max')
|
||||||
|
fieldnames.remove('hr_bottom')
|
||||||
fieldnames.remove('cumdist')
|
fieldnames.remove('cumdist')
|
||||||
|
|
||||||
# HR
|
for field in fieldnames:
|
||||||
hrdict = {
|
thedict = {
|
||||||
'mean':datadf['hr'].mean(),
|
'mean':datadf[field].mean(),
|
||||||
'max': datadf['hr'].max(),
|
'min': datadf[field].min(),
|
||||||
'min': datadf['hr'].min(),
|
'std': datadf[field].std(),
|
||||||
'std': datadf['hr'].std(),
|
'max': datadf[field].max(),
|
||||||
'median': datadf['hr'].median(),
|
'median': datadf[field].median(),
|
||||||
'firstq':datadf['hr'].quantile(q=0.25),
|
'firstq':datadf[field].quantile(q=0.25),
|
||||||
'thirdq':datadf['hr'].quantile(q=0.75),
|
'thirdq':datadf[field].quantile(q=0.75),
|
||||||
}
|
}
|
||||||
|
stats[field] = thedict
|
||||||
stats['hr'] = hrdict
|
|
||||||
|
|
||||||
# Power
|
|
||||||
powerdict = {
|
|
||||||
'mean':datadf['power'].mean(),
|
|
||||||
'max': datadf['power'].max(),
|
|
||||||
'min': datadf['power'].min(),
|
|
||||||
'std': datadf['power'].std(),
|
|
||||||
'median': datadf['power'].median(),
|
|
||||||
'firstq':datadf['power'].quantile(q=0.25),
|
|
||||||
'thirdq':datadf['power'].quantile(q=0.75),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return render(request,
|
return render(request,
|
||||||
|
|||||||
Reference in New Issue
Block a user