Private
Public Access
1
0
This commit is contained in:
Sander Roosendaal
2019-04-04 22:05:10 +02:00
parent 0ff24d8aee
commit c3fda7e206
7 changed files with 94 additions and 24 deletions

View File

@@ -25,6 +25,12 @@ import datetime
from django.forms import formset_factory from django.forms import formset_factory
from rowers.utils import landingpages from rowers.utils import landingpages
from rowers.metrics import axes from rowers.metrics import axes
from rowers.metrics import axlabels
formaxlabels = axlabels.copy()
formaxlabels.pop('None')
parchoices = list(sorted(formaxlabels.items(), key = lambda x:x[1]))
class FlexibleDecimalField(forms.DecimalField): class FlexibleDecimalField(forms.DecimalField):
@@ -710,6 +716,12 @@ class DataFrameColumnsForm(forms.Form):
cols = forms.MultipleChoiceField(choices=colchoices, cols = forms.MultipleChoiceField(choices=colchoices,
label='Table Columns') label='Table Columns')
class HistoForm(forms.Form):
includereststrokes = forms.BooleanField(initial=False,label='Include Rest Strokes',required=False)
histoparam = forms.ChoiceField(choices=parchoices,initial='power',
label='Metric')
# form to select modality and boat type for trend flex # form to select modality and boat type for trend flex
class TrendFlexModalForm(forms.Form): class TrendFlexModalForm(forms.Form):
modality = forms.ChoiceField(choices=workouttypes, modality = forms.ChoiceField(choices=workouttypes,
@@ -797,12 +809,6 @@ class PlannedSessionMultipleCloneForm(forms.Form):
label='Planned Sessions' label='Planned Sessions'
) )
from rowers.metrics import axlabels
formaxlabels = axlabels.copy()
formaxlabels.pop('None')
parchoices = list(sorted(formaxlabels.items(), key = lambda x:x[1]))
class BoxPlotChoiceForm(forms.Form): class BoxPlotChoiceForm(forms.Form):
yparam = forms.ChoiceField(choices=parchoices,initial='spm', yparam = forms.ChoiceField(choices=parchoices,initial='spm',

View File

@@ -1214,12 +1214,13 @@ def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower',startdate=None,
return [script,div] return [script,div]
def interactive_histoall(theworkouts): def interactive_histoall(theworkouts,histoparam,includereststrokes):
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]
rowdata = dataprep.getsmallrowdata_db(['power'],ids=ids,doclean=True) workstrokesonly = not includereststrokes
rowdata = dataprep.getsmallrowdata_db([histoparam],ids=ids,doclean=True,workstrokesonly=workstrokesonly)
rowdata.dropna(axis=0,how='any',inplace=True) rowdata.dropna(axis=0,how='any',inplace=True)
@@ -1227,16 +1228,16 @@ def interactive_histoall(theworkouts):
return "","No Valid Data Available","","" return "","No Valid Data Available","",""
try: try:
histopwr = rowdata['power'].values histopwr = rowdata[histoparam].values
except KeyError: except KeyError:
return "","No power data","","" return "","No data","",""
if len(histopwr) == 0: if len(histopwr) == 0:
return "","No valid data available","","" return "","No valid data available","",""
# throw out nans # throw out nans
histopwr = histopwr[~np.isinf(histopwr)] histopwr = histopwr[~np.isinf(histopwr)]
histopwr = histopwr[histopwr > 25] histopwr = histopwr[histopwr > yaxminima[histoparam]]
histopwr = histopwr[histopwr < 1000] histopwr = histopwr[histopwr < yaxmaxima[histoparam]]
plot = Figure(tools=TOOLS,plot_width=900, plot = Figure(tools=TOOLS,plot_width=900,
toolbar_sticky=False, toolbar_sticky=False,
@@ -1289,7 +1290,7 @@ def interactive_histoall(theworkouts):
# plot.quad(top='hist_norm',bottom=0,left=edges[:-1],right=edges[1:]) # plot.quad(top='hist_norm',bottom=0,left=edges[:-1],right=edges[1:])
plot.quad(top='hist_norm',bottom=0,left='left',right='right',source=source) plot.quad(top='hist_norm',bottom=0,left='left',right='right',source=source)
plot.xaxis.axis_label = "Power (W)" plot.xaxis.axis_label = axlabels[histoparam]
plot.yaxis.axis_label = "% of strokes" plot.yaxis.axis_label = "% of strokes"
plot.y_range = Range1d(0,1.05*max(hist_norm)) plot.y_range = Range1d(0,1.05*max(hist_norm))
@@ -1297,7 +1298,7 @@ def interactive_histoall(theworkouts):
hover = plot.select(dict(type=HoverTool)) hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([ hover.tooltips = OrderedDict([
('Power(W)','@left{int}'), (axlabels[histoparam],'@left{int}'),
('% of strokes','@hist_norm'), ('% of strokes','@hist_norm'),
('Cumulative %','@histsum{int}'), ('Cumulative %','@histsum{int}'),
]) ])
@@ -1311,12 +1312,36 @@ def interactive_histoall(theworkouts):
axis_label="Cumulative % of strokes"),'right') axis_label="Cumulative % of strokes"),'right')
plot.sizing_mode = 'scale_width' plot.sizing_mode = 'scale_width'
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',
)
plot.add_layout(annolabel)
callback = CustomJS(args = dict(
annolabel=annolabel,
), code="""
var annotation = annotation.value
annolabel.text = annotation
""")
annotation = TextInput(title="Type your plot notes here", value="",
callback=callback)
callback.args["annotation"] = annotation
layout = layoutcolumn([annotation,plot])
try: try:
script, div = components(plot) script, div = components(layout)
except ValueError: except ValueError:
script = '' script = ''
div = '' div = ''
return [script,div] return [script,div]
def course_map(course): def course_map(course):
@@ -3889,7 +3914,7 @@ def interactive_flex_chart2(id=0,promember=0,
""") """)
annotation = TextInput(title="Type your plot notes here", value="", annotation = TextInput(title="Type your plot notes here", value="",
callback=callback) callback=callback)
callback.args["annotation"] = annotation 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,

View File

@@ -40,14 +40,14 @@
</p> </p>
</li> </li>
<li class="rounder"> <li class="rounder">
<h2>Power Histogram</h2> <h2>Histogram</h2>
<a href="/rowers/histo/"> <a href="/rowers/histo/">
<div class="vignet"> <div class="vignet">
<img src="/static/img/histogram.png" alt="Power Histogram"> <img src="/static/img/histogram.png" alt="Power Histogram">
</div> </div>
</a> </a>
<p> <p>
Plot a power histogram of all your strokes over a date range. Plot a histogram chart of one metric for all your strokes over a date range.
</p> </p>
</li> </li>
<li class="rounder"> <li class="rounder">

View File

@@ -75,6 +75,8 @@
</div> </div>
<h1>Histogram View</h1>
<ul class="main-content"> <ul class="main-content">
<li class="grid_4"> <li class="grid_4">
@@ -100,6 +102,11 @@
{{ form.as_table }} {{ form.as_table }}
</table> </table>
</li> </li>
<li>
<table>
{{ histoform.as_table }}
</table>
</li>
<li> <li>
{% csrf_token %} {% csrf_token %}
<input class="button green small" value="Submit" type="Submit"> <input class="button green small" value="Submit" type="Submit">

View File

@@ -62,9 +62,9 @@
<i class="fal fa-table fa-fw"></i>&nbsp;Statistics <i class="fal fa-table fa-fw"></i>&nbsp;Statistics
</a> </a>
</li> </li>
<li id="stats-histopower"> <li id="stats-histo">
<a href="/rowers/histo/"> <a href="/rowers/histo/">
<i class="fas fa-chart-bar"></i>&nbsp;Power Histogram <i class="fas fa-chart-bar"></i>&nbsp;Histogram
</a> </a>
</li> </li>
</ul> </ul>

View File

@@ -20,11 +20,17 @@ def histo(request,theuser=0,
'workouttypes':[i[0] for i in mytypes.workouttypes], 'workouttypes':[i[0] for i in mytypes.workouttypes],
'waterboattype':mytypes.waterboattype, 'waterboattype':mytypes.waterboattype,
'rankingonly': False, 'rankingonly': False,
'histoparam':'power'
}): }):
r = getrequestrower(request,userid=theuser) r = getrequestrower(request,userid=theuser)
theuser = r.user theuser = r.user
if 'histoparam' in request.session:
histoparam = request.session['histoparam']
else:
histoparam = 'power'
if 'waterboattype' in request.session: if 'waterboattype' in request.session:
waterboattype = request.session['waterboattype'] waterboattype = request.session['waterboattype']
else: else:
@@ -81,6 +87,7 @@ def histo(request,theuser=0,
if request.method == 'POST': if request.method == 'POST':
form = DateRangeForm(request.POST) form = DateRangeForm(request.POST)
modalityform = TrendFlexModalForm(request.POST) modalityform = TrendFlexModalForm(request.POST)
histoform = HistoForm(request.POST)
if form.is_valid(): if form.is_valid():
startdate = form.cleaned_data['startdate'] startdate = form.cleaned_data['startdate']
enddate = form.cleaned_data['enddate'] enddate = form.cleaned_data['enddate']
@@ -110,6 +117,11 @@ def histo(request,theuser=0,
'startdate': startdate, 'startdate': startdate,
'enddate': enddate, 'enddate': enddate,
}) })
if histoform.is_valid():
includereststrokes = histoform.cleaned_data['includereststrokes']
histoparam = histoform.cleaned_data['histoparam']
request.session['histoparam'] = histoparam
request.session['includereststrokes'] = includereststrokes
else: else:
form = DateRangeForm(initial={ form = DateRangeForm(initial={
'startdate': startdate, 'startdate': startdate,
@@ -125,6 +137,10 @@ def histo(request,theuser=0,
'rankingonly':rankingonly, 'rankingonly':rankingonly,
} }
) )
histoform = HistoForm(initial={
'includereststrokes':False,
'histoparam':histoparam
})
negtypes = [] negtypes = []
for b in mytypes.boattypes: for b in mytypes.boattypes:
@@ -149,6 +165,7 @@ def histo(request,theuser=0,
'enddatestring':enddatestring, 'enddatestring':enddatestring,
'rankingonly':rankingonly, 'rankingonly':rankingonly,
'includereststrokes':includereststrokes, 'includereststrokes':includereststrokes,
'histoparam':histoparam,
} }
request.session['options'] = options request.session['options'] = options
@@ -163,9 +180,21 @@ def histo(request,theuser=0,
request.session['options'] = options request.session['options'] = options
breadcrumbs = [
{
'url':'/rowers/analysis',
'name':'Analysis'
},
{
'url':reverse('histo'),
'name': 'Histogram'
}
]
return render(request, 'histo.html', return render(request, 'histo.html',
{'interactiveplot':script, {'interactiveplot':script,
'the_div':div, 'the_div':div,
'breadcrumbs':breadcrumbs,
'id':theuser, 'id':theuser,
'active':'nav-analysis', 'active':'nav-analysis',
'theuser':theuser, 'theuser':theuser,
@@ -174,6 +203,7 @@ def histo(request,theuser=0,
'enddate':enddate, 'enddate':enddate,
'form':form, 'form':form,
'optionsform':modalityform, 'optionsform':modalityform,
'histoform':histoform,
'teams':get_my_teams(request.user), 'teams':get_my_teams(request.user),
}) })
@@ -295,6 +325,7 @@ def histo_data(
'enddatestring':timezone.now().strftime("%Y-%m-%d"), 'enddatestring':timezone.now().strftime("%Y-%m-%d"),
'startdatestring':(timezone.now()-datetime.timedelta(days=30)).strftime("%Y-%m-%d"), 'startdatestring':(timezone.now()-datetime.timedelta(days=30)).strftime("%Y-%m-%d"),
'deltadays':-1, 'deltadays':-1,
'histoparam':'power',
}): }):
def_options = options def_options = options
@@ -311,6 +342,7 @@ def histo_data(
theuser = keyvalue_get_default('theuser',options,def_options) theuser = keyvalue_get_default('theuser',options,def_options)
startdatestring = keyvalue_get_default('startdatestring',options,def_options) startdatestring = keyvalue_get_default('startdatestring',options,def_options)
enddatestring = keyvalue_get_default('enddatestring',options,def_options) enddatestring = keyvalue_get_default('enddatestring',options,def_options)
histoparam = keyvalue_get_default('histoparam',options,def_options)
if modality == 'all': if modality == 'all':
modalities = [m[0] for m in mytypes.workouttypes] modalities = [m[0] for m in mytypes.workouttypes]
@@ -358,7 +390,7 @@ def histo_data(
rankingpiece__in=rankingpiece) rankingpiece__in=rankingpiece)
if allworkouts: if allworkouts:
res = interactive_histoall(allworkouts) res = interactive_histoall(allworkouts,histoparam,includereststrokes)
script = res[0] script = res[0]
div = res[1] div = res[1]
else: else:

View File

@@ -48,7 +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, ForceCurveOptionsForm,HistoForm,
LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,CourseForm, LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,CourseForm,
TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm, TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm,
WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement, WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement,