From 766318ff40648b10ae067ac586842eb62839626d Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 8 Jun 2020 20:00:34 +0200 Subject: [PATCH 1/3] fixing ub --- rowers/datautils.py | 56 +++++++++++++++++++++++++-------------------- rowers/tasks.py | 6 ++++- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/rowers/datautils.py b/rowers/datautils.py index 283b7ed4..824a3278 100644 --- a/rowers/datautils.py +++ b/rowers/datautils.py @@ -26,7 +26,7 @@ def updatecp(delta,cpvalues,r): powerdf.dropna(axis=0,inplace=True) powerdf.sort_values(['Delta','CP'],ascending=[1,0],inplace=True) powerdf.drop_duplicates(subset='Delta',keep='first',inplace=True) - + res = cpfit(powerdf) p1 = res[0] @@ -45,7 +45,7 @@ def cpfit(powerdf): # Fit the data to thee parameter CP model fitfunc = lambda pars,x: abs(pars[0])/(1+(x/abs(pars[2]))) + abs(pars[1])/(1+(x/abs(pars[3]))) errfunc = lambda pars,x,y: fitfunc(pars,x)-y - + p1 = p0 @@ -58,7 +58,7 @@ def cpfit(powerdf): except: factor = fitfunc(p0,thesecs.mean())/theavpower.mean() p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] - + else: factor = fitfunc(p0,thesecs.mean())/theavpower.mean() p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] @@ -82,7 +82,7 @@ def cpfit(powerdf): dd = fitpoints-theavpower ddmin = dd.min() frac = abs(ddmin)/fitpoints.mean() - + ratio = fitpoints.mean()/fitpoints0.mean() return p1,fitt,fitpower,ratio @@ -90,8 +90,15 @@ def cpfit(powerdf): def getlogarr(maxt): maxlog10 = np.log10(maxt-5) logarr = np.arange(50)*maxlog10/50. - logarr = [5+int(10.**(la)) for la in logarr] - logarr = pd.Series(logarr) + res = [] + for la in logarr: + try: + v = 5+int(10.**(la)) + except ValueError: + v = 0 + res.append(v) + + logarr = pd.Series(res) logarr.drop_duplicates(keep='first',inplace=True) logarr = logarr.values @@ -111,9 +118,9 @@ def getsinglecp(df): 'time':1000*(df['TimeStamp (sec)']-df.loc[:,'TimeStamp (sec)'].iloc[0]), 'power':df[' Power (watts)'] }) - + dfnew['workoutid'] = 0 - + dfgrouped = dfnew.groupby(['workoutid']) delta,cpvalue,avgpower = getcp(dfgrouped,logarr) @@ -124,7 +131,7 @@ def getcp_new(dfgrouped,logarr): cpvalue = [] avgpower = {} - + for id, group in dfgrouped: tt = group['time'].copy() @@ -149,7 +156,7 @@ def getcp_new(dfgrouped,logarr): ww.values, newt,method='linear', rescale=True) - + tt = pd.Series(newt) ww = pd.Series(ww) @@ -178,7 +185,7 @@ def getcp_new(dfgrouped,logarr): restime = [] power = [] - + for i in np.arange(0,len(tt)+1,1): restime.append(deltat*i) cp = np.diag(F,i).max() @@ -189,19 +196,19 @@ def getcp_new(dfgrouped,logarr): restime = np.array(restime) power = np.array(power) - + #power[0] = power[1] - + cpvalues = griddata(restime,power, logarr,method='linear', fill_value=0) - + for cpv in cpvalues: cpvalue.append(cpv) for d in logarr: delta.append(d) - + df = pd.DataFrame({ 'delta':delta, 'cpvalue':cpvalue @@ -215,8 +222,8 @@ def getcp_new(dfgrouped,logarr): cpvalue = df['cpvalue'] return delta,cpvalue,avgpower - - + + def getcp(dfgrouped,logarr): delta = [] cpvalue = [] @@ -228,7 +235,7 @@ def getcp(dfgrouped,logarr): ww = group['power'].copy() # Remove data where PM is repeating final power value - # of an interval during the rest + # of an interval during the rest rolling_std = ww.rolling(window=4).std() deltas = tt.diff() @@ -240,7 +247,7 @@ def getcp(dfgrouped,logarr): tmax = tt.max() - + if tmax > 500000: newlen = int(tmax/2000.) else: @@ -255,7 +262,7 @@ def getcp(dfgrouped,logarr): tt = pd.Series(newt) ww = pd.Series(ww) - + try: avgpower[id] = int(ww.mean()) except ValueError: @@ -272,7 +279,7 @@ def getcp(dfgrouped,logarr): cpw.append(wmax) - + dt = pd.Series(dt) cpw = pd.Series(cpw) if len(dt)>2: @@ -286,12 +293,12 @@ def getcp(dfgrouped,logarr): for d in logarr: delta.append(d) - - + + delta = pd.Series(delta,name='Delta') cpvalue = pd.Series(cpvalue,name='CP') - + cpdf = pd.DataFrame({ 'delta':delta, 'cpvalue':cpvalue @@ -332,4 +339,3 @@ def getmaxwattinterval(tt,ww,i): deltat = 0 return deltat,wmax - diff --git a/rowers/tasks.py b/rowers/tasks.py index 405434d4..d9ca397a 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -30,6 +30,7 @@ import datetime import pytz import iso8601 +from json.decoder import JSONDecodeError from matplotlib.backends.backend_agg import FigureCanvas #from matplotlib.backends.backend_cairo import FigureCanvasCairo as FigureCanvas @@ -2028,7 +2029,10 @@ def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename, elif (plotnr == 2): fig1 = row.get_metersplot_erg(t,pacerange=oterange,**kwargs) elif (plotnr == 3): - t += ' - Heart Rate Distribution' + try: + t += ' - Heart Rate Distribution' + except TypeError: + t = 'Heart Rate Distribution' fig1 = row.get_piechart(t,**kwargs) elif (plotnr == 4): if haspower: From 9a9f0725ba7b4c491dc123e5fcd5a0b0dcb471f9 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 9 Jun 2020 22:46:16 +0200 Subject: [PATCH 2/3] better gps comparisons --- rowers/tasks.py | 3 ++- rowers/views/workoutviews.py | 35 ++++++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/rowers/tasks.py b/rowers/tasks.py index d9ca397a..fcd7bc62 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -381,8 +381,9 @@ def handle_check_race_course(self, except IOError: return 0 - + row.calc_dist_from_gps() rowdata = row.df + rowdata['cum_dist'] = rowdata['gps_dist_calculated'] try: s = rowdata[' latitude'] diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 955e6abe..a407d0e2 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -5913,13 +5913,34 @@ def workout_summary_edit_view(request,id,message="",successmessage="" # we are saving the results obtained from the split by power/pace interpreter elif request.method == 'POST' and "savepowerpaceform" in request.POST: - powerorpace = request.POST['powerorpace'] - value_pace = request.POST['value_pace'] - value_power = request.POST['value_power'] - value_work = request.POST['value_work'] - value_spm = request.POST['value_spm'] - activeminutesmin = request.POST['activeminutesmin'] - activeminutesmax = request.POST['activeminutesmax'] + try: + powerorpace = request.POST['powerorpace'] + except: + powerorpace = 'pace' + try: + value_pace = request.POST['value_pace'] + except: + value_pace = avpace + try: + value_power = request.POST['value_power'] + except: + value_power = int(normp) + try: + value_work = request.POST['value_work'] + except: + value_work = int(normw) + try: + value_spm = request.POST['value_spm'] + except: + value_spm = int(normspm) + try: + activeminutesmin = request.POST['activeminutesmin'] + except: + activeminutesmin = 0 + try: + activeminutesmax = request.POST['activeminutesmax'] + except: + pass try: activesecondsmin = 60.*float(activeminutesmin) activesecondsmax = 60.*float(activeminutesmax) From 132ffa856c5e2cf6dd616eae39cfdd43d03a0d23 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 10 Jun 2020 08:23:08 +0200 Subject: [PATCH 3/3] bug fix and fairer GPS comparisons --- rowers/interactiveplots.py | 14 ++++++- rowers/mytypes.py | 3 +- rowers/views/racesviews.py | 82 +++++++++++++++++++++----------------- 3 files changed, 61 insertions(+), 38 deletions(-) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index c993dd42..754c651c 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -261,6 +261,18 @@ def pretty_timedelta(secs): return '{}:{:02}:{:02}'.format(int(hours),int(minutes),int(seconds)) +def mapcolors(x): + try: + return mytypes.color_map[x] + except KeyError: + return mytypes.colors[-1] + +def maptypes(x): + try: + return mytypes.workouttypes_ordered[x] + except KeyError: + return 'Other' + def interactive_workouttype_piechart(workouts): if len(workouts) == 0: return "","Not enough workouts to make a chart" @@ -286,7 +298,7 @@ def interactive_workouttype_piechart(workouts): data = pd.DataFrame(data) - data['color'] = data['type'].apply(lambda x:mytypes.color_map[x]) + data['color'] = data['type'].apply(lambda x:mapcolors(x)) data['totaltime'] = data['value'].apply(lambda x:pretty_timedelta(x)) data['type'] = data['type'].apply(lambda x:mytypes.workouttypes_ordered[x]) diff --git a/rowers/mytypes.py b/rowers/mytypes.py index 294cb8bb..42538697 100644 --- a/rowers/mytypes.py +++ b/rowers/mytypes.py @@ -273,7 +273,8 @@ checktypes = [i[0] for i in workouttypes] from bokeh.palettes import Category10,Category20, Category20c -colors = Category10[9]+Category20[19]+Category20c[19] +#colors = Category10[9] +colors = Category10[9]+list(set(Category20[19]+Category20c[19])) color_map = {checktypes[i]:colors[i] for i in range(len(checktypes))} workoutsources = ( diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 09a3cb0e..1f6f4a33 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -1640,18 +1640,22 @@ def virtualevent_addboat_view(request,id=0): race = race).exclude(userid = r.id) for otherrecord in otherrecords: - otheruser = Rower.objects.get(id=otherrecord.userid) - othername = otheruser.user.first_name+' '+otheruser.user.last_name - registeredname = r.user.first_name+' '+r.user.last_name - if otherrecord.emailnotifications: - job = myqueue( - queue, - handle_sendemail_raceregistration, - otheruser.user.email, othername, - registeredname, - race.name, - race.id - ) + try: + otheruser = Rower.objects.get(id=otherrecord.userid) + othername = otheruser.user.first_name+' '+otheruser.user.last_name + registeredname = r.user.first_name+' '+r.user.last_name + if otherrecord.emailnotifications: + job = myqueue( + queue, + handle_sendemail_raceregistration, + otheruser.user.email, othername, + registeredname, + race.name, + race.id + ) + except Rower.DoesNotExist: + pass + followers = VirtualRaceFollower.objects.filter(race = race) @@ -1868,18 +1872,21 @@ def virtualevent_register_view(request,id=0): race = race).exclude(userid = r.id) for otherrecord in otherrecords: - otheruser = Rower.objects.get(id=otherrecord.userid) - othername = otheruser.user.first_name+' '+otheruser.user.last_name - registeredname = r.user.first_name+' '+r.user.last_name - if otherrecord.emailnotifications: - job = myqueue( - queue, - handle_sendemail_raceregistration, - otheruser.user.email, othername, - registeredname, - race.name, - race.id - ) + try: + otheruser = Rower.objects.get(id=otherrecord.userid) + othername = otheruser.user.first_name+' '+otheruser.user.last_name + registeredname = r.user.first_name+' '+r.user.last_name + if otherrecord.emailnotifications: + job = myqueue( + queue, + handle_sendemail_raceregistration, + otheruser.user.email, othername, + registeredname, + race.name, + race.id + ) + except Rower.DoesNotExist: + pass followers = VirtualRaceFollower.objects.filter(race = race) @@ -2136,18 +2143,21 @@ def indoorvirtualevent_register_view(request,id=0): race = race).exclude(userid = r.id) for otherrecord in otherrecords: - otheruser = Rower.objects.get(id=otherrecord.userid) - othername = otheruser.user.first_name+' '+otheruser.user.last_name - registeredname = r.user.first_name+' '+r.user.last_name - if otherrecord.emailnotifications: - job = myqueue( - queue, - handle_sendemail_raceregistration, - otheruser.user.email, othername, - registeredname, - race.name, - race.id - ) + try: + otheruser = Rower.objects.get(id=otherrecord.userid) + othername = otheruser.user.first_name+' '+otheruser.user.last_name + registeredname = r.user.first_name+' '+r.user.last_name + if otherrecord.emailnotifications: + job = myqueue( + queue, + handle_sendemail_raceregistration, + otheruser.user.email, othername, + registeredname, + race.name, + race.id + ) + except Rower.DoesNotExist: + pass followers = VirtualRaceFollower.objects.filter(race = race)