Merge branch 'release/v9.63'
This commit is contained in:
+9
-2
@@ -108,9 +108,16 @@ def get_c2_workouts(rower):
|
|||||||
for item in res.json()['data']:
|
for item in res.json()['data']:
|
||||||
alldata[item['id']] = item
|
alldata[item['id']] = item
|
||||||
|
|
||||||
knownc2ids = uniqify([
|
knownc2ids = [
|
||||||
w.uploadedtoc2 for w in Workout.objects.filter(user=rower)
|
w.uploadedtoc2 for w in Workout.objects.filter(user=rower)
|
||||||
])
|
]
|
||||||
|
|
||||||
|
tombstones = [
|
||||||
|
t.uploadedtoc2 for t in TombStone.objects.filter(user=rower)
|
||||||
|
]
|
||||||
|
|
||||||
|
knownc2ids = uniqify(knownc2ids+tombstones)
|
||||||
|
|
||||||
newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
|
newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
|
||||||
|
|
||||||
for c2id in newids:
|
for c2id in newids:
|
||||||
|
|||||||
+24
-8
@@ -723,6 +723,7 @@ class TrendFlexModalForm(forms.Form):
|
|||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# This form sets options for the summary stats page
|
# This form sets options for the summary stats page
|
||||||
class StatsOptionsForm(forms.Form):
|
class StatsOptionsForm(forms.Form):
|
||||||
includereststrokes = forms.BooleanField(initial=False,label='Include Rest Strokes',required=False)
|
includereststrokes = forms.BooleanField(initial=False,label='Include Rest Strokes',required=False)
|
||||||
@@ -1181,24 +1182,39 @@ class FlexOptionsForm(forms.Form):
|
|||||||
('line','Line Plot'),
|
('line','Line Plot'),
|
||||||
('scatter','Scatter Plot'),
|
('scatter','Scatter Plot'),
|
||||||
)
|
)
|
||||||
plottype = forms.ChoiceField(choices=plotchoices,initial='scatter',
|
plottype = forms.ChoiceField(choices=plotchoices,initial='line',
|
||||||
label='Chart Type')
|
label='Chart Type')
|
||||||
|
|
||||||
|
class ForceCurveOptionsForm(forms.Form):
|
||||||
|
includereststrokes = forms.BooleanField(initial=False, required = False,
|
||||||
|
label='Include Rest Strokes')
|
||||||
|
plotchoices = (
|
||||||
|
('line','Force Curve Collection Plot'),
|
||||||
|
('scatter','Peak Force Scatter Plot'),
|
||||||
|
('none','Only aggregrate data')
|
||||||
|
)
|
||||||
|
plottype = forms.ChoiceField(choices=plotchoices,initial='scatter',
|
||||||
|
label='Individual Stroke Chart Type')
|
||||||
|
|
||||||
|
|
||||||
class FlexAxesForm(forms.Form):
|
class FlexAxesForm(forms.Form):
|
||||||
axchoices = (
|
axchoices = list(
|
||||||
(ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','None']
|
(ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','None']
|
||||||
)
|
)
|
||||||
|
axchoices = dict((x,y) for x,y in axchoices)
|
||||||
|
axchoices = list(sorted(axchoices.items(), key = lambda x:x[1]))
|
||||||
|
|
||||||
|
|
||||||
yaxchoices = (
|
yaxchoices = list((ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time'])
|
||||||
|
yaxchoices = dict((x,y) for x,y in yaxchoices)
|
||||||
|
yaxchoices = list(sorted(yaxchoices.items(), key = lambda x:x[1]))
|
||||||
|
|
||||||
|
|
||||||
|
yaxchoices2 = list(
|
||||||
(ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time']
|
(ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time']
|
||||||
)
|
)
|
||||||
|
yaxchoices2 = dict((x,y) for x,y in yaxchoices2)
|
||||||
yaxchoices2 = (
|
yaxchoices2 = list(sorted(yaxchoices2.items(), key = lambda x:x[1]))
|
||||||
(ax[0], ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time']
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
xaxis = forms.ChoiceField(
|
xaxis = forms.ChoiceField(
|
||||||
choices=axchoices,label='X-Axis',required=True)
|
choices=axchoices,label='X-Axis',required=True)
|
||||||
|
|||||||
+391
-33
@@ -17,6 +17,7 @@ from math import pi
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from bokeh.palettes import Dark2_8 as palette
|
from bokeh.palettes import Dark2_8 as palette
|
||||||
|
from bokeh.models.glyphs import MultiLine
|
||||||
import itertools
|
import itertools
|
||||||
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
|
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
|
||||||
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation
|
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation
|
||||||
@@ -64,6 +65,7 @@ activate(settings.TIME_ZONE)
|
|||||||
thetimezone = get_current_timezone()
|
thetimezone = get_current_timezone()
|
||||||
|
|
||||||
from scipy.stats import linregress,percentileofscore
|
from scipy.stats import linregress,percentileofscore
|
||||||
|
from scipy.spatial import ConvexHull,Delaunay
|
||||||
from scipy import optimize
|
from scipy import optimize
|
||||||
from scipy.signal import savgol_filter
|
from scipy.signal import savgol_filter
|
||||||
from scipy.interpolate import griddata
|
from scipy.interpolate import griddata
|
||||||
@@ -164,7 +166,8 @@ def tailwind(bearing,vwind,winddir):
|
|||||||
from rowers.dataprep import nicepaceformat,niceformat
|
from rowers.dataprep import nicepaceformat,niceformat
|
||||||
from rowers.dataprep import timedeltaconv
|
from rowers.dataprep import timedeltaconv
|
||||||
|
|
||||||
def interactive_boxchart(datadf,fieldname,extratitle=''):
|
def interactive_boxchart(datadf,fieldname,extratitle='',
|
||||||
|
spmmin=0,spmmax=0,workmin=0,workmax=0):
|
||||||
|
|
||||||
if datadf.empty:
|
if datadf.empty:
|
||||||
return '','It looks like there are no data matching your filter'
|
return '','It looks like there are no data matching your filter'
|
||||||
@@ -186,15 +189,6 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
|
|||||||
|
|
||||||
plot = hv.render(boxwhiskers)
|
plot = hv.render(boxwhiskers)
|
||||||
|
|
||||||
#plot = BoxPlot(datadf, values=fieldname, label='date',
|
|
||||||
# legend=False,
|
|
||||||
# title=axlabels[fieldname]+' '+extratitle,
|
|
||||||
# outliers=False,
|
|
||||||
# tools=TOOLS,
|
|
||||||
# toolbar_location="above",
|
|
||||||
# toolbar_sticky=False,
|
|
||||||
# x_mapper_type='datetime',plot_width=920)
|
|
||||||
|
|
||||||
yrange1 = Range1d(start=yaxminima[fieldname],end=yaxmaxima[fieldname])
|
yrange1 = Range1d(start=yaxminima[fieldname],end=yaxmaxima[fieldname])
|
||||||
plot.y_range = yrange1
|
plot.y_range = yrange1
|
||||||
plot.sizing_mode = 'scale_width'
|
plot.sizing_mode = 'scale_width'
|
||||||
@@ -221,6 +215,18 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
|
|||||||
plot.plot_width=920
|
plot.plot_width=920
|
||||||
plot.plot_height=600
|
plot.plot_height=600
|
||||||
|
|
||||||
|
slidertext = 'SPM: {:.0f}-{:.0f}, WpS: {:.0f}-{:.0f}'.format(
|
||||||
|
spmmin,spmmax,workmin,workmax
|
||||||
|
)
|
||||||
|
sliderlabel = Label(x=50,y=20,x_units='screen',y_units='screen',
|
||||||
|
text=slidertext,
|
||||||
|
background_fill_alpha=0.7,
|
||||||
|
background_fill_color='white',
|
||||||
|
text_color='black',text_font_size='10pt',
|
||||||
|
)
|
||||||
|
|
||||||
|
plot.add_layout(sliderlabel)
|
||||||
|
|
||||||
script, div = components(plot)
|
script, div = components(plot)
|
||||||
|
|
||||||
return script,div
|
return script,div
|
||||||
@@ -369,7 +375,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
|
|||||||
script,div = components(p)
|
script,div = components(p)
|
||||||
return script,div
|
return script,div
|
||||||
|
|
||||||
def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
|
||||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
|
||||||
ids = [int(w.id) for w in theworkouts]
|
ids = [int(w.id) for w in theworkouts]
|
||||||
@@ -399,63 +405,268 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
if rowdata.empty:
|
if rowdata.empty:
|
||||||
return "","No Valid Data Available","",""
|
return "","No Valid Data Available","",""
|
||||||
|
|
||||||
|
|
||||||
|
# quick linear regression
|
||||||
|
# peakforce = slope*peakforceangle + intercept
|
||||||
|
slope, intercept, r,p,stderr = linregress(rowdata['peakforceangle'],rowdata['peakforce'])
|
||||||
|
|
||||||
|
covariancematrix = np.cov(rowdata['peakforceangle'],y=rowdata['peakforce'])
|
||||||
|
eig_vals, eig_vecs = np.linalg.eig(covariancematrix)
|
||||||
|
|
||||||
|
a = rowdata['peakforceangle']-rowdata['peakforceangle'].median()
|
||||||
|
F = rowdata['peakforce']-rowdata['peakforce'].median()
|
||||||
|
|
||||||
|
Rinv = eig_vecs
|
||||||
|
R = np.linalg.inv(Rinv)
|
||||||
|
|
||||||
|
x = R[0,0]*a+R[0,1]*F
|
||||||
|
y = R[1,0]*a+R[1,1]*F
|
||||||
|
|
||||||
|
|
||||||
|
x05 = x.quantile(q=0.01)
|
||||||
|
x25 = x.quantile(q=0.15)
|
||||||
|
x75 = x.quantile(q=0.85)
|
||||||
|
x95 = x.quantile(q=0.99)
|
||||||
|
|
||||||
|
y05 = y.quantile(q=0.01)
|
||||||
|
y25 = y.quantile(q=0.15)
|
||||||
|
y75 = y.quantile(q=0.85)
|
||||||
|
y95 = y.quantile(q=0.99)
|
||||||
|
|
||||||
|
a25 = Rinv[0,0]*x25 + rowdata['peakforceangle'].median()
|
||||||
|
F25 = Rinv[1,0]*x25 + rowdata['peakforce'].median()
|
||||||
|
|
||||||
|
a25b = Rinv[0,1]*y25 + rowdata['peakforceangle'].median()
|
||||||
|
F25b = Rinv[1,1]*y25 + rowdata['peakforce'].median()
|
||||||
|
|
||||||
|
a75 = Rinv[0,0]*x75 + rowdata['peakforceangle'].median()
|
||||||
|
F75 = Rinv[1,0]*x75 + rowdata['peakforce'].median()
|
||||||
|
|
||||||
|
a75b = Rinv[0,1]*y75 + rowdata['peakforceangle'].median()
|
||||||
|
F75b = Rinv[1,1]*y75 + rowdata['peakforce'].median()
|
||||||
|
|
||||||
|
|
||||||
|
a05 = Rinv[0,0]*x05 + rowdata['peakforceangle'].median()
|
||||||
|
F05 = Rinv[1,0]*x05 + rowdata['peakforce'].median()
|
||||||
|
|
||||||
|
a05b = Rinv[0,1]*y05 + rowdata['peakforceangle'].median()
|
||||||
|
F05b = Rinv[1,1]*y05 + rowdata['peakforce'].median()
|
||||||
|
|
||||||
|
a95 = Rinv[0,0]*x95 + rowdata['peakforceangle'].median()
|
||||||
|
F95 = Rinv[1,0]*x95 + rowdata['peakforce'].median()
|
||||||
|
|
||||||
|
a95b = Rinv[0,1]*y95 + rowdata['peakforceangle'].median()
|
||||||
|
F95b = Rinv[1,1]*y95 + rowdata['peakforce'].median()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
catchav = rowdata['catch'].mean()
|
catchav = rowdata['catch'].median()
|
||||||
|
catch25 = rowdata['catch'].quantile(q=0.25)
|
||||||
|
catch75 = rowdata['catch'].quantile(q=0.75)
|
||||||
|
catch05 = rowdata['catch'].quantile(q=0.05)
|
||||||
|
catch95 = rowdata['catch'].quantile(q=0.95)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
catchav = 0
|
catchav = 0
|
||||||
|
catch25 = 0
|
||||||
|
catch75 = 0
|
||||||
|
catch05 = 0
|
||||||
|
catch95 = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
finishav = rowdata['finish'].mean()
|
finishav = rowdata['finish'].median()
|
||||||
|
finish25 = rowdata['finish'].quantile(q=0.25)
|
||||||
|
finish75 = rowdata['finish'].quantile(q=0.75)
|
||||||
|
finish05 = rowdata['finish'].quantile(q=0.05)
|
||||||
|
finish95 = rowdata['finish'].quantile(q=0.95)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
finishav = 0
|
finishav = 0
|
||||||
|
finish25 = 0
|
||||||
|
finish75 = 0
|
||||||
|
finish05 = 0
|
||||||
|
finish95 = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
washav = rowdata['wash'].mean()
|
washav = (rowdata['finish']-rowdata['wash']).median()
|
||||||
|
wash25 = (rowdata['finish']-rowdata['wash']).quantile(q=0.25)
|
||||||
|
wash75 = (rowdata['finish']-rowdata['wash']).quantile(q=0.75)
|
||||||
|
wash05 = (rowdata['finish']-rowdata['wash']).quantile(q=0.05)
|
||||||
|
wash95 = (rowdata['finish']-rowdata['wash']).quantile(q=0.95)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
washav = 0
|
washav = 0
|
||||||
|
wash25 = 0
|
||||||
|
wash75 = 0
|
||||||
|
wash05 = 0
|
||||||
|
wash95 = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
slipav = rowdata['slip'].mean()
|
slipav = (rowdata['slip']+rowdata['catch']).median()
|
||||||
|
slip25 = (rowdata['slip']+rowdata['catch']).quantile(q=0.25)
|
||||||
|
slip75 = (rowdata['slip']+rowdata['catch']).quantile(q=0.75)
|
||||||
|
slip05 = (rowdata['slip']+rowdata['catch']).quantile(q=0.05)
|
||||||
|
slip95 = (rowdata['slip']+rowdata['catch']).quantile(q=0.95)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
slipav = 0
|
slipav = 0
|
||||||
|
slip25 = 0
|
||||||
|
slip75 = 0
|
||||||
|
slip05 = 0
|
||||||
|
slip95 = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
peakforceav = rowdata['peakforce'].mean()
|
peakforceav = rowdata['peakforce'].median()
|
||||||
|
peakforce25 = rowdata['peakforce'].quantile(q=0.25)
|
||||||
|
peakforce75 = rowdata['peakforce'].quantile(q=0.75)
|
||||||
|
peakforce05 = rowdata['peakforce'].quantile(q=0.05)
|
||||||
|
peakforce95 = rowdata['peakforce'].quantile(q=0.95)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
peakforceav = 0
|
peakforceav = 0
|
||||||
|
peakforce25 = 0
|
||||||
|
peakforce75 = 0
|
||||||
|
peakforce05 = 0
|
||||||
|
peakforce95 = 0
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
averageforceav = rowdata['averageforce'].mean()
|
averageforceav = rowdata['averageforce'].median()
|
||||||
except KeyError:
|
except KeyError:
|
||||||
averageforceav = 0
|
averageforceav = 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
peakforceangleav = rowdata['peakforceangle'].mean()
|
peakforceangleav = rowdata['peakforceangle'].median()
|
||||||
|
peakforceangle05 = rowdata['peakforceangle'].quantile(q=0.05)
|
||||||
|
peakforceangle25 = rowdata['peakforceangle'].quantile(q=0.25)
|
||||||
|
peakforceangle75 = rowdata['peakforceangle'].quantile(q=0.75)
|
||||||
|
peakforceangle95 = rowdata['peakforceangle'].quantile(q=0.95)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
peakforceangleav = 0
|
peakforceangleav = 0
|
||||||
|
peakforceangle25 = 0
|
||||||
|
peakforceangle75 = 0
|
||||||
|
peakforceangle05 = 0
|
||||||
|
peakforceangle95 = 0
|
||||||
|
|
||||||
|
|
||||||
|
#thresholdforce /= 4.45 # N to lbs
|
||||||
|
thresholdforce = 100 if 'x' in boattype else 200
|
||||||
|
points2575 = [
|
||||||
|
(catch25,0), #0
|
||||||
|
(slip25,thresholdforce), #1
|
||||||
|
(a75,F75),#4
|
||||||
|
(a25b,F25b), #9
|
||||||
|
(a25,F25), #2
|
||||||
|
(wash75,thresholdforce), #5
|
||||||
|
(finish75,0), #6
|
||||||
|
(finish25,0), #7
|
||||||
|
(wash25,thresholdforce), #8
|
||||||
|
(a75b,F75b), #3
|
||||||
|
(slip75,thresholdforce), #10
|
||||||
|
(catch75,0), #11
|
||||||
|
]
|
||||||
|
|
||||||
|
points0595 = [
|
||||||
|
(catch05,0), #0
|
||||||
|
(slip05,thresholdforce), #1
|
||||||
|
(a95,F95),#4
|
||||||
|
(a05b,F05b), #9
|
||||||
|
(a05,F05), #2
|
||||||
|
(wash95,thresholdforce), #5
|
||||||
|
(finish95,0), #6
|
||||||
|
(finish05,0), #7
|
||||||
|
(wash05,thresholdforce), #8
|
||||||
|
(a95b,F95b), #3
|
||||||
|
(slip95,thresholdforce), #10
|
||||||
|
(catch95,0), #11
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
hull2575 = ConvexHull(points2575)
|
||||||
|
|
||||||
|
|
||||||
|
angles2575 = []
|
||||||
|
forces2575 = []
|
||||||
|
|
||||||
|
for x,y in points2575:
|
||||||
|
angles2575.append(x)
|
||||||
|
forces2575.append(y)
|
||||||
|
|
||||||
|
|
||||||
|
angles0595 = []
|
||||||
|
forces0595 = []
|
||||||
|
|
||||||
|
for x,y in points0595:
|
||||||
|
angles0595.append(x)
|
||||||
|
forces0595.append(y)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
x = [catchav,
|
x = [catchav,
|
||||||
catchav+slipav,
|
slipav,
|
||||||
peakforceangleav,
|
peakforceangleav,
|
||||||
finishav-washav,
|
washav,
|
||||||
finishav]
|
finishav]
|
||||||
|
|
||||||
thresholdforce = 100 if 'x' in boattype else 200
|
|
||||||
#thresholdforce /= 4.45 # N to lbs
|
|
||||||
y = [0,thresholdforce,
|
y = [0,thresholdforce,
|
||||||
peakforceav,
|
peakforceav,
|
||||||
thresholdforce,0]
|
thresholdforce,0]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
source = ColumnDataSource(
|
source = ColumnDataSource(
|
||||||
data = dict(
|
data = dict(
|
||||||
x = x,
|
x = x,
|
||||||
y = y,
|
y = y,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
sourceslipwash = ColumnDataSource(
|
||||||
|
data = dict(
|
||||||
|
xslip = [slipav,washav],
|
||||||
|
yslip = [thresholdforce,thresholdforce]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
sourcetrend = ColumnDataSource(
|
||||||
|
data = dict(
|
||||||
|
x = [peakforceangle25,peakforceangle75],
|
||||||
|
y = [peakforce25,peakforce75]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
sourcefit = ColumnDataSource(
|
||||||
|
data = dict(
|
||||||
|
x = np.array([peakforceangle25,peakforceangle75]),
|
||||||
|
y = slope*np.array([peakforceangle25,peakforceangle75])+intercept
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
source2 = ColumnDataSource(
|
source2 = ColumnDataSource(
|
||||||
rowdata
|
rowdata
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if plottype == 'scatter':
|
||||||
|
sourcepoints = ColumnDataSource(
|
||||||
|
data = dict(
|
||||||
|
peakforceangle = rowdata['peakforceangle'],
|
||||||
|
peakforce = rowdata['peakforce']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
sourcepoints = ColumnDataSource(
|
||||||
|
data = dict(
|
||||||
|
peakforceangle = [],
|
||||||
|
peakforce = []
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
sourcerange = ColumnDataSource(
|
||||||
|
data = dict(
|
||||||
|
x2575 = angles2575,
|
||||||
|
y2575 = forces2575,
|
||||||
|
x0595 = angles0595,
|
||||||
|
y0595 = forces0595,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
plot = Figure(tools=TOOLS,
|
plot = Figure(tools=TOOLS,
|
||||||
toolbar_sticky=False,toolbar_location="above")
|
toolbar_sticky=False,toolbar_location="above")
|
||||||
|
|
||||||
@@ -489,6 +700,56 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
avf = Span(location=averageforceav,dimension='width',line_color='blue',
|
avf = Span(location=averageforceav,dimension='width',line_color='blue',
|
||||||
line_dash=[6,6],line_width=2)
|
line_dash=[6,6],line_width=2)
|
||||||
|
|
||||||
|
plot.patch('x0595','y0595',source=sourcerange,color="red",alpha=0.05)
|
||||||
|
plot.patch('x2575','y2575',source=sourcerange,color="red",alpha=0.2)
|
||||||
|
plot.line('x','y',source=source,color="red")
|
||||||
|
plot.circle('xslip','yslip',source=sourceslipwash,color="red")
|
||||||
|
|
||||||
|
plot.circle('peakforceangle','peakforce',source=sourcepoints,color='black',alpha=0.1)
|
||||||
|
|
||||||
|
if plottype == 'line':
|
||||||
|
multilinedatax = []
|
||||||
|
multilinedatay = []
|
||||||
|
for i in range(len(rowdata)):
|
||||||
|
x = [
|
||||||
|
rowdata['catch'].values[i],
|
||||||
|
rowdata['slip'].values[i]+rowdata['catch'].values[i],
|
||||||
|
rowdata['peakforceangle'].values[i],
|
||||||
|
rowdata['finish'].values[i]-rowdata['wash'].values[i],
|
||||||
|
rowdata['finish'].values[i]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
y = [
|
||||||
|
0,
|
||||||
|
thresholdforce,
|
||||||
|
rowdata['peakforce'].values[i],
|
||||||
|
thresholdforce,
|
||||||
|
0]
|
||||||
|
|
||||||
|
multilinedatax.append(x)
|
||||||
|
multilinedatay.append(y)
|
||||||
|
|
||||||
|
sourcemultiline = ColumnDataSource(dict(
|
||||||
|
x=multilinedatax,
|
||||||
|
y=multilinedatay,
|
||||||
|
))
|
||||||
|
|
||||||
|
sourcemultiline2 = ColumnDataSource(dict(
|
||||||
|
x=multilinedatax,
|
||||||
|
y=multilinedatay,
|
||||||
|
))
|
||||||
|
|
||||||
|
glyph = MultiLine(xs='x',ys='y',line_color='black',line_alpha=0.05)
|
||||||
|
plot.add_glyph(sourcemultiline,glyph)
|
||||||
|
else:
|
||||||
|
sourcemultiline = ColumnDataSource(dict(
|
||||||
|
x=[],y=[]))
|
||||||
|
|
||||||
|
sourcemultiline2 = ColumnDataSource(dict(
|
||||||
|
x=[],y=[]))
|
||||||
|
|
||||||
|
|
||||||
plot.line('x','y',source=source,color="red")
|
plot.line('x','y',source=source,color="red")
|
||||||
|
|
||||||
plot.add_layout(avf)
|
plot.add_layout(avf)
|
||||||
@@ -529,19 +790,34 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
)
|
)
|
||||||
|
|
||||||
sliplabel = Label(x=370,y=280,x_units='screen',y_units='screen',
|
sliplabel = Label(x=370,y=280,x_units='screen',y_units='screen',
|
||||||
text="Slip: {slipav:6.2f}".format(slipav=slipav),
|
text="Slip: {slipav:6.2f}".format(slipav=slipav-catchav),
|
||||||
background_fill_alpha=0.7,
|
background_fill_alpha=0.7,
|
||||||
background_fill_color='white',
|
background_fill_color='white',
|
||||||
text_color='red',
|
text_color='red',
|
||||||
)
|
)
|
||||||
|
|
||||||
washlabel = Label(x=360,y=250,x_units='screen',y_units='screen',
|
washlabel = Label(x=360,y=250,x_units='screen',y_units='screen',
|
||||||
text="Wash: {washav:6.2f}".format(washav=washav),
|
text="Wash: {washav:6.2f}".format(washav=finishav-washav),
|
||||||
background_fill_alpha=0.7,
|
background_fill_alpha=0.7,
|
||||||
background_fill_color='white',
|
background_fill_color='white',
|
||||||
text_color='red',
|
text_color='red',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
annolabel = Label(x=50,y=450,x_units='screen',y_units='screen',
|
||||||
|
text='',
|
||||||
|
background_fill_alpha=0.7,
|
||||||
|
background_fill_color='white',
|
||||||
|
text_color='black',
|
||||||
|
)
|
||||||
|
|
||||||
|
sliderlabel = Label(x=10,y=470,x_units='screen',y_units='screen',
|
||||||
|
text='',
|
||||||
|
background_fill_alpha=0.7,
|
||||||
|
background_fill_color='white',
|
||||||
|
text_color='black',text_font_size='10pt',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
plot.add_layout(peakflabel)
|
plot.add_layout(peakflabel)
|
||||||
plot.add_layout(peakforceanglelabel)
|
plot.add_layout(peakforceanglelabel)
|
||||||
plot.add_layout(avflabel)
|
plot.add_layout(avflabel)
|
||||||
@@ -549,6 +825,8 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
plot.add_layout(sliplabel)
|
plot.add_layout(sliplabel)
|
||||||
plot.add_layout(washlabel)
|
plot.add_layout(washlabel)
|
||||||
plot.add_layout(finishlabel)
|
plot.add_layout(finishlabel)
|
||||||
|
plot.add_layout(annolabel)
|
||||||
|
plot.add_layout(sliderlabel)
|
||||||
|
|
||||||
plot.xaxis.axis_label = "Angle"
|
plot.xaxis.axis_label = "Angle"
|
||||||
plot.yaxis.axis_label = "Force (N)"
|
plot.yaxis.axis_label = "Force (N)"
|
||||||
@@ -564,6 +842,8 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
callback = CustomJS(args = dict(
|
callback = CustomJS(args = dict(
|
||||||
source=source,
|
source=source,
|
||||||
source2=source2,
|
source2=source2,
|
||||||
|
sourceslipwash=sourceslipwash,
|
||||||
|
sourcepoints=sourcepoints,
|
||||||
avf=avf,
|
avf=avf,
|
||||||
avflabel=avflabel,
|
avflabel=avflabel,
|
||||||
catchlabel=catchlabel,
|
catchlabel=catchlabel,
|
||||||
@@ -572,12 +852,28 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
washlabel=washlabel,
|
washlabel=washlabel,
|
||||||
peakflabel=peakflabel,
|
peakflabel=peakflabel,
|
||||||
peakforceanglelabel=peakforceanglelabel,
|
peakforceanglelabel=peakforceanglelabel,
|
||||||
|
annolabel=annolabel,
|
||||||
|
sliderlabel=sliderlabel,
|
||||||
|
plottype=plottype,
|
||||||
|
sourcemultiline=sourcemultiline,
|
||||||
|
sourcemultiline2=sourcemultiline2
|
||||||
), code="""
|
), code="""
|
||||||
var data = source.data
|
var data = source.data
|
||||||
var data2 = source2.data
|
var data2 = source2.data
|
||||||
|
var dataslipwash = sourceslipwash.data
|
||||||
|
var datapoints = sourcepoints.data
|
||||||
|
var multilines = sourcemultiline.data
|
||||||
|
var multilines2 = sourcemultiline2.data
|
||||||
|
var plottype = plottype
|
||||||
|
|
||||||
|
var multilinesx = multilines2['x']
|
||||||
|
var multilinesy = multilines2['y']
|
||||||
|
|
||||||
var x = data['x']
|
var x = data['x']
|
||||||
var y = data['y']
|
var y = data['y']
|
||||||
|
|
||||||
|
var xslip = dataslipwash['xslip']
|
||||||
|
|
||||||
var spm1 = data2['spm']
|
var spm1 = data2['spm']
|
||||||
var distance1 = data2['distance']
|
var distance1 = data2['distance']
|
||||||
var driveenergy1 = data2['driveenergy']
|
var driveenergy1 = data2['driveenergy']
|
||||||
@@ -592,6 +888,10 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
var peakforce = data2['peakforce']
|
var peakforce = data2['peakforce']
|
||||||
var averageforce = data2['averageforce']
|
var averageforce = data2['averageforce']
|
||||||
|
|
||||||
|
var peakforcepoints = datapoints['peakforce']
|
||||||
|
var peakforceanglepoints = datapoints['peakforceangle']
|
||||||
|
|
||||||
|
var annotation = annotation.value
|
||||||
var minspm = minspm.value
|
var minspm = minspm.value
|
||||||
var maxspm = maxspm.value
|
var maxspm = maxspm.value
|
||||||
var mindist = mindist.value
|
var mindist = mindist.value
|
||||||
@@ -599,6 +899,10 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
var minwork = minwork.value
|
var minwork = minwork.value
|
||||||
var maxwork = maxwork.value
|
var maxwork = maxwork.value
|
||||||
|
|
||||||
|
sliderlabel.text = 'SPM: '+minspm.toFixed(0)+'-'+maxspm.toFixed(0)
|
||||||
|
sliderlabel.text += ', Dist: '+mindist.toFixed(0)+'-'+maxdist.toFixed(0)
|
||||||
|
sliderlabel.text += ', WpS: '+minwork.toFixed(0)+'-'+maxwork.toFixed(0)
|
||||||
|
|
||||||
var catchav = 0
|
var catchav = 0
|
||||||
var finishav = 0
|
var finishav = 0
|
||||||
var slipav = 0
|
var slipav = 0
|
||||||
@@ -608,11 +912,23 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
var peakforceav = 0
|
var peakforceav = 0
|
||||||
var count = 0
|
var count = 0
|
||||||
|
|
||||||
|
datapoints['peakforceangle'] = []
|
||||||
|
datapoints['peakforce'] = []
|
||||||
|
multilines['x'] = []
|
||||||
|
multilines['y'] = []
|
||||||
|
|
||||||
for (i=0; i<c.length; i++) {
|
for (i=0; i<c.length; i++) {
|
||||||
if (spm1[i]>=minspm && spm1[i]<=maxspm) {
|
if (spm1[i]>=minspm && spm1[i]<=maxspm) {
|
||||||
if (distance1[i]>=mindist && distance1[i]<=maxdist) {
|
if (distance1[i]>=mindist && distance1[i]<=maxdist) {
|
||||||
if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
|
if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
|
||||||
|
if (plottype=='scatter') {
|
||||||
|
datapoints['peakforceangle'].push(peakforceangle[i])
|
||||||
|
datapoints['peakforce'].push(peakforce[i])
|
||||||
|
}
|
||||||
|
if (plottype=='line') {
|
||||||
|
multilines['x'].push(multilinesx[i])
|
||||||
|
multilines['y'].push(multilinesy[i])
|
||||||
|
}
|
||||||
catchav += c[i]
|
catchav += c[i]
|
||||||
finishav += finish[i]
|
finishav += finish[i]
|
||||||
slipav += slip[i]
|
slipav += slip[i]
|
||||||
@@ -637,6 +953,9 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
data['x'] = [catchav,catchav+slipav,peakforceangleav,finishav-washav,finishav]
|
data['x'] = [catchav,catchav+slipav,peakforceangleav,finishav-washav,finishav]
|
||||||
data['y'] = [0,thresholdforce,peakforceav,thresholdforce,0]
|
data['y'] = [0,thresholdforce,peakforceav,thresholdforce,0]
|
||||||
|
|
||||||
|
dataslipwash['xslip'] = [catchav+slipav,finishav-washav]
|
||||||
|
dataslipwash['yslip'] = [thresholdforce,thresholdforce]
|
||||||
|
|
||||||
avf.location = averageforceav
|
avf.location = averageforceav
|
||||||
avflabel.text = 'Favg: '+averageforceav.toFixed(2)
|
avflabel.text = 'Favg: '+averageforceav.toFixed(2)
|
||||||
catchlabel.text = 'Catch: '+catchav.toFixed(2)
|
catchlabel.text = 'Catch: '+catchav.toFixed(2)
|
||||||
@@ -645,11 +964,23 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
washlabel.text = 'Wash: '+washav.toFixed(2)
|
washlabel.text = 'Wash: '+washav.toFixed(2)
|
||||||
peakflabel.text = 'Fpeak: '+peakforceav.toFixed(2)
|
peakflabel.text = 'Fpeak: '+peakforceav.toFixed(2)
|
||||||
peakforceanglelabel.text = 'Peak angle: '+peakforceangleav.toFixed(2)
|
peakforceanglelabel.text = 'Peak angle: '+peakforceangleav.toFixed(2)
|
||||||
|
annolabel.text = annotation
|
||||||
|
|
||||||
|
console.log(count);
|
||||||
|
console.log(multilines['x'].length);
|
||||||
|
console.log(multilines['y'].length);
|
||||||
|
|
||||||
// source.trigger('change');
|
// source.trigger('change');
|
||||||
source.change.emit();
|
source.change.emit();
|
||||||
|
sourceslipwash.change.emit()
|
||||||
|
sourcepoints.change.emit();
|
||||||
|
sourcemultiline.change.emit();
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
annotation = TextInput(title="Type your plot notes here", value="",
|
||||||
|
callback=callback)
|
||||||
|
callback.args["annotation"] = annotation
|
||||||
|
|
||||||
slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1,
|
slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1,
|
||||||
title="Min SPM",callback=callback)
|
title="Min SPM",callback=callback)
|
||||||
callback.args["minspm"] = slider_spm_min
|
callback.args["minspm"] = slider_spm_min
|
||||||
@@ -679,7 +1010,8 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
title="Max Distance",callback=callback)
|
title="Max Distance",callback=callback)
|
||||||
callback.args["maxdist"] = slider_dist_max
|
callback.args["maxdist"] = slider_dist_max
|
||||||
|
|
||||||
layout = layoutrow([layoutcolumn([slider_spm_min,
|
layout = layoutrow([layoutcolumn([annotation,
|
||||||
|
slider_spm_min,
|
||||||
slider_spm_max,
|
slider_spm_max,
|
||||||
slider_dist_min,
|
slider_dist_min,
|
||||||
slider_dist_max,
|
slider_dist_max,
|
||||||
@@ -2370,7 +2702,8 @@ def interactive_chart(id=0,promember=0,intervaldata = {}):
|
|||||||
|
|
||||||
def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
|
def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
|
||||||
ploterrorbars=False,
|
ploterrorbars=False,
|
||||||
title=None,binsize=1,colorlegend=[]):
|
title=None,binsize=1,colorlegend=[],
|
||||||
|
spmmin=0,spmmax=0,workmin=0,workmax=0):
|
||||||
|
|
||||||
if datadf.empty:
|
if datadf.empty:
|
||||||
return ['','<p>No non-zero data in selection</p>']
|
return ['','<p>No non-zero data in selection</p>']
|
||||||
@@ -2515,8 +2848,8 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
|
|||||||
|
|
||||||
|
|
||||||
for nr, gvalue, color in colorlegend:
|
for nr, gvalue, color in colorlegend:
|
||||||
box = BoxAnnotation(bottom=125+20*nr,left=100,top=145+20*nr,
|
box = BoxAnnotation(bottom=75+20*nr,left=50,top=95+20*nr,
|
||||||
right=120,
|
right=70,
|
||||||
bottom_units='screen',
|
bottom_units='screen',
|
||||||
top_units='screen',
|
top_units='screen',
|
||||||
left_units='screen',
|
left_units='screen',
|
||||||
@@ -2524,7 +2857,7 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
|
|||||||
fill_color=color,
|
fill_color=color,
|
||||||
fill_alpha=1.0,
|
fill_alpha=1.0,
|
||||||
line_color=color)
|
line_color=color)
|
||||||
legendlabel = Label(x=121,y=128+20*nr,x_units='screen',
|
legendlabel = Label(x=71,y=78+20*nr,x_units='screen',
|
||||||
y_units='screen',
|
y_units='screen',
|
||||||
text = "{gvalue:3.0f}".format(gvalue=gvalue),
|
text = "{gvalue:3.0f}".format(gvalue=gvalue),
|
||||||
background_fill_alpha=1.0,
|
background_fill_alpha=1.0,
|
||||||
@@ -2534,7 +2867,7 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
|
|||||||
plot.add_layout(legendlabel)
|
plot.add_layout(legendlabel)
|
||||||
|
|
||||||
if colorlegend:
|
if colorlegend:
|
||||||
legendlabel = Label(x=372,y=300,x_units='screen',
|
legendlabel = Label(x=322,y=250,x_units='screen',
|
||||||
y_units='screen',
|
y_units='screen',
|
||||||
text = 'group legend',
|
text = 'group legend',
|
||||||
text_color='black',
|
text_color='black',
|
||||||
@@ -2552,15 +2885,27 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
|
|||||||
else:
|
else:
|
||||||
plot.yaxis.axis_label = axlabels[yparam]
|
plot.yaxis.axis_label = axlabels[yparam]
|
||||||
|
|
||||||
binlabel = Label(x=100,y=100,x_units='screen',
|
binlabel = Label(x=50,y=50,x_units='screen',
|
||||||
y_units='screen',
|
y_units='screen',
|
||||||
text="Bin size {binsize:3.1f}".format(binsize=binsize),
|
text="Bin size {binsize:3.1f}".format(binsize=binsize),
|
||||||
background_fill_alpha=0.7,
|
background_fill_alpha=0.7,
|
||||||
background_fill_color='white',
|
background_fill_color='white',
|
||||||
text_color='black',
|
text_color='black',text_font_size='10pt',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
slidertext = 'SPM: {:.0f}-{:.0f}, WpS: {:.0f}-{:.0f}'.format(
|
||||||
|
spmmin,spmmax,workmin,workmax
|
||||||
|
)
|
||||||
|
sliderlabel = Label(x=50,y=20,x_units='screen',y_units='screen',
|
||||||
|
text=slidertext,
|
||||||
|
background_fill_alpha=0.7,
|
||||||
|
background_fill_color='white',
|
||||||
|
text_color='black',text_font_size='10pt',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
plot.add_layout(binlabel)
|
plot.add_layout(binlabel)
|
||||||
|
plot.add_layout(sliderlabel)
|
||||||
|
|
||||||
yrange1 = Range1d(start=yaxmin,end=yaxmax)
|
yrange1 = Range1d(start=yaxmin,end=yaxmax)
|
||||||
plot.y_range = yrange1
|
plot.y_range = yrange1
|
||||||
@@ -2752,11 +3097,18 @@ def interactive_cum_flex_chart2(theworkouts,promember=0,
|
|||||||
text_color='green',
|
text_color='green',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
sliderlabel = Label(x=10,y=470,x_units='screen',y_units='screen',
|
||||||
|
text='',
|
||||||
|
background_fill_alpha=0.7,
|
||||||
|
background_fill_color='white',
|
||||||
|
text_color='black',text_font_size='10pt',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
plot.add_layout(x1means)
|
plot.add_layout(x1means)
|
||||||
plot.add_layout(xlabel)
|
plot.add_layout(xlabel)
|
||||||
|
|
||||||
plot.add_layout(y1means)
|
plot.add_layout(y1means)
|
||||||
|
plot.add_layout(sliderlabel)
|
||||||
|
|
||||||
y1label = Label(x=50,y=50,x_units='screen',y_units='screen',
|
y1label = Label(x=50,y=50,x_units='screen',y_units='screen',
|
||||||
text=axlabels[yparam1]+": {y1mean:6.2f}".format(y1mean=y1mean),
|
text=axlabels[yparam1]+": {y1mean:6.2f}".format(y1mean=y1mean),
|
||||||
@@ -2820,6 +3172,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0,
|
|||||||
y1label=y1label,
|
y1label=y1label,
|
||||||
y2label=y2label,
|
y2label=y2label,
|
||||||
xlabel=xlabel,
|
xlabel=xlabel,
|
||||||
|
sliderlabel=sliderlabel,
|
||||||
y2means=y2means), code="""
|
y2means=y2means), code="""
|
||||||
var data = source.data
|
var data = source.data
|
||||||
var data2 = source2.data
|
var data2 = source2.data
|
||||||
@@ -2844,6 +3197,11 @@ def interactive_cum_flex_chart2(theworkouts,promember=0,
|
|||||||
var maxdist = maxdist.value
|
var maxdist = maxdist.value
|
||||||
var minwork = minwork.value
|
var minwork = minwork.value
|
||||||
var maxwork = maxwork.value
|
var maxwork = maxwork.value
|
||||||
|
|
||||||
|
sliderlabel.text = 'SPM: '+minspm.toFixed(0)+'-'+maxspm.toFixed(0)
|
||||||
|
sliderlabel.text += ', Dist: '+mindist.toFixed(0)+'-'+maxdist.toFixed(0)
|
||||||
|
sliderlabel.text += ', WpS: '+minwork.toFixed(0)+'-'+maxwork.toFixed(0)
|
||||||
|
|
||||||
var xm = 0
|
var xm = 0
|
||||||
var ym1 = 0
|
var ym1 = 0
|
||||||
var ym2 = 0
|
var ym2 = 0
|
||||||
|
|||||||
+1
-1
@@ -285,7 +285,7 @@ axesnew = [
|
|||||||
(name,d['verbose_name'],d['ax_min'],d['ax_max'],d['type']) for name,d in rowingmetrics
|
(name,d['verbose_name'],d['ax_min'],d['ax_max'],d['type']) for name,d in rowingmetrics
|
||||||
]
|
]
|
||||||
|
|
||||||
axes = tuple(axesnew+[('None','None',0,1,'basic')])
|
axes = tuple(axesnew+[('None','<None>',0,1,'basic')])
|
||||||
|
|
||||||
axlabels = {ax[0]:ax[1] for ax in axes}
|
axlabels = {ax[0]:ax[1] for ax in axes}
|
||||||
|
|
||||||
|
|||||||
+21
-1
@@ -2506,7 +2506,6 @@ class PlannedSessionFormSmall(ModelForm):
|
|||||||
boattypes = mytypes.boattypes
|
boattypes = mytypes.boattypes
|
||||||
|
|
||||||
# Workout
|
# Workout
|
||||||
@python_2_unicode_compatible
|
|
||||||
class Workout(models.Model):
|
class Workout(models.Model):
|
||||||
workouttypes = mytypes.workouttypes
|
workouttypes = mytypes.workouttypes
|
||||||
workoutsources = mytypes.workoutsources
|
workoutsources = mytypes.workoutsources
|
||||||
@@ -2612,6 +2611,27 @@ class Workout(models.Model):
|
|||||||
|
|
||||||
return stri
|
return stri
|
||||||
|
|
||||||
|
class TombStone(models.Model):
|
||||||
|
user = models.ForeignKey(Rower,on_delete=models.CASCADE)
|
||||||
|
uploadedtoc2 = models.IntegerField(default=0)
|
||||||
|
uploadedtostrava = models.BigIntegerField(default=0)
|
||||||
|
uploadedtosporttracks = models.BigIntegerField(default=0)
|
||||||
|
uploadedtounderarmour = models.BigIntegerField(default=0)
|
||||||
|
uploadedtotp = models.BigIntegerField(default=0)
|
||||||
|
uploadedtorunkeeper = models.BigIntegerField(default=0)
|
||||||
|
|
||||||
|
@receiver(models.signals.pre_delete,sender=Workout)
|
||||||
|
def create_tombstone_on_delete(sender, instance, **kwargs):
|
||||||
|
t = TombStone(
|
||||||
|
user=instance.user,
|
||||||
|
uploadedtoc2 = instance.uploadedtoc2,
|
||||||
|
uploadedtostrava = instance.uploadedtostrava,
|
||||||
|
uploadedtounderarmour = instance.uploadedtounderarmour,
|
||||||
|
uploadedtotp = instance.uploadedtotp,
|
||||||
|
uploadedtorunkeeper = instance.uploadedtorunkeeper,
|
||||||
|
)
|
||||||
|
t.save()
|
||||||
|
|
||||||
# delete files belonging to workout instance
|
# delete files belonging to workout instance
|
||||||
# related GraphImage objects should be deleted automatically
|
# related GraphImage objects should be deleted automatically
|
||||||
@receiver(models.signals.post_delete,sender=Workout)
|
@receiver(models.signals.post_delete,sender=Workout)
|
||||||
|
|||||||
@@ -165,9 +165,15 @@ def get_strava_workouts(rower):
|
|||||||
w.uploadedtostrava = int(stravaid)
|
w.uploadedtostrava = int(stravaid)
|
||||||
w.save()
|
w.save()
|
||||||
|
|
||||||
knownstravaids = uniqify([
|
knownstravaids = [
|
||||||
w.uploadedtostrava for w in Workout.objects.filter(user=rower)
|
w.uploadedtostrava for w in Workout.objects.filter(user=rower)
|
||||||
])
|
]
|
||||||
|
|
||||||
|
tombstones = [
|
||||||
|
t.uploadedtostrava for t in TombStone.objects.filter(user=rower)
|
||||||
|
]
|
||||||
|
|
||||||
|
knownstravaids = uniqify(knownstravaids+tombstones)
|
||||||
|
|
||||||
newids = [stravaid for stravaid in stravaids if not stravaid in knownstravaids]
|
newids = [stravaid for stravaid in stravaids if not stravaid in knownstravaids]
|
||||||
|
|
||||||
|
|||||||
@@ -23,23 +23,22 @@
|
|||||||
|
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
<li class="grid_4">
|
<li class="grid_4">
|
||||||
{% if user.is_authenticated and mayedit %}
|
<div id="theplot" class="flexplot">
|
||||||
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
{{ the_div|safe }}
|
||||||
{% csrf_token %}
|
</div>
|
||||||
{% if workstrokesonly %}
|
|
||||||
<input type="hidden" name="workstrokesonly" value="True">
|
|
||||||
<input class="button blue small" value="Remove Rest Strokes" type="Submit">
|
|
||||||
{% else %}
|
|
||||||
<input class="button blue small" type="hidden" name="workstrokesonly" value="False">
|
|
||||||
<input class="button blue small" value="Include Rest Strokes" type="Submit">
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
<span class="tooltiptext">If your data source allows, this will show or hide strokes taken during rest intervals.</span>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_4">
|
<li class="grid_4">
|
||||||
{{ the_div|safe }}
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<table>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
<input name="chartform" type="submit"
|
||||||
|
value="Update Chart">
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -2593,7 +2593,9 @@ def multiflex_data(request,userid=0,
|
|||||||
extratitle=extratitle,
|
extratitle=extratitle,
|
||||||
ploterrorbars=ploterrorbars,
|
ploterrorbars=ploterrorbars,
|
||||||
binsize=binsize,
|
binsize=binsize,
|
||||||
colorlegend=colorlegend)
|
colorlegend=colorlegend,
|
||||||
|
spmmin=spmmin,spmmax=spmmax,
|
||||||
|
workmin=workmin,workmax=workmax)
|
||||||
|
|
||||||
scripta= script.split('\n')[2:-1]
|
scripta= script.split('\n')[2:-1]
|
||||||
script = ''.join(scripta)
|
script = ''.join(scripta)
|
||||||
@@ -3085,7 +3087,8 @@ def boxplot_view_data(request,userid=0,
|
|||||||
|
|
||||||
|
|
||||||
script,div = interactive_boxchart(datadf,plotfield,
|
script,div = interactive_boxchart(datadf,plotfield,
|
||||||
extratitle=extratitle)
|
extratitle=extratitle,
|
||||||
|
spmmin=spmmin,spmmax=spmmax,workmin=workmin,workmax=workmax)
|
||||||
|
|
||||||
scripta = script.split('\n')[2:-1]
|
scripta = script.split('\n')[2:-1]
|
||||||
script = ''.join(scripta)
|
script = ''.join(scripta)
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ from django.http import (
|
|||||||
)
|
)
|
||||||
from django.contrib.auth import authenticate, login, logout
|
from django.contrib.auth import authenticate, login, logout
|
||||||
from rowers.forms import (
|
from rowers.forms import (
|
||||||
|
ForceCurveOptionsForm,
|
||||||
LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,CourseForm,
|
LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,CourseForm,
|
||||||
TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm,
|
TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm,
|
||||||
WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement,
|
WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement,
|
||||||
|
|||||||
@@ -26,15 +26,24 @@ def workout_forcecurve_view(request,id=0,workstrokesonly=False):
|
|||||||
if not promember:
|
if not promember:
|
||||||
return HttpResponseRedirect("/rowers/about/")
|
return HttpResponseRedirect("/rowers/about/")
|
||||||
|
|
||||||
if request.method == 'POST' and 'workstrokesonly' in request.POST:
|
if request.method == 'POST':
|
||||||
workstrokesonly = request.POST['workstrokesonly']
|
form = ForceCurveOptionsForm(request.POST)
|
||||||
if workstrokesonly == 'True':
|
if form.is_valid():
|
||||||
workstrokesonly = True
|
includereststrokes = form.cleaned_data['includereststrokes']
|
||||||
|
plottype = form.cleaned_data['plottype']
|
||||||
|
workstrokesonly = not includereststrokes
|
||||||
else:
|
else:
|
||||||
workstrokesonly = False
|
workstrokesonly = True
|
||||||
|
plottype = 'line'
|
||||||
|
else:
|
||||||
|
form = ForceCurveOptionsForm()
|
||||||
|
plottype = 'line'
|
||||||
|
|
||||||
script,div,js_resources,css_resources = interactive_forcecurve([row],
|
script,div,js_resources,css_resources = interactive_forcecurve(
|
||||||
workstrokesonly=workstrokesonly)
|
[row],
|
||||||
|
workstrokesonly=workstrokesonly,
|
||||||
|
plottype=plottype,
|
||||||
|
)
|
||||||
|
|
||||||
breadcrumbs = [
|
breadcrumbs = [
|
||||||
{
|
{
|
||||||
@@ -59,6 +68,7 @@ def workout_forcecurve_view(request,id=0,workstrokesonly=False):
|
|||||||
{
|
{
|
||||||
'the_script':script,
|
'the_script':script,
|
||||||
'rower':r,
|
'rower':r,
|
||||||
|
'form':form,
|
||||||
'workout':row,
|
'workout':row,
|
||||||
'breadcrumbs':breadcrumbs,
|
'breadcrumbs':breadcrumbs,
|
||||||
'active':'nav-workouts',
|
'active':'nav-workouts',
|
||||||
@@ -67,7 +77,6 @@ def workout_forcecurve_view(request,id=0,workstrokesonly=False):
|
|||||||
'css_res':css_resources,
|
'css_res':css_resources,
|
||||||
'id':id,
|
'id':id,
|
||||||
'mayedit':mayedit,
|
'mayedit':mayedit,
|
||||||
'workstrokesonly': not workstrokesonly,
|
|
||||||
'teams':get_my_teams(request.user),
|
'teams':get_my_teams(request.user),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -4834,8 +4843,8 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
|||||||
s = cd["intervalstring"]
|
s = cd["intervalstring"]
|
||||||
try:
|
try:
|
||||||
rowdata.updateinterval_string(s)
|
rowdata.updateinterval_string(s)
|
||||||
except (ParseException,err):
|
except:
|
||||||
messages.error(request,'Parsing error in column '+str(err.col))
|
messages.error(request,'Parsing error')
|
||||||
intervalstats = rowdata.allstats()
|
intervalstats = rowdata.allstats()
|
||||||
itime,idist,itype = rowdata.intervalstats_values()
|
itime,idist,itype = rowdata.intervalstats_values()
|
||||||
nrintervals = len(idist)
|
nrintervals = len(idist)
|
||||||
|
|||||||
@@ -608,7 +608,7 @@
|
|||||||
|
|
||||||
#theplot .bk-plot-layout {
|
#theplot .bk-plot-layout {
|
||||||
position: auto;
|
position: auto;
|
||||||
width: 100%;
|
width: 90%;
|
||||||
height: auto;
|
height: auto;
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user