force curve with lines
This commit is contained in:
@@ -722,7 +722,8 @@ class TrendFlexModalForm(forms.Form):
|
|||||||
label='Only Ranking Pieces',
|
label='Only Ranking Pieces',
|
||||||
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,10 +1182,21 @@ 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 = list(
|
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']
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -374,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]
|
||||||
@@ -642,12 +643,20 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
rowdata
|
rowdata
|
||||||
)
|
)
|
||||||
|
|
||||||
sourcepoints = ColumnDataSource(
|
if plottype == 'scatter':
|
||||||
data = dict(
|
sourcepoints = ColumnDataSource(
|
||||||
peakforceangle = rowdata['peakforceangle'],
|
data = dict(
|
||||||
peakforce = rowdata['peakforce']
|
peakforceangle = rowdata['peakforceangle'],
|
||||||
|
peakforce = rowdata['peakforce']
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
sourcepoints = ColumnDataSource(
|
||||||
|
data = dict(
|
||||||
|
peakforceangle = [],
|
||||||
|
peakforce = []
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
sourcerange = ColumnDataSource(
|
sourcerange = ColumnDataSource(
|
||||||
data = dict(
|
data = dict(
|
||||||
@@ -697,6 +706,50 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
plot.circle('xslip','yslip',source=sourceslipwash,color="red")
|
plot.circle('xslip','yslip',source=sourceslipwash,color="red")
|
||||||
|
|
||||||
plot.circle('peakforceangle','peakforce',source=sourcepoints,color='black',alpha=0.1)
|
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)
|
||||||
@@ -801,11 +854,20 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
peakforceanglelabel=peakforceanglelabel,
|
peakforceanglelabel=peakforceanglelabel,
|
||||||
annolabel=annolabel,
|
annolabel=annolabel,
|
||||||
sliderlabel=sliderlabel,
|
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 dataslipwash = sourceslipwash.data
|
||||||
var datapoints = sourcepoints.data
|
var datapoints = sourcepoints.data
|
||||||
|
var multilines = sourcemultiline.data
|
||||||
|
var multilines2 = sourcemultiline2.data
|
||||||
|
var plottype = plottype
|
||||||
|
|
||||||
|
var multilinesx = multilines['xs']
|
||||||
|
var multilinesy = multilines['ys']
|
||||||
|
|
||||||
var x = data['x']
|
var x = data['x']
|
||||||
var y = data['y']
|
var y = data['y']
|
||||||
@@ -826,6 +888,9 @@ 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 annotation = annotation.value
|
||||||
var minspm = minspm.value
|
var minspm = minspm.value
|
||||||
var maxspm = maxspm.value
|
var maxspm = maxspm.value
|
||||||
@@ -849,13 +914,21 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
|
|
||||||
datapoints['peakforceangle'] = []
|
datapoints['peakforceangle'] = []
|
||||||
datapoints['peakforce'] = []
|
datapoints['peakforce'] = []
|
||||||
|
multilines['xs'] = []
|
||||||
|
multilines['ys'] = []
|
||||||
|
|
||||||
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) {
|
||||||
datapoints['peakforceangle'].push(peakforceangle[i])
|
if (plottype=='scatter') {
|
||||||
datapoints['peakforce'].push(peakforce[i])
|
datapoints['peakforceangle'].push(peakforceangle[i])
|
||||||
|
datapoints['peakforce'].push(peakforce[i])
|
||||||
|
}
|
||||||
|
if (plottype=='line') {
|
||||||
|
multilines['xs'].push(multilinesx[i])
|
||||||
|
multilines['ys'].push(multilinesy[i])
|
||||||
|
}
|
||||||
catchav += c[i]
|
catchav += c[i]
|
||||||
finishav += finish[i]
|
finishav += finish[i]
|
||||||
slipav += slip[i]
|
slipav += slip[i]
|
||||||
@@ -897,6 +970,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
source.change.emit();
|
source.change.emit();
|
||||||
sourceslipwash.change.emit()
|
sourceslipwash.change.emit()
|
||||||
sourcepoints.change.emit();
|
sourcepoints.change.emit();
|
||||||
|
sourcemultiline.change.emit();
|
||||||
""")
|
""")
|
||||||
|
|
||||||
annotation = TextInput(title="Type your plot notes here", value="",
|
annotation = TextInput(title="Type your plot notes here", value="",
|
||||||
|
|||||||
@@ -22,27 +22,24 @@
|
|||||||
<h1>Empower Force Curve</h1>
|
<h1>Empower Force Curve</h1>
|
||||||
|
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
<li class="grid_4">
|
|
||||||
{% if user.is_authenticated and mayedit %}
|
|
||||||
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
{% 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 class="grid_4">
|
<li class="grid_4">
|
||||||
<div id="theplot" class="flexplot">
|
<div id="theplot" class="flexplot">
|
||||||
{{ the_div|safe }}
|
{{ the_div|safe }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
<li class="grid_4">
|
||||||
|
<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>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 = [
|
||||||
{
|
{
|
||||||
@@ -53,12 +62,13 @@ def workout_forcecurve_view(request,id=0,workstrokesonly=False):
|
|||||||
]
|
]
|
||||||
|
|
||||||
r = getrower(request.user)
|
r = getrower(request.user)
|
||||||
|
|
||||||
return render(request,
|
return render(request,
|
||||||
'forcecurve_single.html',
|
'forcecurve_single.html',
|
||||||
{
|
{
|
||||||
'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),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user