diff --git a/rowers/templates/alert_delete_confirm.html b/rowers/templates/alert_delete_confirm.html index 8871a27d..39a7646f 100644 --- a/rowers/templates/alert_delete_confirm.html +++ b/rowers/templates/alert_delete_confirm.html @@ -6,20 +6,20 @@ {% block main %}
This will permanently delete the alert
- +
No pieces uploaded for this date range.
' - - scripta = script.split('\n')[2:-1] - script = ''.join(scripta) - - data = { - "script":script, - "div":div, - } - - return JSONResponse(data) - -# The Flex plot for a large selection of workouts -@login_required() -def histo_data( - request, - options={ - 'includereststrokes':False, - 'rankingonly':False, - 'modality':'all', - 'waterboattype':mytypes.waterboattype, - 'theuser':0, - 'enddatestring':timezone.now().strftime("%Y-%m-%d"), - 'startdatestring':(timezone.now()-datetime.timedelta(days=30)).strftime("%Y-%m-%d"), - 'deltadays':-1, - 'histoparam':'power', - }): - - def_options = options - - - if 'options' in request.session: - options = request.session['options'] - - modality = keyvalue_get_default('modality',options,def_options) - rankingonly = keyvalue_get_default('rankingonly',options,def_options) - includereststrokes = keyvalue_get_default('includereststrokes',options,def_options) - waterboattype = keyvalue_get_default('waterboattype',options,def_options) - workstrokesonly = not includereststrokes - theuser = keyvalue_get_default('theuser',options,def_options) - startdatestring = keyvalue_get_default('startdatestring',options,def_options) - enddatestring = keyvalue_get_default('enddatestring',options,def_options) - histoparam = keyvalue_get_default('histoparam',options,def_options) - - if modality == 'all': - modalities = [m[0] for m in mytypes.workouttypes] - else: # pragma: no cover - modalities = [modality] - - try: - startdate = iso8601.parse_date(startdatestring) - except ParseError: # pragma: no cover - startdate = timezone.now()-datetime.timedelta(days=7) - - try: - enddate = iso8601.parse_date(enddatestring) - except ParseError: # pragma: no cover - enddate = timezone.now() - - - if enddate < startdate: # pragma: no cover - s = enddate - enddate = startdate - startdate = s - - promember=0 - if theuser == 0: - theuser = request.user.id - - if not request.user.is_anonymous: - r = getrower(request.user) - result = request.user.is_authenticated and ispromember(request.user) - if result: - promember=1 - - r2 = getrower(theuser) - - if rankingonly: # pragma: no cover - rankingpiece = [True,] - else: - rankingpiece = [True,False] - - allworkouts = Workout.objects.filter(user=r2, - workouttype__in=modalities, - boattype__in=waterboattype, - startdatetime__gte=startdate, - startdatetime__lte=enddate, - rankingpiece__in=rankingpiece) - - if allworkouts: - res = interactive_histoall(allworkouts,histoparam,includereststrokes) - script = res[0] - div = res[1] - else: - script = '' - div = 'No pieces uploaded for this date range.
' - - scripta = script.split('\n')[2:-1] - script = ''.join(scripta) - - data = { - "script":script, - "div":div, - } - - return JSONResponse(data) - - - - -@login_required() -def cum_flex(request,theuser=0, - xparam='spm', - yparam1='power', - yparam2='None', - startdate=timezone.now()-datetime.timedelta(days=10), - enddate=timezone.now(), - deltadays=-1, - enddatestring=timezone.now().strftime("%Y-%m-%d"), - startdatestring=(timezone.now()-datetime.timedelta(days=30)).strftime("%Y-%m-%d"), - options={ - 'includereststrokes':False, - 'workouttypes':[i[0] for i in mytypes.workouttypes], - 'waterboattype':mytypes.waterboattype, - 'rankingonly':False, - }): - - - r = getrequestrower(request,userid=theuser) - theuser = r.user - - if 'waterboattype' in request.session: # pragma: no cover - waterboattype = request.session['waterboattype'] - else: - waterboattype = mytypes.waterboattype - - - if 'rankingonly' in request.session: # pragma: no cover - rankingonly = request.session['rankingonly'] - else: - rankingonly = False - - if 'modalities' in request.session: # pragma: no cover - modalities = request.session['modalities'] - if len(modalities) > 1: - modality = 'all' - else: - modality = modalities[0] - else: - modalities = [m[0] for m in mytypes.workouttypes] - modality = 'all' - - - try: - rankingonly = options['rankingonly'] - except KeyError: # pragma: no cover - rankingonly = False - - try: - includereststrokes = options['includereststrokes'] - except KeyError: # pragma: no cover - includereststrokes = False - - - workstrokesonly = not includereststrokes - - waterboattype = mytypes.waterboattype - - - if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) - - if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) - - if enddate < startdate: # pragma: no cover - s = enddate - enddate = startdate - startdate = s - - - # get all indoor rows of in date range - - # process form - if request.method == 'POST': - form = DateRangeForm(request.POST) - modalityform = TrendFlexModalForm(request.POST) - flexaxesform = FlexAxesForm(request,request.POST) - if form.is_valid(): - startdate = form.cleaned_data['startdate'] - enddate = form.cleaned_data['enddate'] - if startdate > enddate: # pragma: no cover - s = enddate - enddate = startdate - startdate = s - startdatestring = startdate.strftime('%Y-%m-%d') - enddatestring = enddate.strftime('%Y-%m-%d') - if modalityform.is_valid(): - modality = modalityform.cleaned_data['modality'] - waterboattype = modalityform.cleaned_data['waterboattype'] - rankingonly = modalityform.cleaned_data['rankingonly'] - if modality == 'all': - modalities = [m[0] for m in mytypes.workouttypes] - else: # pragma: no cover - modalities = [modality] - - if modality != 'water': - waterboattype = [b[0] for b in mytypes.boattypes] - - - request.session['modalities'] = modalities - request.session['waterboattype'] = waterboattype - request.session['rankingonly'] = rankingonly - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - if flexaxesform.is_valid(): - xparam = flexaxesform.cleaned_data['xaxis'] - yparam1 = flexaxesform.cleaned_data['yaxis1'] - yparam2 = flexaxesform.cleaned_data['yaxis2'] - else: - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - includereststrokes = False - - workstrokesonly = not includereststrokes - modalityform = TrendFlexModalForm( - initial={ - 'modality':modality, - 'waterboattype':waterboattype, - 'rankingonly':rankingonly, - } - ) - initial = { - 'xaxis':xparam, - 'yaxis1':yparam1, - 'yaxis2':yparam2 - } - flexaxesform = FlexAxesForm(request,initial=initial) - - negtypes = [] - for b in mytypes.boattypes: - if b[0] not in waterboattype: # pragma: no cover - negtypes.append(b[0]) - - - - script = '' - div = get_call() - js_resources = '' - css_resources = '' - - - - - options = { - 'xparam': xparam, - 'yparam1': yparam1, - 'yparam2': yparam2, - 'modality': modality, - 'theuser': theuser.id, - 'waterboattype':waterboattype, - 'startdatestring':startdatestring, - 'enddatestring':enddatestring, - 'rankingonly':rankingonly, - 'includereststrokes':includereststrokes, - } - - request.session['options'] = options - - promember=0 - mayedit=0 - if not request.user.is_anonymous: - result = request.user.is_authenticated and ispromember(request.user) - if result: - promember = 1 - - - request.session['options'] = options - - - return render(request, 'cum_flex.html', - {'interactiveplot':script, - 'the_div':div, - 'js_res': js_resources, - 'css_res':css_resources, - 'id':theuser, - 'rower':r, - 'active':'nav-analysis', - 'theuser':theuser, - 'startdate':startdate, - 'enddate':enddate, - 'form':form, - 'optionsform':modalityform, - 'xparam':xparam, - 'yparam1':yparam1, - 'yparam2':yparam2, - 'promember':promember, - 'teams':get_my_teams(request.user), - 'flexaxesform':flexaxesform, - }) def planrequired_view(request): @@ -1895,7 +1295,7 @@ def rankings_view2(request,userid=0, if dateform.is_valid(): startdate = dateform.cleaned_data['startdate'] enddate = dateform.cleaned_data['enddate'] - if startdate > enddate: + if startdate > enddate: # pragma: no cover s = enddate enddate = startdate startdate = s @@ -1928,7 +1328,7 @@ def rankings_view2(request,userid=0, # get all 2k (if any) - this rower, in date range try: r = getrower(theuser) - except Rower.DoesNotExist: + except Rower.DoesNotExist: # pragma: no cover allergworkouts = [] r=0 @@ -2012,7 +1412,7 @@ def rankings_view2(request,userid=0, message = res[5] try: testcalc = pd.Series(res[6])*3 - except TypeError: + except TypeError: # pragma: no cover age = 0 else: @@ -2085,7 +1485,7 @@ def rankings_view2(request,userid=0, pwr3 = 50. velo3 = (pwr3/2.8)**(1./3.) - if np.isnan(velo3) or velo3 <= 0: + if np.isnan(velo3) or velo3 <= 0: # pragma: no cover velo3 = 1.0 t3 = rankingdistance/velo3 @@ -2206,21 +1606,21 @@ def otecp_toadmin_view(request,theuser=0, enddate=timezone.now(), startdatestring="", enddatestring="", - ): + ): # pragma: no cover - if startdatestring != "": + if startdatestring != "": # pragma: no cover try: startdate = iso8601.parse_date(startdatestring) except ParseError: pass - if enddatestring != "": + if enddatestring != "": # pragma: no cover try: enddate = iso8601.parse_date(enddatestring) except ParseError: pass - if theuser == 0: + if theuser == 0: # pragma: no cover theuser = request.user.id u = User.objects.get(id=theuser) @@ -2280,7 +1680,7 @@ def otwcp_toadmin_view(request,theuser=0, enddate=timezone.now(), startdatestring="", enddatestring="", - ): + ): # pragma: no cover if startdatestring != "": try: @@ -2345,1407 +1745,6 @@ def otwcp_toadmin_view(request,theuser=0, return response - -# Multi Flex Chart with Grouping -@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) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def user_multiflex_select(request, - startdatestring="", - enddatestring="", - message='', - successmessage='', - startdate=timezone.now()-datetime.timedelta(days=30), - enddate=timezone.now(), - userid=0): - - r = getrequestrower(request,userid=userid) - user = r.user - - if 'options' in request.session: - options = request.session['options'] - else: - options = {} - - try: - palette = request.session['palette'] - except KeyError: - palette = 'monochrome_blue' - - try: - includereststrokes = request.session['includereststrokes'] - except KeyError: - includereststrokes = False - - try: - ploterrorbars = request.session['ploterrorbars'] - except: - ploterrorbars = False - - if 'startdate' in request.session: - startdate = iso8601.parse_date(request.session['startdate']) - - - if 'enddate' in request.session: - enddate = iso8601.parse_date(request.session['enddate']) - - try: - waterboattype = request.session['waterboattype'] - except KeyError: - waterboattype = mytypes.waterboattype - else: - waterboattype = mytypes.waterboattype - - if 'rankingonly' in request.session: - rankingonly = request.session['rankingonly'] - else: - rankingonly = False - - - if 'modalities' in request.session: - modalities = request.session['modalities'] - if len(modalities) > 1: - modality = 'all' - else: - modality = modalities[0] - else: - modalities = [m[0] for m in mytypes.workouttypes] - modality = 'all' - - if request.method == 'POST': - dateform = DateRangeForm(request.POST) - if dateform.is_valid(): - startdate = dateform.cleaned_data['startdate'] - enddate = dateform.cleaned_data['enddate'] - startdatestring = startdate.strftime('%Y-%m-%d') - enddatestring = enddate.strftime('%Y-%m-%d') - request.session['startdate'] = startdatestring - request.session['enddate'] = enddatestring - modalityform = TrendFlexModalForm(request.POST) - if modalityform.is_valid(): - modality = modalityform.cleaned_data['modality'] - waterboattype = modalityform.cleaned_data['waterboattype'] - rankingonly = modalityform.cleaned_data['rankingonly'] - if modality == 'all': - modalities = [m[0] for m in mytypes.workouttypes] - else: - modalities = [modality] - - if modality != 'water': - waterboattype = [b[0] for b in mytypes.boattypes] - - - request.session['modalities'] = modalities - request.session['waterboattype'] = waterboattype - request.session['rankingonly'] = rankingonly - 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 - - - negtypes = [] - for b in mytypes.boattypes: - if b[0] not in waterboattype: - negtypes.append(b[0]) - - if rankingonly: - rankingpiece = [True] - else: - rankingpiece = [True,False] - - # make sure the dates are not naive - try: - startdate = pytz.utc.localize(startdate) - except (ValueError, AttributeError): - pass - try: - enddate = pytz.utc.localize(enddate) - except (ValueError, AttributeError): - pass - - workouts = Workout.objects.filter( - user=r, - startdatetime__gte=startdate, - startdatetime__lte=enddate, - workouttype__in=modalities, - rankingpiece__in=rankingpiece - ).order_by( - "-date", "-starttime" - ).exclude( - boattype__in=negtypes - ) - - 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)) - ) - searchform = SearchForm(initial={'q':query}) - else: - searchform = SearchForm() - - form = WorkoutMultipleCompareForm() - form.fields["workouts"].queryset = workouts - - chartform = MultiFlexChoiceForm(initial={ - 'palette':palette, - 'ploterrorbars':ploterrorbars, - 'includereststrokes':includereststrokes, - }) - - modalityform = TrendFlexModalForm(initial={ - 'modality':modality, - 'waterboattype':waterboattype, - 'rankingonly':rankingonly, - }) - - 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 - - request.session['waterboattype'] = waterboattype - request.session['rankingonly'] = rankingonly - request.session['modalities'] = modalities - - - breadcrumbs = [ - { - 'url':'/rowers/analysis', - 'name':'Analysis' - }, - { - 'url':reverse(user_multiflex_select,kwargs={'userid':userid}), - 'name': 'Compare Select' - }, - { - 'url':reverse('multi_compare_view'), - 'name': 'Comparison Chart' - } - ] - - return render(request, 'user_multiflex_select.html', - {'workouts': workouts, - 'dateform':dateform, - 'breadcrumbs':breadcrumbs, - 'startdate':startdate, - 'enddate':enddate, - 'theuser':user, - 'rower':r, - 'form':form, - 'chartform':chartform, - 'searchform':searchform, - 'modalityform':modalityform, - 'teams':get_my_teams(request.user), - }) - -@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) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def multiflex_data(request,userid=0, - options={ - 'includereststrokes':False, - 'ploterrorbars':False, - 'userid':0, - 'palette': 'monochrome_blue', - 'groupby': 'spm', - 'binsize': 1, - 'xparam': 'hr', - 'yparam': 'pace', - 'spmmin': 15, - 'spmmax': 55, - 'workmin': 400, - 'workmax': 1500, - 'ids': [], - 'ploterrorbars':False, - }): - - def_options = options - - if 'options' in request.session: - options = request.session['options'] - - try: - includereststrokes = options['includereststrokes'] - except KeyError: - includereststrokes = False - - try: - ploterrorbars = options['ploterrorbars'] - except KeyError: - ploterrorbars = False - - try: - palette = request.session['palette'] - except KeyError: - palette = 'monochrome_blue' - - workstrokesonly = not includereststrokes - - if userid==0: - userid = request.user.id - - - palette = keyvalue_get_default('palette',options, def_options) - groupby = keyvalue_get_default('groupby',options, def_options) - binsize = keyvalue_get_default('binsize',options, def_options) - xparam = keyvalue_get_default('xparam',options, def_options) - yparam = keyvalue_get_default('yparam',options, def_options) - spmmin = keyvalue_get_default('spmmin',options, def_options) - spmmax = keyvalue_get_default('spmmax',options, def_options) - workmin = keyvalue_get_default('workmin',options, def_options) - workmax = keyvalue_get_default('workmax',options, def_options) - ids = keyvalue_get_default('ids',options, def_options) - - workouts = [] - - for id in ids: - try: - workouts.append(Workout.objects.get(id=id)) - except Workout.DoesNotExist: - pass - - labeldict = { - int(w.id): w.__str__() for w in workouts - } - - fieldlist,fielddict = dataprep.getstatsfields() - fieldlist = [xparam,yparam,groupby, - 'workoutid','spm','driveenergy', - 'workoutstate'] - - # prepare data frame - datadf,extracols = dataprep.read_cols_df_sql(ids,fieldlist) - - if xparam == groupby: - datadf['groupby'] = datadf[xparam] - groupy = 'groupby' - - datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly) - - - datadf = dataprep.filter_df(datadf,'spm',spmmin, - largerthan=True) - datadf = dataprep.filter_df(datadf,'spm',spmmax, - largerthan=False) - - datadf = dataprep.filter_df(datadf,'driveenergy',workmin, - largerthan=True) - datadf = dataprep.filter_df(datadf,'driveneergy',workmax, - largerthan=False) - - - datadf.dropna(axis=0,how='any',inplace=True) - - - datemapping = { - w.id:w.date for w in workouts - } - - datadf['date'] = datadf['workoutid'] - datadf['date'].replace(datemapping,inplace=True) - - today = datetime.date.today() - try: - datadf['days ago'] = map(lambda x : x.days, datadf.date - today) - except TypeError: - datadf['days ago'] = 0 - - if groupby != 'date': - try: - bins = np.arange(datadf[groupby].min()-binsize, - datadf[groupby].max()+binsize, - binsize) - groups = datadf.groupby(pd.cut(datadf[groupby],bins,labels=False)) - except (ValueError, AttributeError): - messages.error( - request, - "Unable to compete. Probably not enough data selected" - ) - url = reverse(user_multiflex_select) - return HttpResponseRedirect(url) - else: - bins = np.arange(datadf['days ago'].min()-binsize, - datadf['days ago'].max()+binsize, - binsize, - ) - groups = datadf.groupby(pd.cut(datadf['days ago'], bins, - labels=False)) - - - xvalues = groups.mean()[xparam] - yvalues = groups.mean()[yparam] - xerror = groups.std()[xparam] - yerror = groups.std()[yparam] - groupsize = groups.count()[xparam] - - mask = groupsize <= min([0.01*groupsize.sum(),0.2*groupsize.mean()]) - xvalues.loc[mask] = np.nan - - yvalues.loc[mask] = np.nan - xerror.loc[mask] = np.nan - yerror.loc[mask] = np.nan - groupsize.loc[mask] = np.nan - - xvalues.dropna(inplace=True) - yvalues.dropna(inplace=True) - xerror.dropna(inplace=True) - yerror.dropna(inplace=True) - groupsize.dropna(inplace=True) - - if len(groupsize) == 0: - messages.error(request,'No data in selection') - url = reverse(user_multiflex_select) - return HttpResponseRedirect(url) - else: - groupsize = 30.*np.sqrt(groupsize/float(groupsize.max())) - - df = pd.DataFrame({ - xparam:xvalues, - yparam:yvalues, - 'x':xvalues, - 'y':yvalues, - 'xerror':xerror, - 'yerror':yerror, - 'groupsize':groupsize, - }) - - - if yparam == 'pace': - df['y'] = dataprep.paceformatsecs(df['y']/1.0e3) - - aantal = len(df) - - if groupby != 'date': - try: - df['groupval'] = groups.mean()[groupby] - df['groupval'].loc[mask] = np.nan - - groupcols = df['groupval'] - except (ValueError, AttributeError): - df['groupval'] = groups.mean()[groupby].fillna(value=0) - df['groupval'].loc[mask] = np.nan - groupcols = df['groupval'] - except KeyError: - messages.error(request,'Data selection error') - url = reverse(user_multiflex_select) - return HttpResponseRedirect(url) - else: - try: - dates = groups.min()[groupby] - dates.loc[mask] = np.nan - dates.dropna(inplace=True) - df['groupval'] = [x.strftime("%Y-%m-%d") for x in dates] - df['groupval'].loc[mask] = np.nan - groupcols = 100.*np.arange(aantal)/float(aantal) - except AttributeError: - df['groupval'] = groups.mean()['days ago'].fillna(value=0) - groupcols = 100.*np.arange(aantal)/float(aantal) - - - groupcols = (groupcols-groupcols.min())/(groupcols.max()-groupcols.min()) - - if aantal == 1: - groupcols = np.array([1.]) - - - colors = range_to_color_hex(groupcols,palette=palette) - - df['color'] = colors - - clegendx = np.arange(0,1.2,.2) - legcolors = range_to_color_hex(clegendx,palette=palette) - if groupby != 'date': - clegendy = df['groupval'].min()+clegendx*(df['groupval'].max()-df['groupval'].min()) - else: - clegendy = df.index.min()+clegendx*(df.index.max()-df.index.min()) - - - - colorlegend = zip(range(6),clegendy,legcolors) - - - if userid == 0: - extratitle = '' - else: - u = User.objects.get(id=userid) - extratitle = ' '+u.first_name+' '+u.last_name - - - - script,div = interactive_multiflex(df,xparam,yparam, - groupby, - extratitle=extratitle, - ploterrorbars=ploterrorbars, - binsize=binsize, - colorlegend=colorlegend, - spmmin=spmmin,spmmax=spmmax, - workmin=workmin,workmax=workmax) - - scripta= script.split('\n')[2:-1] - script = ''.join(scripta) - - - return JSONResponse({ - "script":script, - "div":div, - }) - - -@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) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def multiflex_view(request,userid=0, - options={ - 'includereststrokes':False, - 'ploterrorbars':False, - }): - - if 'options' in request.session: - options = request.session['options'] - - try: - includereststrokes = options['includereststrokes'] - except KeyError: - includereststrokes = False - - try: - ploterrorbars = options['ploterrorbars'] - except KeyError: - ploterrorbars = False - - try: - palette = request.session['palette'] - except KeyError: - palette = 'monochrome_blue' - - if 'startdate' in request.session: - startdate = iso8601.parse_date(request.session['startdate']) - - - if 'enddate' in request.session: - enddate = iso8601.parse_date(request.session['enddate']) - - workstrokesonly = not includereststrokes - - if userid==0: - userid = request.user.id - - if request.method == 'POST' and 'workouts' in request.POST: - form = WorkoutMultipleCompareForm(request.POST) - chartform = MultiFlexChoiceForm(request.POST) - if form.is_valid() and chartform.is_valid(): - cd = form.cleaned_data - workouts = cd['workouts'] - xparam = chartform.cleaned_data['xparam'] - yparam = chartform.cleaned_data['yparam'] - includereststrokes = chartform.cleaned_data['includereststrokes'] - ploterrorbars = chartform.cleaned_data['ploterrorbars'] - - workstrokesonly = not includereststrokes - palette = chartform.cleaned_data['palette'] - - groupby = chartform.cleaned_data['groupby'] - binsize = chartform.cleaned_data['binsize'] - if binsize <= 0: - binsize = 1 - if groupby == 'pace': - binsize *= 1000 - - spmmin = chartform.cleaned_data['spmmin'] - spmmax = chartform.cleaned_data['spmmax'] - workmin = chartform.cleaned_data['workmin'] - workmax = chartform.cleaned_data['workmax'] - - ids = [int(w.id) for w in workouts] - request.session['ids'] = ids - - else: - return HttpResponse("Form is not valid") - elif request.method == 'POST' and 'ids' in request.session: - chartform = MultiFlexChoiceForm(request.POST) - if chartform.is_valid(): - xparam = chartform.cleaned_data['xparam'] - yparam = chartform.cleaned_data['yparam'] - includereststrokes = chartform.cleaned_data['includereststrokes'] - ploterrorbars = chartform.cleaned_data['ploterrorbars'] - request.session['ploterrorbars'] = ploterrorbars - request.session['includereststrokes'] = includereststrokes - workstrokesonly = not includereststrokes - palette = chartform.cleaned_data['palette'] - - groupby = chartform.cleaned_data['groupby'] - binsize = chartform.cleaned_data['binsize'] - if binsize <= 0: - binsize = 1 - if groupby == 'pace': - binsize *= 1000. - - spmmin = chartform.cleaned_data['spmmin'] - spmmax = chartform.cleaned_data['spmmax'] - workmin = chartform.cleaned_data['workmin'] - workmax = chartform.cleaned_data['workmax'] - - ids = request.session['ids'] - request.session['ids'] = ids - workouts = dataprep.get_workouts(ids,userid) - if not workouts: - message = 'Error: Workouts in session storage do not belong to this user.' - messages.error(request,message) - url = reverse(user_multiflex_select, - kwargs={ - 'userid':userid, - } - ) - return HttpResponseRedirect(url) - - # workouts = [Workout.objects.get(id=id) for id in ids] - - - else: - return HttpResponse("invalid form") - else: - url = reverse(user_multiflex_select) - return HttpResponseRedirect(url) - - div = get_call() - - options['includereststrokes'] = includereststrokes - options['ploterrorbars'] = ploterrorbars - options['userid'] = userid - options['palette'] = palette - options['groupby'] = groupby - options['binsize'] = binsize - options['xparam'] = xparam - options['yparam'] = yparam - options['spmmin'] = spmmin - options['spmmax'] = spmmax - options['workmin'] = workmin - options['workmax'] = workmax - options['idso'] = ids - - - request.session['options'] = options - - r = getrequestrower(request,userid=userid) - - breadcrumbs = [ - { - 'url':'/rowers/analysis', - 'name':'Analysis' - }, - { - 'url':reverse(user_multiflex_select,kwargs={'userid':userid}), - 'name': 'Trend Flex Select' - }, - { - 'url':reverse(multiflex_view), - 'name': 'Trend Flex Chart' - } - ] - - - return render(request,'multiflex.html', - {'interactiveplot':'', - 'active':'nav-analysis', - 'rower':r, - 'breadcrumbs':breadcrumbs, - 'the_div':div, - 'active':'nav-analysis', - 'chartform':chartform, - 'userid':userid, - 'teams':get_my_teams(request.user), - }) - - -# Box plots -@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) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def user_boxplot_select(request, - startdatestring="", - enddatestring="", - message='', - successmessage='', - startdate=timezone.now()-datetime.timedelta(days=30), - enddate=timezone.now(), - options={ - 'includereststrokes':False, - 'workouttypes':['rower','dynamic','slides'], - 'waterboattype':mytypes.waterboattype, - 'rankingonly':False, - }, - userid=0): - - r = getrequestrower(request,userid=userid) - user = r.user - userid = user.id - - if 'options' in request.session: - options = request.session['options'] - - - try: - workouttypes = options['workouttypes'] - except KeyError: - workouttypes = ['rower','dynamic','slides'] - - try: - rankingonly = options['rankingonly'] - except KeyError: - rankingonly = False - - try: - includereststrokes = options['includereststrokes'] - except KeyError: - includereststrokes = False - - if 'startdate' in request.session: - startdate = iso8601.parse_date(request.session['startdate']) - - - if 'enddate' in request.session: - enddate = iso8601.parse_date(request.session['enddate']) - - workstrokesonly = not includereststrokes - - waterboattype = mytypes.waterboattype - - - if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) - - if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) - - if enddate < startdate: - s = enddate - enddate = startdate - startdate = s - - - if request.method == 'POST': - dateform = DateRangeForm(request.POST) - if dateform.is_valid(): - startdate = dateform.cleaned_data['startdate'] - enddate = dateform.cleaned_data['enddate'] - startdatestring = startdate.strftime('%Y-%m-%d') - enddatestring = enddate.strftime('%Y-%m-%d') - request.session['startdate'] = startdatestring - request.session['enddate'] = enddatestring - optionsform = TrendFlexModalForm(request.POST) - if optionsform.is_valid(): - modality = optionsform.cleaned_data['modality'] - waterboattype = optionsform.cleaned_data['waterboattype'] - if modality == 'all': - modalities = [m[0] for m in mytypes.workouttypes] - else: - modalities = [modality] - if modality != 'water': - waterboattype = [b[0] for b in mytypes.boattypes] - - - if 'rankingonly' in optionsform.cleaned_data: - rankingonly = optionsform.cleaned_data['rankingonly'] - else: - rankingonly = False - - request.session['modalities'] = modalities - request.session['waterboattype'] = waterboattype - else: - dateform = DateRangeForm(initial={ - 'startdate':startdate, - 'enddate':enddate, - }) - - if 'modalities' in request.session: - modalities = request.session['modalities'] - if len(modalities) > 1: - modality = 'all' - else: - modality = modalities[0] - else: - modalities = [m[0] for m in mytypes.workouttypes] - modality = 'all' - - - - - negtypes = [] - for b in mytypes.boattypes: - if b[0] not in waterboattype: - negtypes.append(b[0]) - - - 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 - - negtypes = [] - for b in mytypes.boattypes: - if b[0] not in waterboattype: - negtypes.append(b[0]) - - # make sure the dates are not naive - try: - startdate = pytz.utc.localize(startdate) - except (ValueError, AttributeError): - pass - try: - enddate = pytz.utc.localize(enddate) - except (ValueError, AttributeError): - pass - - workouts = Workout.objects.filter(user=r, - startdatetime__gte=startdate, - startdatetime__lte=enddate, - workouttype__in=modalities, - ).order_by( - "-date", "-starttime" - ).exclude(boattype__in=negtypes) - # workouttypes = [w for w in workouttypes if w not in mytypes.otwtypes] - - if rankingonly: - workouts = workouts.exclude(rankingpiece=False) - - 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)) - ) - searchform = SearchForm(initial={'q':query}) - else: - searchform = SearchForm() - - form = WorkoutMultipleCompareForm() - form.fields["workouts"].queryset = workouts - - chartform = BoxPlotChoiceForm() - optionsform = TrendFlexModalForm(initial={ - 'modality':modality, - 'waterboattype':waterboattype, - 'rankingonly':rankingonly, - }) - - 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 - - - breadcrumbs = [ - { - 'url':'/rowers/analysis', - 'name':'Analysis' - }, - { - 'url':reverse(user_boxplot_select,kwargs={'userid':userid}), - 'name': 'BoxPlot Select' - }, - ] - return render(request, 'user_boxplot_select.html', - {'workouts': workouts, - 'dateform':dateform, - 'startdate':startdate, - 'enddate':enddate, - 'rower':r, - 'breadcrumbs':breadcrumbs, - 'theuser':user, - 'form':form, - 'active':'nav-analysis', - 'chartform':chartform, - 'searchform':searchform, - 'optionsform':optionsform, - 'teams':get_my_teams(request.user), - }) - -@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) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def boxplot_view_data(request,userid=0, - options={ - 'includereststrokes':False, - 'spmmin':15, - 'spmmax':55, - 'workmin':0, - 'workmax':1500, - 'ids':[], - 'userid':0, - 'plotfield':'spm', - }): - - if 'options' in request.session: - options = request.session['options'] - - try: - includereststrokes = options['includereststrokes'] - spmmin = options['spmmin'] - spmmax = options['spmmax'] - workmin = options['workmin'] - workmax = options['workmax'] - ids = options['ids'] - userid = options['userid'] - plotfield = options['plotfield'] - except KeyError: - includereststrokes = False - spmmin = 15 - spmmax = 55 - workmin = 0 - workmax = 55 - ids = [] - userid = 0 - plotfield = 'spm' - - - workstrokesonly = not includereststrokes - - if userid==0: - userid = request.user.id - - workouts = [] - - - if not ids: - return JSONResponse({ - "script":'', - "div":'No data found' - }) - - for id in ids: - try: - workouts.append(Workout.objects.get(id=id)) - except Workout.DoesNotExist: - pass - - labeldict = { - int(w.id): w.__str__() for w in workouts - } - - - datemapping = { - w.id:w.date for w in workouts - } - - - - fieldlist,fielddict = dataprep.getstatsfields() - fieldlist = [plotfield,'workoutid','spm','driveenergy', - 'workoutstate'] - - # prepare data frame - datadf,extracols = dataprep.read_cols_df_sql(ids,fieldlist) - - - - datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly) - - datadf = dataprep.filter_df(datadf,'spm',spmmin, - largerthan=True) - datadf = dataprep.filter_df(datadf,'spm',spmmax, - largerthan=False) - datadf = dataprep.filter_df(datadf,'driveenergy',workmin, - largerthan=True) - datadf = dataprep.filter_df(datadf,'driveneergy',workmax, - largerthan=False) - - datadf.dropna(axis=0,how='any',inplace=True) - - - datadf['workoutid'].replace(datemapping,inplace=True) - datadf.rename(columns={"workoutid":"date"},inplace=True) - datadf = datadf.sort_values(['date']) - - if userid == 0: - extratitle = '' - else: - u = User.objects.get(id=userid) - extratitle = ' '+u.first_name+' '+u.last_name - - - - script,div = interactive_boxchart(datadf,plotfield, - extratitle=extratitle, - spmmin=spmmin,spmmax=spmmax,workmin=workmin,workmax=workmax) - - scripta = script.split('\n')[2:-1] - script = ''.join(scripta) - - - return JSONResponse({ - "script":script, - "div":div, - }) - -@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) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def boxplot_view(request,userid=0, - options={ - 'includereststrokes':False, - 'rankingonly':False, - }): - - if 'options' in request.session: - options = request.session['options'] - else: - options = {} - - try: - includereststrokes = options['includereststrokes'] - except KeyError: - includereststrokes = False - options['includereststrokes'] = False - - try: - rankingonly = options['rankingonly'] - except KeyError: - rankingonly = False - options['rankingonly'] = False - - workstrokesonly = not includereststrokes - - if userid==0: - userid = request.user.id - - - if request.method == 'POST' and 'workouts' in request.POST: - form = WorkoutMultipleCompareForm(request.POST) - chartform = BoxPlotChoiceForm(request.POST) - if form.is_valid() and chartform.is_valid(): - cd = form.cleaned_data - workouts = cd['workouts'] - plotfield = chartform.cleaned_data['yparam'] - includereststrokes = chartform.cleaned_data['includereststrokes'] - request.session['includereststrokes'] = includereststrokes - workstrokesonly = not includereststrokes - - spmmin = chartform.cleaned_data['spmmin'] - spmmax = chartform.cleaned_data['spmmax'] - workmin = chartform.cleaned_data['workmin'] - workmax = chartform.cleaned_data['workmax'] - - ids = [int(w.id) for w in workouts] - request.session['ids'] = ids - - else: - url = reverse(user_boxplot_select,kwargs={'userid':userid}) - return HttpResponseRedirect(url) - elif request.method == 'POST' and 'ids' in request.session: - chartform = BoxPlotChoiceForm(request.POST) - if chartform.is_valid(): - plotfield = chartform.cleaned_data['yparam'] - includereststrokes = chartform.cleaned_data['includereststrokes'] - spmmin = chartform.cleaned_data['spmmin'] - spmmax = chartform.cleaned_data['spmmax'] - workmin = chartform.cleaned_data['workmin'] - workmax = chartform.cleaned_data['workmax'] - request.session['includereststrokes'] = includereststrokes - workstrokesonly = not includereststrokes - ids = request.session['ids'] - request.session['ids'] = ids - - - else: - url = reverse(user_boxplot_select,kwargs={'userid':userid}) - return HttpResponseRedirect(url) - else: - url = reverse(user_boxplot_select,kwargs={'userid':userid}) - return HttpResponseRedirect(url) - - div = get_call() - - - options['spmmin'] = spmmin - options['spmmax'] = spmmax - options['workmin'] = workmin - options['workmax'] = workmax - options['ids'] = ids - options['userid'] = userid - options['plotfield'] = plotfield - options['rankingonly'] = rankingonly - - - request.session['options'] = options - - r = getrequestrower(request,userid=userid) - breadcrumbs = [ - { - 'url':'/rowers/Analysis', - 'name':'Analysis' - }, - { - 'url':reverse(user_boxplot_select,kwargs={'userid':userid}), - 'name': 'BoxPlot Select' - }, - { - 'url':reverse(boxplot_view,kwargs={'userid':userid}), - 'name': 'BoxPlot Select' - }, - ] - - return render(request,'boxplot.html', - {'interactiveplot':'', - 'the_div':div, - 'rower':r, - 'breadcrumbs':breadcrumbs, - 'active':'nav-analysis', - 'chartform':chartform, - 'userid':userid, - 'teams':get_my_teams(request.user), - }) - - -# Cumulative stats page -@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) -@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) -def cumstats(request,userid=0, - startdate=timezone.now()-datetime.timedelta(days=30), - enddate=timezone.now(), - deltadays=-1, - startdatestring="", - enddatestring="", - options={ - 'includereststrokes':False, - 'workouttypes':['rower','dynamic','slides'], - 'waterboattype':mytypes.waterboattype, - 'rankingonly':False, - }): - - r = getrequestrower(request,userid=userid) - theuser = r.user - - if 'waterboattype' in request.session: - waterboattype = request.session['waterboattype'] - else: - waterboattype = mytypes.waterboattype - - - if 'rankingonly' in request.session: - rankingonly = request.session['rankingonly'] - else: - rankingonly = False - - if 'modalities' in request.session: - modalities = request.session['modalities'] - if len(modalities) > 1: - modality = 'all' - else: - modality = modalities[0] - else: - modalities = [m[0] for m in mytypes.workouttypes] - modality = 'all' - - - try: - rankingonly = options['rankingonly'] - except KeyError: - rankingonly = False - - try: - includereststrokes = options['includereststrokes'] - except KeyError: - includereststrokes = False - - - workstrokesonly = not includereststrokes - - waterboattype = mytypes.waterboattype - - - if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) - - if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) - - if enddate < startdate: - s = enddate - enddate = startdate - startdate = s - - - # get all indoor rows of in date range - - # process form - if request.method == 'POST': - form = DateRangeForm(request.POST) - modalityform = TrendFlexModalForm(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 - startdatestring = startdate.strftime('%Y-%m-%d') - enddatestring = enddate.strftime('%Y-%m-%d') - if modalityform.is_valid(): - modality = modalityform.cleaned_data['modality'] - waterboattype = modalityform.cleaned_data['waterboattype'] - rankingonly = modalityform.cleaned_data['rankingonly'] - if modality == 'all': - modalities = [m[0] for m in mytypes.workouttypes] - else: - modalities = [modality] - - if modality != 'water': - waterboattype = [b[0] for b in mytypes.boattypes] - - - request.session['modalities'] = modalities - request.session['waterboattype'] = waterboattype - request.session['rankingonly'] = rankingonly - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - else: - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - includereststrokes = False - - workstrokesonly = not includereststrokes - modalityform = TrendFlexModalForm( - initial={ - 'modality':modality, - 'waterboattype':waterboattype, - 'rankingonly':rankingonly, - } - ) - - negtypes = [] - for b in mytypes.boattypes: - if b[0] not in waterboattype: - negtypes.append(b[0]) - - - - script = '' - div = get_call() - js_resources = '' - css_resources = '' - - options = { - 'modality': modality, - 'userid': theuser.id, - 'waterboattype':waterboattype, - 'startdatestring':startdatestring, - 'enddatestring':enddatestring, - 'rankingonly':rankingonly, - 'includereststrokes':includereststrokes, - } - - - request.session['options'] = options - - - if modality == 'all': - modalities = [m[0] for m in mytypes.workouttypes] - else: - modalities = [modality] - - try: - startdate = iso8601.parse_date(startdatestring) - except ParseError: - startdate = timezone.now()-datetime.timedelta(days=7) - - try: - enddate = iso8601.parse_date(enddatestring) - except ParseError: - enddate = timezone.now() - - - if enddate < startdate: - s = enddate - enddate = startdate - startdate = s - - promember=0 - if theuser == 0: - theuser = request.user.id - - if not request.user.is_anonymous: - r = getrower(request.user) - result = request.user.is_authenticated and ispromember(request.user) - if result: - promember=1 - - r2 = getrower(theuser) - - if rankingonly: - rankingpiece = [True,] - else: - rankingpiece = [True,False] - - allworkouts = Workout.objects.filter( - user=r2, - workouttype__in=modalities, - boattype__in=waterboattype, - startdatetime__gte=startdate, - startdatetime__lte=enddate, - rankingpiece__in=rankingpiece - ).order_by("-date", "-starttime") - - ids = [int(workout.id) for workout in allworkouts] - - datemapping = { - w.id:w.date for w in allworkouts - } - - - - fieldlist,fielddict = dataprep.getstatsfields() - - # prepare data frame - datadf,extracols = dataprep.read_cols_df_sql(ids,fieldlist) - - datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly) - try: - datadf['pace'] = datadf['pace']/1000. - except KeyError: - pass - - request.session['rowerid'] = r.id - - if datadf.empty: - stats = {} - cordict = {} - - response = render(request, - 'cumstats.html', - { - 'stats':stats, - 'teams':get_my_teams(request.user), - 'options':options, - 'active':'nav-analysis', - 'rower':r, - 'id':theuser, - 'theuser':theuser, - 'startdate':startdate, - 'enddate':enddate, - 'form':form, - 'optionsform':modalityform, - 'cordict':cordict, - }) - - request.session['options'] = options - - return response - - - - # Create stats - stats = {} - try: - fielddict.pop('pace') - except KeyError: - pass - - for field,verbosename in fielddict.items(): - thedict = { - 'mean':datadf[field].mean(), - 'min': datadf[field].min(), - 'std': datadf[field].std(), - 'max': datadf[field].max(), - 'median': datadf[field].median(), - 'firstq':datadf[field].quantile(q=0.25), - 'thirdq':datadf[field].quantile(q=0.75), - 'verbosename':verbosename, - } - stats[field] = thedict - - # Create a dict with correlation values - cor = datadf.corr(method='spearman') - cor.fillna(value=0,inplace=True) - cordict = {} - for field1,verbosename1 in fielddict.items(): - thedict = {} - for field2,verbosename2 in fielddict.items(): - try: - thedict[verbosename2] = cor.loc[field1,field2] - except KeyError: - thedict[verbosename2] = 0 - - cordict[verbosename1] = thedict - - # set options form correctly - initial = {} - initial['includereststrokes'] = includereststrokes - initial['waterboattype'] = waterboattype - initial['rankingonly'] = rankingonly - - - response = render(request, - 'cumstats.html', - { - 'stats':stats, - 'teams':get_my_teams(request.user), - 'active':'nav-analysis', - 'rower':r, - 'options':options, - 'id':theuser, - 'theuser':theuser, - 'startdate':startdate, - 'enddate':enddate, - 'form':form, - 'optionsform':modalityform, - 'cordict':cordict, - }) - - request.session['options'] = options - - return response - - def agegroupcpview(request,age,normalize=0): script,div = interactive_agegroupcpchart(age,normalized=normalize) @@ -3808,7 +1807,7 @@ def alerts_view(request,userid=0): stats = [] - for alert in alerts: + for alert in alerts: # pragma: no cover stats.append(alert_get_stats(alert)) @@ -4219,7 +2218,7 @@ def history_view(request,userid=0): ddict['id'] = wtype try: ddict['wtype'] = mytypes.workouttypes_ordered[wtype] - except KeyError: + except KeyError: # pragma: no cover ddict['wtype'] = wtype ddict['distance'] = wmeters ddict['duration'] = "{whours}:{wminutes:02d}:{wseconds:02d}".format( @@ -4330,7 +2329,7 @@ def history_view_data(request,userid=0): yaxis = request.GET.get('yaxis','duration') - if yaxis.lower() not in ['duration','rscore','trimp']: + if yaxis.lower() not in ['duration','rscore','trimp']: # pragma: no cover yaxis = 'duration' g_workouts = Workout.objects.filter( @@ -4368,9 +2367,9 @@ def history_view_data(request,userid=0): a_workouts = g_workouts.filter(workouttype=wtype) wmeters, whours, wminutes,wseconds = get_totals(a_workouts) ddict = {} - try: + try: # pragma: no cover ddict['wtype'] = mytypes.workouttypes_ordered[wtype] - except KeyError: + except KeyError: # pragma: no cover ddict['wtype'] = wtype ddict['id'] = wtype @@ -4382,7 +2381,7 @@ def history_view_data(request,userid=0): ddf = getsmallrowdata_db(columns,ids=[w.id for w in a_workouts]) try: ddf['deltat'] = ddf['time'].diff().clip(lower=0) - except KeyError: + except KeyError: # pragma: no cover pass @@ -4393,7 +2392,7 @@ def history_view_data(request,userid=0): ddict['hrmean'] = int(wavg(ddf,'hr','deltat')) try: ddict['hrmax'] = ddf['hr'].max().astype(int) - except (ValueError, AttributeError): + except (ValueError, AttributeError): # pragma: no cover ddict['hrmax'] = 0 ddict['powermean'] = int(wavg(ddf,'power','deltat')) @@ -4417,7 +2416,7 @@ def history_view_data(request,userid=0): try: totalsdict['hrmean'] = int(wavg(df,'hr','deltat')) totalsdict['hrmax'] = df['hr'].max().astype(int) - except KeyError: + except KeyError: # pragma: no cover totalsdict['hrmean'] = 0 totalsdict['hrmax'] = 0