diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py
index 57405046..49d8cb7f 100644
--- a/rowers/interactiveplots.py
+++ b/rowers/interactiveplots.py
@@ -13,6 +13,7 @@ import itertools
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation
from bokeh.charts import Histogram,HeatMap,Area,BoxPlot,Bar
+from bokeh.charts.attributes import CatAttr
from bokeh.resources import CDN,INLINE
from bokeh.embed import components
from bokeh.layouts import layout,widgetbox
@@ -227,6 +228,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
return "",""
dates = []
+ dates_sorting = []
types = []
rowers = []
durations = []
@@ -234,8 +236,10 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
for w in workouts:
if w.privacy == 'visible':
dd = w.date.strftime('%m/%d')
+ dd2 = w.date.strftime('%Y/%m/%d')
du = w.duration.hour*60+w.duration.minute
dates.append(dd)
+ dates_sorting.append(dd2)
durations.append(du)
types.append(w.workouttype)
try:
@@ -253,9 +257,10 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
except ValueError:
pass
-
+ # add dates with no activity
while d<=enddate:
dates.append(d.strftime('%m/%d'))
+ dates_sorting.append(d.strftime('%Y/%m/%d'))
durations.append(0)
types.append('rower')
rowers.append('Sander')
@@ -263,12 +268,19 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
df = pd.DataFrame({
'date':dates,
+ 'date_sorting':dates_sorting,
'duration':durations,
'type':types,
'rower':rowers,
})
+
+ df.sort_values('date_sorting',inplace=True)
- p = Bar(df,'date',values='duration',title='Activity',
+ p = Bar(df,values='duration',
+ label = CatAttr(columns=['date'], sort=False),
+ xlabel='Date',
+ ylabel='Time',
+ title='Activity',
stack=stack,
plot_width=350,
plot_height=250,
diff --git a/rowers/metrics.py b/rowers/metrics.py
index 72d2d1bb..b2f3eaa6 100644
--- a/rowers/metrics.py
+++ b/rowers/metrics.py
@@ -354,14 +354,21 @@ def getagegrouprecord(age,sex='male',weightcategory='hwt',
p0 = [700,120,700,10,100,100]
- p1, success = optimize.leastsq(errfunc,p0[:],
+ try:
+ p1, success = optimize.leastsq(errfunc,p0[:],
args = (ages,powers))
+ except:
+ p1 = p0
+ success = 0
- power = fitfunc(p1, float(age))
+ if success:
+ power = fitfunc(p1, float(age))
- #power = np.polyval(poly_coefficients,age)
+ #power = np.polyval(poly_coefficients,age)
- power = 0.5*(np.abs(power)+power)
+ power = 0.5*(np.abs(power)+power)
+ else:
+ power = 0
else:
power = 0
diff --git a/rowers/tasks.py b/rowers/tasks.py
index f17fb216..a89377de 100644
--- a/rowers/tasks.py
+++ b/rowers/tasks.py
@@ -66,7 +66,10 @@ def long_test_task2(self,aantal,**kwargs):
kwargs['jobid'] = job_id
return longtask.longtask2(aantal,**kwargs)
+
+
+
# create workout
@app.task
def handle_new_workout_from_file(r, f2,
diff --git a/rowers/templates/rankings.html b/rowers/templates/rankings.html
index ee6fc209..6c0b0b6a 100644
--- a/rowers/templates/rankings.html
+++ b/rowers/templates/rankings.html
@@ -5,6 +5,25 @@
{% block title %}Workouts{% endblock %}
{% block scripts %}
{% include "monitorjobs.html" %}
+
+
+
{% endblock %}
{% block content %}
diff --git a/rowers/urls.py b/rowers/urls.py
index 7c5b3679..7d345028 100644
--- a/rowers/urls.py
+++ b/rowers/urls.py
@@ -123,6 +123,8 @@ urlpatterns = [
url(r'^imports/$', TemplateView.as_view(template_name='imports.html'), name='imports'),
url(r'^agegroupcp/(?P\d+)$',views.agegroupcpview),
url(r'^agegroupcp/(?P\d+)/(?P\d+)$',views.agegroupcpview),
+ url(r'^ajax_agegroup/(?P\d+)/(?P\w+.*)/(?P\w+.*)/(?P\d+)$',
+ views.ajax_agegrouprecords),
url(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/(?P\d+)m$',
views.agegrouprecordview),
url(r'^agegrouprecords/(?P\w+.*)/(?P\w+.*)/(?P\d+)min$',
diff --git a/rowers/views.py b/rowers/views.py
index dca8b0a2..5364fbdc 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -2957,9 +2957,15 @@ def histo(request,theuser=0,
if 'options' in request.session:
options = request.session['options']
- workouttypes = options['workouttypes']
- includereststrokes = options['includereststrokes']
- waterboattype = options['waterboattype']
+ try:
+ workouttypes = options['workouttypes']
+ includereststrokes = options['includereststrokes']
+ waterboattype = options['waterboattype']
+ except KeyError:
+ workouttypes = ['water','rower','dynamic','slides']
+ waterboattype = ['1x','2x','2-','4x','4-','8+']
+ includereststrokes = False
+
workstrokesonly = not includereststrokes
@@ -3509,6 +3515,66 @@ def rankings_view(request,theuser=0,
'teams':get_my_teams(request.user),
})
+@login_required()
+def ajax_agegrouprecords(request,
+ age=25,
+ sex='female',
+ weightcategory='hwt',
+ userid=0):
+
+ wcdurations = []
+ wcpower = []
+ durations = [1,4,30,60]
+ distances = [100,500,1000,2000,5000,6000,10000,21097,42195]
+ for distance in distances:
+ worldclasspower = metrics.getagegrouprecord(
+ age,
+ sex=sex,
+ distance=distance,
+ weightcategory=weightcategory
+ )
+ velo = (worldclasspower/2.8)**(1./3.)
+ try:
+ duration = distance/velo
+ wcdurations.append(duration)
+ wcpower.append(worldclasspower)
+ except ZeroDivisionError:
+ pass
+ for duration in durations:
+ worldclasspower = metrics.getagegrouprecord(
+ age,
+ sex=sex,
+ duration=duration,
+ weightcategory=weightcategory
+ )
+ try:
+ velo = (worldclasspower/2.8)**(1./3.)
+ distance = int(60*duration*velo)
+ wcdurations.append(60.*duration)
+ wcpower.append(worldclasspower)
+ except ValueError:
+ pass
+
+ options = {}
+ options['wcpower'] = wcpower
+ options['wcdurations'] = wcdurations
+
+ thenowtime = timezone.now().isoformat()
+ options['lastupdated'] = thenowtime
+ options['userid'] = userid
+
+ request.session['options'] = options
+
+
+ return JSONResponse(
+ {
+ 'wcdurations': wcdurations,
+ 'wcpower': wcpower,
+ 'lastupdated': thenowtime,
+ }
+ )
+
+
# Show ranking distances including predicted paces
@login_required()
def rankings_view2(request,theuser=0,
@@ -3534,48 +3600,60 @@ def rankings_view2(request,theuser=0,
if theuser == 0:
theuser = request.user.id
+ else:
+ lastupdated = "01-01-1900"
+
promember=0
if not request.user.is_anonymous():
- r = getrower(request.user)
+ r = getrower(theuser)
wcdurations = []
wcpower = []
+ lastupdated = "01-01-1900"
+ userid = 0
+ if 'options' in request.session:
+ options = request.session['options']
+ try:
+ wcdurations = options['wcdurations']
+ wcpower = options['wcpower']
+ lastupdated = options['lastupdated']
+ except KeyError:
+ pass
+ try:
+ userid = options['userid']
+ except KeyError:
+ userid = 0
+ else:
+ options = {}
+
+
+
+ lastupdatedtime = arrow.get(lastupdated).timestamp
+ current_time = arrow.utcnow().timestamp
+
+ deltatime_seconds = current_time - lastupdatedtime
+ recalc = False
+ if str(userid) != str(theuser) or deltatime_seconds > 3600:
+ recalc = True
+ else:
+ recalc = False
+
+ options['userid'] = theuser
+
if r.birthdate:
- age = calculate_age(r.birthdate)
- durations = [1,4,30,60]
- distances = [100,500,1000,2000,5000,6000,10000,21097,42195]
- for distance in distances:
- worldclasspower = metrics.getagegrouprecord(
- age,
- sex=r.sex,
- distance=distance,
- weightcategory=r.weightcategory
- )
- velo = (worldclasspower/2.8)**(1./3.)
- try:
- duration = distance/velo
- wcdurations.append(duration)
- wcpower.append(worldclasspower)
- except ZeroDivisionError:
- pass
- for duration in durations:
- worldclasspower = metrics.getagegrouprecord(
- age,
- sex=r.sex,
- duration=duration,
- weightcategory=r.weightcategory
- )
- try:
- velo = (worldclasspower/2.8)**(1./3.)
- distance = int(60*duration*velo)
- wcdurations.append(60.*duration)
- wcpower.append(worldclasspower)
- except ValueError:
- pass
+ age = calculate_age(r.birthdate)
else:
worldclasspower = None
age = 0
+
+ options['wcpower'] = wcpower
+ options['wcdurations'] = wcdurations
+ if theuser:
+ options['userid'] = theuser
+
+ request.session['options'] = options
+
result = request.user.is_authenticated() and ispromember(request.user)
if result:
@@ -3852,6 +3930,7 @@ def rankings_view2(request,theuser=0,
'theuser':uu,
'age':age,
'sex':r.sex,
+ 'recalc':recalc,
'weightcategory':r.weightcategory,
'startdate':startdate,
'enddate':enddate,
@@ -5687,15 +5766,25 @@ def boxplot_view_data(request,userid=0,
if 'options' in request.session:
options = request.session['options']
-
- includereststrokes = options['includereststrokes']
- spmmin = options['spmmin']
- spmmax = options['spmmax']
- workmin = options['workmin']
- workmax = options['workmax']
- ids = options['ids']
- userid = options['userid']
- plotfield = options['plotfield']
+
+ try:
+ includereststrokes = options['includereststrokes']
+ spmmin = options['spmmin']
+ spmmax = options['spmmax']
+ workmin = options['workmin']
+ workmax = options['workmax']
+ ids = options['ids']
+ userid = options['userid']
+ plotfield = options['plotfield']
+ except KeyError:
+ includereststrokes = False
+ spmmin = 15
+ spmmax = 55
+ workmin = 0
+ workmax = 55
+ ids = []
+ userid = 0
+ plotfield = 'spm'
workstrokesonly = not includereststrokes
@@ -5767,8 +5856,13 @@ def boxplot_view(request,userid=0,
if 'options' in request.session:
options = request.session['options']
+
+ try:
+ includereststrokes = options['includereststrokes']
+ except KeyError:
+ includereststrokes = False
+ options['includereststrokes'] = False
- includereststrokes = options['includereststrokes']
workstrokesonly = not includereststrokes
if userid==0:
@@ -5887,7 +5981,6 @@ def workouts_view(request,message='',successmessage='',
except ValueError:
activity_enddate = enddate
-
if teamid:
try:
theteam = Team.objects.get(id=teamid)
@@ -5954,7 +6047,7 @@ def workouts_view(request,message='',successmessage='',
stack='rower'
else:
stack='type'
-
+
script,div = interactive_activitychart(g_workouts,
activity_startdate,
activity_enddate,