mirror of https://github.com/snachodog/mybuddy.git
Add graph handling for sleep entry start and end dates that cross midnight.
This commit is contained in:
parent
9d0572ba92
commit
2320d31d48
|
@ -5,13 +5,14 @@ from collections import OrderedDict
|
|||
|
||||
from django.db.models import Count, Case, When
|
||||
from django.db.models.functions import TruncDate
|
||||
from django.utils import timezone, duration
|
||||
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 core.utils import duration_string
|
||||
|
||||
from .utils import default_graph_layout_options, split_graph_output
|
||||
|
||||
|
@ -58,49 +59,81 @@ def diaperchange_types(child):
|
|||
|
||||
|
||||
def sleep_times(child):
|
||||
# TODO: Handle dates crossing over midnight!
|
||||
"""Create a graph showing blocked out period of sleep during each day."""
|
||||
instances = Sleep.objects.filter(child=child).order_by('start')
|
||||
y_df = pd.DataFrame()
|
||||
text_df = pd.DataFrame()
|
||||
last_end_time = None
|
||||
adjustment = 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()
|
||||
duration = instance.duration
|
||||
|
||||
# Check if the previous entry crossed midnight (see below).
|
||||
if adjustment:
|
||||
# Fake (0) entry to keep the color switching logic working.
|
||||
df_index = _add_sleep_entry(
|
||||
y_df, text_df, 0, adjustment['column'], 0)
|
||||
# Real adjustment entry.
|
||||
df_index = _add_sleep_entry(
|
||||
y_df,
|
||||
text_df,
|
||||
df_index,
|
||||
adjustment['column'],
|
||||
adjustment['duration'],
|
||||
'Asleep {} ({} to {})'.format(
|
||||
duration_string(duration),
|
||||
adjustment['start_time'].strftime('%I:%M %p'),
|
||||
adjustment['end_time'].strftime('%I:%M %p')
|
||||
)
|
||||
)
|
||||
last_end_time = timezone.localtime(adjustment['end_time'])
|
||||
adjustment = None
|
||||
|
||||
# If the dates do not match, set up an adjustment for the next day.
|
||||
if end_time.date() != start_time.date():
|
||||
adj_start_time = end_time.replace(hour=0, minute=0, second=0)
|
||||
adjustment = {
|
||||
'column': end_time.date().isoformat(),
|
||||
'start_time': adj_start_time,
|
||||
'end_time': end_time,
|
||||
'duration': (end_time - adj_start_time).seconds/60
|
||||
}
|
||||
|
||||
# Adjust end_time for the current entry.
|
||||
end_time = end_time.replace(
|
||||
day=start_time.day, hour=23, minute=59, second=0)
|
||||
duration = end_time - start_time
|
||||
|
||||
if start_date not in y_df:
|
||||
y_df.assign(**{start_date: 0 in range(0, len(y_df.index))})
|
||||
text_df.assign(**{start_date: 0 in range(0, len(y_df.index))})
|
||||
last_end_time = start_time.replace(hour=0, minute=0, second=0)
|
||||
df_index = 0
|
||||
|
||||
# Awake time.
|
||||
y_df.set_value(
|
||||
df_index, start_date, (start_time - last_end_time).seconds/60,
|
||||
)
|
||||
text_df.set_value(
|
||||
df_index = _add_sleep_entry(
|
||||
y_df,
|
||||
text_df,
|
||||
df_index,
|
||||
start_date,
|
||||
'Awake for from {} to {} ({})'.format(
|
||||
last_end_time.strftime('%I:%M %p'),
|
||||
start_time.strftime('%I:%M %p'),
|
||||
duration.duration_string(start_time - last_end_time)
|
||||
(start_time - last_end_time).seconds/60
|
||||
)
|
||||
)
|
||||
df_index += 1
|
||||
|
||||
# Asleep time.
|
||||
y_df.set_value(df_index, start_date, instance.duration.seconds/60)
|
||||
text_df.set_value(
|
||||
df_index = _add_sleep_entry(
|
||||
y_df,
|
||||
text_df,
|
||||
df_index,
|
||||
start_date,
|
||||
'Asleep for from {} to {} ({})'.format(
|
||||
duration.seconds/60,
|
||||
'Asleep {} ({} to {})'.format(
|
||||
duration_string(duration),
|
||||
start_time.strftime('%I:%M %p'),
|
||||
end_time.strftime('%I:%M %p'),
|
||||
duration.duration_string(instance.duration)
|
||||
end_time.strftime('%I:%M %p')
|
||||
)
|
||||
)
|
||||
df_index += 1
|
||||
|
||||
last_end_time = end_time
|
||||
|
||||
dates = list(y_df)
|
||||
|
@ -151,3 +184,16 @@ def sleep_times(child):
|
|||
})
|
||||
output = plotly.plot(fig, output_type='div', include_plotlyjs=False)
|
||||
return split_graph_output(output)
|
||||
|
||||
|
||||
def _add_sleep_entry(y_df, text_df, index, column, duration, text=''):
|
||||
"""Create a duration and text description entry in a DataFrame and return
|
||||
the next index on success."""
|
||||
if column not in y_df:
|
||||
y_df.assign(**{column: 0 in range(0, len(y_df.index))})
|
||||
text_df.assign(**{column: 0 in range(0, len(text_df.index))})
|
||||
index = 0
|
||||
|
||||
y_df.set_value(index, column, duration)
|
||||
text_df.set_value(index, column, text)
|
||||
return index + 1
|
||||
|
|
Loading…
Reference in New Issue