Create a sleep times graph (WIP).

Adding a Pandas requirement for dealing with the data and separating graph processing in to a separate file.
This commit is contained in:
Christopher Charbonneau Wells 2017-08-25 12:19:06 -04:00
parent ae71c5933e
commit 9a2facfa72
3 changed files with 133 additions and 62 deletions

View File

@ -8,6 +8,7 @@ djangorestframework = "*"
django-filter = "*"
django-widget-tweaks = "*"
plotly = "*"
pandas = "*"
[dev-packages]
faker = "*"

113
reports/graphs.py Normal file
View File

@ -0,0 +1,113 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db.models import Count, Case, When
from django.db.models.functions import TruncDate
from django.utils import timezone
import pandas as pd
import plotly.offline as plotly
import plotly.graph_objs as go
from core.models import DiaperChange, Sleep
from .utils import default_graph_layout_options, split_graph_output
def diaperchange_types(child):
changes = DiaperChange.objects.filter(child=child) \
.annotate(date=TruncDate('time')) \
.values('date') \
.annotate(wet_count=Count(Case(When(wet=True, then=1)))) \
.annotate(solid_count=Count(Case(When(solid=True, then=1)))) \
.annotate(total=Count('id')) \
.order_by('-date')
solid_trace = go.Scatter(
mode='markers',
name='Solid changes',
x=list(changes.values_list('date', flat=True)),
y=list(changes.values_list('solid_count', flat=True)),
)
wet_trace = go.Scatter(
mode='markers',
name='Wet changes',
x=list(changes.values_list('date', flat=True)),
y=list(changes.values_list('wet_count', flat=True))
)
total_trace = go.Scatter(
name='Total changes',
x=list(changes.values_list('date', flat=True)),
y=list(changes.values_list('total', flat=True))
)
layout_args = default_graph_layout_options()
layout_args['barmode'] = 'stack'
layout_args['title'] = 'Diaper Change types'
layout_args['xaxis']['title'] = 'Date'
layout_args['yaxis']['title'] = 'Number of changes'
fig = go.Figure({
'data': [solid_trace, wet_trace, total_trace],
'layout': go.Layout(**layout_args)
})
output = plotly.plot(fig, output_type='div', include_plotlyjs=False)
return split_graph_output(output)
def sleep_times(child):
instances = Sleep.objects.filter(child=child).order_by('start')
df = pd.DataFrame()
last_end_time = None
df_index = 0
for instance in instances:
start_time = timezone.localtime(instance.start)
end_time = timezone.localtime(instance.end)
start_date = start_time.date().isoformat()
if start_date not in df:
df.assign(**{start_date: 0 in range(0, len(df.index))})
last_end_time = start_time.replace(hour=0, minute=0, second=0)
df_index = 0
df.set_value(
df_index, start_date, (start_time - last_end_time).seconds/60)
df_index += 1
df.set_value(df_index, start_date, instance.duration.seconds/60)
df_index += 1
last_end_time = end_time
dates = list(df)
traces = []
color = 'rgba(255, 255, 255, 0)'
for index, row in df.iterrows():
traces.append(go.Bar(
x=dates,
y=row,
marker={'color': color},
showlegend=False,
))
if color == 'rgba(255, 255, 255, 0)':
color = 'rgb(0, 0, 255)'
else:
color = 'rgba(255, 255, 255, 0)'
layout_args = default_graph_layout_options()
layout_args['barmode'] = 'stack'
layout_args['hovermode'] = 'closest'
layout_args['title'] = 'Sleep entries per day'
layout_args['xaxis']['title'] = 'Date'
layout_args['xaxis']['type'] = 'category'
layout_args['yaxis']['title'] = 'Time of day'
layout_args['yaxis']['rangemode'] = 'tozero'
layout_args['yaxis']['tickmode'] = 'array'
layout_args['yaxis']['tickvals'] = list(range(0, 1441, 60))
layout_args['yaxis']['ticktext'] = list(range(0, 1441, 60))
fig = go.Figure({
'data': traces,
'layout': go.Layout(**layout_args)
})
output = plotly.plot(fig, output_type='div', include_plotlyjs=False)
return split_graph_output(output)

View File

@ -2,82 +2,39 @@
from __future__ import unicode_literals
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.db.models import Count, Case, When
from django.db.models.functions import TruncDate
from django.views.generic.detail import DetailView
import plotly.offline as plotly
import plotly.graph_objs as go
from core.models import Child
from core.models import Child, DiaperChange
from .utils import default_graph_layout_options, split_graph_output
from .graphs import diaperchange_types, sleep_times
class DiaperChangesChildReport(PermissionRequiredMixin, DetailView):
"""All sleep data for a child."""
"""Diaper change information by type."""
model = Child
permission_required = ('core.view_child',)
template_name = 'reports/diaperchange.html'
def get_context_data(self, **kwargs):
context = super(DiaperChangesChildReport, self).get_context_data(**kwargs)
child = context['object']
context['html'], context['javascript'] = diaperchange_types(child)
return context
class SleepChildReport(PermissionRequiredMixin, DetailView):
"""All sleep times by date."""
model = Child
permission_required = ('core.view_child',)
template_name = 'reports/sleep.html'
def __init__(self):
super(DiaperChangesChildReport, self).__init__()
super(SleepChildReport, self).__init__()
self.html = ''
self.javascript = ''
def get_context_data(self, **kwargs):
context = super(DiaperChangesChildReport, self).get_context_data(**kwargs)
context = super(SleepChildReport, self).get_context_data(**kwargs)
child = context['object']
self._change_types_over_time(child)
context['html'] = self.html
context['javascript'] = self.javascript
context['html'], context['javascript'] = sleep_times(child)
return context
def _change_types_over_time(self, child):
changes = DiaperChange.objects.filter(child=child) \
.annotate(date=TruncDate('time')) \
.values('date') \
.annotate(wet_count=Count(Case(When(wet=True, then=1)))) \
.annotate(solid_count=Count(Case(When(solid=True, then=1)))) \
.annotate(total=Count('id')) \
.order_by('-date')
solid_trace = go.Scatter(
mode='markers',
name='Solid changes',
x=list(changes.values_list('date', flat=True)),
y=list(changes.values_list('solid_count', flat=True)),
)
wet_trace = go.Scatter(
mode='markers',
name='Wet changes',
x=list(changes.values_list('date', flat=True)),
y=list(changes.values_list('wet_count', flat=True))
)
total_trace = go.Scatter(
name='Total changes',
x=list(changes.values_list('date', flat=True)),
y=list(changes.values_list('total', flat=True))
)
layout_args = default_graph_layout_options()
layout_args['barmode'] = 'stack'
layout_args['title'] = 'Diaper change types over time'
layout_args['xaxis']['title'] = 'Date'
layout_args['yaxis']['title'] = 'Number of changes'
fig = go.Figure({
'data': [solid_trace, wet_trace, total_trace],
'layout': go.Layout(**layout_args)
})
output = plotly.plot(fig, output_type='div', include_plotlyjs=False)
html, javascript = split_graph_output(output)
self.html += '<a name="change_types_over_time">' + html
self.javascript += javascript
class SleepChildReport(PermissionRequiredMixin, DetailView):
"""All sleep data for a child."""
model = Child
permission_required = ('core.view_child',)
template_name = 'reports/sleep.html'