Revert custom graph works and add Plotly-based example.

This commit is contained in:
Christopher Charbonneau Wells 2017-08-23 09:04:05 -04:00
parent 7ba85f29d4
commit ed96814b10
6 changed files with 70 additions and 80 deletions

View File

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

View File

@ -0,0 +1,19 @@
{% extends 'reports/report_base.html' %}
{% block title %}Diaper Change Report - {{ object }}{% endblock %}
{% block content %}
<div>
Diaper change report for {{ object }}.
</div>
<div style="min-height: 600px;">
{{ html|safe }}
</div>
{% endblock %}
{% block javascript %}
{{ block.super }}
{{ javascript|safe }}
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends 'babyblotter/page.html' %}
{% block javascript %}
<script src="https://cdn.plot.ly/plotly-latest.js"></script>
{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends 'babyblotter/page.html' %}
{% extends 'reports/report_base.html' %}
{% block title %}Sleep Report - {{ object }}{% endblock %}
@ -7,54 +7,6 @@
Sleep report for {{ object }}.
</div>
<pre>{{ stats|pprint }}</pre>
<div class="row">
<div class="col-md-1 d-flex align-self-center">
Tuesday, 22 Aug.
</div>
<div class="col-md-11">
<div class="progress" style="height: 32px; border-radius: 0;">
<div class="progress-bar" role="progressbar" style="width: 5%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 2%"></div>
<div class="progress-bar" role="progressbar" style="width: 15%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 6%"></div>
<div class="progress-bar" role="progressbar" style="width: 3%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 10%"></div>
<div class="progress-bar" role="progressbar" style="width: 5%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 2%"></div>
<div class="progress-bar" role="progressbar" style="width: 15%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 6%"></div>
<div class="progress-bar" role="progressbar" style="width: 3%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 10%"></div>
<div class="progress-bar" role="progressbar" style="width: 8%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 10%"></div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-1">
Monday, 21 Aug.
</div>
<div class="col-md-11">
<div class="progress" style="height: 32px; border-radius: 0;">
<div class="progress-bar" role="progressbar" style="width: 5%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 2%"></div>
<div class="progress-bar" role="progressbar" style="width: 3%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 10%"></div>
<div class="progress-bar" role="progressbar" style="width: 5%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 2%"></div>
<div class="progress-bar" role="progressbar" style="width: 15%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 6%"></div>
<div class="progress-bar" role="progressbar" style="width: 3%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 10%"></div>
<div class="progress-bar" role="progressbar" style="width: 8%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 10%"></div>
<div class="progress-bar" role="progressbar" style="width: 15%; background: none;"></div>
<div class="progress-bar bg-info" role="progressbar" style="width: 6%"></div>
</div>
</div>
</div>
Test
{% endblock %}

View File

@ -6,6 +6,8 @@ from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^reports/(?P<slug>[^/.]+)/changes/$',
views.DiaperChangeReport.as_view(), name='report-diaperchange'),
url(r'^reports/(?P<slug>[^/.]+)/sleep/$',
views.SleepReport.as_view(), name='report-sleep'),
]

View File

@ -1,13 +1,50 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from collections import OrderedDict
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.utils import timezone
from django.db.models import Count
from django.db.models.functions import TruncDate
from django.views.generic.detail import DetailView
from core.models import Child, Sleep
import plotly.offline as plotly
import plotly.graph_objs as go
from core.models import Child, DiaperChange
class DiaperChangeReport(PermissionRequiredMixin, DetailView):
"""All sleep data for a child."""
model = Child
permission_required = ('core.view_child',)
template_name = 'reports/diaperchange.html'
def get_context_data(self, **kwargs):
context = super(DiaperChangeReport, self).get_context_data(**kwargs)
child = context['object']
# TODO: Move this logic to the model? Where should data processing like
# this happen?
changes = DiaperChange.objects.filter(child=child)\
.annotate(date=TruncDate('time'))\
.values('date')\
.annotate(count=Count('id'))\
.order_by('-date')
trace1 = go.Scatter(
x=list(changes.values_list('date', flat=True)),
y=list(changes.values_list('count', flat=True))
)
fig = go.Figure({
"data": [trace1],
"layout": go.Layout(title='Diaper Changes')
})
div = plotly.plot(fig, output_type='div', include_plotlyjs=False)
html, javascript = div.split('<script')
context['html'] = html
context['javascript'] = '<script' + javascript
return context
class SleepReport(PermissionRequiredMixin, DetailView):
@ -18,30 +55,4 @@ class SleepReport(PermissionRequiredMixin, DetailView):
def get_context_data(self, **kwargs):
context = super(SleepReport, self).get_context_data(**kwargs)
child = context['object']
sleep_entries = Sleep.objects.filter(child=child).order_by('-end')
diff = timezone.localtime().date() - timezone.localtime(sleep_entries.last().end).date()
stats = OrderedDict()
for x in range(0, diff.days + 1):
key = (timezone.localtime() - timezone.timedelta(days=x))
stats[key.date()] = []
last = None
for entry in sleep_entries:
start = timezone.localtime(entry.start)
end = timezone.localtime(entry.end)
if not stats[end.date()]:
last = end.replace(hour=23, minute=59, second=59)
# TODO: Account for sleep sessions crossing midnight.
stats[start.date()].append((
(last - end).seconds/86400 * 100,
(end - start).seconds/86400 * 100
))
last = start
context['stats'] = stats
return context