diff --git a/rowers/datautils.py b/rowers/datautils.py index 8c7727c7..8489af1f 100644 --- a/rowers/datautils.py +++ b/rowers/datautils.py @@ -468,7 +468,6 @@ def getfastest(df,thevalue,mode='distance'): starttime = griddata(restime,starttimes,[thevalue*60*1000],method='linear',rescale=True) duration = griddata(restime,restime,[thevalue*60*1000],method='linear',rescale=True) endtime = starttime+duration - print(distance,starttime,endtime ) return distance[0],starttime[0]/1000.,endtime[0]/1000. return 0 # pragma: no cover diff --git a/rowers/templates/summary_edit.html b/rowers/templates/summary_edit.html index fb021a59..13e6f8c7 100644 --- a/rowers/templates/summary_edit.html +++ b/rowers/templates/summary_edit.html @@ -41,24 +41,75 @@ title="Jump to following workout">Next {% endif %}
++
| Name | {{ workout.name }} | +|
|---|---|---|
| Distance: | {{ workout.distance }}m | +|
| Duration: | {{ workout.duration |durationprint:"%H:%M:%S.%f" }} | +|
| Public link to this workout | ++ https://rowsandall.com/rowers/workout/{{ workout.id|encode }} + | + |
| Name | {{ workout.name }} | -|
|---|---|---|
| Distance: | {{ workout.distance }}m | -|
| Duration: | {{ workout.duration |durationprint:"%H:%M:%S.%f" }} | -|
| Public link to this workout | -- https://rowsandall.com/rowers/workout/{{ workout.id|encode }} - | - |
+
+ {{ intervalstats }}
+
+
+ This new, experimental feature tries to find intervals by looking for patterns in the data. It does not + autodetect rest and work intervals yet. The resulting "interval string" is copied to the Interval Shorthand + section below, where you can edit it. +
+ +See the how-to at the bottom of this page for details on how to use this form. @@ -70,6 +121,8 @@ {% csrf_token %} +
With this form, you can specify a power or pace level. Everything faster/harder than the @@ -92,40 +145,6 @@
-
- {{ intervalstats }}
-
-
- This is a quick way to enter the intervals using a special mini-language.
diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz new file mode 100644 index 00000000..887f897c Binary files /dev/null and b/rowers/tests/testdata/testdata.tcx.gz differ diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index fb740432..4fb21bef 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -18,6 +18,8 @@ from rowers.utils import intervals_to_string from urllib.parse import urlparse, parse_qs from json.decoder import JSONDecodeError +import ruptures as rpt + def default(o): # pragma: no cover if isinstance(o, numpy.int64): return int(o) if isinstance(o, numpy.int32): return int(o) @@ -6144,6 +6146,42 @@ def workout_summary_edit_view(request,id,message="",successmessage="" powerupdateform = PowerIntervalUpdateForm(initial=data) + # feeling lucky / ruptures + if request.method == 'POST' and "ruptures" in request.POST: + df = pd.DataFrame({ + 'spm':rowdata.df[' Cadence (stokes/min)'], + 'power':rowdata.df[' Power (watts)'], + 'v':rowdata.df[' AverageBoatSpeed (m/s)'] + }) + algo = rpt.Pelt(model="rbf").fit(df.values) + result = algo.predict(pen=10) + + + df['time'] = rowdata.df['TimeStamp (sec)'].values + timeprev = int(df['time'].values[0]) + timenext = int(df['time'].values[result[0]]) + s = '{delta}sec'.format(delta=timenext-timeprev) + + + for i in range(len(result)-1): + timeprev = int(df['time'].values[result[i]-1]) + timenext = int(df['time'].values[result[i+1]-1]) + interval = '+{delta}sec'.format(delta=timenext-timeprev) + s += interval + + try: + rowdata.updateinterval_string(s) + except: + messages.error(request,"Nope, you were not lucky") + + intervalstats = rowdata.allstats() + itime, idist, itype = rowdata.intervalstats_values() + nrintervals = len(idist) + savebutton = 'savestringform' + intervalString = s + form = SummaryStringForm(initial={'intervalstring':intervalString}) + + # We have submitted the mini language interpreter if request.method == 'POST' and "intervalstring" in request.POST: form = SummaryStringForm(request.POST)