diff --git a/dashboard/templates/dashboard/child.html b/dashboard/templates/dashboard/child.html
index 0613f5e2..2d949a93 100644
--- a/dashboard/templates/dashboard/child.html
+++ b/dashboard/templates/dashboard/child.html
@@ -23,6 +23,7 @@
{% if perms.core.view_sleep %}
Sleep Pattern
+ Sleep Totals
{% endif %}
diff --git a/reports/graphs.py b/reports/graphs.py
index b569d51f..3c30dae8 100644
--- a/reports/graphs.py
+++ b/reports/graphs.py
@@ -58,19 +58,48 @@ def diaperchange_types(child):
return split_graph_output(output)
-def sleep_amount(child):
+def sleep_totals(child):
"""Create a graph showing total time sleeping for each day."""
instances = Sleep.objects.filter(child=child).order_by('start')
totals = {}
for instance in instances:
- start_time = timezone.localtime(instance.start)
- start_date = start_time.date().isoformat()
+ start = timezone.localtime(instance.start)
+ end = timezone.localtime(instance.end)
+ if start.date() not in totals.keys():
+ totals[start.date()] = timezone.timedelta(seconds=0)
+ if end.date() not in totals.keys():
+ totals[end.date()] = timezone.timedelta(seconds=0)
- if start_date not in totals.keys():
- totals[start_date] = timezone.timedelta()
+ # Account for dates crossing midnight.
+ if start.date() != end.date():
+ totals[start.date()] += end.replace(
+ day=start.day, hour=23, minute=59, second=59) - start
+ totals[end.date()] += end - start.replace(
+ day=end.day, hour=0, minute=0, second=0)
+ else:
+ totals[start.date()] += instance.duration
- totals[start_date] += instance.duration
+ trace = go.Bar(
+ name='Total sleep',
+ x=list(totals.keys()),
+ y=[td.seconds/3600 for td in totals.values()],
+ hoverinfo='text',
+ text=[duration_string(td) for td in totals.values()]
+ )
+
+ layout_args = default_graph_layout_options()
+ layout_args['barmode'] = 'stack'
+ layout_args['title'] = 'Sleep Totals
{}'.format(child)
+ layout_args['xaxis']['title'] = 'Date'
+ layout_args['yaxis']['title'] = 'Hours of sleep'
+
+ fig = go.Figure({
+ 'data': [trace],
+ 'layout': go.Layout(**layout_args)
+ })
+ output = plotly.plot(fig, output_type='div', include_plotlyjs=False)
+ return split_graph_output(output)
def sleep_pattern(child):
diff --git a/reports/templates/reports/sleep_totals.html b/reports/templates/reports/sleep_totals.html
new file mode 100644
index 00000000..ffc31024
--- /dev/null
+++ b/reports/templates/reports/sleep_totals.html
@@ -0,0 +1,8 @@
+{% extends 'reports/report_base.html' %}
+
+{% block title %}Sleep Totals - {{ object }}{% endblock %}
+
+{% block javascript %}
+ {{ block.super }}
+ {{ javascript|safe }}
+{% endblock %}
\ No newline at end of file
diff --git a/reports/urls.py b/reports/urls.py
index 5cc4343f..59063985 100644
--- a/reports/urls.py
+++ b/reports/urls.py
@@ -9,7 +9,11 @@ urlpatterns = [
url(r'^reports/changes/types/(?P[^/.]+)/$',
views.DiaperChangeTypesChildReport.as_view(),
name='report-diaperchange-types-child'),
+
url(r'^reports/sleep/pattern/(?P[^/.]+)$',
views.SleepPatternChildReport.as_view(),
name='report-sleep-pattern-child'),
+ url(r'^reports/sleep/totals/(?P[^/.]+)$',
+ views.SleepTotalsChildReport.as_view(),
+ name='report-sleep-totals-child'),
]
diff --git a/reports/views.py b/reports/views.py
index c84867d3..379a2959 100644
--- a/reports/views.py
+++ b/reports/views.py
@@ -6,7 +6,7 @@ from django.views.generic.detail import DetailView
from core.models import Child
-from .graphs import diaperchange_types, sleep_pattern
+from .graphs import diaperchange_types, sleep_pattern, sleep_totals
class DiaperChangeTypesChildReport(PermissionRequiredMixin, DetailView):
@@ -38,3 +38,21 @@ class SleepPatternChildReport(PermissionRequiredMixin, DetailView):
child = context['object']
context['html'], context['javascript'] = sleep_pattern(child)
return context
+
+
+class SleepTotalsChildReport(PermissionRequiredMixin, DetailView):
+ """Graph of total sleep by day."""
+ model = Child
+ permission_required = ('core.view_child',)
+ template_name = 'reports/sleep_totals.html'
+
+ def __init__(self):
+ super(SleepTotalsChildReport, self).__init__()
+ self.html = ''
+ self.javascript = ''
+
+ def get_context_data(self, **kwargs):
+ context = super(SleepTotalsChildReport, self).get_context_data(**kwargs)
+ child = context['object']
+ context['html'], context['javascript'] = sleep_totals(child)
+ return context