From 47d8dd63d320ee4b9fb83e894c033cfcc9bab584 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Thu, 15 Dec 2022 22:10:37 +0100
Subject: [PATCH] better power zones
---
rowers/dataroutines.py | 1 -
rowers/interactiveplots.py | 16 +-
rowers/models.py | 13 +-
rowers/templates/rower_preferences.html | 187 +++++++++++++-----------
rowers/templatetags/rowerfilters.py | 5 +
rowers/views/userviews.py | 15 +-
6 files changed, 134 insertions(+), 103 deletions(-)
diff --git a/rowers/dataroutines.py b/rowers/dataroutines.py
index 31129951..2e8e4c5c 100644
--- a/rowers/dataroutines.py
+++ b/rowers/dataroutines.py
@@ -1259,7 +1259,6 @@ def getsmallrowdata_db(columns, ids=[], doclean=True, workstrokesonly=True, comp
df = pd.concat(data, axis=0)
except ValueError: # pragma: no cover
return pd.DataFrame()
- # df = dd.concat(data,axis=0)
else:
try:
diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py
index a3dc27bf..c1fa8eaf 100644
--- a/rowers/interactiveplots.py
+++ b/rowers/interactiveplots.py
@@ -6283,7 +6283,15 @@ def thumbnails_set(r, id, favorites):
columns += ['time']
rowdata = dataprep.getsmallrowdata_db(columns, ids=[id], doclean=True)
- rowdata.dropna(axis=1, how='all', inplace=True)
+ try:
+ rowdata.dropna(axis=1, how='all', inplace=True)
+ except TypeError:
+ return [
+ {'script': "",
+ 'div': "",
+ 'notes': ""
+ }]
+
if rowdata.empty:
try:
@@ -6303,12 +6311,6 @@ def thumbnails_set(r, id, favorites):
'notes': ""
}]
- # else:
- # try:
- # rowdata.sort_values(by='time',ascending=True,inplace=True)
- # except KeyError:
- # pass
-
lengte = len(rowdata)
maxlength = 50
if lengte > maxlength:
diff --git a/rowers/models.py b/rowers/models.py
index bcbfdf6e..e533f129 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -964,6 +964,7 @@ class Rower(models.Model):
# Power Zone Data
ftp = models.IntegerField(
default=226, verbose_name="Functional Threshold Power")
+ cogganzones = models.BooleanField(verbose_name='Use Default Power Zones',default=True)
p0 = models.FloatField(default=1.0, verbose_name="CP p1")
p1 = models.FloatField(default=1.0, verbose_name="CP p2")
@@ -997,11 +998,11 @@ class Rower(models.Model):
pw_an = models.IntegerField(default=273, verbose_name="AN Power")
powerzones = PowerZonesField(default=['Rest',
- 'Pwr UT2',
- 'Pwr UT1',
- 'Pwr AT',
- 'Pwr TR',
- 'Pwr AN'])
+ 'Active Recovery',
+ 'Endurance',
+ 'Tempo',
+ 'Threshold',
+ 'Anaerobic'])
hrzones = PowerZonesField(default=['Rest',
'UT2',
@@ -4224,7 +4225,7 @@ class RowerExportForm(ModelForm):
class RowerPowerForm(ModelForm):
class Meta:
model = Rower
- fields = ['hrftp', 'ftp', 'otwslack']
+ fields = ['hrftp', 'ftp', 'otwslack','cogganzones']
class RowerCPForm(ModelForm):
diff --git a/rowers/templates/rower_preferences.html b/rowers/templates/rower_preferences.html
index 28f27dc2..ba9456ad 100644
--- a/rowers/templates/rower_preferences.html
+++ b/rowers/templates/rower_preferences.html
@@ -10,6 +10,103 @@
Need help? Click to read the tutorial
+
+
+
+
+ Power Zones
+ Use this form if you want to rename and redefine your power
+ zones independent of the value of FTP. We recommend, however, that
+ you leave these values as they are and only change the FTP and OTW
+ slack values.
+
+
+
+
+
Heart Rate Zones
@@ -22,7 +119,7 @@
{% endif %}
-
+
ID Zone Name Lower Boundary (BPM)
@@ -52,7 +149,7 @@
6 {{ form.hranname }}
{{ form.an }}
-
+
7 {{ form.hrmaxname }}
{{ form.max }}
@@ -62,92 +159,6 @@
-
- Power Zones
- The power zones are defined relative to power as measured by the
- indoor rower.
-
-
-
-
-
-
-
-
diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py
index a1e234ab..40924683 100644
--- a/rowers/templatetags/rowerfilters.py
+++ b/rowers/templatetags/rowerfilters.py
@@ -1039,3 +1039,8 @@ def previousworkout(workout, user):
return encoder.encode_hex(ws[0].id)
else:
return 0
+
+@register.filter
+def otwslack(value, user):
+ r = Rower.objects.get(user=user)
+ return int(value*(100.-r.otwslack)/100.)
diff --git a/rowers/views/userviews.py b/rowers/views/userviews.py
index 6f1492e9..cd744ffd 100644
--- a/rowers/views/userviews.py
+++ b/rowers/views/userviews.py
@@ -618,13 +618,23 @@ def rower_prefs_view(request, userid=0, message=""):
hrftp = int((r.an+r.tr)/2.)
ftp = cd['ftp']
otwslack = cd['otwslack']
+ cogganzones = cd['cogganzones']
powerfrac = 100*np.array([r.pw_ut2,
r.pw_ut1,
r.pw_at,
r.pw_tr, r.pw_an])/r.ftp
+ if cogganzones:
+ powerfrac = np.array([55.,75.,90.,105.,120.])
+ powerzones = ['Rest',
+ 'Active Recovery',
+ 'Endurance',
+ 'Tempo',
+ 'Threshold',
+ 'Anaerobic']
+ r.powerzones = powerzones
+
r.ftp = max(min(ftp, 650), 50)
- r.otwslack = max(min(otwslack, 50), 0)
ut2, ut1, at, tr, an = (r.ftp*powerfrac/100.).astype(int)
r.pw_ut2 = ut2
r.pw_ut1 = ut1
@@ -632,7 +642,10 @@ def rower_prefs_view(request, userid=0, message=""):
r.pw_tr = tr
r.pw_an = an
r.hrftp = hrftp
+ r.otwslack = max(min(otwslack, 50), 0)
r.save()
+ powerzonesform = RowerPowerZonesForm(instance=r)
+
message = "FTP and/or OTW slack values changed."
messages.info(request, message)