From cde3eaf60595ccf8d193a20e5262c7824aefdcea Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 6 Jul 2017 09:57:20 +0200 Subject: [PATCH] start of multiflex --- rowers/interactiveplots.py | 20 ++++ rowers/templates/analysis.html | 14 ++- rowers/templates/user_multiflex_select.html | 118 ++++++++++++++++++++ rowers/urls.py | 4 + rowers/views.py | 91 +++++++++++++++ 5 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 rowers/templates/user_multiflex_select.html diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index e8b5ec77..a8e3f38a 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -69,7 +69,27 @@ watermarkw = 184 watermarkh = 35 watermarkanchor = 'bottom_right' +def errorbar(fig, x, y, xerr=None, yerr=None, color='red', + point_kwargs={}, error_kwargs={}): + fig.circle(x, y, color=color, **point_kwargs) + + if xerr: + x_err_x = [] + x_err_y = [] + for px, py, err in zip(x, y, xerr): + x_err_x.append((px - err, px + err)) + x_err_y.append((py, py)) + fig.multi_line(x_err_x, x_err_y, color=color, **error_kwargs) + + if yerr: + y_err_x = [] + y_err_y = [] + for px, py, err in zip(x, y, yerr): + y_err_x.append((px, px)) + y_err_y.append((py - err, py + err)) + fig.multi_line(y_err_x, y_err_y, color=color, **error_kwargs) + def tailwind(bearing,vwind,winddir): """ Calculates head-on head/tailwind in direction of rowing diff --git a/rowers/templates/analysis.html b/rowers/templates/analysis.html index 4eae9987..2aeca53a 100644 --- a/rowers/templates/analysis.html +++ b/rowers/templates/analysis.html @@ -95,7 +95,7 @@ Analyse power vs piece duration to make predictions.

-
+

{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} Multi Compare @@ -107,6 +107,18 @@ Compare many workouts

+
+

+ {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + Multi Flex + {% else %} + Multi Flex + {% endif %} +

+

+ Select workouts and make X-Y charts of averages over various metrics +

+
diff --git a/rowers/templates/user_multiflex_select.html b/rowers/templates/user_multiflex_select.html new file mode 100644 index 00000000..2033faf9 --- /dev/null +++ b/rowers/templates/user_multiflex_select.html @@ -0,0 +1,118 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Workouts{% endblock %} + +{% block content %} + + + + {% if team %} +
+ {% include "teambuttons.html" with teamid=team.id team=team %} +
+{% endif %} +
+
+ {% if theuser %} +

{{ theuser.first_name }}'s Workouts

+ {% else %} +

{{ user.first_name }}'s Workouts

+ {% endif %} +
+
+ {% if user.is_authenticated and user|is_manager %} + +
+
+
+ + {% if theuser %} +
+ {% else %} + + {% endif %} + + + {{ dateform.as_table }} +
+ {% csrf_token %} +
+
+ +
+
+
+
+ +
+
+ +
+
+
+ +
+ + +
+
+ + + {% if workouts %} + + Toggle All
+ + {{ form.as_table }} +
+{% else %} +

No workouts found

+{% endif %} +
+
+

Warning: You are on an experimental part of the site. Use at your own risk.

+

Select two or more workouts on the left, set your plot settings below, + and press submit"

+ {% csrf_token %} + + {{ chartform.as_table }} +
+
+

+ +

+
+
+

You can use the date and search forms above to search through all + workouts from this team.

+

TIP: Agree with your team members to put tags (e.g. '8x500m') in the notes section of + your workouts. That makes it easy to search.

+
+
+
+ + +{% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index edf1f23d..9c415836 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -129,6 +129,10 @@ urlpatterns = [ url(r'^user-boxplot-select/user/(?P\d+)/$',views.user_boxplot_select), url(r'^user-boxplot-select/(?P\w+.*)/(?P\w+.*)$',views.user_boxplot_select), url(r'^user-boxplot-select/$',views.user_boxplot_select), + url(r'^user-multiflex-select/user/(?P\d+)/(?P\w+.*)/(?P\w+.*)$',views.user_multiflex_select), + url(r'^user-multiflex-select/user/(?P\d+)/$',views.user_multiflex_select), + url(r'^user-multiflex-select/(?P\w+.*)/(?P\w+.*)$',views.user_multiflex_select), + url(r'^user-multiflex-select/$',views.user_multiflex_select), url(r'^list-graphs/$',views.graphs_view), url(r'^(?P\d+)/ote-bests/(?P\w+.*)/(?P\w+.*)$',views.rankings_view), url(r'^(?P\d+)/ote-bests/(?P\d+)$',views.rankings_view), diff --git a/rowers/views.py b/rowers/views.py index a1f76391..63562b39 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -3324,6 +3324,97 @@ def multi_compare_view(request): url = reverse(workouts_view) return HttpResponseRedirect(url) +# Box plots +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) +def user_multiflex_select(request, + startdatestring="", + enddatestring="", + message='', + successmessage='', + startdate=timezone.now()-datetime.timedelta(days=30), + enddate=timezone.now()+datetime.timedelta(days=1), + userid=0): + + if userid == 0: + user = request.user + else: + user = User.objects.get(id=userid) + + + r = getrower(user) + + if 'startdate' in request.session: + startdate = iso8601.parse_date(request.session['startdate']) + + + if 'enddate' in request.session: + enddate = iso8601.parse_date(request.session['enddate']) + + + if request.method == 'POST': + dateform = DateRangeForm(request.POST) + if dateform.is_valid(): + startdate = dateform.cleaned_data['startdate'] + enddate = dateform.cleaned_data['enddate'] + else: + dateform = DateRangeForm(initial={ + 'startdate':startdate, + 'enddate':enddate, + }) + + startdate = datetime.datetime.combine(startdate,datetime.time()) + enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) + enddate = enddate+datetime.timedelta(days=1) + + if startdatestring: + startdate = iso8601.parse_date(startdatestring) + if enddatestring: + enddate = iso8601.parse_date(enddatestring) + + if enddate < startdate: + s = enddate + enddate = startdate + startdate = s + + + workouts = Workout.objects.filter(user=r, + startdatetime__gte=startdate, + startdatetime__lte=enddate).order_by("-date", "-starttime") + + query = request.GET.get('q') + if query: + query_list = query.split() + workouts = workouts.filter( + reduce(operator.and_, + (Q(name__icontains=q) for q in query_list)) | + reduce(operator.and_, + (Q(notes__icontains=q) for q in query_list)) + ) + + form = WorkoutMultipleCompareForm() + form.fields["workouts"].queryset = workouts + + chartform = BoxPlotChoiceForm() + + messages.info(request,successmessage) + messages.error(request,message) + + startdatestring = startdate.strftime('%Y-%m-%d') + enddatestring = enddate.strftime('%Y-%m-%d') + request.session['startdate'] = startdatestring + request.session['enddate'] = enddatestring + + return render(request, 'user_boxplot_select.html', + {'workouts': workouts, + 'dateform':dateform, + 'startdate':startdate, + 'enddate':enddate, + 'theuser':user, + 'form':form, + 'chartform':chartform, + 'teams':get_my_teams(request.user), + }) + # Box plots @user_passes_test(ispromember,login_url="/",redirect_field_name=None) def user_boxplot_select(request,