From e806089ef7f95ded6d5450630ee1ccaaa9867e57 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 12 Oct 2017 22:20:07 +0200 Subject: [PATCH] v1 of workflow.html - need speed up chart generation --- rowers/interactiveplots.py | 195 ++++++++++++++++++++++++++++++++- rowers/templates/workflow.html | 41 +++++++ rowers/urls.py | 1 + rowers/views.py | 60 ++++++++-- 4 files changed, 288 insertions(+), 9 deletions(-) create mode 100644 rowers/templates/workflow.html diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 7e828b40..9732440c 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -2482,13 +2482,13 @@ def interactive_flex_chart2(id=0,promember=0, title="Max Distance",callback=callback) callback.args["maxdist"] = slider_dist_max - layout = layoutrow([layoutcolumn([slider_spm_min, + layout = layoutrow([layoutcolumn([annotation, + slider_spm_min, slider_spm_max, slider_dist_min, slider_dist_max, slider_work_min, slider_work_max, - annotation, ], ), plot]) @@ -2499,6 +2499,197 @@ def interactive_flex_chart2(id=0,promember=0, return [script,div,js_resources,css_resources,workstrokesonly] +def thumbnail_flex_chart(id=0,promember=0, + xparam='time', + yparam1='pace', + yparam2='hr', + plottype='line', + workstrokesonly=False): + + + #rowdata,row = dataprep.getrowdata_db(id=id) + columns = [xparam,yparam1,yparam2,'time'] + + rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True, + workstrokesonly=workstrokesonly) + + if rowdata.empty: + rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True, + workstrokesonly=False) + workstrokesonly=False + + try: + tests = rowdata[yparam2] + except KeyError: + yparam2 = 'None' + + try: + tests = rowdata[yparam1] + except KeyError: + yparam1 = 'None' + + rowdata.dropna(axis=1,how='all',inplace=True) + + if rowdata.empty: + return "","No valid data" + else: + try: + rowdata.sort_values(by='time',ascending=True,inplace=True) + except KeyError: + pass + + workoutstateswork = [1,4,5,8,9,6,7] + workoutstatesrest = [3] + workoutstatetransition = [0,2,10,11,12,13] + + if workstrokesonly: + try: + rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)] + except KeyError: + pass + + try: + tseconds = rowdata.ix[:,'time'] + except KeyError: + return '','No time data - cannot make flex plot','','' + + + try: + rowdata['x1'] = rowdata.ix[:,xparam] + except KeyError: + rowdata['x1'] = 0*rowdata.ix[:,'time'] + + try: + rowdata['y1'] = rowdata.ix[:,yparam1] + except KeyError: + rowdata['y1'] = 0*rowdata.ix[:,'time'] + + if yparam2 != 'None': + try: + rowdata['y2'] = rowdata.ix[:,yparam2] + except KeyError: + rowdata['y2'] = 0*rowdata.ix[:,'time'] + else: + rowdata['y2'] = rowdata['y1'] + + if xparam=='time': + xaxmax = tseconds.max() + xaxmin = tseconds.min() + elif xparam=='distance' or xparam=='cumdist': + xaxmax = rowdata['x1'].max() + xaxmin = rowdata['x1'].min() + else: + xaxmax = yaxmaxima[xparam] + xaxmin = yaxminima[xparam] + + x_axis_type = 'linear' + y_axis_type = 'linear' + if xparam == 'time': + x_axis_type = 'datetime' + + if yparam1 == 'pace': + y_axis_type = 'datetime' + y1mean = rowdata.ix[:,'pace'].mean() + + + rowdata['xname'] = axlabels[xparam] + rowdata['yname1'] = axlabels[yparam1] + if yparam2 != 'None': + rowdata['yname2'] = axlabels[yparam2] + else: + rowdata['yname2'] = axlabels[yparam1] + + + # prepare data + source = ColumnDataSource( + rowdata + ) + + + sizing_mode = 'fixed' # 'scale_width' also looks nice with this example + plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, + plot_width=200,plot_height=150, + ) + + + + plot.toolbar.logo = None + plot.toolbar_location = None + #plot.yaxis.visible = False + plot.xaxis.axis_label_text_font_size = "7pt" + plot.yaxis.axis_label_text_font_size = "7pt" + plot.xaxis.major_label_text_font_size = "7pt" + plot.yaxis.major_label_text_font_size = "7pt" + # add watermark + plot.extra_y_ranges = {"watermark": watermarkrange} + plot.extra_x_ranges = {"watermark": watermarkrange} + + + + if plottype=='line': + plot.line('x1','y1',source=source) + elif plottype=='scatter': + plot.scatter('x1','y1',source=source,fill_alpha=0.4, + line_color=None) + + plot.xaxis.axis_label = axlabels[xparam] + plot.yaxis.axis_label = axlabels[yparam1] + + + + yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1]) + plot.y_range = yrange1 + + if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): + xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) + plot.x_range = xrange1 + + if xparam == 'time': + xrange1 = Range1d(start=xaxmin,end=xaxmax) + plot.x_range = xrange1 + plot.xaxis[0].formatter = DatetimeTickFormatter( + hours = ["%H"], + minutes = ["%M"], + seconds = ["%S"], + days = ["0"], + months = [""], + years = [""] + ) + + + if yparam1 == 'pace': + plot.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) + + + if yparam2 != 'None': + yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2]) + plot.extra_y_ranges["yax2"] = yrange2 + #= {"yax2": yrange2} + + if plottype=='line': + plot.line('x1','y2',color="red",y_range_name="yax2", + source=source) + + elif plottype=='scatter': + plot.scatter('x1','y2',source=source, + fill_alpha=0.4, + line_color=None,color="red",y_range_name="yax2") + + plot.add_layout(LinearAxis(y_range_name="yax2", + axis_label=axlabels[yparam2], + major_label_text_font_size="7pt", + axis_label_text_font_size="7pt", + ),'right', + ) + + + script, div = components(plot) + + return [script,div] + def interactive_bar_chart(id=0,promember=0): # check if valid ID exists (workout exists) diff --git a/rowers/templates/workflow.html b/rowers/templates/workflow.html new file mode 100644 index 00000000..2a454179 --- /dev/null +++ b/rowers/templates/workflow.html @@ -0,0 +1,41 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} +{% load tz %} + + +{% get_current_timezone as TIME_ZONE %} + +{% block title %}{{ workout.name }}{% endblock %} +{% block og_title %}{{ workout.name }}{% endblock %} +{% block description %}{{ workout.name }} +{{ workout.date }} - {{ workout.distance }}m - {{ workout.duration |durationprint:"%H:%M:%S.%f" }}{% endblock %} +{% block og_description %}{{ workout.name }} +{{ workout.date }} - {{ workout.distance }}m - {{ workout.duration |durationprint:"%H:%M:%S.%f" }}{% endblock %} + +{% block meta %} + + + +{% for chart in charts %} +{{ chart.script |safe }} +{% endfor %} +{% endblock %} + +{% block content %} +
+ {% for chart in charts %} +
+

{{ forloop.counter }}

+
+ + {{ chart.div | safe }} + + {{ chart.notes }} +
+
+ {% endfor %} +
+{% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index 96199525..7e6b9fee 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -327,6 +327,7 @@ urlpatterns = [ url(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'), url(r'^register$',views.rower_register_view), url(r'^register/thankyou/$', TemplateView.as_view(template_name='registerthankyou.html'), name='registerthankyou'), + url(r'^workout/(?P\d+)/workflow$',views.workout_workflow_view), url(r'^workout/(?P\d+)/flexchart/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\w+)/$',views.workout_flexchart3_view), url(r'^workout/(?P\d+)/flexchart/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)$',views.workout_flexchart3_view), url(r'^workout/(?P\d+)/flexchart/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)$',views.workout_flexchart3_view), diff --git a/rowers/views.py b/rowers/views.py index 03f119a3..630970c4 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -5846,7 +5846,59 @@ def workout_comparison_view2(request,id1=0,id2=0,xparam='distance', 'promember':promember, }) - + +# Flex thumbnails +@login_required() +def workout_workflow_view(request,id): + try: + row = Workout.objects.get(id=id) + except Workout.DoesNotExist: + raise Http404("Workout doesn't exist") + + r = getrower(request.user) + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 + if request.user == row.user.user: + mayedit=1 + + workouttype = 'ote' + if row.workouttype in ('water','coastal'): + workouttype = 'otw' + + try: + favorites = FavoriteChart.objects.filter(user=r, + workouttype__in=[workouttype,'both']).order_by("id") + maxfav = len(favorites)-1 + except: + favorites = None + maxfav = 0 + + charts = [] + + if favorites: + for f in favorites: + workstrokesonly = not f.reststrokes + script,div = thumbnail_flex_chart(id=id,promember=promember, + xparam=f.xparam, + yparam1=f.yparam1, + yparam2=f.yparam2, + plottype=f.plottype, + workstrokesonly=workstrokesonly) + + charts.append({ + 'script':script, + 'div':div, + 'notes':f.notes}) + + + return render(request, + 'workflow.html', + { + 'charts':charts, + 'workout':row, + }) + # The famous flex chart def workout_flexchart3_view(request,*args,**kwargs): @@ -5978,12 +6030,6 @@ def workout_flexchart3_view(request,*args,**kwargs): css_resources = "" - # script = res[0] - # div = res[1] - # js_resources = res[2] - # css_resources = res[3] - - axchoicesbasic = {ax[0]:ax[1] for ax in axes if ax[4]=='basic'} axchoicespro = {ax[0]:ax[1] for ax in axes if ax[4]=='pro'} noylist = ["time","distance"]