diff --git a/rowers/dataroutines.py b/rowers/dataroutines.py index d2857736..9360b1b7 100644 --- a/rowers/dataroutines.py +++ b/rowers/dataroutines.py @@ -176,6 +176,7 @@ columndict = { 'slip': 'slip', 'workoutstate': ' WorkoutState', 'cumdist': 'cum_dist', + 'check_factor': 'check_factor', } @@ -1599,6 +1600,10 @@ def read_data(columns, ids=[], doclean=True, workstrokesonly=True, debug=False, try: datadf = pl.concat(data).select(columns) + except ColumnNotFoundError: + datadf = pl.concat(data) + existing_columns = [col for col in columns if col in datadf.columns] + datadf = datadf.select(existing_columns) except (ShapeError, SchemaError): data = [ df.select(columns) @@ -2302,6 +2307,16 @@ def dataplep(rowdatadf, id=0, inboard=0.88, forceunit='lbs', bands=True, barchar hr_bottom = 0.0*df[' HRCur (bpm)'], ) + + if 'check_factor' not in df.columns: + data = data.with_columns( + check_factor = pl.lit(0.0), + ) + else: + data = data.with_columns( + check_factor = df['check_factor'], + ) + if 'wash' not in df.columns: data = data.with_columns( wash = pl.lit(0.0), diff --git a/rowers/forms.py b/rowers/forms.py index 66d723c0..fa3f1b4b 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -1478,15 +1478,18 @@ class FusionMetricChoiceForm(ModelForm): value in self.fields['columns'].choices} for label in labeldict: - if df.loc[:, label].std() == 0: - try: - formaxlabels2.pop(label) - except KeyError: # pragma: no cover - pass + try: + if df.loc[:, label].std() == 0: + try: + formaxlabels2.pop(label) + except KeyError: # pragma: no cover + pass + except KeyError: # pragma: no cover + formaxlabels2.pop(label) - metricchoices = list( - sorted(formaxlabels2.items(), key=lambda x: x[1])) - self.fields['columns'].choices = metricchoices + metricchoices = list( + sorted(formaxlabels2.items(), key=lambda x: x[1])) + self.fields['columns'].choices = metricchoices class PlannedSessionSelectForm(forms.Form): diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 2995162a..4e4d4c74 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -1841,6 +1841,8 @@ def interactive_flex_chart2(id, r, promember=0, rowdata[column], 5)) except KeyError: pass + except ColumnNotFoundError: + pass if len(rowdata) < 2: if promember: @@ -1938,10 +1940,10 @@ def interactive_flex_chart2(id, r, promember=0, rowdata = rowdata.with_columns((pl.lit(axlabels[yparam2])).alias("yname2")) except (KeyError, ColumnNotFoundError): # pragma: no cover rowdata = rowdata.with_columns((pl.lit(yparam2)).alias("yname2")) - else: # pragma: no cover rowdata = rowdata.with_columns((pl.col("yname1")).alias("yname2")) + def func(x, a, b): return a*x+b diff --git a/rowers/metrics.py b/rowers/metrics.py index 83299c9c..832453aa 100644 --- a/rowers/metrics.py +++ b/rowers/metrics.py @@ -1,7 +1,7 @@ from rowers.utils import lbstoN import numpy as np - +import yaml import pandas as pd from scipy import optimize from django.utils import timezone @@ -44,322 +44,16 @@ nometrics = [ 'cum_dist.1' ] -rowingmetrics = ( - ('time', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Time', - 'ax_min': 0, - 'ax_max': 1e5, - 'mode': 'both', - 'type': 'basic', - 'group': 'basic', - 'maysmooth': False, - 'sigfigs': -1}), - - ('hr', { - 'numtype': 'integer', - 'null': True, - 'verbose_name': 'Heart Rate (bpm)', - 'ax_min': 100, - 'ax_max': 200, - 'mode': 'both', - 'type': 'basic', - 'maysmooth': False, - 'group': 'athlete', - 'sigfigs': 0, }), - - ('pace', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Pace (/500m)', - 'ax_min': 1.0e3*210, - 'ax_max': 1.0e3*75, - 'mode': 'both', - 'type': 'basic', - 'sigfigs': 1, - 'maysmooth': True, - 'group': 'basic'}), - - ('velo', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Boat Speed (m/s)', - 'ax_min': 0, - 'ax_max': 8, - 'default': 0, - 'mode': 'both', - 'sigfigs': 1, - 'maysmooth': True, - 'type': 'pro', - 'group': 'basic'}), - - # ('powerhr',{ - # 'numtype':'float', - # 'null':True, - # 'verbose_name': 'Power Heart Rate Efficiency (J/beat)', - # 'ax_min':0, - # 'ax_max':300, - # 'mode':'both', - # 'type':'pro', - # 'group':'athlete'}), - - ('spm', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Stroke Rate (spm)', - 'ax_min': 15, - 'ax_max': 45, - 'mode': 'both', - 'sigfigs': 1, - 'type': 'basic', - 'maysmooth': True, - 'group': 'basic'}), - - ('driveenergy', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Work Per Stroke (J)', - 'ax_min': 0, - 'ax_max': 1000, - 'mode': 'both', - 'sigfigs': 0, - 'type': 'pro', - 'maysmooth': True, - 'group': 'forcepower'}), - - ('power', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Power (W)', - 'ax_min': 0, - 'ax_max': 600, - 'mode': 'both', - 'sigfigs': 0, - 'type': 'basic', - 'maysmooth': True, - 'group': 'forcepower'}), - - ('averageforce', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Average Drive Force (N)', - 'ax_min': 0, - 'ax_max': 1200, - 'mode': 'both', - 'sigfigs': 0, - 'maysmooth': True, - 'type': 'pro', - 'group': 'forcepower'}), - - ('peakforce', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Peak Drive Force (N)', - 'ax_min': 0, - 'ax_max': 1500, - 'sigfigs': 0, - 'mode': 'both', - 'maysmooth': True, - 'type': 'pro', - 'group': 'forcepower'}), - - ('drivelength', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Drive Length (m)', - 'ax_min': 0, - 'ax_max': 2.5, - 'mode': 'rower', - 'sigfigs': 2, - 'maysmooth': False, - 'type': 'pro', - 'group': 'stroke'}), - - ('forceratio', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Average/Peak Force Ratio', - 'ax_min': 0, - 'ax_max': 1, - 'sigfigs': 2, - 'maysmooth': True, - 'mode': 'both', - 'type': 'pro', - 'group': 'forcepower'}), - - ('distance', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Interval Distance (m)', - 'ax_min': 0, - 'ax_max': 1e5, - 'sigfigs': 0, - 'mode': 'both', - 'maysmooth': False, - 'type': 'basic', - 'group': 'basic'}), - - ('cumdist', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Cumulative Distance (m)', - 'ax_min': 0, - 'ax_max': 1e5, - 'mode': 'both', - 'sigfigs': 0, - 'maysmooth': False, - 'type': 'basic', - 'group': 'basic'}), - - ('drivespeed', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Drive Speed (m/s)', - 'ax_min': 0, - 'ax_max': 4, - 'default': 0, - 'sigfigs': 2, - 'maysmooth': True, - 'mode': 'both', - 'type': 'pro', - 'group': 'stroke'}), - - - ('catch', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Catch Angle (degrees)', - 'ax_min': -40, - 'ax_max': -75, - 'default': 0, - 'sigfigs': 0, - 'mode': 'water', - 'maysmooth': True, - 'type': 'pro', - 'group': 'stroke'}), - - ('slip', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Slip (degrees)', - 'ax_min': 0, - 'ax_max': 20, - 'default': 0, - 'sigfigs': 1, - 'maysmooth': True, - 'mode': 'water', - 'type': 'pro', - 'group': 'stroke'}), - - ('finish', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Finish Angle (degrees)', - 'ax_min': 20, - 'ax_max': 55, - 'default': 0, - 'sigfigs': 0, - 'maysmooth': True, - 'mode': 'water', - 'type': 'pro', - 'group': 'stroke'}), - - ('wash', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Wash (degrees)', - 'ax_min': 0, - 'ax_max': 30, - 'default': 0, - 'sigfigs': 1, - 'maysmooth': True, - 'mode': 'water', - 'type': 'pro', - 'group': 'stroke'}), - - ('peakforceangle', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Peak Force Angle', - 'ax_min': -50, - 'ax_max': 50, - 'default': 0, - 'sigfigs': 0, - 'maysmooth': True, - 'mode': 'water', - 'type': 'pro', - 'group': 'stroke'}), - - - ('totalangle', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Drive Length (deg)', - 'ax_min': 40, - 'ax_max': 140, - 'default': 0, - 'sigfigs': 0, - 'maysmooth': True, - 'mode': 'water', - 'type': 'pro', - 'group': 'stroke'}), - - - ('effectiveangle', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Effective Drive Length (deg)', - 'ax_min': 40, - 'ax_max': 140, - 'default': 0, - 'sigfigs': 0, - 'mode': 'water', - 'maysmooth': True, - 'type': 'pro', - 'group': 'stroke'}), - - ('rhythm', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Stroke Rhythm', - 'ax_min': 20, - 'ax_max': 55, - 'default': 1.0, - 'sigfigs': 0, - 'mode': 'erg', - 'maysmooth': True, - 'type': 'pro', - 'group': 'stroke'}), - - ('efficiency', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'OTW Efficiency (%)', - 'ax_min': 0, - 'ax_max': 110, - 'default': 0, - 'sigfigs': 0, - 'mode': 'water', - 'maysmooth': True, - 'type': 'pro', - 'group': 'forcepower'}), - - ('distanceperstroke', { - 'numtype': 'float', - 'null': True, - 'verbose_name': 'Distance per Stroke (m)', - 'ax_min': 0, - 'ax_max': 15, - 'default': 0, - 'sigfigs': 1, - 'maysmooth': True, - 'mode': 'both', - 'type': 'basic', - 'group': 'basic'}), +with open("rowingmetrics.yaml", "r") as file: + td = yaml.safe_load(file) +rowingmetrics = tuple( + (key, value) + for key, value in td.items() ) + + metricsdicts = {} for key, dict in rowingmetrics: metricsdicts[key] = dict diff --git a/rowingmetrics.yaml b/rowingmetrics.yaml new file mode 100644 index 00000000..73957883 --- /dev/null +++ b/rowingmetrics.yaml @@ -0,0 +1,288 @@ +time: + numtype: float + 'null': true + verbose_name: Time + ax_min: 0 + ax_max: 100000.0 + mode: both + type: basic + group: basic + maysmooth: false + sigfigs: -1 +hr: + numtype: integer + 'null': true + verbose_name: Heart Rate (bpm) + ax_min: 100 + ax_max: 200 + mode: both + type: basic + maysmooth: false + group: athlete + sigfigs: 0 +pace: + numtype: float + 'null': true + verbose_name: Pace (/500m) + ax_min: 210000.0 + ax_max: 75000.0 + mode: both + type: basic + sigfigs: 1 + maysmooth: true + group: basic +velo: + numtype: float + 'null': true + verbose_name: Boat Speed (m/s) + ax_min: 0 + ax_max: 8 + default: 0 + mode: both + sigfigs: 1 + maysmooth: true + type: pro + group: basic +spm: + numtype: float + 'null': true + verbose_name: Stroke Rate (spm) + ax_min: 15 + ax_max: 45 + mode: both + sigfigs: 1 + type: basic + maysmooth: true + group: basic +driveenergy: + numtype: float + 'null': true + verbose_name: Work Per Stroke (J) + ax_min: 0 + ax_max: 1000 + mode: both + sigfigs: 0 + type: pro + maysmooth: true + group: forcepower +power: + numtype: float + 'null': true + verbose_name: Power (W) + ax_min: 0 + ax_max: 600 + mode: both + sigfigs: 0 + type: basic + maysmooth: true + group: forcepower +averageforce: + numtype: float + 'null': true + verbose_name: Average Drive Force (N) + ax_min: 0 + ax_max: 1200 + mode: both + sigfigs: 0 + maysmooth: true + type: pro + group: forcepower +peakforce: + numtype: float + 'null': true + verbose_name: Peak Drive Force (N) + ax_min: 0 + ax_max: 1500 + sigfigs: 0 + mode: both + maysmooth: true + type: pro + group: forcepower +drivelength: + numtype: float + 'null': true + verbose_name: Drive Length (m) + ax_min: 0 + ax_max: 2.5 + mode: rower + sigfigs: 2 + maysmooth: false + type: pro + group: stroke +forceratio: + numtype: float + 'null': true + verbose_name: Average/Peak Force Ratio + ax_min: 0 + ax_max: 1 + sigfigs: 2 + maysmooth: true + mode: both + type: pro + group: forcepower +distance: + numtype: float + 'null': true + verbose_name: Interval Distance (m) + ax_min: 0 + ax_max: 100000.0 + sigfigs: 0 + mode: both + maysmooth: false + type: basic + group: basic +cumdist: + numtype: float + 'null': true + verbose_name: Cumulative Distance (m) + ax_min: 0 + ax_max: 100000.0 + mode: both + sigfigs: 0 + maysmooth: false + type: basic + group: basic +drivespeed: + numtype: float + 'null': true + verbose_name: Drive Speed (m/s) + ax_min: 0 + ax_max: 4 + default: 0 + sigfigs: 2 + maysmooth: true + mode: both + type: pro + group: stroke +catch: + numtype: float + 'null': true + verbose_name: Catch Angle (degrees) + ax_min: -40 + ax_max: -75 + default: 0 + sigfigs: 0 + mode: water + maysmooth: true + type: pro + group: stroke +slip: + numtype: float + 'null': true + verbose_name: Slip (degrees) + ax_min: 0 + ax_max: 20 + default: 0 + sigfigs: 1 + maysmooth: true + mode: water + type: pro + group: stroke +finish: + numtype: float + 'null': true + verbose_name: Finish Angle (degrees) + ax_min: 20 + ax_max: 55 + default: 0 + sigfigs: 0 + maysmooth: true + mode: water + type: pro + group: stroke +wash: + numtype: float + 'null': true + verbose_name: Wash (degrees) + ax_min: 0 + ax_max: 30 + default: 0 + sigfigs: 1 + maysmooth: true + mode: water + type: pro + group: stroke +peakforceangle: + numtype: float + 'null': true + verbose_name: Peak Force Angle + ax_min: -50 + ax_max: 50 + default: 0 + sigfigs: 0 + maysmooth: true + mode: water + type: pro + group: stroke +totalangle: + numtype: float + 'null': true + verbose_name: Drive Length (deg) + ax_min: 40 + ax_max: 140 + default: 0 + sigfigs: 0 + maysmooth: true + mode: water + type: pro + group: stroke +check_factor: + numtype: float + 'null': true + verbose_name: Check Factor + ax_min: 0 + ax_max: 100 + default: 0 + sigfigs: 1 + maysmooth: true + mode: water + type: pro + group: stroke +effectiveangle: + numtype: float + 'null': true + verbose_name: Effective Drive Length (deg) + ax_min: 40 + ax_max: 140 + default: 0 + sigfigs: 0 + mode: water + maysmooth: true + type: pro + group: stroke +rhythm: + numtype: float + 'null': true + verbose_name: Stroke Rhythm + ax_min: 20 + ax_max: 55 + default: 1.0 + sigfigs: 0 + mode: erg + maysmooth: true + type: pro + group: stroke +efficiency: + numtype: float + 'null': true + verbose_name: OTW Efficiency (%) + ax_min: 0 + ax_max: 110 + default: 0 + sigfigs: 0 + mode: water + maysmooth: true + type: pro + group: forcepower +distanceperstroke: + numtype: float + 'null': true + verbose_name: Distance per Stroke (m) + ax_min: 0 + ax_max: 15 + default: 0 + sigfigs: 1 + maysmooth: true + mode: both + type: basic + group: basic