Private
Public Access
1
0

OTW power CP graph working!

This commit is contained in:
Sander Roosendaal
2017-06-08 14:19:21 +02:00
parent 8b42de8a53
commit 832d6f8878
4 changed files with 130 additions and 84 deletions

View File

@@ -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')

View File

@@ -77,8 +77,28 @@
</div>
</div>
<div class="grid_12 alpha">
<div class="grid_6 alpha">
<p>&nbsp;</p>
</div>
<div class="grid_6 omega">
<div class="grid_2 suffix_4 alpha">
<p>
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
<a class="button blue small" href="/rowers/otw-bests">OTW Ranking Pieces</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">OTW Ranking Pieces</a>
{% endif %}
</p>
<p>
Analyse power vs piece duration to make predictions.
</p>
</div>
</div>
</div>
{% endblock %}

View File

@@ -67,9 +67,12 @@
<a href="/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">https://rowsandall.com/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
</p>
<p>The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.</p>
<p>This page will evolve and try to give you guidance on where to improve.</p>
<p>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.
</p>
<p>At the bottom of the page, you will find predictions derived from the model.</p>
</div>
<div id="form" class="grid_6 omega">
<p>Use this form to select a different date range:</p>
@@ -98,6 +101,16 @@
</div>
</div>
<div id="theplot" class="grid_12 alpha">
<h2>Critical Power Plot</h2>
{{ the_div|safe }}
</div>
<div class="grid_12 alpha">
<h2>Ranking Piece Results</h2>
@@ -109,6 +122,7 @@
<tr>
<th> Distance</th>
<th> Duration</th>
<th> Avg Power</th>
<th> Date</th>
<th> Avg HR </th>
<th> Max HR </th>
@@ -118,8 +132,9 @@
<tbody>
{% for workout in rankingworkouts %}
<tr>
<td> {{ workout.distance }} </td>
<td> {{ workout.distance }} m</td>
<td> {{ workout.duration |durationprint:"%H:%M:%S.%f" }} </td>
<td> {{ avgpower|lookup:workout.id }} W</td>
<td> {{ workout.date }} </td>
<td> {{ workout.averagehr }} </td>
<td> {{ workout.maxhr }} </td>
@@ -137,63 +152,56 @@
</div>
<div id="theplot" class="grid_12 alpha">
<h2>Critical Power Plot</h2>
{{ the_div|safe }}
</div>
<div id="predictions" class="grid_12 alpha">
<h2>Pace predictions for Ranking Pieces</h2>
<h2>Pace predictions for Ranking Pieces</h2>
<p>Add non-ranking piece using the form. The piece will be added in the prediction tables below. </p>
<div class="grid_4 alpha">
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{{ form.value }} {{ form.pieceunit }}
{% csrf_token %}
</div>
<div class="grid_2 suffix_6 omega">
<input name="piece" class="button green"
formaction="/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
type="submit" value="Add">
</form>
</div>
<p>Add non-ranking piece using the form. The piece will be added in the prediction tables below. </p>
<div id="paul" class="grid_6 alpha">
No Paul Data
</div>
<div id="cpmodel" class="grid_6 omega">
<h3>CP Model</h3>
<table width="70%" class="listtable">
<thead>
<tr>
<th> Duration</th>
<th> Power </th>
<tr>
</thead>
<tbody>
{% for pred in cpredictions %}
<tr>
{% for key, value in pred.items %}
{% if key == "power" %}
<td> {{ value }} W </td>
{% endif %}
{% if key == "duration" %}
<td> {{ value |deltatimeprint }} </td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
<div id="cpmodel" class="grid_6 alpha">
<table width="70%" class="listtable">
<thead>
<tr>
<th> Duration</th>
<th> Power </th>
<tr>
</thead>
<tbody>
{% for pred in cpredictions %}
<tr>
{% for key, value in pred.items %}
{% if key == "power" %}
<td> {{ value }} W </td>
{% endif %}
{% if key == "duration" %}
<td> {{ value |deltatimeprint }} </td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="grid_3">
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{{ form.value }} {{ form.pieceunit }}
{% csrf_token %}
</div>
<div class="grid_1">
minutes
</div>
<div class="grid_2 omega">
<input name="piece" class="button green"
formaction="/rowers/{{ id }}/otw-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
type="submit" value="Add">
</form>
</div>
</div>
{% endblock %}

View File

@@ -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,