diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 71f154b3..84a25803 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -272,7 +272,7 @@ def getstatsfields(): fielddict = {field.name:field.verbose_name for field in fields} - fielddict.pop('workoutid') + #fielddict.pop('workoutid') fielddict.pop('ergpace') fielddict.pop('hr_an') fielddict.pop('hr_tr') @@ -968,6 +968,12 @@ def read_cols_df_sql(ids,columns): connection = engine.raw_connection() df = pd.read_sql_query(query,engine) df = df.fillna(value=0) + try: + df['peakforce'] = df['peakforce']*lbstoN + df['averageforce'] = df['averageforce']*lbstoN + except KeyError: + pass + engine.dispose() return df @@ -980,6 +986,12 @@ def read_df_sql(id): engine.dispose() df = df.fillna(value=0) + try: + df['peakforce'] = df['peakforce']*lbstoN + df['averageforce'] = df['averageforce']*lbstoN + except KeyError: + pass + return df # Get the necessary data from the strokedata table in the DB. diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index f79b9ce2..72607cbf 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -4,14 +4,14 @@ from rowingdata import main as rmain from rowingdata import cumcpdata,histodata from rowingdata import rowingdata as rrdata - +from math import pi from django.utils import timezone from bokeh.palettes import Dark2_8 as palette import itertools from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc from bokeh.models import CustomJS,Slider, TextInput -from bokeh.charts import Histogram,HeatMap +from bokeh.charts import Histogram,HeatMap,Area,BoxPlot from bokeh.resources import CDN,INLINE from bokeh.embed import components from bokeh.layouts import layout,widgetbox @@ -87,6 +87,34 @@ def tailwind(bearing,vwind,winddir): from rowers.dataprep import nicepaceformat,niceformat from rowers.dataprep import timedeltaconv +def interactive_boxchart(datadf,fieldname): + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,resize' + plot = BoxPlot(datadf, values=fieldname, label='date', + legend=False, + title=axlabels[fieldname], + outliers=False, + tools=TOOLS, + x_mapper_type='datetime') + + yrange1 = Range1d(start=yaxminima[fieldname],end=yaxmaxima[fieldname]) + plot.y_range = yrange1 + + plot.xaxis.axis_label = 'Date' + plot.yaxis.axis_label = axlabels[fieldname] + + + plot.xaxis.formatter = DatetimeTickFormatter( + days=["%d %B %Y"], + months=["%d %B %Y"], + years=["%d %B %Y"], + ) + plot.xaxis.major_label_orientation = pi/4 + + script, div = components(plot) + + + return script,div + def interactive_forcecurve(theworkouts,workstrokesonly=False): TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' diff --git a/rowers/templates/cumstats.html b/rowers/templates/cumstats.html index eb0b9654..7d814c62 100644 --- a/rowers/templates/cumstats.html +++ b/rowers/templates/cumstats.html @@ -5,6 +5,35 @@ {% block title %}Workout Statistics{% endblock %} {% block content %} + + + + + {{ plotscript |safe }} + + + + +

Workout Statistics

@@ -18,7 +47,7 @@ between {{ startdate|date }} and {{ enddate|date }}

Direct link for other Pro users: - https://rowsandall.com/rowers/{{ id }}/cumstats/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }} + https://rowsandall.com/rowers/{{ id }}/cumstats/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}/p/{{ plotfield }}

@@ -66,7 +95,13 @@
{% if stats %} {% for key, value in stats.items %} -

{{ value.verbosename }}

+

{{ value.verbosename }}

+
+

+ Plot +

+
+ @@ -97,6 +132,7 @@
{% if cordict %} +

Correlation Matrix

This matrix indicates a positive (+) or negative (-) correlation between two parameters. The Spearman correlation coefficient has values between +1 and -1. Positive correlation between two metrics means that if one metric increases, the other value is also likely to increase. Negative is the opposite. The further from zero, the higher the likelyhood.

@@ -132,8 +168,13 @@ {% endfor %}
+
{% endif %} -
+ +
+ {{ plotdiv|safe }} +
+
{% endblock %} diff --git a/rowers/templates/histoall.html b/rowers/templates/histoall.html index 11f7b63e..6b1ee9c6 100644 --- a/rowers/templates/histoall.html +++ b/rowers/templates/histoall.html @@ -51,4 +51,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index a7593b1a..952b6175 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -141,6 +141,8 @@ urlpatterns = [ url(r'^histo/(?P\w+.*)/(?P\w+.*)$',views.histo), url(r'^histo/(?P\d+)$',views.histo), url(r'^histo/$',views.histo), + url(r'^cumstats/(?P\w+.*)/(?P\w+.*)/p/(?P\w+.*)$',views.cumstats), + url(r'^(?P\d+)/cumstats/(?P\w+.*)/(?P\w+.*)/p/(?P\w+.*)$',views.cumstats), url(r'^(?P\d+)/cumstats/(?P\w+.*)/(?P\w+.*)$',views.cumstats), url(r'^(?P\d+)/cumstats/(?P\d+)$',views.cumstats), url(r'^cumstats/(?P\w+.*)/(?P\w+.*)$',views.cumstats), diff --git a/rowers/views.py b/rowers/views.py index 1e6b24c8..6746e7fe 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -3834,11 +3834,12 @@ def workout_geeky_view(request,id=0,message="",successmessage=""): # Cumulative stats page @login_required() def cumstats(request,theuser=0, - startdate=timezone.now()-datetime.timedelta(days=365), + startdate=timezone.now()-datetime.timedelta(days=30), enddate=timezone.now(), deltadays=-1, startdatestring="", enddatestring="", + plotfield='spm', options={ 'includereststrokes':False, 'workouttypes':['rower','dynamic','slides'] @@ -3957,6 +3958,12 @@ def cumstats(request,theuser=0, ids = [int(workout.id) for workout in allergworkouts] + datemapping = { + w.id:w.date for w in allergworkouts + } + + + fieldlist,fielddict = dataprep.getstatsfields() # prepare data frame @@ -3972,6 +3979,7 @@ def cumstats(request,theuser=0, # Create stats stats = {} fielddict.pop('workoutstate') + fielddict.pop('workoutid') for field,verbosename in fielddict.iteritems(): thedict = { @@ -3998,8 +4006,14 @@ def cumstats(request,theuser=0, except KeyError: thedict[field2] = 0 - cordict[field1] = thedict + cordict[field1] = thedict + # interactive box plot + datadf['workoutid'].replace(datemapping,inplace=True) + datadf.rename(columns={"workoutid":"date"},inplace=True) + datadf = datadf.sort_values(['date']) + script,div = interactive_boxchart(datadf,plotfield) + # set options form correctly initial = {} initial['includereststrokes'] = includereststrokes @@ -4027,6 +4041,9 @@ def cumstats(request,theuser=0, 'deltaform':deltaform, 'optionsform':optionsform, 'cordict':cordict, + 'plotscript':script, + 'plotdiv':div, + 'plotfield':plotfield, }) request.session['options'] = options