diff --git a/rowers/dataprep.py b/rowers/dataprep.py index ef153533..164e50b9 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -2564,9 +2564,11 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True, if id != 0: data['workoutid'] = id data.fillna(0,inplace=True) - data = data.astype( - dtype=dtypes, - ) + for k, v in dtypes.items(): + try: + data[k] = data[k].astype(v) + except KeyError: + pass filename = 'media/strokedata_{id}.parquet.gz'.format(id=id) diff --git a/rowers/dataprepnodjango.py b/rowers/dataprepnodjango.py index cdf2580a..bdd1f162 100644 --- a/rowers/dataprepnodjango.py +++ b/rowers/dataprepnodjango.py @@ -1254,7 +1254,13 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True, # write data if id given if id != 0: data['workoutid'] = id - data = data.astype(dtype=dtypes) + data.fillna(0,inplace=True) + for k, v in dtypes.items(): + try: + data[k] = data[k].astype(v) + except KeyError: + pass + filename = 'media/strokedata_{id}.parquet.gz'.format(id=id) df = dd.from_pandas(data,npartitions=1) df.to_parquet(filename,engine='fastparquet',compression='GZIP') diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 9cb21f11..d76f3a57 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -48,7 +48,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0): options = request.session['options'] else: options=defaultoptions - + options['userid'] = userid try: workouttypes = options['workouttypes'] @@ -62,13 +62,13 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0): modalities = [m[0] for m in mytypes.workouttypes_ordered.items()] modality = 'all' - - + + try: rankingonly = options['rankingonly'] except KeyError: rankingonly = False - + try: includereststrokes = options['includereststrokes'] except KeyError: @@ -78,7 +78,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0): startdate = iso8601.parse_date(request.session['startdate']) else: startdate=timezone.now()-datetime.timedelta(days=42) - + if function not in [c[0] for c in analysischoices]: function = 'boxplot' @@ -105,7 +105,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0): if optionsform.is_valid(): for key, value in optionsform.cleaned_data.items(): options[key] = value - + modality = optionsform.cleaned_data['modality'] waterboattype = optionsform.cleaned_data['waterboattype'] if modality == 'all': @@ -120,7 +120,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0): rankingonly = optionsform.cleaned_data['rankingonly'] else: rankingonly = False - + options['modalities'] = modalities options['waterboattype'] = waterboattype @@ -128,8 +128,8 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0): if chartform.is_valid(): for key, value in chartform.cleaned_data.items(): options[key] = value - - + + form = WorkoutMultipleCompareForm(request.POST) if form.is_valid(): cd = form.cleaned_data @@ -192,10 +192,10 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0): "-date", "-starttime" ).exclude(boattype__in=negtypes) - + if rankingonly: workouts = workouts.exclude(rankingpiece=False) - + query = request.GET.get('q') if query: query_list = query.split() @@ -215,7 +215,7 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0): selectedworkouts = Workout.objects.none() else: selectedworkouts = Workout.objects.filter(id__in=ids) - + form.fields["workouts"].queryset = workouts | selectedworkouts optionsform = AnalysisOptionsForm(initial={ @@ -223,9 +223,9 @@ def analysis_new(request,userid=0,function='boxplot',teamid=0): 'waterboattype':waterboattype, 'rankingonly':rankingonly, }) - - + + startdatestring = startdate.strftime('%Y-%m-%d') enddatestring = enddate.strftime('%Y-%m-%d') request.session['startdate'] = startdatestring @@ -275,16 +275,16 @@ def trendflexdata(workouts, options,userid=0): ploterrorbars = options['ploterrorbars'] ids = options['ids'] workstrokesonly = not includereststrokes - + 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) @@ -335,9 +335,9 @@ def trendflexdata(workouts, options,userid=0): ) groups = datadf.groupby(pd.cut(datadf['days ago'], bins, labels=False)) - - xvalues = groups.mean()[xparam] + + xvalues = groups.mean()[xparam] yvalues = groups.mean()[yparam] xerror = groups.std()[xparam] yerror = groups.std()[yparam] @@ -363,7 +363,7 @@ def trendflexdata(workouts, options,userid=0): return HttpResponseRedirect(url) else: groupsize = 30.*np.sqrt(groupsize/float(groupsize.max())) - + df = pd.DataFrame({ xparam:xvalues, yparam:yvalues, @@ -377,14 +377,14 @@ def trendflexdata(workouts, options,userid=0): 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: df['groupval'] = groups.mean()[groupby].fillna(value=0) @@ -393,7 +393,7 @@ def trendflexdata(workouts, options,userid=0): except KeyError: messages.error(request,'Data selection error') url = reverse(user_multiflex_select) - return HttpResponseRedirect(url) + return HttpResponseRedirect(url) else: try: dates = groups.min()[groupby] @@ -405,16 +405,16 @@ def trendflexdata(workouts, options,userid=0): 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) @@ -425,7 +425,7 @@ def trendflexdata(workouts, options,userid=0): clegendy = df.index.min()+clegendx*(df.index.max()-df.index.min()) - + colorlegend = zip(range(6),clegendy,legcolors) @@ -434,9 +434,9 @@ def trendflexdata(workouts, options,userid=0): else: u = User.objects.get(id=userid) extratitle = ' '+u.first_name+' '+u.last_name - - + + script,div = interactive_multiflex(df,xparam,yparam, groupby, extratitle=extratitle, @@ -445,7 +445,7 @@ def trendflexdata(workouts, options,userid=0): colorlegend=colorlegend, spmmin=spmmin,spmmax=spmmax, workmin=workmin,workmax=workmax) - + scripta= script.split('\n')[2:-1] script = ''.join(scripta) @@ -471,9 +471,9 @@ def flexalldata(workouts, options): scripta = script.split('\n')[2:-1] script = ''.join(scripta) - + return(script,div) - + def histodata(workouts, options): includereststrokes = options['includereststrokes'] plotfield = options['plotfield'] @@ -482,13 +482,13 @@ def histodata(workouts, options): spmmax = options['spmmax'] workmin = options['workmin'] workmax = options['workmax'] - + workstrokesonly = not includereststrokes script, div = interactive_histoall(workouts,plotfield,includereststrokes, spmmin=spmmin,spmmax=spmmax,workmin=workmin,workmax=workmax) - + scripta = script.split('\n')[2:-1] script = ''.join(scripta) @@ -528,17 +528,20 @@ def statsdata(workouts, options): 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 + try: + 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 + except KeyError: + pass # Create a dict with correlation values cor = datadf.corr(method='spearman') @@ -558,7 +561,7 @@ def statsdata(workouts, options): 'stats':stats, 'cordict':cordict, } - + htmly = env.get_template('statsdiv.html') html_content = htmly.render(context) @@ -591,7 +594,7 @@ def comparisondata(workouts,options): script = ''.join(scripta) return(script,div) - + def boxplotdata(workouts,options): @@ -609,25 +612,25 @@ def boxplotdata(workouts,options): 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'] ids = [w.id for w in workouts] - + # 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, @@ -651,9 +654,9 @@ def boxplotdata(workouts,options): 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) @@ -670,7 +673,7 @@ def analysis_view_data(request,userid=0): if not request.is_ajax(): url = reverse('analysis_new') return HttpResponseRedirect(url) - + if 'options' in request.session: options = request.session['options'] else: @@ -712,14 +715,14 @@ def analysis_view_data(request,userid=0): else: script = '' div = 'Unknown analysis functions' - + return JSONResponse({ "script":script, "div":div, }) - + # Histogram for a date/time range @user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", @@ -745,13 +748,13 @@ def histo(request,theuser=0, histoparam = request.session['histoparam'] else: histoparam = 'power' - + if 'waterboattype' in request.session: waterboattype = request.session['waterboattype'] else: waterboattype = mytypes.waterboattype - + if 'rankingonly' in request.session: rankingonly = request.session['rankingonly'] else: @@ -772,7 +775,7 @@ def histo(request,theuser=0, rankingonly = options['rankingonly'] except KeyError: rankingonly = False - + try: includereststrokes = options['includereststrokes'] except KeyError: @@ -795,9 +798,9 @@ def histo(request,theuser=0, enddate = startdate startdate = s - + # get all indoor rows of in date range - + # process form if request.method == 'POST': form = DateRangeForm(request.POST) @@ -824,7 +827,7 @@ def histo(request,theuser=0, if modality != 'water': waterboattype = [b[0] for b in mytypes.boattypes] - + request.session['modalities'] = modalities request.session['waterboattype'] = waterboattype request.session['rankingonly'] = rankingonly @@ -869,9 +872,9 @@ def histo(request,theuser=0, js_resources = '' css_resources = '' - - - + + + options = { 'modality': modality, 'theuser': theuser.id, @@ -891,7 +894,7 @@ def histo(request,theuser=0, result = request.user.is_authenticated and ispromember(request.user) if result: promember = 1 - + request.session['options'] = options @@ -945,8 +948,8 @@ def cum_flex_data( if 'options' in request.session: options = request.session['options'] - - modality = keyvalue_get_default('modality',options,def_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) @@ -963,7 +966,7 @@ def cum_flex_data( modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] - + try: startdate = iso8601.parse_date(startdatestring) except ParseError: @@ -1003,7 +1006,7 @@ def cum_flex_data( startdatetime__gte=startdate, startdatetime__lte=enddate, rankingpiece__in=rankingpiece) - + if allworkouts: res = interactive_cum_flex_chart2(allworkouts,xparam=xparam, yparam1=yparam1, @@ -1019,7 +1022,7 @@ def cum_flex_data( scripta = script.split('\n')[2:-1] script = ''.join(scripta) - + data = { "script":script, "div":div, @@ -1045,11 +1048,11 @@ def histo_data( def_options = options - + if 'options' in request.session: options = request.session['options'] - modality = keyvalue_get_default('modality',options,def_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) @@ -1063,7 +1066,7 @@ def histo_data( modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] - + try: startdate = iso8601.parse_date(startdatestring) except ParseError: @@ -1096,14 +1099,14 @@ def histo_data( 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] @@ -1114,7 +1117,7 @@ def histo_data( scripta = script.split('\n')[2:-1] script = ''.join(scripta) - + data = { "script":script, "div":div, @@ -1145,13 +1148,13 @@ def cum_flex(request,theuser=0, r = getrequestrower(request,userid=theuser) 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: @@ -1172,7 +1175,7 @@ def cum_flex(request,theuser=0, rankingonly = options['rankingonly'] except KeyError: rankingonly = False - + try: includereststrokes = options['includereststrokes'] except KeyError: @@ -1195,9 +1198,9 @@ def cum_flex(request,theuser=0, enddate = startdate startdate = s - + # get all indoor rows of in date range - + # process form if request.method == 'POST': form = DateRangeForm(request.POST) @@ -1224,7 +1227,7 @@ def cum_flex(request,theuser=0, if modality != 'water': waterboattype = [b[0] for b in mytypes.boattypes] - + request.session['modalities'] = modalities request.session['waterboattype'] = waterboattype request.session['rankingonly'] = rankingonly @@ -1270,9 +1273,9 @@ def cum_flex(request,theuser=0, js_resources = '' css_resources = '' - - - + + + options = { 'xparam': xparam, 'yparam1': yparam1, @@ -1294,11 +1297,11 @@ def cum_flex(request,theuser=0, 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, @@ -1333,7 +1336,7 @@ def fitnessmetric_view(request,id=0,mode='rower', startdate=timezone.now()-timezone.timedelta(days=365), enddate=timezone.now()): - + therower = getrequestrower(request,userid=id) theuser = therower.user @@ -1368,7 +1371,7 @@ def fitnessmetric_view(request,id=0,mode='rower', 'name': 'Power Progress' } ] - + return render(request,'fitnessmetric.html', { @@ -1380,7 +1383,7 @@ def fitnessmetric_view(request,id=0,mode='rower', 'mode':mode, 'form':form, }) - + # Show ranking distances including predicted paces @login_required() @@ -1420,13 +1423,13 @@ def rankings_view(request,theuser=0, )) else: worldclasspower = None - + 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) @@ -1471,7 +1474,7 @@ def rankings_view(request,theuser=0, allergworkouts = [] r=0 - + try: uu = User.objects.get(id=theuser) except User.DoesNotExist: @@ -1491,7 +1494,7 @@ def rankings_view(request,theuser=0, rankingdurations.sort() for rankingdistance in rankingdistances: - + workouts = Workout.objects.filter( user=r,distance=rankingdistance, workouttype__in=['rower','dynamic','slides'], @@ -1507,11 +1510,11 @@ def rankings_view(request,theuser=0, 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', @@ -1527,7 +1530,7 @@ def rankings_view(request,theuser=0, 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) @@ -1599,24 +1602,24 @@ def rankings_view(request,theuser=0, if pwr2 <= 0: pwr2 = 50. - + velo2 = (pwr2/2.8)**(1./3.) if np.isnan(velo2) or velo2 <= 0: velo2 = 1.0 - + t2 = rankingdistance/velo2 - + pwr3 = p1[0]/(1+t2/p1[2]) pwr3 += p1[1]/(1+t2/p1[3]) if pwr3 <= 0: pwr3 = 50. - + velo3 = (pwr3/2.8)**(1./3.) if np.isnan(velo3) or velo3 <= 0: velo3 = 1.0 - + t3 = rankingdistance/velo3 p3 = 500./velo3 @@ -1664,7 +1667,7 @@ def rankings_view(request,theuser=0, if np.isnan(velo) or velo <=0: velo = 1.0 - + d = t*velo p = 500./velo a = {'distance':int(d), @@ -1701,7 +1704,7 @@ def ajax_agegrouprecords(request, sex='female', weightcategory='hwt', userid=0): - + wcdurations = [] wcpower = [] durations = [1,4,30,60] @@ -1717,14 +1720,14 @@ def ajax_agegrouprecords(request, ) jsondf = df.to_json() - + job = myqueue(queue, handle_getagegrouprecords, jsondf,distances,durations,age,sex,weightcategory, ) - - + + return JSONResponse( { 'job':job.id @@ -1760,13 +1763,13 @@ def rankings_view2(request,theuser=0, else: lastupdated = "01-01-1900" - + promember=0 if not request.user.is_anonymous: r = getrower(request.user) wcdurations = [] wcpower = [] - + lastupdated = "01-01-1900" userid = 0 if 'options' in request.session: @@ -1784,7 +1787,7 @@ def rankings_view2(request,theuser=0, else: options = {} - + lastupdatedtime = arrow.get(lastupdated).timestamp current_time = arrow.utcnow().timestamp @@ -1798,9 +1801,9 @@ def rankings_view2(request,theuser=0, recalc = False options['userid'] = theuser - + if r.birthdate: - age = calculate_age(r.birthdate) + age = calculate_age(r.birthdate) else: worldclasspower = None age = 0 @@ -1828,13 +1831,13 @@ def rankings_view2(request,theuser=0, 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) @@ -1879,7 +1882,7 @@ def rankings_view2(request,theuser=0, allergworkouts = [] r=0 - + try: uu = User.objects.get(id=theuser) except User.DoesNotExist: @@ -1902,7 +1905,7 @@ def rankings_view2(request,theuser=0, rankingdurations.sort() for rankingdistance in rankingdistances: - + workouts = Workout.objects.filter( user=r,distance=rankingdistance, workouttype__in=['rower','dynamic','slides'], @@ -1917,11 +1920,11 @@ def rankings_view2(request,theuser=0, 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', @@ -1936,7 +1939,7 @@ def rankings_view2(request,theuser=0, 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) @@ -2014,24 +2017,24 @@ def rankings_view2(request,theuser=0, if pwr2 <= 0: pwr2 = 50. - + velo2 = (pwr2/2.8)**(1./3.) if np.isnan(velo2) or velo2 <= 0: velo2 = 1.0 - + t2 = rankingdistance/velo2 - + pwr3 = p1[0]/(1+t2/p1[2]) pwr3 += p1[1]/(1+t2/p1[3]) if pwr3 <= 0: pwr3 = 50. - + velo3 = (pwr3/2.8)**(1./3.) if np.isnan(velo3) or velo3 <= 0: velo3 = 1.0 - + t3 = rankingdistance/velo3 p3 = 500./velo3 @@ -2082,7 +2085,7 @@ def rankings_view2(request,theuser=0, if np.isnan(velo) or velo <=0: velo = 1.0 - + d = t*velo p = 500./velo a = {'distance':int(d), @@ -2107,7 +2110,7 @@ def rankings_view2(request,theuser=0, ) jsondf = df.to_json() - + job = myqueue(queue, handle_getagegrouprecords, jsondf,distances,durations,age,r.sex,r.weightcategory) @@ -2116,7 +2119,7 @@ def rankings_view2(request,theuser=0, except KeyError: request.session['async_tasks'] = [(job.id,'agegrouprecords')] - + messages.error(request,message) return render(request, 'rankings.html', @@ -2188,7 +2191,7 @@ def otwrankings_view(request,theuser=0, promember=1 # get all OTW rows in date range - + # process form if request.method == 'POST': dateform = DateRangeForm(request.POST) @@ -2236,9 +2239,9 @@ def otwrankings_view(request,theuser=0, request.session['rowerid'] = r.id except Rower.DoesNotExist: raise Http404("Rower doesn't exist") - - + + try: uu = User.objects.get(id=theuser) except User.DoesNotExist: @@ -2250,12 +2253,12 @@ def otwrankings_view(request,theuser=0, enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) #enddate = enddate+datetime.timedelta(days=1) - + thedistances = [] theworkouts = [] thesecs = [] - + theworkouts = Workout.objects.filter( user=r,rankingpiece=True, workouttype='water', @@ -2269,7 +2272,7 @@ def otwrankings_view(request,theuser=0, delta,cpvalue,avgpower = dataprep.fetchcp(r,theworkouts) runningjob = 0 - + taskstatus = get_stored_tasks_status(request) for task in taskstatus: if task['func_name'] == 'updatecpwater': @@ -2303,9 +2306,9 @@ def otwrankings_view(request,theuser=0, try: request.session['async_tasks'] += [(job.id,'updatecpwater')] except KeyError: - request.session['async_tasks'] = [(job.id,'updatecpwater')] + request.session['async_tasks'] = [(job.id,'updatecpwater')] messages.info(request,'New calculation queued. Page will reload automatically. You can check the status of your calculations here') - + powerdf = pd.DataFrame({ 'Delta':delta, 'CP':cpvalue, @@ -2313,7 +2316,7 @@ def otwrankings_view(request,theuser=0, if powerdf.empty: messages.info(request,'Your calculations are running in the background. Page will reload automatically. You can check the status of your calculations here') - + powerdf = powerdf[powerdf['CP']>0] powerdf.dropna(axis=0,inplace=True) powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True) @@ -2361,7 +2364,7 @@ def otwrankings_view(request,theuser=0, pwr = p1[0]/(1+t/p1[2]) pwr += p1[1]/(1+t/p1[3]) - + if pwr <= 0: pwr = 50. @@ -2457,7 +2460,7 @@ def otecp_toadmin_view(request,theuser=0, csvfilename = 'CP_data_user_{id}.csv'.format( id = theuser ) - + powerdf = powerdf[powerdf['CP']>0] powerdf.dropna(axis=0,inplace=True) powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True) @@ -2527,7 +2530,7 @@ def otwcp_toadmin_view(request,theuser=0, csvfilename = 'CP_data_user_{id}.csv'.format( id = theuser ) - + powerdf = powerdf[powerdf['CP']>0] powerdf.dropna(axis=0,inplace=True) powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True) @@ -2594,7 +2597,7 @@ def oterankings_view(request,theuser=0, promember=1 # get all OTW rows in date range - + # process form if request.method == 'POST': dateform = DateRangeForm(request.POST) @@ -2619,14 +2622,14 @@ def oterankings_view(request,theuser=0, trankingdistances = form.cleaned_data['trankingdistances'] except KeyError: trankingdistances = [] - + trankingdistances = [int(d) for d in trankingdistances] try: trankingdurations = form.cleaned_data['trankingdurations'] except KeyError: trankingdurations = [] - + trankingdurations = [ datetime.datetime.strptime(d,"%H:%M:%S").time() for d in trankingdurations ] @@ -2664,7 +2667,7 @@ def oterankings_view(request,theuser=0, allergworkouts = [] raise Http404("Rower doesn't exist") - + try: uu = User.objects.get(id=theuser) except User.DoesNotExist: @@ -2675,12 +2678,12 @@ def oterankings_view(request,theuser=0, startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - - + + thedistances = [] theworkouts = [] thesecs = [] - + theworkouts = Workout.objects.filter( user=r,rankingpiece=True, workouttype__in=workouttypes, @@ -2694,7 +2697,7 @@ def oterankings_view(request,theuser=0, ) runningjob = 0 - + taskstatus = get_stored_tasks_status(request) for task in taskstatus: if task['func_name'] == 'updatecp': @@ -2716,7 +2719,7 @@ def oterankings_view(request,theuser=0, messages.info(request,'Getting ready to update CP chart data') runningjob = 1 - + if not runningjob: job = dataprep.runcpupdate( r,type='rower', @@ -2737,7 +2740,7 @@ def oterankings_view(request,theuser=0, if powerdf.empty: messages.info(request,'Your calculations are running in the background. Page will reload automatically. You can check the status of your calculations here') - + powerdf = powerdf[powerdf['CP']>0] powerdf.dropna(axis=0,inplace=True) powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True) @@ -2791,7 +2794,7 @@ def oterankings_view(request,theuser=0, velo = (pwr/2.8)**(1./3.) p = 500./velo d = t*velo - + if pwr <= 0: pwr = 50. @@ -2822,17 +2825,17 @@ def oterankings_view(request,theuser=0, pace_10 = 500./velo_10 distance_10 = t_10*velo_10 - paulslope = 5. - + paulslope = 5. + for rankingdistance in trankingdistances: delta = paulslope * np.log(rankingdistance/distance_10)/np.log(2) - - + + p = pace_10+delta velo = 500./p t = rankingdistance/velo - + pwr2 = p1[0]/(1+t/p1[2]) pwr2 += p1[1]/(1+t/p1[3]) try: @@ -2842,26 +2845,26 @@ def oterankings_view(request,theuser=0, if pwr2 <= 0: pwr2 = 50. - + velo2 = (pwr2/2.8)**(1./3.) if np.isnan(velo2) or velo2 <= 0: velo2 = 1.0 - + t2 = rankingdistance/velo2 - + pwr3 = p1[0]/(1+t2/p1[2]) pwr3 += p1[1]/(1+t2/p1[3]) pwr3 *= ratio - + if pwr3 <= 0: pwr3 = 50. - + velo3 = (pwr3/2.8)**(1./3.) if np.isnan(velo3) or velo3 <= 0: velo3 = 1.0 - + t3 = rankingdistance/velo3 p3 = 500./velo3 @@ -2898,7 +2901,7 @@ def oterankings_view(request,theuser=0, }) - + # Multi Flex Chart with Grouping @user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", @@ -2914,7 +2917,7 @@ def user_multiflex_select(request, r = getrequestrower(request,userid=userid) user = r.user - + if 'options' in request.session: options = request.session['options'] else: @@ -2924,7 +2927,7 @@ def user_multiflex_select(request, palette = request.session['palette'] except KeyError: palette = 'monochrome_blue' - + try: includereststrokes = request.session['includereststrokes'] except KeyError: @@ -2934,7 +2937,7 @@ def user_multiflex_select(request, ploterrorbars = request.session['ploterrorbars'] except: ploterrorbars = False - + if 'startdate' in request.session: startdate = iso8601.parse_date(request.session['startdate']) @@ -2953,8 +2956,8 @@ def user_multiflex_select(request, rankingonly = request.session['rankingonly'] else: rankingonly = False - - + + if 'modalities' in request.session: modalities = request.session['modalities'] if len(modalities) > 1: @@ -2964,7 +2967,7 @@ def user_multiflex_select(request, else: modalities = [m[0] for m in mytypes.workouttypes] modality = 'all' - + if request.method == 'POST': dateform = DateRangeForm(request.POST) if dateform.is_valid(): @@ -2987,7 +2990,7 @@ def user_multiflex_select(request, if modality != 'water': waterboattype = [b[0] for b in mytypes.boattypes] - + request.session['modalities'] = modalities request.session['waterboattype'] = waterboattype request.session['rankingonly'] = rankingonly @@ -2997,7 +3000,7 @@ def user_multiflex_select(request, '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) @@ -3022,7 +3025,7 @@ def user_multiflex_select(request, rankingpiece = [True] else: rankingpiece = [True,False] - + workouts = Workout.objects.filter( user=r, startdatetime__gte=startdate, @@ -3074,7 +3077,7 @@ def user_multiflex_select(request, request.session['waterboattype'] = waterboattype request.session['rankingonly'] = rankingonly request.session['modalities'] = modalities - + breadcrumbs = [ { @@ -3128,7 +3131,7 @@ def multiflex_data(request,userid=0, }): def_options = options - + if 'options' in request.session: options = request.session['options'] @@ -3146,13 +3149,13 @@ def multiflex_data(request,userid=0, 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) @@ -3165,7 +3168,7 @@ def multiflex_data(request,userid=0, ids = keyvalue_get_default('ids',options, def_options) workouts = [] - + for id in ids: try: workouts.append(Workout.objects.get(id=id)) @@ -3175,12 +3178,12 @@ def multiflex_data(request,userid=0, 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) @@ -3238,9 +3241,9 @@ def multiflex_data(request,userid=0, ) groups = datadf.groupby(pd.cut(datadf['days ago'], bins, labels=False)) - - xvalues = groups.mean()[xparam] + + xvalues = groups.mean()[xparam] yvalues = groups.mean()[yparam] xerror = groups.std()[xparam] yerror = groups.std()[yparam] @@ -3266,7 +3269,7 @@ def multiflex_data(request,userid=0, return HttpResponseRedirect(url) else: groupsize = 30.*np.sqrt(groupsize/float(groupsize.max())) - + df = pd.DataFrame({ xparam:xvalues, yparam:yvalues, @@ -3280,14 +3283,14 @@ def multiflex_data(request,userid=0, 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: df['groupval'] = groups.mean()[groupby].fillna(value=0) @@ -3296,7 +3299,7 @@ def multiflex_data(request,userid=0, except KeyError: messages.error(request,'Data selection error') url = reverse(user_multiflex_select) - return HttpResponseRedirect(url) + return HttpResponseRedirect(url) else: try: dates = groups.min()[groupby] @@ -3308,16 +3311,16 @@ def multiflex_data(request,userid=0, 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) @@ -3328,7 +3331,7 @@ def multiflex_data(request,userid=0, clegendy = df.index.min()+clegendx*(df.index.max()-df.index.min()) - + colorlegend = zip(range(6),clegendy,legcolors) @@ -3337,9 +3340,9 @@ def multiflex_data(request,userid=0, else: u = User.objects.get(id=userid) extratitle = ' '+u.first_name+' '+u.last_name - - + + script,div = interactive_multiflex(df,xparam,yparam, groupby, extratitle=extratitle, @@ -3348,16 +3351,16 @@ def multiflex_data(request,userid=0, 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", @@ -3385,7 +3388,7 @@ def multiflex_view(request,userid=0, palette = request.session['palette'] except KeyError: palette = 'monochrome_blue' - + if 'startdate' in request.session: startdate = iso8601.parse_date(request.session['startdate']) @@ -3397,7 +3400,7 @@ def multiflex_view(request,userid=0, if userid==0: userid = request.user.id - + if request.method == 'POST' and 'workouts' in request.POST: form = WorkoutMultipleCompareForm(request.POST) chartform = MultiFlexChoiceForm(request.POST) @@ -3411,14 +3414,14 @@ def multiflex_view(request,userid=0, 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'] @@ -3447,7 +3450,7 @@ def multiflex_view(request,userid=0, binsize = 1 if groupby == 'pace': binsize *= 1000. - + spmmin = chartform.cleaned_data['spmmin'] spmmax = chartform.cleaned_data['spmmax'] workmin = chartform.cleaned_data['workmin'] @@ -3465,7 +3468,7 @@ def multiflex_view(request,userid=0, } ) return HttpResponseRedirect(url) - + # workouts = [Workout.objects.get(id=id) for id in ids] @@ -3495,7 +3498,7 @@ def multiflex_view(request,userid=0, request.session['options'] = options r = getrequestrower(request,userid=userid) - + breadcrumbs = [ { 'url':'/rowers/analysis', @@ -3510,7 +3513,7 @@ def multiflex_view(request,userid=0, 'name': 'Trend Flex Chart' } ] - + return render(request,'multiflex.html', {'interactiveplot':'', @@ -3547,10 +3550,10 @@ def user_boxplot_select(request, r = getrequestrower(request,userid=userid) user = r.user userid = user.id - + if 'options' in request.session: options = request.session['options'] - + try: workouttypes = options['workouttypes'] @@ -3561,7 +3564,7 @@ def user_boxplot_select(request, rankingonly = options['rankingonly'] except KeyError: rankingonly = False - + try: includereststrokes = options['includereststrokes'] except KeyError: @@ -3616,7 +3619,7 @@ def user_boxplot_select(request, rankingonly = optionsform.cleaned_data['rankingonly'] else: rankingonly = False - + request.session['modalities'] = modalities request.session['waterboattype'] = waterboattype else: @@ -3675,7 +3678,7 @@ def user_boxplot_select(request, if rankingonly: workouts = workouts.exclude(rankingpiece=False) - + query = request.GET.get('q') if query: query_list = query.split() @@ -3698,7 +3701,7 @@ def user_boxplot_select(request, 'waterboattype':waterboattype, 'rankingonly':rankingonly, }) - + messages.info(request,successmessage) messages.error(request,message) @@ -3771,7 +3774,7 @@ def boxplot_view_data(request,userid=0, userid = 0 plotfield = 'spm' - + workstrokesonly = not includereststrokes if userid==0: @@ -3791,27 +3794,27 @@ def boxplot_view_data(request,userid=0, 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, @@ -3835,22 +3838,22 @@ def boxplot_view_data(request,userid=0, 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", redirect_field_name=None) @@ -3876,13 +3879,13 @@ def boxplot_view(request,userid=0, 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) @@ -3969,7 +3972,7 @@ def boxplot_view(request,userid=0, '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",redirect_field_name=None) def cumstats(request,theuser=0, @@ -3987,13 +3990,13 @@ def cumstats(request,theuser=0, r = getrequestrower(request,userid=theuser) 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: @@ -4014,7 +4017,7 @@ def cumstats(request,theuser=0, rankingonly = options['rankingonly'] except KeyError: rankingonly = False - + try: includereststrokes = options['includereststrokes'] except KeyError: @@ -4037,9 +4040,9 @@ def cumstats(request,theuser=0, enddate = startdate startdate = s - + # get all indoor rows of in date range - + # process form if request.method == 'POST': form = DateRangeForm(request.POST) @@ -4065,7 +4068,7 @@ def cumstats(request,theuser=0, if modality != 'water': waterboattype = [b[0] for b in mytypes.boattypes] - + request.session['modalities'] = modalities request.session['waterboattype'] = waterboattype request.session['rankingonly'] = rankingonly @@ -4100,7 +4103,7 @@ def cumstats(request,theuser=0, div = get_call() js_resources = '' css_resources = '' - + options = { 'modality': modality, 'theuser': theuser.id, @@ -4111,7 +4114,7 @@ def cumstats(request,theuser=0, 'includereststrokes':includereststrokes, } - + request.session['options'] = options @@ -4119,7 +4122,7 @@ def cumstats(request,theuser=0, modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] - + try: startdate = iso8601.parse_date(startdatestring) except ParseError: @@ -4152,7 +4155,7 @@ def cumstats(request,theuser=0, rankingpiece = [True,] else: rankingpiece = [True,False] - + allworkouts = Workout.objects.filter( user=r2, workouttype__in=modalities, @@ -4168,21 +4171,21 @@ def cumstats(request,theuser=0, 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) request.session['rowerid'] = r.id - + if datadf.empty: stats = {} cordict = {} - + response = render(request, 'cumstats.html', { @@ -4201,7 +4204,7 @@ def cumstats(request,theuser=0, }) request.session['options'] = options - + return response @@ -4246,7 +4249,7 @@ def cumstats(request,theuser=0, initial['waterboattype'] = waterboattype initial['rankingonly'] = rankingonly - + response = render(request, 'cumstats.html', { @@ -4305,12 +4308,12 @@ def agegrouprecordview(request,sex='male',weightcategory='hwt', ).values() ) ) - + script,div = interactive_agegroup_plot(df,sex=sex,distance=distance, duration=duration, weightcategory=weightcategory) - + return render(request, 'agegroupchart.html', { 'interactiveplot':script, @@ -4328,11 +4331,11 @@ def alerts_view(request,userid=0): alerts = Alert.objects.filter(rower=r).order_by('next_run') stats = [] - + for alert in alerts: stats.append(alert_get_stats(alert)) - + breadcrumbs = [ { 'url':'/rowers/analysis', @@ -4401,13 +4404,13 @@ def alert_create_view(request,userid=0): if result: messages.info(request,message) - + url = reverse('alert_edit_view',kwargs={'id':result}) return HttpResponseRedirect(url) else: form = AlertEditForm() measuredform = ConditionEditForm() - + breadcrumbs = [ { 'url':'/rowers/analysis', @@ -4449,7 +4452,7 @@ def alert_report_view(request,id=0,userid=0,nperiod=0): except Alert.DoesNotExist: raise Http404("This alert doesn't exist") - + if alert.manager != request.user: raise PermissionDenied('You are not allowed to edit this Alert') @@ -4488,7 +4491,7 @@ def alert_report_view(request,id=0,userid=0,nperiod=0): 'alert':alert, 'nperiod':nperiod, }) - + # alert edit view @user_passes_test(ispromember, login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", @@ -4501,7 +4504,7 @@ def alert_edit_view(request,id=0,userid=0): except Alert.DoesNotExist: raise Http404("This alert doesn't exist") - + if alert.manager != request.user: raise PermissionDenied('You are not allowed to edit this Alert') @@ -4514,7 +4517,7 @@ def alert_edit_view(request,id=0,userid=0): 'value2':m.value2, 'condition':m.condition} for m in alert.filter.all()] - + if request.method == 'POST': form = AlertEditForm(request.POST) measuredform = ConditionEditForm(request.POST) @@ -4544,7 +4547,7 @@ def alert_edit_view(request,id=0,userid=0): alert.boattype = boattype alert.name = name alert.save() - + filters = [] for filter_form in filter_formset: @@ -4588,7 +4591,7 @@ def alert_edit_view(request,id=0,userid=0): }, ] - + return render(request,'alert_edit.html', { 'breadcrumbs':breadcrumbs, diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 1c108ad9..e152acf1 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -2796,18 +2796,21 @@ def workout_stats_view(request,id=0,message="",successmessage=""): pass for field,verbosename in fielddict.items(): - thedict = { - 'mean':datadf[field].mean(), - 'wmean': wavg(datadf, field, 'deltat'), - '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 + try: + thedict = { + 'mean':datadf[field].mean(), + 'wmean': wavg(datadf, field, 'deltat'), + '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 + except KeyError: + pass # Create a dict with correlation values cor = datadf.corr(method='spearman')