diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py
index 0fdb77c1..0e2e4d23 100644
--- a/rowers/interactiveplots.py
+++ b/rowers/interactiveplots.py
@@ -608,6 +608,10 @@ def interactive_otwcpchart(powerdf,promember=0):
x_axis_type = 'log'
y_axis_type = 'linear'
+ deltas = powerdf['Delta'].apply(lambda x: timedeltaconv(x))
+ powerdf['ftime'] = niceformat(deltas)
+
+
source = ColumnDataSource(
data = powerdf
)
@@ -668,7 +672,7 @@ def interactive_otwcpchart(powerdf,promember=0):
)
plot.circle('Delta','CP',source=source,fill_color='red',size=15,
- legend='Power')
+ legend='Power Data')
plot.xaxis.axis_label = "Duration (seconds)"
plot.yaxis.axis_label = "Power (W)"
@@ -676,6 +680,14 @@ def interactive_otwcpchart(powerdf,promember=0):
plot.x_range = Range1d(1,2*max(thesecs))
plot.legend.orientation = "vertical"
+ hover = plot.select(dict(type=HoverTool))
+
+ hover.tooltips = OrderedDict([
+ ('Duration ','@ftime'),
+ ('Power (W)','@CP{int}'),
+ ])
+
+ hover.mode = 'mouse'
plot.line('duration','power',source=sourcecomplex,legend="CP Model",
color='green')
diff --git a/rowers/templates/analysis.html b/rowers/templates/analysis.html
index 2dc2cf43..9fd83289 100644
--- a/rowers/templates/analysis.html
+++ b/rowers/templates/analysis.html
@@ -77,8 +77,28 @@
+
+
+
+
+
+ {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
+ OTW Ranking Pieces
+ {% else %}
+ OTW Ranking Pieces
+ {% endif %}
+
+
+ Analyse power vs piece duration to make predictions.
+
+
+
+
+
{% endblock %}
diff --git a/rowers/templates/otwrankings.html b/rowers/templates/otwrankings.html
index 35b35865..a78330e4 100644
--- a/rowers/templates/otwrankings.html
+++ b/rowers/templates/otwrankings.html
@@ -67,9 +67,12 @@
https://rowsandall.com/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}
-The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.
-
-This page will evolve and try to give you guidance on where to improve.
+ The table gives the OTW efforts you marked as Ranking Piece.
+ The graph shows the best segments from those pieces, plotted as
+ average power (over the segment) vs the duration of the segment/
+ In other words: How long you can hold that power.
+
+At the bottom of the page, you will find predictions derived from the model.
+
+
+
+
+
Critical Power Plot
+
+ {{ the_div|safe }}
+
+
+
Ranking Piece Results
@@ -109,6 +122,7 @@
Distance
Duration
+ Avg Power
Date
Avg HR
Max HR
@@ -118,8 +132,9 @@
{% for workout in rankingworkouts %}
- {{ workout.distance }}
+ {{ workout.distance }} m
{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
+ {{ avgpower|lookup:workout.id }} W
{{ workout.date }}
{{ workout.averagehr }}
{{ workout.maxhr }}
@@ -137,63 +152,56 @@
-
-
-
-
Critical Power Plot
-
- {{ the_div|safe }}
-
-
-
-
Pace predictions for Ranking Pieces
+
Pace predictions for Ranking Pieces
-
Add non-ranking piece using the form. The piece will be added in the prediction tables below.
-
-
-
-
-
-
+
Add non-ranking piece using the form. The piece will be added in the prediction tables below.
-
- No Paul Data
-
-
-
CP Model
-
-
-
- Duration
- Power
-
-
-
- {% for pred in cpredictions %}
-
- {% for key, value in pred.items %}
- {% if key == "power" %}
- {{ value }} W
- {% endif %}
- {% if key == "duration" %}
- {{ value |deltatimeprint }}
- {% endif %}
- {% endfor %}
-
- {% endfor %}
-
-
+
+
+
+
+ Duration
+ Power
+
+
+
+ {% for pred in cpredictions %}
+
+ {% for key, value in pred.items %}
+ {% if key == "power" %}
+ {{ value }} W
+ {% endif %}
+ {% if key == "duration" %}
+ {{ value |deltatimeprint }}
+ {% endif %}
+ {% endfor %}
+
+ {% endfor %}
+
+
-
+
+
+
+
+
+ minutes
+
+
+
+
+
+
+
{% endblock %}
diff --git a/rowers/views.py b/rowers/views.py
index 85f321aa..0c5ae939 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -292,14 +292,11 @@ def iscoachmember(user):
return result
def getrower(user):
- if not user.is_anonymous():
- try:
- r = Rower.objects.get(user=user)
- except Rower.DoesNotExist:
- r = Rower(user=user)
- r.save()
- else:
- raise PermissionDenied("You need to log in to use this function")
+ try:
+ r = Rower.objects.get(user=user)
+ except Rower.DoesNotExist:
+ r = Rower(user=user)
+ r.save()
return r
@@ -2900,8 +2897,10 @@ def otwrankings_view(request,theuser=0,
thesecs.append(timesecs)
-
- maxt = pd.Series(thesecs).max()
+ if len(thesecs) != 0:
+ maxt = pd.Series(thesecs).max()
+ else:
+ maxt = 1000.
maxlog10 = np.log10(maxt)
logarr = np.arange(100)*maxlog10/100.
@@ -2912,11 +2911,16 @@ def otwrankings_view(request,theuser=0,
delta = []
cpvalue = []
+ avgpower = {}
dfgrouped = df.groupby(['workoutid'])
for id,group in dfgrouped:
tt = group['time']
ww = group['power']
+ try:
+ avgpower[id] = int(ww.mean())
+ except ValueError:
+ avgpower[id] = '---'
if not np.isnan(ww.mean()):
length = len(ww)
dt = []
@@ -2946,6 +2950,7 @@ def otwrankings_view(request,theuser=0,
for d in logarr:
delta.append(d)
+ print avgpower
dt = pd.Series(delta,name='Delta')
cpvalue = pd.Series(cpvalue,name='CP')
@@ -2955,13 +2960,15 @@ def otwrankings_view(request,theuser=0,
'CP':cpvalue,
})
- powerdf.sort_values(['Delta','CP'],ascending=[1,0])
- powerdf.drop_duplicates(subset='Delta',keep='first')
+ powerdf = powerdf[powerdf['CP']>0]
+ powerdf.dropna(axis=0,inplace=True)
+ powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True)
+ powerdf.drop_duplicates(subset='Delta',keep='first',inplace=True)
# create interactive plot
if len(powerdf) !=0 :
- res = interactive_otwcpchart(powerdf)
+ res = interactive_otwcpchart(powerdf,promember=promember)
script = res[0]
div = res[1]
p1 = res[2]
@@ -2979,16 +2986,12 @@ def otwrankings_view(request,theuser=0,
if request.method == 'POST' and "piece" in request.POST:
form = PredictedPieceForm(request.POST)
- if form.is_valid():
- value = form.cleaned_data['value']
- hourvalue,value = divmod(value,60)
- if hourvalue >= 24:
- hourvalue = 23
- pieceunit = form.cleaned_data['pieceunit']
- if pieceunit == 'd':
- rankingdistances.append(value)
- else:
- rankingdurations.append(datetime.time(minute=value,hour=hourvalue))
+ clean = form.is_valid()
+ value = form.cleaned_data['value']
+ hourvalue,value = divmod(value,60)
+ if hourvalue >= 24:
+ hourvalue = 23
+ rankingdurations.append(datetime.time(minute=value,hour=hourvalue))
else:
form = PredictedPieceForm()
@@ -3012,13 +3015,15 @@ def otwrankings_view(request,theuser=0,
if pwr <= 0:
pwr = 50.
- a = {
- 'duration':timedeltaconv(t),
- 'power':int(pwr)}
- cpredictions.append(a)
+ if not np.isnan(pwr):
+ a = {
+ 'duration':timedeltaconv(t),
+ 'power':int(pwr)}
+ cpredictions.append(a)
- print cpredictions
+ del form.fields["pieceunit"]
+
messages.error(request,message)
return render(request, 'otwrankings.html',
{'rankingworkouts':theworkouts,
@@ -3026,6 +3031,7 @@ def otwrankings_view(request,theuser=0,
'the_div':div,
'predictions':predictions,
'cpredictions':cpredictions,
+ 'avgpower':avgpower,
'form':form,
'dateform':dateform,
'deltaform':deltaform,