Private
Public Access
1
0

zones chart

This commit is contained in:
2024-04-17 12:30:48 +02:00
parent eec03965c8
commit b008773a7e
4 changed files with 228 additions and 35 deletions

View File

@@ -74,27 +74,6 @@ class ResampleForm(forms.Form):
class TrainingZonesForm(forms.Form):
zoneschoices = (
('power', 'Power Zones'),
('hr', 'Heart Rate Zones')
)
datechoices = (
('month', 'By Month'),
('week', 'By Week'),
)
yaxischoices = (
('time', 'Time'),
('percentage', 'Percentage of Time')
)
zones = forms.ChoiceField(
initial='hr', label='Training Zones', choices=zoneschoices)
dates = forms.ChoiceField(
initial='week', label='Date Aggregation', choices=datechoices)
yaxis = forms.ChoiceField(initial='percentage',
label='Y axis', choices=yaxischoices)
startdate = forms.DateField(
initial=timezone.now()-datetime.timedelta(days=42),
widget=AdminDateWidget(), # format='%Y-%m-%d'),

View File

@@ -2185,6 +2185,194 @@ def interactive_multiple_compare_chart(ids, xparam, yparam, plottype='line',
script, div = get_chart("/compare", chart_data)
return script, div, message, errormessage
def get_zones_report_pl(rower, startdate, enddate, trainingzones='hr', date_agg='week',
yaxis='time'):
data = []
enddate = enddate + datetime.timedelta(days=1)
workouts = Workout.objects.filter(
user=rower,
startdatetime__gte=startdate,
startdatetime__lte=enddate,
duplicate=False,
).order_by("-startdatetime")
ids = [w.id for w in workouts]
columns = ['workoutid', 'hr', 'power', 'time']
df = dataprep.getsmallrowdata_pl(columns, ids=ids)
df = df.with_columns((pl.col("time").diff().clip(0, 20*1.e3)).alias("deltat")).lazy()
hrzones = rower.hrzones
powerzones = rower.powerzones
for w in workouts:
iswater = w.workouttype in mytypes.otwtypes
pw_ut2 = rower.pw_ut2
pw_ut1 = rower.pw_ut1
pw_at = rower.pw_at
pw_tr = rower.pw_tr
pw_an = rower.pw_an
if iswater:
pw_ut2 = pw_ut2*rower.otwslack/100.
pw_ut1 = pw_ut1*rower.otwslack/100.
pw_at = pw_at*rower.otwslack/100.
pw_tr = pw_tr*rower.otwslack/100.
pw_an = pw_an*rower.otwslack/100.
# 1
time_ut2 = df.filter(
pl.col("workoutid") == w.id,
pl.col("hr") < rower.ut2,
)
time_pw_ut2 = df.filter(
pl.col("workoutid") == w.id,
pl.col("power") < pw_ut2,
)
# 2
time_ut1 = df.filter(
pl.col("workoutid") == w.id,
pl.col("hr") >= rower.ut2,
pl.col("hr") < rower.ut1,
)
time_pw_ut1 = df.filter(
pl.col("workoutid") == w.id,
pl.col("power") >= pw_ut2,
pl.col("power") < pw_ut1,
)
#3
time_at = df.filter(
pl.col("workoutid") == w.id,
pl.col("hr") >= rower.ut1,
pl.col("hr") < rower.at,
)
time_pw_at = df.filter(
pl.col("workoutid") == w.id,
pl.col("power") >= pw_ut1,
pl.col("power") < pw_at,
)
#4
time_tr = df.filter(
pl.col("workoutid") == w.id,
pl.col("hr") >= rower.at,
pl.col("hr") < rower.tr,
)
time_pw_tr = df.filter(
pl.col("workoutid") == w.id,
pl.col("power") >= pw_at,
pl.col("power") < pw_tr,
)
#5
time_an = df.filter(
pl.col("workoutid") == w.id,
pl.col("hr") >= rower.tr,
pl.col("hr") < rower.an,
)
time_pw_an = df.filter(
pl.col("workoutid") == w.id,
pl.col("power") >= pw_tr,
pl.col("power") < pw_an,
)
time_max = df.filter(
pl.col("workoutid") == w.id,
pl.col("hr") >= rower.an,
)
time_pw_max = df.filter(
pl.col("workoutid") == w.id,
pl.col("power") >= pw_an,
)
time_in_ut2 = time_ut2.collect()['deltat'].sum()/(60*1.e3)
time_in_ut2_pw = time_pw_ut2.collect()['deltat'].sum()/(60*1.e3)
time_in_ut1 = time_ut1.collect()['deltat'].sum()/(60*1.e3)
time_in_ut1_pw = time_pw_ut1.collect()['deltat'].sum()/(60*1.e3)
time_in_at = time_at.collect()['deltat'].sum()/(60*1.e3)
time_in_at_pw = time_pw_at.collect()['deltat'].sum()/(60*1.e3)
time_in_tr = time_tr.collect()['deltat'].sum()/(60*1.e3)
time_in_tr_pw = time_pw_tr.collect()['deltat'].sum()/(60*1.e3)
time_in_an = time_an.collect()['deltat'].sum()/(60*1.e3)
time_in_an_pw = time_pw_an.collect()['deltat'].sum()/(60*1.e3)
time_in_max = time_max.collect()['deltat'].sum()/(60*1.e3)
time_in_max_pw = time_pw_max.collect()['deltat'].sum()/(60*1.e3)
data.append({
'date': w.date.strftime("%Y-%m-%d"),
'id': w.id,
'zonename': '<{ut2}'.format(ut2=hrzones[1]),
'time_in_zone': time_in_ut2,
'pw_zonename': '<{ut2}'.format(ut2=powerzones[1]),
'pw_time_in_zone': time_in_ut2_pw,
})
data.append({
'date': w.date.strftime("%Y-%m-%d"),
'id': w.id,
'zonename': hrzones[1],
'time_in_zone': time_in_ut1,
'pw_zonename': powerzones[1],
'pw_time_in_zone': time_in_ut1_pw,
})
data.append({
'date': w.date.strftime("%Y-%m-%d"),
'id': w.id,
'zonename': hrzones[2],
'time_in_zone': time_in_at,
'pw_zonename': powerzones[2],
'pw_time_in_zone': time_in_at_pw,
})
data.append({
'date': w.date.strftime("%Y-%m-%d"),
'id': w.id,
'zonename': hrzones[3],
'time_in_zone': time_in_tr,
'pw_zonename': powerzones[3],
'pw_time_in_zone': time_in_tr_pw,
})
data.append({
'date': w.date.strftime("%Y-%m-%d"),
'id': w.id,
'zonename': hrzones[4],
'time_in_zone': time_in_an,
'pw_zonename': powerzones[4],
'pw_time_in_zone': time_in_an_pw,
})
data.append({
'date': w.date.strftime("%Y-%m-%d"),
'id': w.id,
'zonename': hrzones[5],
'time_in_zone': time_in_max,
'pw_zonename': powerzones[5],
'pw_time_in_zone': time_in_max_pw,
})
chart_data = {
'data': data,
'hrzones': hrzones,
'powerzones': powerzones,
}
return chart_data
def get_zones_report(rower, startdate, enddate, trainingzones='hr', date_agg='week',
yaxis='time'):
@@ -2402,6 +2590,36 @@ def get_zones_report(rower, startdate, enddate, trainingzones='hr', date_agg='we
return data
def interactive_zoneschart2(rower, data, startdate, enddate, trainingzones='hr', date_agg='week',
yaxis='time'):
if startdate >= enddate: # pragma: no cover
st = startdate
startdate = enddate
enddate = st
hrzones = data['hrzones']
powerzones = data['powerzones']
data['yaxis'] = yaxis
data['title'] = 'Activity {d1} to {d2} for {r}'.format(
d1=startdate.strftime("%Y-%m-%d"),
d2=enddate.strftime("%Y-%m-%d"),
r=str(rower),
)
data['stackBy'] = 'time_in_zone'
data['colorBy'] = 'zonename'
if trainingzones == 'power':
data['stackBy'] = 'pw_time_in_zone'
data['colorBy'] = 'pw_zonename'
data['doReduce'] = True
data['datebin'] = date_agg
data['colors'] = ['green', 'lime', 'yellow', 'blue', 'purple', 'red']
script, div = get_chart("/zones", data, debug=False)
return script, div
def interactive_zoneschart(rower, data, startdate, enddate, trainingzones='hr', date_agg='week',
yaxis='time'):

View File

@@ -11,17 +11,15 @@
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
<div id="id_js_res">
<script src="https://d3js.org/d3.v7.min.js"></script>
</div>
<h1>Training Zones</h1>
<div id="id_script">
</div>
<ul class="main-content">
<li class="grid_4">
<div id="id_chart">

View File

@@ -1144,9 +1144,6 @@ def trainingzones_view(request, userid=0):
form = TrainingZonesForm({
'startdate': startdate,
'enddate': enddate,
'zones': zones,
'dates': date_agg,
'yaxis': yaxis,
})
if request.method == 'POST': # pragma: no cover
@@ -1155,9 +1152,6 @@ def trainingzones_view(request, userid=0):
if form.is_valid():
startdate = form.cleaned_data['startdate']
enddate = form.cleaned_data['enddate']
zones = form.cleaned_data['zones']
date_agg = form.cleaned_data['dates']
yaxis = form.cleaned_data['yaxis']
if date_agg == 'week':
startdate = startdate - datetime.timedelta(days=startdate.weekday())
@@ -1229,12 +1223,16 @@ def trainingzones_view_data(request, userid=0):
request.GET.get('enddate'), "%Y-%m-%d")
enddate = arrow.get(enddate).datetime
data = get_zones_report(r, startdate, enddate,
trainingzones=zones, date_agg=date_agg, yaxis=yaxis)
if (enddate-startdate).days > 200:
date_agg = "month"
script, div = interactive_zoneschart(
data = get_zones_report_pl(r, startdate, enddate,
trainingzones=zones, date_agg=date_agg, yaxis=yaxis)
script, div = interactive_zoneschart2(
r, data, startdate, enddate, trainingzones=zones, date_agg=date_agg, yaxis=yaxis)
return JSONResponse({
'script': script,
'div': div,