From 2519dad74cb926de64e5a65d4dcf4eb5a3a63567 Mon Sep 17 00:00:00 2001 From: Pavol Gazda Date: Tue, 3 Jan 2023 00:27:15 +0100 Subject: [PATCH] Add reports for temperature readings --- reports/graphs/__init__.py | 1 + reports/graphs/temperature_change.py | 34 +++++++++++++++++++ reports/templates/reports/report_list.html | 1 + .../templates/reports/temperature_change.html | 10 ++++++ reports/urls.py | 5 +++ reports/utils.py | 18 ++++++++++ reports/views.py | 18 ++++++++++ 7 files changed, 87 insertions(+) create mode 100644 reports/graphs/temperature_change.py create mode 100644 reports/templates/reports/temperature_change.html diff --git a/reports/graphs/__init__.py b/reports/graphs/__init__.py index 6d31a582..712694df 100644 --- a/reports/graphs/__init__.py +++ b/reports/graphs/__init__.py @@ -9,5 +9,6 @@ from .height_change import height_change # NOQA from .pumping_amounts import pumping_amounts # NOQA from .sleep_pattern import sleep_pattern # NOQA from .sleep_totals import sleep_totals # NOQA +from .temperature_change import temperature_change # NOQA from .tummytime_duration import tummytime_duration # NOQA from .weight_change import weight_change # NOQA diff --git a/reports/graphs/temperature_change.py b/reports/graphs/temperature_change.py new file mode 100644 index 00000000..25cf6bc7 --- /dev/null +++ b/reports/graphs/temperature_change.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +from django.utils.translation import gettext as _ + +import plotly.offline as plotly +import plotly.graph_objs as go + +from reports import utils + + +def temperature_change(objects): + """ + Create a graph showing temperature over time. + :param objects: a QuerySet of Temperature instances. + :returns: a tuple of the graph's html and javascript. + """ + objects = objects.order_by("-time") + + trace = go.Scatter( + name=_("Temperature"), + x=list(objects.values_list("time", flat=True)), + y=list(objects.values_list("temperature", flat=True)), + fill="tozeroy", + ) + + layout_args = utils.default_graph_layout_options() + layout_args["barmode"] = "stack" + layout_args["title"] = _("Temperature") + layout_args["xaxis"]["title"] = _("Time") + layout_args["xaxis"]["rangeselector"] = utils.rangeselector_time() + layout_args["yaxis"]["title"] = _("Temperature") + + fig = go.Figure({"data": [trace], "layout": go.Layout(**layout_args)}) + output = plotly.plot(fig, output_type="div", include_plotlyjs=False) + return utils.split_graph_output(output) diff --git a/reports/templates/reports/report_list.html b/reports/templates/reports/report_list.html index af62656e..2a4f3856 100644 --- a/reports/templates/reports/report_list.html +++ b/reports/templates/reports/report_list.html @@ -27,6 +27,7 @@ {% trans "Pumping Amounts" %} {% trans "Sleep Pattern" %} {% trans "Sleep Totals" %} + {% trans "Temperature" %} {% trans "Tummy Time Durations (Sum)" %} {% trans "Weight" %} diff --git a/reports/templates/reports/temperature_change.html b/reports/templates/reports/temperature_change.html new file mode 100644 index 00000000..2bd0cbc1 --- /dev/null +++ b/reports/templates/reports/temperature_change.html @@ -0,0 +1,10 @@ +{% extends 'reports/report_base.html' %} +{% load i18n %} + +{% block title %}{% trans "Temperature" %} - {{ object }}{% endblock %} + +{% block breadcrumbs %} + {{ block.super }} + {% include 'reports/breadcrumb_common_chunk.html' with target_url='reports:report-temperature-change-child' %} + +{% endblock %} diff --git a/reports/urls.py b/reports/urls.py index 1b36320f..a30e85bf 100644 --- a/reports/urls.py +++ b/reports/urls.py @@ -66,6 +66,11 @@ urlpatterns = [ views.SleepTotalsChildReport.as_view(), name="report-sleep-totals-child", ), + path( + "children//reports/temperature/temperature/", + views.TemperatureChangeChildReport.as_view(), + name="report-temperature-change-child", + ), path( "children//reports/tummy-time/duration/", views.TummyTimeDurationChildReport.as_view(), diff --git a/reports/utils.py b/reports/utils.py index 2eebf429..f791d976 100644 --- a/reports/utils.py +++ b/reports/utils.py @@ -50,6 +50,24 @@ def rangeselector_date(): } +def rangeselector_time(): + """ + Graph time range selectors settings for 12h, 24h, 48h, 3d and all. + :returns: a dict of settings for the selectors. + """ + return { + "bgcolor": "rgb(35, 149, 86)", + "activecolor": "rgb(25, 108, 62)", + "buttons": [ + {"count": 12, "label": "12h", "step": "hour", "stepmode": "backward"}, + {"count": 24, "label": "24h", "step": "hour", "stepmode": "backward"}, + {"count": 48, "label": "48h", "step": "hour", "stepmode": "backward"}, + {"count": 3, "label": "3d", "step": "day", "stepmode": "backward"}, + {"count": 7, "label": "7d", "step": "day", "stepmode": "backward"}, + {"step": "all"}, + ], + } + def split_graph_output(output): """ Split out of a Plotly graph in to html and javascript. diff --git a/reports/views.py b/reports/views.py index 968a5a36..ab8ccb8e 100644 --- a/reports/views.py +++ b/reports/views.py @@ -242,6 +242,24 @@ class SleepTotalsChildReport(PermissionRequiredMixin, DetailView): return context +class TemperatureChangeChildReport(PermissionRequiredMixin, DetailView): + """ + Graph of temperature change over time. + """ + + model = models.Child + permission_required = ("core.view_child",) + template_name = "reports/temperature_change.html" + + def get_context_data(self, **kwargs): + context = super(TemperatureChangeChildReport, self).get_context_data(**kwargs) + child = context["object"] + objects = models.Temperature.objects.filter(child=child) + if objects: + context["html"], context["js"] = graphs.temperature_change(objects) + return context + + class TummyTimeDurationChildReport(PermissionRequiredMixin, DetailView): """ Graph of tummy time durations over time.