Merge branch 'release/v21.0.0'
This commit is contained in:
+4
-2
@@ -1,6 +1,6 @@
|
||||
from rowers.models import Alert, Condition, User, Rower, Workout
|
||||
from rowers.teams import coach_getcoachees
|
||||
from rowers.dataprep import getsmallrowdata_db, getrowdata_db
|
||||
from rowers.dataprep import getrowdata_db, read_data, remove_nulls_pl
|
||||
import datetime
|
||||
import numpy as np
|
||||
import math
|
||||
@@ -101,8 +101,10 @@ def alert_get_stats(alert, nperiod=0): # pragma: no cover
|
||||
ids = [w.id for w in workouts]
|
||||
|
||||
try:
|
||||
df = getsmallrowdata_db(columns, ids=ids, doclean=True,
|
||||
df = getsmallrowdata_pd(columns, ids=ids, doclean=True,
|
||||
workstrokesonly=workstrokesonly)
|
||||
df.dropna(axis=1,how='all',inplace=True)
|
||||
df.dropna(axis=0,how='all',inplace=True)
|
||||
except:
|
||||
return {
|
||||
'workouts': workouts.count(),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from rowers.courseutils import coursetime_paths, coursetime_first, time_in_path
|
||||
import pandas as pd
|
||||
from rowers.models import (
|
||||
Rower, Workout,
|
||||
GeoPoint, GeoPolygon, GeoCourse,
|
||||
@@ -420,62 +419,6 @@ def createcourse(
|
||||
return c
|
||||
|
||||
|
||||
def get_time_course(ws, course): # pragma: no cover
|
||||
coursetimeseconds = 0.0
|
||||
coursecompleted = False
|
||||
|
||||
w = ws[0]
|
||||
columns = ['time', ' latitude', ' longitude', 'cum_dist']
|
||||
rowdata = dataprep.getsmallrowdata_db(
|
||||
columns,
|
||||
ids=[w.id],
|
||||
doclean=False,
|
||||
workstrokesonly=False
|
||||
)
|
||||
|
||||
rowdata.rename(columns={
|
||||
' latitude': 'latitude',
|
||||
' longitude': 'longitude',
|
||||
}, inplace=True)
|
||||
|
||||
rowdata['time'] = rowdata['time']/1000.
|
||||
|
||||
rowdata.fillna(method='backfill', inplace=True)
|
||||
|
||||
rowdata['time'] = rowdata['time']-rowdata.ix[0, 'time']
|
||||
# we may want to expand the time (interpolate)
|
||||
rowdata['dt'] = rowdata['time'].apply(
|
||||
lambda x: timedelta(seconds=x)
|
||||
)
|
||||
rowdata = rowdata.resample('100ms', on='dt').mean()
|
||||
rowdata = rowdata.interpolate()
|
||||
|
||||
# create path
|
||||
polygons = GeoPolygon.objects.filter(
|
||||
course=course).order_by("order_in_course")
|
||||
paths = []
|
||||
for polygon in polygons:
|
||||
path = polygon_to_path(polygon)
|
||||
paths.append(path)
|
||||
|
||||
(
|
||||
coursetimeseconds,
|
||||
coursemeters,
|
||||
coursecompleted,
|
||||
|
||||
) = coursetime_paths(rowdata, paths)
|
||||
(
|
||||
coursetimefirst,
|
||||
coursemetersfirst,
|
||||
firstcompleted
|
||||
) = coursetime_first(
|
||||
rowdata, paths)
|
||||
|
||||
coursetimeseconds = coursetimeseconds-coursetimefirst
|
||||
coursemeters = coursemeters-coursemetersfirst
|
||||
|
||||
return coursetimeseconds, coursemeters, coursecompleted
|
||||
|
||||
|
||||
def replacecourse(course1, course2):
|
||||
ps = PlannedSession.objects.filter(course=course1)
|
||||
|
||||
+81
-105
@@ -8,6 +8,7 @@ from rowers.datautils import p0
|
||||
from scipy import optimize
|
||||
from rowers.utils import calculate_age
|
||||
import datetime
|
||||
import gzip
|
||||
from scipy.signal import savgol_filter
|
||||
from rowers.opaque import encoder
|
||||
from rowers.database import *
|
||||
@@ -27,6 +28,8 @@ from fitparse import FitFile
|
||||
import itertools
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import polars as pl
|
||||
from polars.exceptions import ColumnNotFoundError
|
||||
from zipfile import BadZipFile
|
||||
import zipfile
|
||||
import os
|
||||
@@ -73,6 +76,7 @@ import pytz
|
||||
import collections
|
||||
import pendulum
|
||||
from rowingdata import rowingdata as rrdata
|
||||
from rowingdata import rowingdata_pl as rrdata_pl
|
||||
|
||||
from rowingdata import rower as rrower
|
||||
|
||||
@@ -88,10 +92,9 @@ from rowers.dataroutines import *
|
||||
|
||||
from rowers.tasks import (
|
||||
handle_sendemail_newftp,
|
||||
handle_sendemail_unrecognized, handle_setcp,
|
||||
handle_sendemail_unrecognized,
|
||||
handle_getagegrouprecords, handle_update_wps,
|
||||
handle_request_post, handle_calctrimp,
|
||||
handle_updatecp, handle_updateergcp,
|
||||
handle_sendemail_breakthrough,
|
||||
handle_sendemail_hard,
|
||||
)
|
||||
@@ -123,6 +126,10 @@ from rq import Queue
|
||||
from rowers.datautils import rpetotss
|
||||
|
||||
def rscore_approx(row):
|
||||
if isinstance(row, pl.DataFrame):
|
||||
row = {'rscore': row['rscore'][0]}
|
||||
if isinstance(row, pl.Series):
|
||||
row = {'rscore': row['rscore'][0]}
|
||||
if row['rscore'] > 0:
|
||||
return row['rscore']
|
||||
if row['rscore'] == 0: # pragma: no cover
|
||||
@@ -215,18 +222,18 @@ def check_marker(workout):
|
||||
ids.append(w.id)
|
||||
gms.append(gmstandard)
|
||||
|
||||
df = pd.DataFrame({
|
||||
df = pl.DataFrame({
|
||||
'id': ids,
|
||||
'gms': gms,
|
||||
})
|
||||
|
||||
if df.empty: # pragma: no cover
|
||||
if df.is_empty(): # pragma: no cover
|
||||
workout.ranking = True
|
||||
workout.save()
|
||||
return workout
|
||||
|
||||
indexmax = df['gms'].idxmax()
|
||||
theid = df.loc[indexmax, 'id']
|
||||
theid = df.filter(pl.col("gms") == pl.col("gms").max())['id'][0]
|
||||
|
||||
|
||||
wmax = Workout.objects.get(id=theid)
|
||||
# gms_max = wmax.goldmedalstandard
|
||||
@@ -322,7 +329,7 @@ def workout_summary_to_df(
|
||||
goldstandarddurations.append(int(goldstandardduration))
|
||||
rankingpieces.append(w.rankingpiece)
|
||||
|
||||
df = pd.DataFrame({
|
||||
df = pl.DataFrame({
|
||||
'ID': ids,
|
||||
'date': startdatetimes,
|
||||
'name': names,
|
||||
@@ -392,7 +399,7 @@ def resample(id, r, parent, overwrite='copy'):
|
||||
|
||||
row.write_csv(parent.csvfilename, gzip=True)
|
||||
|
||||
_ = dataprep(row.df, id=parent.id, bands=True, barchart=True,
|
||||
_ = dataplep(row.df, id=parent.id, bands=True, barchart=True,
|
||||
otwpower=True, empower=True, inboard=parent.inboard)
|
||||
isbreakthrough, ishard = checkbreakthrough(parent, r)
|
||||
_ = check_marker(parent)
|
||||
@@ -414,18 +421,23 @@ def resample(id, r, parent, overwrite='copy'):
|
||||
def calculate_goldmedalstandard(rower, workout, recurrance=True):
|
||||
cpfile = 'media/cpdata_{id}.parquet.gz'.format(id=workout.id)
|
||||
try:
|
||||
df = pd.read_parquet(cpfile)
|
||||
df = pl.read_parquet(cpfile)
|
||||
except:
|
||||
df = read_data(['power'], ids=[workout.id])
|
||||
df = remove_nulls_pl(df)
|
||||
background = True
|
||||
if settings.TESTING:
|
||||
background = False
|
||||
if recurrance:
|
||||
df, delta, cpvalues = setcp(workout, background=background)
|
||||
if df.empty:
|
||||
if df.is_empty():
|
||||
return 0, 0
|
||||
else:
|
||||
return 0,0
|
||||
|
||||
if df.empty and recurrance: # pragma: no cover
|
||||
if df.is_empty() and recurrance: # pragma: no cover
|
||||
df, delta, cpvalues = setcp(workout, recurrance=False, background=True)
|
||||
if df.empty:
|
||||
if df.is_empty():
|
||||
return 0, 0
|
||||
|
||||
age = calculate_age(rower.birthdate, today=workout.date)
|
||||
@@ -453,7 +465,7 @@ def calculate_goldmedalstandard(rower, workout, recurrance=True):
|
||||
if getrecords: # pragma: no cover
|
||||
durations = [1, 4, 30, 60]
|
||||
distances = [100, 500, 1000, 2000, 5000, 6000, 10000, 21097, 42195]
|
||||
df2 = pd.DataFrame(
|
||||
df2 = pl.DataFrame(
|
||||
list(
|
||||
C2WorldClassAgePerformance.objects.filter(
|
||||
sex=rower.sex,
|
||||
@@ -461,7 +473,7 @@ def calculate_goldmedalstandard(rower, workout, recurrance=True):
|
||||
).values()
|
||||
)
|
||||
)
|
||||
jsondf = df2.to_json()
|
||||
jsondf = df2.write_json()
|
||||
_ = myqueue(queuelow, handle_getagegrouprecords,
|
||||
jsondf, distances, durations, age, rower.sex, rower.weightcategory)
|
||||
|
||||
@@ -489,9 +501,10 @@ def calculate_goldmedalstandard(rower, workout, recurrance=True):
|
||||
scores = 100.*powers/wcpowers
|
||||
|
||||
try:
|
||||
indexmax = scores.idxmax()
|
||||
delta = int(df.loc[indexmax, 'delta'])
|
||||
maxvalue = scores.max()
|
||||
df = pl.DataFrame({'times': times, 'scores': scores})
|
||||
df = df.filter(pl.col("scores") == pl.col("scores").max())
|
||||
delta = df[0, "times"]
|
||||
maxvalue = df[0, "scores"]
|
||||
except (ValueError, TypeError, KeyError): # pragma: no cover
|
||||
indexmax = 0
|
||||
delta = 0
|
||||
@@ -504,21 +517,22 @@ def calculate_goldmedalstandard(rower, workout, recurrance=True):
|
||||
def setcp(workout, background=False, recurrance=True):
|
||||
try:
|
||||
filename = 'media/cpdata_{id}.parquet.gz'.format(id=workout.id)
|
||||
df = pd.read_parquet(filename)
|
||||
df = pl.read_parquet(filename)
|
||||
|
||||
if not df.empty:
|
||||
if not df.is_empty():
|
||||
# check dts
|
||||
tarr = datautils.getlogarr(4000)
|
||||
if df['delta'][0] in tarr:
|
||||
return(df, df['delta'], df['cp'])
|
||||
except:
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
strokesdf = getsmallrowdata_db(
|
||||
strokesdf = read_data(
|
||||
['power', 'workoutid', 'time'], ids=[workout.id])
|
||||
strokesdf = remove_nulls_pl(strokesdf)
|
||||
|
||||
if strokesdf.empty:
|
||||
return pd.DataFrame({'delta': [], 'cp': []}), pd.Series(dtype='float'), pd.Series(dtype='float')
|
||||
if strokesdf.is_empty():
|
||||
return pl.DataFrame({'delta': [], 'cp': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||
|
||||
totaltime = strokesdf['time'].max()
|
||||
maxt = totaltime/1000.
|
||||
@@ -533,7 +547,7 @@ def setcp(workout, background=False, recurrance=True):
|
||||
elif os.path.exists(csvfilename+'.gz'): # pragma: no cover
|
||||
csvfile = csvfilename+'.gz'
|
||||
else: # pragma: no cover
|
||||
return pd.DataFrame({'delta': [], 'cp': []}), pd.Series(dtype='float'), pd.Series(dtype='float')
|
||||
return pl.DataFrame({'delta': [], 'cp': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||
csvfile = os.path.abspath(csvfile)
|
||||
|
||||
|
||||
@@ -547,7 +561,7 @@ def setcp(workout, background=False, recurrance=True):
|
||||
grpc.channel_ready_future(channel).result(timeout=10)
|
||||
except grpc.FutureTimeoutError: # pragma: no cover
|
||||
dologging('metrics.log','grpc channel time out in setcp')
|
||||
return pd.DataFrame({'delta': [], 'cp': []}), pd.Series(dtype='float'), pd.Series(dtype='float')
|
||||
return pl.DataFrame({'delta': [], 'cp': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||
|
||||
stub = metrics_pb2_grpc.MetricsStub(channel)
|
||||
req = metrics_pb2.CPRequest(filename = csvfile, filetype = "CSV", tarr = logarr)
|
||||
@@ -556,25 +570,29 @@ def setcp(workout, background=False, recurrance=True):
|
||||
response = stub.GetCP(req, timeout=60)
|
||||
except Exception as e:
|
||||
dologging('metrics.log', traceback.format_exc())
|
||||
return pd.DataFrame({'delta': [], 'cp': []}), pd.Series(dtype='float'), pd.Series(dtype='float')
|
||||
return pl.DataFrame({'delta': [], 'cp': []}), pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||
|
||||
delta = pd.Series(np.array(response.delta))
|
||||
cpvalues = pd.Series(np.array(response.power))
|
||||
delta = pl.Series(np.array(response.delta))
|
||||
cpvalues = pl.Series(np.array(response.power))
|
||||
powermean = response.avgpower
|
||||
|
||||
|
||||
|
||||
df = pd.DataFrame({
|
||||
df = pl.DataFrame({
|
||||
'delta': delta,
|
||||
'cp': cpvalues,
|
||||
'id': workout.id,
|
||||
})
|
||||
|
||||
df.to_parquet(filename, engine='fastparquet', compression='GZIP')
|
||||
df = df.drop_nulls()
|
||||
|
||||
with gzip.open(filename, 'w') as f:
|
||||
df.write_parquet(f)
|
||||
|
||||
|
||||
#df.to_parquet(filename, engine='fastparquet', compression='GZIP')
|
||||
|
||||
if recurrance:
|
||||
goldmedalstandard, goldmedalduration = calculate_goldmedalstandard(
|
||||
workout.user, workout)
|
||||
workout.user, workout, recurrance=False)
|
||||
workout.goldmedalstandard = goldmedalstandard
|
||||
workout.goldmedalduration = goldmedalduration
|
||||
workout.save()
|
||||
@@ -602,14 +620,10 @@ def update_wps(r, types, mode='water', asynchron=True):
|
||||
mode
|
||||
)
|
||||
|
||||
df = getsmallrowdata_db(['time', 'driveenergy'], ids=ids)
|
||||
df = read_data(['time', 'driveenergy'], ids=ids)
|
||||
|
||||
try:
|
||||
mask = df['driveenergy'] > 100
|
||||
except (KeyError, TypeError):
|
||||
return False
|
||||
try:
|
||||
wps_median = int(df.loc[mask, 'driveenergy'].median())
|
||||
wps_median = int(df.filter(pl.col("driveenergy")>100)["driveenergy"].median())
|
||||
if mode == 'water':
|
||||
r.median_wps = wps_median
|
||||
else: # pragma: no cover
|
||||
@@ -618,6 +632,10 @@ def update_wps(r, types, mode='water', asynchron=True):
|
||||
r.save()
|
||||
except ValueError: # pragma: no cover
|
||||
pass
|
||||
except OverflowError:
|
||||
pass
|
||||
except ColumnNotFoundError:
|
||||
pass
|
||||
|
||||
return True
|
||||
|
||||
@@ -718,77 +736,28 @@ def fetchcp_new(rower, workouts):
|
||||
data = []
|
||||
|
||||
for workout in workouts:
|
||||
cpfile = 'media/cpdata_{id}.parquet.gz'.format(id=workout.id)
|
||||
try:
|
||||
df, delta, cpvalues = setcp(workout)
|
||||
df = pd.read_parquet(cpfile)
|
||||
df['workout'] = str(workout)
|
||||
df['url'] = workout.url()
|
||||
data.append(df)
|
||||
except:
|
||||
# CP data file doesn't exist yet. has to be created
|
||||
df, delta, cpvalues = setcp(workout)
|
||||
df['workout'] = str(workout)
|
||||
df['url'] = workout.url()
|
||||
df = df.drop('id')
|
||||
df = df.with_columns((pl.lit(str(workout))).alias("workout"))
|
||||
df = df.with_columns((pl.lit(workout.url())).alias("url"))
|
||||
if not df.is_empty():
|
||||
data.append(df)
|
||||
|
||||
if len(data) == 0:
|
||||
return pd.Series(dtype='float'), pd.Series(dtype='float'), 0, pd.Series(dtype='float'), pd.Series(dtype='float')
|
||||
return pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), 0, pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||
if len(data) > 1:
|
||||
df = pd.concat(data, axis=0)
|
||||
|
||||
df = pl.concat(data)
|
||||
|
||||
try:
|
||||
df = df[df['cp'] == df.groupby(['delta'])['cp'].transform('max')]
|
||||
except KeyError: # pragma: no cover
|
||||
return pd.Series(dtype='float'), pd.Series(dtype='float'), 0, pd.Series(dtype='float'), pd.Series(dtype='float')
|
||||
|
||||
df = df.sort_values(['delta']).reset_index()
|
||||
df = df[df['cp']>20]
|
||||
df = df.group_by(pl.col("delta")).agg(pl.max("cp"), pl.max("workout"), pl.max("url")).sort("delta")
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
return pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64), 0, pl.Series(dtype=pl.Float64), pl.Series(dtype=pl.Float64)
|
||||
|
||||
df = df.filter(pl.col("cp")>20)
|
||||
|
||||
return df['delta'], df['cp'], 0, df['workout'], df['url']
|
||||
|
||||
|
||||
def fetchcp(rower, theworkouts, table='cpdata'): # pragma: no cover
|
||||
# get all power data from database (plus workoutid)
|
||||
theids = [int(w.id) for w in theworkouts]
|
||||
columns = ['power', 'workoutid', 'time']
|
||||
df = getsmallrowdata_db(columns, ids=theids)
|
||||
df.dropna(inplace=True, axis=0)
|
||||
if df.empty:
|
||||
avgpower2 = {}
|
||||
for id in theids:
|
||||
avgpower2[id] = 0
|
||||
return pd.Series([], dtype='float'), pd.Series([], dtype='float'), avgpower2
|
||||
|
||||
try:
|
||||
dfgrouped = df.groupby(['workoutid'])
|
||||
except KeyError:
|
||||
avgpower2 = {}
|
||||
return pd.Series([], dtype='float'), pd.Series([], dtype='float'), avgpower2
|
||||
try:
|
||||
avgpower2 = dict(dfgrouped.mean()['power'].astype(int))
|
||||
except KeyError:
|
||||
avgpower2 = {}
|
||||
for id in theids:
|
||||
avgpower2[id] = 0
|
||||
return pd.Series([], dtype='float'), pd.Series([], dtype='float'), avgpower2
|
||||
|
||||
cpdf = getcpdata_sql(rower.id, table=table)
|
||||
|
||||
if not cpdf.empty:
|
||||
return cpdf['delta'], cpdf['cp'], avgpower2
|
||||
else:
|
||||
_ = myqueue(queuelow,
|
||||
handle_updatecp,
|
||||
rower.id,
|
||||
theids,
|
||||
table=table)
|
||||
|
||||
return pd.Series([], dtype='float'), pd.Series([], dtype='float'), avgpower2
|
||||
|
||||
return pd.Series([], dtype='float'), pd.Series([], dtype='float'), avgpower2
|
||||
|
||||
|
||||
def update_rolling_cp(r, types, mode='water', dosend=False):
|
||||
@@ -801,15 +770,17 @@ def update_rolling_cp(r, types, mode='water', dosend=False):
|
||||
|
||||
delta, cp, avgpower, workoutnames, urls = fetchcp_new(r, workouts)
|
||||
|
||||
powerdf = pd.DataFrame({
|
||||
powerdf = pl.DataFrame({
|
||||
'Delta': delta,
|
||||
'CP': cp,
|
||||
})
|
||||
|
||||
powerdf = powerdf[powerdf['CP'] > 0]
|
||||
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)
|
||||
powerdf = powerdf.filter(pl.col("CP")>0)
|
||||
powerdf = powerdf.fill_nan(None).drop_nulls().sort(["Delta", "CP"])
|
||||
powerdf = powerdf.unique(subset=["Delta"], keep="first")
|
||||
|
||||
if powerdf.is_empty():
|
||||
return False
|
||||
|
||||
res2 = datautils.cpfit(powerdf)
|
||||
p1 = res2[0]
|
||||
@@ -1051,7 +1022,7 @@ def checkbreakthrough(w, r):
|
||||
workouttype = w.workouttype
|
||||
if workouttype in rowtypes:
|
||||
cpdf, delta, cpvalues = setcp(w)
|
||||
if not cpdf.empty:
|
||||
if not cpdf.is_empty():
|
||||
if workouttype in otwtypes:
|
||||
try:
|
||||
res, btvalues, res2 = utils.isbreakthrough(
|
||||
@@ -1397,7 +1368,12 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
w.team.add(t)
|
||||
|
||||
# put stroke data in database
|
||||
_ = dataprep(row.df, id=w.id, bands=True,
|
||||
try:
|
||||
row = rrdata_pl(df=pl.from_pandas(row.df))
|
||||
except:
|
||||
pass
|
||||
|
||||
_ = dataplep(row.df, id=w.id, bands=True,
|
||||
barchart=True, otwpower=True, empower=True, inboard=inboard)
|
||||
|
||||
isbreakthrough, ishard = checkbreakthrough(w, r)
|
||||
|
||||
+827
-54
File diff suppressed because it is too large
Load Diff
+19
-32
@@ -1,8 +1,10 @@
|
||||
import pandas as pd
|
||||
import polars as pl
|
||||
import numpy as np
|
||||
from scipy.interpolate import griddata
|
||||
from scipy import optimize
|
||||
|
||||
|
||||
from rowers.mytypes import otwtypes, otetypes, rowtypes
|
||||
from rowers.models import Workout
|
||||
|
||||
@@ -81,8 +83,9 @@ def cpfit(powerdf, fraclimit=0.0001, nmax=1000):
|
||||
|
||||
p1 = p0
|
||||
|
||||
thesecs = powerdf['Delta']
|
||||
theavpower = powerdf['CP']
|
||||
thesecs = powerdf['Delta'].to_numpy()
|
||||
theavpower = powerdf['CP'].to_numpy()
|
||||
|
||||
|
||||
if len(thesecs) >= 4:
|
||||
try:
|
||||
@@ -96,13 +99,14 @@ def cpfit(powerdf, fraclimit=0.0001, nmax=1000):
|
||||
factor = fitfunc(p0, thesecs.mean())/theavpower.mean()
|
||||
p1 = [p0[0]/factor, p0[1]/factor, p0[2], p0[3]]
|
||||
|
||||
|
||||
p1 = [abs(p) for p in p1]
|
||||
fitt = pd.Series(10**(4*np.arange(100)/100.))
|
||||
|
||||
fitpower = fitfunc(p1, fitt)
|
||||
|
||||
fitpoints = fitfunc(p1, thesecs)
|
||||
fitpoints0 = fitpoints.copy()
|
||||
fitpoints0 = fitpoints
|
||||
dd = fitpoints-theavpower
|
||||
|
||||
ddmin = dd.min()
|
||||
@@ -356,8 +360,8 @@ def getmaxwattinterval(tt, ww, i):
|
||||
|
||||
|
||||
def getfastest(df, thevalue, mode='distance'):
|
||||
tt = df['time'].copy()
|
||||
dd = df['cumdist'].copy()
|
||||
tt = df['time'].clone()
|
||||
dd = df['cumdist'].clone()
|
||||
|
||||
tmax = tt.max()
|
||||
if mode == 'distance': # pragma: no cover
|
||||
@@ -368,40 +372,28 @@ def getfastest(df, thevalue, mode='distance'):
|
||||
return 0
|
||||
|
||||
|
||||
# if tmax > 500000:
|
||||
# newlen=int(tmax/2000.)
|
||||
# newt = np.arange(newlen)*tmax/float(newlen)
|
||||
# deltat = newt[1]-newt[0]
|
||||
# else:
|
||||
# newt = np.arange(0,tmax,10.)
|
||||
# deltat = 10.
|
||||
|
||||
newlen = 1000
|
||||
newt = np.arange(newlen)*tmax/float(newlen)
|
||||
deltat = newt[1]-newt[0]
|
||||
|
||||
dd = griddata(tt.values,
|
||||
dd.values, newt, method='linear', rescale=True)
|
||||
dd = griddata(tt.to_numpy(),
|
||||
dd.to_numpy(), newt, method='linear', rescale=True)
|
||||
|
||||
tt = pd.Series(newt, dtype='float')
|
||||
dd = pd.Series(dd, dtype='float')
|
||||
tt = pl.Series(newt, dtype=pl.Float64)
|
||||
dd = pl.Series(dd, dtype=pl.Float64)
|
||||
|
||||
G = pl.concat([pl.Series([0.0]), dd])
|
||||
|
||||
G = pd.concat([pd.Series([0]), dd])
|
||||
# T = pd.concat([pd.Series([0]), dd])
|
||||
# h = np.mgrid[0:len(tt)+1:1, 0:len(tt)+1:1]
|
||||
# distances = pd.DataFrame(h[1]-h[0])
|
||||
ones = 1+np.zeros(len(G))
|
||||
Ghor = np.outer(ones, G)
|
||||
# Thor = np.outer(ones, T)
|
||||
# Tver = np.outer(T, ones)
|
||||
|
||||
Gver = np.outer(G, ones)
|
||||
Gdif = Ghor-Gver
|
||||
Gdif = np.tril(Gdif.T).T
|
||||
Gdif = pd.DataFrame(Gdif)
|
||||
Gdif = pl.DataFrame(Gdif)
|
||||
F = Gdif
|
||||
|
||||
F.fillna(inplace=True, method='ffill', axis=1)
|
||||
F.fillna(inplace=True, value=0)
|
||||
F = F.fill_nan(0)
|
||||
|
||||
restime = []
|
||||
distance = []
|
||||
@@ -412,7 +404,7 @@ def getfastest(df, thevalue, mode='distance'):
|
||||
restime.append(deltat*i)
|
||||
cp = np.diag(F, i).max()
|
||||
loc = np.argmax(np.diag(F, i))
|
||||
thestarttime = tt[loc]
|
||||
thestarttime = tt.to_numpy()[loc]
|
||||
starttimes.append(thestarttime)
|
||||
distance.append(cp)
|
||||
|
||||
@@ -422,10 +414,6 @@ def getfastest(df, thevalue, mode='distance'):
|
||||
distance = np.array(distance)
|
||||
starttimes = np.array(starttimes)
|
||||
|
||||
# for i in range(len(restime)):
|
||||
# if restime[i]<thevalue*60*1000:
|
||||
# print(i,restime[i],distance[i],60*1000*thevalue)
|
||||
|
||||
if mode == 'distance':
|
||||
duration = griddata(distance, restime, [
|
||||
thevalue], method='linear', rescale=True)
|
||||
@@ -434,7 +422,6 @@ def getfastest(df, thevalue, mode='distance'):
|
||||
distance = griddata(distance, distance, [
|
||||
thevalue], method='linear', rescale=True)
|
||||
endtime = starttime+duration
|
||||
# print(duration,starttime,endtime,'aa')
|
||||
return duration[0]/1000., starttime[0]/1000., endtime[0]/1000.
|
||||
else: # pragma: no cover
|
||||
distance = griddata(restime, distance, [
|
||||
|
||||
+10
-83
@@ -74,27 +74,6 @@ class ResampleForm(forms.Form):
|
||||
|
||||
|
||||
class TrainingZonesForm(forms.Form):
|
||||
zoneschoices = (
|
||||
('power', 'Power Zones'),
|
||||
('hr', 'Heart Rate Zones')
|
||||
)
|
||||
|
||||
datechoices = (
|
||||
('month', 'By Month'),
|
||||
('week', 'By Week'),
|
||||
)
|
||||
|
||||
yaxischoices = (
|
||||
('time', 'Time'),
|
||||
('percentage', 'Percentage of Time')
|
||||
)
|
||||
|
||||
zones = forms.ChoiceField(
|
||||
initial='hr', label='Training Zones', choices=zoneschoices)
|
||||
dates = forms.ChoiceField(
|
||||
initial='week', label='Date Aggregation', choices=datechoices)
|
||||
yaxis = forms.ChoiceField(initial='percentage',
|
||||
label='Y axis', choices=yaxischoices)
|
||||
startdate = forms.DateField(
|
||||
initial=timezone.now()-datetime.timedelta(days=42),
|
||||
widget=AdminDateWidget(), # format='%Y-%m-%d'),
|
||||
@@ -778,59 +757,7 @@ class PredictedPieceFormNoDistance(forms.Form):
|
||||
value = forms.FloatField(initial=10, label='Free ranking piece')
|
||||
|
||||
|
||||
# On the Geeky side, to update stream information for river dwellers
|
||||
class UpdateStreamForm(forms.Form):
|
||||
unitchoices = (
|
||||
('m', 'm/s'),
|
||||
('f', 'foot/s'),
|
||||
('k', 'knots'),
|
||||
('p', 'pace difference (sec/500m)'),
|
||||
)
|
||||
dist1 = forms.FloatField(initial=0, label='Distance 1')
|
||||
dist2 = forms.FloatField(initial=1000, label='Distance 2')
|
||||
stream1 = forms.FloatField(initial=0, label='Stream velocity 1')
|
||||
stream2 = forms.FloatField(initial=0, label='Stream velocity 2')
|
||||
streamunit = forms.ChoiceField(required=True,
|
||||
choices=unitchoices,
|
||||
initial='m',
|
||||
label='Unit')
|
||||
|
||||
class Meta:
|
||||
fields = ['dist1', 'dist2', 'stream1', 'stream2', 'streamunit']
|
||||
|
||||
# add wind information to your workout
|
||||
|
||||
|
||||
class UpdateWindForm(forms.Form):
|
||||
unitchoices = (
|
||||
('m', 'm/s'),
|
||||
('k', 'knots'),
|
||||
('b', 'beaufort'),
|
||||
('kmh', 'km/h'),
|
||||
('mph', 'miles/hour'),
|
||||
)
|
||||
dist1 = forms.FloatField(initial=0, label='Distance 1')
|
||||
dist2 = forms.FloatField(initial=1000, label='Distance 2')
|
||||
vwind1 = forms.FloatField(initial=0, required=False, label='Wind Speed 1')
|
||||
vwind2 = forms.FloatField(initial=0, required=False, label='Wind Speed 2')
|
||||
windunit = forms.ChoiceField(required=True,
|
||||
choices=unitchoices,
|
||||
initial='m',
|
||||
label='Unit')
|
||||
winddirection1 = forms.IntegerField(initial=0, required=False,
|
||||
label='Wind Direction 1')
|
||||
winddirection2 = forms.IntegerField(initial=0, required=False,
|
||||
label='Wind Direction 2')
|
||||
|
||||
class Meta:
|
||||
fields = ['dist1', 'dist2',
|
||||
'vwind1', 'vwind2',
|
||||
'windunit',
|
||||
'winddirection1', 'winddirection2']
|
||||
|
||||
# Form to select a data range to show workouts from a certain time period
|
||||
|
||||
|
||||
class DateRangeForm(forms.Form):
|
||||
startdate = forms.DateField(
|
||||
initial=timezone.now()-datetime.timedelta(days=365),
|
||||
@@ -1859,27 +1786,27 @@ class FlexOptionsForm(forms.Form):
|
||||
|
||||
class ForceCurveOptionsForm(forms.Form):
|
||||
includereststrokes = forms.BooleanField(initial=False, required=False,
|
||||
label='Include Rest Strokes')
|
||||
label='Include Rest Strokes',
|
||||
widget=forms.CheckboxInput(attrs={'class':'hidden'}))
|
||||
|
||||
spm_min = forms.FloatField(initial=15.0,label='SPM Min',widget=HiddenInput,required=False)
|
||||
spm_max = forms.FloatField(initial=55.0,label='SPM Max',widget=HiddenInput,required=False)
|
||||
dist_min = forms.IntegerField(initial=0,label='Dist Min',widget=HiddenInput,required=False)
|
||||
dist_max = forms.IntegerField(initial=0,label='Dist Max',widget=HiddenInput,required=False)
|
||||
dist_max = forms.IntegerField(initial=150000,label='Dist Max',widget=HiddenInput,required=False)
|
||||
work_min = forms.IntegerField(initial=0,label='Work Min',widget=HiddenInput,required=False)
|
||||
work_max = forms.IntegerField(initial=1500,label='Work Max',widget=HiddenInput,required=False)
|
||||
|
||||
notes = forms.CharField(initial="", label='notes', widget=HiddenInput, required=False)
|
||||
|
||||
plotchoices = (
|
||||
('line', 'Force Curve Collection Plot'),
|
||||
('scatter', 'Peak Force Scatter Plot'),
|
||||
('none', 'Only aggregrate data')
|
||||
)
|
||||
plottype = forms.ChoiceField(choices=plotchoices, initial='line',
|
||||
label='Individual Stroke Chart Type')
|
||||
|
||||
name = forms.CharField(initial="", label='Name',required=False)
|
||||
|
||||
plotcircles = forms.BooleanField(initial=False,
|
||||
widget=forms.CheckboxInput(attrs={'class':'hidden'}),
|
||||
required=False)
|
||||
plotlines = forms.BooleanField(initial=False,
|
||||
widget=forms.CheckboxInput(attrs={'class':'hidden'}),
|
||||
required=False)
|
||||
|
||||
|
||||
axchoices = list(
|
||||
(ax[0], ax[1]) for ax in axes if ax[0] not in ['cumdist', 'None']
|
||||
|
||||
@@ -2,7 +2,7 @@ from .integrations import SyncIntegration, NoTokenError, create_or_update_syncre
|
||||
from rowers.models import User, Rower, Workout, TombStone
|
||||
from django.db.utils import IntegrityError
|
||||
|
||||
from rowingdata import rowingdata
|
||||
from rowingdata import rowingdata, rowingdata_pl
|
||||
import numpy as np
|
||||
import datetime
|
||||
import json
|
||||
|
||||
+904
-5759
File diff suppressed because it is too large
Load Diff
@@ -364,6 +364,7 @@ for key, dict in rowingmetrics:
|
||||
metricsdicts[key] = dict
|
||||
|
||||
|
||||
|
||||
metricsgroups = list(set([d['group'] for n, d in rowingmetrics]))
|
||||
|
||||
dtypes = {}
|
||||
|
||||
+6
-1
@@ -3833,8 +3833,11 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
|
||||
# remove parquet file
|
||||
try:
|
||||
dirname = 'media/strokedata_{id}.parquet.gz'.format(id=instance.id)
|
||||
shutil.rmtree(dirname)
|
||||
os.remove(dirname)
|
||||
except FileNotFoundError:
|
||||
try:
|
||||
shutil.rmtree(dirname)
|
||||
except:
|
||||
pass
|
||||
|
||||
# remove parquet file
|
||||
@@ -5257,6 +5260,8 @@ class ForceCurveAnalysis(models.Model):
|
||||
average_spm = models.FloatField(default=23)
|
||||
average_boatspeed = models.FloatField(default=4.0)
|
||||
include_rest_strokes = models.BooleanField(default=False)
|
||||
plotcircles = models.BooleanField(default=False)
|
||||
plotlines = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
s = 'Force Curve Analysis {name} ({date})'.format(name = self.name,
|
||||
|
||||
+11
-17
@@ -18,13 +18,12 @@ import rowers.dataprep as dataprep
|
||||
import numpy as np
|
||||
import rowers.metrics as metrics
|
||||
import rowers.mytypes as mytypes
|
||||
from rowers.courses import get_time_course
|
||||
from rowers.utils import to_pace
|
||||
from rowers.opaque import encoder
|
||||
from rowingdata import rower as rrower
|
||||
from rowingdata import rowingdata as rrdata
|
||||
import arrow
|
||||
import pandas as pd
|
||||
import polars as pl
|
||||
import json
|
||||
|
||||
# Python
|
||||
@@ -203,16 +202,8 @@ def get_execution_report(rower, startdate, enddate, plan=None):
|
||||
startdate__gte=enddate)
|
||||
else: # pragma: no cover
|
||||
plans = TrainingPlan.objects.filter(rowers__in=[rower])
|
||||
#plans2 = TrainingPlan.objects.filter(
|
||||
# enddate__lte=enddate, startdate__lte=enddate, rowers__in=[rower])
|
||||
#plans = plans | plans2
|
||||
|
||||
#plans = plans.exclude(status=False).order_by("-enddate")
|
||||
|
||||
if not plans:
|
||||
# make week cycles here
|
||||
# get monday before startdate
|
||||
|
||||
micros = []
|
||||
else:
|
||||
sorted_plans = sorted(plans, key= lambda t: t.overlap(startdate,enddate))
|
||||
@@ -290,7 +281,7 @@ def get_execution_report(rower, startdate, enddate, plan=None):
|
||||
else:
|
||||
plannedscore += 60
|
||||
actualscore += 0
|
||||
elif w.hrtss != 0:
|
||||
elif w.hrtss >= 0:
|
||||
if ratio > 0:
|
||||
plannedscore += w.hrtss/ratio
|
||||
actualscore += w.hrtss
|
||||
@@ -313,7 +304,7 @@ def get_execution_report(rower, startdate, enddate, plan=None):
|
||||
planned += [plannedscore]
|
||||
executed += [actualscore]
|
||||
|
||||
data = pd.DataFrame({
|
||||
data = pl.DataFrame({
|
||||
'startdate': startdates,
|
||||
'planned': planned,
|
||||
'executed': executed,
|
||||
@@ -444,8 +435,9 @@ def add_workouts_plannedsession(ws, ps, r):
|
||||
for record in records:
|
||||
record.delete()
|
||||
|
||||
df = dataprep.getsmallrowdata_db(
|
||||
df = dataprep.read_data(
|
||||
['time', 'cumdist'], ids=[w.id])
|
||||
df = dataprep.remove_nulls_pl(df)
|
||||
fastest_milliseconds, starttime, endtime = datautils.getfastest(
|
||||
df, ps.sessionvalue, mode='distance')
|
||||
|
||||
@@ -475,11 +467,11 @@ def add_workouts_plannedsession(ws, ps, r):
|
||||
for record in records:
|
||||
record.delete()
|
||||
|
||||
df = dataprep.getsmallrowdata_db(
|
||||
df = dataprep.read_data(
|
||||
['time', 'cumdist'], ids=[w.id])
|
||||
df = dataprep.remove_nulls_pl(df)
|
||||
fastest_meters, starttime, endtime = datautils.getfastest(
|
||||
df, ps.sessionvalue, mode='time')
|
||||
|
||||
if fastest_meters > 0:
|
||||
w.plannedsession = ps
|
||||
w.save()
|
||||
@@ -1694,8 +1686,9 @@ def add_workout_fastestrace(ws, race, r, recordid=0, doregister=False):
|
||||
record.coursecompleted = True
|
||||
record.workoutid = ws[0].id
|
||||
if race.sessiontype == 'fastest_distance':
|
||||
df = dataprep.getsmallrowdata_db(
|
||||
df = dataprep.read_data(
|
||||
['time', 'cumdist'], ids=[ws[0].id])
|
||||
df = dataprep.remove_nulls_pl(df)
|
||||
fastest_milliseconds, startsecond, endsecond = datautils.getfastest(
|
||||
df, race.sessionvalue, mode='distance')
|
||||
velo = race.sessionvalue/fastest_milliseconds
|
||||
@@ -1711,8 +1704,9 @@ def add_workout_fastestrace(ws, race, r, recordid=0, doregister=False):
|
||||
record.endsecond = endsecond
|
||||
record.save()
|
||||
if race.sessiontype == 'fastest_time': # pragma: no cover
|
||||
df = dataprep.getsmallrowdata_db(
|
||||
df = dataprep.read_data(
|
||||
['time', 'cumdist'], ids=[ws[0].id])
|
||||
df = dataprep.remove_nulls_pl(df)
|
||||
fastest_meters, startsecond, endsecond = datautils.getfastest(
|
||||
df, race.sessionvalue, mode='time')
|
||||
velo = fastest_meters/(60.*race.sessionvalue)
|
||||
|
||||
+17
-1
@@ -6,7 +6,7 @@ from rest_framework import serializers
|
||||
from rowers.models import (
|
||||
Workout, Rower, FavoriteChart, VirtualRaceResult,
|
||||
VirtualRace, GeoCourse, StandardCollection, CourseStandard,
|
||||
GeoPolygon, GeoPoint, PlannedSession,
|
||||
GeoPolygon, GeoPoint, PlannedSession, ForceCurveAnalysis
|
||||
)
|
||||
|
||||
from django.core.exceptions import PermissionDenied
|
||||
@@ -297,6 +297,22 @@ class GeoPointSerializer(serializers.ModelSerializer):
|
||||
)
|
||||
extra_kwargs = {'id': {'read_only': False, 'required': True}}
|
||||
|
||||
class ForceCurveAnalysisSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ForceCurveAnalysis
|
||||
fields = (
|
||||
'id',
|
||||
'name',
|
||||
'workout',
|
||||
'dist_min',
|
||||
'dist_max',
|
||||
'spm_min',
|
||||
'spm_max',
|
||||
'work_min',
|
||||
'work_max',
|
||||
'include_rest_strokes'
|
||||
)
|
||||
|
||||
|
||||
class GeoPolygonSerializer(serializers.ModelSerializer):
|
||||
points = GeoPointSerializer(many=True)
|
||||
|
||||
+37
-117
@@ -56,7 +56,7 @@ from scipy.signal import savgol_filter
|
||||
from scipy.interpolate import griddata
|
||||
|
||||
import rowingdata
|
||||
from rowingdata import make_cumvalues
|
||||
from rowingdata import make_cumvalues, make_cumvalues_array
|
||||
from uuid import uuid4
|
||||
from rowingdata import rowingdata as rdata
|
||||
|
||||
@@ -115,6 +115,9 @@ tpapilocation = TP_API_LOCATION
|
||||
from requests_oauthlib import OAuth1, OAuth1Session
|
||||
|
||||
import pandas as pd
|
||||
import polars as pl
|
||||
from polars.exceptions import ColumnNotFoundError
|
||||
|
||||
|
||||
from django_rq import job
|
||||
from django.utils import timezone
|
||||
@@ -127,7 +130,8 @@ from rowers import mytypes
|
||||
|
||||
|
||||
from rowers.dataroutines import (
|
||||
getsmallrowdata_db, updatecpdata_sql, update_c2id_sql,
|
||||
getsmallrowdata_pd, updatecpdata_sql, update_c2id_sql,
|
||||
read_data,
|
||||
#update_workout_field_sql,
|
||||
update_agegroup_db, update_strokedata,
|
||||
add_c2_stroke_data_db, totaltime_sec_to_string,
|
||||
@@ -2549,9 +2553,10 @@ def handle_otwsetpower(self, f1, boattype, boatclass, coastalbrand, weightvalue,
|
||||
totaltime = totaltime + rowdata.df.loc[0, ' ElapsedTime (sec)']
|
||||
except KeyError: # pragma: no cover
|
||||
pass
|
||||
df = getsmallrowdata_db(
|
||||
df = getsmallrowdata_pd(
|
||||
['power', 'workoutid', 'time'], ids=[workoutid],
|
||||
debug=debug)
|
||||
|
||||
thesecs = totaltime
|
||||
maxt = 1.05 * thesecs
|
||||
logarr = datautils.getlogarr(maxt)
|
||||
@@ -2583,53 +2588,6 @@ def handle_otwsetpower(self, f1, boattype, boatclass, coastalbrand, weightvalue,
|
||||
return 1
|
||||
|
||||
|
||||
@app.task
|
||||
def handle_updateergcp(rower_id, workoutfilenames, debug=False, **kwargs):
|
||||
therows = []
|
||||
for f1 in workoutfilenames:
|
||||
try:
|
||||
rowdata = rdata(csvfile=f1)
|
||||
except IOError: # pragma: no cover
|
||||
try:
|
||||
rowdata = rdata(csvfile=f1 + '.csv')
|
||||
except IOError:
|
||||
try:
|
||||
rowdata = rdata(csvfile=f1 + '.gz')
|
||||
except IOError:
|
||||
rowdata = 0
|
||||
if rowdata != 0:
|
||||
therows.append(rowdata)
|
||||
|
||||
cpdata = rowingdata.cumcpdata(therows)
|
||||
cpdata.columns = cpdata.columns.str.lower()
|
||||
|
||||
updatecpdata_sql(rower_id, cpdata['delta'], cpdata['cp'],
|
||||
table='ergcpdata', distance=cpdata['distance'],
|
||||
debug=debug)
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
@app.task
|
||||
def handle_updatecp(rower_id, workoutids, debug=False, table='cpdata', **kwargs):
|
||||
columns = ['power', 'workoutid', 'time']
|
||||
df = getsmallrowdata_db(columns, ids=workoutids, debug=debug)
|
||||
|
||||
if df.empty: # pragma: no cover
|
||||
return 0
|
||||
|
||||
maxt = 1.05*df['time'].max()/1000.
|
||||
|
||||
logarr = datautils.getlogarr(maxt)
|
||||
|
||||
dfgrouped = df.groupby(['workoutid'])
|
||||
|
||||
delta, cpvalue, avgpower = datautils.getcp(dfgrouped, logarr)
|
||||
|
||||
updatecpdata_sql(rower_id, delta, cpvalue, debug=debug, table=table)
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
@app.task
|
||||
def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename,
|
||||
@@ -3179,43 +3137,6 @@ def handle_sendemail_invite_reject(email, name, teamname, managername,
|
||||
return 1
|
||||
|
||||
|
||||
@app.task
|
||||
def handle_setcp(strokesdf, filename, workoutid, debug=False, **kwargs):
|
||||
try:
|
||||
os.remove(filename)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
if not strokesdf.empty:
|
||||
|
||||
try:
|
||||
totaltime = strokesdf['time'].max()
|
||||
except KeyError: # pragma: no cover
|
||||
return 0
|
||||
try:
|
||||
powermean = strokesdf['power'].mean()
|
||||
except KeyError: # pragma: no cover
|
||||
powermean = 0
|
||||
|
||||
if powermean != 0:
|
||||
thesecs = totaltime
|
||||
maxt = 1.05 * thesecs
|
||||
|
||||
if maxt > 0:
|
||||
logarr = datautils.getlogarr(maxt)
|
||||
dfgrouped = strokesdf.groupby(['workoutid'])
|
||||
delta, cpvalues, avgpower = datautils.getcp(dfgrouped, logarr)
|
||||
|
||||
df = pd.DataFrame({
|
||||
'delta': delta,
|
||||
'cp': cpvalues,
|
||||
'id': workoutid,
|
||||
})
|
||||
df.to_parquet(filename, engine='fastparquet',
|
||||
compression='GZIP')
|
||||
return 1
|
||||
|
||||
return 1 # pragma: no cover
|
||||
|
||||
|
||||
@app.task
|
||||
def handle_sendemail_invite_accept(email, name, teamname, managername,
|
||||
@@ -3251,23 +3172,22 @@ graphql_url = "https://rp3rowing-app.com/graphql"
|
||||
|
||||
@app.task
|
||||
def handle_update_wps(rid, types, ids, mode, debug=False, **kwargs):
|
||||
df = getsmallrowdata_db(['time', 'driveenergy'], ids=ids)
|
||||
df = read_data(['time', 'driveenergy'], ids=ids)
|
||||
try:
|
||||
mask = df['driveenergy'] > 100
|
||||
except (KeyError, TypeError): # pragma: no cover
|
||||
return 0
|
||||
try:
|
||||
wps_median = int(df.loc[mask, 'driveenergy'].median())
|
||||
except ValueError: # pragma: no cover
|
||||
return 0
|
||||
|
||||
wps_median = int(df.filter(pl.col("driveenergy")>100)["driveenergy"].median())
|
||||
rower = Rower.objects.get(id=rid)
|
||||
if mode == 'water':
|
||||
rower.median_wps = wps_median
|
||||
else:
|
||||
else: # pragma: no cover
|
||||
rower.median_wps_erg = wps_median
|
||||
|
||||
rower.save()
|
||||
except ValueError: # pragma: no cover
|
||||
wps_median = 0
|
||||
except OverflowError:
|
||||
wps_median = 0
|
||||
except ColumnNotFoundError:
|
||||
wps_median = 0
|
||||
|
||||
return wps_median
|
||||
|
||||
@@ -3901,7 +3821,7 @@ def fetch_strava_workout(stravatoken, oauth_data, stravaid, csvfilename, userid,
|
||||
pace[np.isinf(pace)] = 0.0
|
||||
|
||||
try:
|
||||
strokedata = pd.DataFrame({'t': 10*t,
|
||||
strokedata = pl.DataFrame({'t': 10*t,
|
||||
'd': 10*d,
|
||||
'p': 10*pace,
|
||||
'spm': spm,
|
||||
@@ -3947,18 +3867,18 @@ def fetch_strava_workout(stravatoken, oauth_data, stravaid, csvfilename, userid,
|
||||
|
||||
starttimeunix = arrow.get(rowdatetime).timestamp()
|
||||
|
||||
res = make_cumvalues(0.1*strokedata['t'])
|
||||
cum_time = res[0]
|
||||
lapidx = res[1]
|
||||
res = make_cumvalues_array(0.1*strokedata['t'].to_numpy())
|
||||
cum_time = pl.Series(res[0])
|
||||
lapidx = pl.Series(res[1])
|
||||
|
||||
unixtime = cum_time+starttimeunix
|
||||
seconds = 0.1*strokedata.loc[:, 't']
|
||||
seconds = 0.1*strokedata['t']
|
||||
|
||||
nr_rows = len(unixtime)
|
||||
|
||||
try:
|
||||
latcoord = strokedata.loc[:, 'lat']
|
||||
loncoord = strokedata.loc[:, 'lon']
|
||||
latcoord = strokedata['lat']
|
||||
loncoord = strokedata['lon']
|
||||
if latcoord.std() == 0 and loncoord.std() == 0 and workouttype == 'water': # pragma: no cover
|
||||
workouttype = 'rower'
|
||||
except: # pragma: no cover
|
||||
@@ -3968,29 +3888,29 @@ def fetch_strava_workout(stravatoken, oauth_data, stravaid, csvfilename, userid,
|
||||
workouttype = 'rower'
|
||||
|
||||
try:
|
||||
strokelength = strokedata.loc[:, 'strokelength']
|
||||
strokelength = strokedata['strokelength']
|
||||
except: # pragma: no cover
|
||||
strokelength = np.zeros(nr_rows)
|
||||
|
||||
dist2 = 0.1*strokedata.loc[:, 'd']
|
||||
dist2 = 0.1*strokedata['d']
|
||||
|
||||
try:
|
||||
spm = strokedata.loc[:, 'spm']
|
||||
except KeyError: # pragma: no cover
|
||||
spm = strokedata['spm']
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
spm = 0*dist2
|
||||
|
||||
try:
|
||||
hr = strokedata.loc[:, 'hr']
|
||||
except KeyError: # pragma: no cover
|
||||
hr = strokedata['hr']
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
hr = 0*spm
|
||||
pace = strokedata.loc[:, 'p']/10.
|
||||
pace = strokedata['p']/10.
|
||||
pace = np.clip(pace, 0, 1e4)
|
||||
pace = pace.replace(0, 300)
|
||||
pace = pl.Series(pace).replace(0, 300)
|
||||
|
||||
velo = 500./pace
|
||||
|
||||
try:
|
||||
power = strokedata.loc[:, 'power']
|
||||
power = strokedata['power']
|
||||
except KeyError: # pragma: no cover
|
||||
power = 2.8*velo**3
|
||||
|
||||
@@ -3999,7 +3919,7 @@ def fetch_strava_workout(stravatoken, oauth_data, stravaid, csvfilename, userid,
|
||||
|
||||
# save csv
|
||||
# Create data frame with all necessary data to write to csv
|
||||
df = pd.DataFrame({'TimeStamp (sec)': unixtime,
|
||||
df = pl.DataFrame({'TimeStamp (sec)': unixtime,
|
||||
' Horizontal (meters)': dist2,
|
||||
' Cadence (stokes/min)': spm,
|
||||
' HRCur (bpm)': hr,
|
||||
@@ -4019,10 +3939,10 @@ def fetch_strava_workout(stravatoken, oauth_data, stravaid, csvfilename, userid,
|
||||
'cum_dist': dist2,
|
||||
})
|
||||
|
||||
df.sort_values(by='TimeStamp (sec)', ascending=True)
|
||||
df.sort('TimeStamp (sec)')
|
||||
|
||||
row = rowingdata.rowingdata(df=df)
|
||||
row.write_csv(csvfilename, gzip=False)
|
||||
row = rowingdata.rowingdata_pl(df=df)
|
||||
row.write_csv(csvfilename, compressed=False)
|
||||
|
||||
# summary = row.allstats()
|
||||
# maxdist = df['cum_dist'].max()
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
{{ mapscript|safe }}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -37,8 +37,9 @@
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
<script>
|
||||
{{ mapscript|safe }}
|
||||
</script>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -45,7 +45,9 @@
|
||||
<li class="grid_4">
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
<script>
|
||||
{{ mapscript|safe }}
|
||||
</script>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
{{ mapscript|safe }}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -102,14 +102,11 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="grid_2">
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
{{ interactiveplot |safe }}
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
|
||||
{{ the_div|safe }}
|
||||
{{ interactiveplot |safe }}
|
||||
|
||||
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
|
||||
@@ -116,7 +116,7 @@ function copyText() {
|
||||
</li>
|
||||
{% if user.is_authenticated and user == workout.user.user and not locked %}
|
||||
<li class="grid_2">
|
||||
<p>Paste link to you tube video below</p>
|
||||
<p>Paste link to Youtube video below</p>
|
||||
<p>Use the slider to locate start point for video on workout map</p>
|
||||
<p>Playing the video will advance the data in synchonization. Use the regular YouTube
|
||||
controls
|
||||
@@ -169,9 +169,8 @@ function copyText() {
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<div id="player"></div>
|
||||
<script>
|
||||
// 1. Code for the map
|
||||
{{ mapscript | safe }}
|
||||
<script>
|
||||
|
||||
|
||||
// 2. This code loads the IFrame Player API code asynchronously.
|
||||
@@ -189,6 +188,7 @@ function copyText() {
|
||||
|
||||
var videotime = 0;
|
||||
var data = JSON.parse('{{ data|safe }}');
|
||||
|
||||
{% for id, metric in metrics.items %}
|
||||
var {{ id }}_values = data["{{ id }}"];
|
||||
// console.log("{{ id }}_values",{{ id }}_values);
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
{% extends "newbase.html" %}
|
||||
{% load static %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}Rowsandall {% endblock %}
|
||||
{% block meta %}
|
||||
<style type="text/css">
|
||||
|
||||
circle {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.axis path,
|
||||
.axis line {
|
||||
fill: none;
|
||||
stroke: black;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
.axis text {
|
||||
font-family: sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
padding: 1em;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background-color: #f00;
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<script src="https://d3js.org/d3.v3.min.js"></script>
|
||||
|
||||
|
||||
<h1>Film Deaths</h1>
|
||||
|
||||
<ul class="main-content">
|
||||
|
||||
|
||||
<li class="grid_4">
|
||||
<div id="id_chart">
|
||||
<script>
|
||||
{{ the_script| safe }}
|
||||
</script>
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script type='text/javascript'
|
||||
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% include 'menu_analytics.html' %}
|
||||
{% endblock %}
|
||||
@@ -8,16 +8,6 @@
|
||||
{% localtime on %}
|
||||
{% block main %}
|
||||
|
||||
{{ js_res | safe }}
|
||||
{{ css_res| safe }}
|
||||
|
||||
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
{{ the_script |safe }}
|
||||
|
||||
<p>
|
||||
{% if workout|previousworkout:rower.user %}
|
||||
@@ -34,10 +24,9 @@
|
||||
<h1>Flexible Chart</h1>
|
||||
|
||||
<ul class="main-content">
|
||||
<canvas hidden id="canvas"></canvas>
|
||||
<li class="grid_4">
|
||||
<div id="theplot" class="flexplot">
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<form enctype="multipart/form-data"
|
||||
@@ -96,6 +85,10 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
{{ the_script |safe }}
|
||||
|
||||
{% endblock %}
|
||||
{% endlocaltime %}
|
||||
|
||||
|
||||
@@ -8,16 +8,8 @@
|
||||
{% localtime on %}
|
||||
{% block main %}
|
||||
|
||||
{{ js_res | safe }}
|
||||
{{ css_res| safe }}
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
{{ the_script |safe }}
|
||||
|
||||
<p>
|
||||
{% if workout|previousworkout:rower.user %}
|
||||
@@ -34,6 +26,7 @@
|
||||
<h1>Chart Stack</h1>
|
||||
|
||||
<ul class="main-content">
|
||||
<canvas hidden id="canvas"></canvas>
|
||||
<li class="grid_4">
|
||||
<div id="theplot">
|
||||
{{ the_div|safe }}
|
||||
@@ -57,6 +50,7 @@
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
{{ the_script |safe }}
|
||||
|
||||
{% endblock %}
|
||||
{% endlocaltime %}
|
||||
|
||||
@@ -6,25 +6,20 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
{{ js_res | safe }}
|
||||
{{ css_res| safe }}
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
{{ the_script |safe }}
|
||||
|
||||
<h1>Force Curve Analysis for {{ rower.user.first_name }} {{ rower.user.last_name }}</h1>
|
||||
|
||||
|
||||
<ul class="main-content">
|
||||
<canvas hidden id="canvas"></canvas>
|
||||
{% if the_div %}
|
||||
<li class="grid_4">
|
||||
<div id="theplot" class="flexplot">
|
||||
{{ the_div|safe }}
|
||||
{{ the_script |safe }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@@ -8,23 +8,17 @@
|
||||
{% localtime on %}
|
||||
{% block main %}
|
||||
|
||||
{{ js_res | safe }}
|
||||
{{ css_res| safe }}
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
{{ the_script |safe }}
|
||||
|
||||
<h1>Empower Force Curve</h1>
|
||||
|
||||
<ul class="main-content">
|
||||
<canvas hidden id="canvas"></canvas>
|
||||
<li class="grid_4">
|
||||
<div id="theplot" class="flexplot">
|
||||
{{ the_div|safe }}
|
||||
{{ the_script |safe }}
|
||||
</div>
|
||||
|
||||
</li>
|
||||
@@ -52,27 +46,13 @@
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
var slider_min_spm = Bokeh.documents[0].get_model_by_name('min_spm_slider')
|
||||
slider_min_spm.value = {{ spm_min }}
|
||||
console.log('min spm value after:', slider_min_spm.value)
|
||||
var slider_max_spm = Bokeh.documents[0].get_model_by_name('max_spm_slider')
|
||||
slider_max_spm.value = {{ spm_max }}
|
||||
console.log('max spm value after:', slider_max_spm.value)
|
||||
var slider_min_work = Bokeh.documents[0].get_model_by_name('min_work_slider')
|
||||
slider_min_work.value = {{ work_min }}
|
||||
console.log('min work value after:', slider_min_work.value)
|
||||
var slider_max_work = Bokeh.documents[0].get_model_by_name('max_work_slider')
|
||||
slider_max_work.value = {{ work_max }}
|
||||
console.log('max work value after:', slider_max_work.value)
|
||||
var slider_min_dist = Bokeh.documents[0].get_model_by_name('min_dist_slider')
|
||||
slider_min_dist.value = {{ dist_min }}
|
||||
console.log('min dist value after:', slider_min_dist.value)
|
||||
var slider_max_dist = Bokeh.documents[0].get_model_by_name('max_dist_slider')
|
||||
slider_max_dist.value = {{ dist_max }}
|
||||
console.log('max dist value after:', slider_max_dist.value)
|
||||
var annotation = Bokeh.documents[0].get_model_by_name('annotation')
|
||||
annotation.value = "{{ annotation }}"
|
||||
console.log('Annotation set to ', annotation.value)
|
||||
var label = $('label[for="' + $("#id_plotcircles").attr('id') + '"]');
|
||||
label.attr("class", "hidden")
|
||||
var label2 = $('label[for="' + $("#id_plotlines").attr('id') + '"]');
|
||||
label2.attr("class", "hidden")
|
||||
var label3 = $('label[for="' + $("#id_includereststrokes").attr('id') + '"]');
|
||||
label3.attr("class", "hidden")
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -60,17 +60,6 @@
|
||||
{% block main %}
|
||||
|
||||
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
<div id="id_script">
|
||||
{{ chartscript |safe }}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% if rower.user %}
|
||||
<h1>Gold Medal Scores for {{ rower.user.first_name }} </h1>
|
||||
{% else %}
|
||||
@@ -79,6 +68,7 @@
|
||||
|
||||
|
||||
<ul class="main-content">
|
||||
<canvas hidden id="canvas"></canvas>
|
||||
<li class="grid_4">
|
||||
<p>Hover over the workout to see details, click on the workout to open in a
|
||||
separate page.</p>
|
||||
@@ -136,6 +126,11 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
|
||||
<div id="id_script">
|
||||
{{ chartscript |safe }}
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
{% block main %}
|
||||
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||
<script src="https://d3js.org/d3/v6/js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
|
||||
@@ -86,7 +87,6 @@
|
||||
|
||||
<li class="grid_4">
|
||||
<div id="id_chart">
|
||||
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
</li>
|
||||
@@ -129,6 +129,7 @@
|
||||
var counter=0;
|
||||
var script = json.script;
|
||||
var div = json.div;
|
||||
console.log(div)
|
||||
console.log('set vars');
|
||||
$("#id_sitready").remove();
|
||||
console.log('sitready removed');
|
||||
|
||||
@@ -6,12 +6,9 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
|
||||
|
||||
{{ interactiveplot |safe }}
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +21,7 @@
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
{{ interactiveplot |safe }}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -5,25 +5,14 @@
|
||||
{% block title %}Rowsandall {% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div id="id_css_res">
|
||||
<link rel="stylesheet" href="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.css" type="text/css" />
|
||||
</div>
|
||||
<div id="id_js_res">
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.js"></script>
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
</div>
|
||||
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
<div id="id_script">
|
||||
</div>
|
||||
|
||||
<div id="t_script">
|
||||
{{ tscript|safe}}
|
||||
</div>
|
||||
|
||||
<div id="activities_script">
|
||||
</div>
|
||||
@@ -90,6 +79,10 @@
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
{{ tdiv|safe }}
|
||||
<div id="t_script">
|
||||
{{ tscript|safe}}
|
||||
</div>
|
||||
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<div id="id_chart">
|
||||
@@ -157,7 +150,6 @@
|
||||
var activities_chart = json.activities_chart
|
||||
$("#id_sitready").remove();
|
||||
$("#id_chart").append(div);
|
||||
// $("#id_script").append("<s"+"cript>"+script+"</s"+"cript>");
|
||||
$("#id_script").append(script);
|
||||
$("#id_activities").append(activities_chart)
|
||||
$("#activities_script").append(activities_script)
|
||||
@@ -165,6 +157,8 @@
|
||||
$("#total_maxhr").append(totalsdict.hrmax);
|
||||
$("#total_power").append(totalsdict.powermean);
|
||||
$("#total_maxpower").append(totalsdict.powermax);
|
||||
$("#selectors").hide();
|
||||
|
||||
listofdicts.forEach(function(item){
|
||||
var id = "#"+item.id+"_hr";
|
||||
$(id).append(item.hrmean);
|
||||
|
||||
@@ -6,24 +6,20 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
{{ js_res | safe }}
|
||||
{{ css_res| safe }}
|
||||
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.js"></script>
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
{{ the_script |safe }}
|
||||
|
||||
<h1>In-Stroke Analysis for {{ rower.user.first_name }} {{ rower.user.last_name }}</h1>
|
||||
|
||||
<ul class="main-content">
|
||||
<canvas hidden id="canvas"></canvas>
|
||||
{% if the_div %}
|
||||
<li class="grid_4">
|
||||
<div id="theplot" class="flexplot">
|
||||
{{ the_div|safe }}
|
||||
{{ the_script |safe }}
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
@@ -11,10 +11,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>jQuery UI Slider - Range slider</title>
|
||||
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
|
||||
<link rel="stylesheet" href="/resources/demos/style.css">
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
|
||||
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
|
||||
|
||||
<script>
|
||||
function submit_form() {
|
||||
console.log("form changed");
|
||||
@@ -30,11 +28,14 @@
|
||||
dataType: 'json',
|
||||
|
||||
success: function(data) {
|
||||
console.log(data);
|
||||
$("#id_script").replaceWith('<div id="id_script">'+data.script+'</d'+'iv>');
|
||||
$("#id_chart").replaceWith('<div id="id_chart">'+data.div+'</d'+'iv>');
|
||||
$("#ds").replaceWith('<div id="ds">'+data.ds+'</d'+'iv>');
|
||||
$("#dd").replaceWith('<div id="dd">'+data.dd+'</d'+'iv>');
|
||||
$("#id_script").replaceWith('<div id="id_script">'+data.script+'</d'+'iv>');
|
||||
|
||||
|
||||
$("#dd").empty();
|
||||
$("#dd").html(data.dd);
|
||||
$("#ds").empty();
|
||||
$('#ds').html(data.ds)
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -119,15 +120,10 @@ $( function() {
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
<div id="id_script">
|
||||
{{ the_script |safe }}
|
||||
</div>
|
||||
<div id="ds">
|
||||
{{ ds |safe }}
|
||||
</div>
|
||||
|
||||
<h1>In Stroke Metrics</h1>
|
||||
<ul class="main-content">
|
||||
<canvas hidden id="canvas"></canvas>
|
||||
<li class="grid_4" >
|
||||
{% if user.rower|is_basic %}
|
||||
|
||||
@@ -144,7 +140,7 @@ $( function() {
|
||||
</table>
|
||||
<div id="slider-range"></div>
|
||||
<p>
|
||||
<label for="amountspm">Active Range:</label>
|
||||
<label for="amountspm">Stroke Rate:</label>
|
||||
<input type="text" id="amountspm" readonly style="border:0; color:#1c75bc; font-weight:bold;">
|
||||
</p>
|
||||
<div id="slider-timerange"></div>
|
||||
@@ -168,14 +164,23 @@ $( function() {
|
||||
</p>
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
<div id="id_chart" class="flexplot">
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
<div id="id_script">
|
||||
{{ the_script |safe }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
<li class="grid_2" id="interactive">
|
||||
<div id="dd" class="flexplot">
|
||||
{{ dd|safe }}
|
||||
</div>
|
||||
<div id="ds">
|
||||
{{ ds |safe }}
|
||||
</div>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -229,22 +229,11 @@
|
||||
Total meters: {{ totalmeters }}. Total time {{ totalhours }}:{{ totalminutes }}h.
|
||||
<a href="/rowers/history/">Dig deeper</a>.
|
||||
</p>
|
||||
<p>
|
||||
Activity chart by
|
||||
<a href="{{ request.get_path }}?yaxis=trimp">TRIMP</a>,
|
||||
<a href="{{ request.get_path }}?yaxis=rscore">rScore</a>,
|
||||
<a href="{{ request.get_path }}?yaxis=duration">Time</a>.
|
||||
</p>
|
||||
<link rel="stylesheet" href="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.css" type="text/css" />
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/text/javascript">
|
||||
Bokeh.set_log_level("info")
|
||||
</script>
|
||||
|
||||
{{ interactiveplot |safe }}
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
|
||||
{{ the_div |safe }}
|
||||
{{ interactiveplot |safe }}
|
||||
|
||||
</li>
|
||||
{% if announcements %}
|
||||
<li class="grid_4">
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
<div style="height:100%;" id="theplot" class="flexplot mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
{{ mapscript|safe }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
<script>
|
||||
{{ mapscript|safe }}
|
||||
</script>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -101,11 +101,6 @@
|
||||
<i class="fas fa-dumbbell fa-fw"></i> Force Curve
|
||||
</a>
|
||||
</li>
|
||||
<li id="chart-otwpower">
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/interactiveotwplot/">
|
||||
<i class="fal fa-calculator-alt fa-fw"></i> Corrected Pace Plot
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</li>
|
||||
@@ -294,26 +289,6 @@
|
||||
<label for="group-advanced">Advanced</label>
|
||||
<ul>
|
||||
{% if workout|water %}
|
||||
<li id="advanced-wind">
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/wind/">
|
||||
<i class="fas fa-pennant fa-fw"></i> Wind
|
||||
</a>
|
||||
</li>
|
||||
<li id="advanced-stream">
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/stream/">
|
||||
<i class="fas fa-stream fa-fw"></i> Stream
|
||||
</a>
|
||||
</li>
|
||||
<li id="advanced-otwpower">
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/otwsetpower/">
|
||||
<i class="fas fa-calculator-alt fa-fw"></i> OTW Power
|
||||
</a>
|
||||
</li>
|
||||
<li id="advanced-otwpower">
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/zeropower-confirm/">
|
||||
<i class="fas fa-eraser fa-fw"></i> Remove Power Data
|
||||
</a>
|
||||
</li>
|
||||
{% if 'speedcoach2' in workout.workoutsource or 'nklinklogbook' in workout.workoutsource %}
|
||||
<li id="advanced-usegps">
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/otwusegps/">
|
||||
|
||||
@@ -6,12 +6,9 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
|
||||
|
||||
{{ interactiveplot |safe }}
|
||||
|
||||
<h1>Interactive Comparison</h1>
|
||||
|
||||
@@ -20,6 +17,7 @@
|
||||
<li class="grid_4">
|
||||
<div>
|
||||
{{ the_div|safe }}
|
||||
{{ interactiveplot |safe }}
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
{{ mapscript|safe }}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -8,6 +8,15 @@
|
||||
<script type='text/javascript'
|
||||
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
|
||||
<script src="https://d3js.org/d3.v6.js">
|
||||
</script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
function submit_form() {
|
||||
@@ -25,11 +34,14 @@
|
||||
dataType: 'json',
|
||||
|
||||
success: function(data) {
|
||||
console.log(data.div);
|
||||
|
||||
// var parsedJSON = $.parseJSON(data); //
|
||||
$("#id_script").replaceWith('<div id="id_script">'+data.script+'</d'+'iv>');
|
||||
|
||||
// $('#id_script').remove()
|
||||
|
||||
$("#id_chart").replaceWith('<div id="id_chart">'+data.div+'</d'+'iv>');
|
||||
$("#id_chart").append(data.script)
|
||||
$("#endfitness").html(data.endfitness)
|
||||
$("#endfatigue").html(data.endfatigue)
|
||||
$("#endform").html(data.endform)
|
||||
@@ -59,19 +71,6 @@
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
<div id="id_script">
|
||||
{{ chartscript |safe }}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -83,10 +82,12 @@
|
||||
|
||||
|
||||
<ul class="main-content">
|
||||
<canvas hidden id="canvas"></canvas>
|
||||
<li class="grid_4">
|
||||
<div id="id_chart">
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
|
||||
</li>
|
||||
<li class="grid_1">
|
||||
<form id="performanceform" enctype="multipart/form-data" method="post">
|
||||
@@ -188,6 +189,9 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="id_script">
|
||||
{{ chartscript |safe }}
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
{% extends "newbase.html" %}
|
||||
{% load static %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}Rowsandall {% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div id="id_css_res">
|
||||
<link rel="stylesheet" href="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.css" type="text/css" />
|
||||
</div>
|
||||
<div id="id_js_res">
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-api-3.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-api-3.1.1.min.js"></script>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||
|
||||
|
||||
|
||||
<h1>Sleep</h1>
|
||||
|
||||
<ul class="main-content">
|
||||
|
||||
|
||||
<li class="grid_4">
|
||||
<div id="id_chart">
|
||||
<script>
|
||||
{{ the_script| safe }}
|
||||
</script>
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script type='text/javascript'
|
||||
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% include 'menu_analytics.html' %}
|
||||
{% endblock %}
|
||||
@@ -23,7 +23,7 @@
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -89,14 +89,11 @@
|
||||
</p>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
{{ interactiveplot |safe }}
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
|
||||
{{ the_div |safe }}
|
||||
{{ interactiveplot |safe }}
|
||||
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<h1>Feeling lucky?</h1>
|
||||
|
||||
@@ -6,25 +6,22 @@
|
||||
|
||||
|
||||
{% block main %}
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||
|
||||
|
||||
<h1>Training Plan - {{ plan.name }}</h1>
|
||||
|
||||
{{ the_script | safe }}
|
||||
|
||||
<ul class="main-content">
|
||||
<li class="grid_4">
|
||||
<div id="theplot" class="flexplot">
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
{{ the_script | safe }}
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
|
||||
@@ -11,17 +11,15 @@
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
<div id="id_js_res">
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
</div>
|
||||
|
||||
<h1>Training Zones</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="id_script">
|
||||
</div>
|
||||
|
||||
|
||||
<ul class="main-content">
|
||||
<li class="grid_4">
|
||||
<div id="id_chart">
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
}
|
||||
</script>
|
||||
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
|
||||
@@ -387,29 +388,11 @@
|
||||
|
||||
</script>
|
||||
|
||||
<div id="id_css_res">
|
||||
</div>
|
||||
<div id="id_js_res">
|
||||
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-3.1.1.min.js"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.1.1.min.js"
|
||||
crossorigin="anonymous"></script>
|
||||
</div>
|
||||
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
<div id="id_script">
|
||||
</div>
|
||||
|
||||
<ul class="main-content">
|
||||
<canvas hidden id="canvas"></canvas>
|
||||
<li class="grid_4">
|
||||
<div id="id_chart">
|
||||
{{ the_div|safe }}
|
||||
|
||||
@@ -67,7 +67,9 @@
|
||||
<div class="mapdiv">
|
||||
|
||||
{{ gmapdiv |safe }}
|
||||
<script>
|
||||
{{ gmap |safe }}
|
||||
</script>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -98,14 +98,11 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="grid_2">
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
{{ interactiveplot |safe }}
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
|
||||
{{ the_div|safe }}
|
||||
{{ interactiveplot |safe }}
|
||||
|
||||
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
{% block meta %}
|
||||
{% leaflet_js %}
|
||||
{% leaflet_css %}
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
{% for chart in charts %}
|
||||
{{ chart.script |safe }}
|
||||
@@ -51,7 +47,7 @@
|
||||
"<a href=\"/rowers/workout/"+workoutid+"/flexchart?favoritechart="+counter+"\">"+element.div+"</a>"+
|
||||
"</li>");
|
||||
|
||||
$("#id_thumbscripts").append(element.script);
|
||||
$("#id_thumbs").append(element.script);
|
||||
counter += 1;
|
||||
});
|
||||
});
|
||||
@@ -64,6 +60,7 @@
|
||||
|
||||
|
||||
{% block main %}
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
<p>
|
||||
{% if workout|previousworkout:rower.user %}
|
||||
<a href="/rowers/workout/{{ workout|previousworkout:rower.user }}/workflow"
|
||||
|
||||
@@ -217,9 +217,9 @@
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
{{ mapscript|safe }}
|
||||
|
||||
</script>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% for graph in graphs %}
|
||||
|
||||
@@ -131,21 +131,16 @@
|
||||
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
<script>
|
||||
{{ mapscript|safe }}
|
||||
</script>
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="grid_2">
|
||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-3.1.1.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
{{ interactiveplot |safe }}
|
||||
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
{{ the_div|safe }}
|
||||
|
||||
{{ interactiveplot |safe }}
|
||||
</li>
|
||||
{% for graph in graphs %}
|
||||
<li>
|
||||
|
||||
+18
-6
@@ -38,6 +38,7 @@ from nose.tools import assert_true
|
||||
from mock import Mock, patch
|
||||
#from minimocktest import MockTestCase
|
||||
import pandas as pd
|
||||
import polars as pl
|
||||
|
||||
import arrow
|
||||
from django.http import HttpResponseRedirect
|
||||
@@ -271,7 +272,7 @@ def mocked_fetchcperg(*args, **kwargs):
|
||||
|
||||
return df
|
||||
|
||||
import pandas as pd
|
||||
|
||||
def mocked_read_df_sql(id): # pragma: no cover
|
||||
df = pd.read_csv('rowers/tests/testdata/fake_strokedata.csv')
|
||||
|
||||
@@ -300,7 +301,7 @@ def mocked_getrowdata_db(*args, **kwargs):
|
||||
return df,row
|
||||
|
||||
def mocked_getrowdata_uh(*args, **kwargs): # pragma: no cover
|
||||
df = pd.read_csv('rowers/tests/testdata/uhfull.csv')
|
||||
df = pl.read_csv('rowers/tests/testdata/uhfull.csv')
|
||||
|
||||
id = kwargs['id']
|
||||
|
||||
@@ -308,13 +309,19 @@ def mocked_getrowdata_uh(*args, **kwargs): # pragma: no cover
|
||||
|
||||
return df, row
|
||||
|
||||
|
||||
def mocked_getsmallrowdata_uh(*args, **kwargs): # pragma: no cover
|
||||
df = pl.read_csv('rowers/tests/testdata/uhfull.csv')
|
||||
|
||||
return df
|
||||
|
||||
def mocked_getsmallrowdata_uh_pd(*args, **kwargs): # pragma: no cover
|
||||
df = pd.read_csv('rowers/tests/testdata/uhfull.csv')
|
||||
|
||||
return df
|
||||
|
||||
def mocked_getsmallrowdata_forfusion(*args, **kwargs):
|
||||
df = pd.read_csv('rowers/tests/testdata/getrowdata_mock.csv')
|
||||
df = pl.read_csv('rowers/tests/testdata/getrowdata_mock.csv')
|
||||
|
||||
return df
|
||||
|
||||
@@ -335,6 +342,11 @@ def mocked_getsmallrowdata_db(*args, **kwargs):
|
||||
|
||||
return df
|
||||
|
||||
def mocked_read_data(*args, **kwargs):
|
||||
df = pl.read_csv('rowers/tests/testdata/colsfromdb.csv')
|
||||
|
||||
return df
|
||||
|
||||
def mocked_getsmallrowdata_db_updatecp(*args, **kwargs): # pragma: no cover
|
||||
df = pd.read_csv('rowers/tests/testdata/colsfromdb.csv')
|
||||
|
||||
@@ -351,8 +363,8 @@ def mocked_getsmallrowdata_db_water(*args, **kwargs): # pragma: no cover
|
||||
|
||||
return df
|
||||
|
||||
def mocked_getsmallrowdata_db_wps(*args, **kwargs): # pragma: no cover
|
||||
df = pd.read_csv('rowers/tests/testdata/driveenergies.csv')
|
||||
def mocked_read_data_wps(*args, **kwargs): # pragma: no cover
|
||||
df = pl.read_csv('rowers/tests/testdata/driveenergies.csv')
|
||||
|
||||
return df
|
||||
|
||||
@@ -384,7 +396,7 @@ def mocked_read_cols_df_sql(*args, **kwargs):
|
||||
|
||||
|
||||
def mock_workout_summaries(*args, **kwargs):
|
||||
df = pd.read_csv('rowers/tests/testdata/workout_summaries.csv')
|
||||
df = pl.read_csv('rowers/tests/testdata/workout_summaries.csv')
|
||||
return df
|
||||
|
||||
def mocked_read_df_cols_sql_multi(ids, columns, convertnewtons=True): # pragma: no cover
|
||||
|
||||
@@ -65,6 +65,7 @@ from nose.tools import assert_true
|
||||
from mock import Mock, patch
|
||||
#from minimocktest import MockTestCase
|
||||
import pandas as pd
|
||||
import polars as pl
|
||||
import rowers.c2stuff as c2stuff
|
||||
|
||||
import rowers.rojabo_stuff as rojabo_stuff
|
||||
|
||||
@@ -43,10 +43,10 @@ class ListWorkoutTest(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('rowers.dataprep.myqueue')
|
||||
def test_list_workouts(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mocked_myqueue):
|
||||
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
@@ -169,8 +169,8 @@ class ForcecurveTest(TestCase):
|
||||
pass
|
||||
|
||||
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect = mocked_getempowerdata_db)
|
||||
def test_forcecurve_plot(self, mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect = mocked_read_data)
|
||||
def test_forcecurve_plot(self, mocked_read_data):
|
||||
login = self.c.login(username=self.u.username, password = self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -296,9 +296,9 @@ class WorkoutCompareTestNew(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_workouts_compare(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -309,9 +309,9 @@ class WorkoutCompareTestNew(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_workouts_compare_submit(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -398,9 +398,9 @@ class WorkoutBoxPlotTestNew(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_workouts_boxplot(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -411,9 +411,9 @@ class WorkoutBoxPlotTestNew(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_workouts_boxplot_submit(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -499,9 +499,9 @@ class WorkoutHistoTestNew(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_workouts_histo(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -512,9 +512,9 @@ class WorkoutHistoTestNew(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_workouts_histo_submit(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -600,9 +600,9 @@ class History(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_workouts_history(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -618,9 +618,9 @@ class History(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_workouts_history_submit(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -713,9 +713,9 @@ class GoldMedalScores(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_workouts_goldmedalscores(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
ws = Workout.objects.filter(rankingpiece=True)
|
||||
self.assertEqual(ws.count(),2)
|
||||
@@ -729,9 +729,9 @@ class GoldMedalScores(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_workouts_goldmedalscores_submit(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -795,9 +795,9 @@ class WorkoutFlexallTestNew(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_workouts_flexall(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -808,9 +808,9 @@ class WorkoutFlexallTestNew(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_workouts_flexall_submit(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -903,9 +903,9 @@ class WorkoutStatsTestNew(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_workouts_stats(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -916,11 +916,11 @@ class WorkoutStatsTestNew(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect=mocked_read_cols_df_sql)
|
||||
def test_analysis_data(self,
|
||||
mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mocked_read_cols_df_sql,
|
||||
):
|
||||
|
||||
@@ -979,11 +979,11 @@ class WorkoutStatsTestNew(TestCase):
|
||||
script, div = comparisondata(workouts,options)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect=mocked_read_cols_df_sql)
|
||||
def test_analysis_data2(self,
|
||||
mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mocked_read_cols_df_sql,
|
||||
):
|
||||
|
||||
@@ -1042,11 +1042,11 @@ class WorkoutStatsTestNew(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect=mocked_read_cols_df_sql)
|
||||
def test_analysis_data2(self,
|
||||
mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mocked_read_cols_df_sql,
|
||||
):
|
||||
|
||||
@@ -1120,9 +1120,9 @@ class WorkoutStatsTestNew(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_workouts_stats_submit(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -1241,9 +1241,9 @@ class MarkerPerformanceTest(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_create_marker_workouts(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -1257,8 +1257,8 @@ class MarkerPerformanceTest(TestCase):
|
||||
|
||||
self.assertRedirects(response, expected_url=expected_url, status_code=302,target_status_code=200)
|
||||
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_uh)
|
||||
def test_trainingzones_view(self,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_getsmallrowdata_uh)
|
||||
def test_trainingzones_view(self,mocked_getsmallrowdata_uh):
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -1326,9 +1326,9 @@ class MarkerPerformanceTest(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_performancemanager_view(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -1356,36 +1356,6 @@ class MarkerPerformanceTest(TestCase):
|
||||
response = self.c.post(url,form_data)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_ranking_view2(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
startdate = (self.user_workouts[0].startdatetime-datetime.timedelta(days=3)).date()
|
||||
enddate = (self.user_workouts[0].startdatetime+datetime.timedelta(days=3)).date()
|
||||
|
||||
url = reverse('rankings_view2')
|
||||
response = self.c.get(url)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
form_data = {
|
||||
'startdate':startdate.strftime("%Y-%m-%d"),
|
||||
'enddate': enddate.strftime("%Y-%m-%d"),
|
||||
'doform': True,
|
||||
'dofatigue': True,
|
||||
'metricchoice':'rscore',
|
||||
'modelchoice': 'coggan',
|
||||
'daterange': '',
|
||||
}
|
||||
form = DateRangeForm(form_data)
|
||||
if not form.is_valid():
|
||||
print(form.errors)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
class AlertTest(TestCase):
|
||||
def setUp(self):
|
||||
@@ -1443,9 +1413,9 @@ class AlertTest(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.alerts.getsmallrowdata_db')
|
||||
@patch('rowers.alerts.read_data')
|
||||
def test_alerts(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
|
||||
@@ -58,6 +58,8 @@ class OwnApi(TestCase):
|
||||
response = self.c.get(url)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
with patch('rowers.dataprep.read_data') as mock_read_data:
|
||||
mock_read_data.return_value = pl.read_csv('rowers/tests/testdata/colsfromdb.csv')
|
||||
url = reverse('strokedatajson',kwargs={'id':w.id})
|
||||
|
||||
request = self.factory.get(url)
|
||||
@@ -67,10 +69,11 @@ class OwnApi(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
# response must be json
|
||||
strokedata = json.loads(response.content)
|
||||
df = pd.DataFrame(strokedata)
|
||||
|
||||
self.assertFalse(df.empty)
|
||||
strokedata = json.loads(response.content)
|
||||
df = pl.from_dict(strokedata)
|
||||
|
||||
self.assertFalse(df.is_empty())
|
||||
|
||||
form_data = {
|
||||
"distance": [23, 46, 48],
|
||||
@@ -119,13 +122,16 @@ class OwnApi(TestCase):
|
||||
request = self.factory.get(url)
|
||||
request.user = self.u
|
||||
force_authenticate(request, user=self.u)
|
||||
with patch('rowers.dataprep.read_data') as mock_read_data:
|
||||
mock_read_data.return_value = pl.read_csv('rowers/tests/testdata/colsfromdb.csv')
|
||||
response = strokedatajson_v2(request,id=w.id)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
# response must be json
|
||||
strokedata = json.loads(response.content)
|
||||
df = pd.DataFrame(strokedata)
|
||||
self.assertFalse(df.empty)
|
||||
df = pl.from_dicts(strokedata['data'])
|
||||
|
||||
self.assertFalse(df.is_empty())
|
||||
|
||||
|
||||
form_data = {
|
||||
|
||||
@@ -484,54 +484,10 @@ class AsyncTaskTests(TestCase):
|
||||
res = tasks.handle_c2_import_stroke_data(c2token,c2id,workoutid,starttimeunix,csvfilename)
|
||||
self.assertEqual(res,1)
|
||||
|
||||
@patch('rowers.tasks.grpc',side_effect=mocked_grpc)
|
||||
@patch('rowers.tasks.send_template_email',side_effect=mocked_send_template_email)
|
||||
def test_handle_otwsetpower(self,mocked_send_template_email,mocked_grpc):
|
||||
f1 = get_random_file(filename='rowers/tests/testdata/sprintervals.csv')['filename']
|
||||
boattype = '1x'
|
||||
boatclass = 'water'
|
||||
coastalbrand = 'other'
|
||||
weightvalue = 80.
|
||||
first_name = self.u.first_name
|
||||
last_name = self.u.last_name
|
||||
email = self.u.email
|
||||
workoutid = self.wwater.id
|
||||
job = fakerequest()
|
||||
|
||||
res = tasks.handle_otwsetpower(f1,boattype,boatclass,coastalbrand,
|
||||
weightvalue,first_name,last_name,email,workoutid,
|
||||
jobkey='23')
|
||||
|
||||
self.assertEqual(res,1)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
def test_handle_updateergcp(self,mocked_sqlalchemy):
|
||||
f1 = get_random_file()['filename']
|
||||
res = tasks.handle_updateergcp(1,[f1])
|
||||
self.assertEqual(res,1)
|
||||
|
||||
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_handle_updatecp(self,mocked_getsmallrowdata_db_updatecp):
|
||||
rower_id = 1
|
||||
workoutids = [1]
|
||||
res = tasks.handle_updatecp(rower_id,workoutids)
|
||||
self.assertEqual(res,1)
|
||||
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_handle_setcp(self,mocked_getsmallrowdata_db_setcp):
|
||||
strokesdf = pd.read_csv('rowers/tests/testdata/uhfull.csv')
|
||||
filename = 'rowers/tests/testdata/temp/pq.gz'
|
||||
workoutids = 1
|
||||
res = tasks.handle_setcp(strokesdf,filename,1)
|
||||
self.assertEqual(res,1)
|
||||
try:
|
||||
os.remove(filename)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_handle_update_wps(self,mocked_getsmallrowdata_db_wps):
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_handle_update_wps(self,mocked_read_data_wps):
|
||||
ids = [1,2,3]
|
||||
|
||||
result = tasks.handle_update_wps(self.r.id,['water'],ids,mode='water')
|
||||
|
||||
+33
-178
@@ -62,10 +62,10 @@ class ListWorkoutTest(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('rowers.dataprep.myqueue')
|
||||
def test_list_workouts(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mocked_myqueue):
|
||||
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
@@ -87,10 +87,10 @@ class ListWorkoutTest(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('rowers.dataprep.myqueue')
|
||||
def test_bulk_workouts(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mocked_myqueue):
|
||||
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
@@ -234,9 +234,9 @@ class WorkoutViewTest(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('rowers.middleware.myqueue')
|
||||
def test_forcecurve(self, mocked_sqlalchemy, mocked_getsmallrowdata_db,
|
||||
def test_forcecurve(self, mocked_sqlalchemy, mocked_read_data,
|
||||
mocked_myqueue):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -255,9 +255,9 @@ class WorkoutViewTest(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('rowers.middleware.myqueue')
|
||||
def test_resample(self, mocked_sqlalchemy, mocked_getsmallrowdata_db,
|
||||
def test_resample(self, mocked_sqlalchemy, mocked_read_data,
|
||||
mocked_myqueue):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -283,9 +283,9 @@ class WorkoutViewTest(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_joins(self, mocked_sqlalchemy, mocked_getsmallrowdata_db):
|
||||
def test_joins(self, mocked_sqlalchemy, mocked_read_data):
|
||||
with transaction.atomic():
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -350,10 +350,10 @@ class WorkoutViewTest(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('rowers.weather.requests.get', side_effect=mocked_requests)
|
||||
def test_waterworkout_view(self,
|
||||
mocked_sqlalchemy, mocked_getsmallrowdata_db, mocked_requests):
|
||||
mocked_sqlalchemy, mocked_read_data, mocked_requests):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -362,22 +362,6 @@ class WorkoutViewTest(TestCase):
|
||||
response = self.c.get(url)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
url = reverse('workout_downloadmetar_view',kwargs={
|
||||
'id': encoder.encode_hex(self.wwater.id),
|
||||
'airportcode': 'LKHO'
|
||||
}
|
||||
)
|
||||
|
||||
response = self.c.get(url,follow=True)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
url = reverse('workout_downloadwind_view',kwargs={
|
||||
'id': encoder.encode_hex(self.wwater.id),
|
||||
}
|
||||
)
|
||||
|
||||
response = self.c.get(url,follow=True)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
# Stacked Flex Chart
|
||||
url = reverse('workout_flexchart_stacked_view',kwargs={
|
||||
@@ -422,8 +406,8 @@ class WorkoutViewTest(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_smoothen(self, mocked_sqlalchemy, mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_smoothen(self, mocked_sqlalchemy, mocked_read_data):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -459,125 +443,12 @@ class WorkoutViewTest(TestCase):
|
||||
status_code=302,target_status_code=200)
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_windform(self, mocked_sqlalchemy, mocked_getsmallrowdata_db):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
|
||||
url = reverse('workout_wind_view',kwargs={'id':encoder.encode_hex(self.wwater.id)})
|
||||
|
||||
response = self.c.get(url)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
form_data = {
|
||||
'dist1':1000,
|
||||
'dist2':2000,
|
||||
'vwind1':2.0,
|
||||
'vwind2':1.4,
|
||||
'windunit':'m',
|
||||
'winddirection1': 0,
|
||||
'winddirection2': 90,
|
||||
}
|
||||
|
||||
form = UpdateWindForm(form_data)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_streamform(self, mocked_sqlalchemy, mocked_getsmallrowdata_db):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
|
||||
url = reverse('workout_stream_view',kwargs={'id':encoder.encode_hex(self.wwater.id)})
|
||||
|
||||
response = self.c.get(url)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
form_data = {
|
||||
'dist1':1000,
|
||||
'dist2':2000,
|
||||
'stream1':2.0,
|
||||
'stream2':1.4,
|
||||
'streamunit':'m',
|
||||
}
|
||||
|
||||
form = UpdateStreamForm(form_data)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.middleware.myqueue')
|
||||
def test_setpowerform(self, mocked_sqlalchemy, mocked_getsmallrowdata_db,
|
||||
mocked_myqueue):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
url = reverse('instroke_view',kwargs={'id':encoder.encode_hex(self.winstroke.id)})
|
||||
|
||||
response = self.c.get(url)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
rowdata = rowingdata.rowingdata(csvfile=self.winstroke.csvfilename)
|
||||
instrokemetrics = rowdata.get_instroke_columns()
|
||||
|
||||
self.assertTrue(len(instrokemetrics)>0)
|
||||
|
||||
url = reverse('instroke_chart',
|
||||
kwargs={
|
||||
'id':encoder.encode_hex(self.winstroke.id),
|
||||
'metric':instrokemetrics[0],
|
||||
})
|
||||
url2 = reverse(self.r.defaultlandingpage,kwargs={'id':encoder.encode_hex(self.winstroke.id)})
|
||||
response = self.c.get(url)
|
||||
self.assertRedirects(response,
|
||||
expected_url=url2,
|
||||
status_code=302,target_status_code=200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_setpowerform(self, mocked_sqlalchemy, mocked_getsmallrowdata_db):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
|
||||
url = reverse('workout_otwsetpower_view',kwargs={'id':encoder.encode_hex(self.wwater.id)})
|
||||
|
||||
response = self.c.get(url)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
form_data = {
|
||||
'quick_calc':True,
|
||||
'boattype': '1x',
|
||||
'weightvalue': 75.0,
|
||||
'boatbrand':'maas',
|
||||
}
|
||||
|
||||
form = AdvancedWorkoutForm(form_data)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data,follow=True)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
expected_url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(self.wwater.id)})
|
||||
|
||||
self.assertRedirects(response,
|
||||
expected_url=expected_url,
|
||||
status_code=302,target_status_code=200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_commentview(self, mocked_sqlalchemy, mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_commentview(self, mocked_sqlalchemy, mocked_read_data):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -602,8 +473,8 @@ class WorkoutViewTest(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_mapview(self, mocked_sqlalchemy, mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_mapview(self, mocked_sqlalchemy, mocked_read_data):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -614,9 +485,9 @@ class WorkoutViewTest(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def notworking_test_workout_image(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -642,10 +513,10 @@ class WorkoutViewTest(TestCase):
|
||||
status_code=302,target_status_code=200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('rowers.dataprep.getrowdata_db',side_effect=mocked_getrowdata_db)
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_workout_split(self, mocked_sqlalchemy, mocked_getsmallrowdata_db,
|
||||
def test_workout_split(self, mocked_sqlalchemy, mocked_read_data,
|
||||
mocked_getrowdata_db):
|
||||
with transaction.atomic():
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
@@ -670,9 +541,9 @@ class WorkoutViewTest(TestCase):
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getrowdata_db',side_effect=mocked_getrowdata_db)
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_forfusion)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_getsmallrowdata_forfusion)
|
||||
def test_workout_fusion(self, mocked_sqlalchemy, mocked_getrowdata_db,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -699,27 +570,11 @@ class WorkoutViewTest(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
|
||||
def test_remove_power_view(self):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
url = reverse('remove_power_view',kwargs={'id':encoder.encode_hex(self.wwater.id)})
|
||||
url2 = reverse(self.r.defaultlandingpage,
|
||||
kwargs={
|
||||
'id':encoder.encode_hex(self.wwater.id)
|
||||
}
|
||||
)
|
||||
response = self.c.get(url)
|
||||
self.assertRedirects(response,
|
||||
expected_url=url2,
|
||||
status_code=302,
|
||||
target_status_code=200
|
||||
)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('rowers.dataprep.get_video_data',side_effect=mocked_videodata)
|
||||
def test_workout_video_view(self, mocked_sqlalchemy, mocked_getsmallrowdata_db,
|
||||
def test_workout_video_view(self, mocked_sqlalchemy, mocked_read_data,
|
||||
mocked_videodata):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -779,9 +634,9 @@ class WorkoutViewTest(TestCase):
|
||||
self.assertRedirects(response,expected_url=expected_url,status_code=302,target_status_code=200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('rowers.dataprep.get_video_data',side_effect=mocked_videodata)
|
||||
def test_workout_video_view_erg(self, mocked_sqlalchemy, mocked_getsmallrowdata_db,
|
||||
def test_workout_video_view_erg(self, mocked_sqlalchemy, mocked_read_data,
|
||||
mocked_videodata):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -843,7 +698,7 @@ class WorkoutViewTest(TestCase):
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getrowdata_db',side_effect=mocked_getrowdata_db)
|
||||
@patch('rowers.dataprep.get_video_data',side_effect=mocked_videodata)
|
||||
def test_video_selectworkout(self, mocked_sqlalchemy, mocked_getsmallrowdata_db,
|
||||
def test_video_selectworkout(self, mocked_sqlalchemy, mocked_read_data,
|
||||
mocked_videodata):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
@@ -874,8 +729,8 @@ class WorkoutViewTest(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_editsummaryview(self, mocked_sqlalchemy, mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_editsummaryview(self, mocked_sqlalchemy, mocked_read_data):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -940,8 +795,8 @@ class WorkoutViewTest(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_workout_delete(self, mocked_sqlalchemy, mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_workout_delete(self, mocked_sqlalchemy, mocked_read_data):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
|
||||
@@ -166,65 +166,3 @@ class CPChartTest(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
|
||||
@patch('rowers.dataprep.fetchcperg', side_effect = mocked_fetchcperg)
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
def test_rankingpieces(self, mocked_fetchcperg, mocked_sqlalchemy):
|
||||
url = '/rowers/ote-bests2/'
|
||||
|
||||
login = self.c.login(username=self.u.username,password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
# update_records(url='rowers/tests/c2worldrecords.html',verbose=False)
|
||||
|
||||
form_data = {
|
||||
'name': faker.word(),
|
||||
'date': nu.date(),
|
||||
'timezone': 'UTC',
|
||||
'duration': '00:02:00.0',
|
||||
'starttime': '10:01:43',
|
||||
'distance': 500,
|
||||
'workouttype': 'rower',
|
||||
'boattype': '1x',
|
||||
'weightcategory': 'hwt',
|
||||
'adaptiveclass': 'None',
|
||||
'notes': faker.text(),
|
||||
'rankingpiece': True,
|
||||
'duplicate': False,
|
||||
'avghr': '160',
|
||||
'avgpwr': 0,
|
||||
'avgspm': 40,
|
||||
}
|
||||
|
||||
url2 = '/rowers/workout/addmanual/'
|
||||
|
||||
response = self.c.post(url2, form_data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
form_data['distance'] = 100
|
||||
form_data['duration'] = '00:00:18.5'
|
||||
|
||||
response = self.c.post(url2, form_data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
form_data['distance'] = 2000
|
||||
form_data['duration'] = '00:06:56.5'
|
||||
response = self.c.post(url2, form_data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
form_data['distance'] = 5000
|
||||
form_data['duration'] = '00:20:48.0'
|
||||
response = self.c.post(url2, form_data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
form_data['distance'] = 6000
|
||||
form_data['duration'] = '00:22:17.6'
|
||||
response = self.c.post(url2, form_data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
form_data['distance'] = 10000
|
||||
form_data['duration'] = '00:38:16.5'
|
||||
response = self.c.post(url2, form_data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
response = self.c.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
@@ -55,8 +55,8 @@ class EmailUpload(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_uploadapi(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_uploadapi(self,mocked_sqlalchemy,mocked_read_data):
|
||||
form_data = {
|
||||
'title': 'test',
|
||||
'workouttype':'rower',
|
||||
@@ -108,8 +108,8 @@ class EmailUpload(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_uploadapi2(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_uploadapi2(self,mocked_sqlalchemy,mocked_read_data):
|
||||
form_data = {"secret": settings.UPLOAD_SERVICE_SECRET,
|
||||
"user": 1,
|
||||
"file": 'media/mailbox_attachments/colin3.csv',
|
||||
@@ -140,8 +140,8 @@ class EmailUpload(TestCase):
|
||||
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_uploadapi3(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_uploadapi3(self,mocked_sqlalchemy,mocked_read_data):
|
||||
with transaction.atomic():
|
||||
form_data = {
|
||||
'title': 'test',
|
||||
@@ -167,8 +167,8 @@ class EmailUpload(TestCase):
|
||||
self.assertEqual(w.notes,'aap noot mies')
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_uploadapi_credentials(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_uploadapi_credentials(self,mocked_sqlalchemy,mocked_read_data):
|
||||
form_data = {
|
||||
'title': 'test',
|
||||
'workouttype':'rower',
|
||||
|
||||
@@ -103,8 +103,8 @@ class WorkoutViewTest(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_flexchart_water(self, mocked_sqlalechemy, mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_flexchart_water(self, mocked_sqlalechemy, mocked_read_data):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -151,8 +151,8 @@ class WorkoutViewTest(TestCase):
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
def test_flexchart_erg(self, mocked_sqlalechemy, mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_flexchart_erg(self, mocked_sqlalechemy, mocked_read_data):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
self.assertTrue(login)
|
||||
|
||||
|
||||
@@ -720,8 +720,8 @@ class NKObjects(DjangoTestCase):
|
||||
)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_nk_intervals(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_nk_intervals(self,mocked_sqlalchemy,mocked_read_data):
|
||||
with open('rowers/tests/testdata/carlos_workout.json','r') as f:
|
||||
workoutdata = json.load(f)
|
||||
with open('rowers/tests/testdata/carlos_strokes.json','r') as f:
|
||||
@@ -817,10 +817,10 @@ class NKObjects(DjangoTestCase):
|
||||
@patch('rowers.integrations.nk.requests.get', side_effect=mocked_requests)
|
||||
@patch('rowers.integrations.nk.requests.post', side_effect=mocked_requests)
|
||||
@patch('rowers.nkimportutils.requests.session', side_effect=mocked_session)
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_nk_import(self, mock_get, mock_post,
|
||||
mocked_session,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
integration = NKIntegration(self.u)
|
||||
result = integration.token_refresh()
|
||||
@@ -854,10 +854,10 @@ class NKObjects(DjangoTestCase):
|
||||
@patch('rowers.integrations.nk.requests.get', side_effect=mocked_requests)
|
||||
@patch('rowers.integrations.nk.requests.post', side_effect=mocked_requests)
|
||||
@patch('rowers.nkimportutils.requests.session', side_effect=mocked_session)
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_nk_import_task(self, mock_get, mock_post,
|
||||
mocked_session,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
alldata = {
|
||||
469: {'elapsedTime': 3901900,
|
||||
'totalDistanceImp': 0,
|
||||
@@ -904,10 +904,10 @@ class NKObjects(DjangoTestCase):
|
||||
@patch('rowers.integrations.nk.requests.get', side_effect=mocked_requests)
|
||||
@patch('rowers.integrations.nk.requests.post', side_effect=mocked_requests)
|
||||
@patch('rowers.nkimportutils.requests.session', side_effect=mocked_session)
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_nk_import_impeller(self, mock_get, mock_post,
|
||||
mocked_session,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
integration = NKIntegration(self.u)
|
||||
result = integration.token_refresh()
|
||||
@@ -1083,9 +1083,9 @@ class RP3Objects(DjangoTestCase):
|
||||
|
||||
@patch('rowers.integrations.rp3.requests.get', side_effect=mocked_requests)
|
||||
@patch('rowers.integrations.rp3.requests.post', side_effect=mocked_requests)
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_rp3_import(self, mock_get, mockpost,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
response = self.c.get('/rowers/workout/rp3import/591621',follow=True)
|
||||
|
||||
@@ -1268,9 +1268,9 @@ class StravaObjects(DjangoTestCase):
|
||||
|
||||
@patch('rowers.utils.requests.get', side_effect=mocked_requests)
|
||||
@patch('rowers.integrations.strava.requests.post', side_effect=mocked_requests)
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
def test_strava_import(self, mock_get, mock_post,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
|
||||
response = self.c.get('/rowers/workout/stravaimport/12',follow=True)
|
||||
expected_url = reverse('workout_import_view',kwargs={'source':'strava'})
|
||||
@@ -1307,7 +1307,7 @@ class STObjects(DjangoTestCase):
|
||||
|
||||
|
||||
self.r.sporttrackstoken = '12'
|
||||
self.r.sporttracksrefreshtoken = '12'
|
||||
self.r.sporttroacksrefreshtoken = '12'
|
||||
self.r.sporttrackstokenexpirydate = arrow.get(datetime.datetime.now()+datetime.timedelta(days=1)).datetime
|
||||
self.r.save()
|
||||
|
||||
|
||||
@@ -51,16 +51,16 @@ class InteractiveChartTest(TestCase):
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_interactive_chart1(self, mocked_sqlalchemy,mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
res = iplots.interactive_chart(self.wote.id)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_interactive_chart2(self, mocked_sqlalchemy,mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
res = iplots.interactive_chart(self.wote.id,promember=1)
|
||||
|
||||
|
||||
@@ -80,52 +80,52 @@ class InteractiveChartTest(TestCase):
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_interactive_chart7(self, mocked_sqlalchemy,mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
res = iplots.interactive_flex_chart2(self.wote.id,self.r,promember=0,
|
||||
xparam='time',
|
||||
yparam1='pace',yparam2='spm',mode='water')
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_interactive_chart8(self, mocked_sqlalchemy,mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
res = iplots.interactive_flex_chart2(self.wote.id,self.r,
|
||||
promember=0,xparam='distance',
|
||||
yparam1='pace',yparam2='spm',mode='water')
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_interactive_chart9(self, mocked_sqlalchemy,mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
res = iplots.interactive_flex_chart2(self.wote.id,self.r,
|
||||
promember=1,xparam='time',
|
||||
yparam1='pace',yparam2='hr',mode='water')
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_interactive_chart10(self, mocked_sqlalchemy,mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
res = iplots.interactive_flex_chart2(self.wote.id,self.r,
|
||||
promember=1,xparam='distance',
|
||||
yparam1='pace',yparam2='hr',mode='water')
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_interactive_chart11(self, mocked_sqlalchemy,mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
res = iplots.interactive_flex_chart2(self.wote.id,self.r,
|
||||
promember=1,xparam='time',
|
||||
yparam1='pace',yparam2='spm',mode='water')
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_interactive_chart12(self, mocked_sqlalchemy,mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
res = iplots.interactive_flex_chart2(self.wote.id,self.r,
|
||||
promember=1,
|
||||
xparam='distance',
|
||||
|
||||
@@ -911,8 +911,8 @@ class PermissionsViewTests(TestCase):
|
||||
|
||||
## Coach can upload on behalf of athlete - if team allows
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_coach_edit_athlete_upload(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_coach_edit_athlete_upload(self,mocked_sqlalchemy,mocked_read_data):
|
||||
self.rbasic.team.add(self.teamcoach)
|
||||
self.rbasic.coachinggroups.add(self.coachinggroup)
|
||||
|
||||
@@ -957,8 +957,8 @@ class PermissionsViewTests(TestCase):
|
||||
|
||||
## Coach can upload on behalf of athlete - if team allows
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_coach_edit_athlete_uploadnot(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_coach_edit_athlete_uploadnot(self,mocked_sqlalchemy,mocked_read_data):
|
||||
self.rbasic.team.add(self.teamcoach)
|
||||
|
||||
login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword)
|
||||
@@ -1168,8 +1168,8 @@ class PermissionsViewTests(TestCase):
|
||||
|
||||
## Self Coach cannot upload on behalf of athlete
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_plan_edit_athlete_upload(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_plan_edit_athlete_upload(self,mocked_sqlalchemy,mocked_read_data):
|
||||
self.rpro.team.add(self.teamplan)
|
||||
|
||||
login = self.c.login(username=self.uplan2.username, password=self.uplan2password)
|
||||
@@ -1291,8 +1291,8 @@ class PermissionsViewTests(TestCase):
|
||||
|
||||
## Self Coach cannot upload on behalf of athlete
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_plan_edit_athlete_upload(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_plan_edit_athlete_upload(self,mocked_sqlalchemy,mocked_read_data):
|
||||
self.rpro.team.add(self.teamplan)
|
||||
|
||||
login = self.c.login(username=self.uplan2.username, password=self.uplan2password)
|
||||
|
||||
@@ -218,7 +218,7 @@ class PermissionsViewTests(TestCase):
|
||||
@patch('rowers.integrations.c2.C2Integration.open')
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('requests.get',side_effect=mocked_requests)
|
||||
@patch('requests.post',side_effect=mocked_requests)
|
||||
@patch('rowers.dataprep.get_video_data',side_effect=mocked_get_video_data)
|
||||
@@ -228,7 +228,7 @@ class PermissionsViewTests(TestCase):
|
||||
mock_c2open,
|
||||
mocked_sqlalchemy,
|
||||
mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mock_get,
|
||||
mock_post,
|
||||
mocked_get_video_data,
|
||||
@@ -253,7 +253,7 @@ class PermissionsViewTests(TestCase):
|
||||
@patch('rowers.integrations.c2.C2Integration.open')
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('requests.get',side_effect=mocked_requests)
|
||||
@patch('requests.post',side_effect=mocked_requests)
|
||||
@patch('rowers.dataprep.get_video_data',side_effect=mocked_get_video_data)
|
||||
@@ -263,7 +263,7 @@ class PermissionsViewTests(TestCase):
|
||||
mock_c2open,
|
||||
mocked_sqlalchemy,
|
||||
mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mock_get,
|
||||
mock_post,
|
||||
mocked_get_video_data,
|
||||
@@ -335,7 +335,7 @@ class PermissionsViewTests(TestCase):
|
||||
@patch('rowers.integrations.c2.C2Integration.open')
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('requests.get',side_effect=mocked_requests)
|
||||
@patch('requests.post',side_effect=mocked_requests)
|
||||
@patch('rowers.dataprep.get_video_data',side_effect=mocked_get_video_data)
|
||||
@@ -345,7 +345,7 @@ class PermissionsViewTests(TestCase):
|
||||
mock_c2open,
|
||||
mocked_sqlalchemy,
|
||||
mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mock_get,
|
||||
mock_post,
|
||||
mocked_get_video_data,
|
||||
@@ -418,7 +418,7 @@ class PermissionsViewTests(TestCase):
|
||||
@patch('rowers.integrations.c2.C2Integration.open')
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('requests.get',side_effect=mocked_requests)
|
||||
@patch('requests.post',side_effect=mocked_requests)
|
||||
@patch('rowers.dataprep.get_video_data',side_effect=mocked_get_video_data)
|
||||
@@ -428,7 +428,7 @@ class PermissionsViewTests(TestCase):
|
||||
mock_c2open,
|
||||
mocked_sqlalchemy,
|
||||
mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mock_get,
|
||||
mock_post,
|
||||
mocked_get_video_data,
|
||||
|
||||
@@ -13,6 +13,7 @@ from django.db import transaction
|
||||
nu = datetime.datetime.now()
|
||||
import datetime
|
||||
import pytz
|
||||
import polars as pl
|
||||
|
||||
# interactive plots
|
||||
from rowers import interactiveplots
|
||||
@@ -581,7 +582,7 @@ class DataPrepTests(TestCase):
|
||||
age = dataprep.calculate_age(born,today=today)
|
||||
self.assertEqual(age,49)
|
||||
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_uh)
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_getsmallrowdata_uh)
|
||||
def test_goldmedalstandard(self,mocked_getsmallrowdata_uh):
|
||||
maxvalue, delta = dataprep.calculate_goldmedalstandard(self.r,self.wuh_otw)
|
||||
records = CalcAgePerformance.objects.filter(
|
||||
@@ -596,8 +597,8 @@ class DataPrepTests(TestCase):
|
||||
result = getagegrouprecord(25)
|
||||
self.assertEqual(int(result),590)
|
||||
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_uh)
|
||||
def test_get_videodata(self,mocked_getsmallrowdata_uh):
|
||||
@patch('rowers.dataprep.getsmallrowdata_pd',side_effect=mocked_getsmallrowdata_uh_pd)
|
||||
def test_get_videodata(self,mocked_getsmallrowdata_uh_pd):
|
||||
data, metrics, maxtime = dataprep.get_video_data(self.wuh_otw)
|
||||
|
||||
self.assertEqual(len(data),9)
|
||||
@@ -659,7 +660,7 @@ class InteractivePlotTests(TestCase):
|
||||
pass
|
||||
|
||||
def test_interactive_hr_piechart(self):
|
||||
df = pd.read_csv('rowers/tests/testdata/getrowdata_mock.csv')
|
||||
df = pl.read_csv('rowers/tests/testdata/getrowdata_mock.csv')
|
||||
|
||||
script, div = interactiveplots.interactive_hr_piechart(df, self.r,'')
|
||||
self.assertFalse(len(script)==0)
|
||||
@@ -672,7 +673,8 @@ class InteractivePlotTests(TestCase):
|
||||
self.assertFalse(len(div)==0)
|
||||
|
||||
def test_interactive_boxchart(self):
|
||||
df = pd.read_csv('rowers/tests/testdata/boxplotdata.csv')
|
||||
df = pl.read_csv('rowers/tests/testdata/boxplotdata.csv')
|
||||
df = df.with_columns(pl.col("date").str.to_datetime("%Y-%m-%d"))
|
||||
|
||||
script, div = interactiveplots.interactive_boxchart(df, 'spm')
|
||||
|
||||
@@ -685,12 +687,12 @@ class InteractivePlotTests(TestCase):
|
||||
|
||||
startdate = workouts[0].date-datetime.timedelta(days=5)
|
||||
enddate = workouts2[0].date+datetime.timedelta(days=5)
|
||||
script, div = interactiveplots.interactive_activitychart(workouts,startdate,enddate)
|
||||
script, div = interactiveplots.interactive_activitychart2(workouts,startdate,enddate)
|
||||
self.assertFalse(len(script)==0)
|
||||
self.assertFalse(len(div)==0)
|
||||
|
||||
def test_interactive_otwcpchart(self):
|
||||
df = pd.read_csv('rowers/tests/testdata/otwcp.csv')
|
||||
df = pl.read_csv('rowers/tests/testdata/otwcp.csv')
|
||||
|
||||
script, div, p1, ratio, message = interactiveplots.interactive_otwcpchart(df,r=self.r,cpfit='data')
|
||||
self.assertFalse(len(script)==0)
|
||||
@@ -701,9 +703,9 @@ class InteractivePlotTests(TestCase):
|
||||
self.assertFalse(len(div)==0)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_interactive_chart(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
workout = Workout.objects.filter(user=self.r,workouttype__in=mytypes.rowtypes)[0]
|
||||
id = workout.id
|
||||
|
||||
@@ -733,12 +735,12 @@ class InteractivePlotTests(TestCase):
|
||||
self.assertFalse(len(div)==0)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
|
||||
@patch('rowers.dataprep.read_data', side_effect=mocked_read_data)
|
||||
def test_interactive_flexchart_stacked(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db):
|
||||
mocked_read_data):
|
||||
workout = Workout.objects.filter(user=self.r,workouttype__in=mytypes.rowtypes)[0]
|
||||
id = workout.id
|
||||
|
||||
script, div, js_res, css_res, comment = interactiveplots.interactive_flexchart_stacked(id,self.r)
|
||||
script, div = interactiveplots.interactive_flexchart_stacked(id,self.r)
|
||||
self.assertFalse(len(script)==0)
|
||||
self.assertFalse(len(div)==0)
|
||||
|
||||
@@ -71,9 +71,10 @@ class ForceUnits(TestCase):
|
||||
w = Workout.objects.get(id=1)
|
||||
self.assertEqual(w.forceunit,'lbs')
|
||||
|
||||
df = dataprep.getsmallrowdata_db(['averageforce'],ids=[13])
|
||||
df = dataprep.read_data(['averageforce'],ids=[13])
|
||||
df = dataprep.remove_nulls_pl(df)
|
||||
average_N = int(df['averageforce'].mean())
|
||||
self.assertEqual(average_N,398)
|
||||
self.assertEqual(average_N,400)
|
||||
|
||||
data = dataprep.read_df_sql(13)
|
||||
average_N = int(data['averageforce'].mean())
|
||||
@@ -119,9 +120,10 @@ class ForceUnits(TestCase):
|
||||
w = Workout.objects.get(id=13)
|
||||
self.assertEqual(w.forceunit,'N')
|
||||
|
||||
df = dataprep.getsmallrowdata_db(['averageforce'],ids=[13])
|
||||
df = dataprep.read_data(['averageforce'],ids=[13])
|
||||
df = dataprep.remove_nulls_pl(df)
|
||||
average_N = int(df['averageforce'].mean())
|
||||
self.assertEqual(average_N,263)
|
||||
self.assertEqual(average_N,271)
|
||||
|
||||
def test_upload_speedcoach_colin(self):
|
||||
login = self.c.login(username=self.u.username, password=self.password)
|
||||
@@ -155,9 +157,10 @@ class ForceUnits(TestCase):
|
||||
w = Workout.objects.get(id=13)
|
||||
self.assertEqual(w.forceunit,'N')
|
||||
|
||||
df = dataprep.getsmallrowdata_db(['averageforce'],ids=[13])
|
||||
df = dataprep.read_data(['averageforce'],ids=[13])
|
||||
df = dataprep.remove_nulls_pl(df)
|
||||
average_N = int(df['averageforce'].mean())
|
||||
self.assertEqual(average_N,105)
|
||||
self.assertEqual(average_N,122)
|
||||
|
||||
@override_settings(TESTING=True)
|
||||
class TestForceUnit(TestCase):
|
||||
@@ -206,7 +209,7 @@ class TestForceUnit(TestCase):
|
||||
|
||||
rowdata = dataprep.rdata('rowers/tests/testdata/PainsledForce.csv')
|
||||
df = dataprep.dataprep(rowdata.df)
|
||||
#df = dataprep.getsmallrowdata_db(['averageforce'],ids=[w[0].id],doclean=False,
|
||||
#df = dataprep.read_data(['averageforce'],ids=[w[0].id],doclean=False,
|
||||
# compute=False)
|
||||
try:
|
||||
average_N = int(df['averageforce'].mean())
|
||||
|
||||
@@ -29,8 +29,8 @@ class ViewTest(TestCase):
|
||||
self.nu = datetime.datetime.now()
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_upload_view_sled(self, mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_upload_view_sled(self, mocked_sqlalchemy,mocked_read_data):
|
||||
login = self.c.login(username='john',password='koeinsloot')
|
||||
self.assertTrue(login)
|
||||
|
||||
@@ -74,10 +74,6 @@ class ViewTest(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
response = self.c.get('/rowers/workout/'+encoded1+'/histo/', form_data, follow=True)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
f.close()
|
||||
|
||||
|
||||
@@ -124,8 +120,8 @@ class ViewTest(TestCase):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_upload_view_sled_bg(self, mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
@patch('rowers.dataprep.read_data',side_effect=mocked_read_data)
|
||||
def test_upload_view_sled_bg(self, mocked_sqlalchemy,mocked_read_data):
|
||||
login = self.c.login(username='john',password='koeinsloot')
|
||||
self.assertTrue(login)
|
||||
|
||||
|
||||
@@ -79,11 +79,6 @@ class URLTests(TestCase):
|
||||
'/rowers/502/',
|
||||
'/rowers/about/',
|
||||
'/rowers/workout/addmanual/',
|
||||
'/rowers/agegroupcp/30/',
|
||||
'/rowers/agegroupcp/30/1/',
|
||||
'/rowers/agegrouprecords/male/hwt/',
|
||||
'/rowers/agegrouprecords/male/hwt/2000m/',
|
||||
'/rowers/agegrouprecords/male/hwt/30min/',
|
||||
'/rowers/ajax_agegroup/45/hwt/male/1/',
|
||||
'/rowers/analysis/',
|
||||
'/rowers/analysis/user/1/',
|
||||
@@ -122,8 +117,6 @@ class URLTests(TestCase):
|
||||
'/rowers/me/workflowconfig2/',
|
||||
'/rowers/me/workflowconfig2/user/1/',
|
||||
'/rowers/me/workflowdefault/',
|
||||
'/rowers/ote-bests2/',
|
||||
'/rowers/ote-bests2/user/1/',
|
||||
'/rowers/partners/',
|
||||
'/rowers/physics/',
|
||||
'/rowers/planrequired/',
|
||||
@@ -148,29 +141,23 @@ class URLTests(TestCase):
|
||||
'/rowers/workout/'+encoded1+'/addtimeplot/',
|
||||
'/rowers/workout/'+encoded1+'/addtimeplot2/',
|
||||
'/rowers/workout/'+encoded1+'/comment/',
|
||||
'/rowers/workout/'+encoded1+'/darkskywind/',
|
||||
'/rowers/workout/'+encoded1+'/data/',
|
||||
'/rowers/workout/'+encoded1+'/edit/',
|
||||
'/rowers/workout/'+encoded1+'/editintervals/',
|
||||
'/rowers/workout/'+encoded1+'/flexchart/',
|
||||
'/rowers/workout/'+encoded1+'/forcecurve/',
|
||||
'/rowers/workout/'+encoded1+'/get-thumbnails/',
|
||||
'/rowers/workout/'+encoded1+'/histo/',
|
||||
'/rowers/workout/'+encoded1+'/image/',
|
||||
'/rowers/workout/'+encoded1+'/instroke/',
|
||||
'/rowers/workout/'+encoded1+'/interactiveotwplot/',
|
||||
'/rowers/workout/'+encoded1+'/map/',
|
||||
'/rowers/workout/'+encoded1+'/otwsetpower/',
|
||||
'/rowers/workout/'+encoded1+'/recalcsummary/',
|
||||
'/rowers/workout/'+encoded1+'/restore/',
|
||||
'/rowers/workout/'+encoded1+'/smoothenpace/',
|
||||
'/rowers/workout/'+encoded1+'/split/',
|
||||
'/rowers/workout/'+encoded1+'/stats/',
|
||||
'/rowers/workout/'+encoded1+'/stream/',
|
||||
'/rowers/workout/'+encoded1+'/undosmoothenpace/',
|
||||
'/rowers/workout/'+encoded1+'/unsubscribe/',
|
||||
'/rowers/workout/'+encoded1+'/view/',
|
||||
'/rowers/workout/'+encoded1+'/wind/',
|
||||
'/rowers/workout/'+encoded1+'/workflow/',
|
||||
'/rowers/workout/fusion/'+encoded1+'/',
|
||||
'/rowers/workout/upload/',
|
||||
@@ -206,7 +193,7 @@ class URLTests(TestCase):
|
||||
@parameterized.expand(lijst)
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.read_df_sql')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_data')
|
||||
@patch('requests.get',side_effect=mocked_requests)
|
||||
@patch('requests.post',side_effect=mocked_requests)
|
||||
@patch('rowers.dataprep.get_video_data',side_effect=mocked_get_video_data)
|
||||
@@ -214,7 +201,7 @@ class URLTests(TestCase):
|
||||
def test_url_generator(self,url,expected,
|
||||
mocked_sqlalchemy,
|
||||
mocked_read_df_sql,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_read_data,
|
||||
mock_get,
|
||||
mock_post,
|
||||
mocked_get_video_data,
|
||||
|
||||
BIN
Binary file not shown.
@@ -1,9 +1,7 @@
|
||||
,id,view,function,anonymous,anonymous_response,own,own_response,own_nonperm,member,member_response,member_nonperm,coachee,coachee_response,coachee_nonperm,is_staff,userid,workoutid,dotest,realtest,kwargs
|
||||
0,0,workouts_summaries_email_view,sends summary excel with workouts list and links to data to user,TRUE,302,basic,200,302,FALSE,403,403,FALSE,403,403,FALSE,FALSE,FALSE,TRUE,TRUE,
|
||||
1,1,rower_update_empower_view,updates old Empower Oarlock files (corrects Power bug),TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE,TRUE,
|
||||
2,2,agegroupcpview,needs age,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE,
|
||||
3,4,ajax_agegrouprecords,gets age group records from C2 ,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE,
|
||||
5,6,agegrouprecordview,shows ergo age group records,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE,TRUE,
|
||||
6,7,workouts_view,workouts list,TRUE,302,basic,200,302,basic,200,403,coach,200,403,FALSE,TRUE,FALSE,TRUE,TRUE,
|
||||
7,8,virtualevents_view,virtual races list,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE,TRUE,
|
||||
8,9,virtualevent_create_view,create virtual event,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE,TRUE,
|
||||
@@ -31,7 +29,6 @@
|
||||
33,35,kill_async_job,kill job,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE,
|
||||
34,36,post_progress,post progress,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE,
|
||||
35,37,graphs_view,view charts,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,TRUE,TRUE,
|
||||
38,40,rankings_view2,view ranking,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,TRUE,TRUE,
|
||||
41,43,cum_flex,flex all chart,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE,
|
||||
42,44,analysis_view_data,redirects to analysis direct,TRUE,302,pro,200,302,pro,200,302,coach,200,302,FALSE,FALSE,FALSE,TRUE,TRUE,
|
||||
43,47,cum_flex_data,flex all chart data (json),TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE,
|
||||
@@ -43,7 +40,6 @@
|
||||
52,58,workout_toggle_ranking,toggle ranking,TRUE,302,basic,302,302,basic,403,302,coach,302,302,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
53,59,team_workout_upload_view,upload workout for team member,TRUE,302,coach,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE,TRUE,
|
||||
54,60,workout_upload_view,upload a workout,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE,TRUE,
|
||||
55,61,workout_histo_view,histogram ,TRUE,302,basic,200,302,basic,403,403,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
56,62,workout_forcecurve_view,force curve,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
57,63,workout_unsubscribe_view,unsubscribe from comments,TRUE,302,basic,200,302,basic,200,302,basic,200,302,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
58,64,workout_comment_view,comment on workout,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
@@ -57,17 +53,11 @@
|
||||
67,73,instroke_view,Create in stroke chart,TRUE,403,basic,200,302,basic,403,403,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
68,74,workout_stats_view,View Workout Stats,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
69,75,workout_data_view,shows the detailed data for a workout,TRUE,403,basic,200,403,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
70,76,workout_otwsetpower_view,set weight and start offline OTW power calculations,TRUE,403,pro,200,302,pro,403,403,coach,200,403,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
71,77,workout_otwpowerplot_view,generates OTW power chart,TRUE,200,basic,200,200,basic,200,200,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
72,78,workout_wind_view,set wind,TRUE,403,pro,200,302,pro,403,403,coach,200,403,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
73,79,workout_uploadimage_view,upload image,TRUE,403,basic,200,403,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
74,80,virtualevent_compare_view,compare workouts from a virtual event,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE,
|
||||
75,81,virtualevent_uploadimage_view,upload image to virtual event,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE,
|
||||
76,82,virtualevent_setlogo_view,set logo of virtual event,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE,
|
||||
77,83,logo_delete_view,delete logo,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE,
|
||||
78,84,workout_downloadwind_view,download Wind,TRUE,403,pro,302,302,pro,403,403,coach,302,403,FALSE,FALSE,TRUE,FALSE,FALSE,
|
||||
79,85,workout_downloadmetar_view,download METAR,TRUE,403,pro,200,302,pro,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,FALSE,
|
||||
80,86,workout_stream_view,edit stream (redirects as no data in test suite),TRUE,403,pro,200,302,pro,403,403,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
81,87,workout_summary_edit_view,edit workout summary,TRUE,302,basic,200,403,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
82,88,workout_summary_restore_view,restore workout summary,TRUE,403,basic,302,403,basic,403,403,coach,302,403,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
83,89,workout_split_view,split workout,TRUE,403,pro,200,302,pro,403,403,coach,200,302,FALSE,FALSE,TRUE,TRUE,TRUE,
|
||||
|
||||
|
+2
-23
@@ -273,19 +273,13 @@ urlpatterns = [
|
||||
re_path(r'^exportallworkouts/?/$', views.workouts_summaries_email_view,
|
||||
name='workouts_summaries_email_view'),
|
||||
path('failedjobs/', views.failed_queue_view, name='failed_queue_view'),
|
||||
path('sleep/', views.sleep_view, name='sleep_view'),
|
||||
path('filmdeaths/', views.filmdeaths_view, name='filmdeaths_view'),
|
||||
path('failedjobs/empty/', views.failed_queue_empty, name='failed_queue_empty'),
|
||||
re_path('^failedjobs/(?P<id>\w+.*)/$',
|
||||
views.failed_job_view, name='failed_job_view'),
|
||||
re_path(r'^update_empower/$', views.rower_update_empower_view,
|
||||
name='rower_update_empower_view'),
|
||||
re_path(r'^agegroupcp/(?P<age>\d+)/$',
|
||||
views.agegroupcpview, name='agegroupcpview'),
|
||||
re_path(r'^agegroupcp/(?P<age>\d+)/user/(?P<userid>\d+)/$',
|
||||
views.agegroupcpview, name='agegroupcpview'),
|
||||
re_path(r'^agegroupcp/(?P<age>\d+)/(?P<normalize>\d+)/$',
|
||||
views.agegroupcpview, name='agegroupcpview'),
|
||||
re_path(r'^agegroupcp/(?P<age>\d+)/(?P<normalize>\d+)/user/(?P<userid>\d+)/$',
|
||||
views.agegroupcpview, name='agegroupcpview'),
|
||||
re_path(r'^ajax_agegroup/(?P<age>\d+)/(?P<weightcategory>\w+.*)/(?P<sex>\w+.*)/(?P<userid>\d+)/$',
|
||||
views.ajax_agegrouprecords, name='ajax_agegrouprecords'),
|
||||
re_path(r'^agegrouprecords/(?P<sex>\w+.*)/(?P<weightcategory>\w+.*)/(?P<distance>\d+)m/$',
|
||||
@@ -448,9 +442,6 @@ urlpatterns = [
|
||||
views.trainingzones_view_data, name="trainingzones_view_data"),
|
||||
re_path(r'^trainingzones/data/$', views.trainingzones_view_data,
|
||||
name="trainingzones_view_data"),
|
||||
re_path(r'^ote-bests2/user/(?P<userid>\d+)/$',
|
||||
views.rankings_view2, name='rankings_view2'),
|
||||
re_path(r'^ote-bests2/$', views.rankings_view2, name='rankings_view2'),
|
||||
re_path(r'^analysisdata/user/(?P<userid>\d+)/$', views.analysis_view_data,
|
||||
name='analysis_view_data'),
|
||||
re_path(r'^analysisdata/$', views.analysis_view_data,
|
||||
@@ -475,8 +466,6 @@ urlpatterns = [
|
||||
views.workout_upload_view, name='workout_upload_view'),
|
||||
re_path(r'^workout/upload/$', views.workout_upload_view,
|
||||
name='workout_upload_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/histo/$', views.workout_histo_view,
|
||||
name='workout_histo_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/forcecurve/$', views.workout_forcecurve_view,
|
||||
name='workout_forcecurve_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/forcecurve/(?P<analysis>\d+)/$', views.workout_forcecurve_view,
|
||||
@@ -513,14 +502,6 @@ urlpatterns = [
|
||||
name='workout_erase_column_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/zeropower-confirm/$', views.remove_power_confirm_view,
|
||||
name='remove_power_confirm_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/zeropower/$', views.remove_power_view,
|
||||
name='remove_power_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/otwsetpower/$',
|
||||
views.workout_otwsetpower_view, name='workout_otwsetpower_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/interactiveotwplot/$',
|
||||
views.workout_otwpowerplot_view, name='workout_otwpowerplot_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/wind/$',
|
||||
views.workout_wind_view, name='workout_wind_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/image/$',
|
||||
views.workout_uploadimage_view, name='workout_uploadimage_view'),
|
||||
re_path(r'^virtualevent/(?P<id>\d+)/compare/$',
|
||||
@@ -543,8 +524,6 @@ urlpatterns = [
|
||||
views.workout_downloadwind_view, name='workout_downloadwind_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/metar/(?P<airportcode>\w+)/$',
|
||||
views.workout_downloadmetar_view, name='workout_downloadmetar_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/stream/$',
|
||||
views.workout_stream_view, name='workout_stream_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/editintervals/$', views.workout_summary_edit_view,
|
||||
name='workout_summary_edit_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/restore/$',
|
||||
|
||||
+20
-21
@@ -6,6 +6,8 @@ from django.utils import timezone
|
||||
import math
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import polars as pl
|
||||
from polars.exceptions import ColumnNotFoundError
|
||||
import colorsys
|
||||
from django.conf import settings
|
||||
import collections
|
||||
@@ -155,12 +157,7 @@ def get_call():
|
||||
call1 = random.choice(coxes_calls)
|
||||
call2 = random.choice(info_calls)
|
||||
|
||||
call = """<div id="id_sitready" class="successmessage">
|
||||
<p>
|
||||
%s (%s)
|
||||
</p>
|
||||
</div>
|
||||
""" % (call1, call2)
|
||||
call = """<div id="id_sitready" class="successmessage"><p>%s (%s)</p></div>""" % (call1, call2)
|
||||
|
||||
return call
|
||||
|
||||
@@ -347,22 +344,22 @@ def isbreakthrough(delta, cpvalues, p0, p1, p2, p3, ratio):
|
||||
|
||||
pwr *= ratio
|
||||
|
||||
delta = delta.astype(int, errors='ignore').values
|
||||
cpvalues = cpvalues.astype(int, errors='ignore').values
|
||||
pwr = pwr.astype(int, errors='ignore').values
|
||||
delta = delta.cast(pl.Int32)
|
||||
cpvalues = cpvalues.cast(pl.Int32)
|
||||
pwr = pwr.cast(pl.Int32)
|
||||
|
||||
res = np.sum(cpvalues > pwr+1)
|
||||
res2 = np.sum(cpvalues > pwr2+1)
|
||||
btdf = pl.DataFrame({
|
||||
'delta': delta,
|
||||
'cpvalues': cpvalues,
|
||||
'pwr': pwr,
|
||||
'pwr2': pwr2
|
||||
})
|
||||
|
||||
btdf = pd.DataFrame(
|
||||
{
|
||||
'delta': delta[cpvalues > pwr],
|
||||
'cpvalues': cpvalues[cpvalues > pwr],
|
||||
'pwr': pwr[cpvalues > pwr],
|
||||
}
|
||||
)
|
||||
res = btdf.select(pl.col("cpvalues")>pl.col("pwr")+1)['cpvalues'].sum()
|
||||
res2 = btdf.select(pl.col("cpvalues")> pl.col("pwr2")+1)['cpvalues'].sum()
|
||||
|
||||
btdf.sort_values('delta', axis=0, inplace=True)
|
||||
btdf = btdf.filter(pl.col("cpvalues")>pl.col("pwr"))
|
||||
btdf = btdf.sort('delta')
|
||||
|
||||
return res >= 1, btdf, res2 >= 1
|
||||
|
||||
@@ -444,17 +441,19 @@ def wavg(group, avg_name, weight_name):
|
||||
"""
|
||||
try:
|
||||
d = group[avg_name]
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
return 0
|
||||
try:
|
||||
w = group[weight_name]
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
return d.mean()
|
||||
try:
|
||||
return (d * w).sum() / w.sum()
|
||||
except ZeroDivisionError: # pragma: no cover
|
||||
return d.mean()
|
||||
|
||||
return 0
|
||||
|
||||
from string import Formatter
|
||||
|
||||
def totaltime_sec_to_string(totaltime, shorten=False):
|
||||
|
||||
+67
-598
@@ -296,7 +296,10 @@ def analysis_new(request,
|
||||
df = cpdata(tw, options)
|
||||
options['savedata'] = False
|
||||
request.session['options'] = options
|
||||
try:
|
||||
response = HttpResponse(df.to_csv())
|
||||
except AttributeError:
|
||||
response = HttpResponse(df.write_csv())
|
||||
code = str(uuid4())
|
||||
filename = code+'.csv'
|
||||
chartform.fields['savedata'].initial = False
|
||||
@@ -384,6 +387,9 @@ def trendflexdata(workouts, options, userid=0):
|
||||
datadf = dataprep.filter_df(datadf, 'driveneergy', workmax,
|
||||
largerthan=False)
|
||||
|
||||
if yparam == 'power':
|
||||
datadf = dataprep.filter_df(datadf, 'power', 1, largerthan=True)
|
||||
|
||||
datadf.dropna(axis=0, how='any', inplace=True)
|
||||
|
||||
datemapping = {
|
||||
@@ -472,8 +478,8 @@ def trendflexdata(workouts, options, userid=0):
|
||||
'groupsize': groupsize,
|
||||
})
|
||||
|
||||
if yparam == 'pace':
|
||||
df['y'] = dataprep.paceformatsecs(df['y']/1.0e3)
|
||||
#if yparam == 'pace':
|
||||
# df['y'] = dataprep.paceformatsecs(df['y']/1.0e3)
|
||||
|
||||
aantal = len(df)
|
||||
|
||||
@@ -568,7 +574,7 @@ def flexalldata(workouts, options):
|
||||
workstrokesonly = not includereststrokes
|
||||
columns = [xparam, yparam1, yparam2, 'spm', 'driveenergy', 'distance']
|
||||
ids = [int(w.id) for w in workouts]
|
||||
df = dataprep.getsmallrowdata_db(columns, ids=ids,
|
||||
df = dataprep.read_data(columns, ids=ids,
|
||||
workstrokesonly=workstrokesonly,
|
||||
doclean=True,
|
||||
)
|
||||
@@ -609,7 +615,7 @@ def histodata(workouts, options):
|
||||
if savedata: # pragma: no cover
|
||||
workstrokesonly = not includereststrokes
|
||||
ids = [int(w.id) for w in workouts]
|
||||
df = dataprep.getsmallrowdata_db([plotfield], ids=ids,
|
||||
df = dataprep.read_data([plotfield], ids=ids,
|
||||
workstrokesonly=workstrokesonly,
|
||||
doclean=True,
|
||||
)
|
||||
@@ -625,6 +631,7 @@ def histodata(workouts, options):
|
||||
|
||||
|
||||
def cpdata(workouts, options):
|
||||
start = timezone.now()
|
||||
userid = options['userid']
|
||||
cpfit = options['cpfit']
|
||||
cpoverlay = options['cpoverlay']
|
||||
@@ -635,7 +642,7 @@ def cpdata(workouts, options):
|
||||
delta, cpvalue, avgpower, workoutnames, urls = dataprep.fetchcp_new(
|
||||
r, workouts)
|
||||
|
||||
powerdf = pd.DataFrame({
|
||||
powerdf = pl.DataFrame({
|
||||
'Delta': delta,
|
||||
'CP': cpvalue,
|
||||
'workout': workoutnames,
|
||||
@@ -644,16 +651,17 @@ def cpdata(workouts, options):
|
||||
|
||||
savedata = options.get('savedata',False)
|
||||
if savedata: # pragma: no cover
|
||||
return powerdf
|
||||
return powerdf.to_pandas()
|
||||
|
||||
if powerdf.empty: # pragma: no cover
|
||||
if powerdf.is_empty(): # pragma: no cover
|
||||
return('', '<p>No valid data found</p>')
|
||||
|
||||
|
||||
powerdf = powerdf[powerdf['CP'] > 0]
|
||||
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)
|
||||
powerdf = powerdf.lazy().filter(pl.col("CP")>0)
|
||||
powerdf = powerdf.sort(["Delta", "CP"], descending=[False, True])
|
||||
powerdf = powerdf.unique(subset="Delta", keep="first")
|
||||
powerdf = powerdf.fill_nan(None).drop_nulls()
|
||||
powerdf = powerdf.collect()
|
||||
|
||||
rowername = r.user.first_name+" "+r.user.last_name
|
||||
|
||||
@@ -880,7 +888,7 @@ def comparisondata(workouts, options):
|
||||
'time', 'pace', 'workoutstate',
|
||||
'workoutid']
|
||||
|
||||
df = dataprep.getsmallrowdata_db(columns, ids=ids,
|
||||
df = dataprep.read_data(columns, ids=ids,
|
||||
workstrokesonly=workstrokesonly,
|
||||
doclean=True,
|
||||
)
|
||||
@@ -923,28 +931,22 @@ def boxplotdata(workouts, options):
|
||||
ids = [w.id for w in workouts]
|
||||
|
||||
# prepare data frame
|
||||
datadf, extracols = dataprep.read_cols_df_sql(ids, fieldlist)
|
||||
datadf = dataprep.read_data(fieldlist, ids)
|
||||
|
||||
datadf = dataprep.clean_df_stats(datadf, workstrokesonly=workstrokesonly)
|
||||
datadf = dataprep.remove_nulls_pl(datadf)
|
||||
|
||||
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)
|
||||
try:
|
||||
datadf = datadf.filter(
|
||||
pl.col("spm")>spmmin,
|
||||
pl.col("spm")<spmmax,
|
||||
pl.col("driveenergy")>workmin,
|
||||
pl.col("driveenergy")<workmax,
|
||||
)
|
||||
except ColumnNotFoundError:
|
||||
pass
|
||||
|
||||
datadf.dropna(axis=0, how='any', inplace=True)
|
||||
datadf = datadf[datadf['workoutid'].isin(ids) == True]
|
||||
|
||||
datadf['workoutid'].replace(datemapping, inplace=True)
|
||||
datadf.rename(columns={"workoutid": "date"}, inplace=True)
|
||||
|
||||
datadf['date'] = pd.to_datetime(datadf['date'], errors='coerce')
|
||||
datadf = datadf.dropna(subset=['date'])
|
||||
datadf = datadf.sort_values(['date'])
|
||||
datadf = datadf.with_columns((pl.col("workoutid").apply(lambda x: datemapping[x])).alias("date"))
|
||||
|
||||
if userid == 0: # pragma: no cover
|
||||
extratitle = ''
|
||||
@@ -954,7 +956,7 @@ def boxplotdata(workouts, options):
|
||||
|
||||
savedata = options.get('savedata',False)
|
||||
if savedata: # pragma: no cover
|
||||
return datadf
|
||||
return datadf.to_pandas()
|
||||
|
||||
script, div = interactive_boxchart(datadf, plotfield,
|
||||
extratitle=extratitle,
|
||||
@@ -1149,9 +1151,6 @@ def trainingzones_view(request, userid=0):
|
||||
form = TrainingZonesForm({
|
||||
'startdate': startdate,
|
||||
'enddate': enddate,
|
||||
'zones': zones,
|
||||
'dates': date_agg,
|
||||
'yaxis': yaxis,
|
||||
})
|
||||
|
||||
if request.method == 'POST': # pragma: no cover
|
||||
@@ -1160,9 +1159,6 @@ def trainingzones_view(request, userid=0):
|
||||
if form.is_valid():
|
||||
startdate = form.cleaned_data['startdate']
|
||||
enddate = form.cleaned_data['enddate']
|
||||
zones = form.cleaned_data['zones']
|
||||
date_agg = form.cleaned_data['dates']
|
||||
yaxis = form.cleaned_data['yaxis']
|
||||
|
||||
if date_agg == 'week':
|
||||
startdate = startdate - datetime.timedelta(days=startdate.weekday())
|
||||
@@ -1234,12 +1230,16 @@ def trainingzones_view_data(request, userid=0):
|
||||
request.GET.get('enddate'), "%Y-%m-%d")
|
||||
enddate = arrow.get(enddate).datetime
|
||||
|
||||
data = get_zones_report(r, startdate, enddate,
|
||||
if (enddate-startdate).days > 200:
|
||||
date_agg = "month"
|
||||
|
||||
data = get_zones_report_pl(r, startdate, enddate,
|
||||
trainingzones=zones, date_agg=date_agg, yaxis=yaxis)
|
||||
|
||||
script, div = interactive_zoneschart(
|
||||
script, div = interactive_zoneschart2(
|
||||
r, data, startdate, enddate, trainingzones=zones, date_agg=date_agg, yaxis=yaxis)
|
||||
|
||||
|
||||
return JSONResponse({
|
||||
'script': script,
|
||||
'div': div,
|
||||
@@ -1384,547 +1384,6 @@ def ajax_agegrouprecords(request,
|
||||
)
|
||||
|
||||
|
||||
# Show ranking distances including predicted paces
|
||||
@login_required()
|
||||
@permission_required('rower.is_coach', fn=get_user_by_userid, raise_exception=True)
|
||||
def rankings_view2(request, userid=0,
|
||||
startdate=timezone.now()-datetime.timedelta(days=365),
|
||||
enddate=timezone.now(),
|
||||
deltadays=-1,
|
||||
startdatestring="",
|
||||
enddatestring=""):
|
||||
|
||||
if deltadays > 0: # pragma: no cover
|
||||
startdate = enddate-datetime.timedelta(days=int(deltadays))
|
||||
|
||||
if startdatestring != "": # pragma: no cover
|
||||
startdate = iso8601.parse_date(startdatestring)
|
||||
|
||||
if enddatestring != "": # pragma: no cover
|
||||
enddate = iso8601.parse_date(enddatestring)
|
||||
|
||||
if enddate < startdate: # pragma: no cover
|
||||
s = enddate
|
||||
enddate = startdate
|
||||
startdate = s
|
||||
|
||||
if userid == 0:
|
||||
userid = request.user.id
|
||||
else:
|
||||
lastupdated = "1900-01-01"
|
||||
|
||||
promember = 0
|
||||
r = getrequestrower(request, userid=userid)
|
||||
theuser = r.user
|
||||
|
||||
wcdurations = []
|
||||
wcpower = []
|
||||
|
||||
lastupdated = "1900-01-01"
|
||||
userid = 0
|
||||
if 'options' in request.session:
|
||||
options = request.session['options']
|
||||
try:
|
||||
wcdurations = options['wcdurations']
|
||||
wcpower = options['wcpower']
|
||||
lastupdated = options['lastupdated']
|
||||
except KeyError: # pragma: no cover
|
||||
pass
|
||||
try:
|
||||
userid = options['userid']
|
||||
except KeyError: # pragma: no cover
|
||||
userid = 0
|
||||
else:
|
||||
options = {}
|
||||
|
||||
lastupdatedtime = arrow.get(lastupdated).timestamp()
|
||||
current_time = arrow.utcnow().timestamp()
|
||||
|
||||
deltatime_seconds = current_time - lastupdatedtime
|
||||
recalc = False
|
||||
if str(userid) != str(theuser) or deltatime_seconds > 3600:
|
||||
recalc = True
|
||||
options['lastupdated'] = arrow.utcnow().isoformat()
|
||||
else: # pragma: no cover
|
||||
recalc = False
|
||||
|
||||
options['userid'] = theuser.id
|
||||
|
||||
if r.birthdate:
|
||||
age = calculate_age(r.birthdate)
|
||||
else:
|
||||
age = 0
|
||||
|
||||
agerecords = CalcAgePerformance.objects.filter(
|
||||
age=age,
|
||||
sex=r.sex,
|
||||
weightcategory=r.weightcategory)
|
||||
|
||||
if len(agerecords) == 0:
|
||||
recalc = True
|
||||
wcpower = []
|
||||
wcdurations = []
|
||||
else:
|
||||
wcdurations = []
|
||||
wcpower = []
|
||||
for record in agerecords:
|
||||
wcdurations.append(record.duration)
|
||||
wcpower.append(record.power)
|
||||
|
||||
options['wcpower'] = wcpower
|
||||
options['wcdurations'] = wcdurations
|
||||
if theuser:
|
||||
options['userid'] = theuser.id
|
||||
|
||||
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)
|
||||
deltaform = DeltaDaysForm(request.POST)
|
||||
if dateform.is_valid():
|
||||
startdate = dateform.cleaned_data['startdate']
|
||||
enddate = dateform.cleaned_data['enddate']
|
||||
if startdate > enddate: # pragma: no cover
|
||||
s = enddate
|
||||
enddate = startdate
|
||||
startdate = s
|
||||
elif request.method == 'POST' and "datedelta" in request.POST: # pragma: no cover
|
||||
deltaform = DeltaDaysForm(request.POST)
|
||||
if deltaform.is_valid():
|
||||
deltadays = deltaform.cleaned_data['deltadays']
|
||||
if deltadays:
|
||||
enddate = timezone.now()
|
||||
startdate = enddate-datetime.timedelta(days=deltadays)
|
||||
if startdate > enddate:
|
||||
s = enddate
|
||||
enddate = startdate
|
||||
startdate = s
|
||||
dateform = DateRangeForm(initial={
|
||||
'startdate': startdate,
|
||||
'enddate': enddate,
|
||||
})
|
||||
else:
|
||||
dateform = DateRangeForm()
|
||||
deltaform = DeltaDaysForm()
|
||||
|
||||
else:
|
||||
dateform = DateRangeForm(initial={
|
||||
'startdate': startdate,
|
||||
'enddate': enddate,
|
||||
})
|
||||
deltaform = DeltaDaysForm()
|
||||
|
||||
# get all 2k (if any) - this rower, in date range
|
||||
try:
|
||||
r = getrower(theuser)
|
||||
except Rower.DoesNotExist: # pragma: no cover
|
||||
r = 0
|
||||
|
||||
uu = theuser
|
||||
|
||||
# test to fix bug
|
||||
startdate = datetime.datetime.combine(startdate, datetime.time())
|
||||
enddate = datetime.datetime.combine(enddate, datetime.time(23, 59, 59))
|
||||
startdate = arrow.get(startdate).datetime
|
||||
enddate = arrow.get(enddate).datetime
|
||||
|
||||
thedistances = []
|
||||
theworkouts = []
|
||||
thesecs = []
|
||||
|
||||
rankingdistances.sort()
|
||||
rankingdurations.sort()
|
||||
|
||||
for rankingdistance in rankingdistances:
|
||||
|
||||
workouts = Workout.objects.filter(
|
||||
user=r, distance=rankingdistance,
|
||||
workouttype__in=['rower', 'dynamic', 'slides'],
|
||||
rankingpiece=True,
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate).order_by('duration')
|
||||
if workouts:
|
||||
thedistances.append(rankingdistance)
|
||||
theworkouts.append(workouts[0])
|
||||
|
||||
timesecs = 3600*workouts[0].duration.hour
|
||||
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',
|
||||
rankingpiece=True,
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate).order_by('-distance')
|
||||
if workouts:
|
||||
thedistances.append(workouts[0].distance)
|
||||
theworkouts.append(workouts[0])
|
||||
|
||||
timesecs = 3600*workouts[0].duration.hour
|
||||
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)
|
||||
thesecs = np.array(thesecs)
|
||||
|
||||
thevelos = thedistances/thesecs
|
||||
theavpower = 2.8*(thevelos**3)
|
||||
|
||||
# create interactive plot
|
||||
if len(thedistances) != 0:
|
||||
res = interactive_cpchart(
|
||||
r, thedistances, thesecs, theavpower,
|
||||
theworkouts, promember=promember,
|
||||
wcdurations=wcdurations, wcpower=wcpower
|
||||
)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
paulslope = res[2]
|
||||
paulintercept = res[3]
|
||||
p1 = res[4]
|
||||
message = res[5]
|
||||
else:
|
||||
script = ''
|
||||
div = '<p>No ranking pieces found.</p>'
|
||||
paulslope = 1
|
||||
paulintercept = 1
|
||||
p1 = [1, 1, 1, 1]
|
||||
message = ""
|
||||
|
||||
if request.method == 'POST' and "piece" in request.POST: # pragma: no cover
|
||||
form = PredictedPieceForm(request.POST)
|
||||
if form.is_valid():
|
||||
value = form.cleaned_data['value']
|
||||
hourvalue, value = divmod(value, 60)
|
||||
if hourvalue >= 24:
|
||||
hourvalue = 23
|
||||
pieceunit = form.cleaned_data['pieceunit']
|
||||
if pieceunit == 'd':
|
||||
rankingdistances.append(value)
|
||||
else:
|
||||
rankingdurations.append(datetime.time(
|
||||
minute=int(value), hour=int(hourvalue)))
|
||||
else:
|
||||
form = PredictedPieceForm()
|
||||
|
||||
rankingdistances.sort()
|
||||
rankingdurations.sort()
|
||||
|
||||
predictions = []
|
||||
cpredictions = []
|
||||
|
||||
for rankingdistance in rankingdistances:
|
||||
# Paul's model
|
||||
p = paulslope*np.log10(rankingdistance)+paulintercept
|
||||
velo = 500./p
|
||||
t = rankingdistance/velo
|
||||
pwr = 2.8*(velo**3)
|
||||
try:
|
||||
pwr = int(pwr)
|
||||
except (ValueError, AttributeError): # pragma: no cover
|
||||
pwr = 0
|
||||
|
||||
a = {'distance': rankingdistance,
|
||||
'duration': timedeltaconv(t),
|
||||
'pace': timedeltaconv(p),
|
||||
'power': int(pwr)}
|
||||
predictions.append(a)
|
||||
|
||||
# CP model -
|
||||
pwr2 = p1[0]/(1+t/p1[2])
|
||||
pwr2 += p1[1]/(1+t/p1[3])
|
||||
|
||||
if pwr2 <= 0: # pragma: no cover
|
||||
pwr2 = 50.
|
||||
|
||||
velo2 = (pwr2/2.8)**(1./3.)
|
||||
|
||||
if np.isnan(velo2) or velo2 <= 0: # pragma: no cover
|
||||
velo2 = 1.0
|
||||
|
||||
t2 = rankingdistance/velo2
|
||||
|
||||
pwr3 = p1[0]/(1+t2/p1[2])
|
||||
pwr3 += p1[1]/(1+t2/p1[3])
|
||||
|
||||
if pwr3 <= 0: # pragma: no cover
|
||||
pwr3 = 50.
|
||||
|
||||
velo3 = (pwr3/2.8)**(1./3.)
|
||||
if np.isnan(velo3) or velo3 <= 0: # pragma: no cover
|
||||
velo3 = 1.0
|
||||
|
||||
t3 = rankingdistance/velo3
|
||||
p3 = 500./velo3
|
||||
|
||||
a = {'distance': rankingdistance,
|
||||
'duration': timedeltaconv(t3),
|
||||
'pace': timedeltaconv(p3),
|
||||
'power': int(pwr3)}
|
||||
cpredictions.append(a)
|
||||
|
||||
for rankingduration in rankingdurations:
|
||||
t = 3600.*rankingduration.hour
|
||||
t += 60.*rankingduration.minute
|
||||
t += rankingduration.second
|
||||
t += rankingduration.microsecond/1.e6
|
||||
|
||||
# Paul's model
|
||||
ratio = paulintercept/paulslope
|
||||
|
||||
u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/paulslope
|
||||
|
||||
d = 500*t*np.log(10.)
|
||||
d = d/(paulslope*lambertw(u))
|
||||
d = d.real
|
||||
|
||||
velo = d/t
|
||||
p = 500./velo
|
||||
pwr = 2.8*(velo**3)
|
||||
try:
|
||||
a = {'distance': int(d),
|
||||
'duration': timedeltaconv(t),
|
||||
'pace': timedeltaconv(p),
|
||||
'power': int(pwr)}
|
||||
predictions.append(a)
|
||||
except: # pragma: no cover
|
||||
pass
|
||||
|
||||
# CP model
|
||||
pwr = p1[0] / (1 + t / p1[2])
|
||||
pwr += p1[1] / (1 + t / p1[3])
|
||||
|
||||
if pwr <= 0: # pragma: no cover
|
||||
pwr = 50.
|
||||
|
||||
velo = (pwr / 2.8)**(1. / 3.)
|
||||
|
||||
if np.isnan(velo) or velo <= 0: # pragma: no cover
|
||||
velo = 1.0
|
||||
|
||||
d = t * velo
|
||||
p = 500. / velo
|
||||
a = {'distance': int(d),
|
||||
'duration': timedeltaconv(t),
|
||||
'pace': timedeltaconv(p),
|
||||
'power': int(pwr)}
|
||||
cpredictions.append(a)
|
||||
|
||||
if recalc:
|
||||
wcdurations = []
|
||||
wcpower = []
|
||||
durations = [1, 4, 30, 60]
|
||||
distances = [100, 500, 1000, 2000, 5000, 6000, 10000, 21097, 42195]
|
||||
|
||||
df = pd.DataFrame(
|
||||
list(
|
||||
C2WorldClassAgePerformance.objects.filter(
|
||||
sex=r.sex,
|
||||
weightcategory=r.weightcategory
|
||||
).values()
|
||||
)
|
||||
)
|
||||
|
||||
jsondf = df.to_json()
|
||||
|
||||
messages.error(request, message)
|
||||
return render(request, 'rankings.html',
|
||||
{'rankingworkouts': theworkouts,
|
||||
'interactiveplot': script,
|
||||
'the_div': div,
|
||||
'predictions': predictions,
|
||||
'cpredictions': cpredictions,
|
||||
'nrdata': len(thedistances),
|
||||
'form': form,
|
||||
'dateform': dateform,
|
||||
'deltaform': deltaform,
|
||||
'id': theuser,
|
||||
'theuser': uu,
|
||||
'rower': r,
|
||||
'active': 'nav-analysis',
|
||||
'age': age,
|
||||
'sex': r.sex,
|
||||
'recalc': recalc,
|
||||
'weightcategory': r.weightcategory,
|
||||
'startdate': startdate,
|
||||
'enddate': enddate,
|
||||
'teams': get_my_teams(request.user),
|
||||
})
|
||||
|
||||
|
||||
@login_required()
|
||||
def otecp_toadmin_view(request, theuser=0,
|
||||
startdate=timezone.now() - datetime.timedelta(days=365),
|
||||
enddate=timezone.now(),
|
||||
startdatestring="",
|
||||
enddatestring="",
|
||||
): # pragma: no cover
|
||||
|
||||
if startdatestring != "": # pragma: no cover
|
||||
try:
|
||||
startdate = iso8601.parse_date(startdatestring)
|
||||
except ParseError:
|
||||
pass
|
||||
|
||||
if enddatestring != "": # pragma: no cover
|
||||
try:
|
||||
enddate = iso8601.parse_date(enddatestring)
|
||||
except ParseError:
|
||||
pass
|
||||
|
||||
if theuser == 0: # pragma: no cover
|
||||
theuser = request.user.id
|
||||
|
||||
u = User.objects.get(id=theuser)
|
||||
r = Rower.objects.get(user=u)
|
||||
|
||||
startdate = datetime.datetime.combine(startdate, datetime.time())
|
||||
enddate = datetime.datetime.combine(enddate, datetime.time(23, 59, 59))
|
||||
|
||||
theworkouts = Workout.objects.filter(
|
||||
user=r, rankingpiece=True,
|
||||
workouttype__in=[
|
||||
'rower',
|
||||
'dynamic',
|
||||
'slides'
|
||||
],
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate
|
||||
).order_by("-startdatetime")
|
||||
|
||||
delta, cpvalue, avgpower = dataprep.fetchcp(
|
||||
r, theworkouts, table='cpergdata'
|
||||
)
|
||||
|
||||
powerdf = pd.DataFrame({
|
||||
'Delta': delta,
|
||||
'CP': cpvalue,
|
||||
})
|
||||
|
||||
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)
|
||||
powerdf.drop_duplicates(subset='Delta', keep='first', inplace=True)
|
||||
powerdf.to_csv(csvfilename)
|
||||
|
||||
_ = myqueue(queuehigh,
|
||||
handle_sendemailfile,
|
||||
'Sander',
|
||||
'Roosendaal',
|
||||
'roosendaalsander@gmail.com',
|
||||
csvfilename,
|
||||
delete=True)
|
||||
|
||||
successmessage = "The CSV file was sent to the site admin per email"
|
||||
messages.info(request, successmessage)
|
||||
response = HttpResponseRedirect('/rowers/list-workouts/')
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@login_required()
|
||||
def otwcp_toadmin_view(request, theuser=0,
|
||||
startdate=timezone.now() - datetime.timedelta(days=365),
|
||||
enddate=timezone.now(),
|
||||
startdatestring="",
|
||||
enddatestring="",
|
||||
): # pragma: no cover
|
||||
|
||||
if startdatestring != "":
|
||||
try:
|
||||
startdate = iso8601.parse_date(startdatestring)
|
||||
except ParseError:
|
||||
pass
|
||||
|
||||
if enddatestring != "":
|
||||
try:
|
||||
enddate = iso8601.parse_date(enddatestring)
|
||||
except ParseError:
|
||||
pass
|
||||
|
||||
if theuser == 0:
|
||||
theuser = request.user.id
|
||||
|
||||
u = User.objects.get(id=theuser)
|
||||
r = Rower.objects.get(user=u)
|
||||
|
||||
startdate = datetime.datetime.combine(startdate, datetime.time())
|
||||
enddate = datetime.datetime.combine(enddate, datetime.time(23, 59, 59))
|
||||
|
||||
theworkouts = Workout.objects.filter(
|
||||
user=r, rankingpiece=True,
|
||||
workouttype='water',
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate
|
||||
).order_by("-startdatetime")
|
||||
|
||||
delta, cpvalue, avgpower = dataprep.fetchcp(
|
||||
r, theworkouts, table='cpdata'
|
||||
)
|
||||
|
||||
powerdf = pd.DataFrame({
|
||||
'Delta': delta,
|
||||
'CP': cpvalue,
|
||||
})
|
||||
|
||||
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)
|
||||
powerdf.drop_duplicates(subset='Delta', keep='first', inplace=True)
|
||||
powerdf.to_csv(csvfilename)
|
||||
|
||||
_ = myqueue(queuehigh,
|
||||
handle_sendemailfile,
|
||||
'Sander',
|
||||
'Roosendaal',
|
||||
'roosendaalsander@gmail.com',
|
||||
csvfilename,
|
||||
delete=True)
|
||||
|
||||
successmessage = "The CSV file was sent to the site admin per email"
|
||||
messages.info(request, successmessage)
|
||||
response = HttpResponseRedirect('/rowers/list-workouts/')
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def agegroupcpview(request, age, normalize=0, userid=0):
|
||||
script, div = interactive_agegroupcpchart(age, normalized=normalize)
|
||||
|
||||
response = render(request, 'agegroupcp.html',
|
||||
{
|
||||
'active': 'nav-analysis',
|
||||
'interactiveplot': script,
|
||||
'the_div': div,
|
||||
}
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def agegrouprecordview(request, sex='male', weightcategory='hwt',
|
||||
distance=2000, duration=None):
|
||||
@@ -2761,15 +2220,16 @@ def history_view_data(request, userid=0):
|
||||
|
||||
ids = [w.id for w in g_workouts]
|
||||
|
||||
columns = ['hr', 'power', 'time']
|
||||
columns = ['hr', 'power', 'time', 'workoutstate', 'workoutid']
|
||||
|
||||
df = dataprep.read_data(columns, ids=ids)
|
||||
df = dataprep.remove_nulls_pl(df)
|
||||
|
||||
df = getsmallrowdata_db(columns, ids=ids)
|
||||
try:
|
||||
df['deltat'] = df['time'].diff().clip(lower=0)
|
||||
df = df.with_columns(pl.col('time').diff().clip(lower_bound=0).alias("deltat"))
|
||||
except KeyError: # pragma: no cover
|
||||
pass
|
||||
df = dataprep.clean_df_stats(df, workstrokesonly=True,
|
||||
ignoreadvanced=True, ignorehr=False)
|
||||
|
||||
|
||||
totalmeters, totalhours, totalminutes, totalseconds = get_totals(
|
||||
g_workouts)
|
||||
@@ -2798,13 +2258,14 @@ def history_view_data(request, userid=0):
|
||||
whours=whours,
|
||||
wminutes=wminutes, wseconds=wseconds,
|
||||
)
|
||||
ddf = getsmallrowdata_db(columns, ids=[w.id for w in a_workouts])
|
||||
ddf = dataprep.read_data(columns, ids=[w.id for w in a_workouts])
|
||||
ddf = dataprep.remove_nulls_pl(ddf)
|
||||
try:
|
||||
ddf['deltat'] = ddf['time'].diff().clip(lower=0)
|
||||
ddf = ddf.with_columns(pl.col("time").diff().clip(lower_bound=0).alias("deltat"))
|
||||
except KeyError: # pragma: no cover
|
||||
pass
|
||||
|
||||
ddf = dataprep.clean_df_stats(ddf, workstrokesonly=False,
|
||||
ddf = dataprep.clean_df_stats_pl(ddf, workstrokesonly=False,
|
||||
ignoreadvanced=True)
|
||||
|
||||
try:
|
||||
@@ -2812,14 +2273,14 @@ def history_view_data(request, userid=0):
|
||||
except (KeyError, ValueError, AttributeError): # pragma: no cover
|
||||
ddict['hrmean'] = 0
|
||||
try:
|
||||
ddict['hrmax'] = ddf['hr'].max().astype(int)
|
||||
ddict['hrmax'] = int(ddf['hr'].max())
|
||||
except (KeyError, ValueError, AttributeError): # pragma: no cover
|
||||
ddict['hrmax'] = 0
|
||||
|
||||
ddict['powermean'] = int(wavg(ddf, 'power', 'deltat'))
|
||||
try:
|
||||
ddict['powermax'] = ddf['power'].max().astype(int)
|
||||
except KeyError: # pragma: no cover
|
||||
ddict['powermax'] = int(ddf['power'].max())
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
ddict['powermax'] = 0
|
||||
ddict['nrworkouts'] = a_workouts.count()
|
||||
listofdicts.append(ddict)
|
||||
@@ -2833,14 +2294,14 @@ def history_view_data(request, userid=0):
|
||||
totalsdict['distance'] = totalmeters
|
||||
try:
|
||||
totalsdict['powermean'] = int(wavg(df, 'power', 'deltat'))
|
||||
totalsdict['powermax'] = df['power'].max().astype(int)
|
||||
except KeyError: # pragma: no cover
|
||||
totalsdict['powermax'] = int(df['power'].max())
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
totalsdict['powermean'] = 0
|
||||
totalsdict['powermax'] = 0
|
||||
try:
|
||||
totalsdict['hrmean'] = int(wavg(df, 'hr', 'deltat'))
|
||||
totalsdict['hrmax'] = df['hr'].max().astype(int)
|
||||
except KeyError: # pragma: no cover
|
||||
totalsdict['hrmax'] = int(df['hr'].max())
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
totalsdict['hrmean'] = 0
|
||||
totalsdict['hrmax'] = 0
|
||||
|
||||
@@ -2859,14 +2320,22 @@ def history_view_data(request, userid=0):
|
||||
a_workouts = g_workouts.filter(workouttype=typeselect)
|
||||
meters, hours, minutes, seconds = get_totals(a_workouts)
|
||||
totalseconds = 3600 * hours + 60 * minutes + seconds
|
||||
ddf = getsmallrowdata_db(columns, ids=[w.id for w in a_workouts])
|
||||
ddf = dataprep.read_data(columns, ids=[w.id for w in a_workouts])
|
||||
ddf = dataprep.remove_nulls_pl(ddf)
|
||||
if ddf.is_empty():
|
||||
totalscript = ""
|
||||
totaldiv = "No data"
|
||||
|
||||
try:
|
||||
ddf['deltat'] = ddf['time'].diff().clip(lower=0)
|
||||
ddf = ddf.with_columns(pl.col("time").diff().clip(lower_bound=0).alias("deltat"))
|
||||
except KeyError:
|
||||
pass
|
||||
except ColumnNotFoundError:
|
||||
totalscript = ""
|
||||
totaldiv = "No data"
|
||||
|
||||
ddf = dataprep.clean_df_stats(ddf, workstrokesonly=True,
|
||||
|
||||
ddf = dataprep.clean_df_stats_pl(ddf, workstrokesonly=True,
|
||||
ignoreadvanced=True)
|
||||
|
||||
totalscript, totaldiv = interactive_hr_piechart(
|
||||
|
||||
+64
-61
@@ -69,102 +69,102 @@ def strokedataform(request, id=0):
|
||||
def api_get_dataframe(startdatetime, df):
|
||||
try:
|
||||
time = df['time']/1.e3
|
||||
except KeyError: # pragma: no cover
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
try:
|
||||
time = df['t']/10.
|
||||
except KeyError:
|
||||
return 400, "Missing time", pd.DataFrame()
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
return 400, "Missing time", pl.DataFrame()
|
||||
|
||||
try:
|
||||
spm = df['spm']
|
||||
except KeyError: # pragma: no cover
|
||||
return 400, "Missing spm", pd.DataFrame()
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
return 400, "Missing spm", pl.DataFrame()
|
||||
try:
|
||||
distance = df['distance']
|
||||
except KeyError: # pragma: no cover
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
try:
|
||||
distance = df['d']/10.
|
||||
except KeyError:
|
||||
return 400, "Missing distance", pd.DataFrame()
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
return 400, "Missing distance", pl.DataFrame()
|
||||
|
||||
try:
|
||||
pace = df['pace']/1.e3
|
||||
except KeyError: # pragma: no cover
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
try:
|
||||
pace = df['p']/10.
|
||||
except KeyError:
|
||||
return 400, "Missing pace", pd.DataFrame()
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
return 400, "Missing pace", pl.DataFrame()
|
||||
|
||||
|
||||
try:
|
||||
power = df['power']
|
||||
except KeyError: # pragma: no cover
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
power = 0*time
|
||||
try:
|
||||
drivelength = df['drivelength']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
drivelength = 0*time
|
||||
try:
|
||||
dragfactor = df['dragfactor']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
dragfactor = 0*time
|
||||
try:
|
||||
drivetime = df['drivetime']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
drivetime = 0*time
|
||||
try:
|
||||
strokerecoverytime = df['strokerecoverytime']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
strokerecoverytime = 0*time
|
||||
try:
|
||||
averagedriveforce = df['averagedriveforce']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
averagedriveforce = 0*time
|
||||
try:
|
||||
peakdriveforce = df['peakdriveforce']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
peakdriveforce = 0*time
|
||||
try:
|
||||
wash = df['wash']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
wash = 0*time
|
||||
try:
|
||||
catch = df['catch']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
catch = 0*time
|
||||
try:
|
||||
finish = df['finish']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
finish = 0*time
|
||||
try:
|
||||
peakforceangle = df['peakforceangle']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
peakforceangle = 0*time
|
||||
try:
|
||||
driveenergy = df['driveenergy']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
driveenergy = 60.*power/spm
|
||||
try:
|
||||
slip = df['slip']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
slip = 0*time
|
||||
try:
|
||||
lapidx = df['lapidx']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
lapidx = 0*time
|
||||
try:
|
||||
hr = df['hr']
|
||||
except KeyError: # pragma: no cover
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
hr = 0*df['time']
|
||||
|
||||
try:
|
||||
latitude = df['latitude']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
latitude = 0*df['time']
|
||||
|
||||
try:
|
||||
longitude = df['longitude']
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
longitude = 0*df['time']
|
||||
|
||||
starttime = totimestamp(startdatetime)+time[0]
|
||||
@@ -172,7 +172,7 @@ def api_get_dataframe(startdatetime, df):
|
||||
|
||||
dologging('apilog.log',"(strokedatajson_v2/3 POST - data parsed)")
|
||||
|
||||
data = pd.DataFrame({'TimeStamp (sec)': unixtime,
|
||||
data = pl.DataFrame({'TimeStamp (sec)': unixtime,
|
||||
' Horizontal (meters)': distance,
|
||||
' Cadence (stokes/min)': spm,
|
||||
' HRCur (bpm)': hr,
|
||||
@@ -526,7 +526,7 @@ def strokedatajson_v3(request):
|
||||
title = request.data.get('name','')
|
||||
try:
|
||||
elapsedTime = request.data['elapsedTime']
|
||||
except KeyError: # pragma: no cover
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
try:
|
||||
duration = request.data['duration']
|
||||
try:
|
||||
@@ -538,7 +538,7 @@ def strokedatajson_v3(request):
|
||||
return HttpResponse("Missing Elapsed Time", status=400)
|
||||
try:
|
||||
totalDistance = request.data['distance']
|
||||
except KeyError: # pragma: no cover
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
return HttpResponse("Missing Total Distance", status=400)
|
||||
timeZone = request.data.get('timezone','UTC')
|
||||
workouttype = request.data.get('workouttype','rower')
|
||||
@@ -556,23 +556,21 @@ def strokedatajson_v3(request):
|
||||
dologging('apilog.log',totalDistance)
|
||||
dologging('apilog.log',elapsedTime)
|
||||
|
||||
df = pd.DataFrame()
|
||||
df = pl.DataFrame()
|
||||
try:
|
||||
strokes = request.data['strokes']
|
||||
except KeyError: # pragma: no cover
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
return HttpResponse("No Stroke Data in JSON", status=400)
|
||||
|
||||
try:
|
||||
df = pd.DataFrame(strokes['data'])
|
||||
except KeyError: # pragma: no cover
|
||||
df = pl.DataFrame(strokes['data'])
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
try:
|
||||
df = pd.DataFrame(request.data['strokedata'])
|
||||
df = pl.DataFrame(request.data['strokedata'])
|
||||
except:
|
||||
return HttpResponse("No JSON Object could be decoded", status=400)
|
||||
|
||||
df.index = df.index.astype(int)
|
||||
df.sort_index(inplace=True)
|
||||
|
||||
df = df.sort("time")
|
||||
status, comment, data = api_get_dataframe(startdatetime, df)
|
||||
|
||||
if status != 200: # pragma: no cover
|
||||
@@ -580,7 +578,8 @@ def strokedatajson_v3(request):
|
||||
|
||||
|
||||
csvfilename = 'media/{code}.csv.gz'.format(code=uuid4().hex[:16])
|
||||
_ = data.to_csv(csvfilename, index_label='index', compression='gzip')
|
||||
with gzip.open(csvfilename, 'w') as f:
|
||||
_ = data.write_csv(f)
|
||||
|
||||
duration = datetime.time(0,0,1)
|
||||
w = Workout(
|
||||
@@ -672,10 +671,11 @@ def strokedatajson_v2(request, id):
|
||||
|
||||
if request.method == 'GET':
|
||||
columns = ['spm', 'time', 'hr', 'pace', 'power', 'distance']
|
||||
datadf = dataprep.getsmallrowdata_db(columns, ids=[id])
|
||||
datadf = dataprep.read_data(columns, ids=[id])
|
||||
datadf = dataprep.remove_nulls_pl(datadf)
|
||||
dologging('apilog.log',request.user.username+"(strokedatajson_v2 GET)")
|
||||
|
||||
data = datadf.to_json(orient='records')
|
||||
data = datadf.write_json(row_oriented=True)
|
||||
data2 = json.loads(data)
|
||||
data2 = {"data": data2}
|
||||
|
||||
@@ -686,28 +686,27 @@ def strokedatajson_v2(request, id):
|
||||
try:
|
||||
for d in request.data['data']:
|
||||
dologging('apilog.log',json.dumps(d))
|
||||
except KeyError: # pragma: no cover
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
try:
|
||||
for d in request.data['strokedata']:
|
||||
dologging('apilog.log',json.dumps(d))
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
dologging('apilog.log','No data in request.data')
|
||||
checkdata, r = dataprep.getrowdata_db(id=row.id)
|
||||
if not checkdata.empty: # pragma: no cover
|
||||
return HttpResponse("Duplicate Error", status=409)
|
||||
|
||||
df = pd.DataFrame()
|
||||
df = pl.DataFrame()
|
||||
|
||||
try:
|
||||
df = pd.DataFrame(request.data['data'])
|
||||
except KeyError: # pragma: no cover
|
||||
df = pl.DataFrame(request.data['data'])
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
try:
|
||||
df = pd.DataFrame(request.data['strokedata'])
|
||||
df = pl.DataFrame(request.data['strokedata'])
|
||||
except:
|
||||
return HttpResponse("No JSON object could be decoded", status=400)
|
||||
|
||||
df.index = df.index.astype(int)
|
||||
df.sort_index(inplace=True)
|
||||
df = df.sort("time")
|
||||
|
||||
status, comment, data = api_get_dataframe(row.startdatetime, df)
|
||||
if status != 200: # pragma: no cover
|
||||
@@ -729,7 +728,8 @@ def strokedatajson_v2(request, id):
|
||||
row.duplicate = True
|
||||
row.save()
|
||||
|
||||
_ = data.to_csv(csvfilename+'.gz', index_label='index', compression='gzip')
|
||||
with gzip.open(csvfilename+'.gz', 'w') as f:
|
||||
_ = data.write_csv(f)
|
||||
row.csvfilename = csvfilename
|
||||
row.save()
|
||||
|
||||
@@ -748,7 +748,7 @@ def strokedatajson_v2(request, id):
|
||||
powerperc=powerperc, powerzones=r.powerzones)
|
||||
rowdata = rdata(csvfile=row.csvfilename, rower=rr).df
|
||||
|
||||
datadf = dataprep.dataprep(
|
||||
datadf = dataprep.dataplep(
|
||||
rowdata, id=row.id, bands=True, barchart=True, otwpower=True, empower=True)
|
||||
|
||||
_ = myqueue(queuehigh, handle_calctrimp, row.id,
|
||||
@@ -802,7 +802,11 @@ def strokedatajson(request, id=0):
|
||||
if request.method == 'GET':
|
||||
# currently only returns a subset.
|
||||
columns = ['spm', 'time', 'hr', 'pace', 'power', 'distance']
|
||||
datadf = dataprep.getsmallrowdata_db(columns, ids=[id])
|
||||
|
||||
datadf = dataprep.read_data(columns, ids=[id])
|
||||
datadf = dataprep.remove_nulls_pl(datadf)
|
||||
datadf = datadf.to_pandas()
|
||||
|
||||
dologging("apilog.log",request.user.username+"(strokedatajson GET) ")
|
||||
return JSONResponse(datadf)
|
||||
|
||||
@@ -823,14 +827,13 @@ def strokedatajson(request, id=0):
|
||||
return HttpResponse("No JSON object could be decoded", status=400)
|
||||
|
||||
try:
|
||||
df = pd.DataFrame(strokedata)
|
||||
df = pl.DataFrame(strokedata)
|
||||
except ValueError: # pragma: no cover
|
||||
return HttpResponse("Arrays must all be same length", status=400)
|
||||
df.index = df.index.astype(int)
|
||||
df.sort_index(inplace=True)
|
||||
df = df.sort("time")
|
||||
try:
|
||||
time = df['time']/1.e3
|
||||
except KeyError: # pragma: no cover
|
||||
except (KeyError, ColumnNotFoundError): # pragma: no cover
|
||||
return HttpResponse("There must be time values", status=400)
|
||||
aantal = len(time)
|
||||
pace = df['pace']/1.e3
|
||||
@@ -869,7 +872,7 @@ def strokedatajson(request, id=0):
|
||||
|
||||
dologging("apilog.log",request.user.username+"(POST)")
|
||||
|
||||
data = pd.DataFrame({'TimeStamp (sec)': unixtime,
|
||||
data = pl.DataFrame({'TimeStamp (sec)': unixtime,
|
||||
' Horizontal (meters)': distance,
|
||||
' Cadence (stokes/min)': spm,
|
||||
' HRCur (bpm)': hr,
|
||||
@@ -896,8 +899,8 @@ def strokedatajson(request, id=0):
|
||||
timestr = row.startdatetime.strftime("%Y%m%d-%H%M%S")
|
||||
csvfilename = 'media/Import_'+timestr+'.csv'
|
||||
|
||||
res = data.to_csv(csvfilename+'.gz', index_label='index',
|
||||
compression='gzip')
|
||||
with gzip.open(csvfilename+'.gz','w') as f:
|
||||
res = data.write_csv(f)
|
||||
row.csvfilename = csvfilename
|
||||
row.save()
|
||||
|
||||
@@ -916,7 +919,7 @@ def strokedatajson(request, id=0):
|
||||
powerperc=powerperc, powerzones=r.powerzones)
|
||||
rowdata = rdata(csvfile=row.csvfilename, rower=rr).df
|
||||
|
||||
datadf = dataprep.dataprep(
|
||||
datadf = dataprep.dataplep(
|
||||
rowdata, id=row.id, bands=True, barchart=True, otwpower=True, empower=True)
|
||||
# mangling
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ def workouts_summaries_email_view(request):
|
||||
)
|
||||
df = dataprep.workout_summary_to_df(
|
||||
r, startdate=startdate, enddate=enddate)
|
||||
df.to_csv(filename, encoding='utf-8')
|
||||
df.write_csv(filename)
|
||||
_ = myqueue(queuehigh, handle_sendemailsummary,
|
||||
r.user.first_name,
|
||||
r.user.last_name,
|
||||
|
||||
@@ -1,10 +1,33 @@
|
||||
|
||||
from rowers.views.statements import *
|
||||
from rowers.interactiveplots import sleep
|
||||
|
||||
from rq import Queue
|
||||
from redis import Redis
|
||||
from rq.job import Job
|
||||
|
||||
@login_required()
|
||||
def sleep_view(request):
|
||||
|
||||
script, div = sleep()
|
||||
|
||||
return render(request,
|
||||
"sleep.html",
|
||||
{
|
||||
"the_div": div,
|
||||
"the_script": script,
|
||||
})
|
||||
|
||||
def filmdeaths_view(request):
|
||||
script, div = filmdeaths()
|
||||
|
||||
return render(request,
|
||||
"filmdeaths.html",
|
||||
{
|
||||
"the_div": div,
|
||||
"the_script": script,
|
||||
}
|
||||
)
|
||||
|
||||
@login_required()
|
||||
def download_fit(request, filename=''):
|
||||
|
||||
@@ -3569,7 +3569,7 @@ def rower_trainingplan_execution_view(request,
|
||||
else: # pragma: no cover
|
||||
data, message = get_execution_report(r, startdate, enddate)
|
||||
|
||||
if not data.empty:
|
||||
if not data.is_empty():
|
||||
script, div = interactive_planchart(data, startdate, enddate)
|
||||
else: # pragma: no cover
|
||||
script = ''
|
||||
|
||||
@@ -16,7 +16,7 @@ from rowers.utils import (
|
||||
from rowers.celery import result as celery_result
|
||||
from rowers.interactiveplots import *
|
||||
from scipy.interpolate import griddata
|
||||
from rowers.dataprep import getsmallrowdata_db
|
||||
from rowers.dataprep import getsmallrowdata_pd, read_data
|
||||
from rowers.dataprep import timedeltaconv
|
||||
from scipy.special import lambertw
|
||||
from io import BytesIO
|
||||
@@ -35,6 +35,7 @@ import threading
|
||||
import redis
|
||||
import colorsys
|
||||
import re
|
||||
import gzip
|
||||
import zipfile
|
||||
import bleach
|
||||
import arrow
|
||||
@@ -136,9 +137,9 @@ from rowers.forms import (
|
||||
FitnessMetricForm, PredictedPieceFormNoDistance,
|
||||
EmailForm, RegistrationForm, RegistrationFormTermsOfService,
|
||||
RegistrationFormUniqueEmail, RegistrationFormSex,
|
||||
CNsummaryForm, UpdateWindForm,
|
||||
CNsummaryForm,
|
||||
StandardsForm,
|
||||
UpdateStreamForm, WorkoutMultipleCompareForm, ChartParamChoiceForm,
|
||||
WorkoutMultipleCompareForm, ChartParamChoiceForm,
|
||||
FusionMetricChoiceForm, BoxPlotChoiceForm, MultiFlexChoiceForm,
|
||||
TrendFlexModalForm, WorkoutSplitForm, WorkoutJoinParamForm,
|
||||
AnalysisOptionsForm, AnalysisChoiceForm,
|
||||
@@ -205,6 +206,7 @@ from rowers.rojabo_stuff import rojabo_open
|
||||
|
||||
from rowers.integrations import *
|
||||
|
||||
from polars.exceptions import ColumnNotFoundError
|
||||
|
||||
import rowers.ownapistuff as ownapistuff
|
||||
from rowers.ownapistuff import TEST_CLIENT_ID, TEST_CLIENT_SECRET, TEST_REDIRECT_URI
|
||||
@@ -251,7 +253,7 @@ from rowers.tasks import (
|
||||
handle_sendemailfile,
|
||||
handle_sendemailkml,
|
||||
handle_sendemailnewresponse, handle_updatedps,
|
||||
handle_updatecp, long_test_task, long_test_task2,
|
||||
long_test_task, long_test_task2,
|
||||
handle_zip_file, handle_getagegrouprecords,
|
||||
handle_update_empower,
|
||||
handle_sendemailics,
|
||||
@@ -1344,9 +1346,9 @@ def trydf(df, aantal, column): # pragma: no cover
|
||||
s = df[column]
|
||||
if len(s) != aantal:
|
||||
return np.zeros(aantal)
|
||||
if not np.issubdtype(s, np.number):
|
||||
if not s.dtype in pl.NUMERIC_DTYPES:
|
||||
return np.zeros(aantal)
|
||||
except KeyError:
|
||||
except (KeyError, ColumnNotFoundError):
|
||||
s = np.zeros(aantal)
|
||||
|
||||
return s
|
||||
|
||||
+38
-494
@@ -126,8 +126,7 @@ def workout_video_view_mini(request, id=''):
|
||||
hascoordinates = pd.Series(data['latitude']).std() > 0
|
||||
# create map
|
||||
if hascoordinates and mode == 'water':
|
||||
mapscript, mapdiv = leaflet_chart_video(data['latitude'], data['longitude'],
|
||||
w.name)
|
||||
mapscript, mapdiv = leaflet_chart(data['latitude'], data['longitude'])
|
||||
else:
|
||||
mapscript, mapdiv = interactive_chart_video(data)
|
||||
data['longitude'] = data['spm']
|
||||
@@ -237,8 +236,7 @@ def workout_video_view(request, id=''):
|
||||
hascoordinates = pd.Series(data['latitude']).std() > 0
|
||||
# create map
|
||||
if hascoordinates and mode == 'water':
|
||||
mapscript, mapdiv = leaflet_chart_video(data['latitude'], data['longitude'],
|
||||
w.name)
|
||||
mapscript, mapdiv = leaflet_chart(data['latitude'], data['longitude'])
|
||||
else:
|
||||
mapscript, mapdiv = interactive_chart_video(data)
|
||||
data['longitude'] = data['spm']
|
||||
@@ -349,12 +347,12 @@ def workout_video_create_view(request, id=0):
|
||||
# get data
|
||||
data, metrics, maxtime = dataprep.get_video_data(
|
||||
w, groups=metricsgroups, mode=mode)
|
||||
|
||||
hascoordinates = pd.Series(data['latitude']).std() > 0
|
||||
|
||||
# create map
|
||||
if hascoordinates and mode == 'water':
|
||||
mapscript, mapdiv = leaflet_chart_video(data['latitude'], data['longitude'],
|
||||
w.name)
|
||||
mapscript, mapdiv = leaflet_chart(data['latitude'], data['longitude'])
|
||||
else:
|
||||
mapscript, mapdiv = interactive_chart_video(data)
|
||||
data['longitude'] = data['spm']
|
||||
@@ -380,6 +378,7 @@ def workout_video_create_view(request, id=0):
|
||||
|
||||
template = 'embedded_video.html'
|
||||
|
||||
|
||||
return render(request,
|
||||
template,
|
||||
{
|
||||
@@ -429,12 +428,14 @@ def workout_forcecurve_view(request, id=0, analysis=0, userid=0, workstrokesonly
|
||||
work_max = forceanalysis.work_max
|
||||
notes = forceanalysis.notes
|
||||
name = forceanalysis.name
|
||||
plotcircles = forceanalysis.plotcircles
|
||||
plotlines = forceanalysis.plotlines
|
||||
includereststrokes = forceanalysis.include_rest_strokes
|
||||
except (ForceCurveAnalysis.DoesNotExist, ValueError):
|
||||
pass
|
||||
else:
|
||||
dist_min = 0
|
||||
dist_max = 0
|
||||
dist_max = row.distance
|
||||
spm_min = 15
|
||||
spm_max = 55
|
||||
work_min = 0
|
||||
@@ -442,6 +443,8 @@ def workout_forcecurve_view(request, id=0, analysis=0, userid=0, workstrokesonly
|
||||
notes = ''
|
||||
includereststrokes = False
|
||||
name = ''
|
||||
plotcircles = True
|
||||
plotlines = False
|
||||
|
||||
form = ForceCurveOptionsForm(initial={
|
||||
'spm_min': spm_min,
|
||||
@@ -451,10 +454,10 @@ def workout_forcecurve_view(request, id=0, analysis=0, userid=0, workstrokesonly
|
||||
'work_min': work_min,
|
||||
'work_max': work_max,
|
||||
'notes': notes,
|
||||
'plottype': 'line',
|
||||
'name': name,
|
||||
'plotcircles': plotcircles,
|
||||
'plotlines': plotlines,
|
||||
})
|
||||
plottype = 'line'
|
||||
|
||||
|
||||
if request.method == 'POST':
|
||||
@@ -468,10 +471,11 @@ def workout_forcecurve_view(request, id=0, analysis=0, userid=0, workstrokesonly
|
||||
work_max = form.cleaned_data['work_max']
|
||||
notes = form.cleaned_data['notes']
|
||||
name = form.cleaned_data['name']
|
||||
plotlines = form.cleaned_data['plotlines']
|
||||
plotcircles = form.cleaned_data['plotcircles']
|
||||
if not name:
|
||||
name = row.name
|
||||
includereststrokes = form.cleaned_data['includereststrokes']
|
||||
plottype = form.cleaned_data['plottype']
|
||||
workstrokesonly = not includereststrokes
|
||||
|
||||
if "_save" in request.POST and "new" not in request.POST: # pragma: no cover
|
||||
@@ -488,6 +492,8 @@ def workout_forcecurve_view(request, id=0, analysis=0, userid=0, workstrokesonly
|
||||
spm_min = spm_min,
|
||||
spm_max = spm_max,
|
||||
rower=row.user,
|
||||
plotlines = plotlines,
|
||||
plotcircles = plotcircles,
|
||||
include_rest_strokes = includereststrokes,
|
||||
)
|
||||
else:
|
||||
@@ -501,6 +507,8 @@ def workout_forcecurve_view(request, id=0, analysis=0, userid=0, workstrokesonly
|
||||
forceanalysis.work_max = work_max
|
||||
forceanalysis.spm_min = spm_min
|
||||
forceanalysis.spm_max = spm_max
|
||||
forceanalysis.plotcircles = plotcircles
|
||||
forceanalysis.plotlines = plotlines
|
||||
forceanalysis.include_rest_strokes = includereststrokes
|
||||
forceanalysis.save()
|
||||
dosave = True
|
||||
@@ -526,20 +534,10 @@ def workout_forcecurve_view(request, id=0, analysis=0, userid=0, workstrokesonly
|
||||
|
||||
else: # pragma: no cover
|
||||
workstrokesonly = True
|
||||
plottype = 'line'
|
||||
|
||||
|
||||
script, div, js_resources, css_resources = interactive_forcecurve(
|
||||
[row],
|
||||
workstrokesonly=workstrokesonly,
|
||||
plottype=plottype,
|
||||
dist_min = dist_min,
|
||||
dist_max = dist_max,
|
||||
spm_min = spm_min,
|
||||
spm_max = spm_max,
|
||||
work_min = work_min,
|
||||
work_max = work_max,
|
||||
notes=notes,
|
||||
script, div = interactive_forcecurve(
|
||||
[row]
|
||||
)
|
||||
|
||||
breadcrumbs = [
|
||||
@@ -580,8 +578,6 @@ def workout_forcecurve_view(request, id=0, analysis=0, userid=0, workstrokesonly
|
||||
'work_max': work_max,
|
||||
'annotation': notes,
|
||||
'the_div': div,
|
||||
'js_res': js_resources,
|
||||
'css_res': css_resources,
|
||||
'id': id,
|
||||
'mayedit': mayedit,
|
||||
'teams': get_my_teams(request.user),
|
||||
@@ -633,50 +629,6 @@ def otw_use_gps(request, id=0):
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
# Show Stroke power histogram for a workout
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
|
||||
def workout_histo_view(request, id=0):
|
||||
w = get_workoutuser(id, request)
|
||||
r = getrequestrower(request)
|
||||
|
||||
mayedit = 0
|
||||
if w.user == r:
|
||||
mayedit = 1
|
||||
|
||||
res = interactive_histoall([w], 'power', False)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url': '/rowers/list-workouts/',
|
||||
'name': 'Workouts'
|
||||
},
|
||||
{
|
||||
'url': get_workout_default_page(request, id),
|
||||
'name': w.name
|
||||
},
|
||||
{
|
||||
'url': reverse('workout_histo_view', kwargs={'id': id}),
|
||||
'name': 'Histogram'
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
return render(request,
|
||||
'histo_single.html',
|
||||
{'interactiveplot': script,
|
||||
'breadcrumbs': breadcrumbs,
|
||||
'active': 'nav-workouts',
|
||||
'workout': w,
|
||||
'rower': r,
|
||||
'the_div': div,
|
||||
'id': id,
|
||||
'mayedit': mayedit,
|
||||
'teams': get_my_teams(request.user),
|
||||
})
|
||||
|
||||
|
||||
# add a workout manually
|
||||
@login_required()
|
||||
@@ -1343,7 +1295,7 @@ def remove_power_view(request, id=0):
|
||||
row = rdata(csvfile=f, rower=rr)
|
||||
row.df[' Power (watts)'] = 0
|
||||
row.write_csv(f)
|
||||
_ = dataprep.dataprep(row.df, id=workout.id)
|
||||
_ = dataprep.dataplep(row.df, id=workout.id)
|
||||
cpdf, delta, cpvalues = dataprep.setcp(workout)
|
||||
|
||||
workout.normp = 0
|
||||
@@ -1667,15 +1619,10 @@ def course_compare_view(request, id=0):
|
||||
except: # pragma: no cover
|
||||
labeldict = {}
|
||||
|
||||
res = interactive_multiple_compare_chart(workoutids, xparam, yparam,
|
||||
script, div = interactive_multiple_compare_chart(workoutids, xparam, yparam,
|
||||
promember=promember,
|
||||
plottype=plottype,
|
||||
labeldict=labeldict, startenddict=startenddict)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
errormessage = res[3]
|
||||
if errormessage != '': # pragma: no cover
|
||||
messages.error(request, errormessage)
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
@@ -1849,15 +1796,10 @@ def virtualevent_compare_view(request, id=0):
|
||||
except: # pragma: no cover
|
||||
labeldict = {}
|
||||
|
||||
res = interactive_multiple_compare_chart(workoutids, xparam, yparam,
|
||||
script, div = interactive_multiple_compare_chart(workoutids, xparam, yparam,
|
||||
promember=promember,
|
||||
plottype=plottype,
|
||||
labeldict=labeldict, startenddict=startenddict)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
errormessage = res[3]
|
||||
if errormessage != '': # pragma: no cover
|
||||
messages.error(request, errormessage)
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
@@ -2237,10 +2179,6 @@ def workouts_view(request, message='', successmessage='',
|
||||
for w in workoutsnohr: # pragma: no cover
|
||||
_ = dataprep.workout_trimp(w)
|
||||
|
||||
# ids = [w.id for w in workouts]
|
||||
# df = dataprep.getsmallrowdata_db(['time','power'],ids=ids)
|
||||
# polarization = dataprep.polarization_index(df,r)
|
||||
|
||||
if query: # pragma: no cover
|
||||
query_list = query.split()
|
||||
workouts = workouts.filter(
|
||||
@@ -2278,7 +2216,7 @@ def workouts_view(request, message='', successmessage='',
|
||||
if yaxis not in ['duration', 'trimp', 'rscore']: # pragma: no cover
|
||||
yaxis = 'duration'
|
||||
|
||||
script, div = interactive_activitychart(g_workouts,
|
||||
script, div = interactive_activitychart2(g_workouts,
|
||||
g_startdate,
|
||||
g_enddate,
|
||||
stack=stack,
|
||||
@@ -2823,348 +2761,6 @@ def workout_downloadmetar_view(request, id=0,
|
||||
return response
|
||||
|
||||
|
||||
# Show form to update wind data
|
||||
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
|
||||
@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)
|
||||
def workout_wind_view(request, id=0, message="", successmessage=""):
|
||||
row = get_workoutuser(id, request)
|
||||
r = getrower(request.user)
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url': '/rowers/list-workouts/',
|
||||
'name': 'Workouts'
|
||||
},
|
||||
{
|
||||
'url': get_workout_default_page(request, id),
|
||||
'name': row.name
|
||||
},
|
||||
{
|
||||
'url': reverse('workout_wind_view', kwargs={'id': id}),
|
||||
'name': 'Wind'
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
# get data
|
||||
f1 = row.csvfilename
|
||||
u = row.user.user
|
||||
r = getrower(u)
|
||||
|
||||
# create bearing
|
||||
rowdata = rdata(csvfile=f1)
|
||||
if row == 0: # pragma: no cover
|
||||
return HttpResponse("Error: CSV Data File Not Found")
|
||||
|
||||
hascoordinates = 1
|
||||
try:
|
||||
latitude = rowdata.df.loc[:, ' latitude']
|
||||
except KeyError:
|
||||
hascoordinates = 0
|
||||
|
||||
if hascoordinates and not latitude.std(): # pragma: no cover
|
||||
hascoordinates = 0
|
||||
|
||||
try:
|
||||
_ = rowdata.df.loc[:, 'bearing'].values
|
||||
except KeyError:
|
||||
rowdata.add_bearing()
|
||||
rowdata.write_csv(f1, gzip=True)
|
||||
|
||||
if hascoordinates:
|
||||
avglat = rowdata.df[' latitude'].mean()
|
||||
avglon = rowdata.df[' longitude'].mean()
|
||||
airportcode, newlat, newlon, airportdistance = get_airport_code(
|
||||
avglat, avglon)
|
||||
airportcode = airportcode.upper()
|
||||
airportdistance = airportdistance[0]
|
||||
else:
|
||||
airportcode = 'UNKNOWN'
|
||||
airportdistance = 0
|
||||
|
||||
if request.method == 'POST':
|
||||
# process form
|
||||
form = UpdateWindForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
|
||||
vwind1 = form.cleaned_data['vwind1']
|
||||
vwind2 = form.cleaned_data['vwind2']
|
||||
dist1 = form.cleaned_data['dist1']
|
||||
dist2 = form.cleaned_data['dist2']
|
||||
winddirection1 = form.cleaned_data['winddirection1']
|
||||
winddirection2 = form.cleaned_data['winddirection2']
|
||||
windunit = form.cleaned_data['windunit']
|
||||
|
||||
rowdata.update_wind(vwind1, vwind2,
|
||||
winddirection1,
|
||||
winddirection2,
|
||||
dist1, dist2,
|
||||
units=windunit)
|
||||
|
||||
rowdata.write_csv(f1, gzip=True)
|
||||
|
||||
else: # pragma: no cover
|
||||
message = "Invalid Form"
|
||||
messages.error(request, message)
|
||||
kwargs = {
|
||||
'id': id
|
||||
}
|
||||
url = reverse('workout_wind_view', kwargs=kwargs)
|
||||
_ = HttpResponseRedirect(url)
|
||||
|
||||
else:
|
||||
form = UpdateWindForm()
|
||||
|
||||
# create interactive plot
|
||||
res = interactive_windchart(encoder.decode_hex(id), promember=1)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
|
||||
if hascoordinates:
|
||||
gmscript, gmdiv = leaflet_chart(
|
||||
rowdata.df[' latitude'],
|
||||
rowdata.df[' longitude'],
|
||||
row.name)
|
||||
else:
|
||||
gmscript = ""
|
||||
gmdiv = "No GPS data available"
|
||||
|
||||
messages.info(request, successmessage)
|
||||
messages.error(request, message)
|
||||
|
||||
return render(request,
|
||||
'windedit.html',
|
||||
{'workout': row,
|
||||
'rower': r,
|
||||
'breadcrumbs': breadcrumbs,
|
||||
'active': 'nav-workouts',
|
||||
'teams': get_my_teams(request.user),
|
||||
'interactiveplot': script,
|
||||
'form': form,
|
||||
'airport': airportcode,
|
||||
'airportdistance': airportdistance,
|
||||
'the_div': div,
|
||||
'gmap': gmscript,
|
||||
'gmapdiv': gmdiv})
|
||||
|
||||
|
||||
# Show form to update River stream data (for river dwellers)
|
||||
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
|
||||
@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)
|
||||
def workout_stream_view(request, id=0, message="", successmessage=""):
|
||||
row = get_workoutuser(id, request)
|
||||
r = getrower(request.user)
|
||||
|
||||
# create interactive plot
|
||||
f1 = row.csvfilename
|
||||
u = row.user.user
|
||||
r = getrower(u)
|
||||
|
||||
rowdata = rdata(csvfile=f1)
|
||||
if rowdata == 0: # pragma: no cover
|
||||
messages.info(request, "Error: CSV data file not found")
|
||||
url = reverse('workout_edit_view', kwargs={
|
||||
'id': encoder.encode_hex(row.id)})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
if request.method == 'POST':
|
||||
# process form
|
||||
form = UpdateStreamForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
|
||||
dist1 = form.cleaned_data['dist1']
|
||||
dist2 = form.cleaned_data['dist2']
|
||||
stream1 = form.cleaned_data['stream1']
|
||||
stream2 = form.cleaned_data['stream2']
|
||||
streamunit = form.cleaned_data['streamunit']
|
||||
|
||||
rowdata.update_stream(stream1, stream2, dist1, dist2,
|
||||
units=streamunit)
|
||||
|
||||
rowdata.write_csv(f1, gzip=True)
|
||||
|
||||
else: # pragma: no cover
|
||||
message = "Invalid Form"
|
||||
messages.error(request, message)
|
||||
kwargs = {
|
||||
'id': id}
|
||||
url = reverse('workout_wind_view', kwargs=kwargs)
|
||||
_ = HttpResponseRedirect(url)
|
||||
|
||||
else:
|
||||
form = UpdateStreamForm()
|
||||
|
||||
# create interactive plot
|
||||
res = interactive_streamchart(encoder.decode_hex(id), promember=1)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url': '/rowers/list-workouts/',
|
||||
'name': 'Workouts'
|
||||
},
|
||||
{
|
||||
'url': get_workout_default_page(request, id),
|
||||
'name': row.name
|
||||
},
|
||||
{
|
||||
'url': reverse('workout_stream_view', kwargs={'id': id}),
|
||||
'name': 'Stream'
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
messages.info(request, successmessage)
|
||||
messages.error(request, message)
|
||||
return render(request,
|
||||
'streamedit.html',
|
||||
{'workout': row,
|
||||
'rower': r,
|
||||
'breadcrumbs': breadcrumbs,
|
||||
'active': 'nav-workouts',
|
||||
'teams': get_my_teams(request.user),
|
||||
'interactiveplot': script,
|
||||
'form': form,
|
||||
'the_div': div})
|
||||
|
||||
# Form to set average crew weight and boat type, then run power calcs
|
||||
|
||||
|
||||
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
|
||||
@user_passes_test(ispromember, login_url="/rowers/paidplans", redirect_field_name=None)
|
||||
def workout_otwsetpower_view(request, id=0, message="", successmessage=""):
|
||||
w = get_workoutuser(id, request)
|
||||
r = getrower(request.user)
|
||||
|
||||
mayedit = 1
|
||||
|
||||
if request.method == 'POST':
|
||||
# process form
|
||||
form = AdvancedWorkoutForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
boattype = form.cleaned_data['boattype']
|
||||
weightvalue = form.cleaned_data['weightvalue']
|
||||
coastalbrand = form.cleaned_data['boatbrand']
|
||||
boatclass = w.workouttype
|
||||
w.boattype = boattype
|
||||
w.weightvalue = weightvalue
|
||||
w.boatbrand = coastalbrand
|
||||
w.save()
|
||||
|
||||
# load row data & create power/wind/bearing columns if not set
|
||||
f1 = w.csvfilename
|
||||
rowdata = rdata(csvfile=f1)
|
||||
if rowdata == 0: # pragma: no cover
|
||||
return HttpResponse("Error: CSV Data File Not Found")
|
||||
try:
|
||||
_ = rowdata.df['vstream']
|
||||
except KeyError:
|
||||
rowdata.add_stream(0)
|
||||
rowdata.write_csv(f1, gzip=True)
|
||||
|
||||
try:
|
||||
_ = rowdata.df['bearing']
|
||||
except KeyError:
|
||||
rowdata.add_bearing()
|
||||
rowdata.write_csv(f1, gzip=True)
|
||||
|
||||
try:
|
||||
_ = rowdata.df['vwind']
|
||||
except KeyError:
|
||||
rowdata.add_wind(0, 0)
|
||||
rowdata.write_csv(f1, gzip=True)
|
||||
|
||||
# do power calculation (asynchronous)
|
||||
r = w.user
|
||||
u = r.user
|
||||
|
||||
first_name = u.first_name
|
||||
last_name = u.last_name
|
||||
emailaddress = u.email
|
||||
|
||||
job = myqueue(queue,
|
||||
handle_otwsetpower, f1, boattype, boatclass, coastalbrand,
|
||||
weightvalue,
|
||||
first_name, last_name, emailaddress, encoder.decode_hex(
|
||||
id),
|
||||
ps=[r.p0, r.p1, r.p2, r.p3],
|
||||
ratio=r.cpratio,
|
||||
# quick_calc = quick_calc,
|
||||
# go_service=go_service,
|
||||
emailbounced=r.emailbounced
|
||||
)
|
||||
|
||||
try:
|
||||
request.session['async_tasks'] += [(job.id, 'otwsetpower')]
|
||||
except KeyError:
|
||||
request.session['async_tasks'] = [(job.id, 'otwsetpower')]
|
||||
|
||||
successmessage = 'Your calculations have been submitted." \
|
||||
" You will receive an email when they are done." \
|
||||
" You can check the status of your calculations" \
|
||||
" <a href="/rowers/jobs-status/" target="_blank">here</a>'
|
||||
messages.info(request, successmessage)
|
||||
kwargs = {
|
||||
'id': id}
|
||||
|
||||
try:
|
||||
url = request.session['referer']
|
||||
except KeyError:
|
||||
url = reverse('workout_edit_view', kwargs=kwargs)
|
||||
|
||||
response = HttpResponseRedirect(url)
|
||||
return response
|
||||
|
||||
else: # pragma: no cover
|
||||
message = "Invalid Form"
|
||||
messages.error(request, message)
|
||||
kwargs = {
|
||||
'id': id}
|
||||
url = reverse('workout_otwsetpower_view', kwargs=kwargs)
|
||||
response = HttpResponseRedirect(url)
|
||||
|
||||
else:
|
||||
form = AdvancedWorkoutForm(instance=w)
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url': '/rowers/list-workouts/',
|
||||
'name': 'Workouts'
|
||||
},
|
||||
{
|
||||
'url': get_workout_default_page(request, id),
|
||||
'name': w.name
|
||||
},
|
||||
{
|
||||
'url': reverse('workout_otwsetpower_view', kwargs={'id': id}),
|
||||
'name': 'OTW Power'
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
messages.error(request, message)
|
||||
messages.info(request, successmessage)
|
||||
return render(request,
|
||||
'otwsetpower.html',
|
||||
{'workout': w,
|
||||
'rower': w,
|
||||
'mayedit': mayedit,
|
||||
'active': 'nav-workouts',
|
||||
'breadcrumbs': breadcrumbs,
|
||||
'teams': get_my_teams(request.user),
|
||||
'form': form,
|
||||
})
|
||||
|
||||
|
||||
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
|
||||
@@ -3598,7 +3194,7 @@ def workout_erase_column_view(request, id=0, column=''):
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
try:
|
||||
data = dataprep.getsmallrowdata_db([column], ids=[w.id])
|
||||
data = dataprep.read_data([column], ids=[w.id])
|
||||
except: # pragma: no cover
|
||||
messages.error(request, 'Invalid column')
|
||||
url = reverse('workout_data_view', kwargs={
|
||||
@@ -3654,12 +3250,18 @@ def workout_erase_column_view(request, id=0, column=''):
|
||||
|
||||
row, workout = dataprep.getrowdata(id=w.id)
|
||||
row.df[columnl] = defaultvalue
|
||||
try:
|
||||
os.remove(w.csvfilename+'.gz')
|
||||
except FileNotFoundError:
|
||||
try:
|
||||
os.remove(w.csvfilename)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
row.write_csv(w.csvfilename, gzip=True)
|
||||
|
||||
row, workout = dataprep.getrowdata(id=w.id)
|
||||
_ = dataprep.dataprep(row.df, id=w.id)
|
||||
_ = dataprep.dataplep(row.df, id=w.id)
|
||||
|
||||
if column == 'hr':
|
||||
w.hrtss = 0
|
||||
@@ -4141,7 +3743,7 @@ def workout_workflow_view(request, id):
|
||||
|
||||
if 'panel_map.html' in r.workflowmiddlepanel and rowhascoordinates(row):
|
||||
rowdata = rdata(csvfile=row.csvfilename)
|
||||
mapscript, mapdiv = leaflet_chart2(rowdata.df[' latitude'],
|
||||
mapscript, mapdiv = leaflet_chart(rowdata.df[' latitude'],
|
||||
rowdata.df[' longitude'],
|
||||
row.name)
|
||||
else:
|
||||
@@ -4370,7 +3972,7 @@ def workout_flexchart3_view(request, *args, **kwargs):
|
||||
|
||||
# create interactive plot
|
||||
(
|
||||
script, div, js_resources, css_resources, workstrokesonly
|
||||
script, div, workstrokesonly
|
||||
) = interactive_flex_chart2(
|
||||
encoder.decode_hex(id), request.user.rower,
|
||||
xparam=xparam, yparam1=yparam1,
|
||||
@@ -4456,8 +4058,6 @@ def workout_flexchart3_view(request, *args, **kwargs):
|
||||
'workout': row,
|
||||
'chartform': flexaxesform,
|
||||
'optionsform': flexoptionsform,
|
||||
'js_res': js_resources,
|
||||
'css_res': css_resources,
|
||||
'teams': get_my_teams(request.user),
|
||||
'id': id,
|
||||
'xparam': xparam,
|
||||
@@ -4505,7 +4105,7 @@ def workout_flexchart_stacked_view(request, *args, **kwargs):
|
||||
yparam4 = cd['yaxis4']
|
||||
|
||||
(
|
||||
script, div, js_resources, css_resources, comment
|
||||
script, div
|
||||
) = interactive_flexchart_stacked(
|
||||
encoder.decode_hex(id), r, xparam=xparam,
|
||||
yparam1=yparam1,
|
||||
@@ -4515,9 +4115,6 @@ def workout_flexchart_stacked_view(request, *args, **kwargs):
|
||||
mode=workout.workouttype,
|
||||
)
|
||||
|
||||
if comment is not None: # pragma: no cover
|
||||
messages.error(request, comment)
|
||||
|
||||
initial = {
|
||||
'xaxis': xparam,
|
||||
'yaxis1': yparam1,
|
||||
@@ -4554,8 +4151,6 @@ def workout_flexchart_stacked_view(request, *args, **kwargs):
|
||||
'active': 'nav-workouts',
|
||||
'workout': workout,
|
||||
'chartform': flexaxesform,
|
||||
'js_res': js_resources,
|
||||
'css_res': css_resources,
|
||||
'id': id,
|
||||
'xparam': xparam,
|
||||
'yparam1': yparam1,
|
||||
@@ -4568,57 +4163,6 @@ def workout_flexchart_stacked_view(request, *args, **kwargs):
|
||||
# The interactive plot with wind corrected pace for OTW outings
|
||||
|
||||
|
||||
def workout_otwpowerplot_view(request, id=0, message="", successmessage=""):
|
||||
w = get_workout(id)
|
||||
r = getrower(request.user)
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url': '/rowers/list-workouts/',
|
||||
'name': 'Workouts'
|
||||
},
|
||||
{
|
||||
'url': get_workout_default_page(request, id),
|
||||
'name': w.name
|
||||
},
|
||||
{
|
||||
'url': reverse('workout_otwpowerplot_view', kwargs={'id': id}),
|
||||
'name': 'Interactive OTW Power Plot'
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
# check if user is owner of this workout
|
||||
|
||||
# create interactive plot
|
||||
|
||||
promember = 0
|
||||
mayedit = 0
|
||||
result = request.user.is_authenticated and ispromember(request.user)
|
||||
if result:
|
||||
promember = 1
|
||||
if request.user == w.user.user:
|
||||
mayedit = 1
|
||||
|
||||
# create interactive plot
|
||||
res = interactive_otw_advanced_pace_chart(
|
||||
encoder.decode_hex(id), promember=promember)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
|
||||
messages.error(request, message)
|
||||
messages.info(request, successmessage)
|
||||
|
||||
return render(request,
|
||||
'otwinteractive.html',
|
||||
{'workout': w,
|
||||
'rower': r,
|
||||
'active': 'nav-workouts',
|
||||
'breadcrumbs': breadcrumbs,
|
||||
'teams': get_my_teams(request.user),
|
||||
'interactiveplot': script,
|
||||
'the_div': div,
|
||||
'mayedit': mayedit})
|
||||
|
||||
|
||||
#
|
||||
@@ -4780,7 +4324,7 @@ def workout_edit_view(request, id=0, message="", successmessage=""):
|
||||
row = get_workoutuser(id, request)
|
||||
|
||||
if request.user.rower.rowerplan == 'basic' and 'speedcoach2' in row.workoutsource: # pragma: no cover
|
||||
data = getsmallrowdata_db(['wash'], ids=[encoder.decode_hex(id)])
|
||||
data = read_data(['wash'], ids=[encoder.decode_hex(id)])
|
||||
try:
|
||||
if data['wash'].std() != 0:
|
||||
url = reverse('paidplans_view')
|
||||
@@ -4793,7 +4337,7 @@ def workout_edit_view(request, id=0, message="", successmessage=""):
|
||||
pass
|
||||
|
||||
if request.user.rower.rowerplan == 'basic' and 'nklinklogbook' in row.workoutsource: # pragma: no cover
|
||||
data = getsmallrowdata_db(['wash'], ids=[encoder.decode_hex(id)])
|
||||
data = read_data(['wash'], ids=[encoder.decode_hex(id)])
|
||||
try:
|
||||
if data['wash'].std() != 0:
|
||||
url = reverse('paidplans_view')
|
||||
@@ -5063,7 +4607,7 @@ def workout_map_view(request, id=0):
|
||||
hascoordinates = 0
|
||||
|
||||
if hascoordinates:
|
||||
mapscript, mapdiv = leaflet_chart2(rowdata.df[' latitude'],
|
||||
mapscript, mapdiv = leaflet_chart(rowdata.df[' latitude'],
|
||||
rowdata.df[' longitude'],
|
||||
w.name)
|
||||
else:
|
||||
|
||||
@@ -599,6 +599,13 @@ except KeyError: # pragma: no cover
|
||||
WORKOUTS_FIT_TOKEN = 'aapnootmies'
|
||||
WORKOUTS_FIT_URL = 'http://localhost:50053/tojson'
|
||||
|
||||
try:
|
||||
ROWSANDALL_CHARTS_TOKEN = CFG['rowsandall_charts_token']
|
||||
ROWSANDALL_CHARTS_URL = CFG['rowsandall_charts_url']
|
||||
except KeyError:
|
||||
ROWSANDALL_CHARTS_TOKEN = 'aapnootmies'
|
||||
ROWSANDALL_CHARTS_URL = 'http://localhost:3000'
|
||||
|
||||
# Recaptcha
|
||||
|
||||
try:
|
||||
|
||||
@@ -32,6 +32,16 @@
|
||||
color: red;
|
||||
}
|
||||
|
||||
.chart {
|
||||
background-image: url(/static/img/logo7.png);
|
||||
background-size: 200px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top 50px right 100px;
|
||||
}
|
||||
|
||||
.chartlabel {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.watermark {
|
||||
position: absolute;
|
||||
|
||||
Reference in New Issue
Block a user