close #359
This commit is contained in:
@@ -106,6 +106,7 @@ from utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Form to change Workflow page layout
|
# Form to change Workflow page layout
|
||||||
class WorkFlowLeftPanelForm(forms.Form):
|
class WorkFlowLeftPanelForm(forms.Form):
|
||||||
panels = defaultleft
|
panels = defaultleft
|
||||||
@@ -533,6 +534,20 @@ ww = list(workouttypes)
|
|||||||
ww.append(tuple(('all','All')))
|
ww.append(tuple(('all','All')))
|
||||||
workouttypes = tuple(ww)
|
workouttypes = tuple(ww)
|
||||||
|
|
||||||
|
class DataFrameColumnsForm(forms.Form):
|
||||||
|
cols = ['ftime','cumdist','fpace','spm',
|
||||||
|
'hr','power','driveenergy','drivelength','averageforce',
|
||||||
|
'peakforce','distance','drivespeed','workoutstate',
|
||||||
|
'catch','finish','peakforceangle','wash','slip','rhythm',
|
||||||
|
'effectiveangle','totalangle','distanceperstroke','velo']
|
||||||
|
|
||||||
|
colchoices = [
|
||||||
|
(c, c) for c in cols
|
||||||
|
]
|
||||||
|
|
||||||
|
cols = forms.MultipleChoiceField(choices=colchoices,
|
||||||
|
label='Table Columns')
|
||||||
|
|
||||||
# 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,
|
||||||
|
|||||||
@@ -259,6 +259,10 @@
|
|||||||
<i class="fas fa-cut fa-fw"></i> Split Workout
|
<i class="fas fa-cut fa-fw"></i> Split Workout
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li id="data-view">
|
||||||
|
<a href="/rowers/workout/{{ workout.id }}/data">
|
||||||
|
<i class="fal fa-table fa-fw"></i> Explore Raw Data
|
||||||
|
</a>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="has-children" id="advanced">
|
<li class="has-children" id="advanced">
|
||||||
|
|||||||
29
rowers/templates/workout_data.html
Normal file
29
rowers/templates/workout_data.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{% extends "newbase.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
|
||||||
|
{% block title %}Workout Data{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<h1>Workout Data for {{ workout.name }}</h1>
|
||||||
|
|
||||||
|
<ul class="main-content">
|
||||||
|
<li class="grid_4">
|
||||||
|
<p>
|
||||||
|
<form method="post" enctype="multipart/form-data">
|
||||||
|
{{ form.as_table }}
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li class="grid_4">
|
||||||
|
{{ htmltable|safe }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include 'menu_workout.html' %}
|
||||||
|
{% endblock %}
|
||||||
@@ -246,6 +246,7 @@ urlpatterns = [
|
|||||||
url(r'^workout/(?P<id>\d+)/instroke/(?P<metric>\w+.*)$',views.instroke_chart),
|
url(r'^workout/(?P<id>\d+)/instroke/(?P<metric>\w+.*)$',views.instroke_chart),
|
||||||
url(r'^workout/(?P<id>\d+)/instroke$',views.instroke_view),
|
url(r'^workout/(?P<id>\d+)/instroke$',views.instroke_view),
|
||||||
url(r'^workout/(?P<id>\d+)/stats$',views.workout_stats_view),
|
url(r'^workout/(?P<id>\d+)/stats$',views.workout_stats_view),
|
||||||
|
url(r'^workout/(?P<id>\d+)/data$',views.workout_data_view),
|
||||||
url(r'^workout/(?P<id>\d+)/otwsetpower$',views.workout_otwsetpower_view),
|
url(r'^workout/(?P<id>\d+)/otwsetpower$',views.workout_otwsetpower_view),
|
||||||
url(r'^workout/(?P<id>\d+)/interactiveotwplot$',views.workout_otwpowerplot_view),
|
url(r'^workout/(?P<id>\d+)/interactiveotwplot$',views.workout_otwpowerplot_view),
|
||||||
url(r'^workout/(?P<id>\d+)/wind$',views.workout_wind_view),
|
url(r'^workout/(?P<id>\d+)/wind$',views.workout_wind_view),
|
||||||
|
|||||||
101
rowers/views.py
101
rowers/views.py
@@ -44,7 +44,7 @@ from rowers.forms import (
|
|||||||
PlannedSessionTeamForm,PlannedSessionTeamMemberForm,
|
PlannedSessionTeamForm,PlannedSessionTeamMemberForm,
|
||||||
VirtualRaceSelectForm,WorkoutRaceSelectForm,CourseSelectForm,
|
VirtualRaceSelectForm,WorkoutRaceSelectForm,CourseSelectForm,
|
||||||
RaceResultFilterForm,PowerIntervalUpdateForm,FlexAxesForm,
|
RaceResultFilterForm,PowerIntervalUpdateForm,FlexAxesForm,
|
||||||
FlexOptionsForm
|
FlexOptionsForm,DataFrameColumnsForm,
|
||||||
)
|
)
|
||||||
from django.core.urlresolvers import reverse, reverse_lazy
|
from django.core.urlresolvers import reverse, reverse_lazy
|
||||||
|
|
||||||
@@ -8093,6 +8093,100 @@ def cumstats(request,theuser=0,
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
# data explorer
|
||||||
|
@login_required()
|
||||||
|
def workout_data_view(request, id=0):
|
||||||
|
|
||||||
|
r = getrower(request.user)
|
||||||
|
w = get_workout(id)
|
||||||
|
|
||||||
|
if not checkworkoutuser(request.user,w):
|
||||||
|
raise PermissionDenied('Access Denied')
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':'/rowers/list-workouts',
|
||||||
|
'name':'Workouts'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':get_workout_default_page(request,id),
|
||||||
|
'name': str(w.id)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(workout_data_view,kwargs={'id':id}),
|
||||||
|
'name': 'Data Explorer'
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
datadf,row = dataprep.getrowdata_db(id=id)
|
||||||
|
|
||||||
|
|
||||||
|
datadf.sort_values(['ftime'],inplace=True)
|
||||||
|
|
||||||
|
datadf.drop(labels=[
|
||||||
|
'id','time','hr_an','hr_at','hr_bottom','hr_max',
|
||||||
|
'hr_tr','hr_ut1','hr_ut2','x_right',
|
||||||
|
],inplace=True,axis=1)
|
||||||
|
|
||||||
|
|
||||||
|
cols = ['ftime','cumdist','fpace','spm',
|
||||||
|
'hr','power','driveenergy','drivelength','averageforce',
|
||||||
|
'peakforce','distance','drivespeed','workoutstate',
|
||||||
|
'catch','finish','peakforceangle','wash','slip','rhythm',
|
||||||
|
'effectiveangle','totalangle','distanceperstroke','velo']
|
||||||
|
|
||||||
|
|
||||||
|
tcols = ['ftime','cumdist','fpace','spm','hr','power']
|
||||||
|
|
||||||
|
datadf = datadf[cols]
|
||||||
|
datadf.loc[:,'hr'] = datadf['hr'].astype('int')
|
||||||
|
datadf.loc[:,'power'] = datadf['power'].astype('int')
|
||||||
|
datadf.loc[:,'distance'] = datadf['distance'].astype('int')
|
||||||
|
datadf.loc[:,'spm'] = 10*datadf['spm'].astype('int')/10.
|
||||||
|
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = DataFrameColumnsForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
tcols = form.cleaned_data['cols']
|
||||||
|
|
||||||
|
else:
|
||||||
|
form = DataFrameColumnsForm(initial = {'cols':tcols})
|
||||||
|
|
||||||
|
datadf = datadf[tcols]
|
||||||
|
|
||||||
|
for col in cols:
|
||||||
|
try:
|
||||||
|
if datadf[col].mean() == 0 and datadf[col].std() == 0:
|
||||||
|
datadf.drop(labels=[col],axis=1,inplace=True)
|
||||||
|
except (TypeError,KeyError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# pd.set_option('display.width', 1000)
|
||||||
|
pd.set_option('colheader_justify', 'left')
|
||||||
|
|
||||||
|
htmltable = datadf.to_html(
|
||||||
|
bold_rows=True,
|
||||||
|
show_dimensions=True,border=1,
|
||||||
|
classes='pandastable',justify='justify'
|
||||||
|
)
|
||||||
|
|
||||||
|
return render(request,
|
||||||
|
'workout_data.html',
|
||||||
|
{
|
||||||
|
'htmltable': htmltable,
|
||||||
|
'form':form,
|
||||||
|
'teams':get_my_teams(request.user),
|
||||||
|
'workout': w,
|
||||||
|
'breadcrumbs': breadcrumbs,
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Stats page
|
# Stats page
|
||||||
@login_required()
|
@login_required()
|
||||||
def workout_stats_view(request,id=0,message="",successmessage=""):
|
def workout_stats_view(request,id=0,message="",successmessage=""):
|
||||||
@@ -8130,10 +8224,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
|
|||||||
# prepare data frame
|
# prepare data frame
|
||||||
datadf,row = dataprep.getrowdata_db(id=id)
|
datadf,row = dataprep.getrowdata_db(id=id)
|
||||||
if (checkworkoutuser(request.user,row)==False):
|
if (checkworkoutuser(request.user,row)==False):
|
||||||
message = "You are not allowed to see the stats of this workout"
|
raise PermissionDenied('Access Denied')
|
||||||
messages.error(request,message)
|
|
||||||
url = reverse(workouts_view)
|
|
||||||
return HttpResponseRedirect(url)
|
|
||||||
|
|
||||||
datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)
|
datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly)
|
||||||
|
|
||||||
|
|||||||
@@ -972,3 +972,38 @@ a.wh:hover {
|
|||||||
width: auto !important;
|
width: auto !important;
|
||||||
max-width: 1px;
|
max-width: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mystyle {
|
||||||
|
font-size: 11pt;
|
||||||
|
font-family: Arial;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: 1px solid silver;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.pandastable tr {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pandastable th, table td {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pandastable tbody {
|
||||||
|
display: block;
|
||||||
|
height: 300px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pandastable td, th {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pandastable tr:nth-child(even) {
|
||||||
|
background: #E0E0E0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pandastable tr:hover {
|
||||||
|
background: silver;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|||||||
@@ -501,6 +501,18 @@
|
|||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.maxheightwidth {
|
||||||
|
position: relative;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maxheightwidthcontent {
|
||||||
|
position: relative;
|
||||||
|
max-width: 700px;
|
||||||
|
overflow: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
.main-content li.grid_4 {
|
.main-content li.grid_4 {
|
||||||
grid-column-end: span 1;
|
grid-column-end: span 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user