diff --git a/rowers/forms.py b/rowers/forms.py index 310ef7d5..d7210ac4 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -6,6 +6,8 @@ from django.contrib.auth.models import User from django.contrib.admin.widgets import AdminDateWidget from django.forms.extras.widgets import SelectDateWidget from django.utils import timezone,translation +from django.forms import ModelForm +import dataprep import datetime @@ -261,7 +263,7 @@ from rowers.interactiveplots import axlabels formaxlabels = axlabels.copy() formaxlabels.pop('None') -parchoices = list(sorted(axlabels.items(), key = lambda x:x[1])) +parchoices = list(sorted(formaxlabels.items(), key = lambda x:x[1])) class ChartParamChoiceForm(forms.Form): @@ -275,9 +277,13 @@ class ChartParamChoiceForm(forms.Form): teamid = forms.IntegerField(widget=forms.HiddenInput()) formaxlabels.pop('time') -metricchoices = list(sorted(axlabels.items(), key = lambda x:x[1])) +metricchoices = list(sorted(formaxlabels.items(), key = lambda x:x[1])) -class FusionMetricChoiceForm(forms.Form): +class FusionMetricChoiceForm(ModelForm): + class Meta: + model = Workout + fields = [] + posneg = ( ('pos','Workout 2 starts after Workout 1'), ('neg','Workout 2 starts before Workout 1'), @@ -287,3 +293,17 @@ class FusionMetricChoiceForm(forms.Form): widget=forms.CheckboxSelectMultiple()) posneg = forms.ChoiceField(choices=posneg,initial='pos') offset = forms.DurationField(label='Time Offset',initial=datetime.timedelta()) + + def __init__(self, *args, **kwargs): + super(FusionMetricChoiceForm, self).__init__(*args, **kwargs) + # need to add code to remove "empty" fields + + id = self.instance.id + df = dataprep.getrowdata_db(id=id) + + labeldict = {key:value for key,value in metricchoices} + + for label in labeldict: + if df[label].std() == 0: + self.fields['columns'].choices.remove((label, labeldict[label])) + diff --git a/rowers/templates/advancededit.html b/rowers/templates/advancededit.html index fe002787..6db5b03c 100644 --- a/rowers/templates/advancededit.html +++ b/rowers/templates/advancededit.html @@ -121,7 +121,7 @@
-
+

{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} Power Histogram @@ -133,9 +133,20 @@ Plot the Power Histogram of this workout

+
+

+ {% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %} + Sensor Fusion + {% else %} + Dist Metrics Plot + {% endif %} +

+

+ Merge data from another source into this workout +

+
-
diff --git a/rowers/templates/fusion.html b/rowers/templates/fusion.html index bb0840d6..52de737e 100644 --- a/rowers/templates/fusion.html +++ b/rowers/templates/fusion.html @@ -13,7 +13,7 @@

- Adding sensor data from workout {{ workout2.id }} into workout {{ workout1.id2 }}. + Adding sensor data from workout {{ workout2.id }} into workout {{ workout1.id }}. This will create a new workout. After you submit the form, you will be taken to the newly created workout. If you are happy with the result, you can delete the two original workouts manually. diff --git a/rowers/templates/fusion_list.html b/rowers/templates/fusion_list.html new file mode 100644 index 00000000..b7f285d7 --- /dev/null +++ b/rowers/templates/fusion_list.html @@ -0,0 +1,121 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Workouts{% endblock %} + +{% block content %} +

+
+

Workout {{ id }}

+ + + + + + + + + + + + + + + + + + + + +
Rower:{{ first_name }} {{ last_name }}
Name:{{ workout.name }}
Date:{{ workout.date }}
Time:{{ workout.starttime }}
Distance:{{ workout.distance }}m
Duration:{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
Type:{{ workout.workouttype }}
Weight Category:{{ workout.weightcategory }}
+
+
+

+

+ + +
+

+
+ + Select start and end date for a date range: +
+

+

+ + + {{ dateform.as_table }} +
+ {% csrf_token %} +
+
+ +

+
+ + +
+ +
+

Fuse this workout with data from:

+ {% if workouts %} + + + + + + + + + + + + + + + + {% for cworkout in workouts %} + + + + + + + + + + {% if id == cworkout.id %} + + {% else %} + + {% endif %} + + + {% endfor %} + +
Date Time Name Type Distance Duration Avg HR Max HR Fusion
{{ cworkout.date }} {{ cworkout.starttime }} {{ cworkout.name }} {{ cworkout.workouttype }} {{ cworkout.distance }}m {{ cworkout.duration |durationprint:"%H:%M:%S.%f" }} {{ cworkout.averagehr }} {{ cworkout.maxhr }}   Fusion
+ {% else %} +

No workouts found

+ {% endif %} + +
+ + {% if workouts.has_previous %} + < + {% endif %} + + + Page {{ workouts.number }} of {{ workouts.paginator.num_pages }}. + + + {% if workouts.has_next %} + > + {% endif %} + +
+
+{% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index b5a8629c..6a524940 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -190,6 +190,9 @@ urlpatterns = [ url(r'^workout/(\d+)/view$',views.workout_view), url(r'^workout/(\d+)$',views.workout_view), url(r'^workout/fusion/(?P\d+)/(?P\d+)$',views.workout_fusion_view), + url(r'^workout/fusion/(\d+)/$',views.workout_fusion_list), + url(r'^workout/fusion/(?P\d+)/(?P\d+-\d+-\d+)/(?P\w+.*)$',views.workout_fusion_list), + url(r'^physics$',TemplateView.as_view(template_name='physics.html'),name='physics'), url(r'^workout/(\d+)/$',views.workout_view), url(r'^workout/(\d+)/addtimeplot$',views.workout_add_timeplot_view), diff --git a/rowers/views.py b/rowers/views.py index 357eac60..6a5ccf3b 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -2320,6 +2320,85 @@ def workout_comparison_list(request,id=0,message='',successmessage='', except Rower.DoesNotExist: raise Http404("User has no rower instance") +# List of workouts to compare a selected workout to +@user_passes_test(ispromember,login_url="/",redirect_field_name=None) +def workout_fusion_list(request,id=0,message='',successmessage='', + startdatestring="",enddatestring="", + startdate=timezone.now()-datetime.timedelta(days=365), + enddate=timezone.now()): + + try: + r = Rower.objects.get(user=request.user) + u = User.objects.get(id=r.user.id) + 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, + }) + + if startdatestring: + startdate = iso8601.parse_date(startdatestring) + if enddatestring: + enddate = iso8601.parse_date(enddatestring) + + startdate = datetime.datetime.combine(startdate,datetime.time()) + enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) + enddate = enddate+datetime.timedelta(days=1) + + 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").exclude(id=id) + + 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)) + ) + + paginator = Paginator(workouts,15) # show 25 workouts per page + page = request.GET.get('page') + + try: + workouts = paginator.page(page) + except PageNotAnInteger: + workouts = paginator.page(1) + except EmptyPage: + workouts = paginator.page(paginator.num_pages) + try: + row = Workout.objects.get(id=id) + except Workout.DoesNotExist: + raise Http404("Workout doesn't exist") + + + return render(request, 'fusion_list.html', + {'id':id, + 'workout':row, + 'workouts': workouts, + 'last_name':u.last_name, + 'first_name':u.first_name, + 'message': message, + 'successmessage':successmessage, + 'dateform':dateform, + 'startdate':startdate, + 'enddate':enddate, + }) + except Rower.DoesNotExist: + raise Http404("User has no rower instance") + # Basic 'EDIT' view of workout def workout_view(request,id=0): try: @@ -5048,7 +5127,7 @@ def workout_fusion_view(request,id1=0,id2=1): }) - form = FusionMetricChoiceForm() + form = FusionMetricChoiceForm(instance=w2) return render(request, 'fusion.html', {'form':form,