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)
|
||||
|
||||
+84
-108
@@ -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
|
||||
df, delta, cpvalues = setcp(workout, background=background)
|
||||
if df.empty:
|
||||
return 0, 0
|
||||
if recurrance:
|
||||
df, delta, cpvalues = setcp(workout, background=background)
|
||||
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, delta, cpvalues = setcp(workout)
|
||||
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,16 +770,18 @@ 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]
|
||||
# calculate FTP
|
||||
@@ -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)
|
||||
|
||||
+836
-63
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:
|
||||
@@ -95,6 +98,7 @@ def cpfit(powerdf, fraclimit=0.0001, nmax=1000):
|
||||
else:
|
||||
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.))
|
||||
@@ -102,7 +106,7 @@ def cpfit(powerdf, fraclimit=0.0001, nmax=1000):
|
||||
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
|
||||
|
||||
+954
-5809
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 = {}
|
||||
|
||||
+7
-2
@@ -3833,9 +3833,12 @@ 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:
|
||||
pass
|
||||
try:
|
||||
shutil.rmtree(dirname)
|
||||
except:
|
||||
pass
|
||||
|
||||
# remove parquet file
|
||||
try:
|
||||
@@ -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,7 +297,23 @@ 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)
|
||||
|
||||
|
||||
+44
-124
@@ -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,
|
||||
@@ -559,7 +563,7 @@ def handle_sporttracks_workout_from_data(user, importid, source,
|
||||
strokedata = pd.DataFrame.from_dict({
|
||||
key: pd.Series(value, dtype='object') for key, value in data.items()
|
||||
})
|
||||
|
||||
|
||||
try:
|
||||
workouttype = data['type']
|
||||
except KeyError: # pragma: no cover
|
||||
@@ -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())
|
||||
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: # pragma: no cover
|
||||
rower.median_wps_erg = wps_median
|
||||
|
||||
rower.save()
|
||||
except ValueError: # pragma: no cover
|
||||
return 0
|
||||
|
||||
rower = Rower.objects.get(id=rid)
|
||||
if mode == 'water':
|
||||
rower.median_wps = wps_median
|
||||
else:
|
||||
rower.median_wps_erg = wps_median
|
||||
|
||||
rower.save()
|
||||
wps_median = 0
|
||||
except OverflowError:
|
||||
wps_median = 0
|
||||
except ColumnNotFoundError:
|
||||
wps_median = 0
|
||||
|
||||
return wps_median
|
||||
|
||||
@@ -3647,7 +3567,7 @@ def handle_c2_async_workout(alldata, userid, c2token, c2id, delaysec,
|
||||
loncoord = np.zeros(nr_rows)
|
||||
|
||||
try:
|
||||
strokelength = strokedata.loc[:, 'strokelength']
|
||||
strokelength = strokedata.loc[:,'strokelength']
|
||||
except: # pragma: no cover
|
||||
strokelength = np.zeros(nr_rows)
|
||||
|
||||
@@ -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,8 +32,7 @@
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
{{ mapscript|safe }}
|
||||
{{ mapscript|safe }}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
||||
@@ -37,8 +37,9 @@
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
{{ mapscript|safe }}
|
||||
<script>
|
||||
{{ mapscript|safe }}
|
||||
</script>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -45,7 +45,9 @@
|
||||
<li class="grid_4">
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
{{ mapscript|safe }}
|
||||
<script>
|
||||
{{ mapscript|safe }}
|
||||
</script>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -54,8 +54,7 @@
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
{{ mapscript|safe }}
|
||||
{{ mapscript|safe }}
|
||||
</div>
|
||||
</li>
|
||||
{% if records %}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<h1>{{ course.name }}</h1>
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
{{ mapscript|safe }}
|
||||
{{ mapscript|safe }}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -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.
|
||||
@@ -188,7 +187,8 @@ function copyText() {
|
||||
var dataplaying = false;
|
||||
|
||||
var videotime = 0;
|
||||
var data = JSON.parse('{{ data|safe }}');
|
||||
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>
|
||||
{{ the_div|safe }}
|
||||
</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,32 +8,26 @@
|
||||
{% 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 }}
|
||||
</div>
|
||||
{{ the_script |safe }}
|
||||
</div>
|
||||
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
<form enctype="multipart/form-data" action="" method="post">
|
||||
{% csrf_token %}
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
<div class="buttoncontainer">
|
||||
<input name="chartform" type="submit" class="button"
|
||||
value="Update Chart">
|
||||
@@ -51,28 +45,14 @@
|
||||
|
||||
<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)
|
||||
$(document).ready(function() {
|
||||
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 %}
|
||||
|
||||
+16
-15
@@ -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>
|
||||
@@ -123,22 +123,23 @@
|
||||
|
||||
<script>
|
||||
$(function($) {
|
||||
console.log('loading script');
|
||||
$.getJSON(window.location.protocol + '//'+window.location.host + '/rowers/histodata/', function(json) {
|
||||
console.log('got script');
|
||||
var counter=0;
|
||||
var script = json.script;
|
||||
var div = json.div;
|
||||
console.log('set vars');
|
||||
$("#id_sitready").remove();
|
||||
console.log('sitready removed');
|
||||
$("#id_chart").append(div);
|
||||
console.log('div appended');
|
||||
$("#id_script").append("<script>"+script+"</s"+"cript>");
|
||||
console.log('script changed');
|
||||
console.log('loading script');
|
||||
$.getJSON(window.location.protocol + '//'+window.location.host + '/rowers/histodata/', function(json) {
|
||||
console.log('got script');
|
||||
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');
|
||||
$("#id_chart").append(div);
|
||||
console.log('div appended');
|
||||
$("#id_script").append("<script>"+script+"</s"+"cript>");
|
||||
console.log('script changed');
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -52,35 +41,35 @@
|
||||
<input type="submit" value="Submit"/>
|
||||
</form>
|
||||
</p>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<h2>All workouts</h2>
|
||||
|
||||
|
||||
<p>
|
||||
<table class="listtable shortpadded">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Total Distance</td><td>{{ totalsdict|lookup:"distance"}} meters</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Duration</td><td>{{ totalsdict|lookup:"duration"}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Number of workouts</td><td>{{ totalsdict|lookup:"nrworkouts"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Average heart rate</td><td><span id="total_hr"></span> bpm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Maximum heart rate</td><td><span id="total_maxhr"></span> bpm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Average power</td><td><span id="total_power"></span> W</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Maximum power</td><td><span id="total_maxpower"></span> W</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Total Distance</td><td>{{ totalsdict|lookup:"distance"}} meters</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Duration</td><td>{{ totalsdict|lookup:"duration"}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Number of workouts</td><td>{{ totalsdict|lookup:"nrworkouts"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Average heart rate</td><td><span id="total_hr"></span> bpm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Maximum heart rate</td><td><span id="total_maxhr"></span> bpm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Average power</td><td><span id="total_power"></span> W</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Maximum power</td><td><span id="total_maxpower"></span> W</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</p>
|
||||
</li>
|
||||
@@ -90,46 +79,50 @@
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
{{ tdiv|safe }}
|
||||
<div id="t_script">
|
||||
{{ tscript|safe}}
|
||||
</div>
|
||||
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<div id="id_chart">
|
||||
{{ totaldiv|safe }}
|
||||
</div>
|
||||
</li>
|
||||
|
||||
|
||||
{% for ddict in typedicts %}
|
||||
<li class="grid_1">
|
||||
<h2>{{ ddict|lookup:"wtype"}}</h2>
|
||||
|
||||
|
||||
<p>
|
||||
<table class="listtable shortpadded">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Total Distance</td><td>{{ ddict|lookup:"distance"}} meters</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Duration</td><td>{{ ddict|lookup:"duration"}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Number of workouts</td><td>{{ ddict|lookup:"nrworkouts"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Average heart rate</td><td><span id="{{ ddict|lookup:'id'}}_hr"></span> bpm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Maximum heart rate</td><td><span id="{{ ddict|lookup:'id' }}_hrmax"></span> bpm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Average power</td><td><span id="{{ ddict|lookup:'id'}}_power"></span> W</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Maximum power</td><td><span id="{{ ddict|lookup:'id'}}_powermax"></span> W</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Total Distance</td><td>{{ ddict|lookup:"distance"}} meters</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Duration</td><td>{{ ddict|lookup:"duration"}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Number of workouts</td><td>{{ ddict|lookup:"nrworkouts"}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Average heart rate</td><td><span id="{{ ddict|lookup:'id'}}_hr"></span> bpm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Maximum heart rate</td><td><span id="{{ ddict|lookup:'id' }}_hrmax"></span> bpm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Average power</td><td><span id="{{ ddict|lookup:'id'}}_power"></span> W</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Maximum power</td><td><span id="{{ ddict|lookup:'id'}}_powermax"></span> W</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
@@ -142,40 +135,41 @@
|
||||
|
||||
<script>
|
||||
$(function($) {
|
||||
console.log('loading script for chart');
|
||||
var ed = '{{ senddate|date:"Y-m-d" }}'
|
||||
console.log('End',ed);
|
||||
console.log(window.location.protocol + '//'+window.location.host + '/rowers/history/user/{{ rower.user.id }}/data/?startdate={{ sstartdate|date:"Y-m-d" }}&enddate={{ senddate|date:"Y-m-d" }}&workouttype={{ workouttype }}&yaxis={{ yaxis }}')
|
||||
$.getJSON(window.location.protocol + '//'+window.location.host + '/rowers/history/user/{{ rower.user.id }}/data/?startdate={{ sstartdate|date:"Y-m-d" }}&enddate={{ senddate|date:"Y-m-d" }}&workouttype={{ workouttype }}&yaxis={{ yaxis }}', function(json) {
|
||||
console.log('loading script for chart');
|
||||
var ed = '{{ senddate|date:"Y-m-d" }}'
|
||||
console.log('End',ed);
|
||||
console.log(window.location.protocol + '//'+window.location.host + '/rowers/history/user/{{ rower.user.id }}/data/?startdate={{ sstartdate|date:"Y-m-d" }}&enddate={{ senddate|date:"Y-m-d" }}&workouttype={{ workouttype }}&yaxis={{ yaxis }}')
|
||||
$.getJSON(window.location.protocol + '//'+window.location.host + '/rowers/history/user/{{ rower.user.id }}/data/?startdate={{ sstartdate|date:"Y-m-d" }}&enddate={{ senddate|date:"Y-m-d" }}&workouttype={{ workouttype }}&yaxis={{ yaxis }}', function(json) {
|
||||
|
||||
|
||||
var script = json.script;
|
||||
var div = json.div;
|
||||
var totalsdict = json.totalsdict
|
||||
var listofdicts = json.listofdicts
|
||||
var activities_script = json.activities_script
|
||||
var activities_chart = json.activities_chart
|
||||
$("#id_sitready").remove();
|
||||
$("#id_chart").append(div);
|
||||
$("#id_script").append(script);
|
||||
$("#id_activities").append(activities_chart)
|
||||
$("#activities_script").append(activities_script)
|
||||
$("#total_hr").append(totalsdict.hrmean);
|
||||
$("#total_maxhr").append(totalsdict.hrmax);
|
||||
$("#total_power").append(totalsdict.powermean);
|
||||
$("#total_maxpower").append(totalsdict.powermax);
|
||||
$("#selectors").hide();
|
||||
|
||||
|
||||
var script = json.script;
|
||||
var div = json.div;
|
||||
var totalsdict = json.totalsdict
|
||||
var listofdicts = json.listofdicts
|
||||
var activities_script = json.activities_script
|
||||
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)
|
||||
$("#total_hr").append(totalsdict.hrmean);
|
||||
$("#total_maxhr").append(totalsdict.hrmax);
|
||||
$("#total_power").append(totalsdict.powermean);
|
||||
$("#total_maxpower").append(totalsdict.powermax);
|
||||
listofdicts.forEach(function(item){
|
||||
var id = "#"+item.id+"_hr";
|
||||
$(id).append(item.hrmean);
|
||||
id = "#"+item.id+"_hrmax";
|
||||
$(id).append(item.hrmax);
|
||||
id = "#"+item.id+"_power";
|
||||
$(id).append(item.powermean);
|
||||
id = "#"+item.id+"_powermax";
|
||||
$(id).append(item.powermax);
|
||||
})
|
||||
});
|
||||
listofdicts.forEach(function(item){
|
||||
var id = "#"+item.id+"_hr";
|
||||
$(id).append(item.hrmean);
|
||||
id = "#"+item.id+"_hrmax";
|
||||
$(id).append(item.hrmax);
|
||||
id = "#"+item.id+"_power";
|
||||
$(id).append(item.powermean);
|
||||
id = "#"+item.id+"_powermax";
|
||||
$(id).append(item.powermax);
|
||||
})
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -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_chart").replaceWith('<div id="id_chart">'+data.div+'</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,15 +164,24 @@ $( 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>
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
<div id="dd" class="flexplot">
|
||||
{{ dd|safe }}
|
||||
<div id="id_script">
|
||||
{{ the_script |safe }}
|
||||
</div>
|
||||
</li>
|
||||
<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>
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</script>
|
||||
<script
|
||||
type='text/javascript'
|
||||
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
@@ -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,8 +26,7 @@
|
||||
<div style="height:100%;" id="theplot" class="flexplot mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
{{ mapscript|safe }}
|
||||
{{ mapscript|safe }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
<div class="mapdiv">
|
||||
{{ mapdiv|safe }}
|
||||
{{ mapscript|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,13 +6,10 @@
|
||||
|
||||
{% 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>
|
||||
|
||||
<form enctype="multipart/form-data" action="" method="post">
|
||||
@@ -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>
|
||||
</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>
|
||||
|
||||
+121
-124
@@ -8,26 +8,26 @@
|
||||
{% block scripts %}
|
||||
{% include "monitorjobs.html" %}
|
||||
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
|
||||
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
|
||||
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
||||
<script>
|
||||
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
|
||||
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
||||
<script>
|
||||
$( function() {
|
||||
console.log({{ activeminutesmin }}, {{ activeminutesmax}}, 'active range');
|
||||
$( "#slider-range" ).slider({
|
||||
range: true,
|
||||
min: 0,
|
||||
max: {{ maxminutes }},
|
||||
values: [ {{ activeminutesmin }}, {{ activeminutesmax }} ],
|
||||
slide: function( event, ui ) {
|
||||
$( "#amount" ).val(ui.values[ 0 ] + " min - " + ui.values[ 1 ] + " min " );
|
||||
$("#id_activeminutesmin").val(ui.values[0]);
|
||||
$("#id_activeminutesmax").val(ui.values[1]);
|
||||
}
|
||||
});
|
||||
$( "#amount" ).val($( "#slider-range" ).slider( "values", 0 ) +
|
||||
" min - " + $( "#slider-range" ).slider( "values", 1 ) + " min ");
|
||||
console.log({{ activeminutesmin }}, {{ activeminutesmax}}, 'active range');
|
||||
$( "#slider-range" ).slider({
|
||||
range: true,
|
||||
min: 0,
|
||||
max: {{ maxminutes }},
|
||||
values: [ {{ activeminutesmin }}, {{ activeminutesmax }} ],
|
||||
slide: function( event, ui ) {
|
||||
$( "#amount" ).val(ui.values[ 0 ] + " min - " + ui.values[ 1 ] + " min " );
|
||||
$("#id_activeminutesmin").val(ui.values[0]);
|
||||
$("#id_activeminutesmax").val(ui.values[1]);
|
||||
}
|
||||
});
|
||||
$( "#amount" ).val($( "#slider-range" ).slider( "values", 0 ) +
|
||||
" min - " + $( "#slider-range" ).slider( "values", 1 ) + " min ");
|
||||
} );
|
||||
</script>
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
@@ -42,78 +42,75 @@
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
<table width=100%>
|
||||
<tr>
|
||||
<th>Name</th><td>{{ workout.name }}</td>
|
||||
</tr><tr>
|
||||
<th>Distance:</th><td>{{ workout.distance }}m</td>
|
||||
</tr><tr>
|
||||
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
|
||||
</tr><tr>
|
||||
<th>Public link to this workout</th>
|
||||
<td>
|
||||
<table width=100%>
|
||||
<tr>
|
||||
<th>Name</th><td>{{ workout.name }}</td>
|
||||
</tr><tr>
|
||||
<th>Distance:</th><td>{{ workout.distance }}m</td>
|
||||
</tr><tr>
|
||||
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
|
||||
</tr><tr>
|
||||
<th>Public link to this workout</th>
|
||||
<td>
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/">https://rowsandall.com/rowers/workout/{{ workout.id|encode }}</a>
|
||||
<td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
||||
<h1>Edit Workout Interval Data</h1>
|
||||
<p>
|
||||
Use "Interval Shorthand", "Feeling lucky?", or "Intervals by power/pace" methods below to edit work and rest
|
||||
intervals. To save your work, press the Save button above the updated summary.
|
||||
Use "Interval Shorthand", "Feeling lucky?", or "Intervals by power/pace" methods below to edit work and rest
|
||||
intervals. To save your work, press the Save button above the updated summary.
|
||||
</p>
|
||||
<ul class="main-content">
|
||||
<li class="grid_2">
|
||||
<h1>Updated Summary</h1>
|
||||
<form enctype="multipart/form-data" action="/rowers/workout/{{ workout.id|encode }}/editintervals/" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="{{ savebutton }}" value="{{ intervalstring }}">
|
||||
<input type="hidden" name="nrintervals" value={{ nrintervals }}>
|
||||
{% for key,value in formvalues.items %}
|
||||
<input type="hidden" name="{{ key }}" value="{{ value|safe }}">
|
||||
{% endfor %}
|
||||
<p>
|
||||
<input type="submit" value="Save">
|
||||
</p>
|
||||
<span>
|
||||
<a href="">Reset to last saved</a>
|
||||
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/restore/">Restore Original data</a>
|
||||
</span>
|
||||
</form>
|
||||
<p>
|
||||
<pre>
|
||||
{{ intervalstats }}
|
||||
</pre>
|
||||
</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 }}
|
||||
|
||||
{{ the_div |safe }}
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<h1>Feeling lucky?</h1>
|
||||
<p>This new, experimental feature tries to find intervals by looking for patterns in the data. It does not
|
||||
autodetect rest and work intervals yet. The resulting "interval string" is copied to the Interval Shorthand
|
||||
section below, where you can edit it.
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
<input type="hidden" name="ruptures" value="ruptures">
|
||||
<table width=100%>
|
||||
{{ ruptureform.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<input class="button" type="submit" value="I'm feeling lucky">
|
||||
</form>
|
||||
</p>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<li class="grid_2">
|
||||
<h1>Updated Summary</h1>
|
||||
<form enctype="multipart/form-data" action="/rowers/workout/{{ workout.id|encode }}/editintervals/" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="{{ savebutton }}" value="{{ intervalstring }}">
|
||||
<input type="hidden" name="nrintervals" value={{ nrintervals }}>
|
||||
{% for key,value in formvalues.items %}
|
||||
<input type="hidden" name="{{ key }}" value="{{ value|safe }}">
|
||||
{% endfor %}
|
||||
<p>
|
||||
<input type="submit" value="Save">
|
||||
</p>
|
||||
<span>
|
||||
<a href="">Reset to last saved</a>
|
||||
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/restore/">Restore Original data</a>
|
||||
</span>
|
||||
</form>
|
||||
<p>
|
||||
<pre>
|
||||
{{ intervalstats }}
|
||||
</pre>
|
||||
</p>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
|
||||
{{ the_div |safe }}
|
||||
{{ interactiveplot |safe }}
|
||||
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<h1>Feeling lucky?</h1>
|
||||
<p>This new, experimental feature tries to find intervals by looking for patterns in the data. It does not
|
||||
autodetect rest and work intervals yet. The resulting "interval string" is copied to the Interval Shorthand
|
||||
section below, where you can edit it.
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
<input type="hidden" name="ruptures" value="ruptures">
|
||||
<table width=100%>
|
||||
{{ ruptureform.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<input class="button" type="submit" value="I'm feeling lucky">
|
||||
</form>
|
||||
</p>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<h1>Interval Shorthand</h1>
|
||||
<p>
|
||||
See the how-to <a href="#howto">at the bottom of this page</a> for details on how to use this form.
|
||||
@@ -125,26 +122,26 @@
|
||||
{% csrf_token %}
|
||||
<input class="button" type="submit" value="Update">
|
||||
</form>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<h1>Intervals by Power/Pace</h1>
|
||||
|
||||
|
||||
<p>With this form, you can specify a power or pace level. Everything faster/harder than the
|
||||
specified pace/power will become a work interval. Everything slower will become a rest
|
||||
interval. Use the slider to limit the active range. Everything outside the active range will
|
||||
become rest (warming up and cooling down).
|
||||
become rest (warming up and cooling down).
|
||||
</p>
|
||||
|
||||
|
||||
<form ecntype="multipart/form-data" method="post">
|
||||
<div id="slider-range"></div>
|
||||
<p>
|
||||
<label for="amount">Active Range:</label>
|
||||
<input type="text" id="amount" readonly style="border:0; color:#1c75bc; font-weight:bold;">
|
||||
</p>
|
||||
<div id="slider-range"></div>
|
||||
<p>
|
||||
<label for="amount">Active Range:</label>
|
||||
<input type="text" id="amount" readonly style="border:0; color:#1c75bc; font-weight:bold;">
|
||||
</p>
|
||||
<table>
|
||||
{{ powerupdateform.as_table }}
|
||||
</table>
|
||||
|
||||
|
||||
{% csrf_token %}
|
||||
<input class="button" type="submit" value="Submit">
|
||||
</form>
|
||||
@@ -153,11 +150,11 @@
|
||||
<h1 id="howto">Interval Shorthand How-To</h1>
|
||||
<p>This is a quick way to enter the intervals using a special mini-language.</p>
|
||||
<p>You enter something like <em>8x500m/3min</em>, press "Update" and the site will interpret this for you and update the summary on the right. If you're happy with the result, press the green Save button to update the values. Nothing will be changed permanently until you hit Save.</p>
|
||||
|
||||
|
||||
<p>Special characters are <em>x</em> (times), <em>+</em> and <em>/</em> (denotes a rest interval), as well as <em>(</em> and <em>)</em>. Units are <em>min</em> (minutes), <em>sec</em> (seconds), <em>m</em> (meters) and <em>km</em> (km). </p>
|
||||
|
||||
|
||||
<p>A typical interval is described as "<b>10min/5min</b>", with the work part before the "<b>/</b>" and the rest part after it. A zero rest can be omitted, so a single 1000m piece could be described either as "<b>1km</b>" or "<b>1000m</b>". The basic units can be combined with "<b>+</b>" and "<b>Nx</b>". You can use parentheses as in the example below.</p>
|
||||
|
||||
|
||||
<p>Here are a few examples</p>
|
||||
<table class="listtable" width=100%>
|
||||
<tr>
|
||||
@@ -182,32 +179,32 @@
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
{% if courses %}
|
||||
<li>
|
||||
<h1>Interval by Course</h1>
|
||||
<p>
|
||||
This functionality allows you to record a time on a set course that you've rowed during the workout.
|
||||
The summary will be updated to show time on course, and you can compare this with other
|
||||
attempts.
|
||||
</p>
|
||||
<p>
|
||||
{% if rower.share_course_results %}
|
||||
You are currently sharing your course results with all Rowsandall users.
|
||||
Click <a href="/rowers/me/edit/?courseshare=false">here</a> to hide your course results.
|
||||
{% else %}
|
||||
You are currently hiding your course results (except for your participation in online challenges).
|
||||
Click <a href="/rowers/me/edit/?courseshare=true">here</a> to hide your course results.
|
||||
{% endif %}
|
||||
</p>
|
||||
<form ecntype="multipart/form-data" method="post">
|
||||
<table>
|
||||
{{ courseselectform.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<input class="button" type="submit" value="Select Course">
|
||||
</form>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if courses %}
|
||||
<li>
|
||||
<h1>Interval by Course</h1>
|
||||
<p>
|
||||
This functionality allows you to record a time on a set course that you've rowed during the workout.
|
||||
The summary will be updated to show time on course, and you can compare this with other
|
||||
attempts.
|
||||
</p>
|
||||
<p>
|
||||
{% if rower.share_course_results %}
|
||||
You are currently sharing your course results with all Rowsandall users.
|
||||
Click <a href="/rowers/me/edit/?courseshare=false">here</a> to hide your course results.
|
||||
{% else %}
|
||||
You are currently hiding your course results (except for your participation in online challenges).
|
||||
Click <a href="/rowers/me/edit/?courseshare=true">here</a> to hide your course results.
|
||||
{% endif %}
|
||||
</p>
|
||||
<form ecntype="multipart/form-data" method="post">
|
||||
<table>
|
||||
{{ courseselectform.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<input class="button" type="submit" value="Select Course">
|
||||
</form>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -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>
|
||||
{{ the_div|safe }}
|
||||
</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,33 +388,15 @@
|
||||
|
||||
</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 }}
|
||||
</div>
|
||||
<div id="id_chart">
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
<p>You can use the date and search forms to search through all
|
||||
@@ -438,144 +421,144 @@
|
||||
{{ chartform.as_table }}
|
||||
</table>
|
||||
</li>
|
||||
<li class="grid_2 maxheight">
|
||||
<p>{{ searchform }}</p>
|
||||
|
||||
{% if workouts %}
|
||||
|
||||
<input type="checkbox" onClick="toggle(this)" /> Toggle All<br/>
|
||||
<table width="100%" class="listtable">
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{% else %}
|
||||
<p> No workouts found </p>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
{% csrf_token %}
|
||||
<input name='optionsform' type="submit" value="Submit">
|
||||
</form>
|
||||
<li class="grid_2 maxheight">
|
||||
<p>{{ searchform }}</p>
|
||||
|
||||
{% if workouts %}
|
||||
|
||||
<input type="checkbox" onClick="toggle(this)" /> Toggle All<br/>
|
||||
<table width="100%" class="listtable">
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{% else %}
|
||||
<p> No workouts found </p>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% if worldclass %}
|
||||
{% if age and sex != 'not specified' %}
|
||||
<li class="grid_4">
|
||||
<h2>Gold Medal Standards</h2>
|
||||
<p>The dashed lines are based on the
|
||||
<a href="https://log.concept2.com/rankings">Concept2</a>
|
||||
rankings for your age ({{ age }}), gender ({{ sex }})
|
||||
and weight category ({{ weightcategory }}). The Gold Medal
|
||||
Standard power is derived from the
|
||||
<a href="http://www.concept2.com/indoor-rowers/racing/records/world">
|
||||
World Record</a> for your category.
|
||||
The percentile lines are estimates of where the percentiles
|
||||
of the Concept2 rankings historically are for those of exactly
|
||||
your age, gender and weight class.
|
||||
</p>
|
||||
<p>
|
||||
For rowing on the water, the results are corrected for the expected
|
||||
difference in power between the Concept2 indoor rower and power
|
||||
values on the water.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<table width="100%" class="listtable">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/100m/">100m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/500m/">500m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/1000m/">1000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/2000m/">2000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/5000m/">5000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/6000m/">6000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/10000m/">10000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/21097m/">Half Marathon
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/42195m/">Full Marathon
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/1min/">1 minute
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/4min/">4 minutes
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/30min/">30 minutes
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/60min/">1 hour
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<li class="grid_2">
|
||||
{% csrf_token %}
|
||||
<input name='optionsform' type="submit" value="Submit">
|
||||
</form>
|
||||
</li>
|
||||
{% if worldclass %}
|
||||
{% if age and sex != 'not specified' %}
|
||||
<li class="grid_4">
|
||||
<h2>Gold Medal Standards</h2>
|
||||
<p>The dashed lines are based on the
|
||||
<a href="https://log.concept2.com/rankings">Concept2</a>
|
||||
rankings for your age ({{ age }}), gender ({{ sex }})
|
||||
and weight category ({{ weightcategory }}). The Gold Medal
|
||||
Standard power is derived from the
|
||||
<a href="http://www.concept2.com/indoor-rowers/racing/records/world">
|
||||
World Record</a> for your category.
|
||||
The percentile lines are estimates of where the percentiles
|
||||
of the Concept2 rankings historically are for those of exactly
|
||||
your age, gender and weight class.
|
||||
</p>
|
||||
<p>
|
||||
For rowing on the water, the results are corrected for the expected
|
||||
difference in power between the Concept2 indoor rower and power
|
||||
values on the water.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<table width="100%" class="listtable">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/100m/">100m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/500m/">500m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/1000m/">1000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/2000m/">2000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/5000m/">5000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/6000m/">6000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/10000m/">10000m
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_"
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/21097m/">Half Marathon
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/42195m/">Full Marathon
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/1min/">1 minute
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/4min/">4 minutes
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/30min/">30 minutes
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="/rowers/agegrouprecords/{{ sex }}/{{ weightcategory }}/60min/">1 hour
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
@@ -67,7 +67,9 @@
|
||||
<div class="mapdiv">
|
||||
|
||||
{{ gmapdiv |safe }}
|
||||
{{ gmap |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 %}
|
||||
|
||||
@@ -104,58 +104,53 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% for course in courses %}
|
||||
<tr>
|
||||
<th>
|
||||
Timed Course:
|
||||
</th>
|
||||
<td>
|
||||
<a href="/rowers/courses/{{ course.id }}"/>{{ course }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<h1>Workout Summary</h1>
|
||||
|
||||
<p>
|
||||
<pre>
|
||||
{{ summary }}
|
||||
</pre>
|
||||
</p>
|
||||
</li>
|
||||
{% if mapdiv %}
|
||||
<li class="grid_2">
|
||||
<div class="mapdiv">
|
||||
|
||||
{% for course in courses %}
|
||||
<tr>
|
||||
<th>
|
||||
Timed Course:
|
||||
</th>
|
||||
<td>
|
||||
<a href="/rowers/courses/{{ course.id }}"/>{{ course }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<h1>Workout Summary</h1>
|
||||
|
||||
<p>
|
||||
<pre>
|
||||
{{ summary }}
|
||||
</pre>
|
||||
</p>
|
||||
</li>
|
||||
{% if mapdiv %}
|
||||
<li class="grid_2">
|
||||
<div class="mapdiv">
|
||||
|
||||
{{ mapdiv|safe }}
|
||||
|
||||
|
||||
{{ mapscript|safe }}
|
||||
</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>
|
||||
{{ mapscript|safe }}
|
||||
</script>
|
||||
|
||||
{{ interactiveplot |safe }}
|
||||
|
||||
{{ the_div|safe }}
|
||||
|
||||
</li>
|
||||
{% for graph in graphs %}
|
||||
<li>
|
||||
<a href="/rowers/graph/{{ graph.id }}/">
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="grid_2">
|
||||
<script src="https://d3js.org/d3.v6.js"></script>
|
||||
{{ the_div|safe }}
|
||||
{{ interactiveplot |safe }}
|
||||
</li>
|
||||
{% for graph in graphs %}
|
||||
<li>
|
||||
<a href="/rowers/graph/{{ graph.id }}/">
|
||||
<img src="/{{ graph.filename }}"
|
||||
onerror="this.src='/static/img/rowingtimer.gif'"
|
||||
alt="{{ graph.filename }}" width="120" height="100">
|
||||
</a>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
+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)
|
||||
|
||||
|
||||
+22
-16
@@ -58,19 +58,22 @@ class OwnApi(TestCase):
|
||||
response = self.c.get(url)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
url = reverse('strokedatajson',kwargs={'id':w.id})
|
||||
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)
|
||||
request.user = self.u
|
||||
force_authenticate(request, user=self.u)
|
||||
response = strokedatajson(request,id=w.id)
|
||||
self.assertEqual(response.status_code,200)
|
||||
request = self.factory.get(url)
|
||||
request.user = self.u
|
||||
force_authenticate(request, user=self.u)
|
||||
response = strokedatajson(request,id=w.id)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
# response must be json
|
||||
strokedata = json.loads(response.content)
|
||||
df = pd.DataFrame(strokedata)
|
||||
# response must be json
|
||||
|
||||
strokedata = json.loads(response.content)
|
||||
df = pl.from_dict(strokedata)
|
||||
|
||||
self.assertFalse(df.empty)
|
||||
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)
|
||||
response = strokedatajson_v2(request,id=w.id)
|
||||
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')
|
||||
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)
|
||||
# response must be json
|
||||
strokedata = json.loads(response.content)
|
||||
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,
|
||||
@@ -225,7 +212,7 @@ class URLTests(TestCase):
|
||||
self.assertTrue(login)
|
||||
response = self.c.get(url,follow=True)
|
||||
if response.status_code != expected:
|
||||
print(url )
|
||||
print(url)
|
||||
print(response.status_code)
|
||||
|
||||
self.assertEqual(response.status_code,
|
||||
|
||||
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):
|
||||
|
||||
+71
-602
@@ -296,7 +296,10 @@ def analysis_new(request,
|
||||
df = cpdata(tw, options)
|
||||
options['savedata'] = False
|
||||
request.session['options'] = options
|
||||
response = HttpResponse(df.to_csv())
|
||||
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,
|
||||
trainingzones=zones, date_agg=date_agg, yaxis=yaxis)
|
||||
if (enddate-startdate).days > 200:
|
||||
date_agg = "month"
|
||||
|
||||
script, div = interactive_zoneschart(
|
||||
data = get_zones_report_pl(r, startdate, enddate,
|
||||
trainingzones=zones, date_agg=date_agg, yaxis=yaxis)
|
||||
|
||||
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']
|
||||
|
||||
df = getsmallrowdata_db(columns, ids=ids)
|
||||
columns = ['hr', 'power', 'time', 'workoutstate', 'workoutid']
|
||||
|
||||
df = dataprep.read_data(columns, ids=ids)
|
||||
df = dataprep.remove_nulls_pl(df)
|
||||
|
||||
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
|
||||
|
||||
+40
-496
@@ -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
|
||||
os.remove(w.csvfilename+'.gz')
|
||||
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:
|
||||
@@ -5188,7 +4732,7 @@ def workout_uploadimage_view(request, id): # pragma: no cover
|
||||
# Generic chart creation
|
||||
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
|
||||
def workout_add_chart_view(request, id, plotnr=1):
|
||||
|
||||
|
||||
w = get_workoutuser(id, request)
|
||||
r = getrower(request.user)
|
||||
|
||||
|
||||
@@ -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