hr pie v1
This commit is contained in:
@@ -284,7 +284,7 @@ def interactive_hr_piechart(df, rower, title, totalseconds=0):
|
|||||||
frac_an = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr
|
frac_an = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr
|
||||||
|
|
||||||
datadict = {
|
datadict = {
|
||||||
'<{ut2}'.format(ut2=hrzones[1]): frac_lut2,
|
'<{ut2}'.format(ut2=hrzones[1]): frac_lut2,
|
||||||
'{ut2}'.format(ut2=hrzones[1]): frac_ut2,
|
'{ut2}'.format(ut2=hrzones[1]): frac_ut2,
|
||||||
'{ut1}'.format(ut1=hrzones[2]): frac_ut1,
|
'{ut1}'.format(ut1=hrzones[2]): frac_ut1,
|
||||||
'{at}'.format(at=hrzones[3]): frac_at,
|
'{at}'.format(at=hrzones[3]): frac_at,
|
||||||
@@ -299,7 +299,7 @@ def interactive_hr_piechart(df, rower, title, totalseconds=0):
|
|||||||
data['angle'] = data['value']/data['value'].sum() * 2*pi
|
data['angle'] = data['value']/data['value'].sum() * 2*pi
|
||||||
data['color'] = colors
|
data['color'] = colors
|
||||||
data['zone'] = [
|
data['zone'] = [
|
||||||
'<{ut2}'.format(ut2=hrzones[1]),
|
'<{ut2}'.format(ut2=hrzones[1]),
|
||||||
'{ut2}'.format(ut2=hrzones[1]),
|
'{ut2}'.format(ut2=hrzones[1]),
|
||||||
'{ut1}'.format(ut1=hrzones[2]),
|
'{ut1}'.format(ut1=hrzones[2]),
|
||||||
'{at}'.format(at=hrzones[3]),
|
'{at}'.format(at=hrzones[3]),
|
||||||
@@ -309,24 +309,14 @@ def interactive_hr_piechart(df, rower, title, totalseconds=0):
|
|||||||
|
|
||||||
data['totaltime'] = pd.Series([pretty_timedelta(v) for v in data['value']])
|
data['totaltime'] = pd.Series([pretty_timedelta(v) for v in data['value']])
|
||||||
|
|
||||||
TOOLS = 'save,hover'
|
data_dict = data.to_dict("records")
|
||||||
|
chart_data = {
|
||||||
z = figure(title="HR "+title, x_range=(-0.5, 1), height=375,
|
'data': data_dict,
|
||||||
tools=TOOLS, toolbar_location=None, tooltips="@zone: @totaltime",
|
'title': "HR "+ title
|
||||||
)
|
}
|
||||||
|
|
||||||
z.wedge(x=0, y=1, radius=0.4,
|
|
||||||
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
|
|
||||||
line_color='white', fill_color='color', source=data, legend_group='zone')
|
|
||||||
|
|
||||||
z.axis.axis_label = None
|
|
||||||
z.axis.visible = False
|
|
||||||
z.grid.grid_line_color = None
|
|
||||||
z.outline_line_color = None
|
|
||||||
z.toolbar_location = 'right'
|
|
||||||
|
|
||||||
return components(z)
|
|
||||||
|
|
||||||
|
script, div = get_chart("/hrpie", chart_data, debug=True)
|
||||||
|
return script, div
|
||||||
|
|
||||||
def pretty_timedelta(secs):
|
def pretty_timedelta(secs):
|
||||||
hours, remainder = divmod(secs, 3600)
|
hours, remainder = divmod(secs, 3600)
|
||||||
|
|||||||
@@ -102,14 +102,11 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
<script src="https://d3js.org/d3.v6.js"></script>
|
||||||
<script async="true" type="text/javascript">
|
|
||||||
Bokeh.set_log_level("info");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{ interactiveplot |safe }}
|
|
||||||
|
|
||||||
{{ the_div|safe }}
|
{{ the_div|safe }}
|
||||||
|
{{ interactiveplot |safe }}
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_4">
|
<li class="grid_4">
|
||||||
|
|||||||
@@ -6,12 +6,9 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
|
|
||||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
<script src="https://d3js.org/d3.v6.js"></script>
|
||||||
<script async="true" type="text/javascript">
|
|
||||||
Bokeh.set_log_level("info");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{ interactiveplot |safe }}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -24,6 +21,7 @@
|
|||||||
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
{{ interactiveplot |safe }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<div id="id_js_res">
|
<div id="id_js_res">
|
||||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.js"></script>
|
<script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.js"></script>
|
||||||
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script async="true" type="text/javascript">
|
<script async="true" type="text/javascript">
|
||||||
@@ -52,35 +53,35 @@
|
|||||||
<input type="submit" value="Submit"/>
|
<input type="submit" value="Submit"/>
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<h2>All workouts</h2>
|
<h2>All workouts</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<table class="listtable shortpadded">
|
<table class="listtable shortpadded">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total Distance</td><td>{{ totalsdict|lookup:"distance"}} meters</td>
|
<td>Total Distance</td><td>{{ totalsdict|lookup:"distance"}} meters</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total Duration</td><td>{{ totalsdict|lookup:"duration"}} </td>
|
<td>Total Duration</td><td>{{ totalsdict|lookup:"duration"}} </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Number of workouts</td><td>{{ totalsdict|lookup:"nrworkouts"}}</td>
|
<td>Number of workouts</td><td>{{ totalsdict|lookup:"nrworkouts"}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Average heart rate</td><td><span id="total_hr"></span> bpm</td>
|
<td>Average heart rate</td><td><span id="total_hr"></span> bpm</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Maximum heart rate</td><td><span id="total_maxhr"></span> bpm</td>
|
<td>Maximum heart rate</td><td><span id="total_maxhr"></span> bpm</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Average power</td><td><span id="total_power"></span> W</td>
|
<td>Average power</td><td><span id="total_power"></span> W</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Maximum power</td><td><span id="total_maxpower"></span> W</td>
|
<td>Maximum power</td><td><span id="total_maxpower"></span> W</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
@@ -103,29 +104,29 @@
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
<table class="listtable shortpadded">
|
<table class="listtable shortpadded">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total Distance</td><td>{{ ddict|lookup:"distance"}} meters</td>
|
<td>Total Distance</td><td>{{ ddict|lookup:"distance"}} meters</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Total Duration</td><td>{{ ddict|lookup:"duration"}} </td>
|
<td>Total Duration</td><td>{{ ddict|lookup:"duration"}} </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Number of workouts</td><td>{{ ddict|lookup:"nrworkouts"}}</td>
|
<td>Number of workouts</td><td>{{ ddict|lookup:"nrworkouts"}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Average heart rate</td><td><span id="{{ ddict|lookup:'id'}}_hr"></span> bpm</td>
|
<td>Average heart rate</td><td><span id="{{ ddict|lookup:'id'}}_hr"></span> bpm</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Maximum heart rate</td><td><span id="{{ ddict|lookup:'id' }}_hrmax"></span> bpm</td>
|
<td>Maximum heart rate</td><td><span id="{{ ddict|lookup:'id' }}_hrmax"></span> bpm</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Average power</td><td><span id="{{ ddict|lookup:'id'}}_power"></span> W</td>
|
<td>Average power</td><td><span id="{{ ddict|lookup:'id'}}_power"></span> W</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Maximum power</td><td><span id="{{ ddict|lookup:'id'}}_powermax"></span> W</td>
|
<td>Maximum power</td><td><span id="{{ ddict|lookup:'id'}}_powermax"></span> W</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
@@ -142,40 +143,39 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(function($) {
|
$(function($) {
|
||||||
console.log('loading script for chart');
|
console.log('loading script for chart');
|
||||||
var ed = '{{ senddate|date:"Y-m-d" }}'
|
var ed = '{{ senddate|date:"Y-m-d" }}'
|
||||||
console.log('End',ed);
|
console.log('End',ed);
|
||||||
console.log(window.location.protocol + '//'+window.location.host + '/rowers/history/user/{{ rower.user.id }}/data/?startdate={{ sstartdate|date:"Y-m-d" }}&enddate={{ senddate|date:"Y-m-d" }}&workouttype={{ workouttype }}&yaxis={{ yaxis }}')
|
console.log(window.location.protocol + '//'+window.location.host + '/rowers/history/user/{{ rower.user.id }}/data/?startdate={{ sstartdate|date:"Y-m-d" }}&enddate={{ senddate|date:"Y-m-d" }}&workouttype={{ workouttype }}&yaxis={{ yaxis }}')
|
||||||
$.getJSON(window.location.protocol + '//'+window.location.host + '/rowers/history/user/{{ rower.user.id }}/data/?startdate={{ sstartdate|date:"Y-m-d" }}&enddate={{ senddate|date:"Y-m-d" }}&workouttype={{ workouttype }}&yaxis={{ yaxis }}', function(json) {
|
$.getJSON(window.location.protocol + '//'+window.location.host + '/rowers/history/user/{{ rower.user.id }}/data/?startdate={{ sstartdate|date:"Y-m-d" }}&enddate={{ senddate|date:"Y-m-d" }}&workouttype={{ workouttype }}&yaxis={{ yaxis }}', function(json) {
|
||||||
|
|
||||||
|
|
||||||
var script = json.script;
|
var script = json.script;
|
||||||
var div = json.div;
|
var div = json.div;
|
||||||
var totalsdict = json.totalsdict
|
var totalsdict = json.totalsdict
|
||||||
var listofdicts = json.listofdicts
|
var listofdicts = json.listofdicts
|
||||||
var activities_script = json.activities_script
|
var activities_script = json.activities_script
|
||||||
var activities_chart = json.activities_chart
|
var activities_chart = json.activities_chart
|
||||||
$("#id_sitready").remove();
|
$("#id_sitready").remove();
|
||||||
$("#id_chart").append(div);
|
$("#id_chart").append(div);
|
||||||
// $("#id_script").append("<s"+"cript>"+script+"</s"+"cript>");
|
$("#id_script").append(script);
|
||||||
$("#id_script").append(script);
|
$("#id_activities").append(activities_chart)
|
||||||
$("#id_activities").append(activities_chart)
|
$("#activities_script").append(activities_script)
|
||||||
$("#activities_script").append(activities_script)
|
$("#total_hr").append(totalsdict.hrmean);
|
||||||
$("#total_hr").append(totalsdict.hrmean);
|
$("#total_maxhr").append(totalsdict.hrmax);
|
||||||
$("#total_maxhr").append(totalsdict.hrmax);
|
$("#total_power").append(totalsdict.powermean);
|
||||||
$("#total_power").append(totalsdict.powermean);
|
$("#total_maxpower").append(totalsdict.powermax);
|
||||||
$("#total_maxpower").append(totalsdict.powermax);
|
listofdicts.forEach(function(item){
|
||||||
listofdicts.forEach(function(item){
|
var id = "#"+item.id+"_hr";
|
||||||
var id = "#"+item.id+"_hr";
|
$(id).append(item.hrmean);
|
||||||
$(id).append(item.hrmean);
|
id = "#"+item.id+"_hrmax";
|
||||||
id = "#"+item.id+"_hrmax";
|
$(id).append(item.hrmax);
|
||||||
$(id).append(item.hrmax);
|
id = "#"+item.id+"_power";
|
||||||
id = "#"+item.id+"_power";
|
$(id).append(item.powermean);
|
||||||
$(id).append(item.powermean);
|
id = "#"+item.id+"_powermax";
|
||||||
id = "#"+item.id+"_powermax";
|
$(id).append(item.powermax);
|
||||||
$(id).append(item.powermax);
|
})
|
||||||
})
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
|
|
||||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
<script src="https://d3js.org/d3.v6.js"></script>
|
||||||
<script async="true" type="text/javascript">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -8,26 +8,26 @@
|
|||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
{% include "monitorjobs.html" %}
|
{% include "monitorjobs.html" %}
|
||||||
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
|
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
|
||||||
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
|
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
|
||||||
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
||||||
<script>
|
<script>
|
||||||
$( function() {
|
$( function() {
|
||||||
console.log({{ activeminutesmin }}, {{ activeminutesmax}}, 'active range');
|
console.log({{ activeminutesmin }}, {{ activeminutesmax}}, 'active range');
|
||||||
$( "#slider-range" ).slider({
|
$( "#slider-range" ).slider({
|
||||||
range: true,
|
range: true,
|
||||||
min: 0,
|
min: 0,
|
||||||
max: {{ maxminutes }},
|
max: {{ maxminutes }},
|
||||||
values: [ {{ activeminutesmin }}, {{ activeminutesmax }} ],
|
values: [ {{ activeminutesmin }}, {{ activeminutesmax }} ],
|
||||||
slide: function( event, ui ) {
|
slide: function( event, ui ) {
|
||||||
$( "#amount" ).val(ui.values[ 0 ] + " min - " + ui.values[ 1 ] + " min " );
|
$( "#amount" ).val(ui.values[ 0 ] + " min - " + ui.values[ 1 ] + " min " );
|
||||||
$("#id_activeminutesmin").val(ui.values[0]);
|
$("#id_activeminutesmin").val(ui.values[0]);
|
||||||
$("#id_activeminutesmax").val(ui.values[1]);
|
$("#id_activeminutesmax").val(ui.values[1]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
$( "#amount" ).val($( "#slider-range" ).slider( "values", 0 ) +
|
$( "#amount" ).val($( "#slider-range" ).slider( "values", 0 ) +
|
||||||
" min - " + $( "#slider-range" ).slider( "values", 1 ) + " min ");
|
" min - " + $( "#slider-range" ).slider( "values", 1 ) + " min ");
|
||||||
} );
|
} );
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
@@ -42,78 +42,75 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<table width=100%>
|
<table width=100%>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th><td>{{ workout.name }}</td>
|
<th>Name</th><td>{{ workout.name }}</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Distance:</th><td>{{ workout.distance }}m</td>
|
<th>Distance:</th><td>{{ workout.distance }}m</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
|
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Public link to this workout</th>
|
<th>Public link to this workout</th>
|
||||||
<td>
|
<td>
|
||||||
<a href="/rowers/workout/{{ workout.id|encode }}/">https://rowsandall.com/rowers/workout/{{ workout.id|encode }}</a>
|
<a href="/rowers/workout/{{ workout.id|encode }}/">https://rowsandall.com/rowers/workout/{{ workout.id|encode }}</a>
|
||||||
<td>
|
<td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h1>Edit Workout Interval Data</h1>
|
<h1>Edit Workout Interval Data</h1>
|
||||||
<p>
|
<p>
|
||||||
Use "Interval Shorthand", "Feeling lucky?", or "Intervals by power/pace" methods below to edit work and rest
|
Use "Interval Shorthand", "Feeling lucky?", or "Intervals by power/pace" methods below to edit work and rest
|
||||||
intervals. To save your work, press the Save button above the updated summary.
|
intervals. To save your work, press the Save button above the updated summary.
|
||||||
</p>
|
</p>
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<h1>Updated Summary</h1>
|
<h1>Updated Summary</h1>
|
||||||
<form enctype="multipart/form-data" action="/rowers/workout/{{ workout.id|encode }}/editintervals/" method="post">
|
<form enctype="multipart/form-data" action="/rowers/workout/{{ workout.id|encode }}/editintervals/" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="{{ savebutton }}" value="{{ intervalstring }}">
|
<input type="hidden" name="{{ savebutton }}" value="{{ intervalstring }}">
|
||||||
<input type="hidden" name="nrintervals" value={{ nrintervals }}>
|
<input type="hidden" name="nrintervals" value={{ nrintervals }}>
|
||||||
{% for key,value in formvalues.items %}
|
{% for key,value in formvalues.items %}
|
||||||
<input type="hidden" name="{{ key }}" value="{{ value|safe }}">
|
<input type="hidden" name="{{ key }}" value="{{ value|safe }}">
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<p>
|
<p>
|
||||||
<input type="submit" value="Save">
|
<input type="submit" value="Save">
|
||||||
</p>
|
</p>
|
||||||
<span>
|
<span>
|
||||||
<a href="">Reset to last saved</a>
|
<a href="">Reset to last saved</a>
|
||||||
|
|
||||||
<a href="/rowers/workout/{{ workout.id|encode }}/restore/">Restore Original data</a>
|
<a href="/rowers/workout/{{ workout.id|encode }}/restore/">Restore Original data</a>
|
||||||
</span>
|
</span>
|
||||||
</form>
|
</form>
|
||||||
<p>
|
<p>
|
||||||
<pre>
|
<pre>
|
||||||
{{ intervalstats }}
|
{{ intervalstats }}
|
||||||
</pre>
|
</pre>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
<script src="https://d3js.org/d3.v6.js"></script>
|
||||||
<script async="true" type="text/javascript">
|
|
||||||
Bokeh.set_log_level("info");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{ interactiveplot |safe }}
|
{{ the_div |safe }}
|
||||||
|
{{ interactiveplot |safe }}
|
||||||
|
|
||||||
{{ the_div |safe }}
|
</li>
|
||||||
</li>
|
<li class="grid_2">
|
||||||
<li class="grid_2">
|
<h1>Feeling lucky?</h1>
|
||||||
<h1>Feeling lucky?</h1>
|
<p>This new, experimental feature tries to find intervals by looking for patterns in the data. It does not
|
||||||
<p>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
|
||||||
autodetect rest and work intervals yet. The resulting "interval string" is copied to the Interval Shorthand
|
section below, where you can edit it.
|
||||||
section below, where you can edit it.
|
<form enctype="multipart/form-data" method="post">
|
||||||
<form enctype="multipart/form-data" method="post">
|
<input type="hidden" name="ruptures" value="ruptures">
|
||||||
<input type="hidden" name="ruptures" value="ruptures">
|
<table width=100%>
|
||||||
<table width=100%>
|
{{ ruptureform.as_table }}
|
||||||
{{ ruptureform.as_table }}
|
</table>
|
||||||
</table>
|
{% csrf_token %}
|
||||||
{% csrf_token %}
|
<input class="button" type="submit" value="I'm feeling lucky">
|
||||||
<input class="button" type="submit" value="I'm feeling lucky">
|
</form>
|
||||||
</form>
|
</p>
|
||||||
</p>
|
</li>
|
||||||
</li>
|
<li class="grid_2">
|
||||||
<li class="grid_2">
|
|
||||||
<h1>Interval Shorthand</h1>
|
<h1>Interval Shorthand</h1>
|
||||||
<p>
|
<p>
|
||||||
See the how-to <a href="#howto">at the bottom of this page</a> for details on how to use this form.
|
See the how-to <a href="#howto">at the bottom of this page</a> for details on how to use this form.
|
||||||
@@ -125,22 +122,22 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input class="button" type="submit" value="Update">
|
<input class="button" type="submit" value="Update">
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<h1>Intervals by Power/Pace</h1>
|
<h1>Intervals by Power/Pace</h1>
|
||||||
|
|
||||||
<p>With this form, you can specify a power or pace level. Everything faster/harder than the
|
<p>With this form, you can specify a power or pace level. Everything faster/harder than the
|
||||||
specified pace/power will become a work interval. Everything slower will become a rest
|
specified pace/power will become a work interval. Everything slower will become a rest
|
||||||
interval. Use the slider to limit the active range. Everything outside the active range will
|
interval. Use the slider to limit the active range. Everything outside the active range will
|
||||||
become rest (warming up and cooling down).
|
become rest (warming up and cooling down).
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form ecntype="multipart/form-data" method="post">
|
<form ecntype="multipart/form-data" method="post">
|
||||||
<div id="slider-range"></div>
|
<div id="slider-range"></div>
|
||||||
<p>
|
<p>
|
||||||
<label for="amount">Active Range:</label>
|
<label for="amount">Active Range:</label>
|
||||||
<input type="text" id="amount" readonly style="border:0; color:#1c75bc; font-weight:bold;">
|
<input type="text" id="amount" readonly style="border:0; color:#1c75bc; font-weight:bold;">
|
||||||
</p>
|
</p>
|
||||||
<table>
|
<table>
|
||||||
{{ powerupdateform.as_table }}
|
{{ powerupdateform.as_table }}
|
||||||
</table>
|
</table>
|
||||||
@@ -182,32 +179,32 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</li>
|
</li>
|
||||||
{% if courses %}
|
{% if courses %}
|
||||||
<li>
|
<li>
|
||||||
<h1>Interval by Course</h1>
|
<h1>Interval by Course</h1>
|
||||||
<p>
|
<p>
|
||||||
This functionality allows you to record a time on a set course that you've rowed during the workout.
|
This functionality allows you to record a time on a set course that you've rowed during the workout.
|
||||||
The summary will be updated to show time on course, and you can compare this with other
|
The summary will be updated to show time on course, and you can compare this with other
|
||||||
attempts.
|
attempts.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{% if rower.share_course_results %}
|
{% if rower.share_course_results %}
|
||||||
You are currently sharing your course results with all Rowsandall users.
|
You are currently sharing your course results with all Rowsandall users.
|
||||||
Click <a href="/rowers/me/edit/?courseshare=false">here</a> to hide your course results.
|
Click <a href="/rowers/me/edit/?courseshare=false">here</a> to hide your course results.
|
||||||
{% else %}
|
{% else %}
|
||||||
You are currently hiding your course results (except for your participation in online challenges).
|
You are currently hiding your course results (except for your participation in online challenges).
|
||||||
Click <a href="/rowers/me/edit/?courseshare=true">here</a> to hide your course results.
|
Click <a href="/rowers/me/edit/?courseshare=true">here</a> to hide your course results.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<form ecntype="multipart/form-data" method="post">
|
<form ecntype="multipart/form-data" method="post">
|
||||||
<table>
|
<table>
|
||||||
{{ courseselectform.as_table }}
|
{{ courseselectform.as_table }}
|
||||||
</table>
|
</table>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input class="button" type="submit" value="Select Course">
|
<input class="button" type="submit" value="Select Course">
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -98,14 +98,11 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
<script src="https://d3js.org/d3.v6.js"></script>
|
||||||
<script async="true" type="text/javascript">
|
|
||||||
Bokeh.set_log_level("info");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{{ interactiveplot |safe }}
|
|
||||||
|
|
||||||
{{ the_div|safe }}
|
{{ the_div|safe }}
|
||||||
|
{{ interactiveplot |safe }}
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_4">
|
<li class="grid_4">
|
||||||
|
|||||||
@@ -443,9 +443,6 @@ urlpatterns = [
|
|||||||
views.trainingzones_view_data, name="trainingzones_view_data"),
|
views.trainingzones_view_data, name="trainingzones_view_data"),
|
||||||
re_path(r'^trainingzones/data/$', views.trainingzones_view_data,
|
re_path(r'^trainingzones/data/$', views.trainingzones_view_data,
|
||||||
name="trainingzones_view_data"),
|
name="trainingzones_view_data"),
|
||||||
re_path(r'^ote-bests2/user/(?P<userid>\d+)/$',
|
|
||||||
views.rankings_view2, name='rankings_view2'),
|
|
||||||
re_path(r'^ote-bests2/$', views.rankings_view2, name='rankings_view2'),
|
|
||||||
re_path(r'^analysisdata/user/(?P<userid>\d+)/$', views.analysis_view_data,
|
re_path(r'^analysisdata/user/(?P<userid>\d+)/$', views.analysis_view_data,
|
||||||
name='analysis_view_data'),
|
name='analysis_view_data'),
|
||||||
re_path(r'^analysisdata/$', views.analysis_view_data,
|
re_path(r'^analysisdata/$', views.analysis_view_data,
|
||||||
@@ -470,8 +467,6 @@ urlpatterns = [
|
|||||||
views.workout_upload_view, name='workout_upload_view'),
|
views.workout_upload_view, name='workout_upload_view'),
|
||||||
re_path(r'^workout/upload/$', views.workout_upload_view,
|
re_path(r'^workout/upload/$', views.workout_upload_view,
|
||||||
name='workout_upload_view'),
|
name='workout_upload_view'),
|
||||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/histo/$', views.workout_histo_view,
|
|
||||||
name='workout_histo_view'),
|
|
||||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/forcecurve/$', views.workout_forcecurve_view,
|
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/forcecurve/$', views.workout_forcecurve_view,
|
||||||
name='workout_forcecurve_view'),
|
name='workout_forcecurve_view'),
|
||||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/forcecurve/(?P<analysis>\d+)/$', views.workout_forcecurve_view,
|
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/forcecurve/(?P<analysis>\d+)/$', views.workout_forcecurve_view,
|
||||||
|
|||||||
@@ -1382,398 +1382,6 @@ def ajax_agegrouprecords(request,
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Show ranking distances including predicted paces
|
|
||||||
@login_required()
|
|
||||||
@permission_required('rower.is_coach', fn=get_user_by_userid, raise_exception=True)
|
|
||||||
def rankings_view2(request, userid=0,
|
|
||||||
startdate=timezone.now()-datetime.timedelta(days=365),
|
|
||||||
enddate=timezone.now(),
|
|
||||||
deltadays=-1,
|
|
||||||
startdatestring="",
|
|
||||||
enddatestring=""):
|
|
||||||
|
|
||||||
if deltadays > 0: # pragma: no cover
|
|
||||||
startdate = enddate-datetime.timedelta(days=int(deltadays))
|
|
||||||
|
|
||||||
if startdatestring != "": # pragma: no cover
|
|
||||||
startdate = iso8601.parse_date(startdatestring)
|
|
||||||
|
|
||||||
if enddatestring != "": # pragma: no cover
|
|
||||||
enddate = iso8601.parse_date(enddatestring)
|
|
||||||
|
|
||||||
if enddate < startdate: # pragma: no cover
|
|
||||||
s = enddate
|
|
||||||
enddate = startdate
|
|
||||||
startdate = s
|
|
||||||
|
|
||||||
if userid == 0:
|
|
||||||
userid = request.user.id
|
|
||||||
else:
|
|
||||||
lastupdated = "1900-01-01"
|
|
||||||
|
|
||||||
promember = 0
|
|
||||||
r = getrequestrower(request, userid=userid)
|
|
||||||
theuser = r.user
|
|
||||||
|
|
||||||
wcdurations = []
|
|
||||||
wcpower = []
|
|
||||||
|
|
||||||
lastupdated = "1900-01-01"
|
|
||||||
userid = 0
|
|
||||||
if 'options' in request.session:
|
|
||||||
options = request.session['options']
|
|
||||||
try:
|
|
||||||
wcdurations = options['wcdurations']
|
|
||||||
wcpower = options['wcpower']
|
|
||||||
lastupdated = options['lastupdated']
|
|
||||||
except KeyError: # pragma: no cover
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
userid = options['userid']
|
|
||||||
except KeyError: # pragma: no cover
|
|
||||||
userid = 0
|
|
||||||
else:
|
|
||||||
options = {}
|
|
||||||
|
|
||||||
lastupdatedtime = arrow.get(lastupdated).timestamp()
|
|
||||||
current_time = arrow.utcnow().timestamp()
|
|
||||||
|
|
||||||
deltatime_seconds = current_time - lastupdatedtime
|
|
||||||
recalc = False
|
|
||||||
if str(userid) != str(theuser) or deltatime_seconds > 3600:
|
|
||||||
recalc = True
|
|
||||||
options['lastupdated'] = arrow.utcnow().isoformat()
|
|
||||||
else: # pragma: no cover
|
|
||||||
recalc = False
|
|
||||||
|
|
||||||
options['userid'] = theuser.id
|
|
||||||
|
|
||||||
if r.birthdate:
|
|
||||||
age = calculate_age(r.birthdate)
|
|
||||||
else:
|
|
||||||
age = 0
|
|
||||||
|
|
||||||
agerecords = CalcAgePerformance.objects.filter(
|
|
||||||
age=age,
|
|
||||||
sex=r.sex,
|
|
||||||
weightcategory=r.weightcategory)
|
|
||||||
|
|
||||||
if len(agerecords) == 0:
|
|
||||||
recalc = True
|
|
||||||
wcpower = []
|
|
||||||
wcdurations = []
|
|
||||||
else:
|
|
||||||
wcdurations = []
|
|
||||||
wcpower = []
|
|
||||||
for record in agerecords:
|
|
||||||
wcdurations.append(record.duration)
|
|
||||||
wcpower.append(record.power)
|
|
||||||
|
|
||||||
options['wcpower'] = wcpower
|
|
||||||
options['wcdurations'] = wcdurations
|
|
||||||
if theuser:
|
|
||||||
options['userid'] = theuser.id
|
|
||||||
|
|
||||||
request.session['options'] = options
|
|
||||||
|
|
||||||
result = request.user.is_authenticated and ispromember(request.user)
|
|
||||||
if result:
|
|
||||||
promember = 1
|
|
||||||
|
|
||||||
# get all indoor rows in date range
|
|
||||||
|
|
||||||
# process form
|
|
||||||
if request.method == 'POST' and "daterange" in request.POST:
|
|
||||||
dateform = DateRangeForm(request.POST)
|
|
||||||
deltaform = DeltaDaysForm(request.POST)
|
|
||||||
if dateform.is_valid():
|
|
||||||
startdate = dateform.cleaned_data['startdate']
|
|
||||||
enddate = dateform.cleaned_data['enddate']
|
|
||||||
if startdate > enddate: # pragma: no cover
|
|
||||||
s = enddate
|
|
||||||
enddate = startdate
|
|
||||||
startdate = s
|
|
||||||
elif request.method == 'POST' and "datedelta" in request.POST: # pragma: no cover
|
|
||||||
deltaform = DeltaDaysForm(request.POST)
|
|
||||||
if deltaform.is_valid():
|
|
||||||
deltadays = deltaform.cleaned_data['deltadays']
|
|
||||||
if deltadays:
|
|
||||||
enddate = timezone.now()
|
|
||||||
startdate = enddate-datetime.timedelta(days=deltadays)
|
|
||||||
if startdate > enddate:
|
|
||||||
s = enddate
|
|
||||||
enddate = startdate
|
|
||||||
startdate = s
|
|
||||||
dateform = DateRangeForm(initial={
|
|
||||||
'startdate': startdate,
|
|
||||||
'enddate': enddate,
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
dateform = DateRangeForm()
|
|
||||||
deltaform = DeltaDaysForm()
|
|
||||||
|
|
||||||
else:
|
|
||||||
dateform = DateRangeForm(initial={
|
|
||||||
'startdate': startdate,
|
|
||||||
'enddate': enddate,
|
|
||||||
})
|
|
||||||
deltaform = DeltaDaysForm()
|
|
||||||
|
|
||||||
# get all 2k (if any) - this rower, in date range
|
|
||||||
try:
|
|
||||||
r = getrower(theuser)
|
|
||||||
except Rower.DoesNotExist: # pragma: no cover
|
|
||||||
r = 0
|
|
||||||
|
|
||||||
uu = theuser
|
|
||||||
|
|
||||||
# test to fix bug
|
|
||||||
startdate = datetime.datetime.combine(startdate, datetime.time())
|
|
||||||
enddate = datetime.datetime.combine(enddate, datetime.time(23, 59, 59))
|
|
||||||
startdate = arrow.get(startdate).datetime
|
|
||||||
enddate = arrow.get(enddate).datetime
|
|
||||||
|
|
||||||
thedistances = []
|
|
||||||
theworkouts = []
|
|
||||||
thesecs = []
|
|
||||||
|
|
||||||
rankingdistances.sort()
|
|
||||||
rankingdurations.sort()
|
|
||||||
|
|
||||||
for rankingdistance in rankingdistances:
|
|
||||||
|
|
||||||
workouts = Workout.objects.filter(
|
|
||||||
user=r, distance=rankingdistance,
|
|
||||||
workouttype__in=['rower', 'dynamic', 'slides'],
|
|
||||||
rankingpiece=True,
|
|
||||||
startdatetime__gte=startdate,
|
|
||||||
startdatetime__lte=enddate).order_by('duration')
|
|
||||||
if workouts:
|
|
||||||
thedistances.append(rankingdistance)
|
|
||||||
theworkouts.append(workouts[0])
|
|
||||||
|
|
||||||
timesecs = 3600*workouts[0].duration.hour
|
|
||||||
timesecs += 60*workouts[0].duration.minute
|
|
||||||
timesecs += workouts[0].duration.second
|
|
||||||
timesecs += 1.e-6*workouts[0].duration.microsecond
|
|
||||||
|
|
||||||
thesecs.append(timesecs)
|
|
||||||
|
|
||||||
for rankingduration in rankingdurations:
|
|
||||||
|
|
||||||
workouts = Workout.objects.filter(
|
|
||||||
user=r, duration=rankingduration,
|
|
||||||
workouttype='rower',
|
|
||||||
rankingpiece=True,
|
|
||||||
startdatetime__gte=startdate,
|
|
||||||
startdatetime__lte=enddate).order_by('-distance')
|
|
||||||
if workouts:
|
|
||||||
thedistances.append(workouts[0].distance)
|
|
||||||
theworkouts.append(workouts[0])
|
|
||||||
|
|
||||||
timesecs = 3600*workouts[0].duration.hour
|
|
||||||
timesecs += 60*workouts[0].duration.minute
|
|
||||||
timesecs += workouts[0].duration.second
|
|
||||||
timesecs += 1.e-5*workouts[0].duration.microsecond
|
|
||||||
|
|
||||||
thesecs.append(timesecs)
|
|
||||||
|
|
||||||
thedistances = np.array(thedistances)
|
|
||||||
thesecs = np.array(thesecs)
|
|
||||||
|
|
||||||
thevelos = thedistances/thesecs
|
|
||||||
theavpower = 2.8*(thevelos**3)
|
|
||||||
|
|
||||||
# create interactive plot
|
|
||||||
if len(thedistances) != 0:
|
|
||||||
res = interactive_cpchart(
|
|
||||||
r, thedistances, thesecs, theavpower,
|
|
||||||
theworkouts, promember=promember,
|
|
||||||
wcdurations=wcdurations, wcpower=wcpower
|
|
||||||
)
|
|
||||||
script = res[0]
|
|
||||||
div = res[1]
|
|
||||||
paulslope = res[2]
|
|
||||||
paulintercept = res[3]
|
|
||||||
p1 = res[4]
|
|
||||||
message = res[5]
|
|
||||||
else:
|
|
||||||
script = ''
|
|
||||||
div = '<p>No ranking pieces found.</p>'
|
|
||||||
paulslope = 1
|
|
||||||
paulintercept = 1
|
|
||||||
p1 = [1, 1, 1, 1]
|
|
||||||
message = ""
|
|
||||||
|
|
||||||
if request.method == 'POST' and "piece" in request.POST: # pragma: no cover
|
|
||||||
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=int(value), hour=int(hourvalue)))
|
|
||||||
else:
|
|
||||||
form = PredictedPieceForm()
|
|
||||||
|
|
||||||
rankingdistances.sort()
|
|
||||||
rankingdurations.sort()
|
|
||||||
|
|
||||||
predictions = []
|
|
||||||
cpredictions = []
|
|
||||||
|
|
||||||
for rankingdistance in rankingdistances:
|
|
||||||
# Paul's model
|
|
||||||
p = paulslope*np.log10(rankingdistance)+paulintercept
|
|
||||||
velo = 500./p
|
|
||||||
t = rankingdistance/velo
|
|
||||||
pwr = 2.8*(velo**3)
|
|
||||||
try:
|
|
||||||
pwr = int(pwr)
|
|
||||||
except (ValueError, AttributeError): # pragma: no cover
|
|
||||||
pwr = 0
|
|
||||||
|
|
||||||
a = {'distance': rankingdistance,
|
|
||||||
'duration': timedeltaconv(t),
|
|
||||||
'pace': timedeltaconv(p),
|
|
||||||
'power': int(pwr)}
|
|
||||||
predictions.append(a)
|
|
||||||
|
|
||||||
# CP model -
|
|
||||||
pwr2 = p1[0]/(1+t/p1[2])
|
|
||||||
pwr2 += p1[1]/(1+t/p1[3])
|
|
||||||
|
|
||||||
if pwr2 <= 0: # pragma: no cover
|
|
||||||
pwr2 = 50.
|
|
||||||
|
|
||||||
velo2 = (pwr2/2.8)**(1./3.)
|
|
||||||
|
|
||||||
if np.isnan(velo2) or velo2 <= 0: # pragma: no cover
|
|
||||||
velo2 = 1.0
|
|
||||||
|
|
||||||
t2 = rankingdistance/velo2
|
|
||||||
|
|
||||||
pwr3 = p1[0]/(1+t2/p1[2])
|
|
||||||
pwr3 += p1[1]/(1+t2/p1[3])
|
|
||||||
|
|
||||||
if pwr3 <= 0: # pragma: no cover
|
|
||||||
pwr3 = 50.
|
|
||||||
|
|
||||||
velo3 = (pwr3/2.8)**(1./3.)
|
|
||||||
if np.isnan(velo3) or velo3 <= 0: # pragma: no cover
|
|
||||||
velo3 = 1.0
|
|
||||||
|
|
||||||
t3 = rankingdistance/velo3
|
|
||||||
p3 = 500./velo3
|
|
||||||
|
|
||||||
a = {'distance': rankingdistance,
|
|
||||||
'duration': timedeltaconv(t3),
|
|
||||||
'pace': timedeltaconv(p3),
|
|
||||||
'power': int(pwr3)}
|
|
||||||
cpredictions.append(a)
|
|
||||||
|
|
||||||
for rankingduration in rankingdurations:
|
|
||||||
t = 3600.*rankingduration.hour
|
|
||||||
t += 60.*rankingduration.minute
|
|
||||||
t += rankingduration.second
|
|
||||||
t += rankingduration.microsecond/1.e6
|
|
||||||
|
|
||||||
# Paul's model
|
|
||||||
ratio = paulintercept/paulslope
|
|
||||||
|
|
||||||
u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/paulslope
|
|
||||||
|
|
||||||
d = 500*t*np.log(10.)
|
|
||||||
d = d/(paulslope*lambertw(u))
|
|
||||||
d = d.real
|
|
||||||
|
|
||||||
velo = d/t
|
|
||||||
p = 500./velo
|
|
||||||
pwr = 2.8*(velo**3)
|
|
||||||
try:
|
|
||||||
a = {'distance': int(d),
|
|
||||||
'duration': timedeltaconv(t),
|
|
||||||
'pace': timedeltaconv(p),
|
|
||||||
'power': int(pwr)}
|
|
||||||
predictions.append(a)
|
|
||||||
except: # pragma: no cover
|
|
||||||
pass
|
|
||||||
|
|
||||||
# CP model
|
|
||||||
pwr = p1[0] / (1 + t / p1[2])
|
|
||||||
pwr += p1[1] / (1 + t / p1[3])
|
|
||||||
|
|
||||||
if pwr <= 0: # pragma: no cover
|
|
||||||
pwr = 50.
|
|
||||||
|
|
||||||
velo = (pwr / 2.8)**(1. / 3.)
|
|
||||||
|
|
||||||
if np.isnan(velo) or velo <= 0: # pragma: no cover
|
|
||||||
velo = 1.0
|
|
||||||
|
|
||||||
d = t * velo
|
|
||||||
p = 500. / velo
|
|
||||||
a = {'distance': int(d),
|
|
||||||
'duration': timedeltaconv(t),
|
|
||||||
'pace': timedeltaconv(p),
|
|
||||||
'power': int(pwr)}
|
|
||||||
cpredictions.append(a)
|
|
||||||
|
|
||||||
if recalc:
|
|
||||||
wcdurations = []
|
|
||||||
wcpower = []
|
|
||||||
durations = [1, 4, 30, 60]
|
|
||||||
distances = [100, 500, 1000, 2000, 5000, 6000, 10000, 21097, 42195]
|
|
||||||
|
|
||||||
df = pd.DataFrame(
|
|
||||||
list(
|
|
||||||
C2WorldClassAgePerformance.objects.filter(
|
|
||||||
sex=r.sex,
|
|
||||||
weightcategory=r.weightcategory
|
|
||||||
).values()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
jsondf = df.to_json()
|
|
||||||
|
|
||||||
job = myqueue(queue,
|
|
||||||
handle_getagegrouprecords,
|
|
||||||
jsondf, distances, durations, age, r.sex, r.weightcategory)
|
|
||||||
try:
|
|
||||||
request.session['async_tasks'] += [(job.id, 'agegrouprecords')]
|
|
||||||
except KeyError:
|
|
||||||
request.session['async_tasks'] = [(job.id, 'agegrouprecords')]
|
|
||||||
|
|
||||||
messages.error(request, message)
|
|
||||||
return render(request, 'rankings.html',
|
|
||||||
{'rankingworkouts': theworkouts,
|
|
||||||
'interactiveplot': script,
|
|
||||||
'the_div': div,
|
|
||||||
'predictions': predictions,
|
|
||||||
'cpredictions': cpredictions,
|
|
||||||
'nrdata': len(thedistances),
|
|
||||||
'form': form,
|
|
||||||
'dateform': dateform,
|
|
||||||
'deltaform': deltaform,
|
|
||||||
'id': theuser,
|
|
||||||
'theuser': uu,
|
|
||||||
'rower': r,
|
|
||||||
'active': 'nav-analysis',
|
|
||||||
'age': age,
|
|
||||||
'sex': r.sex,
|
|
||||||
'recalc': recalc,
|
|
||||||
'weightcategory': r.weightcategory,
|
|
||||||
'startdate': startdate,
|
|
||||||
'enddate': enddate,
|
|
||||||
'teams': get_my_teams(request.user),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@login_required()
|
@login_required()
|
||||||
def otecp_toadmin_view(request, theuser=0,
|
def otecp_toadmin_view(request, theuser=0,
|
||||||
startdate=timezone.now() - datetime.timedelta(days=365),
|
startdate=timezone.now() - datetime.timedelta(days=365),
|
||||||
|
|||||||
@@ -630,50 +630,6 @@ def otw_use_gps(request, id=0):
|
|||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|
||||||
# Show Stroke power histogram for a workout
|
|
||||||
@login_required()
|
|
||||||
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
|
|
||||||
def workout_histo_view(request, id=0):
|
|
||||||
w = get_workoutuser(id, request)
|
|
||||||
r = getrequestrower(request)
|
|
||||||
|
|
||||||
mayedit = 0
|
|
||||||
if w.user == r:
|
|
||||||
mayedit = 1
|
|
||||||
|
|
||||||
res = interactive_histoall([w], 'power', False)
|
|
||||||
script = res[0]
|
|
||||||
div = res[1]
|
|
||||||
|
|
||||||
breadcrumbs = [
|
|
||||||
{
|
|
||||||
'url': '/rowers/list-workouts/',
|
|
||||||
'name': 'Workouts'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'url': get_workout_default_page(request, id),
|
|
||||||
'name': w.name
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'url': reverse('workout_histo_view', kwargs={'id': id}),
|
|
||||||
'name': 'Histogram'
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
return render(request,
|
|
||||||
'histo_single.html',
|
|
||||||
{'interactiveplot': script,
|
|
||||||
'breadcrumbs': breadcrumbs,
|
|
||||||
'active': 'nav-workouts',
|
|
||||||
'workout': w,
|
|
||||||
'rower': r,
|
|
||||||
'the_div': div,
|
|
||||||
'id': id,
|
|
||||||
'mayedit': mayedit,
|
|
||||||
'teams': get_my_teams(request.user),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
# add a workout manually
|
# add a workout manually
|
||||||
@login_required()
|
@login_required()
|
||||||
|
|||||||
Reference in New Issue
Block a user