Merge branch 'feature/landingpage' into develop
This commit is contained in:
@@ -61,7 +61,6 @@ queuelow = django_rq.get_queue('low')
|
||||
queuehigh = django_rq.get_queue('default')
|
||||
|
||||
|
||||
|
||||
user = settings.DATABASES['default']['USER']
|
||||
password = settings.DATABASES['default']['PASSWORD']
|
||||
database_name = settings.DATABASES['default']['NAME']
|
||||
@@ -106,6 +105,7 @@ from scipy.signal import savgol_filter
|
||||
|
||||
import datetime
|
||||
|
||||
|
||||
def get_latlon(id):
|
||||
try:
|
||||
w = Workout.objects.get(id=id)
|
||||
@@ -126,6 +126,7 @@ def get_latlon(id):
|
||||
|
||||
return [pd.Series([]), pd.Series([])]
|
||||
|
||||
|
||||
def get_workouts(ids, userid):
|
||||
goodids = []
|
||||
for id in ids:
|
||||
@@ -135,6 +136,7 @@ def get_workouts(ids,userid):
|
||||
|
||||
return [Workout.objects.get(id=id) for id in goodids]
|
||||
|
||||
|
||||
def filter_df(datadf, fieldname, value, largerthan=True):
|
||||
|
||||
try:
|
||||
@@ -142,7 +144,6 @@ def filter_df(datadf,fieldname,value,largerthan=True):
|
||||
except KeyError:
|
||||
return datadf
|
||||
|
||||
|
||||
if largerthan:
|
||||
mask = datadf[fieldname] < value
|
||||
else:
|
||||
@@ -150,7 +151,6 @@ def filter_df(datadf,fieldname,value,largerthan=True):
|
||||
|
||||
datadf.loc[mask, fieldname] = np.nan
|
||||
|
||||
|
||||
return datadf
|
||||
|
||||
|
||||
@@ -185,7 +185,6 @@ def clean_df_stats(datadf,workstrokesonly=True,ignorehr=True,
|
||||
datadf = datadf.clip(lower=0)
|
||||
datadf.replace(to_replace=0, value=np.nan, inplace=True)
|
||||
|
||||
|
||||
# return from positive domain to negative
|
||||
try:
|
||||
datadf['catch'] = -datadf['catch']
|
||||
@@ -216,7 +215,6 @@ def clean_df_stats(datadf,workstrokesonly=True,ignorehr=True,
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['pace'] / 1000. > 300.
|
||||
datadf.loc[mask, 'pace'] = np.nan
|
||||
@@ -241,14 +239,12 @@ def clean_df_stats(datadf,workstrokesonly=True,ignorehr=True,
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['wash'] < 1
|
||||
datadf.loc[mask, 'wash'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
if not ignoreadvanced:
|
||||
try:
|
||||
mask = datadf['rhythm'] < 5
|
||||
@@ -256,79 +252,66 @@ def clean_df_stats(datadf,workstrokesonly=True,ignorehr=True,
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['rhythm'] > 70
|
||||
datadf.loc[mask, 'rhythm'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['power'] < 20
|
||||
datadf.loc[mask, 'power'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['drivelength'] < 0.5
|
||||
datadf.loc[mask, 'drivelength'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['forceratio'] < 0.2
|
||||
datadf.loc[mask, 'forceratio'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['forceratio'] > 1.0
|
||||
datadf.loc[mask, 'forceratio'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['drivespeed'] < 0.5
|
||||
datadf.loc[mask, 'drivespeed'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['drivespeed'] > 4
|
||||
datadf.loc[mask, 'drivespeed'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['driveenergy'] > 2000
|
||||
datadf.loc[mask, 'driveenergy'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['driveenergy'] < 100
|
||||
datadf.loc[mask, 'driveenergy'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
try:
|
||||
mask = datadf['catch'] > -30.
|
||||
datadf.loc[mask, 'catch'] = np.nan
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
workoutstateswork = [1, 4, 5, 8, 9, 6, 7]
|
||||
workoutstatesrest = [3]
|
||||
workoutstatetransition = [0, 2, 10, 11, 12, 13]
|
||||
@@ -341,6 +324,7 @@ def clean_df_stats(datadf,workstrokesonly=True,ignorehr=True,
|
||||
|
||||
return datadf
|
||||
|
||||
|
||||
def getstatsfields():
|
||||
# Get field names and remove those that are not useful in stats
|
||||
fields = StrokeData._meta.get_fields()
|
||||
@@ -385,6 +369,8 @@ def niceformat(values):
|
||||
return out
|
||||
|
||||
# A nice printable format for time delta values
|
||||
|
||||
|
||||
def strfdelta(tdelta):
|
||||
try:
|
||||
minutes, seconds = divmod(tdelta.seconds, 60)
|
||||
@@ -402,25 +388,28 @@ def strfdelta(tdelta):
|
||||
return res
|
||||
|
||||
# A nice printable format for pace values
|
||||
|
||||
|
||||
def nicepaceformat(values):
|
||||
out = []
|
||||
for v in values:
|
||||
formattedv = strfdelta(v)
|
||||
out.append(formattedv)
|
||||
|
||||
|
||||
return out
|
||||
|
||||
# Convert seconds to a Time Delta value, replacing NaN with a 5:50 pace
|
||||
|
||||
|
||||
def timedeltaconv(x):
|
||||
if np.isfinite(x) and x != 0 and x > 0 and x < 175000:
|
||||
dt = datetime.timedelta(seconds=x)
|
||||
else:
|
||||
dt = datetime.timedelta(seconds=350.)
|
||||
|
||||
|
||||
return dt
|
||||
|
||||
|
||||
def paceformatsecs(values):
|
||||
out = []
|
||||
for v in values:
|
||||
@@ -431,6 +420,8 @@ def paceformatsecs(values):
|
||||
return out
|
||||
|
||||
# Processes painsled CSV file to database
|
||||
|
||||
|
||||
def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
dosummary=True, title='Workout',
|
||||
workoutsource='unknown',
|
||||
@@ -470,7 +461,8 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
if not value:
|
||||
allchecks = 0
|
||||
if consistencychecks:
|
||||
a_messages.error(r.user,'Failed consistency check: '+key+', autocorrected')
|
||||
a_messages.error(
|
||||
r.user, 'Failed consistency check: ' + key + ', autocorrected')
|
||||
else:
|
||||
pass
|
||||
# a_messages.error(r.user,'Failed consistency check: '+key+', not corrected')
|
||||
@@ -481,7 +473,6 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
# row.repair()
|
||||
pass
|
||||
|
||||
|
||||
if row == 0:
|
||||
return (0, 'Error: CSV data file not found')
|
||||
|
||||
@@ -533,7 +524,8 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
if totaldist == 0:
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
if totaltime == 0:
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = row.df['TimeStamp (sec)'].max(
|
||||
) - row.df['TimeStamp (sec)'].min()
|
||||
try:
|
||||
totaltime = totaltime + row.df.ix[0, ' ElapsedTime (sec)']
|
||||
except KeyError:
|
||||
@@ -573,7 +565,6 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
#summary += '\n'
|
||||
#summary += row.intervalstats()
|
||||
|
||||
|
||||
#workoutstartdatetime = row.rowdatetime
|
||||
timezone_str = 'UTC'
|
||||
try:
|
||||
@@ -581,8 +572,6 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
except ValueError:
|
||||
workoutstartdatetime = row.rowdatetime
|
||||
|
||||
|
||||
|
||||
try:
|
||||
latavg = row.df[' latitude'].mean()
|
||||
lonavg = row.df[' longitude'].mean()
|
||||
@@ -608,8 +597,6 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
except KeyError:
|
||||
timezone_str = r.defaulttimezone
|
||||
|
||||
|
||||
|
||||
workoutdate = workoutstartdatetime.astimezone(
|
||||
pytz.timezone(timezone_str)
|
||||
).strftime('%Y-%m-%d')
|
||||
@@ -636,9 +623,6 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
message = "Warning: This workout probably already exists in the database"
|
||||
privacy = 'hidden'
|
||||
|
||||
|
||||
|
||||
|
||||
w = Workout(user=r, name=title, date=workoutdate,
|
||||
workouttype=workouttype,
|
||||
duration=duration, distance=totaldist,
|
||||
@@ -653,7 +637,6 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
timezone=timezone_str,
|
||||
privacy=privacy)
|
||||
|
||||
|
||||
w.save()
|
||||
|
||||
isbreakthrough = False
|
||||
@@ -668,7 +651,8 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
dfgrouped = df.groupby(['workoutid'])
|
||||
delta, cpvalues, avgpower = datautils.getcp(dfgrouped, logarr)
|
||||
|
||||
res,btvalues,res2 = utils.isbreakthrough(delta,cpvalues,r.p0,r.p1,r.p2,r.p3,r.cpratio)
|
||||
res, btvalues, res2 = utils.isbreakthrough(
|
||||
delta, cpvalues, r.p0, r.p1, r.p2, r.p3, r.cpratio)
|
||||
else:
|
||||
res = 0
|
||||
res2 = 0
|
||||
@@ -680,7 +664,8 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
|
||||
# submit email task to send email about breakthrough workout
|
||||
if isbreakthrough:
|
||||
a_messages.info(r.user,'It looks like you have a new breakthrough workout')
|
||||
a_messages.info(
|
||||
r.user, 'It looks like you have a new breakthrough workout')
|
||||
if settings.DEBUG and r.getemailnotifications:
|
||||
res = handle_sendemail_breakthrough.delay(w.id, r.user.email,
|
||||
r.user.first_name,
|
||||
@@ -730,6 +715,7 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
|
||||
return (w.id, message)
|
||||
|
||||
|
||||
def handle_nonpainsled(f2, fileformat, summary=''):
|
||||
oarlength = 2.89
|
||||
inboard = 0.88
|
||||
@@ -752,7 +738,6 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
if (fileformat == 'ergdata'):
|
||||
row = ErgDataParser(f2)
|
||||
|
||||
|
||||
# handle CoxMate
|
||||
if (fileformat == 'coxmate'):
|
||||
row = CoxMateParser(f2)
|
||||
@@ -786,7 +771,6 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# handle ErgStick
|
||||
if (fileformat == 'ergstick'):
|
||||
row = ErgStickParser(f2)
|
||||
@@ -801,7 +785,6 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
f_to_be_deleted = f2
|
||||
# should delete file
|
||||
f2 = f2[:-4] + 'o.csv'
|
||||
@@ -818,6 +801,8 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
# Create new workout from file and store it in the database
|
||||
# This routine should be used everywhere in views.py and mailprocessing.py
|
||||
# Currently there is code duplication
|
||||
|
||||
|
||||
def new_workout_from_file(r, f2,
|
||||
workouttype='rower',
|
||||
title='Workout',
|
||||
@@ -869,7 +854,6 @@ def new_workout_from_file(r,f2,
|
||||
message = "Rowsandall could not process this file. The extension is supported but the file seems corrupt. Contact info@rowsandall.com if you think this is incorrect."
|
||||
return (0, message, f2)
|
||||
|
||||
|
||||
# Some people try to upload RowPro summary logs
|
||||
if fileformat == 'rowprolog':
|
||||
os.remove(f2)
|
||||
@@ -902,8 +886,6 @@ def new_workout_from_file(r,f2,
|
||||
message = 'Something went wrong: ' + errorstring
|
||||
return (0, message, '')
|
||||
|
||||
|
||||
|
||||
dosummary = (fileformat != 'fit')
|
||||
id, message = save_workout_database(f2, r,
|
||||
workouttype=workouttype,
|
||||
@@ -916,6 +898,7 @@ def new_workout_from_file(r,f2,
|
||||
|
||||
return (id, message, f2)
|
||||
|
||||
|
||||
def split_workout(r, parent, splitsecond, splitmode):
|
||||
data, row = getrowdata_db(id=parent.id)
|
||||
latitude, longitude = get_latlon(parent.id)
|
||||
@@ -938,7 +921,6 @@ def split_workout(r,parent,splitsecond,splitmode):
|
||||
data1['time'] = data1.index
|
||||
data1.reset_index(drop=True, inplace=True)
|
||||
|
||||
|
||||
data2 = data2.sort_values(['time'])
|
||||
data2 = data2.interpolate(method='linear', axis=0, limit_direction='both',
|
||||
limit=10)
|
||||
@@ -952,7 +934,6 @@ def split_workout(r,parent,splitsecond,splitmode):
|
||||
data1['pace'] = data1['pace'] / 1000.
|
||||
data2['pace'] = data2['pace'] / 1000.
|
||||
|
||||
|
||||
data1.drop_duplicates(subset='time', inplace=True)
|
||||
data2.drop_duplicates(subset='time', inplace=True)
|
||||
|
||||
@@ -991,7 +972,6 @@ def split_workout(r,parent,splitsecond,splitmode):
|
||||
messages.append(message)
|
||||
ids.append(id)
|
||||
|
||||
|
||||
if not 'keep original' in splitmode:
|
||||
if 'keep second' in splitmode or 'keep first' in splitmode:
|
||||
parent.delete()
|
||||
@@ -1008,6 +988,8 @@ def split_workout(r,parent,splitsecond,splitmode):
|
||||
# Create new workout from data frame and store it in the database
|
||||
# This routine should be used everywhere in views.py and mailprocessing.py
|
||||
# Currently there is code duplication
|
||||
|
||||
|
||||
def new_workout_from_df(r, df,
|
||||
title='New Workout',
|
||||
parent=None,
|
||||
@@ -1042,7 +1024,6 @@ def new_workout_from_df(r,df,
|
||||
if setprivate:
|
||||
makeprivate = True
|
||||
|
||||
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
|
||||
csvfilename = 'media/df_' + timestr + '.csv'
|
||||
@@ -1075,11 +1056,9 @@ def new_workout_from_df(r,df,
|
||||
dosmooth=False,
|
||||
consistencychecks=False)
|
||||
|
||||
|
||||
return (id, message)
|
||||
|
||||
|
||||
|
||||
# Compare the data from the CSV file and the database
|
||||
# Currently only calculates number of strokes. To be expanded with
|
||||
# more elaborate testing if needed
|
||||
@@ -1111,6 +1090,8 @@ def compare_data(id):
|
||||
|
||||
# Repair data for workouts where the CSV file is lost (or the DB entries
|
||||
# don't exist)
|
||||
|
||||
|
||||
def repair_data(verbose=False):
|
||||
ws = Workout.objects.all()
|
||||
for w in ws:
|
||||
@@ -1153,6 +1134,8 @@ def repair_data(verbose=False):
|
||||
pass
|
||||
|
||||
# A wrapper around the rowingdata class, with some error catching
|
||||
|
||||
|
||||
def rdata(file, rower=rrower()):
|
||||
try:
|
||||
res = rrdata(csvfile=file, rower=rower)
|
||||
@@ -1167,6 +1150,8 @@ def rdata(file,rower=rrower()):
|
||||
return res
|
||||
|
||||
# Remove all stroke data for workout ID from database
|
||||
|
||||
|
||||
def delete_strokedata(id):
|
||||
engine = create_engine(database_url, echo=False)
|
||||
query = sa.text('DELETE FROM strokedata WHERE workoutid={id};'.format(
|
||||
@@ -1181,11 +1166,15 @@ def delete_strokedata(id):
|
||||
engine.dispose()
|
||||
|
||||
# Replace stroke data in DB with data from CSV file
|
||||
|
||||
|
||||
def update_strokedata(id, df):
|
||||
delete_strokedata(id)
|
||||
rowdata = dataprep(df, id=id, bands=True, barchart=True, otwpower=True)
|
||||
|
||||
# Test that all data are of a numerical time
|
||||
|
||||
|
||||
def testdata(time, distance, pace, spm):
|
||||
t1 = np.issubdtype(time, np.number)
|
||||
t2 = np.issubdtype(distance, np.number)
|
||||
@@ -1196,6 +1185,8 @@ def testdata(time,distance,pace,spm):
|
||||
|
||||
# Get data from DB for one workout (fetches all data). If data
|
||||
# is not in DB, read from CSV file (and create DB entry)
|
||||
|
||||
|
||||
def getrowdata_db(id=0, doclean=False, convertnewtons=True):
|
||||
data = read_df_sql(id)
|
||||
data['x_right'] = data['x_right'] / 1.0e6
|
||||
@@ -1203,7 +1194,8 @@ def getrowdata_db(id=0,doclean=False,convertnewtons=True):
|
||||
if data.empty:
|
||||
rowdata, row = getrowdata(id=id)
|
||||
if rowdata:
|
||||
data = dataprep(rowdata.df,id=id,bands=True,barchart=True,otwpower=True)
|
||||
data = dataprep(rowdata.df, id=id, bands=True,
|
||||
barchart=True, otwpower=True)
|
||||
else:
|
||||
data = pd.DataFrame() # returning empty dataframe
|
||||
else:
|
||||
@@ -1215,27 +1207,26 @@ def getrowdata_db(id=0,doclean=False,convertnewtons=True):
|
||||
if doclean:
|
||||
data = clean_df_stats(data, ignorehr=True)
|
||||
|
||||
|
||||
return data, row
|
||||
|
||||
# Fetch a subset of the data from the DB
|
||||
|
||||
|
||||
def getsmallrowdata_db(columns, ids=[], doclean=True, workstrokesonly=True):
|
||||
prepmultipledata(ids)
|
||||
data = read_cols_df_sql(ids, columns)
|
||||
|
||||
# convert newtons
|
||||
|
||||
|
||||
|
||||
if doclean:
|
||||
data = clean_df_stats(data, ignorehr=True,
|
||||
workstrokesonly=workstrokesonly)
|
||||
|
||||
|
||||
|
||||
return data
|
||||
|
||||
# Fetch both the workout and the workout stroke data (from CSV file)
|
||||
|
||||
|
||||
def getrowdata(id=0):
|
||||
|
||||
# check if valid ID exists (workout exists)
|
||||
@@ -1262,6 +1253,8 @@ def getrowdata(id=0):
|
||||
# In theory, this should never yield any work, but it's a good
|
||||
# safety net for programming errors elsewhere in the app
|
||||
# Also used heavily when I moved from CSV file only to CSV+Stroke data
|
||||
|
||||
|
||||
def prepmultipledata(ids, verbose=False):
|
||||
query = sa.text('SELECT DISTINCT workoutid FROM strokedata')
|
||||
engine = create_engine(database_url, echo=False)
|
||||
@@ -1283,11 +1276,14 @@ def prepmultipledata(ids,verbose=False):
|
||||
if verbose:
|
||||
print id
|
||||
if rowdata and len(rowdata.df):
|
||||
data = dataprep(rowdata.df,id=id,bands=True,barchart=True,otwpower=True)
|
||||
data = dataprep(rowdata.df, id=id, bands=True,
|
||||
barchart=True, otwpower=True)
|
||||
return res
|
||||
|
||||
# Read a set of columns for a set of workout ids, returns data as a
|
||||
# pandas dataframe
|
||||
|
||||
|
||||
def read_cols_df_sql(ids, columns, convertnewtons=True):
|
||||
# drop columns that are not in offical list
|
||||
# axx = [ax[0] for ax in axes]
|
||||
@@ -1321,29 +1317,33 @@ def read_cols_df_sql(ids,columns,convertnewtons=True):
|
||||
ids=tuple(ids),
|
||||
))
|
||||
|
||||
|
||||
connection = engine.raw_connection()
|
||||
df = pd.read_sql_query(query, engine)
|
||||
|
||||
df = df.fillna(value=0)
|
||||
|
||||
if 'peakforce' in columns:
|
||||
funits = ((w.id,w.forceunit) for w in Workout.objects.filter(id__in=ids))
|
||||
funits = ((w.id, w.forceunit)
|
||||
for w in Workout.objects.filter(id__in=ids))
|
||||
for id, u in funits:
|
||||
if u == 'lbs':
|
||||
mask = df['workoutid'] == id
|
||||
df.loc[mask, 'peakforce'] = df.loc[mask, 'peakforce'] * lbstoN
|
||||
if 'averageforce' in columns:
|
||||
funits = ((w.id,w.forceunit) for w in Workout.objects.filter(id__in=ids))
|
||||
funits = ((w.id, w.forceunit)
|
||||
for w in Workout.objects.filter(id__in=ids))
|
||||
for id, u in funits:
|
||||
if u == 'lbs':
|
||||
mask = df['workoutid'] == id
|
||||
df.loc[mask,'averageforce'] = df.loc[mask,'averageforce']*lbstoN
|
||||
df.loc[mask, 'averageforce'] = df.loc[mask,
|
||||
'averageforce'] * lbstoN
|
||||
|
||||
engine.dispose()
|
||||
return df
|
||||
|
||||
# Read stroke data from the DB for a Workout ID. Returns a pandas dataframe
|
||||
|
||||
|
||||
def read_df_sql(id):
|
||||
engine = create_engine(database_url, echo=False)
|
||||
|
||||
@@ -1370,6 +1370,8 @@ def read_df_sql(id):
|
||||
|
||||
# Get the necessary data from the strokedata table in the DB.
|
||||
# For the flex plot
|
||||
|
||||
|
||||
def smalldataprep(therows, xparam, yparam1, yparam2):
|
||||
df = pd.DataFrame()
|
||||
if yparam2 == 'None':
|
||||
@@ -1428,10 +1430,11 @@ def smalldataprep(therows,xparam,yparam1,yparam2):
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
|
||||
return df
|
||||
|
||||
# data fusion
|
||||
|
||||
|
||||
def datafusion(id1, id2, columns, offset):
|
||||
workout1 = Workout.objects.get(id=id1)
|
||||
workout2 = Workout.objects.get(id=id2)
|
||||
@@ -1456,7 +1459,6 @@ def datafusion(id1,id2,columns,offset):
|
||||
df1[' latitude'] = latitude
|
||||
df1[' longitude'] = longitude
|
||||
|
||||
|
||||
df2 = getsmallrowdata_db(['time'] + columns, ids=[id2], doclean=False)
|
||||
|
||||
forceunit = 'N'
|
||||
@@ -1465,13 +1467,11 @@ def datafusion(id1,id2,columns,offset):
|
||||
offsetmillisecs += offset.days * (3600 * 24 * 1000)
|
||||
df2['time'] = df2['time'] + offsetmillisecs
|
||||
|
||||
|
||||
keep1 = {c: c for c in set(df1.columns)}
|
||||
|
||||
for c in columns:
|
||||
keep1.pop(c)
|
||||
|
||||
|
||||
for c in df1.columns:
|
||||
if not c in keep1:
|
||||
df1 = df1.drop(c, 1, errors='ignore')
|
||||
@@ -1493,6 +1493,7 @@ def datafusion(id1,id2,columns,offset):
|
||||
|
||||
return df, forceunit
|
||||
|
||||
|
||||
def fix_newtons(id=0, limit=3000):
|
||||
# rowdata,row = getrowdata_db(id=id,doclean=False,convertnewtons=False)
|
||||
rowdata = getsmallrowdata_db(['peakforce'], ids=[id], doclean=False)
|
||||
@@ -1508,6 +1509,7 @@ def fix_newtons(id=0,limit=3000):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
def add_efficiency(id=0):
|
||||
rowdata, row = getrowdata_db(id=id, doclean=False, convertnewtons=False)
|
||||
power = rowdata['power']
|
||||
@@ -1524,7 +1526,8 @@ def add_efficiency(id=0):
|
||||
rowdata['workoutid'] = id
|
||||
engine = create_engine(database_url, echo=False)
|
||||
with engine.connect() as conn, conn.begin():
|
||||
rowdata.to_sql('strokedata',engine,if_exists='append',index=False)
|
||||
rowdata.to_sql('strokedata', engine,
|
||||
if_exists='append', index=False)
|
||||
conn.close()
|
||||
engine.dispose()
|
||||
return rowdata
|
||||
@@ -1533,6 +1536,8 @@ def add_efficiency(id=0):
|
||||
# it reindexes, sorts, filters, and smooths the data, then
|
||||
# saves it to the stroke_data table in the database
|
||||
# Takes a rowingdata object's DataFrame as input
|
||||
|
||||
|
||||
def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
|
||||
empower=True, inboard=0.88, forceunit='lbs'):
|
||||
if rowdatadf.empty:
|
||||
@@ -1589,7 +1594,6 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
except TypeError:
|
||||
t2 = 0 * t
|
||||
|
||||
|
||||
p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
|
||||
|
||||
try:
|
||||
@@ -1597,7 +1601,6 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
except TypeError:
|
||||
drivespeed = 0.0 * rowdatadf['TimeStamp (sec)']
|
||||
|
||||
|
||||
drivespeed = drivespeed.fillna(value=0)
|
||||
|
||||
try:
|
||||
@@ -1613,7 +1616,6 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
|
||||
distanceperstroke = 60. * velo / spm
|
||||
|
||||
|
||||
data = DataFrame(
|
||||
dict(
|
||||
time=t * 1e3,
|
||||
@@ -1682,7 +1684,6 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
except KeyError:
|
||||
peakforceangle = 0 * power
|
||||
|
||||
|
||||
if data['driveenergy'].mean() == 0:
|
||||
try:
|
||||
driveenergy = rowdatadf.ix[:, 'driveenergy']
|
||||
@@ -1691,7 +1692,6 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
else:
|
||||
driveenergy = data['driveenergy']
|
||||
|
||||
|
||||
arclength = (inboard - 0.05) * (np.radians(finish) - np.radians(catch))
|
||||
if arclength.mean() > 0:
|
||||
drivelength = arclength
|
||||
@@ -1750,7 +1750,6 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
|
||||
velo = 500. / p
|
||||
|
||||
|
||||
ergpw = 2.8 * velo**3
|
||||
efficiency = 100. * ergpw / power
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import dataprep
|
||||
import types
|
||||
import datetime
|
||||
from django.forms import formset_factory
|
||||
from utils import landingpages
|
||||
|
||||
# login form
|
||||
class LoginForm(forms.Form):
|
||||
@@ -180,6 +181,10 @@ class UploadOptionsForm(forms.Form):
|
||||
makeprivate = forms.BooleanField(initial=False,required=False,
|
||||
label='Make Workout Private')
|
||||
|
||||
landingpage = forms.ChoiceField(choices=landingpages,
|
||||
initial='workout_edit_view',
|
||||
label='Landing Page')
|
||||
|
||||
class Meta:
|
||||
fields = ['make_plot','plottype','upload_toc2','makeprivate']
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ class TeamRequest(models.Model):
|
||||
|
||||
from utils import (
|
||||
workflowleftpanel,workflowmiddlepanel,
|
||||
defaultleft,defaultmiddle
|
||||
defaultleft,defaultmiddle,landingpages
|
||||
)
|
||||
|
||||
# Extension of User with rowing specific data
|
||||
@@ -281,8 +281,10 @@ class Rower(models.Model):
|
||||
|
||||
# Site Settings
|
||||
workflowleftpanel = TemplateListField(default=defaultleft)
|
||||
|
||||
workflowmiddlepanel = TemplateListField(default=defaultmiddle)
|
||||
defaultlandingpage = models.CharField(default='workout_edit_view',
|
||||
max_length=200,
|
||||
choices=landingpages)
|
||||
|
||||
# Access tokens
|
||||
c2token = models.CharField(default='',max_length=200,blank=True,null=True)
|
||||
@@ -889,7 +891,8 @@ class AccountRowerForm(ModelForm):
|
||||
class Meta:
|
||||
model = Rower
|
||||
fields = ['weightcategory','getemailnotifications',
|
||||
'defaulttimezone','showfavoritechartnotes']
|
||||
'defaulttimezone','showfavoritechartnotes',
|
||||
'defaultlandingpage']
|
||||
|
||||
class UserForm(ModelForm):
|
||||
class Meta:
|
||||
|
||||
@@ -38,23 +38,10 @@
|
||||
You can select one static plot to be generated immediately for
|
||||
this workout. You can select to export to major fitness
|
||||
platforms automatically.
|
||||
If you check "make private", this workout will not be visible to your followers and will not show up in your teams' workouts list.
|
||||
If you check "make private", this workout will not be visible to your followers and will not show up in your teams' workouts list. With the Landing Page option, you can select to which (workout related) page you will be
|
||||
taken after a successfull upload.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Valid file types are:
|
||||
<ul>
|
||||
<li>Painsled iOS Stroke Export (CSV)</li>
|
||||
<li>Painsled desktop version Stroke Export (CSV)</li>
|
||||
<li>A TCX file with location data (lat,long) - with or without Heart Rate value, for example from RiM or CrewNerd</li>
|
||||
<li>RowPro CSV export</li>
|
||||
<li>SpeedCoach GPS and SpeedCoach GPS 2 CSV export</li>
|
||||
<li>ErgData CSV export</li>
|
||||
<li>ErgStick CSV export</li>
|
||||
<li>BoatCoach CSV export</li>
|
||||
<li>A FIT file with location data (experimental)</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -84,9 +84,9 @@
|
||||
[RANKING PIECE]
|
||||
{% endif %}
|
||||
{% if workout.name != '' %}
|
||||
<a href="/rowers/workout/{{ workout.id }}/edit">{{ workout.name }}</a> </td>
|
||||
<a href={% url rower.defaultlandingpage id=workout.id %}>{{ workout.name }}</a> </td>
|
||||
{% else %}
|
||||
<a href="/rowers/workout/{{ workout.id }}/edit">No Name</a> </td>
|
||||
<a href={% url rower.defaultlandingpage id=workout.id %}>No Name</a> </td>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if workout.name != '' %}
|
||||
|
||||
@@ -191,7 +191,8 @@ urlpatterns = [
|
||||
url(r'^workout/compare/(?P<id>\d+)/$',views.workout_comparison_list),
|
||||
url(r'^workout/compare2/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/$',views.workout_comparison_view),
|
||||
url(r'^workout/compare/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\w+.*)$',views.workout_comparison_list),
|
||||
url(r'^workout/(?P<id>\d+)/edit$',views.workout_edit_view),
|
||||
url(r'^workout/(?P<id>\d+)/edit$',views.workout_edit_view,
|
||||
name='workout_edit_view'),
|
||||
url(r'^workout/(?P<id>\d+)/navionics$',views.workout_edit_view_navionics),
|
||||
url(r'^workout/(?P<id>\d+)/map$',views.workout_map_view),
|
||||
url(r'^workout/(?P<id>\d+)/setprivate$',views.workout_setprivate_view),
|
||||
@@ -329,7 +330,8 @@ urlpatterns = [
|
||||
url(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'),
|
||||
url(r'^register$',views.rower_register_view),
|
||||
url(r'^register/thankyou/$', TemplateView.as_view(template_name='registerthankyou.html'), name='registerthankyou'),
|
||||
url(r'^workout/(?P<id>\d+)/workflow$',views.workout_workflow_view),
|
||||
url(r'^workout/(?P<id>\d+)/workflow$',views.workout_workflow_view,
|
||||
name='workout_workflow_view'),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<plottype>\w+)/$',views.workout_flexchart3_view),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<plottype>\w+.*)$',views.workout_flexchart3_view),
|
||||
url(r'^workout/(?P<id>\d+)/flexchart/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)$',views.workout_flexchart3_view),
|
||||
|
||||
@@ -5,6 +5,12 @@ import colorsys
|
||||
|
||||
lbstoN = 4.44822
|
||||
|
||||
landingpages = (
|
||||
('workout_edit_view','Edit View'),
|
||||
('workout_workflow_view','Workflow View'),
|
||||
)
|
||||
|
||||
|
||||
workflowmiddlepanel = (
|
||||
('panel_statcharts.html','Static Charts'),
|
||||
('flexthumbnails.html','Flex Charts'),
|
||||
|
||||
@@ -4454,6 +4454,7 @@ def workouts_view(request,message='',successmessage='',
|
||||
|
||||
return render(request, 'list_workouts.html',
|
||||
{'workouts': workouts,
|
||||
'rower':r,
|
||||
'dateform':dateform,
|
||||
'startdate':startdate,
|
||||
'enddate':enddate,
|
||||
@@ -7587,13 +7588,17 @@ def workout_upload_view(request,
|
||||
'make_plot':False,
|
||||
'upload_to_C2':False,
|
||||
'plottype':'timeplot',
|
||||
'landingpage':'workout_edit_view',
|
||||
},
|
||||
docformoptions={
|
||||
'workouttype':'rower',
|
||||
}):
|
||||
|
||||
r = getrower(request.user)
|
||||
|
||||
if 'uploadoptions' in request.session:
|
||||
uploadoptions = request.session['uploadoptions']
|
||||
uploadoptions['landingpage'] = r.defaultlandingpage
|
||||
else:
|
||||
request.session['uploadoptions'] = uploadoptions
|
||||
|
||||
@@ -7622,36 +7627,40 @@ def workout_upload_view(request,
|
||||
plottype = 'timeplot'
|
||||
|
||||
try:
|
||||
upload_toc2 = uploadoptions['upload_to_C2']
|
||||
landingpage = uploadoptions['landingpage']
|
||||
except KeyError:
|
||||
upload_toc2 = False
|
||||
landingpage = r.defaultlandingpage
|
||||
|
||||
try:
|
||||
upload_tostrava = uploadoptions['upload_to_Strava']
|
||||
upload_to_c2 = uploadoptions['upload_to_C2']
|
||||
except KeyError:
|
||||
upload_tostrava = False
|
||||
upload_to_c2 = False
|
||||
|
||||
try:
|
||||
upload_tost = uploadoptions['upload_to_SportTracks']
|
||||
upload_to_strava = uploadoptions['upload_to_Strava']
|
||||
except KeyError:
|
||||
upload_tost = False
|
||||
upload_to_strava = False
|
||||
|
||||
try:
|
||||
upload_tork = uploadoptions['upload_to_RunKeeper']
|
||||
upload_to_st = uploadoptions['upload_to_SportTracks']
|
||||
except KeyError:
|
||||
upload_tork = False
|
||||
upload_to_st = False
|
||||
|
||||
try:
|
||||
upload_toua = uploadoptions['upload_to_MapMyFitness']
|
||||
upload_to_rk = uploadoptions['upload_to_RunKeeper']
|
||||
except KeyError:
|
||||
upload_toua = False
|
||||
upload_to_rk = False
|
||||
|
||||
try:
|
||||
upload_totp = uploadoptions['upload_to_TrainingPeaks']
|
||||
upload_to_ua = uploadoptions['upload_to_MapMyFitness']
|
||||
except KeyError:
|
||||
upload_totp = False
|
||||
upload_to_ua = False
|
||||
|
||||
try:
|
||||
upload_to_tp = uploadoptions['upload_to_TrainingPeaks']
|
||||
except KeyError:
|
||||
upload_to_tp = False
|
||||
|
||||
r = getrower(request.user)
|
||||
if request.method == 'POST':
|
||||
form = DocumentsForm(request.POST,request.FILES)
|
||||
optionsform = UploadOptionsForm(request.POST)
|
||||
@@ -7676,6 +7685,7 @@ def workout_upload_view(request,
|
||||
upload_to_ua = optionsform.cleaned_data['upload_to_MapMyFitness']
|
||||
upload_to_tp = optionsform.cleaned_data['upload_to_TrainingPeaks']
|
||||
makeprivate = optionsform.cleaned_data['makeprivate']
|
||||
landingpage = optionsform.cleaned_data['landingpage']
|
||||
|
||||
uploadoptions = {
|
||||
'makeprivate':makeprivate,
|
||||
@@ -7687,6 +7697,7 @@ def workout_upload_view(request,
|
||||
'upload_to_RunKeeper':upload_to_rk,
|
||||
'upload_to_MapMyFitness':upload_to_ua,
|
||||
'upload_to_TrainingPeaks':upload_to_tp,
|
||||
'landingpage':r.defaultlandingpage,
|
||||
}
|
||||
|
||||
|
||||
@@ -7810,7 +7821,7 @@ def workout_upload_view(request,
|
||||
else:
|
||||
messages.error(request,message)
|
||||
|
||||
url = reverse(workout_edit_view,
|
||||
url = reverse(landingpage,
|
||||
kwargs = {
|
||||
'id':w.id,
|
||||
})
|
||||
@@ -8778,6 +8789,7 @@ def rower_edit_view(request,message=""):
|
||||
first_name = ucd['first_name']
|
||||
last_name = ucd['last_name']
|
||||
email = ucd['email']
|
||||
defaultlandingpage = cd['defaultlandingpage']
|
||||
weightcategory = cd['weightcategory']
|
||||
getemailnotifications = cd['getemailnotifications']
|
||||
defaulttimezone=cd['defaulttimezone']
|
||||
@@ -8794,6 +8806,7 @@ def rower_edit_view(request,message=""):
|
||||
r.defaulttimezone=defaulttimezone
|
||||
r.weightcategory = weightcategory
|
||||
r.getemailnotifications = getemailnotifications
|
||||
r.defaultlandingpage = defaultlandingpage
|
||||
r.save()
|
||||
form = RowerForm(instance=r)
|
||||
powerform = RowerPowerForm(instance=r)
|
||||
|
||||
Reference in New Issue
Block a user