diff --git a/rowers/dataprep.py b/rowers/dataprep.py index cc8f199f..c14d7d2d 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1126,6 +1126,9 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', summary='', makeprivate=False, oarlength=2.89, inboard=0.88, + boatname='', + empowerside='port', + seatnumber=1, forceunit='lbs', consistencychecks=False, startdatetime='', @@ -1343,6 +1346,9 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', w.startdatetime = workoutstartdatetime w.inboard = inboard w.oarlength = oarlength + w.seatnumber = seatnumber + w.boatname = boatname + w.empowerside = empowerside w.timezone = timezone_str w.privacy = privacy w.impeller = impeller @@ -1367,6 +1373,9 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', maxhr=maxhr, averagehr=averagehr, startdatetime=workoutstartdatetime, inboard=inboard, oarlength=oarlength, + boatname=boatname, + empowerside=empowerside, + seatnumber=seatnumber, timezone=timezone_str, privacy=privacy, impeller=impeller) @@ -1418,6 +1427,9 @@ def new_workout_from_file(r, f2, oarlockfirmware='', inboard=None, oarlength=None, + boatname='', + seatnumber=1, + empowerside='port', impeller=False, uploadoptions={'boattype': '1x', 'workouttype': 'rower'}): message = "" @@ -1583,6 +1595,8 @@ def new_workout_from_file(r, f2, startdatetime=startdatetime, rpe=rpe, inboard=inboard, oarlength=oarlength, + seatnumber=seatnumber, boatname=boatname, + empowerside=empowerside, title=title, forceunit='N', impeller=impeller, diff --git a/rowers/dataroutines.py b/rowers/dataroutines.py index 8ad8d38a..a3e06805 100644 --- a/rowers/dataroutines.py +++ b/rowers/dataroutines.py @@ -1554,19 +1554,22 @@ def read_data(columns, ids=[], doclean=True, workstrokesonly=True, debug=False, _ = dataplep(rowdata.df, id=id, bands=True, otwpower=True, barchart=True, polars=True) - df = pl.scan_parquet(f) - if startenddict: - try: - startsecond, endsecond = startenddict[id] - df = df.filter(pl.col("time") >= 1.0e3*startsecond, - pl.col("time") <= 1.0e3*endsecond) - df = df.with_columns(time = pl.col("time")-1.0e3*startsecond) - if 'cumdist' in columns: - df = df.collect() - df = df.with_columns(cumdist = pl.col("cumdist")-df[0, "cumdist"]).lazy() - except KeyError: - pass - data.append(df) + try: + df = pl.scan_parquet(f) + if startenddict: + try: + startsecond, endsecond = startenddict[id] + df = df.filter(pl.col("time") >= 1.0e3*startsecond, + pl.col("time") <= 1.0e3*endsecond) + df = df.with_columns(time = pl.col("time")-1.0e3*startsecond) + if 'cumdist' in columns: + df = df.collect() + df = df.with_columns(cumdist = pl.col("cumdist")-df[0, "cumdist"]).lazy() + except KeyError: + pass + data.append(df) + except ComputeError: + pass try: data = pl.collect_all(data) @@ -2169,14 +2172,16 @@ def dataplep(rowdatadf, id=0, inboard=0.88, forceunit='lbs', bands=True, barchar df = df.with_columns((pl.col(" AverageDriveForce (lbs)")/pl.col(" PeakDriveForce (lbs)")).alias("forceratio")) else: df = df.with_columns((pl.lit(0)).alias("forceratio")) - f = df['TimeStamp (sec)'].diff().mean() + try: + f = df['TimeStamp (sec)'].diff().mean() + except TypeError: + f = 0 + windowsize = 1 if f != 0 and not np.isinf(f): try: windowsize = 2 * (int(10. / (f))) + 1 except ValueError: windowsize = 1 - else: - windowsize = 1 if windowsize <= 3: windowsize = 5 diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 20989940..4ca7676b 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -22,7 +22,7 @@ import polars as pl import pytz from rowers.rower_rules import ispromember -from polars.exceptions import ColumnNotFoundError +from polars.exceptions import ColumnNotFoundError, ComputeError from scipy.interpolate import griddata from scipy.signal import savgol_filter @@ -758,16 +758,28 @@ def performance_chart(user, startdate=None, enddate=None, kfitness=42, kfatigue= df = df.filter(pl.col("date") > startdate) - df2 = pl.DataFrame({ - "testpower" :df['testpower'], - "testduration":df['testduration'].apply( - lambda x: totaltime_sec_to_string(x, shorten=True)), - "fitness":df['fitness'], - "fatigue":df['fatigue'], - "form":df['form'], - "impulse":df['impulse'], - "date": df['date'].dt.strftime('%Y-%m-%d'), + try: + df2 = pl.DataFrame({ + "testpower" :df['testpower'], + "testduration":df['testduration'].apply( + lambda x: totaltime_sec_to_string(x, shorten=True)), + "fitness":df['fitness'], + "fatigue":df['fatigue'], + "form":df['form'], + "impulse":df['impulse'], + "date": df['date'].dt.strftime('%Y-%m-%d'), }) + except ComputeError: + df2 = pl.DataFrame({ + "testpower" :df['testpower'], + "fitness":df['fitness'], + "fatigue":df['fatigue'], + "form":df['form'], + "impulse":df['impulse'], + "date": df['date'].dt.strftime('%Y-%m-%d'), + }) + df2 = df2.with_columns((pl.lit("--")).alias("testduration")) + df2 = df2.fill_nan(0) diff --git a/rowers/models.py b/rowers/models.py index a05de7c5..bfa22a1c 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -3626,6 +3626,9 @@ class Workout(models.Model): # empower stuff inboard = models.FloatField(default=0.88) oarlength = models.FloatField(default=2.89) + seatnumber = models.IntegerField(default=1, verbose_name='Seat Number') + boatname = models.CharField(default='', blank=True, null=True, max_length=150, verbose_name='Boat Name') + empowerside = models.CharField(default='starboard', blank=True, null=True, max_length=150, verbose_name='Empower Oarlock side') notes = models.CharField(blank=True, null=True, max_length=1000) summary = models.TextField(blank=True) @@ -4360,6 +4363,9 @@ class WorkoutForm(ModelForm): 'distance', 'workouttype', 'boattype', + 'boatname', + 'seatnumber', + 'empowerside', 'dragfactor', 'weightcategory', 'adaptiveclass', diff --git a/rowers/nkimportutils.py b/rowers/nkimportutils.py index 9d682a54..67d65f85 100644 --- a/rowers/nkimportutils.py +++ b/rowers/nkimportutils.py @@ -82,6 +82,14 @@ def add_workout_from_data(userid, nkid, data, strokedata, source='nk', splitdata oarlockfirmware = oarlocksession["firmwareVersion"] except KeyError: oarlockfirmware = '' + try: + boatName = oarlocksession["boatName"] + except: + boatName = '' + try: + portStarboard = oarlocksession["portStarboard"] + except: + portStarboard = 1 else: # pragma: no cover # boatName = '' oarLength = 289 @@ -108,6 +116,8 @@ def add_workout_from_data(userid, nkid, data, strokedata, source='nk', splitdata 'totalDistance': totalDistance, 'useImpeller': useImpeller, 'seatNumber': seatNumber, + 'boatName': boatName, + 'portStarboard': portStarboard, } dologging('nklog.log',json.dumps(uploadoptions)) diff --git a/rowers/templates/panel_empower.html b/rowers/templates/panel_empower.html new file mode 100644 index 00000000..2cd66d26 --- /dev/null +++ b/rowers/templates/panel_empower.html @@ -0,0 +1,22 @@ +{% load rowerfilters %} +{% load tz %} +
    +
  • + + + {% localtime on %} + + {% endlocaltime %} + + + + + + + + + +
    Seat Number:{{ workout.seatnumber}}
    Empower side:{{ workout.empowerside }}
    Boat name:{{ workout.boatname }}
    Oar length:{{ workout.oarlength }}
    Oar inboard:{{ workout.inboard }}
    +
  • +
+ diff --git a/rowers/tests/test_cpchart.py b/rowers/tests/test_cpchart.py index 6f46c0cf..3c6fd404 100644 --- a/rowers/tests/test_cpchart.py +++ b/rowers/tests/test_cpchart.py @@ -95,6 +95,9 @@ class CPChartTest(TestCase): 'distance': 500, 'workouttype': 'rower', 'boattype': '1x', + 'boatname': 'CatchUp', + 'empowerside': 'starboard', + 'seatnumber': 1, 'weightcategory': 'hwt', 'adaptiveclass': 'None', 'notes': faker.text(), diff --git a/rowers/tests/test_races.py b/rowers/tests/test_races.py index ebf0ac06..e783db2e 100644 --- a/rowers/tests/test_races.py +++ b/rowers/tests/test_races.py @@ -1121,6 +1121,9 @@ class IndoorChallengesTest(TestCase): 'adaptiveclass': 'None', 'notes': faker.text(), 'rankingpiece': True, + 'empowerside': 'port', + 'boatname': 'Dolfijn', + 'seatnumber': 1, 'duplicate': False, 'avghr': '160', 'avgpwr': 0, diff --git a/rowers/tests/test_settings.py b/rowers/tests/test_settings.py index 86dc231d..504139fa 100644 --- a/rowers/tests/test_settings.py +++ b/rowers/tests/test_settings.py @@ -34,6 +34,9 @@ class DataTest(TestCase): 'workouttype':'water', 'rpe':1, 'boattype':'1x', + 'boatname': 'BOAT1', + 'empowerside': 'port', + 'seatnumber': 4, 'private':False, } form = WorkoutForm(data=form_data) diff --git a/rowers/tests/test_uploads.py b/rowers/tests/test_uploads.py index b27a198a..f93418e8 100644 --- a/rowers/tests/test_uploads.py +++ b/rowers/tests/test_uploads.py @@ -101,6 +101,9 @@ class ViewTest(TestCase): 'rpe':4, 'dragfactor':'112', 'raceid':0, + 'seatnumber': 1, + 'boatname': '', + 'empowerside': 'port', 'landingpage':'workout_edit_view', 'private':True, 'notes':'noot mies', diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 5735f761..04557774 100644 Binary files a/rowers/tests/testdata/testdata.tcx.gz and b/rowers/tests/testdata/testdata.tcx.gz differ diff --git a/rowers/utils.py b/rowers/utils.py index 7f96a94a..49443593 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -64,6 +64,7 @@ workflowmiddlepanel = ( ('panel_summary.html', 'Summary'), ('panel_map.html', 'Map'), ('panel_comments.html', 'Basic Info and Links'), + ('panel_empower.html', 'Empower Oarlock Info'), ('panel_notes.html', 'Workout Notes'), ('panel_shortcomment.html', 'Comment Link'), ('panel_middlesocial.html', 'Social Media Share Buttons'), diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index e4b49aef..8e74ee2f 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -680,6 +680,9 @@ def addmanual_view(request, raceid=0): privacy = form.cleaned_data.get('privacy', 'visible') rankingpiece = form.cleaned_data.get('rankingpiece', False) duplicate = form.cleaned_data.get('duplicate', False) + seatnumber = form.cleaned_data.get('seatnumber', 1) + boatname = form.cleaned_data.get('boatname', '') + empowerside = form.cleaned_data.get('empowerside','port') if private: # pragma: no cover privacy = 'private' @@ -723,6 +726,9 @@ def addmanual_view(request, raceid=0): w.rpe = rpe w.workouttype = workouttype w.boattype = boattype + w.boatname = boatname + w.empowerside = empowerside + w.seatnumber = seatnumber w.distance = distance w.duration = duration w.save() @@ -4385,6 +4391,10 @@ def workout_edit_view(request, id=0, message="", successmessage=""): 'rankingpiece', Workout.objects.get(id=row.id).rankingpiece) duplicate = form.cleaned_data.get( 'duplicate', Workout.objects.get(id=row.id).duplicate) + seatnumber = form.cleaned_data.get('seatnumber', 1) + boatname = form.cleaned_data.get('boatname', '') + empowerside = form.cleaned_data.get('empowerside','port') + if private: privacy = 'private' @@ -4438,6 +4448,9 @@ def workout_edit_view(request, id=0, message="", successmessage=""): row.rankingpiece = rankingpiece row.timezone = thetimezone row.plannedsession = ps + row.boatname = boatname + row.empowerside = empowerside + row.seatnumber = seatnumber dragchanged = False if newdragfactor != row.dragfactor: # pragma: no cover @@ -4855,6 +4868,13 @@ def workout_upload_api(request): inboard = post_data.get('inboard', None) oarlength = post_data.get('oarlength', None) useImpeller = post_data.get('useImpeller', False) + seatnumber = post_data.get('seatNumber', 1) + boatname = post_data.get('boatName','') + portStarboard = post_data.get('portStarboard', 1) + empowerside = 'port' + if portStarboard == 1: + empowerside = 'starboard' + totalDistance = post_data.get('totalDistance', None) elapsedTime = post_data.get('elapsedTime', None) @@ -4946,6 +4966,9 @@ def workout_upload_api(request): oarlength=oarlength, impeller=useImpeller, workoutid=workoutid, + empowerside=empowerside, + boatname=boatname, + seatnumber=seatnumber, ) if id == 0: # pragma: no cover