Display a message when there is not enough data to generate a report.

This commit is contained in:
Christopher Charbonneau Wells 2017-10-27 20:46:48 -04:00
parent 6ce6599b39
commit c305d8038b
3 changed files with 55 additions and 32 deletions

View File

@ -17,10 +17,9 @@ from core.utils import duration_string, duration_parts
from . import utils from . import utils
def diaperchange_lifetimes(child): def diaperchange_lifetimes(changes):
"""Create a graph showing how long diapers last (time between changes).""" """Create a graph showing how long diapers last (time between changes).
changes = DiaperChange.objects.filter(child=child).order_by('time') """
durations = [] durations = []
last_change = changes.first() last_change = changes.first()
for change in changes[1:]: for change in changes[1:]:
@ -39,7 +38,7 @@ def diaperchange_lifetimes(child):
layout_args = utils.default_graph_layout_options() layout_args = utils.default_graph_layout_options()
layout_args['height'] = 800 layout_args['height'] = 800
layout_args['title'] = '<b>Diaper Lifetimes</b><br>{}'.format(child) layout_args['title'] = '<b>Diaper Lifetimes</b>'
layout_args['yaxis']['title'] = 'Time between changes (hours)' layout_args['yaxis']['title'] = 'Time between changes (hours)'
layout_args['yaxis']['zeroline'] = False layout_args['yaxis']['zeroline'] = False
layout_args['yaxis']['dtick'] = 1 layout_args['yaxis']['dtick'] = 1
@ -52,10 +51,10 @@ def diaperchange_lifetimes(child):
return utils.split_graph_output(output) return utils.split_graph_output(output)
def diaperchange_types(child): def diaperchange_types(changes):
"""Create a graph showing types of totals for diaper changes.""" """Create a graph showing types of totals for diaper changes.
changes = DiaperChange.objects.filter(child=child) \ """
.annotate(date=TruncDate('time')) \ changes = changes.annotate(date=TruncDate('time'))\
.values('date') \ .values('date') \
.annotate(wet_count=Count(Case(When(wet=True, then=1)))) \ .annotate(wet_count=Count(Case(When(wet=True, then=1)))) \
.annotate(solid_count=Count(Case(When(solid=True, then=1)))) \ .annotate(solid_count=Count(Case(When(solid=True, then=1)))) \
@ -82,7 +81,7 @@ def diaperchange_types(child):
layout_args = utils.default_graph_layout_options() layout_args = utils.default_graph_layout_options()
layout_args['barmode'] = 'stack' layout_args['barmode'] = 'stack'
layout_args['title'] = '<b>Diaper Change Types</b><br>{}'.format(child) layout_args['title'] = '<b>Diaper Change Types</b>'
layout_args['xaxis']['title'] = 'Date' layout_args['xaxis']['title'] = 'Date'
layout_args['xaxis']['rangeselector'] = utils.rangeselector_date() layout_args['xaxis']['rangeselector'] = utils.rangeselector_date()
layout_args['yaxis']['title'] = 'Number of changes' layout_args['yaxis']['title'] = 'Number of changes'
@ -95,10 +94,9 @@ def diaperchange_types(child):
return utils.split_graph_output(output) return utils.split_graph_output(output)
def sleep_totals(child): def sleep_totals(instances):
"""Create a graph showing total time sleeping for each day.""" """Create a graph showing total time sleeping for each day.
instances = Sleep.objects.filter(child=child).order_by('start') """
totals = {} totals = {}
for instance in instances: for instance in instances:
start = timezone.localtime(instance.start) start = timezone.localtime(instance.start)
@ -130,7 +128,7 @@ def sleep_totals(child):
layout_args = utils.default_graph_layout_options() layout_args = utils.default_graph_layout_options()
layout_args['barmode'] = 'stack' layout_args['barmode'] = 'stack'
layout_args['title'] = '<b>Sleep Totals</b><br>{}'.format(child) layout_args['title'] = '<b>Sleep Totals</b>'
layout_args['xaxis']['title'] = 'Date' layout_args['xaxis']['title'] = 'Date'
layout_args['xaxis']['rangeselector'] = utils.rangeselector_date() layout_args['xaxis']['rangeselector'] = utils.rangeselector_date()
layout_args['yaxis']['title'] = 'Hours of sleep' layout_args['yaxis']['title'] = 'Hours of sleep'
@ -145,15 +143,16 @@ def sleep_totals(child):
def _duration_string_short(duration): def _duration_string_short(duration):
"""Format a "short" duration string without seconds precision. This is """Format a "short" duration string without seconds precision. This is
intended to fit better in smaller spaces on a graph.""" intended to fit better in smaller spaces on a graph.
"""
h, m, s = duration_parts(duration) h, m, s = duration_parts(duration)
return '{}h{}m'.format(h, m) return '{}h{}m'.format(h, m)
def sleep_pattern(child): def sleep_pattern(instances):
"""Create a graph showing blocked out periods of sleep during each day.""" """Create a graph showing blocked out periods of sleep during each day.
"""
# TODO: Simplify this using the bar charts "base" property. # TODO: Simplify this using the bar charts "base" property.
instances = Sleep.objects.filter(child=child).order_by('start')
y_df = pd.DataFrame() y_df = pd.DataFrame()
text_df = pd.DataFrame() text_df = pd.DataFrame()
last_end_time = None last_end_time = None
@ -252,7 +251,7 @@ def sleep_pattern(child):
layout_args['barmode'] = 'stack' layout_args['barmode'] = 'stack'
layout_args['hovermode'] = 'closest' layout_args['hovermode'] = 'closest'
layout_args['title'] = '<b>Sleep Pattern</b><br>{}'.format(child) layout_args['title'] = '<b>Sleep Pattern</b>'
layout_args['height'] = 800 layout_args['height'] = 800
layout_args['xaxis']['title'] = 'Date' layout_args['xaxis']['title'] = 'Date'
@ -282,7 +281,8 @@ def sleep_pattern(child):
def _add_sleep_entry(y_df, text_df, index, column, duration, text=''): def _add_sleep_entry(y_df, text_df, index, column, duration, text=''):
"""Create a duration and text description entry in a DataFrame and return """Create a duration and text description entry in a DataFrame and return
the next index on success.""" the next index on success.
"""
if column not in y_df: if column not in y_df:
y_df.assign(**{column: 0 in range(0, len(y_df.index))}) y_df.assign(**{column: 0 in range(0, len(y_df.index))})
text_df.assign(**{column: 0 in range(0, len(text_df.index))}) text_df.assign(**{column: 0 in range(0, len(text_df.index))})
@ -294,7 +294,8 @@ def _add_sleep_entry(y_df, text_df, index, column, duration, text=''):
def timeline(child, date): def timeline(child, date):
"""Create a time-sorted dictionary for all events for a child.""" """Create a time-sorted dictionary for all events for a child.
"""
min_date = date min_date = date
max_date = date.replace(hour=23, minute=59, second=59) max_date = date.replace(hour=23, minute=59, second=59)
events = [] events = []

View File

@ -11,7 +11,15 @@
{% block content %} {% block content %}
<div class="container-fluid"> <div class="container-fluid">
{% if html %}
{{ html|safe }} {{ html|safe }}
{% else %}
<div class="jumbotron text-center">
<i class="icon icon-sad" aria-hidden="true"></i>
There is no enough data to generate this report.
<i class="icon icon-sad" aria-hidden="true"></i>
</div>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -5,14 +5,15 @@ from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic.detail import DetailView from django.views.generic.detail import DetailView
from django.utils import timezone from django.utils import timezone
from core.models import Child from core.models import Child, DiaperChange, Sleep
from .graphs import (diaperchange_types, diaperchange_lifetimes, sleep_pattern, from .graphs import (diaperchange_types, diaperchange_lifetimes, sleep_pattern,
sleep_totals, timeline) sleep_totals, timeline)
class DiaperChangeLifetimesChildReport(PermissionRequiredMixin, DetailView): class DiaperChangeLifetimesChildReport(PermissionRequiredMixin, DetailView):
"""Graph of diaper changes by day and type.""" """Graph of diaper changes by day and type.
"""
model = Child model = Child
permission_required = ('core.view_child',) permission_required = ('core.view_child',)
template_name = 'reports/diaperchange_lifetimes.html' template_name = 'reports/diaperchange_lifetimes.html'
@ -21,12 +22,16 @@ class DiaperChangeLifetimesChildReport(PermissionRequiredMixin, DetailView):
context = super( context = super(
DiaperChangeLifetimesChildReport, self).get_context_data(**kwargs) DiaperChangeLifetimesChildReport, self).get_context_data(**kwargs)
child = context['object'] child = context['object']
context['html'], context['javascript'] = diaperchange_lifetimes(child) changes = DiaperChange.objects.filter(child=child)
if changes and changes.count() > 1:
context['html'], context['javascript'] = diaperchange_lifetimes(
changes)
return context return context
class DiaperChangeTypesChildReport(PermissionRequiredMixin, DetailView): class DiaperChangeTypesChildReport(PermissionRequiredMixin, DetailView):
"""Graph of diaper changes by day and type.""" """Graph of diaper changes by day and type.
"""
model = Child model = Child
permission_required = ('core.view_child',) permission_required = ('core.view_child',)
template_name = 'reports/diaperchange_types.html' template_name = 'reports/diaperchange_types.html'
@ -35,12 +40,16 @@ class DiaperChangeTypesChildReport(PermissionRequiredMixin, DetailView):
context = super(DiaperChangeTypesChildReport, self).get_context_data( context = super(DiaperChangeTypesChildReport, self).get_context_data(
**kwargs) **kwargs)
child = context['object'] child = context['object']
context['html'], context['javascript'] = diaperchange_types(child) changes = DiaperChange.objects.filter(child=child)
if changes:
context['html'], context['javascript'] = diaperchange_types(
changes)
return context return context
class SleepPatternChildReport(PermissionRequiredMixin, DetailView): class SleepPatternChildReport(PermissionRequiredMixin, DetailView):
"""Graph of sleep pattern comparing sleep to wake times by day.""" """Graph of sleep pattern comparing sleep to wake times by day.
"""
model = Child model = Child
permission_required = ('core.view_child',) permission_required = ('core.view_child',)
template_name = 'reports/sleep_pattern.html' template_name = 'reports/sleep_pattern.html'
@ -54,12 +63,15 @@ class SleepPatternChildReport(PermissionRequiredMixin, DetailView):
context = super(SleepPatternChildReport, self).get_context_data( context = super(SleepPatternChildReport, self).get_context_data(
**kwargs) **kwargs)
child = context['object'] child = context['object']
context['html'], context['javascript'] = sleep_pattern(child) instances = Sleep.objects.filter(child=child).order_by('start')
if instances:
context['html'], context['javascript'] = sleep_pattern(instances)
return context return context
class SleepTotalsChildReport(PermissionRequiredMixin, DetailView): class SleepTotalsChildReport(PermissionRequiredMixin, DetailView):
"""Graph of total sleep by day.""" """Graph of total sleep by day.
"""
model = Child model = Child
permission_required = ('core.view_child',) permission_required = ('core.view_child',)
template_name = 'reports/sleep_totals.html' template_name = 'reports/sleep_totals.html'
@ -73,7 +85,9 @@ class SleepTotalsChildReport(PermissionRequiredMixin, DetailView):
context = super(SleepTotalsChildReport, self).get_context_data( context = super(SleepTotalsChildReport, self).get_context_data(
**kwargs) **kwargs)
child = context['object'] child = context['object']
context['html'], context['javascript'] = sleep_totals(child) instances = Sleep.objects.filter(child=child).order_by('start')
if instances:
context['html'], context['javascript'] = sleep_totals(instances)
return context return context