From a226a957c8f2cd3b71fa3366c08f95d05433f64a Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Thu, 12 Oct 2017 10:02:50 +0200
Subject: [PATCH 1/6] implemented default set of flex favs on user registration
---
rowers/metrics.py | 59 ++++++++++++++++++++++++++++-
rowers/models.py | 2 +
rowers/templates/flexchart3.html | 2 -
rowers/templates/flexchart3otw.html | 2 -
rowers/views.py | 23 ++++++++++-
5 files changed, 81 insertions(+), 7 deletions(-)
diff --git a/rowers/metrics.py b/rowers/metrics.py
index b4140f1c..27694003 100644
--- a/rowers/metrics.py
+++ b/rowers/metrics.py
@@ -219,7 +219,7 @@ rowingmetrics = (
'ax_max': 15,
'default': 0,
'mode':'both',
- 'type': 'pro'}),
+ 'type': 'basic'}),
)
@@ -236,3 +236,60 @@ axlabels = {ax[0]:ax[1] for ax in axes}
yaxminima = {ax[0]:ax[2] for ax in axes}
yaxmaxima = {ax[0]:ax[3] for ax in axes}
+
+defaultfavoritecharts = (
+ {
+ 'yparam1':'pace',
+ 'yparam2':'spm',
+ 'xparam':'time',
+ 'plottype':'line',
+ 'workouttype':'both',
+ 'reststrokes':True,
+ 'notes':'Some Notes 1',
+ },
+ {
+ 'yparam1':'pace',
+ 'yparam2':'hr',
+ 'xparam':'time',
+ 'plottype':'line',
+ 'workouttype':'both',
+ 'reststrokes':True,
+ 'notes':'Some Notes 2',
+ },
+ {
+ 'yparam1':'distanceperstroke',
+ 'yparam2':'hr',
+ 'xparam':'time',
+ 'plottype':'line',
+ 'workouttype':'otw',
+ 'reststrokes':True,
+ 'notes':'Some Notes 3',
+ },
+ {
+ 'yparam1':'strokeenergy',
+ 'yparam2':'hr',
+ 'xparam':'time',
+ 'plottype':'line',
+ 'workouttype':'ote',
+ 'reststrokes':True,
+ 'notes':'Some Notes 3',
+ },
+ {
+ 'yparam1':'distanceperstroke',
+ 'yparam2':'None',
+ 'xparam':'spm',
+ 'plottype':'line',
+ 'workouttype':'otw',
+ 'reststrokes':True,
+ 'notes':'Some Notes 4',
+ },
+ {
+ 'yparam1':'strokeenergy',
+ 'yparam2':'None',
+ 'xparam':'spm',
+ 'plottype':'line',
+ 'workouttype':'ote',
+ 'reststrokes':True,
+ 'notes':'Some Notes 4',
+ },
+ )
diff --git a/rowers/models.py b/rowers/models.py
index 6bb2c91e..2913c6be 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -344,6 +344,8 @@ class FavoriteChart(models.Model):
default='both',
verbose_name='Workout Type')
reststrokes = models.BooleanField(default=True,verbose_name="Incl. Rest")
+ notes = models.CharField(max_length=300,verbose_name='Chart Notes',
+ default='Flex Chart Notes',blank=True)
user = models.ForeignKey(Rower)
diff --git a/rowers/templates/flexchart3.html b/rowers/templates/flexchart3.html
index aa49ff65..37aaac5c 100644
--- a/rowers/templates/flexchart3.html
+++ b/rowers/templates/flexchart3.html
@@ -168,7 +168,6 @@
-{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if maxfav >= 0 %}
@@ -204,7 +203,6 @@
{% endif %}
-{% endif %}
{% endblock %}
{% endlocaltime %}
diff --git a/rowers/templates/flexchart3otw.html b/rowers/templates/flexchart3otw.html
index 52a8eeaa..5da6e48c 100644
--- a/rowers/templates/flexchart3otw.html
+++ b/rowers/templates/flexchart3otw.html
@@ -151,7 +151,6 @@
-{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
{% if maxfav >= 0 %}
@@ -187,7 +186,6 @@
{% endif %}
-{% endif %}
{% endblock %}
{% endlocaltime %}
diff --git a/rowers/views.py b/rowers/views.py
index 074b5b65..03f119a3 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -49,7 +49,7 @@ from rowers.models import (
WorkoutComment,WorkoutCommentForm,RowerExportForm,
)
from rowers.models import FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement
-from rowers.metrics import rowingmetrics
+from rowers.metrics import rowingmetrics,defaultfavoritecharts
import rowers.uploads as uploads
from django.forms.formsets import formset_factory
import StringIO
@@ -324,6 +324,22 @@ def ispromember(user):
result = False
return result
+# More User/Rower utils
+def add_defaultfavorites(r):
+ for c in defaultfavoritecharts:
+ f = FavoriteChart(user=r,
+ yparam1=c['yparam1'],
+ yparam2=c['yparam2'],
+ xparam=c['xparam'],
+ plottype=c['plottype'],
+ workouttype=c['workouttype'],
+ reststrokes=c['reststrokes'],
+ notes=c['notes'])
+
+ f.save()
+ return 1
+
+
# User registration
def rower_register_view(request):
if request.method == 'POST':
@@ -344,6 +360,9 @@ def rower_register_view(request):
therower.save()
+ # create default favorite charts
+ add_defaultfavorites(therower)
+
# Create Sample workout
f = 'media/testdata.csv.gz'
timestr = strftime("%Y%m%d-%H%M%S")
@@ -8258,7 +8277,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
})
# Page where user can manage his favorite charts
-@user_passes_test(ispromember,login_url="/rowers/me/edit",redirect_field_name=None)
+@login_required()
def rower_favoritecharts_view(request):
message = ''
successmessage = ''
From 08b49b32bbd8bb6ea4a8b0ea3a1ecbbfb1b41318 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Thu, 12 Oct 2017 12:37:33 +0200
Subject: [PATCH 2/6] more around default fav charts
---
rowers/metrics.py | 22 +++++++++++++++-------
rowers/models.py | 13 +++++++++++--
2 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/rowers/metrics.py b/rowers/metrics.py
index 27694003..b2986565 100644
--- a/rowers/metrics.py
+++ b/rowers/metrics.py
@@ -245,7 +245,7 @@ defaultfavoritecharts = (
'plottype':'line',
'workouttype':'both',
'reststrokes':True,
- 'notes':'Some Notes 1',
+ 'notes':"""This chart shows your pace and stroke rate versus time. """,
},
{
'yparam1':'pace',
@@ -254,7 +254,9 @@ defaultfavoritecharts = (
'plottype':'line',
'workouttype':'both',
'reststrokes':True,
- 'notes':'Some Notes 2',
+ 'notes':"""This chart shows your pace and heart rate versus time.
+Heart rate values will be shown only when it is in your data, i.e.
+in case you recorded your heart rate during your workout""",
},
{
'yparam1':'distanceperstroke',
@@ -263,7 +265,8 @@ defaultfavoritecharts = (
'plottype':'line',
'workouttype':'otw',
'reststrokes':True,
- 'notes':'Some Notes 3',
+ 'notes':"""This chart shows the Distance covered per stroke, and your
+heart rate versus time. """,
},
{
'yparam1':'strokeenergy',
@@ -272,16 +275,20 @@ defaultfavoritecharts = (
'plottype':'line',
'workouttype':'ote',
'reststrokes':True,
- 'notes':'Some Notes 3',
+ 'notes':"""This chart shows the Work per Stroke and your heart rate
+plotted versus time. """,
},
{
'yparam1':'distanceperstroke',
'yparam2':'None',
'xparam':'spm',
- 'plottype':'line',
+ 'plottype':'scatter',
'workouttype':'otw',
'reststrokes':True,
- 'notes':'Some Notes 4',
+ 'notes':"""This chart shows the Distance per Stroke versus stroke
+stroke rate. You should see a steady decline of the Distance per Stroke
+as you increase stroke rate. Typical values are > 10m for steady state
+dropping to 8m for race pace in the single.""",
},
{
'yparam1':'strokeenergy',
@@ -290,6 +297,7 @@ defaultfavoritecharts = (
'plottype':'line',
'workouttype':'ote',
'reststrokes':True,
- 'notes':'Some Notes 4',
+ 'notes':"""This chart shows the Work per Stroke versus Stroke Rate.
+This value should be fairly constant across all stroke rates.""",
},
)
diff --git a/rowers/models.py b/rowers/models.py
index 2913c6be..af0b3374 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -298,6 +298,10 @@ class Rower(models.Model):
defaulttimezone = models.CharField(default='UTC',max_length=100,
choices=timezones,
verbose_name='Default Time Zone')
+
+ # Show flex chart notes
+ showfavoritechartnotes = models.BooleanField(default=True,
+ verbose_name='Show Notes for Favorite Charts')
def __str__(self):
return self.user.username
@@ -353,7 +357,11 @@ class FavoriteForm(ModelForm):
class Meta:
model = FavoriteChart
fields = ['xparam','yparam1','yparam2',
- 'plottype','workouttype','reststrokes']
+ 'plottype','workouttype','reststrokes','notes']
+ widgets = {
+ 'notes': forms.Textarea,
+ }
+
# To generate favorite chart forms on the fly
class BaseFavoriteFormSet(BaseFormSet):
@@ -830,7 +838,8 @@ class RowerPowerZonesForm(ModelForm):
class AccountRowerForm(ModelForm):
class Meta:
model = Rower
- fields = ['weightcategory','getemailnotifications','defaulttimezone']
+ fields = ['weightcategory','getemailnotifications',
+ 'defaulttimezone','showfavoritechartnotes']
class UserForm(ModelForm):
class Meta:
From 3028809d24a1948983773d4b001063a78197b059 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Thu, 12 Oct 2017 13:04:18 +0200
Subject: [PATCH 3/6] removed obsolete flexchart template files
---
rowers/models.py | 6 +-
rowers/templates/favoritecharts.html | 11 +-
rowers/templates/flexchart.html | 95 ------------
rowers/templates/flexchart3.html | 208 ---------------------------
4 files changed, 9 insertions(+), 311 deletions(-)
delete mode 100644 rowers/templates/flexchart.html
delete mode 100644 rowers/templates/flexchart3.html
diff --git a/rowers/models.py b/rowers/models.py
index af0b3374..83e699e3 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -358,9 +358,9 @@ class FavoriteForm(ModelForm):
model = FavoriteChart
fields = ['xparam','yparam1','yparam2',
'plottype','workouttype','reststrokes','notes']
- widgets = {
- 'notes': forms.Textarea,
- }
+# widgets = {
+# 'notes': forms.Textarea,
+# }
# To generate favorite chart forms on the fly
diff --git a/rowers/templates/favoritecharts.html b/rowers/templates/favoritecharts.html
index 0ce6512d..efe81047 100644
--- a/rowers/templates/favoritecharts.html
+++ b/rowers/templates/favoritecharts.html
@@ -5,6 +5,11 @@
{% block content %}
@@ -37,4 +37,5 @@
});
+
{% endblock %}
diff --git a/rowers/templates/flexchart.html b/rowers/templates/flexchart.html
deleted file mode 100644
index 479cc35b..00000000
--- a/rowers/templates/flexchart.html
+++ /dev/null
@@ -1,95 +0,0 @@
-{% extends "base.html" %}
-{% load staticfiles %}
-{% load rowerfilters %}
-
-{% block title %} Flexible Plot {% endblock %}
-
-{% block content %}
-
-
-
-
- {{ interactiveplot |safe }}
-
-
-
-
-
- {% if user.is_authenticated and mayedit %}
-
-
- {% endif %}
-
-
-
-
-
-
-
-
-
-
- {{ the_div|safe }}
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/rowers/templates/flexchart3.html b/rowers/templates/flexchart3.html
deleted file mode 100644
index 37aaac5c..00000000
--- a/rowers/templates/flexchart3.html
+++ /dev/null
@@ -1,208 +0,0 @@
-{% extends "base.html" %}
-{% load staticfiles %}
-{% load rowerfilters %}
-{% load tz %}
-
-{% block title %} Flexible Plot {% endblock %}
-
-{% localtime on %}
-{% block content %}
-
-{{ js_res | safe }}
-{{ css_res| safe }}
-
-
-
-
-
-{{ the_script |safe }}
-
-
-
-
-
- {% if user.is_authenticated and mayedit %}
-
-
- {% endif %}
-
-
-
-
-
-
-
-
-
-
- {{ the_div|safe }}
-
-
-
-
-
-
- {% if favoritenr > 0 %}
-
<
- {% else %}
-
<
- {% endif %}
-
-
-
-
-
- {% if favoritenr < maxfav %}
-
>
- {% else %}
-
>
- {% endif %}
-
-
-
-{% endblock %}
-{% endlocaltime %}
From e806089ef7f95ded6d5450630ee1ccaaa9867e57 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Thu, 12 Oct 2017 22:20:07 +0200
Subject: [PATCH 4/6] 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 }}
+
+
+ {% 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"]
From 5ab1152825d8ec2c83f1911d2e07d4e4937d50d7 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Fri, 13 Oct 2017 14:10:53 +0200
Subject: [PATCH 5/6] added workflow view
---
rowers/interactiveplots.py | 90 +++++++++++++++----------
rowers/templates/flexthumbnails.html | 11 +++
rowers/templates/panel_editbuttons.html | 15 +++++
rowers/templates/panel_statcharts.html | 8 +++
rowers/templates/panel_staticchart.html | 20 ++++++
rowers/templates/panel_stats.html | 5 ++
rowers/templates/panel_summary.html | 5 ++
rowers/templates/workflow.html | 34 +++++++---
rowers/views.py | 37 +++++-----
9 files changed, 161 insertions(+), 64 deletions(-)
create mode 100644 rowers/templates/flexthumbnails.html
create mode 100644 rowers/templates/panel_editbuttons.html
create mode 100644 rowers/templates/panel_statcharts.html
create mode 100644 rowers/templates/panel_staticchart.html
create mode 100644 rowers/templates/panel_stats.html
create mode 100644 rowers/templates/panel_summary.html
diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py
index 9732440c..2cc207c0 100644
--- a/rowers/interactiveplots.py
+++ b/rowers/interactiveplots.py
@@ -2499,25 +2499,64 @@ 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):
+def thumbnails_set(r,id,favorites):
+ charts = []
+ columns = [f.xparam for f in favorites]
+ columns += [f.yparam1 for f in favorites]
+ columns += [f.yparam2 for f in favorites]
- #rowdata,row = dataprep.getrowdata_db(id=id)
- columns = [xparam,yparam1,yparam2,'time']
-
- rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True,
- workstrokesonly=workstrokesonly)
+ columns += ['time']
+ rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True)
+ rowdata.dropna(axis=1,how='all',inplace=True)
if rowdata.empty:
- rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True,
- workstrokesonly=False)
- workstrokesonly=False
+ return [
+ {'script':"",
+ 'div':"",
+ 'notes':""
+ }]
+ else:
+ try:
+ rowdata.sort_values(by='time',ascending=True,inplace=True)
+ except KeyError:
+ pass
+
+ l = len(rowdata)
+ maxlength = 50
+ if l > maxlength:
+ bins = np.linspace(rowdata['time'].min(),rowdata['time'].max(),maxlength)
+ groups = rowdata.groupby(np.digitize(rowdata['time'],bins))
+ rowdata = groups.mean()
+ for f in favorites:
+ workstrokesonly = not f.reststrokes
+ script,div = thumbnail_flex_chart(
+ rowdata,
+ id=id,
+ xparam=f.xparam,
+ yparam1=f.yparam1,
+ yparam2=f.yparam2,
+ plottype=f.plottype,
+ )
+
+
+ charts.append({
+ 'script':script,
+ 'div':div,
+ 'notes':f.notes})
+
+ return charts
+
+
+def thumbnail_flex_chart(rowdata,id=0,promember=0,
+ xparam='time',
+ yparam1='pace',
+ yparam2='hr',
+ plottype='line',
+ workstrokesonly=False):
+
+
try:
tests = rowdata[yparam2]
except KeyError:
@@ -2528,25 +2567,7 @@ def thumbnail_flex_chart(id=0,promember=0,
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']
@@ -2620,11 +2641,6 @@ def thumbnail_flex_chart(id=0,promember=0,
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)
diff --git a/rowers/templates/flexthumbnails.html b/rowers/templates/flexthumbnails.html
new file mode 100644
index 00000000..d6a5016a
--- /dev/null
+++ b/rowers/templates/flexthumbnails.html
@@ -0,0 +1,11 @@
+ {% for chart in charts %}
+
+
{{ forloop.counter }}
+
+
+ {% endfor %}
diff --git a/rowers/templates/panel_editbuttons.html b/rowers/templates/panel_editbuttons.html
new file mode 100644
index 00000000..e2c836ea
--- /dev/null
+++ b/rowers/templates/panel_editbuttons.html
@@ -0,0 +1,15 @@
+
+
+
diff --git a/rowers/templates/panel_statcharts.html b/rowers/templates/panel_statcharts.html
new file mode 100644
index 00000000..141fd15e
--- /dev/null
+++ b/rowers/templates/panel_statcharts.html
@@ -0,0 +1,8 @@
+{% for graph in statcharts %}
+
+
+ 
+
+{% endfor %}
diff --git a/rowers/templates/panel_staticchart.html b/rowers/templates/panel_staticchart.html
new file mode 100644
index 00000000..90095d8d
--- /dev/null
+++ b/rowers/templates/panel_staticchart.html
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/rowers/templates/panel_stats.html b/rowers/templates/panel_stats.html
new file mode 100644
index 00000000..248127f8
--- /dev/null
+++ b/rowers/templates/panel_stats.html
@@ -0,0 +1,5 @@
+
diff --git a/rowers/templates/panel_summary.html b/rowers/templates/panel_summary.html
new file mode 100644
index 00000000..759fd39b
--- /dev/null
+++ b/rowers/templates/panel_summary.html
@@ -0,0 +1,5 @@
+
+
+ {{ workout.summary }}
+
+
diff --git a/rowers/templates/workflow.html b/rowers/templates/workflow.html
index 2a454179..a4fe822f 100644
--- a/rowers/templates/workflow.html
+++ b/rowers/templates/workflow.html
@@ -25,17 +25,29 @@
{% endblock %}
{% block content %}
-
- {% for chart in charts %}
-
-
{{ forloop.counter }}
-
+
+
+
{{ workout.name }}
- {% endfor %}
+
+ {% block left_panel %}
+ {% for templateName in leftTemplates %}
+ {% include templateName %}
+ {% endfor %}
+ {% endblock %}
+
+
+ {% block middle_panel %}
+ {% for templateName in middleTemplates %}
+
+ {% include templateName %}
+
+ {% endfor %}
+ {% endblock %}
+
+
+ {% block right_panel %}
+
+ {% endblock %}
{% endblock %}
diff --git a/rowers/views.py b/rowers/views.py
index 630970c4..88ed6029 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -5850,6 +5850,8 @@ def workout_comparison_view2(request,id1=0,id2=0,xparam='distance',
# Flex thumbnails
@login_required()
def workout_workflow_view(request,id):
+ request.session['referer'] = absolute(request)['PATH']
+ request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
try:
row = Workout.objects.get(id=id)
except Workout.DoesNotExist:
@@ -5876,28 +5878,28 @@ def workout_workflow_view(request,id):
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})
+ if favorites:
+ charts = thumbnails_set(r,id,favorites)
+ statcharts = GraphImage.objects.filter(workout=row)
+
+ # This will be user configurable in the future
+ middleTemplates = ['panel_statcharts.html','flexthumbnails.html',
+ 'panel_summary.html']
+ leftTemplates = [
+ 'panel_editbuttons.html','panel_staticchart.html',
+ 'panel_stats.html'
+ ]
return render(request,
'workflow.html',
{
+ 'middleTemplates':middleTemplates,
+ 'leftTemplates':leftTemplates,
'charts':charts,
'workout':row,
- })
+ 'statcharts':statcharts,
+ })
# The famous flex chart
def workout_flexchart3_view(request,*args,**kwargs):
@@ -6810,7 +6812,10 @@ def workout_add_chart_view(request,id,plotnr=1):
imagename=imagename)
- url = "/rowers/workout/"+str(w.id)+"/edit"
+ try:
+ url = request.session['referer']
+ except KeyError:
+ url = "/rowers/workout/"+str(w.id)+"/edit"
return HttpResponseRedirect(url)
From 80cdd24913914d85a26fd76a668d02341d75c0c0 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Fri, 13 Oct 2017 14:30:16 +0200
Subject: [PATCH 6/6] fine tuning headers
---
rowers/templates/flexthumbnails.html | 7 +++++--
rowers/templates/panel_editbuttons.html | 3 +++
rowers/templates/panel_statcharts.html | 3 +++
rowers/templates/panel_staticchart.html | 3 +++
rowers/templates/panel_summary.html | 1 +
rowers/templates/workflow.html | 5 ++++-
rowers/views.py | 5 +++--
static/css/rowsandall.css | 19 ++++++++++++++++++-
8 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/rowers/templates/flexthumbnails.html b/rowers/templates/flexthumbnails.html
index d6a5016a..24d88ffc 100644
--- a/rowers/templates/flexthumbnails.html
+++ b/rowers/templates/flexthumbnails.html
@@ -1,6 +1,8 @@
- {% for chart in charts %}
+{% if charts %}
+Flex Charts
+{% for chart in charts %}
-
{{ forloop.counter }}
+
{{ forloop.counter }}
{% endfor %}
+{% endif %}
diff --git a/rowers/templates/panel_editbuttons.html b/rowers/templates/panel_editbuttons.html
index e2c836ea..a79cb80a 100644
--- a/rowers/templates/panel_editbuttons.html
+++ b/rowers/templates/panel_editbuttons.html
@@ -1,3 +1,6 @@
+
+
Navigation
+
Edit Workout
diff --git a/rowers/templates/panel_statcharts.html b/rowers/templates/panel_statcharts.html
index 141fd15e..e1e44ea9 100644
--- a/rowers/templates/panel_statcharts.html
+++ b/rowers/templates/panel_statcharts.html
@@ -1,3 +1,5 @@
+{% if statcharts %}
+
Static Charts
{% for graph in statcharts %}
{% endfor %}
+{% endif %}
diff --git a/rowers/templates/panel_staticchart.html b/rowers/templates/panel_staticchart.html
index 90095d8d..60da93a4 100644
--- a/rowers/templates/panel_staticchart.html
+++ b/rowers/templates/panel_staticchart.html
@@ -1,3 +1,6 @@
+
+
Create Charts
+
Add Time Plot
diff --git a/rowers/templates/panel_summary.html b/rowers/templates/panel_summary.html
index 759fd39b..47ad211e 100644
--- a/rowers/templates/panel_summary.html
+++ b/rowers/templates/panel_summary.html
@@ -1,3 +1,4 @@
+
Summary
{{ workout.summary }}
diff --git a/rowers/templates/workflow.html b/rowers/templates/workflow.html
index a4fe822f..a7de9675 100644
--- a/rowers/templates/workflow.html
+++ b/rowers/templates/workflow.html
@@ -33,8 +33,11 @@
{% block left_panel %}
{% for templateName in leftTemplates %}
{% include templateName %}
- {% endfor %}
+ {% endfor %}
{% endblock %}
+
+
Click on the thumbnails to view the full chart
+
{% block middle_panel %}
diff --git a/rowers/views.py b/rowers/views.py
index 88ed6029..efc20124 100644
--- a/rowers/views.py
+++ b/rowers/views.py
@@ -5887,8 +5887,9 @@ def workout_workflow_view(request,id):
middleTemplates = ['panel_statcharts.html','flexthumbnails.html',
'panel_summary.html']
leftTemplates = [
- 'panel_editbuttons.html','panel_staticchart.html',
- 'panel_stats.html'
+ 'panel_editbuttons.html',
+ 'panel_stats.html',
+ 'panel_staticchart.html',
]
return render(request,
diff --git a/static/css/rowsandall.css b/static/css/rowsandall.css
index 7dfd9851..7be4294f 100644
--- a/static/css/rowsandall.css
+++ b/static/css/rowsandall.css
@@ -62,11 +62,28 @@ h1 {
font-weight: normal;
/* padding-top: 20px; */
text-align: left;
+ font-size: 2em;
}
h2 {
-/* padding-top: 20px; */
+ /* padding-top: 20px; */
+ font-weight: normal;
text-align: left;
+ font-size: 1.5em;
+}
+
+h3 {
+ /* padding-top: 20px; */
+ font-weight: normal;
+ text-align: left;
+ font-size: 1em;
+}
+
+h3 {
+ /* padding-top: 20px; */
+ font-weight: normal;
+ text-align: left;
+ font-size: 1em;
}
p {