2017-11-10 12:20:34 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
2023-09-27 13:24:53 +00:00
|
|
|
from datetime import datetime, timedelta
|
2019-04-14 20:32:46 +00:00
|
|
|
from django.utils.translation import gettext as _
|
2023-09-27 13:24:53 +00:00
|
|
|
from django.db.models.manager import BaseManager
|
2019-04-14 20:32:46 +00:00
|
|
|
|
2017-11-10 12:20:34 +00:00
|
|
|
import plotly.offline as plotly
|
|
|
|
import plotly.graph_objs as go
|
|
|
|
|
|
|
|
from reports import utils
|
|
|
|
|
|
|
|
|
2023-09-27 13:24:53 +00:00
|
|
|
def weight_change(
|
|
|
|
actual_weights: BaseManager, percentile_weights: BaseManager, birthday: datetime
|
|
|
|
):
|
2017-11-10 12:20:34 +00:00
|
|
|
"""
|
|
|
|
Create a graph showing weight over time.
|
2023-09-27 13:24:53 +00:00
|
|
|
:param actual_weights: a QuerySet of Weight instances.
|
|
|
|
:param percentile_weights: a QuerySet of Weight Percentile instances.
|
|
|
|
:param birthday: a datetime of the child's birthday
|
2024-01-28 03:42:12 +00:00
|
|
|
:returns: a tuple of the graph's html and javascript.
|
2017-11-10 12:20:34 +00:00
|
|
|
"""
|
2023-09-27 13:24:53 +00:00
|
|
|
actual_weights = actual_weights.order_by("-date")
|
2017-11-10 12:20:34 +00:00
|
|
|
|
2023-09-27 13:24:53 +00:00
|
|
|
weighing_dates: list[datetime] = list(actual_weights.values_list("date", flat=True))
|
|
|
|
measured_weights = list(actual_weights.values_list("weight", flat=True))
|
|
|
|
|
|
|
|
actual_weights_trace = go.Scatter(
|
2022-02-10 00:00:30 +00:00
|
|
|
name=_("Weight"),
|
2023-09-27 13:24:53 +00:00
|
|
|
x=weighing_dates,
|
|
|
|
y=measured_weights,
|
2022-02-10 00:00:30 +00:00
|
|
|
fill="tozeroy",
|
2023-09-27 13:24:53 +00:00
|
|
|
mode="lines+markers",
|
2017-11-10 12:20:34 +00:00
|
|
|
)
|
|
|
|
|
2023-09-27 13:24:53 +00:00
|
|
|
if percentile_weights:
|
|
|
|
dates = list(
|
|
|
|
map(
|
|
|
|
lambda timedelta: birthday + timedelta,
|
|
|
|
percentile_weights.values_list("age_in_days", flat=True),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
# reduce percentile data xrange to end 1 day after last weigh in for formatting purposes
|
|
|
|
# https://github.com/babybuddy/babybuddy/pull/708#discussion_r1332335789
|
|
|
|
last_date_for_percentiles = max(weighing_dates) + timedelta(days=2)
|
|
|
|
dates = dates[: dates.index(last_date_for_percentiles)]
|
|
|
|
|
|
|
|
percentile_weight_3_trace = go.Scatter(
|
|
|
|
name=_("P3"),
|
|
|
|
x=dates,
|
|
|
|
y=list(percentile_weights.values_list("p3_weight", flat=True)),
|
|
|
|
line={"color": "red"},
|
|
|
|
)
|
|
|
|
percentile_weight_15_trace = go.Scatter(
|
|
|
|
name=_("P15"),
|
|
|
|
x=dates,
|
|
|
|
y=list(percentile_weights.values_list("p15_weight", flat=True)),
|
|
|
|
line={"color": "orange"},
|
|
|
|
)
|
|
|
|
percentile_weight_50_trace = go.Scatter(
|
|
|
|
name=_("P50"),
|
|
|
|
x=dates,
|
|
|
|
y=list(percentile_weights.values_list("p50_weight", flat=True)),
|
|
|
|
line={"color": "green"},
|
|
|
|
)
|
|
|
|
percentile_weight_85_trace = go.Scatter(
|
|
|
|
name=_("P85"),
|
|
|
|
x=dates,
|
|
|
|
y=list(percentile_weights.values_list("p85_weight", flat=True)),
|
|
|
|
line={"color": "orange"},
|
|
|
|
)
|
|
|
|
percentile_weight_97_trace = go.Scatter(
|
|
|
|
name=_("P97"),
|
|
|
|
x=dates,
|
|
|
|
y=list(percentile_weights.values_list("p97_weight", flat=True)),
|
|
|
|
line={"color": "red"},
|
|
|
|
)
|
|
|
|
|
|
|
|
data = [
|
|
|
|
actual_weights_trace,
|
|
|
|
]
|
2017-11-10 12:20:34 +00:00
|
|
|
layout_args = utils.default_graph_layout_options()
|
2022-02-10 00:00:30 +00:00
|
|
|
layout_args["barmode"] = "stack"
|
|
|
|
layout_args["title"] = _("<b>Weight</b>")
|
|
|
|
layout_args["xaxis"]["title"] = _("Date")
|
|
|
|
layout_args["xaxis"]["rangeselector"] = utils.rangeselector_date()
|
|
|
|
layout_args["yaxis"]["title"] = _("Weight")
|
2023-09-27 13:24:53 +00:00
|
|
|
if percentile_weights:
|
|
|
|
# zoom in on the relevant dates
|
|
|
|
layout_args["xaxis"]["range"] = [
|
|
|
|
birthday,
|
|
|
|
max(weighing_dates) + timedelta(days=1),
|
|
|
|
]
|
|
|
|
layout_args["yaxis"]["range"] = [0, max(measured_weights) * 1.5]
|
|
|
|
data.extend(
|
|
|
|
[
|
|
|
|
percentile_weight_97_trace,
|
|
|
|
percentile_weight_85_trace,
|
|
|
|
percentile_weight_50_trace,
|
|
|
|
percentile_weight_15_trace,
|
|
|
|
percentile_weight_3_trace,
|
|
|
|
]
|
|
|
|
)
|
2017-11-10 12:20:34 +00:00
|
|
|
|
2023-09-27 13:24:53 +00:00
|
|
|
fig = go.Figure({"data": data, "layout": go.Layout(**layout_args)})
|
2022-02-10 00:00:30 +00:00
|
|
|
output = plotly.plot(fig, output_type="div", include_plotlyjs=False)
|
2017-11-10 12:20:34 +00:00
|
|
|
return utils.split_graph_output(output)
|