diff --git a/rowers/forms.py b/rowers/forms.py index d9c7da0c..dba009c4 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -1518,6 +1518,7 @@ class VirtualRaceSelectForm(forms.Form): choices = get_countries(),initial='All' ) + class FlexOptionsForm(forms.Form): includereststrokes = forms.BooleanField(initial=True, required = False, label='Include Rest Strokes') @@ -1540,24 +1541,80 @@ class ForceCurveOptionsForm(forms.Form): label='Individual Stroke Chart Type') +axchoices = list( + (ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','None'] + ) +axchoices = dict((x,y) for x,y in axchoices) +axchoices = list(sorted(axchoices.items(), key = lambda x:x[1])) + + +yaxchoices = list((ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time']) +yaxchoices = dict((x,y) for x,y in yaxchoices) +yaxchoices = list(sorted(yaxchoices.items(), key = lambda x:x[1])) + + +yaxchoices2 = list( + (ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time'] + ) +yaxchoices2 = dict((x,y) for x,y in yaxchoices2) +yaxchoices2 = list(sorted(yaxchoices2.items(), key = lambda x:x[1])) + +class StravaChartForm(forms.Form): + xaxischoices = ( + ('cumdist','Distance'), + ('time','Time') + ) + + xaxis = forms.ChoiceField( + choices = xaxischoices,label='X-Axis',required=True) + + + yaxis1 = forms.ChoiceField( + choices=yaxchoices,label='First Chart',required=True) + yaxis2 = forms.ChoiceField( + choices=yaxchoices2,label='Second Chart',required=True) + + yaxis3 = forms.ChoiceField( + choices=yaxchoices,label='Third Chart',required=True) + yaxis4 = forms.ChoiceField( + choices=yaxchoices2,label='Fourth Chart',required=True) + + def __init__(self,request,*args,**kwargs): + extrametrics = kwargs.pop('extrametrics',[]) + super(StravaChartForm, self).__init__(*args, **kwargs) + + + rower = Rower.objects.get(user=request.user) + + axchoicespro = ( + ('',ax[1]) if ax[4] == 'pro' and ax[0] else (ax[0],ax[1]) for ax in axes + ) + + axchoicesbasicx = [] + axchoicesbasicy = [] + + for ax in axes: + if ax[4] != 'pro' and ax[0] != 'cumdist': + if ax[0] != 'None': + axchoicesbasicx.insert(0,(ax[0],ax[1])) + if ax[0] not in ['cumdist','distance','time']: + axchoicesbasicy.insert(0,(ax[0],ax[1])) + else: + if ax[0] != 'None': + axchoicesbasicx.insert(0,('None',ax[1]+' (PRO)')) + if ax[0] not in ['cumdist','distance','time']: + axchoicesbasicy.insert(0,('None',ax[1]+' (PRO)')) + + + if not user_is_not_basic(rower.user): + self.fields['xaxis'].choices = axchoicesbasicx + self.fields['yaxis1'].choices = axchoicesbasicy + self.fields['yaxis2'].choices = axchoicesbasicy + self.fields['yaxis3'].choices = axchoicesbasicy + self.fields['yaxis4'].choices = axchoicesbasicy + + class FlexAxesForm(forms.Form): - axchoices = list( - (ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','None'] - ) - axchoices = dict((x,y) for x,y in axchoices) - axchoices = list(sorted(axchoices.items(), key = lambda x:x[1])) - - - yaxchoices = list((ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time']) - yaxchoices = dict((x,y) for x,y in yaxchoices) - yaxchoices = list(sorted(yaxchoices.items(), key = lambda x:x[1])) - - - yaxchoices2 = list( - (ax[0],ax[1]) for ax in axes if ax[0] not in ['cumdist','distance','time'] - ) - yaxchoices2 = dict((x,y) for x,y in yaxchoices2) - yaxchoices2 = list(sorted(yaxchoices2.items(), key = lambda x:x[1])) xaxis = forms.ChoiceField( choices=axchoices,label='X-Axis',required=True) diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index c271506c..3297a83c 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -4412,6 +4412,213 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, return [script,div,js_resources,css_resources] +def interactive_flexchart_stacked(id,r,xparam='time', + yparam1='pace', + yparam2='power', + yparam3='hr', + yparam4='spm', + mode='erg'): + + columns = [xparam,yparam1,yparam2, + 'ftime','distance','fpace', + 'power','hr','spm','driveenergy', + 'time','pace','workoutstate'] + + rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True, + workstrokesonly=False) + + if r.usersmooth > 1: + for column in columns: + try: + if metricsdicts[column]['maysmooth']: + nrsteps = int(log2(r.usersmooth)) + for i in range(nrsteps): + rowdata[column] = stravastuff.ewmovingaverage(rowdata[column],5) + except KeyError: + pass + + if len(rowdata)<2: + rowdata = dataprep.getsmallrowdata_db(columns,ids=[id], + doclean=False, + workstrokesonly=False) + + row = Workout.objects.get(id=id) + if rowdata.empty: + return "","No valid data",'','' + + try: + tseconds = rowdata.loc[:,'time'] + except KeyError: + return '','No time data - cannot make flex plot','','' + + try: + rowdata['x1'] = rowdata.loc[:,xparam] + rowmin = rowdata[xparam].min() + except KeyError: + rowdata['x1'] = 0*rowdata.loc[:,'time'] + + try: + rowdata['y1'] = rowdata.loc[:,yparam1] + rowmin = rowdata[yparam1].min() + except KeyError: + rowdata['y1'] = 0*rowdata.loc[:,'time'] + rowdata[yparam1] = rowdata['y1'] + + try: + rowdata['y2'] = rowdata.loc[:,yparam2] + rowmin = rowdata[yparam2].min() + except KeyError: + rowdata['y2'] = 0*rowdata.loc[:,'time'] + rowdata[yparam2] = rowdata['y2'] + + try: + rowdata['y3'] = rowdata.loc[:,yparam3] + rowmin = rowdata[yparam3].min() + except KeyError: + rowdata['y3'] = 0*rowdata.loc[:,'time'] + rowdata[yparam3] = rowdata['y3'] + + try: + rowdata['y4'] = rowdata.loc[:,yparam4] + rowmin = rowdata[yparam4].min() + except KeyError: + rowdata['y4'] = 0*rowdata.loc[:,'time'] + rowdata[yparam4] = rowdata['y4'] + + if xparam=='time': + xaxmax = tseconds.max() + xaxmin = tseconds.min() + elif xparam=='distance' or xparam=='cumdist': + xaxmax = rowdata['x1'].max() + xaxmin = rowdata['x1'].min() + else: + try: + xaxmax = get_yaxmaxima(r,xparam,mode) + xaxmin = get_yaxminima(r,xparam,mode) + except KeyError: + xaxmax = rowdata['x1'].max() + xaxmin = rowdata['x1'].min() + + + x_axis_type = 'linear' + y1_axis_type = 'linear' + y2_axis_type = 'linear' + y3_axis_type = 'linear' + y4_axis_type = 'linear' + if xparam == 'time': + x_axis_type = 'datetime' + + if yparam1 == 'pace': + y1_axis_type = 'datetime' + + if yparam2 == 'pace': + y2_axis_type = 'datetime' + + if yparam3 == 'pace': + y3_axis_type = 'datetime' + + if yparam4 == 'pace': + y4_axis_type = 'datetime' + + try: + rowdata['xname'] = axlabels[xparam] + except KeyError: + rowdata['xname'] = xparam + + try: + rowdata['yname1'] = axlabels[yparam1] + except KeyError: + rowdata['yname1'] = yparam1 + + try: + rowdata['yname2'] = axlabels[yparam2] + except KeyError: + rowdata['yname2'] = yparam2 + + try: + rowdata['yname3'] = axlabels[yparam3] + except KeyError: + rowdata['yname3'] = yparam3 + + try: + rowdata['yname4'] = axlabels[yparam4] + except KeyError: + rowdata['yname4'] = yparam4 + + # prepare data + source = ColumnDataSource( + rowdata + ) + + plot1 = Figure(x_axis_type=x_axis_type,y_axis_type=y1_axis_type,plot_width=920,plot_height=150) + plot2 = Figure(x_axis_type=x_axis_type,y_axis_type=y2_axis_type,plot_width=920,plot_height=150) + plot3 = Figure(x_axis_type=x_axis_type,y_axis_type=y3_axis_type,plot_width=920,plot_height=150) + plot4 = Figure(x_axis_type=x_axis_type,y_axis_type=y4_axis_type,plot_width=920,plot_height=150) + + y1min = get_yaxminima(r,yparam1,mode) + y2min = get_yaxminima(r,yparam2,mode) + y3min = get_yaxminima(r,yparam3,mode) + y4min = get_yaxminima(r,yparam4,mode) + + y1max = get_yaxmaxima(r,yparam1,mode) + y2max = get_yaxmaxima(r,yparam2,mode) + y3max = get_yaxmaxima(r,yparam3,mode) + y4max = get_yaxmaxima(r,yparam4,mode) + + plot1.y_range = Range1d(start=y1min,end=y1max) + plot2.y_range = Range1d(start=y2min,end=y2max) + plot3.y_range = Range1d(start=y3min,end=y3max) + plot4.y_range = Range1d(start=y4min,end=y4max) + + if yparam1 == 'pace': + plot1.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) + plot1.y_range = Range1d(y1min,y1max) + + if yparam2 == 'pace': + plot2.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) + plot2.y_range = Range1d(y2min,y2max) + + + if yparam3 == 'pace': + plot3.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) + plot3.y_range = Range1d(y3min,y3max) + + if yparam4 == 'pace': + plot4.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) + plot4.y_range = Range1d(y4min,y4max) + + plot1.line('x1','y1',source=source,color="cyan") + plot2.line('x1','y2',source=source,color="red") + plot3.line('x1','y3',source=source,color="green") + plot4.line('x1','y4',source=source,color="blue") + + layout = layoutcolumn([ + plot1, + plot2, + plot3, + plot4, + ]) + + layout.sizing_mode = 'scale_width' + + script, div = components(layout) + js_resources = INLINE.render_js() + css_resources = INLINE.render_css() + + return script,div,js_resources,css_resources + def interactive_flex_chart2(id,r,promember=0, diff --git a/rowers/templates/flexchartstacked.html b/rowers/templates/flexchartstacked.html new file mode 100644 index 00000000..d6468570 --- /dev/null +++ b/rowers/templates/flexchartstacked.html @@ -0,0 +1,66 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} +{% load tz %} + +{% block title %} Flexible Plot {% endblock %} + +{% localtime on %} +{% block main %} + +{{ js_res | safe }} +{{ css_res| safe }} + + + + + +{{ the_script |safe }} + +
+ {% if workout|previousworkout:rower.user %} + Previous + {% endif %} + {% if workout|nextworkout:rower.user %} + Next + {% endif %} +
+ + +