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.resources import CDN,INLINE
from bokeh.embed import components from bokeh.embed import components
from bokeh.layouts import layout,widgetbox from bokeh.layouts import layout,widgetbox
from bokeh.palettes import Category20c
from bokeh.layouts import row as layoutrow from bokeh.layouts import row as layoutrow
from bokeh.layouts import column as layoutcolumn from bokeh.layouts import column as layoutcolumn
from bokeh.models import LinearAxis,LogAxis,Range1d,DatetimeTickFormatter,HoverTool from bokeh.models import LinearAxis,LogAxis,Range1d,DatetimeTickFormatter,HoverTool
@@ -37,6 +38,7 @@ from bokeh.models import (
ResetTool, TapTool,CrosshairTool,BoxZoomTool, ResetTool, TapTool,CrosshairTool,BoxZoomTool,
Span, Label Span, Label
) )
from bokeh.transform import cumsum
from bokeh.models.glyphs import ImageURL from bokeh.models.glyphs import ImageURL
from bokeh.models import OpenURL, TapTool from bokeh.models import OpenURL, TapTool
from rowers.opaque import encoder from rowers.opaque import encoder
@@ -51,6 +53,7 @@ from rowers.courses import (
polygon_coord_center polygon_coord_center
) )
from rowers import mytypes
from rowers.models import course_spline from rowers.models import course_spline
import datetime import datetime
@@ -234,7 +237,8 @@ def interactive_hr_piechart(df,rower,title):
tools=TOOLS, 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) 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) 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='', def interactive_boxchart(datadf,fieldname,extratitle='',
spmmin=0,spmmax=0,workmin=0,workmax=0): spmmin=0,spmmax=0,workmin=0,workmax=0):

View File

@@ -21,6 +21,10 @@
<div id="id_script"> <div id="id_script">
</div> </div>
<div id="t_script">
{{ tscript|safe}}
</div>
<ul class="main-content"> <ul class="main-content">
<li class="grid_2"> <li class="grid_2">
<h1>History for {{ rower.user.first_name }} {{ rower.user.last_name }}</h1> <h1>History for {{ rower.user.first_name }} {{ rower.user.last_name }}</h1>
@@ -43,6 +47,8 @@
<input type="submit" value="Submit"/> <input type="submit" value="Submit"/>
</form> </form>
</p> </p>
</li>
<li class="grid_2">
<h2>All workouts</h2> <h2>All workouts</h2>
<p> <p>
@@ -52,7 +58,7 @@
<td>Total Distance</td><td>{{ totalsdict|lookup:"distance"}} meters</td> <td>Total Distance</td><td>{{ totalsdict|lookup:"distance"}} meters</td>
</tr> </tr>
<tr> <tr>
<td>Total Duration</td><td>{{ totalsdict|lookup:"duration"}} hours</td> <td>Total Duration</td><td>{{ totalsdict|lookup:"duration"}} </td>
</tr> </tr>
<tr> <tr>
<td>Number of workouts</td><td>{{ totalsdict|lookup:"nrworkouts"}}</td> <td>Number of workouts</td><td>{{ totalsdict|lookup:"nrworkouts"}}</td>
@@ -73,6 +79,9 @@
</table> </table>
</p> </p>
</li> </li>
<li class="grid_2">
{{ tdiv|safe }}
</li>
<li class="grid_2"> <li class="grid_2">
<div id="id_chart"> <div id="id_chart">
{{ totaldiv|safe }} {{ totaldiv|safe }}
@@ -90,7 +99,7 @@
<td>Total Distance</td><td>{{ ddict|lookup:"distance"}} meters</td> <td>Total Distance</td><td>{{ ddict|lookup:"distance"}} meters</td>
</tr> </tr>
<tr> <tr>
<td>Total Duration</td><td>{{ ddict|lookup:"duration"}} hours</td> <td>Total Duration</td><td>{{ ddict|lookup:"duration"}} </td>
</tr> </tr>
<tr> <tr>
<td>Number of workouts</td><td>{{ ddict|lookup:"nrworkouts"}}</td> <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'] 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) totalminutes = "{totalminutes:02d}".format(totalminutes=totalminutes)
# meters, duration per workout type # meters, duration per workout type
@@ -4715,7 +4716,7 @@ def history_view(request,userid=0):
for wtype in wtypes: for wtype in wtypes:
a_workouts = g_workouts.filter(workouttype=wtype) a_workouts = g_workouts.filter(workouttype=wtype)
wmeters, whours, wminutes = get_totals(a_workouts) wmeters, whours, wminutes,wseconds = get_totals(a_workouts)
ddict = {} ddict = {}
ddict['id'] = wtype ddict['id'] = wtype
try: try:
@@ -4723,9 +4724,10 @@ def history_view(request,userid=0):
except KeyError: except KeyError:
ddict['wtype'] = wtype ddict['wtype'] = wtype
ddict['distance'] = wmeters ddict['distance'] = wmeters
ddict['duration'] = "{whours}:{wminutes:02d}".format( ddict['duration'] = "{whours}:{wminutes:02d}:{wseconds:02d}".format(
whours=whours, whours=whours,
wminutes=wminutes wminutes=wminutes,
wseconds=wseconds,
) )
ddict['nrworkouts'] = a_workouts.count() ddict['nrworkouts'] = a_workouts.count()
listofdicts.append(ddict) listofdicts.append(ddict)
@@ -4736,9 +4738,10 @@ def history_view(request,userid=0):
totaldiv = get_call() totaldiv = get_call()
totalsdict = {} totalsdict = {}
totalsdict['duration'] = "{totalhours}:{totalminutes}".format( totalsdict['duration'] = "{totalhours}:{totalminutes}:{totalseconds}".format(
totalhours=totalhours, totalhours=totalhours,
totalminutes=totalminutes totalminutes=totalminutes,
totalseconds=totalseconds
) )
totalsdict['distance'] = totalmeters totalsdict['distance'] = totalmeters
@@ -4768,6 +4771,8 @@ def history_view(request,userid=0):
return render(request,'history.html', return render(request,'history.html',
{ {
'tscript':tscript,
'tdiv':tdiv,
'rower':r, 'rower':r,
'breadcrumbs':breadcrumbs, 'breadcrumbs':breadcrumbs,
'active':'nav-analysis', 'active':'nav-analysis',
@@ -4833,9 +4838,11 @@ def history_view_data(request,userid=0):
df = dataprep.clean_df_stats(df,workstrokesonly=True, df = dataprep.clean_df_stats(df,workstrokesonly=True,
ignoreadvanced=True) ignoreadvanced=True)
totalmeters,totalhours, totalminutes = get_totals(g_workouts) totalmeters,totalhours, totalminutes,totalseconds = get_totals(g_workouts)
totalminutes = "{totalminutes:02d}".format(totalminutes=totalminutes) totalminutes = "{totalminutes:02d}".format(totalminutes=totalminutes)
# meters, duration per workout type # meters, duration per workout type
wtypes = list(set([w.workouttype for w in g_workouts])) 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: for wtype in wtypes:
a_workouts = g_workouts.filter(workouttype=wtype) a_workouts = g_workouts.filter(workouttype=wtype)
wmeters, whours, wminutes = get_totals(a_workouts) wmeters, whours, wminutes,wseconds = get_totals(a_workouts)
ddict = {} ddict = {}
try: try:
ddict['wtype'] = mytypes.workouttypes_ordered[wtype] ddict['wtype'] = mytypes.workouttypes_ordered[wtype]
except KeyError: except KeyError:
ddict['wtype'] = wtype ddict['wtype'] = wtype
ddict['id'] = wtype ddict['id'] = wtype
ddict['distance'] = wmeters ddict['distance'] = wmeters
ddict['duration'] = "{whours}:{wminutes:02d}".format( ddict['duration'] = "{whours}:{wminutes:02d}:{wseconds:02d}".format(
whours=whours, whours=whours,
wminutes=wminutes wminutes=wminutes,wseconds=wseconds,
) )
ddf = getsmallrowdata_db(columns,ids=[w.id for w in a_workouts]) ddf = getsmallrowdata_db(columns,ids=[w.id for w in a_workouts])
try: try:

View File

@@ -260,16 +260,17 @@ from django_mailbox.models import Message,Mailbox,MessageAttachment
from rules.contrib.views import permission_required, objectgetter from rules.contrib.views import permission_required, objectgetter
def get_totals(workouts): def get_totals(workouts):
totalminutes = 0 totalseconds = 0
totalmeters = 0 totalmeters = 0
for w in workouts: for w in workouts:
totalmeters += w.distance 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 # creating shareable views
def allow_shares(view_func): def allow_shares(view_func):

View File

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