Merge branch 'develop' into feature/restapi
This commit is contained in:
@@ -8,6 +8,7 @@ from pandas import DataFrame,Series
|
|||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import itertools
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
@@ -84,9 +85,33 @@ def rdata(file,rower=rrower()):
|
|||||||
|
|
||||||
def getrowdata_db(id=0):
|
def getrowdata_db(id=0):
|
||||||
data = read_df_sql(id)
|
data = read_df_sql(id)
|
||||||
|
data['pace'] = data['pace']/1.0e6
|
||||||
|
data['ergpace'] = data['ergpace']/1.0e6
|
||||||
|
data['nowindpace'] = data['nowindpace']/1.0e6
|
||||||
|
data['time'] = data['time']/1.0e6
|
||||||
|
data['x_right'] = data['x_right']/1.0e6
|
||||||
if data.empty:
|
if data.empty:
|
||||||
rowdata,row = getrowdata(id=id)
|
rowdata,row = getrowdata(id=id)
|
||||||
data = dataprep(rowdata.df,id=id,bands=True,barchart=True,otwpower=True)
|
if rowdata:
|
||||||
|
data = dataprep(rowdata.df,id=id,bands=True,barchart=True,otwpower=True)
|
||||||
|
else:
|
||||||
|
data = pd.DataFrame() # returning empty dataframe
|
||||||
|
else:
|
||||||
|
row = Workout.objects.get(id=id)
|
||||||
|
|
||||||
|
return data,row
|
||||||
|
|
||||||
|
def getsmallrowdata_db(xparam,yparam1,yparam2,ids=[]):
|
||||||
|
if yparam2 == 'None':
|
||||||
|
yparam2 = yparam1
|
||||||
|
prepmultipledata(ids)
|
||||||
|
data = read_cols_df_sql(ids,xparam,yparam1,yparam2)
|
||||||
|
if xparam == 'time':
|
||||||
|
data['time'] = data['time']/1.0e6
|
||||||
|
if yparam1 == 'pace':
|
||||||
|
data['pace'] = data['pace']/1.0e6
|
||||||
|
if yparam2 == 'pace':
|
||||||
|
data['pace'] = data['pace']/1.0e6
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@@ -110,7 +135,34 @@ def getrowdata(id=0):
|
|||||||
|
|
||||||
return rowdata,row
|
return rowdata,row
|
||||||
|
|
||||||
# temporary
|
def prepmultipledata(ids):
|
||||||
|
query = sa.text('SELECT DISTINCT workoutid FROM strokedata')
|
||||||
|
with engine.connect() as conn, conn.begin():
|
||||||
|
res = conn.execute(query)
|
||||||
|
res = list(itertools.chain.from_iterable(res.fetchall()))
|
||||||
|
|
||||||
|
res = list(set(ids)-set(res))
|
||||||
|
|
||||||
|
for id in res:
|
||||||
|
rowdata,row = getrowdata(id=id)
|
||||||
|
if rowdata:
|
||||||
|
data = dataprep(rowdata.df,id=id,bands=True,barchart=True,otwpower=True)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def read_cols_df_sql(ids,col1,col2,col3):
|
||||||
|
columns = list(set((col1,col2,col3,'distance','spm')))
|
||||||
|
cls = ''
|
||||||
|
for column in columns:
|
||||||
|
cls += column+', '
|
||||||
|
cls = cls[:-2]
|
||||||
|
query = sa.text('SELECT {columns} FROM strokedata WHERE workoutid IN {ids}'.format(
|
||||||
|
columns = cls,
|
||||||
|
ids = tuple(ids),
|
||||||
|
))
|
||||||
|
df = pd.read_sql_query(query,engine)
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
def read_df_sql(id):
|
def read_df_sql(id):
|
||||||
df = pd.read_sql_query(sa.text('SELECT * FROM strokedata WHERE workoutid={id}'.format(
|
df = pd.read_sql_query(sa.text('SELECT * FROM strokedata WHERE workoutid={id}'.format(
|
||||||
id=id)), engine)
|
id=id)), engine)
|
||||||
@@ -118,6 +170,37 @@ def read_df_sql(id):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def smalldataprep(therows,xparam,yparam1,yparam2):
|
||||||
|
df = pd.DataFrame()
|
||||||
|
if yparam2 == 'None':
|
||||||
|
yparam2 = 'power'
|
||||||
|
df[xparam] = []
|
||||||
|
df[yparam1] = []
|
||||||
|
df[yparam2] = []
|
||||||
|
df['distance'] = []
|
||||||
|
df['spm'] = []
|
||||||
|
for workout in therows:
|
||||||
|
f1 = workout.csvfilename
|
||||||
|
|
||||||
|
try:
|
||||||
|
rowdata = dataprep(rrdata(f1).df)
|
||||||
|
|
||||||
|
rowdata = pd.DataFrame({xparam: rowdata[xparam],
|
||||||
|
yparam1: rowdata[yparam1],
|
||||||
|
yparam2: rowdata[yparam2],
|
||||||
|
'distance': rowdata['distance'],
|
||||||
|
'spm': rowdata['spm'],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
df = pd.concat([df,rowdata],ignore_index=True)
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return df
|
||||||
|
|
||||||
|
|
||||||
def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False):
|
def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False):
|
||||||
rowdatadf.set_index([range(len(rowdatadf))],inplace=True)
|
rowdatadf.set_index([range(len(rowdatadf))],inplace=True)
|
||||||
t = rowdatadf.ix[:,'TimeStamp (sec)']
|
t = rowdatadf.ix[:,'TimeStamp (sec)']
|
||||||
@@ -134,8 +217,11 @@ def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False):
|
|||||||
power = rowdatadf.ix[:,' Power (watts)']
|
power = rowdatadf.ix[:,' Power (watts)']
|
||||||
averageforce = rowdatadf.ix[:,' AverageDriveForce (lbs)']
|
averageforce = rowdatadf.ix[:,' AverageDriveForce (lbs)']
|
||||||
drivelength = rowdatadf.ix[:,' DriveLength (meters)']
|
drivelength = rowdatadf.ix[:,' DriveLength (meters)']
|
||||||
|
try:
|
||||||
|
workoutstate = rowdatadf.ix[:,' WorkoutState']
|
||||||
|
except KeyError:
|
||||||
|
workoutstate = 0*hr
|
||||||
|
|
||||||
peakforce = rowdatadf.ix[:,' PeakDriveForce (lbs)']
|
peakforce = rowdatadf.ix[:,' PeakDriveForce (lbs)']
|
||||||
|
|
||||||
forceratio = averageforce/peakforce
|
forceratio = averageforce/peakforce
|
||||||
@@ -152,7 +238,10 @@ def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False):
|
|||||||
drivelength = savgol_filter(drivelength,windowsize,3)
|
drivelength = savgol_filter(drivelength,windowsize,3)
|
||||||
forceratio = savgol_filter(forceratio,windowsize,3)
|
forceratio = savgol_filter(forceratio,windowsize,3)
|
||||||
|
|
||||||
t2 = t.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
|
try:
|
||||||
|
t2 = t.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
|
||||||
|
except TypeError:
|
||||||
|
t2 = 0*t
|
||||||
|
|
||||||
|
|
||||||
p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
|
p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
|
||||||
@@ -179,6 +268,7 @@ def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False):
|
|||||||
fpace = nicepaceformat(p2),
|
fpace = nicepaceformat(p2),
|
||||||
driveenergy=driveenergy,
|
driveenergy=driveenergy,
|
||||||
power=power,
|
power=power,
|
||||||
|
workoutstate=workoutstate,
|
||||||
averageforce=averageforce,
|
averageforce=averageforce,
|
||||||
drivelength=drivelength,
|
drivelength=drivelength,
|
||||||
peakforce=peakforce,
|
peakforce=peakforce,
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ from rowingdata import cumcpdata,histodata
|
|||||||
|
|
||||||
from rowingdata import rowingdata as rrdata
|
from rowingdata import rowingdata as rrdata
|
||||||
|
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
|
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
|
||||||
from bokeh.models import CustomJS,Slider
|
from bokeh.models import CustomJS,Slider
|
||||||
from bokeh.charts import Histogram
|
from bokeh.charts import Histogram,HeatMap
|
||||||
from bokeh.resources import CDN,INLINE
|
from bokeh.resources import CDN,INLINE
|
||||||
from bokeh.embed import components
|
from bokeh.embed import components
|
||||||
from bokeh.layouts import layout,widgetbox
|
from bokeh.layouts import layout,widgetbox
|
||||||
@@ -68,14 +70,13 @@ from rowers.dataprep import timedeltaconv
|
|||||||
def interactive_histoall(theworkouts):
|
def interactive_histoall(theworkouts):
|
||||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
|
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
|
||||||
|
|
||||||
therows = []
|
ids = [w.id for w in theworkouts]
|
||||||
for workout in theworkouts:
|
rowdata = dataprep.getsmallrowdata_db('power','power','power',ids=ids)
|
||||||
f1 = workout.csvfilename
|
|
||||||
rowdata = rdata(f1)
|
histopwr = rowdata['power'].values
|
||||||
if rowdata != 0:
|
if len(histopwr) == 0:
|
||||||
therows.append(rowdata)
|
return "","CSV file not found","",""
|
||||||
|
|
||||||
histopwr = histodata(therows)
|
|
||||||
# throw out nans
|
# throw out nans
|
||||||
histopwr = histopwr[~np.isinf(histopwr)]
|
histopwr = histopwr[~np.isinf(histopwr)]
|
||||||
histopwr = histopwr[histopwr > 25]
|
histopwr = histopwr[histopwr > 25]
|
||||||
@@ -494,18 +495,15 @@ def interactive_chart(id=0,promember=0):
|
|||||||
else:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
|
||||||
rowdata,row = dataprep.getrowdata(id=id)
|
|
||||||
if rowdata == 0:
|
datadf,row = dataprep.getrowdata_db(id=id)
|
||||||
|
if datadf.empty:
|
||||||
return "","CSV Data File Not Found"
|
return "","CSV Data File Not Found"
|
||||||
|
|
||||||
datadf = dataprep.dataprep(rowdata.df)
|
|
||||||
|
|
||||||
source = ColumnDataSource(
|
source = ColumnDataSource(
|
||||||
datadf
|
datadf
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
|
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
|
||||||
plot_width=400,
|
plot_width=400,
|
||||||
plot_height=400,
|
plot_height=400,
|
||||||
@@ -552,10 +550,10 @@ def interactive_chart(id=0,promember=0):
|
|||||||
|
|
||||||
hover.mode = 'mouse'
|
hover.mode = 'mouse'
|
||||||
|
|
||||||
plot.extra_y_ranges = {"hr": Range1d(start=100,end=200)}
|
plot.extra_y_ranges = {"hrax": Range1d(start=100,end=200)}
|
||||||
plot.line('time','hr',source=source,color="red",
|
plot.line('time','hr',source=source,color="red",
|
||||||
y_range_name="hr", legend="Heart Rate")
|
y_range_name="hrax", legend="Heart Rate")
|
||||||
plot.add_layout(LinearAxis(y_range_name="hr",axis_label="HR"),'right')
|
plot.add_layout(LinearAxis(y_range_name="hrax",axis_label="HR"),'right')
|
||||||
|
|
||||||
plot.legend.location = "bottom_right"
|
plot.legend.location = "bottom_right"
|
||||||
|
|
||||||
@@ -563,23 +561,15 @@ def interactive_chart(id=0,promember=0):
|
|||||||
|
|
||||||
return [script,div]
|
return [script,div]
|
||||||
|
|
||||||
def interactive_cum_flex_chart(theworkouts,promember=0,
|
def interactive_cum_flex_chart2(theworkouts,promember=0,
|
||||||
xparam='spm',
|
xparam='spm',
|
||||||
yparam1='power',
|
yparam1='power',
|
||||||
yparam2='hr',
|
yparam2='spm'):
|
||||||
):
|
|
||||||
|
|
||||||
|
|
||||||
therows = []
|
|
||||||
for workout in theworkouts:
|
|
||||||
f1 = workout.csvfilename
|
|
||||||
rowdata = rdata(f1)
|
|
||||||
if rowdata != 0:
|
|
||||||
therows.append(rowdata.df)
|
|
||||||
|
|
||||||
datadf = pd.concat(therows)
|
|
||||||
|
|
||||||
|
|
||||||
|
# datadf = dataprep.smalldataprep(theworkouts,xparam,yparam1,yparam2)
|
||||||
|
ids = [w.id for w in theworkouts]
|
||||||
|
datadf = dataprep.getsmallrowdata_db(xparam,yparam1,yparam2,ids=ids)
|
||||||
|
|
||||||
axlabels = {
|
axlabels = {
|
||||||
'time': 'Time',
|
'time': 'Time',
|
||||||
'distance': 'Distance (m)',
|
'distance': 'Distance (m)',
|
||||||
@@ -626,21 +616,11 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
datadf = dataprep.dataprep(datadf)
|
|
||||||
|
|
||||||
if yparam1 != 'pace' and yparam1 != 'time':
|
datadf = datadf[datadf[yparam1] > 0]
|
||||||
datadf = datadf[datadf[yparam1] > 0]
|
|
||||||
elif yparam1 == 'time':
|
|
||||||
datadf = datadf[datadf['timesecs'] > 0]
|
|
||||||
else:
|
|
||||||
datadf = datadf[datadf['pseconds']>0]
|
|
||||||
|
|
||||||
if xparam != 'time' and xparam != 'pace':
|
|
||||||
datadf = datadf[datadf[xparam] > 0]
|
datadf = datadf[datadf[xparam] > 0]
|
||||||
elif xparam == 'time':
|
|
||||||
datadf = datadf[datadf['timesecs']>0]
|
|
||||||
else:
|
|
||||||
datadf = datadf[datadf['pseconds']>0]
|
|
||||||
|
|
||||||
if yparam2 != 'None':
|
if yparam2 != 'None':
|
||||||
datadf = datadf[datadf[yparam2] > 0]
|
datadf = datadf[datadf[yparam2] > 0]
|
||||||
@@ -651,9 +631,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
|
|
||||||
|
|
||||||
datadf['x1'] = datadf.ix[:,xparam]
|
datadf['x1'] = datadf.ix[:,xparam]
|
||||||
tseconds = datadf.ix[:,'timesecs']
|
|
||||||
|
|
||||||
|
|
||||||
datadf['y1'] = datadf.ix[:,yparam1]
|
datadf['y1'] = datadf.ix[:,yparam1]
|
||||||
if yparam2 != 'None':
|
if yparam2 != 'None':
|
||||||
datadf['y2'] = datadf.ix[:,yparam2]
|
datadf['y2'] = datadf.ix[:,yparam2]
|
||||||
@@ -661,12 +639,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
datadf['y2'] = datadf['y1']
|
datadf['y2'] = datadf['y1']
|
||||||
|
|
||||||
|
|
||||||
if xparam=='time':
|
if xparam=='distance':
|
||||||
xaxmax = tseconds.max()
|
|
||||||
xaxmin = tseconds.min()
|
|
||||||
xaxmax = 1.0e3*xaxmax
|
|
||||||
xaxmin = 1.0e3*xaxmin
|
|
||||||
elif xparam=='distance':
|
|
||||||
xaxmax = datadf['x1'].max()
|
xaxmax = datadf['x1'].max()
|
||||||
xaxmin = datadf['x1'].min()
|
xaxmin = datadf['x1'].min()
|
||||||
else:
|
else:
|
||||||
@@ -674,27 +647,16 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
xaxmin = yaxminima[xparam]
|
xaxmin = yaxminima[xparam]
|
||||||
|
|
||||||
# average values
|
# average values
|
||||||
if xparam != 'time':
|
x1mean = datadf['x1'].mean()
|
||||||
x1mean = datadf['x1'].mean()
|
|
||||||
else:
|
|
||||||
x1mean = 0
|
|
||||||
|
|
||||||
y1mean = datadf['y1'].mean()
|
y1mean = datadf['y1'].mean()
|
||||||
y2mean = datadf['y2'].mean()
|
y2mean = datadf['y2'].mean()
|
||||||
|
|
||||||
if xparam != 'time':
|
|
||||||
xvals = pd.Series(xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.)
|
xvals = pd.Series(xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.)
|
||||||
else:
|
|
||||||
xvals = pd.Series(np.arange(100))
|
|
||||||
|
|
||||||
x_axis_type = 'linear'
|
x_axis_type = 'linear'
|
||||||
y_axis_type = 'linear'
|
y_axis_type = 'linear'
|
||||||
if xparam == 'time':
|
|
||||||
x_axis_type = 'datetime'
|
|
||||||
|
|
||||||
if yparam1 == 'pace':
|
|
||||||
y_axis_type = 'datetime'
|
|
||||||
y1mean = datadf.ix[:,'pseconds'].mean()
|
|
||||||
|
|
||||||
datadf['xname'] = xparam
|
datadf['xname'] = xparam
|
||||||
datadf['yname1'] = yparam1
|
datadf['yname1'] = yparam1
|
||||||
@@ -703,6 +665,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
else:
|
else:
|
||||||
datadf['yname2'] = yparam1
|
datadf['yname2'] = yparam1
|
||||||
|
|
||||||
|
|
||||||
source = ColumnDataSource(
|
source = ColumnDataSource(
|
||||||
datadf
|
datadf
|
||||||
)
|
)
|
||||||
@@ -713,9 +676,9 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
|
|
||||||
# Add hover to this comma-separated string and see what changes
|
# Add hover to this comma-separated string and see what changes
|
||||||
if (promember==1):
|
if (promember==1):
|
||||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
|
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
|
||||||
else:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
|
||||||
|
|
||||||
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
|
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
|
||||||
tools=TOOLS,
|
tools=TOOLS,
|
||||||
@@ -735,9 +698,9 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
text_color='green',
|
text_color='green',
|
||||||
)
|
)
|
||||||
|
|
||||||
if (xparam != 'time') and (xparam != 'distance'):
|
|
||||||
plot.add_layout(x1means)
|
plot.add_layout(x1means)
|
||||||
plot.add_layout(xlabel)
|
plot.add_layout(xlabel)
|
||||||
|
|
||||||
plot.add_layout(y1means)
|
plot.add_layout(y1means)
|
||||||
|
|
||||||
@@ -746,8 +709,8 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
background_fill_alpha=.7,
|
background_fill_alpha=.7,
|
||||||
text_color='blue',
|
text_color='blue',
|
||||||
)
|
)
|
||||||
if yparam1 != 'time' and yparam1 != 'pace':
|
|
||||||
plot.add_layout(y1label)
|
plot.add_layout(y1label)
|
||||||
|
|
||||||
y2label = y1label
|
y2label = y1label
|
||||||
plot.circle('x1','y1',source=source2,fill_alpha=0.3,line_color=None,
|
plot.circle('x1','y1',source=source2,fill_alpha=0.3,line_color=None,
|
||||||
@@ -761,29 +724,9 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
|
yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
|
||||||
plot.y_range = yrange1
|
plot.y_range = yrange1
|
||||||
|
|
||||||
if (xparam != 'time') and (xparam != 'distance'):
|
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
|
||||||
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
|
plot.x_range = xrange1
|
||||||
plot.x_range = xrange1
|
|
||||||
|
|
||||||
if xparam == 'time':
|
|
||||||
xrange1 = Range1d(start=xaxmin,end=xaxmax)
|
|
||||||
plot.x_range = xrange1
|
|
||||||
plot.xaxis[0].formatter = DatetimeTickFormatter(
|
|
||||||
hours = ["%H"],
|
|
||||||
minutes = ["%M"],
|
|
||||||
seconds = ["%S"],
|
|
||||||
days = ["0"],
|
|
||||||
months = [""],
|
|
||||||
years = [""]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if yparam1 == 'pace':
|
|
||||||
plot.yaxis[0].formatter = DatetimeTickFormatter(
|
|
||||||
seconds = ["%S"],
|
|
||||||
minutes = ["%M"]
|
|
||||||
)
|
|
||||||
|
|
||||||
if yparam2 != 'None':
|
if yparam2 != 'None':
|
||||||
yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2])
|
yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2])
|
||||||
@@ -809,18 +752,6 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
if yparam2 != 'pace' and yparam2 != 'time':
|
if yparam2 != 'pace' and yparam2 != 'time':
|
||||||
plot.add_layout(y2label)
|
plot.add_layout(y2label)
|
||||||
|
|
||||||
hover = plot.select(dict(type=HoverTool))
|
|
||||||
|
|
||||||
|
|
||||||
hover.tooltips = OrderedDict([
|
|
||||||
('Time','@ftime'),
|
|
||||||
('Pace','@fpace'),
|
|
||||||
('HR','@hr{int}'),
|
|
||||||
('SPM','@spm{1.1}'),
|
|
||||||
('Power','@power{int}'),
|
|
||||||
])
|
|
||||||
|
|
||||||
hover.mode = 'mouse'
|
|
||||||
|
|
||||||
callback = CustomJS(args = dict(source=source,source2=source2,
|
callback = CustomJS(args = dict(source=source,source2=source2,
|
||||||
x1means=x1means,
|
x1means=x1means,
|
||||||
@@ -835,11 +766,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
var y1 = data['y1']
|
var y1 = data['y1']
|
||||||
var y2 = data['y2']
|
var y2 = data['y2']
|
||||||
var spm1 = data['spm']
|
var spm1 = data['spm']
|
||||||
var time1 = data['time']
|
|
||||||
var pace1 = data['pace']
|
|
||||||
var hr1 = data['hr']
|
|
||||||
var distance1 = data['distance']
|
var distance1 = data['distance']
|
||||||
var power1 = data['power']
|
|
||||||
var xname = data['xname'][0]
|
var xname = data['xname'][0]
|
||||||
var yname1 = data['yname1'][0]
|
var yname1 = data['yname1'][0]
|
||||||
var yname2 = data['yname2'][0]
|
var yname2 = data['yname2'][0]
|
||||||
@@ -856,11 +783,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
data2['y1'] = []
|
data2['y1'] = []
|
||||||
data2['y2'] = []
|
data2['y2'] = []
|
||||||
data2['spm'] = []
|
data2['spm'] = []
|
||||||
data2['time'] = []
|
|
||||||
data2['pace'] = []
|
|
||||||
data2['hr'] = []
|
|
||||||
data2['distance'] = []
|
data2['distance'] = []
|
||||||
data2['power'] = []
|
|
||||||
data2['x1mean'] = []
|
data2['x1mean'] = []
|
||||||
data2['y1mean'] = []
|
data2['y1mean'] = []
|
||||||
data2['y2mean'] = []
|
data2['y2mean'] = []
|
||||||
@@ -875,11 +798,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
data2['y1'].push(y1[i])
|
data2['y1'].push(y1[i])
|
||||||
data2['y2'].push(y2[i])
|
data2['y2'].push(y2[i])
|
||||||
data2['spm'].push(spm1[i])
|
data2['spm'].push(spm1[i])
|
||||||
data2['time'].push(time1[i])
|
|
||||||
data2['pace'].push(pace1[i])
|
|
||||||
data2['hr'].push(hr1[i])
|
|
||||||
data2['distance'].push(distance1[i])
|
data2['distance'].push(distance1[i])
|
||||||
data2['power'].push(power1[i])
|
|
||||||
|
|
||||||
xm += x1[i]
|
xm += x1[i]
|
||||||
ym1 += y1[i]
|
ym1 += y1[i]
|
||||||
@@ -944,6 +863,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def interactive_flex_chart2(id=0,promember=0,
|
def interactive_flex_chart2(id=0,promember=0,
|
||||||
xparam='time',
|
xparam='time',
|
||||||
yparam1='pace',
|
yparam1='pace',
|
||||||
@@ -994,8 +914,8 @@ def interactive_flex_chart2(id=0,promember=0,
|
|||||||
'drivespeed':4,
|
'drivespeed':4,
|
||||||
}
|
}
|
||||||
|
|
||||||
rowdata,row = dataprep.getrowdata(id=id)
|
rowdata,row = dataprep.getrowdata_db(id=id)
|
||||||
if rowdata == 0:
|
if rowdata.empty:
|
||||||
return "","CSV Data File Not Found"
|
return "","CSV Data File Not Found"
|
||||||
|
|
||||||
workoutstateswork = [1,4,5,8,9,6,7]
|
workoutstateswork = [1,4,5,8,9,6,7]
|
||||||
@@ -1004,16 +924,10 @@ def interactive_flex_chart2(id=0,promember=0,
|
|||||||
|
|
||||||
if workstrokesonly:
|
if workstrokesonly:
|
||||||
try:
|
try:
|
||||||
rowdata.df = rowdata.df[~rowdata.df[' WorkoutState'].isin(workoutstatesrest)]
|
rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
rowdata = dataprep.dataprep(rowdata.df)
|
|
||||||
|
|
||||||
|
|
||||||
# get user
|
|
||||||
# u = User.objects.get(id=row.user.id)
|
|
||||||
|
|
||||||
rowdata['x1'] = rowdata.ix[:,xparam]
|
rowdata['x1'] = rowdata.ix[:,xparam]
|
||||||
|
|
||||||
rowdata['y1'] = rowdata.ix[:,yparam1]
|
rowdata['y1'] = rowdata.ix[:,yparam1]
|
||||||
@@ -1336,15 +1250,10 @@ def interactive_flex_chart2(id=0,promember=0,
|
|||||||
|
|
||||||
def interactive_bar_chart(id=0,promember=0):
|
def interactive_bar_chart(id=0,promember=0):
|
||||||
# check if valid ID exists (workout exists)
|
# check if valid ID exists (workout exists)
|
||||||
rowdata,row = dataprep.getrowdata(id=id)
|
rowdata,row = dataprep.getrowdata_db(id=id)
|
||||||
if rowdata == 0:
|
if rowdata.empty:
|
||||||
return "","CSV Data File Not Found"
|
return "","CSV Data File Not Found"
|
||||||
|
|
||||||
rowdata = dataprep.dataprep(rowdata.df,bands=True,barchart=True)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Add hover to this comma-separated string and see what changes
|
# Add hover to this comma-separated string and see what changes
|
||||||
if (promember==1):
|
if (promember==1):
|
||||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
|
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
|
||||||
@@ -1355,8 +1264,6 @@ def interactive_bar_chart(id=0,promember=0):
|
|||||||
rowdata
|
rowdata
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
|
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
|
||||||
toolbar_sticky=False,
|
toolbar_sticky=False,
|
||||||
plot_width=920,
|
plot_width=920,
|
||||||
@@ -1453,19 +1360,14 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
|
|||||||
|
|
||||||
|
|
||||||
# check if valid ID exists (workout exists)
|
# check if valid ID exists (workout exists)
|
||||||
rowdata1,row1 = dataprep.getrowdata(id=id1)
|
rowdata1,row1 = dataprep.getrowdata_db(id=id1)
|
||||||
rowdata2,row2 = dataprep.getrowdata(id=id2)
|
rowdata2,row2 = dataprep.getrowdata_db(id=id2)
|
||||||
if rowdata1 == 0:
|
if rowdata1.empty:
|
||||||
return "","CSV Data File Not Found"
|
return "","CSV Data File Not Found"
|
||||||
|
|
||||||
if rowdata2 == 0:
|
if rowdata2.empty:
|
||||||
return "","CSV Data File Not Found"
|
return "","CSV Data File Not Found"
|
||||||
|
|
||||||
rowdata1 = dataprep.dataprep(rowdata1.df)
|
|
||||||
rowdata2 = dataprep.dataprep(rowdata2.df)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
x1 = rowdata1.ix[:,xparam]
|
x1 = rowdata1.ix[:,xparam]
|
||||||
x2 = rowdata2.ix[:,xparam]
|
x2 = rowdata2.ix[:,xparam]
|
||||||
|
|
||||||
@@ -1601,12 +1503,10 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
|
|||||||
|
|
||||||
def interactive_otw_advanced_pace_chart(id=0,promember=0):
|
def interactive_otw_advanced_pace_chart(id=0,promember=0):
|
||||||
# check if valid ID exists (workout exists)
|
# check if valid ID exists (workout exists)
|
||||||
rowdata,row = dataprep.getrowdata(id=id)
|
rowdata,row = dataprep.getrowdata_db(id=id)
|
||||||
if rowdata == 0:
|
if rowdata.empty:
|
||||||
return "","CSV Data File Not Found"
|
return "","CSV Data File Not Found"
|
||||||
|
|
||||||
rowdata = dataprep.dataprep(rowdata.df,otwpower=True)
|
|
||||||
|
|
||||||
# Add hover to this comma-separated string and see what changes
|
# Add hover to this comma-separated string and see what changes
|
||||||
if (promember==1):
|
if (promember==1):
|
||||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
|
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
|
||||||
|
|||||||
@@ -9,8 +9,31 @@ from django.forms.widgets import SplitDateTimeWidget
|
|||||||
from datetimewidget.widgets import DateTimeWidget
|
from datetimewidget.widgets import DateTimeWidget
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# Create your models here.
|
from django.conf import settings
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlite3 import OperationalError
|
||||||
|
|
||||||
|
user = settings.DATABASES['default']['USER']
|
||||||
|
password = settings.DATABASES['default']['PASSWORD']
|
||||||
|
database_name = settings.DATABASES['default']['NAME']
|
||||||
|
host = settings.DATABASES['default']['HOST']
|
||||||
|
port = settings.DATABASES['default']['PORT']
|
||||||
|
|
||||||
|
database_url = 'mysql://{user}:{password}@{host}:{port}/{database_name}'.format(
|
||||||
|
user=user,
|
||||||
|
password=password,
|
||||||
|
database_name=database_name,
|
||||||
|
host=host,
|
||||||
|
port=port,
|
||||||
|
)
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
database_url = 'sqlite:///db.sqlite3'
|
||||||
|
|
||||||
|
engine = create_engine(database_url, echo=False)
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
class Team(models.Model):
|
class Team(models.Model):
|
||||||
name = models.CharField(max_length=150)
|
name = models.CharField(max_length=150)
|
||||||
notes = models.CharField(blank=True,max_length=200)
|
notes = models.CharField(blank=True,max_length=200)
|
||||||
@@ -120,6 +143,17 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
|
|||||||
if os.path.isfile(instance.csvfilename):
|
if os.path.isfile(instance.csvfilename):
|
||||||
os.remove(instance.csvfilename)
|
os.remove(instance.csvfilename)
|
||||||
|
|
||||||
|
@receiver(models.signals.post_delete,sender=Workout)
|
||||||
|
def auto_delete_strokedata_on_delete(sender, instance, **kwargs):
|
||||||
|
if instance.id:
|
||||||
|
query = sa.text('DELETE FROM strokedata WHERE workoutid={id};'.format(
|
||||||
|
id=instance.id,
|
||||||
|
))
|
||||||
|
with engine.connect() as conn, conn.begin():
|
||||||
|
try:
|
||||||
|
result = conn.execute(query)
|
||||||
|
except:
|
||||||
|
print "Database Locked"
|
||||||
|
|
||||||
class StrokeData(models.Model):
|
class StrokeData(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -130,6 +164,7 @@ class StrokeData(models.Model):
|
|||||||
timesecs = models.FloatField(null=True)
|
timesecs = models.FloatField(null=True)
|
||||||
hr = models.IntegerField(null=True)
|
hr = models.IntegerField(null=True)
|
||||||
pace = models.TimeField(null=True)
|
pace = models.TimeField(null=True)
|
||||||
|
workoutstate = models.IntegerField(null=True,default=1)
|
||||||
pseconds = models.FloatField(null=True)
|
pseconds = models.FloatField(null=True)
|
||||||
spm = models.FloatField(null=True)
|
spm = models.FloatField(null=True)
|
||||||
cumdist = models.FloatField(null=True)
|
cumdist = models.FloatField(null=True)
|
||||||
|
|||||||
@@ -7,115 +7,132 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="workouts" class="grid_6 alpha">
|
<div id="workouts" class="grid_6 alpha">
|
||||||
|
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
<p style="color: red;">
|
<p style="color: red;">
|
||||||
Please correct the error{{ form.errors|pluralize }} below.
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h1>Advanced Workout Editor</h1>
|
<h1>Advanced Workout Editor</h1>
|
||||||
{% if user.rower.rowerplan == 'basic' %}
|
{% if user.rower.rowerplan == 'basic' %}
|
||||||
<p>This is a preview of the page with advanced functionality for Pro users. See <a href="/rowers/promembership">the page about Pro membership</a> for more information and to sign up for Pro Membership</a>
|
<p>This is a preview of the page with advanced functionality for Pro users.
|
||||||
{% endif %}
|
See
|
||||||
<div class="grid_2 alpha">
|
<a href="/rowers/promembership">the page about Pro membership</a> for more information and to sign up for Pro Membership</a>
|
||||||
<p>
|
{% endif %}
|
||||||
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
|
<div class="grid_2 alpha">
|
||||||
</p>
|
<p>
|
||||||
</div>
|
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit Workout</a>
|
||||||
<div class="grid_2 suffix_2 omega">
|
</p>
|
||||||
<p>
|
</div>
|
||||||
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/export">Export</a>
|
<div class="grid_2 suffix_2 omega">
|
||||||
</p>
|
<p>
|
||||||
|
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/export">Export</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid_6 alpha">
|
<div class="grid_6 alpha">
|
||||||
|
|
||||||
<table width=100%>
|
<table width=100%>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Date:</th><td>{{ workout.date }}</td>
|
<th>Date:</th><td>{{ workout.date }}</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Time:</th><td>{{ workout.starttime }}</td>
|
<th>Time:</th><td>{{ workout.starttime }}</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Distance:</th><td>{{ workout.distance }}m</td>
|
<th>Distance:</th><td>{{ workout.distance }}m</td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
|
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<th>Public link to this workout</th>
|
<th>Public link to this workout</th>
|
||||||
<td>
|
<td>
|
||||||
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
<a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
||||||
<td>
|
<td>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid_6 alpha">
|
<div class="grid_6 alpha">
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' %}
|
||||||
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
|
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id }}">Compare Workouts</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership/">Compare Workouts</a>
|
<a class="button blue small" href="/rowers/promembership/">Compare Workouts</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>
|
<p>
|
||||||
Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts.
|
Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid_2">
|
<div class="grid_2">
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/flexchart">
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/flexchart">
|
||||||
Flexible Interactive Plot
|
Flexible Interactive Plot
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
Flexible Interactive plot. Pick your own X and Y axis parameters.
|
Flexible Interactive plot. Pick your own X and Y axis parameters.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid_2 omega tooltip">
|
<div class="grid_2 omega tooltip">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/editintervals">Edit Intervals</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
|
<a class="button blue small" href="/rowers/promembership">Edit Intervals</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<span class="tooltiptext">Enter or change the interval and summary data for your workout</span>
|
<span class="tooltiptext">Enter or change the interval and summary data for your workout</span>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Enter or change the interval and summary data for your workout
|
Enter or change the interval and summary data for your workout
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid_6 alpha">
|
<div class="grid_6 alpha">
|
||||||
|
|
||||||
<div class="grid_2 alpha">
|
<div class="grid_2 alpha">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/adddistanceplot2">Dist Metrics Plot</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/adddistanceplot2">Dist Metrics Plot</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
|
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Various advanced stroke metrics plotted versus distance.
|
Various advanced stroke metrics plotted versus distance.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid_2">
|
<div class="grid_2">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' %}
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addtimeplot2">Time Metrics Plot</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/addtimeplot2">Time Metrics Plot</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Time Metrics Plot</a>
|
<a class="button blue small" href="/rowers/promembership">Time Metrics Plot</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Various advanced stroke metrics plotted versus time.
|
Various advanced stroke metrics plotted versus time.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid_2 omega">
|
<div class="grid_2 omega">
|
||||||
<p>
|
<p>
|
||||||
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveplot">Big Interactive Plot</a>
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/interactiveplot">Big Interactive Plot</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
See (and save) the big interactive plot
|
See (and save) the big interactive plot
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
|
||||||
|
<div class="grid_2 suffix_4 alpha">
|
||||||
|
<p>
|
||||||
|
{% if user.rower.rowerplan == 'pro' %}
|
||||||
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/histo">Power Histogram</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Plot the Power Histogram of this workout
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -155,4 +172,4 @@ Enter or change the interval and summary data for your workout
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<th>Public link to this workout</th>
|
<th>Public link to this workout</th>
|
||||||
<td>
|
<td>
|
||||||
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
<a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
||||||
<td>
|
<td>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="workouts" class="grid_4 alpha">
|
<div id="workouts" class="grid_4 alpha">
|
||||||
|
<div class="grid_4 alpha">
|
||||||
|
|
||||||
<h1>Workout {{ id }}</h1>
|
<h1>Workout {{ id }}</h1>
|
||||||
<table width=100%>
|
<table width=100%>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -30,6 +29,35 @@
|
|||||||
<th>Weight Category:</th><td>{{ workout.weightcategory }}</td>
|
<th>Weight Category:</th><td>{{ workout.weightcategory }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="grid_4 alpha">
|
||||||
|
<p>
|
||||||
|
<form id="searchform" action=""
|
||||||
|
method="get" accept-charset="utf-8">
|
||||||
|
<button class="button blue small" type="submit">
|
||||||
|
Search
|
||||||
|
</button>
|
||||||
|
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Select start and end date for a date range:
|
||||||
|
<div class="grid_4 alpha">
|
||||||
|
<p>
|
||||||
|
<form enctype="multipart/form-data" action="/rowers/workout/compare/{{ id }}/" method="post">
|
||||||
|
|
||||||
|
<table>
|
||||||
|
{{ dateform.as_table }}
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
</div>
|
||||||
|
<div class="grid_2 suffix_2 omega">
|
||||||
|
<input name='daterange' class="button green" type="submit" value="Submit"> </form>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="comparison" class="grid_8 omega">
|
<div id="comparison" class="grid_8 omega">
|
||||||
@@ -73,5 +101,21 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<p> No workouts found </p>
|
<p> No workouts found </p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="grid_2 prefix_5 suffix_1 omega">
|
||||||
|
<span class="button gray small">
|
||||||
|
{% if workouts.has_previous %}
|
||||||
|
<a class="wh" href="/rowers/workout/compare/{{ id }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}?page={{ workouts.previous_page_number }}"><</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<span>
|
||||||
|
Page {{ workouts.number }} of {{ workouts.paginator.num_pages }}.
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{% if workouts.has_next %}
|
||||||
|
<a class="wh" href="/rowers/workout/compare/{{ id }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}?page={{ workouts.next_page_number }}">></a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -39,18 +39,16 @@
|
|||||||
<div class="grid_2 alpha dropdown">
|
<div class="grid_2 alpha dropdown">
|
||||||
<button class="grid_2 alpha button blue small dropbtn">X-axis</button>
|
<button class="grid_2 alpha button blue small dropbtn">X-axis</button>
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/time/{{ yparam1 }}/{{ yparam2 }}">Time</a>
|
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/distance/{{ yparam1 }}/{{ yparam2 }}">Distance</a>
|
|
||||||
{% if promember %}
|
{% if promember %}
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/power/{{ yparam1 }}/{{ yparam2 }}">Power</a>
|
<a class="button blue small alpha" href="/rowers/flexall/power/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Power</a>
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/hr/{{ yparam1 }}/{{ yparam2 }}">HR</a>
|
<a class="button blue small alpha" href="/rowers/flexall/hr/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">HR</a>
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/spm/{{ yparam1 }}/{{ yparam2 }}">SPM</a>
|
<a class="button blue small alpha" href="/rowers/flexall/spm/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">SPM</a>
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/peakforce/{{ yparam1 }}/{{ yparam2 }}">Peak Force</a>
|
<a class="button blue small alpha" href="/rowers/flexall/peakforce/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Peak Force</a>
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/averageforce/{{ yparam1 }}/{{ yparam2 }}">Average Force</a>
|
<a class="button blue small alpha" href="/rowers/flexall/averageforce/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average Force</a>
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/forceratio/{{ yparam1 }}/{{ yparam2 }}">Average/Peak Force Ratio</a>
|
<a class="button blue small alpha" href="/rowers/flexall/forceratio/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average/Peak Force Ratio</a>
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/drivelength/{{ yparam1 }}/{{ yparam2 }}">Drive Length</a>
|
<a class="button blue small alpha" href="/rowers/flexall/drivelength/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Length</a>
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/driveenergy/{{ yparam1 }}/{{ yparam2 }}">Work per Stroke</a>
|
<a class="button blue small alpha" href="/rowers/flexall/driveenergy/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Work per Stroke</a>
|
||||||
<a class="button blue small alpha" href="/rowers/flexall/drivespeed/{{ yparam1 }}/{{ yparam2 }}">Drive Speed</a>
|
<a class="button blue small alpha" href="/rowers/flexall/drivespeed/{{ yparam1 }}/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Speed</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button rosy small" href="/rowers/promembership">Power (Pro)</a>
|
<a class="button rosy small" href="/rowers/promembership">Power (Pro)</a>
|
||||||
<a class="button rosy small" href="/rowers/promembership">HR (Pro)</a>
|
<a class="button rosy small" href="/rowers/promembership">HR (Pro)</a>
|
||||||
@@ -69,17 +67,16 @@
|
|||||||
<div class="grid_2 dropdown">
|
<div class="grid_2 dropdown">
|
||||||
<button class="grid_2 alpha button blue small dropbtn">Left</button>
|
<button class="grid_2 alpha button blue small dropbtn">Left</button>
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/pace/{{ yparam2 }}">Pace</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/hr/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">HR</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/hr/{{ yparam2 }}">HR</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/spm/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">SPM</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/spm/{{ yparam2 }}">SPM</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/power/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Power</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/power/{{ yparam2 }}">Power</a>
|
|
||||||
{% if promember %}
|
{% if promember %}
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/peakforce/{{ yparam2 }}">Peak Force</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/peakforce/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Peak Force</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/averageforce/{{ yparam2 }}">Average Force</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/averageforce/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average Force</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/forceratio/{{ yparam2 }}">Average/Peak Force Ratio</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/forceratio/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average/Peak Force Ratio</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivelength/{{ yparam2 }}">Drive Length</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivelength/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Length</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/driveenergy/{{ yparam2 }}">Work per Stroke</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/driveenergy/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Work per Stroke</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivespeed/{{ yparam2 }}">Drive Speed</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/drivespeed/{{ yparam2 }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Speed</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
|
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
|
||||||
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
|
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
|
||||||
@@ -95,16 +92,16 @@
|
|||||||
<div class="grid_2 dropdown omega">
|
<div class="grid_2 dropdown omega">
|
||||||
<button class="grid_2 alpha button blue small dropbtn">Right</button>
|
<button class="grid_2 alpha button blue small dropbtn">Right</button>
|
||||||
<div class="dropdown-content">
|
<div class="dropdown-content">
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/hr">HR</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/hr/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">HR</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/spm">SPM</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/spm/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">SPM</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/power">Power</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/power/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Power</a>
|
||||||
{% if promember %}
|
{% if promember %}
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/peakforce">Peak Force</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/peakforce/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Peak Force</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/averageforce">Average Force</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/averageforce/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average Force</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/forceratio">Average/Peak Force Ratio</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/forceratio/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Average/Peak Force Ratio</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivelength">Drive Length</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivelength/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Length</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/driveenergy">Work per Stroke</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/driveenergy/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Work per Stroke</a>
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivespeed">Drive Speed</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/drivespeed/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d"}}">Drive Speed</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
|
<a class="button rosy small" href="/rowers/promembership">Peak Force (Pro)</a>
|
||||||
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
|
<a class="button rosy small" href="/rowers/promembership">Average Force (Pro)</a>
|
||||||
@@ -114,7 +111,7 @@
|
|||||||
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
|
<a class="button rosy small" href="/rowers/promembership">Drive Speed (Pro)</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/None">None</a>
|
<a class="button blue small" href="/rowers/flexall/{{ xparam }}/{{ yparam1 }}/None/{{startdate|date:"Y-m-d"}}/{{ enddate|date:"Y-m-d"}}">None</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
between {{ startdate|date }} and {{ enddate|date }}</p>
|
between {{ startdate|date }} and {{ enddate|date }}</p>
|
||||||
|
|
||||||
<p>Direct link for other Pro users:
|
<p>Direct link for other Pro users:
|
||||||
<a href="/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">http://rowsandall.com/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
|
<a href="/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">https://rowsandall.com/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="form" class="grid_6 omega">
|
<div id="form" class="grid_6 omega">
|
||||||
@@ -82,4 +82,4 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
66
rowers/templates/histo_single.html
Normal file
66
rowers/templates/histo_single.html
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
|
||||||
|
{% block title %}View Workout {% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||||
|
<script async="true" type="text/javascript">
|
||||||
|
Bokeh.set_log_level("info");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{ interactiveplot |safe }}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Set things up to resize the plot on a window resize. You can play with
|
||||||
|
// the arguments of resize_width_height() to change the plot's behavior.
|
||||||
|
var plot_resize_setup = function () {
|
||||||
|
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
|
||||||
|
var plot = Bokeh.index[plotid];
|
||||||
|
var plotresizer = function() {
|
||||||
|
// arguments: use width, use height, maintain aspect ratio
|
||||||
|
plot.resize_width_height(true, false, false);
|
||||||
|
};
|
||||||
|
window.addEventListener('resize', plotresizer);
|
||||||
|
plotresizer();
|
||||||
|
};
|
||||||
|
window.addEventListener('load', plot_resize_setup);
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
|
||||||
|
html, body {height: 100%; margin:5px;}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="navigation" class="grid_12 alpha">
|
||||||
|
{% if user.is_authenticated and mayedit %}
|
||||||
|
<div class="grid_2 alpha">
|
||||||
|
<p>
|
||||||
|
<a class="button gray small" href="/rowers/workout/{{ id }}/edit">Edit Workout</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid_2 suffix_8 omega">
|
||||||
|
<p>
|
||||||
|
<a class="button gray small" href="/rowers/workout/{{ id }}/advanced">Advanced Edit</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="title" class="grid_12 alpha">
|
||||||
|
<h1>Indoor Rower Power Histogram</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="graph" class="grid_12 alpha">
|
||||||
|
|
||||||
|
{{ the_div|safe }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
<p>Summary of the past 12 months for {{ theuser.first_name }} {{ theuser.last_name }}</p>
|
<p>Summary of the past 12 months for {{ theuser.first_name }} {{ theuser.last_name }}</p>
|
||||||
|
|
||||||
<p>Direct link for other Pro users:
|
<p>Direct link for other Pro users:
|
||||||
<a href="/rowers/{{ id }}/histo-all">http://rowsandall.com/rowers/{{ id }}/histo-all</a>
|
<a href="/rowers/{{ id }}/histo-all">https://rowsandall.com/rowers/{{ id }}/histo-all</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="grid_12 alpha">
|
<div class="grid_12 alpha">
|
||||||
|
|||||||
@@ -6,6 +6,14 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Recent Graphs</h1>
|
<h1>Recent Graphs</h1>
|
||||||
|
|
||||||
|
<form id="searchform" action="."
|
||||||
|
method="get" accept-charset="utf-8">
|
||||||
|
<button class="button blue small" type="submit">
|
||||||
|
Search
|
||||||
|
</button>
|
||||||
|
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
|
||||||
|
</form>
|
||||||
{% if graphs1 %}
|
{% if graphs1 %}
|
||||||
<div class="grid_1 alpha">
|
<div class="grid_1 alpha">
|
||||||
<p> </p>
|
<p> </p>
|
||||||
|
|||||||
@@ -5,8 +5,27 @@
|
|||||||
{% block title %}Workouts{% endblock %}
|
{% block title %}Workouts{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div class="grid_12">
|
||||||
|
|
||||||
|
Select start and end date for a date range:
|
||||||
|
<div class="grid_4 alpha">
|
||||||
|
|
||||||
|
<form enctype="multipart/form-data" action="/rowers/list-workouts/" method="post">
|
||||||
|
|
||||||
|
<table>
|
||||||
|
{{ dateform.as_table }}
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
</div>
|
||||||
|
<div class="grid_2 suffix_6 omega">
|
||||||
|
<input name='daterange' class="button green" type="submit" value="Submit"> </form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<h1>My Workouts</h1>
|
<h1>My Workouts</h1>
|
||||||
{% if workouts %}
|
|
||||||
|
{% if workouts %}
|
||||||
<table width="70%" class="listtable">
|
<table width="70%" class="listtable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -49,4 +68,35 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<p> No workouts found </p>
|
<p> No workouts found </p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
<form id="searchform" action="/rowers/list-workouts/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
|
||||||
|
method="get" accept-charset="utf-8">
|
||||||
|
<div class="grid_3 prefix_1 alpha">
|
||||||
|
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
|
||||||
|
</div>
|
||||||
|
<div class="grid_1 suffix_1 omega">
|
||||||
|
<button class="button blue small" type="submit">
|
||||||
|
Search
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="grid_2 prefix_3 omega">
|
||||||
|
<span class="button gray small">
|
||||||
|
{% if workouts.has_previous %}
|
||||||
|
<a class="wh" href="?page={{ workouts.previous_page_number }}"><</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<span>
|
||||||
|
Page {{ workouts.number }} of {{ workouts.paginator.num_pages }}.
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{% if workouts.has_next %}
|
||||||
|
<a class="wh" href="?page={{ workouts.next_page_number }}">></a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<th>Public link to this workout</th>
|
<th>Public link to this workout</th>
|
||||||
<td>
|
<td>
|
||||||
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
<a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
||||||
<td>
|
<td>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
between {{ startdate|date }} and {{ enddate|date }}</p>
|
between {{ startdate|date }} and {{ enddate|date }}</p>
|
||||||
|
|
||||||
<p>Direct link for other users:
|
<p>Direct link for other users:
|
||||||
<a href="/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">http://rowsandall.com/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
|
<a href="/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}">https://rowsandall.com/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.</p>
|
<p>The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.</p>
|
||||||
|
|||||||
@@ -48,12 +48,12 @@
|
|||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Public link to this workout</th>
|
<th>Public link to this workout</th>
|
||||||
<td>
|
<td>
|
||||||
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
<a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
||||||
<td>
|
<td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Public link to interactive chart</th>
|
<th>Public link to interactive chart</th>
|
||||||
<td>
|
<td>
|
||||||
<a href="/rowers/workout/{{ workout.id }}/interactiveplot">http://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a>
|
<a href="/rowers/workout/{{ workout.id }}/interactiveplot">https://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a>
|
||||||
<td>
|
<td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -48,12 +48,12 @@
|
|||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Public link to this workout</th>
|
<th>Public link to this workout</th>
|
||||||
<td>
|
<td>
|
||||||
<a href="/rowers/workout/{{ workout.id }}">http://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
<a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
||||||
<td>
|
<td>
|
||||||
</tr><tr>
|
</tr><tr>
|
||||||
<th>Public link to interactive chart</th>
|
<th>Public link to interactive chart</th>
|
||||||
<td>
|
<td>
|
||||||
<a href="/rowers/workout/{{ workout.id }}/interactiveplot">http://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a>
|
<a href="/rowers/workout/{{ workout.id }}/interactiveplot">https://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a>
|
||||||
<td>
|
<td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -189,6 +189,9 @@
|
|||||||
{{ workout.summary }}
|
{{ workout.summary }}
|
||||||
</pre>
|
</pre>
|
||||||
</p>
|
</p>
|
||||||
|
<div class="grid_2 alpha">
|
||||||
|
<a class="button green small" href="recalcsummary">Update Summary</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -139,4 +139,4 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -425,6 +425,9 @@ class ViewTest(TestCase):
|
|||||||
response = self.c.get('/rowers/workout/1/interactiveplot', form_data, follow=True)
|
response = self.c.get('/rowers/workout/1/interactiveplot', form_data, follow=True)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
response = self.c.get('/rowers/workout/1/histo', form_data, follow=True)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
w = Workout.objects.get(id=1)
|
w = Workout.objects.get(id=1)
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ urlpatterns = [
|
|||||||
url(r'^list-workouts/c/(?P<message>\w+.*)/$',views.workouts_view),
|
url(r'^list-workouts/c/(?P<message>\w+.*)/$',views.workouts_view),
|
||||||
url(r'^list-workouts/s/(?P<successmessage>\w+.*)/$',views.workouts_view),
|
url(r'^list-workouts/s/(?P<successmessage>\w+.*)/$',views.workouts_view),
|
||||||
url(r'^list-workouts/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workouts_view),
|
url(r'^list-workouts/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workouts_view),
|
||||||
|
url(r'^list-workouts/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.workouts_view),
|
||||||
url(r'^list-workouts/$',views.workouts_view),
|
url(r'^list-workouts/$',views.workouts_view),
|
||||||
url(r'^list-graphs/$',views.graphs_view),
|
url(r'^list-graphs/$',views.graphs_view),
|
||||||
url(r'^dashboard/c/(?P<message>\w+.*)/$',views.dashboard_view),
|
url(r'^dashboard/c/(?P<message>\w+.*)/$',views.dashboard_view),
|
||||||
@@ -62,6 +63,7 @@ urlpatterns = [
|
|||||||
url(r'^ote-bests/$',views.rankings_view),
|
url(r'^ote-bests/$',views.rankings_view),
|
||||||
url(r'^(?P<theuser>\d+)/ote-bests/$',views.rankings_view),
|
url(r'^(?P<theuser>\d+)/ote-bests/$',views.rankings_view),
|
||||||
|
|
||||||
|
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.cum_flex),
|
||||||
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)$',views.cum_flex),
|
url(r'^flexall/(?P<xparam>\w+.*)/(?P<yparam1>\w+.*)/(?P<yparam2>\w+.*)$',views.cum_flex),
|
||||||
url(r'^flexall/$',views.cum_flex),
|
url(r'^flexall/$',views.cum_flex),
|
||||||
|
|
||||||
@@ -77,6 +79,7 @@ urlpatterns = [
|
|||||||
url(r'^graph/(\d+)/delete$',views.graph_delete_view),
|
url(r'^graph/(\d+)/delete$',views.graph_delete_view),
|
||||||
url(r'^workout/upload/$',views.workout_upload_view),
|
url(r'^workout/upload/$',views.workout_upload_view),
|
||||||
url(r'^workout/upload/(.+.*)$',views.workout_upload_view),
|
url(r'^workout/upload/(.+.*)$',views.workout_upload_view),
|
||||||
|
url(r'^workout/(?P<id>\d+)/histo$',views.workout_histo_view),
|
||||||
url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workout_export_view),
|
url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workout_export_view),
|
||||||
url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)$',views.workout_export_view),
|
url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)$',views.workout_export_view),
|
||||||
url(r'^workout/(?P<id>\d+)/export/s/(?P<successmessage>\w+.*)$',views.workout_export_view),
|
url(r'^workout/(?P<id>\d+)/export/s/(?P<successmessage>\w+.*)$',views.workout_export_view),
|
||||||
@@ -85,6 +88,7 @@ urlpatterns = [
|
|||||||
url(r'^workout/(\d+)/emailcsv$',views.workout_csvemail_view),
|
url(r'^workout/(\d+)/emailcsv$',views.workout_csvemail_view),
|
||||||
url(r'^workout/compare/(\d+)/$',views.workout_comparison_list),
|
url(r'^workout/compare/(\d+)/$',views.workout_comparison_list),
|
||||||
url(r'^workout/compare2/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/$',views.workout_comparison_view),
|
url(r'^workout/compare2/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/$',views.workout_comparison_view),
|
||||||
|
url(r'^workout/compare/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\w+.*)$',views.workout_comparison_list),
|
||||||
url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workout_edit_view),
|
url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workout_edit_view),
|
||||||
url(r'^workout/(?P<id>\d+)/edit/c/(?P<message>.+.*)$',views.workout_edit_view),
|
url(r'^workout/(?P<id>\d+)/edit/c/(?P<message>.+.*)$',views.workout_edit_view),
|
||||||
url(r'^workout/(?P<id>\d+)/edit/s/(?P<successmessage>.+.*)$',views.workout_edit_view),
|
url(r'^workout/(?P<id>\d+)/edit/s/(?P<successmessage>.+.*)$',views.workout_edit_view),
|
||||||
@@ -131,6 +135,7 @@ urlpatterns = [
|
|||||||
url(r'^workout/(\d+)/c2upload/$',views.list_c2_upload_view),
|
url(r'^workout/(\d+)/c2upload/$',views.list_c2_upload_view),
|
||||||
url(r'^workout/(\d+)/c2uploadw/$',views.workout_c2_upload_view),
|
url(r'^workout/(\d+)/c2uploadw/$',views.workout_c2_upload_view),
|
||||||
url(r'^workout/(\d+)/stravauploadw/$',views.workout_strava_upload_view),
|
url(r'^workout/(\d+)/stravauploadw/$',views.workout_strava_upload_view),
|
||||||
|
url(r'^workout/(\d+)/recalcsummary/$',views.workout_recalcsummary_view),
|
||||||
url(r'^workout/(\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view),
|
url(r'^workout/(\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view),
|
||||||
url(r'^me/edit/$',views.rower_edit_view),
|
url(r'^me/edit/$',views.rower_edit_view),
|
||||||
url(r'^me/edit/(.+.*)/$',views.rower_edit_view),
|
url(r'^me/edit/(.+.*)/$',views.rower_edit_view),
|
||||||
|
|||||||
207
rowers/views.py
207
rowers/views.py
@@ -1,11 +1,14 @@
|
|||||||
import time
|
import time
|
||||||
|
import operator
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
|
from django.db.models import Q
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
from django.contrib.auth import authenticate, login, logout
|
from django.contrib.auth import authenticate, login, logout
|
||||||
from rowers.forms import LoginForm,DocumentsForm,UploadOptionsForm
|
from rowers.forms import LoginForm,DocumentsForm,UploadOptionsForm
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.datastructures import MultiValueDictKeyError
|
from django.utils.datastructures import MultiValueDictKeyError
|
||||||
from django.utils import timezone,translation
|
from django.utils import timezone,translation
|
||||||
@@ -1322,9 +1325,10 @@ def cum_flex(request,theuser=0,
|
|||||||
u = ''
|
u = ''
|
||||||
|
|
||||||
if allergworkouts:
|
if allergworkouts:
|
||||||
res = interactive_cum_flex_chart(allergworkouts,xparam=xparam,
|
res = interactive_cum_flex_chart2(allergworkouts,xparam=xparam,
|
||||||
yparam1=yparam1,yparam2=yparam2,
|
yparam1=yparam1,
|
||||||
promember=promember)
|
yparam2=yparam2,
|
||||||
|
promember=promember)
|
||||||
script = res[0]
|
script = res[0]
|
||||||
div = res[1]
|
div = res[1]
|
||||||
js_resources = res[2]
|
js_resources = res[2]
|
||||||
@@ -1352,6 +1356,36 @@ def cum_flex(request,theuser=0,
|
|||||||
'promember':promember,
|
'promember':promember,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def workout_histo_view(request,id=0):
|
||||||
|
row = Workout.objects.get(id=id)
|
||||||
|
promember=0
|
||||||
|
mayedit=0
|
||||||
|
if not request.user.is_anonymous():
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
result = request.user.is_authenticated() and r.rowerplan=='pro'
|
||||||
|
if result:
|
||||||
|
promember=1
|
||||||
|
if request.user == row.user.user:
|
||||||
|
mayedit=1
|
||||||
|
|
||||||
|
if not promember:
|
||||||
|
return HttpResponseRedirect("/rowers/about/")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
res = interactive_histoall([row])
|
||||||
|
script = res[0]
|
||||||
|
div = res[1]
|
||||||
|
|
||||||
|
return render(request,
|
||||||
|
'histo_single.html',
|
||||||
|
{'interactiveplot':script,
|
||||||
|
'the_div':div,
|
||||||
|
'id':id,
|
||||||
|
'mayedit':mayedit,
|
||||||
|
})
|
||||||
|
|
||||||
@login_required()
|
@login_required()
|
||||||
def histo(request,theuser=0,
|
def histo(request,theuser=0,
|
||||||
@@ -1582,8 +1616,8 @@ def rankings_view(request,theuser=0,
|
|||||||
for rankingduration in rankingdurations:
|
for rankingduration in rankingdurations:
|
||||||
|
|
||||||
workouts = Workout.objects.filter(user=r,duration=rankingduration,
|
workouts = Workout.objects.filter(user=r,duration=rankingduration,
|
||||||
workouttype='rower',
|
workouttype='rower',
|
||||||
startdatetime__gte=startdate,
|
startdatetime__gte=startdate,
|
||||||
startdatetime__lte=enddate).order_by('-distance')
|
startdatetime__lte=enddate).order_by('-distance')
|
||||||
if workouts:
|
if workouts:
|
||||||
thedistances.append(workouts[0].distance)
|
thedistances.append(workouts[0].distance)
|
||||||
@@ -1754,29 +1788,156 @@ def rankings_view(request,theuser=0,
|
|||||||
})
|
})
|
||||||
|
|
||||||
@login_required()
|
@login_required()
|
||||||
def workouts_view(request,message='',successmessage=''):
|
def workout_recalcsummary_view(request,id=0):
|
||||||
|
row = Workout.objects.get(id=id)
|
||||||
|
if (checkworkoutuser(request.user,row)==False):
|
||||||
|
message = "You are not allowed to edit this workout"
|
||||||
|
url = reverse(workouts_view,args=[str(message)])
|
||||||
|
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
filename = row.csvfilename
|
||||||
|
rowdata = rdata(filename)
|
||||||
|
row.summary = rowdata.allstats()
|
||||||
|
row.save()
|
||||||
|
successmessage = "Summary Updated"
|
||||||
|
url = reverse(workout_edit_view,
|
||||||
|
kwargs = {
|
||||||
|
'id':str(id),
|
||||||
|
'successmessage':str(successmessage),
|
||||||
|
})
|
||||||
|
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def workouts_view(request,message='',successmessage='',
|
||||||
|
startdatestring="",enddatestring="",
|
||||||
|
startdate=timezone.now()-datetime.timedelta(days=365),
|
||||||
|
enddate=timezone.now()):
|
||||||
try:
|
try:
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
# res = mailprocessing.safeprocessattachments()
|
# res = mailprocessing.safeprocessattachments()
|
||||||
#if len(res)>0 and np.cumsum(np.array(res)).max()>0:
|
#if len(res)>0 and np.cumsum(np.array(res)).max()>0:
|
||||||
# successmessage = 'New Workouts have been created from email'
|
# successmessage = 'New Workouts have been created from email'
|
||||||
|
|
||||||
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
|
if request.method == 'POST':
|
||||||
|
dateform = DateRangeForm(request.POST)
|
||||||
|
if dateform.is_valid():
|
||||||
|
startdate = dateform.cleaned_data['startdate']
|
||||||
|
enddate = dateform.cleaned_data['enddate']
|
||||||
|
else:
|
||||||
|
dateform = DateRangeForm(initial={
|
||||||
|
'startdate':startdate,
|
||||||
|
'enddate':enddate,
|
||||||
|
})
|
||||||
|
|
||||||
|
startdate = datetime.datetime.combine(startdate,datetime.time())
|
||||||
|
enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
|
||||||
|
|
||||||
|
if startdatestring:
|
||||||
|
startdate = iso8601.parse_date(startdatestring)
|
||||||
|
if enddatestring:
|
||||||
|
enddate = iso8601.parse_date(enddatestring)
|
||||||
|
|
||||||
|
if enddate < startdate:
|
||||||
|
s = enddate
|
||||||
|
enddate = startdate
|
||||||
|
startdate = s
|
||||||
|
|
||||||
|
|
||||||
|
workouts = Workout.objects.filter(user=r,
|
||||||
|
startdatetime__gte=startdate,
|
||||||
|
startdatetime__lte=enddate).order_by("-date", "-starttime")
|
||||||
|
|
||||||
|
query = request.GET.get('q')
|
||||||
|
if query:
|
||||||
|
query_list = query.split()
|
||||||
|
workouts = workouts.filter(
|
||||||
|
reduce(operator.and_,
|
||||||
|
(Q(name__icontains=q) for q in query_list)) |
|
||||||
|
reduce(operator.and_,
|
||||||
|
(Q(notes__icontains=q) for q in query_list))
|
||||||
|
)
|
||||||
|
|
||||||
|
paginator = Paginator(workouts,20) # show 25 workouts per page
|
||||||
|
page = request.GET.get('page')
|
||||||
|
|
||||||
|
try:
|
||||||
|
workouts = paginator.page(page)
|
||||||
|
except PageNotAnInteger:
|
||||||
|
workouts = paginator.page(1)
|
||||||
|
except EmptyPage:
|
||||||
|
workouts = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
return render(request, 'list_workouts.html',
|
return render(request, 'list_workouts.html',
|
||||||
{'workouts': workouts,
|
{'workouts': workouts,
|
||||||
'message': message,
|
'message': message,
|
||||||
'successmessage':successmessage,
|
'successmessage':successmessage,
|
||||||
|
'dateform':dateform,
|
||||||
|
'startdate':startdate,
|
||||||
|
'enddate':enddate,
|
||||||
})
|
})
|
||||||
except Rower.DoesNotExist:
|
except Rower.DoesNotExist:
|
||||||
return HttpResponse("User has no rower instance")
|
return HttpResponse("User has no rower instance")
|
||||||
|
|
||||||
@user_passes_test(promember,login_url="/login")
|
@user_passes_test(promember,login_url="/login")
|
||||||
def workout_comparison_list(request,id=0,message='',successmessage=''):
|
def workout_comparison_list(request,id=0,message='',successmessage='',
|
||||||
|
startdatestring="",enddatestring="",
|
||||||
|
startdate=timezone.now()-datetime.timedelta(days=365),
|
||||||
|
enddate=timezone.now()):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
u = User.objects.get(id=r.user.id)
|
u = User.objects.get(id=r.user.id)
|
||||||
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime").exclude(id=id)
|
if request.method == 'POST':
|
||||||
|
dateform = DateRangeForm(request.POST)
|
||||||
|
if dateform.is_valid():
|
||||||
|
startdate = dateform.cleaned_data['startdate']
|
||||||
|
enddate = dateform.cleaned_data['enddate']
|
||||||
|
else:
|
||||||
|
dateform = DateRangeForm(initial={
|
||||||
|
'startdate':startdate,
|
||||||
|
'enddate':enddate,
|
||||||
|
})
|
||||||
|
|
||||||
|
if startdatestring:
|
||||||
|
startdate = iso8601.parse_date(startdatestring)
|
||||||
|
if enddatestring:
|
||||||
|
enddate = iso8601.parse_date(enddatestring)
|
||||||
|
|
||||||
|
startdate = datetime.datetime.combine(startdate,datetime.time())
|
||||||
|
enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
|
||||||
|
|
||||||
|
if enddate < startdate:
|
||||||
|
s = enddate
|
||||||
|
enddate = startdate
|
||||||
|
startdate = s
|
||||||
|
|
||||||
|
workouts = Workout.objects.filter(user=r,
|
||||||
|
startdatetime__gte=startdate,
|
||||||
|
startdatetime__lte=enddate).order_by("-date", "-starttime").exclude(id=id)
|
||||||
|
|
||||||
|
query = request.GET.get('q')
|
||||||
|
if query:
|
||||||
|
query_list = query.split()
|
||||||
|
workouts = workouts.filter(
|
||||||
|
reduce(operator.and_,
|
||||||
|
(Q(name__icontains=q) for q in query_list)) |
|
||||||
|
reduce(operator.and_,
|
||||||
|
(Q(notes__icontains=q) for q in query_list))
|
||||||
|
)
|
||||||
|
|
||||||
|
paginator = Paginator(workouts,15) # show 25 workouts per page
|
||||||
|
page = request.GET.get('page')
|
||||||
|
|
||||||
|
try:
|
||||||
|
workouts = paginator.page(page)
|
||||||
|
except PageNotAnInteger:
|
||||||
|
workouts = paginator.page(1)
|
||||||
|
except EmptyPage:
|
||||||
|
workouts = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
row = Workout.objects.get(id=id)
|
row = Workout.objects.get(id=id)
|
||||||
|
|
||||||
return render(request, 'comparison_list.html',
|
return render(request, 'comparison_list.html',
|
||||||
@@ -1787,6 +1948,9 @@ def workout_comparison_list(request,id=0,message='',successmessage=''):
|
|||||||
'first_name':u.first_name,
|
'first_name':u.first_name,
|
||||||
'message': message,
|
'message': message,
|
||||||
'successmessage':successmessage,
|
'successmessage':successmessage,
|
||||||
|
'dateform':dateform,
|
||||||
|
'startdate':startdate,
|
||||||
|
'enddate':enddate,
|
||||||
})
|
})
|
||||||
except Rower.DoesNotExist:
|
except Rower.DoesNotExist:
|
||||||
return HttpResponse("User has no rower instance")
|
return HttpResponse("User has no rower instance")
|
||||||
@@ -2712,11 +2876,14 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
|||||||
|
|
||||||
rowdata = rdata(f1)
|
rowdata = rdata(f1)
|
||||||
hascoordinates = 1
|
hascoordinates = 1
|
||||||
try:
|
if rowdata != 0:
|
||||||
latitude = rowdata.df[' latitude']
|
try:
|
||||||
except KeyError:
|
latitude = rowdata.df[' latitude']
|
||||||
hascoordinates = 0
|
except KeyError,AttributeError:
|
||||||
|
hascoordinates = 0
|
||||||
|
else:
|
||||||
|
hascoordinates = 0
|
||||||
|
|
||||||
if hascoordinates:
|
if hascoordinates:
|
||||||
res = googlemap_chart(rowdata.df[' latitude'],
|
res = googlemap_chart(rowdata.df[' latitude'],
|
||||||
rowdata.df[' longitude'],
|
rowdata.df[' longitude'],
|
||||||
@@ -3932,6 +4099,16 @@ def graphs_view(request):
|
|||||||
try:
|
try:
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
|
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
|
||||||
|
query = request.GET.get('q')
|
||||||
|
if query:
|
||||||
|
query_list = query.split()
|
||||||
|
workouts = workouts.filter(
|
||||||
|
reduce(operator.and_,
|
||||||
|
(Q(name__icontains=q) for q in query_list)) |
|
||||||
|
reduce(operator.and_,
|
||||||
|
(Q(notes__icontains=q) for q in query_list))
|
||||||
|
)
|
||||||
|
|
||||||
g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime")
|
g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime")
|
||||||
if (len(g)<=5):
|
if (len(g)<=5):
|
||||||
return render(request, 'list_graphs.html',
|
return render(request, 'list_graphs.html',
|
||||||
|
|||||||
@@ -17,14 +17,19 @@ a {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
a:visited { color:#000; }
|
a:visited { color:#000; }
|
||||||
|
|
||||||
a:link { color: #000; }
|
a:link { color: #000; }
|
||||||
|
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
/* font-family: Georgia, serif; */
|
/* font-family: Georgia, serif; */
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
@@ -471,4 +476,16 @@ a.button {
|
|||||||
.flexplot {
|
.flexplot {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.wh:link {
|
||||||
|
color: #e9e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.wh:visited {
|
||||||
|
color: #e9e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.wh:hover {
|
||||||
|
color: #e9e9e9;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user