First version of gold medal chart
This commit is contained in:
@@ -123,6 +123,29 @@ def newtestpowerid(x):
|
|||||||
|
|
||||||
return x['id']
|
return x['id']
|
||||||
|
|
||||||
|
def newtestpowerdate(x):
|
||||||
|
try:
|
||||||
|
if np.isnan(x['testpower']):
|
||||||
|
return np.nan
|
||||||
|
except (AttributeError,TypeError):
|
||||||
|
return np.nan
|
||||||
|
|
||||||
|
return x['date']
|
||||||
|
|
||||||
|
def all_goldmedalstandards(workouts,startdate,enddate):
|
||||||
|
dates = []
|
||||||
|
testpowers = []
|
||||||
|
testduration = []
|
||||||
|
|
||||||
|
for w in workouts:
|
||||||
|
goldmedalstandard, goldmedalseconds = dataprep.workout_goldmedalstandard(w)
|
||||||
|
if goldmedalseconds > 60:
|
||||||
|
dates.append(arrow.get(w.date).datetime)
|
||||||
|
testpowers.append(goldmedalstandard)
|
||||||
|
testduration.append(goldmedalseconds)
|
||||||
|
|
||||||
|
return dates,testpowers,testduration
|
||||||
|
|
||||||
def build_goldmedalstandards(workouts,kfitness):
|
def build_goldmedalstandards(workouts,kfitness):
|
||||||
dates = []
|
dates = []
|
||||||
testpower = []
|
testpower = []
|
||||||
@@ -1778,6 +1801,162 @@ def getfatigues(
|
|||||||
|
|
||||||
return fatigues,fitnesses,dates,testpower,testduration,impulses
|
return fatigues,fitnesses,dates,testpower,testduration,impulses
|
||||||
|
|
||||||
|
def goldmedalscorechart(user,startdate=None,enddate=None):
|
||||||
|
# to avoid data mess later on
|
||||||
|
startdate = arrow.get(startdate).datetime.replace(hour=0,minute=0,second=0,microsecond=0)
|
||||||
|
enddate = enddate+datetime.timedelta(days=1)
|
||||||
|
enddate = arrow.get(enddate).datetime.replace(hour=0,minute=0,second=0,microsecond=0)
|
||||||
|
|
||||||
|
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
|
||||||
|
workouts = Workout.objects.filter(user=user.rower,date__gte=startdate,
|
||||||
|
date__lte=enddate,
|
||||||
|
workouttype__in=mytypes.rowtypes,
|
||||||
|
duplicate=False)
|
||||||
|
|
||||||
|
# marker workouts
|
||||||
|
dates,testpower,testduration,fatigues,fitnesses,impulses, outids = build_goldmedalstandards(
|
||||||
|
workouts,42
|
||||||
|
)
|
||||||
|
|
||||||
|
df = pd.DataFrame({
|
||||||
|
'date':dates,
|
||||||
|
'testpower':testpower,
|
||||||
|
'testduration':testduration,
|
||||||
|
})
|
||||||
|
df.sort_values(['date'],inplace=True)
|
||||||
|
|
||||||
|
df['testdup'] = df['testpower'].shift(1)
|
||||||
|
df['testpower'] = df.apply(lambda x: newtestpower(x),axis=1)
|
||||||
|
#df['date'] = df.apply(lambda x: newtestpowerdate(x), axis=1)
|
||||||
|
|
||||||
|
mask = df['testpower'].isnull()
|
||||||
|
dates = df.mask(mask)['date'].dropna().values
|
||||||
|
testpower = df.mask(mask)['testpower'].dropna().values
|
||||||
|
|
||||||
|
# all workouts
|
||||||
|
alldates,alltestpower,allduration = all_goldmedalstandards(workouts,startdate,enddate)
|
||||||
|
|
||||||
|
nrdays = (enddate-startdate).days
|
||||||
|
|
||||||
|
td = []
|
||||||
|
markerscore = []
|
||||||
|
score = []
|
||||||
|
markerduration = []
|
||||||
|
duration = []
|
||||||
|
|
||||||
|
previous = 0
|
||||||
|
|
||||||
|
for i in range(len(dates)):
|
||||||
|
dd = str(dates[i])
|
||||||
|
td.append(arrow.get(dd).datetime)
|
||||||
|
markerscore.append(testpower[i])
|
||||||
|
markerduration.append(testduration[i])
|
||||||
|
score.append(np.nan)
|
||||||
|
duration.append(np.nan)
|
||||||
|
|
||||||
|
for i in range(len(alldates)):
|
||||||
|
td.append(arrow.get(alldates[i]).datetime)
|
||||||
|
markerscore.append(np.nan)
|
||||||
|
score.append(alltestpower[i])
|
||||||
|
markerduration.append(np.nan)
|
||||||
|
duration.append(allduration[i])
|
||||||
|
|
||||||
|
for i in range(nrdays+1):
|
||||||
|
td.append(arrow.get(startdate+datetime.timedelta(days=i)).datetime)
|
||||||
|
markerscore.append(np.nan)
|
||||||
|
score.append(np.nan)
|
||||||
|
markerduration.append(np.nan)
|
||||||
|
duration.append(np.nan)
|
||||||
|
|
||||||
|
df = pd.DataFrame({
|
||||||
|
'markerscore':markerscore,
|
||||||
|
'markerduration':markerduration,
|
||||||
|
'score':score,
|
||||||
|
'duration':duration,
|
||||||
|
'date':td,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
df.sort_values(['date'],inplace=True)
|
||||||
|
|
||||||
|
df = df.groupby(['date']).max()
|
||||||
|
df['date'] = df.index.values
|
||||||
|
|
||||||
|
|
||||||
|
source = ColumnDataSource(
|
||||||
|
data = dict(
|
||||||
|
markerscore = df['markerscore'],
|
||||||
|
score = df['score'],
|
||||||
|
markerduration = df['markerduration'].apply(lambda x:totaltime_sec_to_string(x,shorten=True)),
|
||||||
|
duration = df['duration'].apply(lambda x:totaltime_sec_to_string(x,shorten=True)),
|
||||||
|
date = df['date'],
|
||||||
|
fdate = df['date'].map(lambda x: x.strftime('%d-%m-%Y')),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
plot = Figure(tools=TOOLS,x_axis_type='datetime',
|
||||||
|
plot_width=900,plot_height=600,
|
||||||
|
toolbar_location='above',
|
||||||
|
toolbar_sticky=False)
|
||||||
|
|
||||||
|
# add watermark
|
||||||
|
watermarkurl = "/static/img/logo7.png"
|
||||||
|
watermarksource = ColumnDataSource(dict(
|
||||||
|
url = [watermarkurl],))
|
||||||
|
|
||||||
|
watermarkrange = Range1d(start=0,end=1)
|
||||||
|
watermarkalpha = 0.6
|
||||||
|
watermarkx = 0.99
|
||||||
|
watermarky = 0.01
|
||||||
|
watermarkw = 184
|
||||||
|
watermarkh = 35
|
||||||
|
watermarkanchor = 'bottom_right'
|
||||||
|
plot.extra_y_ranges = {"watermark": watermarkrange}
|
||||||
|
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||||
|
|
||||||
|
plot.image_url([watermarkurl],watermarkx,watermarky,
|
||||||
|
watermarkw,watermarkh,
|
||||||
|
global_alpha=watermarkalpha,
|
||||||
|
w_units='screen',
|
||||||
|
h_units='screen',
|
||||||
|
anchor=watermarkanchor,
|
||||||
|
dilate=True,
|
||||||
|
x_range_name = "watermark",
|
||||||
|
y_range_name = "watermark",
|
||||||
|
)
|
||||||
|
|
||||||
|
plot.xaxis.axis_label = 'Date'
|
||||||
|
plot.yaxis.axis_label = 'Gold Medal Score'
|
||||||
|
|
||||||
|
plot.circle('date','score',source=source,fill_color='blue',
|
||||||
|
size=10,
|
||||||
|
legend_label='Workouts')
|
||||||
|
|
||||||
|
plot.circle('date','markerscore',source=source,fill_color='red',
|
||||||
|
size=10,
|
||||||
|
legend_label='Marker Workouts')
|
||||||
|
|
||||||
|
plot.legend.location = "top_left"
|
||||||
|
|
||||||
|
plot.x_range = Range1d(
|
||||||
|
startdate,enddate+datetime.timedelta(days=5),
|
||||||
|
)
|
||||||
|
|
||||||
|
hover = plot.select(dict(type=HoverTool))
|
||||||
|
|
||||||
|
hover.tooltips = OrderedDict([
|
||||||
|
('Marker','@markerscore{int}'),
|
||||||
|
('Test', '@markerduration'),
|
||||||
|
('Score','@score{int}'),
|
||||||
|
('Duration', '@duration'),
|
||||||
|
('Date','@fdate'),
|
||||||
|
])
|
||||||
|
|
||||||
|
script, div = components(plot)
|
||||||
|
|
||||||
|
return script, div
|
||||||
|
|
||||||
def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
||||||
metricchoice='trimp',doform=False,dofatigue=False,
|
metricchoice='trimp',doform=False,dofatigue=False,
|
||||||
showtests=False):
|
showtests=False):
|
||||||
|
|||||||
142
rowers/templates/goldmedalscores.html
Normal file
142
rowers/templates/goldmedalscores.html
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
{% extends "newbase.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
|
||||||
|
{% block title %}Rowsandall Gold Medal Score {% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<script type='text/javascript'
|
||||||
|
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function submit_form() {
|
||||||
|
console.log("form changed");
|
||||||
|
var frm = $("#performanceform");
|
||||||
|
|
||||||
|
var data = new FormData(frm[0]);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url:"/rowers/goldmedalscores/user/{{ rower.user.id }}/",
|
||||||
|
type: "POST",
|
||||||
|
contentType: false,
|
||||||
|
processData: false,
|
||||||
|
data: data,
|
||||||
|
dataType: 'json',
|
||||||
|
|
||||||
|
success: function(data) {
|
||||||
|
console.log(data);
|
||||||
|
// var parsedJSON = $.parseJSON(data); //
|
||||||
|
$("#id_script").replaceWith('<div id="id_script">'+data.script+'</d'+'iv>');
|
||||||
|
$("#id_chart").replaceWith('<div id="id_chart">'+data.div+'</d'+'iv>');
|
||||||
|
console.log('done');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||||
|
console.log("CSRF token",csrftoken);
|
||||||
|
|
||||||
|
function csrfSafeMethod(method) {
|
||||||
|
// these HTTP methods do not require CSRF protection
|
||||||
|
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
||||||
|
}
|
||||||
|
$.ajaxSetup({
|
||||||
|
beforeSend: function(xhr, settings) {
|
||||||
|
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||||
|
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#performanceform").on('change', function(evt) {
|
||||||
|
submit_form();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
|
||||||
|
<script src="https://cdn.pydata.org/bokeh/release/bokeh-2.2.3.min.js"></script>
|
||||||
|
<script async="true" type="text/javascript">
|
||||||
|
Bokeh.set_log_level("info");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="id_script">
|
||||||
|
{{ chartscript |safe }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% if rower.user %}
|
||||||
|
<h1>Gold Medal Scores for {{ rower.user.first_name }} </h1>
|
||||||
|
{% else %}
|
||||||
|
<h1>Gold Medal Scores for {{ user.first_name }} </h1>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
<ul class="main-content">
|
||||||
|
<li class="grid_4">
|
||||||
|
<div id="id_chart">
|
||||||
|
{{ the_div|safe }}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="grid_1">
|
||||||
|
<form id="dateform" enctype="multipart/form-data" method="post">
|
||||||
|
<table>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
<input name='form' class="button" type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
<li class="grid_2">
|
||||||
|
<p>
|
||||||
|
Explanation
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{% if bestworkouts %}
|
||||||
|
<h2>Marker Workouts</h2>
|
||||||
|
<li class="grid_4">
|
||||||
|
<table width="100%" class="listtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Workout</th>
|
||||||
|
<th>Gold Medal Score</th>
|
||||||
|
<th>Duration</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for w in bestworkouts %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ w.date }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/workout/{{ w.id|encode }}/">{{ w.name }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ w.goldmedalstandard|floatformat:"0" }} %
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ w.goldmedalseconds|secondstotimestring }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include 'menu_analytics.html' %}
|
||||||
|
{% endblock %}
|
||||||
@@ -355,6 +355,9 @@ urlpatterns = [
|
|||||||
re_path(r'^fitness-fit/$',views.fitness_from_cp_view,name='fitness_from_cp_view'),
|
re_path(r'^fitness-fit/$',views.fitness_from_cp_view,name='fitness_from_cp_view'),
|
||||||
re_path(r'^fitness-fit/user/(?P<userid>\d+)/$',views.fitness_from_cp_view,name='fitness_from_cp_view'),
|
re_path(r'^fitness-fit/user/(?P<userid>\d+)/$',views.fitness_from_cp_view,name='fitness_from_cp_view'),
|
||||||
re_path(r'^fitness-fit/user/(?P<userid>\d+)/(?P<mode>\w+.*)/$',views.fitness_from_cp_view,name='fitness_from_cp_view'),
|
re_path(r'^fitness-fit/user/(?P<userid>\d+)/(?P<mode>\w+.*)/$',views.fitness_from_cp_view,name='fitness_from_cp_view'),
|
||||||
|
re_path(r'^goldmedalscores/$',views.goldmedalscores_view,name='goldmedalscores_view'),
|
||||||
|
re_path(r'^goldmedalscores/user/(?P<userid>\d+)/$',views.goldmedalscores_view,name='goldmedalscores_view'),
|
||||||
|
re_path(r'^goldmedalscores/user/(?P<userid>\d+)/(?P<mode>\w+.*)/$',views.goldmedalscores_view,name='goldmedalscores_view'),
|
||||||
re_path(r'^performancemanager/$',views.performancemanager_view,name='performancemanager_view'),
|
re_path(r'^performancemanager/$',views.performancemanager_view,name='performancemanager_view'),
|
||||||
re_path(r'^performancemanager/user/(?P<userid>\d+)/$',views.performancemanager_view,name='performancemanager_view'),
|
re_path(r'^performancemanager/user/(?P<userid>\d+)/$',views.performancemanager_view,name='performancemanager_view'),
|
||||||
re_path(r'^performancemanager/user/(?P<userid>\d+)/(?P<mode>\w+.*)/$',views.performancemanager_view,name='performancemanager_view'),
|
re_path(r'^performancemanager/user/(?P<userid>\d+)/(?P<mode>\w+.*)/$',views.performancemanager_view,name='performancemanager_view'),
|
||||||
|
|||||||
@@ -1543,6 +1543,70 @@ def fitnessmetric_view(request,userid=0,mode='rower',
|
|||||||
'form':form,
|
'form':form,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@user_passes_test(ispromember, login_url="/rowers/paidplans",
|
||||||
|
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
|
||||||
|
redirect_field_name=None)
|
||||||
|
def goldmedalscores_view(request,userid=0,
|
||||||
|
startdate=timezone.now()-timezone.timedelta(days=365),
|
||||||
|
enddate=timezone.now()):
|
||||||
|
|
||||||
|
is_ajax = False
|
||||||
|
if request.is_ajax():
|
||||||
|
is_ajax = True
|
||||||
|
|
||||||
|
therower = getrequestrower(request,userid=userid)
|
||||||
|
theuser = therower.user
|
||||||
|
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = DateRangeForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
startdate = form.cleaned_data['startdate']
|
||||||
|
enddate = form.cleaned_data['enddate']
|
||||||
|
if startdate > enddate:
|
||||||
|
s = enddate
|
||||||
|
enddate = startdate
|
||||||
|
startdate = s
|
||||||
|
else:
|
||||||
|
form = DateRangeForm(initial={
|
||||||
|
'startdate':startdate,
|
||||||
|
'enddate':enddate,
|
||||||
|
})
|
||||||
|
|
||||||
|
script, div = goldmedalscorechart(
|
||||||
|
theuser,startdate=startdate,enddate=enddate,
|
||||||
|
)
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':'/rower/analysis',
|
||||||
|
'name':'Analysis',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(goldmedalscores_view),
|
||||||
|
'name': 'Gold Medal Scores'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
if is_ajax:
|
||||||
|
response = json.dumps({
|
||||||
|
'script':script,
|
||||||
|
'div':div,
|
||||||
|
})
|
||||||
|
|
||||||
|
return(HttpResponse(response,content_type='application/json'))
|
||||||
|
|
||||||
|
return render(request,'goldmedalscores.html',
|
||||||
|
{
|
||||||
|
'rower':therower,
|
||||||
|
'active':'nav-analysis',
|
||||||
|
'chartscript':script,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
|
'the_div':div,
|
||||||
|
'form':form,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@user_passes_test(ispromember, login_url="/rowers/paidplans",
|
@user_passes_test(ispromember, login_url="/rowers/paidplans",
|
||||||
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
|
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
|
||||||
redirect_field_name=None)
|
redirect_field_name=None)
|
||||||
@@ -1606,8 +1670,8 @@ def performancemanager_view(request,userid=0,mode='rower',
|
|||||||
'name':'Analysis'
|
'name':'Analysis'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'url':reverse('fitnessmetric_view'),
|
'url':reverse('performancemanager_view'),
|
||||||
'name': 'Power Progress'
|
'name': 'Performance Manager'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user