zones chart
This commit is contained in:
@@ -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'),
|
||||
|
||||
@@ -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'):
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user