OTW power CP graph working!
This commit is contained in:
@@ -608,6 +608,10 @@ def interactive_otwcpchart(powerdf,promember=0):
|
|||||||
x_axis_type = 'log'
|
x_axis_type = 'log'
|
||||||
y_axis_type = 'linear'
|
y_axis_type = 'linear'
|
||||||
|
|
||||||
|
deltas = powerdf['Delta'].apply(lambda x: timedeltaconv(x))
|
||||||
|
powerdf['ftime'] = niceformat(deltas)
|
||||||
|
|
||||||
|
|
||||||
source = ColumnDataSource(
|
source = ColumnDataSource(
|
||||||
data = powerdf
|
data = powerdf
|
||||||
)
|
)
|
||||||
@@ -668,7 +672,7 @@ def interactive_otwcpchart(powerdf,promember=0):
|
|||||||
)
|
)
|
||||||
|
|
||||||
plot.circle('Delta','CP',source=source,fill_color='red',size=15,
|
plot.circle('Delta','CP',source=source,fill_color='red',size=15,
|
||||||
legend='Power')
|
legend='Power Data')
|
||||||
plot.xaxis.axis_label = "Duration (seconds)"
|
plot.xaxis.axis_label = "Duration (seconds)"
|
||||||
plot.yaxis.axis_label = "Power (W)"
|
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.x_range = Range1d(1,2*max(thesecs))
|
||||||
plot.legend.orientation = "vertical"
|
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",
|
plot.line('duration','power',source=sourcecomplex,legend="CP Model",
|
||||||
color='green')
|
color='green')
|
||||||
|
|||||||
@@ -77,8 +77,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="grid_12 alpha">
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
<p> </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>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -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>
|
<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>
|
||||||
|
|
||||||
<p>The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.</p>
|
<p>The table gives the OTW efforts you marked as Ranking Piece.
|
||||||
|
The graph shows the best segments from those pieces, plotted as
|
||||||
<p>This page will evolve and try to give you guidance on where to improve.</p>
|
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>
|
||||||
<div id="form" class="grid_6 omega">
|
<div id="form" class="grid_6 omega">
|
||||||
<p>Use this form to select a different date range:</p>
|
<p>Use this form to select a different date range:</p>
|
||||||
@@ -98,6 +101,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="theplot" class="grid_12 alpha">
|
||||||
|
|
||||||
|
<h2>Critical Power Plot</h2>
|
||||||
|
|
||||||
|
{{ the_div|safe }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="grid_12 alpha">
|
<div class="grid_12 alpha">
|
||||||
|
|
||||||
<h2>Ranking Piece Results</h2>
|
<h2>Ranking Piece Results</h2>
|
||||||
@@ -109,6 +122,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th> Distance</th>
|
<th> Distance</th>
|
||||||
<th> Duration</th>
|
<th> Duration</th>
|
||||||
|
<th> Avg Power</th>
|
||||||
<th> Date</th>
|
<th> Date</th>
|
||||||
<th> Avg HR </th>
|
<th> Avg HR </th>
|
||||||
<th> Max HR </th>
|
<th> Max HR </th>
|
||||||
@@ -118,8 +132,9 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{% for workout in rankingworkouts %}
|
{% for workout in rankingworkouts %}
|
||||||
<tr>
|
<tr>
|
||||||
<td> {{ workout.distance }} </td>
|
<td> {{ workout.distance }} m</td>
|
||||||
<td> {{ workout.duration |durationprint:"%H:%M:%S.%f" }} </td>
|
<td> {{ workout.duration |durationprint:"%H:%M:%S.%f" }} </td>
|
||||||
|
<td> {{ avgpower|lookup:workout.id }} W</td>
|
||||||
<td> {{ workout.date }} </td>
|
<td> {{ workout.date }} </td>
|
||||||
<td> {{ workout.averagehr }} </td>
|
<td> {{ workout.averagehr }} </td>
|
||||||
<td> {{ workout.maxhr }} </td>
|
<td> {{ workout.maxhr }} </td>
|
||||||
@@ -137,39 +152,14 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div id="theplot" class="grid_12 alpha">
|
|
||||||
|
|
||||||
<h2>Critical Power Plot</h2>
|
|
||||||
|
|
||||||
{{ the_div|safe }}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="predictions" class="grid_12 alpha">
|
<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>
|
<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>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div id="paul" class="grid_6 alpha">
|
<div id="cpmodel" class="grid_6 alpha">
|
||||||
No Paul Data
|
|
||||||
</div>
|
|
||||||
<div id="cpmodel" class="grid_6 omega">
|
|
||||||
<h3>CP Model</h3>
|
|
||||||
<table width="70%" class="listtable">
|
<table width="70%" class="listtable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -193,7 +183,25 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</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>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -292,14 +292,11 @@ def iscoachmember(user):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def getrower(user):
|
def getrower(user):
|
||||||
if not user.is_anonymous():
|
|
||||||
try:
|
try:
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
except Rower.DoesNotExist:
|
except Rower.DoesNotExist:
|
||||||
r = Rower(user=user)
|
r = Rower(user=user)
|
||||||
r.save()
|
r.save()
|
||||||
else:
|
|
||||||
raise PermissionDenied("You need to log in to use this function")
|
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
@@ -2900,8 +2897,10 @@ def otwrankings_view(request,theuser=0,
|
|||||||
|
|
||||||
thesecs.append(timesecs)
|
thesecs.append(timesecs)
|
||||||
|
|
||||||
|
if len(thesecs) != 0:
|
||||||
maxt = pd.Series(thesecs).max()
|
maxt = pd.Series(thesecs).max()
|
||||||
|
else:
|
||||||
|
maxt = 1000.
|
||||||
|
|
||||||
maxlog10 = np.log10(maxt)
|
maxlog10 = np.log10(maxt)
|
||||||
logarr = np.arange(100)*maxlog10/100.
|
logarr = np.arange(100)*maxlog10/100.
|
||||||
@@ -2912,11 +2911,16 @@ def otwrankings_view(request,theuser=0,
|
|||||||
|
|
||||||
delta = []
|
delta = []
|
||||||
cpvalue = []
|
cpvalue = []
|
||||||
|
avgpower = {}
|
||||||
|
|
||||||
dfgrouped = df.groupby(['workoutid'])
|
dfgrouped = df.groupby(['workoutid'])
|
||||||
for id,group in dfgrouped:
|
for id,group in dfgrouped:
|
||||||
tt = group['time']
|
tt = group['time']
|
||||||
ww = group['power']
|
ww = group['power']
|
||||||
|
try:
|
||||||
|
avgpower[id] = int(ww.mean())
|
||||||
|
except ValueError:
|
||||||
|
avgpower[id] = '---'
|
||||||
if not np.isnan(ww.mean()):
|
if not np.isnan(ww.mean()):
|
||||||
length = len(ww)
|
length = len(ww)
|
||||||
dt = []
|
dt = []
|
||||||
@@ -2946,6 +2950,7 @@ def otwrankings_view(request,theuser=0,
|
|||||||
for d in logarr:
|
for d in logarr:
|
||||||
delta.append(d)
|
delta.append(d)
|
||||||
|
|
||||||
|
print avgpower
|
||||||
dt = pd.Series(delta,name='Delta')
|
dt = pd.Series(delta,name='Delta')
|
||||||
cpvalue = pd.Series(cpvalue,name='CP')
|
cpvalue = pd.Series(cpvalue,name='CP')
|
||||||
|
|
||||||
@@ -2955,13 +2960,15 @@ def otwrankings_view(request,theuser=0,
|
|||||||
'CP':cpvalue,
|
'CP':cpvalue,
|
||||||
})
|
})
|
||||||
|
|
||||||
powerdf.sort_values(['Delta','CP'],ascending=[1,0])
|
powerdf = powerdf[powerdf['CP']>0]
|
||||||
powerdf.drop_duplicates(subset='Delta',keep='first')
|
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
|
# create interactive plot
|
||||||
if len(powerdf) !=0 :
|
if len(powerdf) !=0 :
|
||||||
res = interactive_otwcpchart(powerdf)
|
res = interactive_otwcpchart(powerdf,promember=promember)
|
||||||
script = res[0]
|
script = res[0]
|
||||||
div = res[1]
|
div = res[1]
|
||||||
p1 = res[2]
|
p1 = res[2]
|
||||||
@@ -2979,15 +2986,11 @@ def otwrankings_view(request,theuser=0,
|
|||||||
|
|
||||||
if request.method == 'POST' and "piece" in request.POST:
|
if request.method == 'POST' and "piece" in request.POST:
|
||||||
form = PredictedPieceForm(request.POST)
|
form = PredictedPieceForm(request.POST)
|
||||||
if form.is_valid():
|
clean = form.is_valid()
|
||||||
value = form.cleaned_data['value']
|
value = form.cleaned_data['value']
|
||||||
hourvalue,value = divmod(value,60)
|
hourvalue,value = divmod(value,60)
|
||||||
if hourvalue >= 24:
|
if hourvalue >= 24:
|
||||||
hourvalue = 23
|
hourvalue = 23
|
||||||
pieceunit = form.cleaned_data['pieceunit']
|
|
||||||
if pieceunit == 'd':
|
|
||||||
rankingdistances.append(value)
|
|
||||||
else:
|
|
||||||
rankingdurations.append(datetime.time(minute=value,hour=hourvalue))
|
rankingdurations.append(datetime.time(minute=value,hour=hourvalue))
|
||||||
else:
|
else:
|
||||||
form = PredictedPieceForm()
|
form = PredictedPieceForm()
|
||||||
@@ -3012,12 +3015,14 @@ def otwrankings_view(request,theuser=0,
|
|||||||
if pwr <= 0:
|
if pwr <= 0:
|
||||||
pwr = 50.
|
pwr = 50.
|
||||||
|
|
||||||
|
if not np.isnan(pwr):
|
||||||
a = {
|
a = {
|
||||||
'duration':timedeltaconv(t),
|
'duration':timedeltaconv(t),
|
||||||
'power':int(pwr)}
|
'power':int(pwr)}
|
||||||
cpredictions.append(a)
|
cpredictions.append(a)
|
||||||
|
|
||||||
print cpredictions
|
|
||||||
|
del form.fields["pieceunit"]
|
||||||
|
|
||||||
messages.error(request,message)
|
messages.error(request,message)
|
||||||
return render(request, 'otwrankings.html',
|
return render(request, 'otwrankings.html',
|
||||||
@@ -3026,6 +3031,7 @@ def otwrankings_view(request,theuser=0,
|
|||||||
'the_div':div,
|
'the_div':div,
|
||||||
'predictions':predictions,
|
'predictions':predictions,
|
||||||
'cpredictions':cpredictions,
|
'cpredictions':cpredictions,
|
||||||
|
'avgpower':avgpower,
|
||||||
'form':form,
|
'form':form,
|
||||||
'dateform':dateform,
|
'dateform':dateform,
|
||||||
'deltaform':deltaform,
|
'deltaform':deltaform,
|
||||||
|
|||||||
Reference in New Issue
Block a user