diff --git a/core/tests/tests_forms.py b/core/tests/tests_forms.py
index 89346cdc..4f8fe53f 100644
--- a/core/tests/tests_forms.py
+++ b/core/tests/tests_forms.py
@@ -791,7 +791,7 @@ class TimerFormsTestCase(FormsTestCaseBase):
class ValidationsTestCase(FormsTestCaseBase):
def test_validate_date(self):
- future = timezone.localtime() + timezone.timedelta(days=1)
+ future = timezone.localtime() + timezone.timedelta(days=10)
params = {
"child": self.child,
"weight": "8.5",
diff --git a/reports/graphs/bmi_change.py b/reports/graphs/bmi_change.py
index 2dd8b471..caaee61e 100644
--- a/reports/graphs/bmi_change.py
+++ b/reports/graphs/bmi_change.py
@@ -11,7 +11,7 @@ def bmi_change(objects):
"""
Create a graph showing bmi over time.
:param objects: a QuerySet of BMI instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
objects = objects.order_by("-date")
diff --git a/reports/graphs/diaperchange_amounts.py b/reports/graphs/diaperchange_amounts.py
index 196c4986..dd36248c 100644
--- a/reports/graphs/diaperchange_amounts.py
+++ b/reports/graphs/diaperchange_amounts.py
@@ -12,7 +12,7 @@ def diaperchange_amounts(instances):
"""
Create a graph showing daily diaper change amounts over time.
:param instances: a QuerySet of DiaperChange instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
totals = {}
for instance in instances:
diff --git a/reports/graphs/diaperchange_intervals.py b/reports/graphs/diaperchange_intervals.py
index d8cca9b3..2973408a 100644
--- a/reports/graphs/diaperchange_intervals.py
+++ b/reports/graphs/diaperchange_intervals.py
@@ -16,7 +16,7 @@ def diaperchange_intervals(changes):
"""
Create a graph showing intervals of diaper changes.
:param changes: a QuerySet of Diaper Change instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
changes = changes.order_by("time")
@@ -65,6 +65,9 @@ def diaperchange_intervals(changes):
layout_args["barmode"] = "stack"
layout_args["title"] = _("Diaper Change Intervals")
layout_args["xaxis"]["title"] = _("Date")
+ layout_args["xaxis"]["type"] = "date"
+ layout_args["xaxis"]["autorange"] = True
+ layout_args["xaxis"]["autorangeoptions"] = utils.autorangeoptions(trace_total.x)
layout_args["xaxis"]["rangeselector"] = utils.rangeselector_date()
layout_args["yaxis"]["title"] = _("Interval (hours)")
diff --git a/reports/graphs/diaperchange_lifetimes.py b/reports/graphs/diaperchange_lifetimes.py
index 33070bae..bc31d81b 100644
--- a/reports/graphs/diaperchange_lifetimes.py
+++ b/reports/graphs/diaperchange_lifetimes.py
@@ -11,7 +11,7 @@ def diaperchange_lifetimes(changes):
"""
Create a graph showing how long diapers last (time between changes).
:param changes: a QuerySet of Diaper Change instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
changes = changes.order_by("time")
durations = []
diff --git a/reports/graphs/diaperchange_types.py b/reports/graphs/diaperchange_types.py
index 88000195..9a1ac528 100644
--- a/reports/graphs/diaperchange_types.py
+++ b/reports/graphs/diaperchange_types.py
@@ -14,7 +14,7 @@ def diaperchange_types(changes):
"""
Create a graph showing types of totals for diaper changes.
:param changes: a QuerySet of Diaper Change instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
changes = (
changes.annotate(date=TruncDate("time"))
@@ -47,6 +47,9 @@ def diaperchange_types(changes):
layout_args["barmode"] = "stack"
layout_args["title"] = _("Diaper Change Types")
layout_args["xaxis"]["title"] = _("Date")
+ layout_args["xaxis"]["type"] = "date"
+ layout_args["xaxis"]["autorange"] = True
+ layout_args["xaxis"]["autorangeoptions"] = utils.autorangeoptions(total_trace.x)
layout_args["xaxis"]["rangeselector"] = utils.rangeselector_date()
layout_args["yaxis"]["title"] = _("Number of changes")
diff --git a/reports/graphs/feeding_amounts.py b/reports/graphs/feeding_amounts.py
index 68a76443..8592ed8a 100644
--- a/reports/graphs/feeding_amounts.py
+++ b/reports/graphs/feeding_amounts.py
@@ -13,7 +13,7 @@ def feeding_amounts(instances):
"""
Create a graph showing daily feeding amounts over time.
:param instances: a QuerySet of Feeding instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
feeding_types, feeding_types_desc = map(
list, zip(*models.Feeding._meta.get_field("type").choices)
diff --git a/reports/graphs/feeding_duration.py b/reports/graphs/feeding_duration.py
index ad02ab03..89768e5f 100644
--- a/reports/graphs/feeding_duration.py
+++ b/reports/graphs/feeding_duration.py
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
+import time
+
from django.db.models import Count, Sum
from django.db.models.functions import TruncDate
from django.utils.translation import gettext as _
@@ -20,7 +22,7 @@ def feeding_duration(instances):
was equal to seven.
:param instances: a QuerySet of Feeding instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
totals = (
instances.annotate(date=TruncDate("start"))
@@ -54,6 +56,9 @@ def feeding_duration(instances):
layout_args = utils.default_graph_layout_options()
layout_args["title"] = _("Average Feeding Durations")
layout_args["xaxis"]["title"] = _("Date")
+ layout_args["xaxis"]["type"] = "date"
+ layout_args["xaxis"]["autorange"] = True
+ layout_args["xaxis"]["autorangeoptions"] = utils.autorangeoptions(trace_avg.x)
layout_args["xaxis"]["rangeselector"] = utils.rangeselector_date()
layout_args["yaxis"]["title"] = _("Average duration (minutes)")
layout_args["yaxis2"] = dict(layout_args["yaxis"])
diff --git a/reports/graphs/feeding_intervals.py b/reports/graphs/feeding_intervals.py
index 35db96a9..f75bce51 100644
--- a/reports/graphs/feeding_intervals.py
+++ b/reports/graphs/feeding_intervals.py
@@ -16,7 +16,7 @@ def feeding_intervals(instances):
Create a graph showing intervals of feeding instances over time.
:param instances: a QuerySet of Feeding instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
totals = instances.annotate(count=Count("id")).order_by("start")
@@ -40,6 +40,9 @@ def feeding_intervals(instances):
layout_args = utils.default_graph_layout_options()
layout_args["title"] = _("Feeding intervals")
layout_args["xaxis"]["title"] = _("Date")
+ layout_args["xaxis"]["type"] = "date"
+ layout_args["xaxis"]["autorange"] = True
+ layout_args["xaxis"]["autorangeoptions"] = utils.autorangeoptions(trace_avg.x)
layout_args["xaxis"]["rangeselector"] = utils.rangeselector_date()
layout_args["yaxis"]["title"] = _("Feeding interval (hours)")
diff --git a/reports/graphs/head_circumference_change.py b/reports/graphs/head_circumference_change.py
index 9d8d3afd..fce43a6f 100644
--- a/reports/graphs/head_circumference_change.py
+++ b/reports/graphs/head_circumference_change.py
@@ -11,7 +11,7 @@ def head_circumference_change(objects):
"""
Create a graph showing head_circumference over time.
:param objects: a QuerySet of Head Circumference instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
objects = objects.order_by("-date")
diff --git a/reports/graphs/height_change.py b/reports/graphs/height_change.py
index aa662f9d..6c0ef21d 100644
--- a/reports/graphs/height_change.py
+++ b/reports/graphs/height_change.py
@@ -17,7 +17,7 @@ def height_change(
:param actual_heights: a QuerySet of Height instances.
:param percentile_heights: a QuerySet of Height Percentile instances.
:param birthday: a datetime of the child's birthday
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
actual_heights = actual_heights.order_by("-date")
diff --git a/reports/graphs/pumping_amounts.py b/reports/graphs/pumping_amounts.py
index 85b121a9..a9dc2558 100644
--- a/reports/graphs/pumping_amounts.py
+++ b/reports/graphs/pumping_amounts.py
@@ -12,7 +12,7 @@ def pumping_amounts(objects):
"""
Create a graph showing pumping amounts over time.
:param instances: a QuerySet of Pumping instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
objects = objects.order_by("start")
diff --git a/reports/graphs/sleep_pattern.py b/reports/graphs/sleep_pattern.py
index bf9eddab..95ffeb8f 100644
--- a/reports/graphs/sleep_pattern.py
+++ b/reports/graphs/sleep_pattern.py
@@ -21,7 +21,7 @@ def sleep_pattern(sleeps):
"""
Create a graph showing blocked out periods of sleep during each day.
:param sleeps: a QuerySet of Sleep instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
last_end_time = None
adjustment = None
diff --git a/reports/graphs/sleep_totals.py b/reports/graphs/sleep_totals.py
index f8bb1033..3b6f5ed5 100644
--- a/reports/graphs/sleep_totals.py
+++ b/reports/graphs/sleep_totals.py
@@ -14,7 +14,7 @@ def sleep_totals(instances):
"""
Create a graph showing total time sleeping for each day.
:param instances: a QuerySet of Sleep instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
totals = {}
for instance in instances:
@@ -57,6 +57,9 @@ def sleep_totals(instances):
layout_args["barmode"] = "stack"
layout_args["title"] = _("Sleep Totals")
layout_args["xaxis"]["title"] = _("Date")
+ layout_args["xaxis"]["type"] = "date"
+ layout_args["xaxis"]["autorange"] = True
+ layout_args["xaxis"]["autorangeoptions"] = utils.autorangeoptions(trace.x)
layout_args["xaxis"]["rangeselector"] = utils.rangeselector_date()
layout_args["yaxis"]["title"] = _("Hours of sleep")
diff --git a/reports/graphs/temperature_change.py b/reports/graphs/temperature_change.py
index 2a696772..f46b8ccb 100644
--- a/reports/graphs/temperature_change.py
+++ b/reports/graphs/temperature_change.py
@@ -25,6 +25,9 @@ def temperature_change(objects):
layout_args["barmode"] = "stack"
layout_args["title"] = _("Temperature")
layout_args["xaxis"]["title"] = _("Time")
+ layout_args["xaxis"]["type"] = "date"
+ layout_args["xaxis"]["autorange"] = True
+ layout_args["xaxis"]["autorangeoptions"] = utils.autorangeoptions(trace.x)
layout_args["xaxis"]["rangeselector"] = utils.rangeselector_time()
layout_args["yaxis"]["title"] = _("Temperature")
diff --git a/reports/graphs/tummytime_duration.py b/reports/graphs/tummytime_duration.py
index 06557a55..e1169c11 100644
--- a/reports/graphs/tummytime_duration.py
+++ b/reports/graphs/tummytime_duration.py
@@ -16,7 +16,7 @@ def tummytime_duration(instances):
Create a graph showing total duration of tummy time instances per day.
:param instances: a QuerySet of TummyTime instances.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
totals = (
instances.annotate(date=TruncDate("start"))
@@ -49,6 +49,11 @@ def tummytime_duration(instances):
layout_args = utils.default_graph_layout_options()
layout_args["title"] = _("Total Tummy Time Durations")
layout_args["xaxis"]["title"] = _("Date")
+ layout_args["xaxis"]["type"] = "date"
+ layout_args["xaxis"]["autorange"] = True
+ layout_args["xaxis"]["autorangeoptions"] = utils.autorangeoptions(
+ trace_avg.x, 35000000
+ )
layout_args["xaxis"]["rangeselector"] = utils.rangeselector_date()
layout_args["yaxis"]["title"] = _("Total duration (minutes)")
layout_args["yaxis2"] = dict(layout_args["yaxis"])
diff --git a/reports/graphs/weight_change.py b/reports/graphs/weight_change.py
index 36da9426..4d95ca24 100644
--- a/reports/graphs/weight_change.py
+++ b/reports/graphs/weight_change.py
@@ -17,7 +17,7 @@ def weight_change(
: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
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
actual_weights = actual_weights.order_by("-date")
diff --git a/reports/utils.py b/reports/utils.py
index 2845c0cf..8b266525 100644
--- a/reports/utils.py
+++ b/reports/utils.py
@@ -1,4 +1,21 @@
# -*- coding: utf-8 -*-
+import time
+
+
+def autorangeoptions(dates, padding=10000000):
+ """
+ Default autorange mix and max for all graphs.
+ See: https://github.com/babybuddy/babybuddy/issues/706
+ :param dates: list of datetime.date objects organized latest to oldest.
+ :param padding: additional padding to add to the bounds.
+ :return: a dict of our autorange options.
+ """
+ return dict(
+ {
+ "minallowed": int(time.mktime(dates[-1].timetuple())) * 1000 - padding,
+ "maxallowed": int(time.mktime(dates[0].timetuple())) * 1000 + padding,
+ },
+ )
def default_graph_layout_options():
@@ -73,7 +90,7 @@ def split_graph_output(output):
"""
Split out of a Plotly graph in to html and javascript.
:param output: a string of html and javascript comprising the graph.
- :returns: a tuple of the the graph's html and javascript.
+ :returns: a tuple of the graph's html and javascript.
"""
html, js = output.split("