diff --git a/rowers/models.py b/rowers/models.py
index 78b95e1b..1cc2fcfb 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -363,22 +363,22 @@ class StrokeData(models.Model):
index_together = ['workoutid']
workoutid = models.IntegerField(null=True)
- time = models.FloatField(null=True)
- hr = models.IntegerField(null=True)
- pace = models.FloatField(null=True)
+ time = models.FloatField(null=True,verbose_name='Time')
+ hr = models.IntegerField(null=True,verbose_name='Heart Rate')
+ pace = models.FloatField(null=True,verbose_name='Pace')
workoutstate = models.IntegerField(null=True,default=1)
- spm = models.FloatField(null=True)
- cumdist = models.FloatField(null=True)
+ spm = models.FloatField(null=True,verbose_name='Stroke Rate')
+ cumdist = models.FloatField(null=True,verbose_name='Cumulative Distance')
ftime = models.CharField(max_length=30)
fpace = models.CharField(max_length=30)
- driveenergy = models.FloatField(null=True)
- power = models.FloatField(null=True)
- averageforce = models.FloatField(null=True)
- drivelength = models.FloatField(null=True)
- peakforce = models.FloatField(null=True)
- forceratio = models.FloatField(null=True)
- distance = models.FloatField(null=True)
- drivespeed = models.FloatField(null=True)
+ driveenergy = models.FloatField(null=True,verbose_name='Work per Stroke')
+ power = models.FloatField(null=True,verbose_name='Power')
+ averageforce = models.FloatField(null=True,verbose_name='Average Force')
+ drivelength = models.FloatField(null=True,verbose_name='Drive Length')
+ peakforce = models.FloatField(null=True,verbose_name='Peak Force')
+ forceratio = models.FloatField(null=True,verbose_name='Average/Peak Force Ratio')
+ distance = models.FloatField(null=True,verbose_name='Distance')
+ drivespeed = models.FloatField(null=True,verbose_name='Drive Speed')
hr_ut2 = models.IntegerField(null=True)
hr_ut1 = models.IntegerField(null=True)
hr_at = models.IntegerField(null=True)
@@ -392,12 +392,12 @@ class StrokeData(models.Model):
equivergpower = models.FloatField(null=True)
fergpace = models.CharField(max_length=30)
fnowindpace = models.CharField(max_length=30)
- catch = models.FloatField(default=0,null=True)
- slip = models.FloatField(default=0,null=True)
- finish = models.FloatField(default=0,null=True)
- wash = models.FloatField(default=0,null=True)
- peakforceangle = models.FloatField(default=0,null=True)
- rhythm = models.FloatField(default=1.0,null=True)
+ catch = models.FloatField(default=0,null=True,verbose_name='Catch Angle')
+ slip = models.FloatField(default=0,null=True,verbose_name='Slip')
+ finish = models.FloatField(default=0,null=True,verbose_name='Finish Angle')
+ wash = models.FloatField(default=0,null=True,verbose_name='Wash')
+ peakforceangle = models.FloatField(default=0,null=True,verbose_name='Peak Force Angle')
+ rhythm = models.FloatField(default=1.0,null=True,verbose_name='Rhythm')
# A wrapper around the png files
class GraphImage(models.Model):
diff --git a/rowers/templates/workoutstats.html b/rowers/templates/workoutstats.html
index aebd71a4..3f470672 100644
--- a/rowers/templates/workoutstats.html
+++ b/rowers/templates/workoutstats.html
@@ -7,6 +7,10 @@
{% block content %}
Workout Statistics for {{ workout.name }}
+
+ This is an experimental page which just lists a bunch of statistics for
+ your workout. This page is under rapid development.
+
Edit Workout
@@ -37,10 +41,10 @@
If your data source allows, this will show or hide strokes taken during rest intervals.
-
+
{% if stats %}
{% for key, value in stats.items %}
-
{{ key }}
+
{{ value.verbosename }}
@@ -69,5 +73,45 @@
{% endfor %}
{% endif %}
+
+ {% if cordict %}
+
Correlation table
+
This table indicates a positive (+) or negative (-) correlation between two parameters. The strong correlations are indicated with ++ and --.
+
+
+
+
+ | |
+ {% for key,value in cordict.items %}
+ {{ key }} |
+ {% endfor %}
+
+
+
+ {% for key, thedict in cordict.items %}
+
+ | {{ key }} |
+ {% for key2,value in thedict.items %}
+
+ {% if value > 0.5 %}
+ ++
+ {% elif value > 0.1 %}
+ +
+ {% elif value < -0.5 %}
+ --
+ {% elif value < -0.1 %}
+ -
+ {% else %}
+
+ {% endif %}
+ |
+ {% endfor %}
+
+ {% endfor %}
+
+
+
+ {% endif %}
+
{% endblock %}
diff --git a/rowers/views.py b/rowers/views.py
index e6a1b021..779b1b89 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -2638,30 +2638,36 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
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')
+ fields = StrokeData._meta.get_fields()
- for field in fieldnames:
+ fielddict = {field.name:field.verbose_name for field in fields}
+
+ print fielddict
+
+ fielddict.pop('workoutid')
+ fielddict.pop('ergpace')
+ fielddict.pop('hr_an')
+ fielddict.pop('hr_tr')
+ fielddict.pop('hr_at')
+ fielddict.pop('hr_ut2')
+ fielddict.pop('hr_ut1')
+ fielddict.pop('time')
+ fielddict.pop('distance')
+ fielddict.pop('nowindpace')
+ fielddict.pop('fnowindpace')
+ fielddict.pop('fergpace')
+ fielddict.pop('equivergpower')
+ fielddict.pop('workoutstate')
+ fielddict.pop('fpace')
+ fielddict.pop('pace')
+ fielddict.pop('id')
+ fielddict.pop('ftime')
+ fielddict.pop('x_right')
+ fielddict.pop('hr_max')
+ fielddict.pop('hr_bottom')
+ fielddict.pop('cumdist')
+
+ for field,verbosename in fielddict.iteritems():
thedict = {
'mean':datadf[field].mean(),
'min': datadf[field].min(),
@@ -2670,9 +2676,23 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
'median': datadf[field].median(),
'firstq':datadf[field].quantile(q=0.25),
'thirdq':datadf[field].quantile(q=0.75),
+ 'verbosename':verbosename,
}
stats[field] = thedict
-
+
+ # Create a dict with correlation values
+ cor = datadf.corr()
+ cor.fillna(value=0,inplace=True)
+ cordict = {}
+ for field1,verbosename in fielddict.iteritems():
+ thedict = {}
+ for field2,verbosename in fielddict.iteritems():
+ try:
+ thedict[field2] = cor.ix[field1,field2]
+ except KeyError:
+ thedict[field2] = 0
+
+ cordict[field1] = thedict
return render(request,
'workoutstats.html',
@@ -2680,6 +2700,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
'stats':stats,
'workout':row,
'workstrokesonly':workstrokesonly,
+ 'cordict':cordict,
})
# The Advanced edit page
diff --git a/static/css/rowsandall.css b/static/css/rowsandall.css
index a3f4e761..6aa18088 100644
--- a/static/css/rowsandall.css
+++ b/static/css/rowsandall.css
@@ -60,6 +60,33 @@ th {
}
.paddedtable td { padding: 1px 20px }
+.cortable {
+ border-collapse: collapse;
+}
+
+.cortable td {
+ border: 1px solid #999;
+ text-align: center;
+}
+
+th.rotate {
+ /* Something you can count on */
+ height: 78px;
+ white-space: nowrap;
+}
+
+th.rotate > div {
+ transform:
+ /* Magic Numbers */
+ translate(18px, 51px)
+ /* 45 is really 360 - 45 */
+ rotate(315deg);
+ width: 30px;
+}
+th.rotate > div > span {
+ border-bottom: 1px solid #ccc;
+ padding: 5px 5px;
+}
.fixtable table {
table-layout: fixed;
@@ -76,6 +103,22 @@ th {
.midden { text-align: center }
+.poscor {
+ background-color: #8f8;
+}
+
+.weakposcor {
+ background-color: #efe;
+}
+
+.negcor {
+ background-color:#f88;
+}
+
+.weaknegcor {
+ background-color: #fee;
+}
+
.successmessage {
border: 1px solid #000;
background-color: #8f8;