Private
Public Access
1
0

instroke interactive as much polars as works

This commit is contained in:
2024-04-15 19:55:04 +02:00
parent 4eb07335f8
commit 0c306c7914
2 changed files with 28 additions and 471 deletions

View File

@@ -1177,440 +1177,6 @@ def interactive_agegroup_plot(df, distance=2000, duration=None,
return script, div
def interactive_cpchart(rower, thedistances, thesecs, theavpower,
theworkouts, promember=0,
wcpower=[], wcdurations=[]):
message = 0
# plot tools
if (promember == 1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
else: # pragma: no cover
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
x_axis_type = 'log'
thesecs = pd.Series(thesecs)
velo = thedistances/thesecs
p = pd.Series(500./velo)
p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
source = ColumnDataSource(
data=dict(
dist=thedistances,
duration=thesecs,
spm=0*theavpower,
tim=niceformat(
thesecs.fillna(method='ffill').apply(
lambda x: timedeltaconv(x))
),
power=theavpower,
fpace=nicepaceformat(p2),
)
)
# fitting the data to Paul
if len(thedistances) >= 2:
paulslope, paulintercept, r, p, stderr = linregress(
np.log10(thedistances), p)
else: # pragma: no cover
paulslope = 5.0/np.log10(2.0)
paulintercept = p[0]-paulslope*np.log10(thedistances[0])
fitx = pd.Series(np.arange(100)*2*max(np.log10(thedistances))/100.)
fitp = paulslope*fitx+paulintercept
fitvelo = 500./fitp
fitpower = 2.8*(fitvelo**3)
fitt = 10**fitx/fitvelo
fitp2 = fitp.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
sourcepaul = ColumnDataSource(
data=dict(
dist=10**fitx,
duration=fitt,
power=fitpower,
spm=0*fitpower,
tim=niceformat(
fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
),
fpace=nicepaceformat(fitp2),
)
)
def fitfunc(pars, x):
return pars[0] / (1+(x/pars[2])) + pars[1]/(1+(x/pars[3]))
def errfunc(pars, x, y):
return fitfunc(pars, x)-y
# p0 = [500,350,10,8000]
wcpower = pd.Series(wcpower, dtype='float')
wcdurations = pd.Series(wcdurations, dtype='float')
# fitting WC data to three parameter CP model
if len(wcdurations) >= 4:
p1wc, success = optimize.leastsq(errfunc, p0[:],
args=(wcdurations, wcpower))
else: # pragma: no cover
p1wc = None
# fitting the data to three parameter CP model
success = 0
p1 = p0
if len(thesecs) >= 4:
try:
p1, success = optimize.leastsq(
errfunc, p0[:], args=(thesecs, theavpower))
except (RuntimeError, RuntimeWarning): # pragma: no cover
factor = fitfunc(p0, thesecs.mean())/theavpower.mean()
p1 = [p0[0]/factor, p0[1]/factor, p0[2], p0[3]]
success = 0
else: # pragma: no cover
factor = fitfunc(p0, thesecs.mean())/theavpower.mean()
p1 = [p0[0]/factor, p0[1]/factor, p0[2], p0[3]]
success = 0
# Get stayer score
if success == 1: # pragma: no cover
power4min = fitfunc(p1, 240.)
power1h = fitfunc(p1, 3600.)
power10sec = fitfunc(p1, 10.)
r10sec4min = 100.*power10sec/power4min
r1h4min = 100.*power1h/power4min
combined = r1h4min-0.2*(r10sec4min-100)
dataset = pd.read_csv('static/stats/combined_set.csv')
stayerscore = int(percentileofscore(dataset['combined'], combined))
else:
stayerscore = None
fitt = pd.Series(10**(4*np.arange(100)/100.))
fitpower = fitfunc(p1, fitt)
if p1wc is not None:
fitpowerwc = 0.95*fitfunc(p1wc, fitt)
fitpowerexcellent = 0.7*fitfunc(p1wc, fitt)
fitpowergood = 0.6*fitfunc(p1wc, fitt)
fitpowerfair = 0.5*fitfunc(p1wc, fitt)
fitpoweraverage = 0.4*fitfunc(p1wc, fitt)
else: # pragma: no cover
fitpowerwc = 0*fitpower
fitpowerexcellent = 0*fitpower
fitpowergood = 0*fitpower
fitpowerfair = 0*fitpower
fitpoweraverage = 0*fitpower
message = ""
if len(fitpower[fitpower < 0]) > 0: # pragma: no cover
message = "CP model fit didn't give correct results"
fitvelo = (fitpower/2.8)**(1./3.)
fitdist = fitt*fitvelo
fitp = 500./fitvelo
fitp2 = fitp.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
sourcecomplex = ColumnDataSource(
data=dict(
dist=fitdist,
duration=fitt,
tim=niceformat(
fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
),
spm=0*fitpower,
power=fitpower,
fitpowerwc=fitpowerwc,
fitpowerexcellent=fitpowerexcellent,
fitpowergood=fitpowergood,
fitpowerfair=fitpowerfair,
fitpoweraverage=fitpoweraverage,
fpace=nicepaceformat(fitp2),
)
)
# making the plot
plot = figure(tools=TOOLS, x_axis_type=x_axis_type,
width=900,
toolbar_location="above",
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarkrange = Range1d(start=0, end=1)
watermarkalpha = 0.6
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
#plot.sizing_mode = 'scale_both'
plot.image_url([watermarkurl], 1.8*max(thesecs), watermarky,
watermarkw, watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
y_range_name="watermark",
)
plot.circle('duration', 'power', source=source, fill_color='red', size=15,
legend_label='Power')
plot.xaxis.axis_label = "Duration (seconds)"
plot.yaxis.axis_label = "Power (W)"
if stayerscore is not None: # pragma: no cover
plot.add_layout(
Label(x=100, y=100, x_units='screen', y_units='screen',
text='Stayer Score '+str(stayerscore)+'%',
background_fill_alpha=0.7,
background_fill_color='white',
text_color='black')
)
# plot.add_layout(
# Label(x=100,y=120,x_units='screen',y_units='screen',
# text='Stayer Score (6min) '+str(stayerscore2)+'%',
# background_fill_alpha=0.7,
# background_fill_color='white',
# text_color='black')
# )
cpdata = dataprep.fetchcperg(rower, theworkouts)
if cpdata.empty: # pragma: no cover
message = 'Calculations are running in the background. Please refresh this page to see updated results'
return ['', '', paulslope, paulintercept, p1, message, p1wc]
velo = cpdata['distance']/cpdata['delta']
p = 500./velo
p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
source2 = ColumnDataSource(
data=dict(
duration=cpdata['delta'],
power=cpdata['cp'],
tim=niceformat(
cpdata['delta'].fillna(method='ffill').apply(
lambda x: timedeltaconv(x))
),
dist=cpdata['distance'],
pace=nicepaceformat(p2),
)
)
plot.circle('duration', 'power', source=source2,
fill_color='blue', size=3,
legend_label='Power from segments')
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Duration ', '@tim'),
('Power (W)', '@power{int}'),
('Distance (m)', '@dist{int}'),
('Pace (/500m)', '@fpace'),
])
hover.mode = 'mouse'
plot.y_range = Range1d(0, 1.5*max(theavpower))
plot.x_range = Range1d(1, 2*max(thesecs))
plot.legend.orientation = "vertical"
plot.line('duration', 'power', source=sourcepaul,
legend_label="Paul's Law")
plot.line('duration', 'power', source=sourcecomplex, legend_label="CP Model",
color='green')
if p1wc is not None:
plot.line('duration', 'fitpowerwc', source=sourcecomplex,
legend_label="World Class",
color='Maroon', line_dash='dotted')
plot.line('duration', 'fitpowerexcellent', source=sourcecomplex,
legend_label="90% percentile",
color='Purple', line_dash='dotted')
plot.line('duration', 'fitpowergood', source=sourcecomplex,
legend_label="75% percentile",
color='Olive', line_dash='dotted')
plot.line('duration', 'fitpowerfair', source=sourcecomplex,
legend_label="50% percentile",
color='Gray', line_dash='dotted')
plot.line('duration', 'fitpoweraverage', source=sourcecomplex,
legend_label="25% percentile",
color='SkyBlue', line_dash='dotted')
script, div = components(plot)
return [script, div, paulslope, paulintercept, p1, message, p1wc]
def interactive_windchart(id=0, promember=0):
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
f1 = row.csvfilename
# create interactive plot
plot = figure(width=400, height=300)
# get user
# u = User.objects.get(id=row.user.id)
r = row.user
rr = rrower(hrmax=r.max, hrut2=r.ut2,
hrut1=r.ut1, hrat=r.at,
hrtr=r.tr, hran=r.an, ftp=r.ftp)
rowdata = rdata(f1, rower=rr)
if rowdata == 0: # pragma: no cover
return 0
try:
dist = rowdata.df.loc[:, 'cum_dist']
except KeyError:
return ['', 'No Data Found']
try: # pragma: no cover
vwind = rowdata.df.loc[:, 'vwind']
winddirection = rowdata.df.loc[:, 'winddirection']
bearing = rowdata.df.loc[:, 'bearing']
except KeyError:
rowdata.add_wind(0, 0)
rowdata.add_bearing()
vwind = rowdata.df.loc[:, 'vwind']
winddirection = rowdata.df.loc[:, 'winddirection']
bearing = rowdata.df.loc[:, 'winddirection']
rowdata.write_csv(f1, gzip=True)
dataprep.update_strokedata(id, rowdata.df)
winddirection = winddirection % 360
winddirection = (winddirection + 360) % 360
tw = tailwind(bearing, vwind, 1.0*winddirection)
source = ColumnDataSource(
data=dict(
dist=dist,
vwind=vwind,
tw=tw,
winddirection=winddirection,
)
)
# plot tools
if (promember == 1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair'
else: # pragma: no cover
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
# making the plot
plot = figure(tools=TOOLS, width=400, height=500,
# toolbar_location="below",
toolbar_sticky=False,
)
plot.line('dist', 'vwind', source=source, legend_label="Wind Speed (m/s)")
plot.line('dist', 'tw', source=source,
legend_label="Tail (+)/Head (-) Wind (m/s)", color='black')
try:
plot.title.text = row.name
except ValueError: # pragma: no cover
plot.title.text = ""
# plot.title.text_font_size="1.0em"
plot.title.text_font = "1.0em"
plot.xaxis.axis_label = "Distance (m)"
plot.yaxis.axis_label = "Wind Speed (m/s)"
plot.y_range = Range1d(-7, 7)
#plot.sizing_mode = 'stretch_both'
plot.extra_y_ranges = {"winddirection": Range1d(start=0, end=360)}
plot.line('dist', 'winddirection', source=source,
legend_label='Wind Direction', color="red",
y_range_name="winddirection")
plot.add_layout(LinearAxis(y_range_name="winddirection",
axis_label="Wind Direction (degree)"), 'right')
script, div = components(plot)
return [script, div]
def interactive_streamchart(id=0, promember=0):
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
f1 = row.csvfilename
# create interactive plot
plot = figure(width=400,
)
# get user
# u = User.objects.get(id=row.user.id)
r = row.user
rr = rrower(hrmax=r.max, hrut2=r.ut2,
hrut1=r.ut1, hrat=r.at,
hrtr=r.tr, hran=r.an, ftp=r.ftp)
rowdata = rdata(f1, rower=rr)
if rowdata == 0: # pragma: no cover
return "", "No Valid Data Available"
try:
dist = rowdata.df.loc[:, 'cum_dist']
except KeyError:
return ['', 'No Data found']
try:
vstream = rowdata.df.loc[:, 'vstream']
except KeyError:
rowdata.add_stream(0)
vstream = rowdata.df.loc[:, 'vstream']
rowdata.write_csv(f1, gzip=True)
dataprep.update_strokedata(id, rowdata.df)
# plot tools
if (promember == 1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair'
else: # pragma: no cover
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
# making the plot
plot = figure(tools=TOOLS, width=400, height=500,
# toolbar_location="below",
toolbar_sticky=False,
)
plot.line(dist, vstream, legend_label="River Stream Velocity (m/s)")
try:
plot.title.text = row.name
except ValueError: # pragma: no cover
plot.title.text = ""
plot.title.text_font_size = "1.0em"
plot.xaxis.axis_label = "Distance (m)"
plot.yaxis.axis_label = "River Current (m/s)"
plot.y_range = Range1d(-2, 2)
#plot.sizing_mode = 'stretch_both'
script, div = components(plot)
return [script, div]
def forcecurve_multi_interactive_chart(selected): # pragma: no cover
ids = [analysis.id for analysis in selected]
workoutids = [analysis.workout.id for analysis in selected]
@@ -1678,12 +1244,13 @@ def instroke_multi_interactive_chart(selected, *args, **kwargs): # pragma: no co
maximum_values[analysis.metric] = mean_vals.max()
xvals = np.arange(len(mean_vals))
data2 = pd.DataFrame({
'x': pd.Series(xvals),
'y': pd.Series(mean_vals),
data2 = pl.DataFrame({
'x': pl.Series(xvals),
'y': pl.Series(mean_vals),
})
data2['id'] = cntr
data2 = data2.with_columns((pl.lit(cntr)).alias("id"))
df2.append(data2)
legendlabel = '{name} - {metric} - {workout}'.format(
@@ -1704,9 +1271,9 @@ def instroke_multi_interactive_chart(selected, *args, **kwargs): # pragma: no co
ytitle = 'Scaled'
cntr = cntr+1
df2 = pd.concat(df2, axis=0)
df2 = pl.concat(df2)
data_dict = df2.to_dict("records")
data_dict = df2.to_dicts()
chart_data = {
'title': '',
@@ -1725,24 +1292,25 @@ def instroke_interactive_chart(df,metric, workout, spm_min, spm_max,
individual_curves,
name='',notes=''): # pragma: no cover
df_pos = (df+abs(df))/2.
df_min = -(-df+abs(-df))/2.
if df.empty:
return "", "No data in selection"
mean_vals = df.median().replace(0, np.nan)
q75 = df_pos.quantile(q=0.75).replace(0,np.nan)
q25 = df_pos.quantile(q=0.25).replace(0,np.nan)
q75min = df_min.quantile(q=0.75).replace(0,np.nan)
q25min = df_min.quantile(q=0.25).replace(0,np.nan)
df_pos = (df+abs(df))/2.
df_min = -(-df+abs(-df))/2.
mean_vals = df.median().replace(0, np.nan)
q75 = df_pos.quantile(q = 0.75).replace(0, np.nan)
q25 = df_pos.quantile(q=0.25).replace(0, np.nan)
q75min = df_min.quantile(q=0.75).replace(0, np.nan)
q25min = df_min.quantile(q=0.25).replace(0, np.nan)
mean_vals = mean_vals.interpolate()
xvals = np.arange(len(mean_vals))
df_plot = pd.DataFrame({
df_plot = pl.DataFrame({
'x':xvals,
'median':mean_vals,
'high':q75,
@@ -1751,14 +1319,17 @@ def instroke_interactive_chart(df,metric, workout, spm_min, spm_max,
'low 2': q25,
})
df_plot['high'].update(df_plot.pop('high 2'))
df_plot['low'].update(df_plot.pop('low 2'))
try:
df_plot.interpolate(axis=1,inplace=True)
except TypeError:
pass
df_plot = df_plot.with_columns(
pl.coalesce(["high", "high 2"]).alias("high")
)
df_plot = df_plot.with_columns(
pl.coalesce("low", "low 2").alias("low")
)
df_plot = df_plot.drop(["high 2", "low 2"])
df_plot = df_plot.drop_nulls()
if metric == 'boat accelerator curve':
ytitle = "Boat acceleration (m/s^2)"
elif metric == 'instroke boat speed':
@@ -1771,7 +1342,7 @@ def instroke_interactive_chart(df,metric, workout, spm_min, spm_max,
lines_dict = df.to_dict("records")
data_dict = df_plot.to_dict("records")
data_dict = df_plot.to_dicts()
chart_data = {
'lines': lines_dict,
@@ -1790,7 +1361,6 @@ def instroke_interactive_chart(df,metric, workout, spm_min, spm_max,
'analysis_name': name,
}
script, div = get_chart("/instroke", chart_data, debug=False)
return script, div

View File

@@ -1523,19 +1523,6 @@ def otwcp_toadmin_view(request, theuser=0,
return response
def agegroupcpview(request, age, normalize=0, userid=0):
script, div = interactive_agegroupcpchart(age, normalized=normalize)
response = render(request, 'agegroupcp.html',
{
'active': 'nav-analysis',
'interactiveplot': script,
'the_div': div,
}
)
return response
def agegrouprecordview(request, sex='male', weightcategory='hwt',
distance=2000, duration=None):