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 }} + +
+

Edit Workout Interval Data

    -
  • - - - - - - - - - - -
    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 }} - -
    +
  • +

    Updated Summary

    +
    + {% csrf_token %} + + + {% for key,value in formvalues.items %} + + {% endfor %} +

    + +

    + + Reset to last saved +   + Restore Original data + +
    +

    +

    +					{{ intervalstats }}
    +				
    +

    +
  • +
  • + + + + {{ interactiveplot |safe }} + + {{ the_div |safe }} +
  • +
  • +

    Feeling lucky?

    +

    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. +

    + + + {{ ruptureform.as_table }} +
    + {% csrf_token %} + +
    +

    +
  • +
  • Interval Shorthand

    See the how-to at the bottom of this page for details on how to use this form. @@ -70,6 +121,8 @@ {% csrf_token %} +

  • +
  • Intervals by Power/Pace

    With this form, you can specify a power or pace level. Everything faster/harder than the @@ -92,40 +145,6 @@

  • -
  • - - - - {{ interactiveplot |safe }} - - {{ the_div |safe }} -
  • -
  • -

    Updated Summary

    -
    - {% csrf_token %} - - - {% for key,value in formvalues.items %} - - {% endfor %} -

    - -

    - - Reset to last saved -   - Restore Original data - -
    -

    -

    -        {{ intervalstats }}
    -      
    -

    -
  • Interval Shorthand How-To

    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)