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