Private
Public Access
1
0

Merge branch 'release/v12.31'

This commit is contained in:
Sander Roosendaal
2020-05-09 16:01:01 +02:00
5 changed files with 84 additions and 19 deletions

View File

@@ -26,6 +26,7 @@ from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation
from bokeh.resources import CDN,INLINE
from bokeh.embed import components
from bokeh.layouts import layout,widgetbox
from bokeh.palettes import Category20c
from bokeh.layouts import row as layoutrow
from bokeh.layouts import column as layoutcolumn
from bokeh.models import LinearAxis,LogAxis,Range1d,DatetimeTickFormatter,HoverTool
@@ -37,6 +38,7 @@ from bokeh.models import (
ResetTool, TapTool,CrosshairTool,BoxZoomTool,
Span, Label
)
from bokeh.transform import cumsum
from bokeh.models.glyphs import ImageURL
from bokeh.models import OpenURL, TapTool
from rowers.opaque import encoder
@@ -51,6 +53,7 @@ from rowers.courses import (
polygon_coord_center
)
from rowers import mytypes
from rowers.models import course_spline
import datetime
@@ -234,7 +237,8 @@ def interactive_hr_piechart(df,rower,title):
tools=TOOLS,
)
for start, end , legend, color in zip(source_starts, source_ends, source_legends, colors[0:len(source_starts)]):
for start, end , legend, color in zip(source_starts, source_ends, source_legends,
colors[0:len(source_starts)]):
z.wedge(x=0, y=0, radius=1, start_angle=start, end_angle=end, color=color, legend=legend)
@@ -249,6 +253,50 @@ def interactive_hr_piechart(df,rower,title):
return components(z)
def pretty_timedelta(secs):
hours, remainder = divmod(secs,3600)
minutes, seconds = divmod(remainder,60)
return '{}:{:02}:{:02}'.format(int(hours),int(minutes),int(seconds))
def interactive_workouttype_piechart(workouts):
if len(workouts) == 0:
return "","Not enough workouts to make a chart"
datadict = {}
for w in workouts:
try:
label = mytypes.workouttypes_ordered[w.workouttype]
except KeyError:
labels = w.workouttype
try:
datadict[label] += 60*(60*w.duration.hour+w.duration.minute)+w.duration.second
except KeyError:
datadict[label] = 60*(60*w.duration.hour+w.duration.minute)+w.duration.second
data = pd.Series(datadict).reset_index(name='value').rename(columns={'index':'type'})
data['angle'] = data['value']/data['value'].sum() * 2*pi
data['color'] = Category20c[len(datadict)]
data['totaltime'] = pd.Series([pretty_timedelta(v) for v in data['value']])
p = figure(plot_height=350, title="Types", toolbar_location=None,
tools="hover,save", tooltips="@type: @totaltime", x_range=(-0.5, 1.0))
p.wedge(x=0, y=1, radius=0.4,
start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
line_color="white", fill_color='color', source=data,legend='type', )
p.axis.axis_label=None
p.axis.visible=False
p.grid.grid_line_color = None
p.outline_line_color = None
p.toolbar_location = 'right'
return components(p)
def interactive_boxchart(datadf,fieldname,extratitle='',
spmmin=0,spmmax=0,workmin=0,workmax=0):

View File

@@ -21,6 +21,10 @@
<div id="id_script">
</div>
<div id="t_script">
{{ tscript|safe}}
</div>
<ul class="main-content">
<li class="grid_2">
<h1>History for {{ rower.user.first_name }} {{ rower.user.last_name }}</h1>
@@ -43,6 +47,8 @@
<input type="submit" value="Submit"/>
</form>
</p>
</li>
<li class="grid_2">
<h2>All workouts</h2>
<p>
@@ -52,7 +58,7 @@
<td>Total Distance</td><td>{{ totalsdict|lookup:"distance"}} meters</td>
</tr>
<tr>
<td>Total Duration</td><td>{{ totalsdict|lookup:"duration"}} hours</td>
<td>Total Duration</td><td>{{ totalsdict|lookup:"duration"}} </td>
</tr>
<tr>
<td>Number of workouts</td><td>{{ totalsdict|lookup:"nrworkouts"}}</td>
@@ -73,6 +79,9 @@
</table>
</p>
</li>
<li class="grid_2">
{{ tdiv|safe }}
</li>
<li class="grid_2">
<div id="id_chart">
{{ totaldiv|safe }}
@@ -90,7 +99,7 @@
<td>Total Distance</td><td>{{ ddict|lookup:"distance"}} meters</td>
</tr>
<tr>
<td>Total Duration</td><td>{{ ddict|lookup:"duration"}} hours</td>
<td>Total Duration</td><td>{{ ddict|lookup:"duration"}} </td>
</tr>
<tr>
<td>Number of workouts</td><td>{{ ddict|lookup:"nrworkouts"}}</td>

View File

@@ -4697,8 +4697,9 @@ def history_view(request,userid=0):
columns = ['hr','power','time']
tscript,tdiv = interactive_workouttype_piechart(g_workouts)
totalmeters,totalhours, totalminutes = get_totals(g_workouts)
totalmeters,totalhours, totalminutes, totalseconds = get_totals(g_workouts)
totalminutes = "{totalminutes:02d}".format(totalminutes=totalminutes)
# meters, duration per workout type
@@ -4715,7 +4716,7 @@ def history_view(request,userid=0):
for wtype in wtypes:
a_workouts = g_workouts.filter(workouttype=wtype)
wmeters, whours, wminutes = get_totals(a_workouts)
wmeters, whours, wminutes,wseconds = get_totals(a_workouts)
ddict = {}
ddict['id'] = wtype
try:
@@ -4723,9 +4724,10 @@ def history_view(request,userid=0):
except KeyError:
ddict['wtype'] = wtype
ddict['distance'] = wmeters
ddict['duration'] = "{whours}:{wminutes:02d}".format(
ddict['duration'] = "{whours}:{wminutes:02d}:{wseconds:02d}".format(
whours=whours,
wminutes=wminutes
wminutes=wminutes,
wseconds=wseconds,
)
ddict['nrworkouts'] = a_workouts.count()
listofdicts.append(ddict)
@@ -4736,9 +4738,10 @@ def history_view(request,userid=0):
totaldiv = get_call()
totalsdict = {}
totalsdict['duration'] = "{totalhours}:{totalminutes}".format(
totalsdict['duration'] = "{totalhours}:{totalminutes}:{totalseconds}".format(
totalhours=totalhours,
totalminutes=totalminutes
totalminutes=totalminutes,
totalseconds=totalseconds
)
totalsdict['distance'] = totalmeters
@@ -4768,6 +4771,8 @@ def history_view(request,userid=0):
return render(request,'history.html',
{
'tscript':tscript,
'tdiv':tdiv,
'rower':r,
'breadcrumbs':breadcrumbs,
'active':'nav-analysis',
@@ -4833,9 +4838,11 @@ def history_view_data(request,userid=0):
df = dataprep.clean_df_stats(df,workstrokesonly=True,
ignoreadvanced=True)
totalmeters,totalhours, totalminutes = get_totals(g_workouts)
totalmeters,totalhours, totalminutes,totalseconds = get_totals(g_workouts)
totalminutes = "{totalminutes:02d}".format(totalminutes=totalminutes)
# meters, duration per workout type
wtypes = list(set([w.workouttype for w in g_workouts]))
@@ -4848,18 +4855,18 @@ def history_view_data(request,userid=0):
for wtype in wtypes:
a_workouts = g_workouts.filter(workouttype=wtype)
wmeters, whours, wminutes = get_totals(a_workouts)
wmeters, whours, wminutes,wseconds = get_totals(a_workouts)
ddict = {}
try:
ddict['wtype'] = mytypes.workouttypes_ordered[wtype]
except KeyError:
ddict['wtype'] = wtype
ddict['id'] = wtype
ddict['distance'] = wmeters
ddict['duration'] = "{whours}:{wminutes:02d}".format(
ddict['duration'] = "{whours}:{wminutes:02d}:{wseconds:02d}".format(
whours=whours,
wminutes=wminutes
wminutes=wminutes,wseconds=wseconds,
)
ddf = getsmallrowdata_db(columns,ids=[w.id for w in a_workouts])
try:

View File

@@ -260,16 +260,17 @@ from django_mailbox.models import Message,Mailbox,MessageAttachment
from rules.contrib.views import permission_required, objectgetter
def get_totals(workouts):
totalminutes = 0
totalseconds = 0
totalmeters = 0
for w in workouts:
totalmeters += w.distance
totalminutes += w.duration.hour*60+w.duration.minute
totalseconds += 60*(w.duration.hour*60+w.duration.minute)+w.duration.second
totalhour, totalminutes = divmod(totalminutes,60)
hours, remainder = divmod(totalseconds,3600)
minutes, seconds = divmod(remainder,60)
return totalmeters,totalhour, totalminutes
return totalmeters,hours, minutes, seconds
# creating shareable views
def allow_shares(view_func):

View File

@@ -2010,7 +2010,7 @@ def workouts_view(request,message='',successmessage='',
g_enddate,
stack=stack)
totalmeters,totalhours, totalminutes = get_totals(g_workouts)
totalmeters,totalhours, totalminutes,total_seconds = get_totals(g_workouts)
totalminutes = '{totalminutes:02d}'.format(totalminutes=totalminutes)