144 lines
4 KiB
Python
Executable file
144 lines
4 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# TODO this should be in dashboard
|
|
from pathlib import Path
|
|
# from kython.plotting import *
|
|
from csv import DictReader
|
|
from itertools import islice
|
|
|
|
from typing import Dict, Any, NamedTuple
|
|
|
|
# sleep = []
|
|
# with open('2017.csv', 'r') as fo:
|
|
# reader = DictReader(fo)
|
|
# for line in islice(reader, 0, 10):
|
|
# sleep
|
|
# print(line)
|
|
|
|
import matplotlib.pyplot as plt # type: ignore
|
|
from numpy import genfromtxt # type: ignore
|
|
import matplotlib.pylab as pylab # type: ignore
|
|
|
|
pylab.rcParams['figure.figsize'] = (32.0, 24.0)
|
|
pylab.rcParams['font.size'] = 10
|
|
|
|
jawboneDataFeatures = Path(__file__).parent / 'features.csv' # Data File Path
|
|
featureDesc: Dict[str, str] = {}
|
|
for x in genfromtxt(jawboneDataFeatures, dtype='unicode', delimiter=','):
|
|
featureDesc[x[0]] = x[1]
|
|
|
|
def _safe_float(s: str):
|
|
if len(s) == 0:
|
|
return None
|
|
return float(s)
|
|
|
|
def _safe_int(s: str):
|
|
if len(s) == 0:
|
|
return None
|
|
return int(float(s)) # TODO meh
|
|
|
|
def _safe_mins(s: float):
|
|
if s is None:
|
|
return None
|
|
return s / 60
|
|
|
|
class SleepData(NamedTuple):
|
|
date: str
|
|
asleep_time: float
|
|
awake_time: float
|
|
total: float
|
|
awake: float # 'awake for' from app, time awake duing sleep (seconds)
|
|
awakenings: int
|
|
light: float # 'light sleep' from app (seconds)
|
|
deep: float # 'deep sleep' from app (sec)
|
|
quality: float # ???
|
|
|
|
@classmethod
|
|
def from_jawbone_dict(cls, d: Dict[str, Any]):
|
|
return cls(
|
|
date=d['DATE'],
|
|
asleep_time=_safe_mins(_safe_float(d['s_asleep_time'])),
|
|
awake_time=_safe_mins(_safe_float(d['s_awake_time'])),
|
|
total=_safe_mins(_safe_float(d['s_duration'])),
|
|
light=_safe_mins(_safe_float(d['s_light'])),
|
|
deep =_safe_mins(_safe_float(d['s_deep'])),
|
|
awake=_safe_mins(_safe_float(d['s_awake'])),
|
|
awakenings=_safe_int(d['s_awakenings']),
|
|
quality=_safe_float(d['s_quality']),
|
|
)
|
|
|
|
def is_bad(self):
|
|
return self.deep is None and self.light is None
|
|
|
|
# @property
|
|
# def total(self) -> float:
|
|
# return self.light + self.deep
|
|
|
|
|
|
|
|
def iter_useful(data_file: str):
|
|
with open(data_file) as fo:
|
|
reader = DictReader(fo)
|
|
for d in reader:
|
|
dt = SleepData.from_jawbone_dict(d)
|
|
if not dt.is_bad():
|
|
yield dt
|
|
|
|
# TODO <<< hmm. these files do contain deep and light sleep??
|
|
# also steps stats??
|
|
from my.config import jawbone as config
|
|
|
|
p = config.export_dir / 'old_csv'
|
|
# TODO with_my?
|
|
files = [
|
|
p / "2015.csv",
|
|
p / "2016.csv",
|
|
p / "2017.csv",
|
|
]
|
|
|
|
from kython import concat, parse_date
|
|
useful = concat(*(list(iter_useful(str(f))) for f in files))
|
|
|
|
# for u in useful:
|
|
# print(f"{u.total} {u.asleep_time} {u.awake_time}")
|
|
# # pprint(u.total)
|
|
# pprint(u)
|
|
# pprint("---")
|
|
|
|
dates = [parse_date(u.date, yearfirst=True, dayfirst=False) for u in useful]
|
|
# TODO filter outliers?
|
|
|
|
# TODO don't need this anymore? it's gonna be in dashboards package
|
|
from kython.plotting import plot_timestamped
|
|
for attr, lims, mavg, fig in [ # type: ignore
|
|
('light', (0, 400), 5, None),
|
|
('deep', (0, 600), 5, None),
|
|
('total', (200, 600), 5, None),
|
|
('awake_time', (0, 1200), None, 1),
|
|
('asleep_time', (-100, 1000), None, 1),
|
|
# ('awakenings', (0, 5)),
|
|
]:
|
|
dates_wkd = [d for d in dates if d.weekday() < 5]
|
|
dates_wke = [d for d in dates if d.weekday() >= 5]
|
|
for dts, dn in [
|
|
(dates, 'total'),
|
|
(dates_wkd, 'weekday'),
|
|
(dates_wke, 'weekend')
|
|
]:
|
|
mavgs = []
|
|
if mavg is not None:
|
|
mavgs.append((mavg, 'green'))
|
|
fig = plot_timestamped(
|
|
dts, # type: ignore
|
|
[getattr(u, attr) for u in useful],
|
|
marker='.',
|
|
ratio=(16, 4),
|
|
mavgs=mavgs,
|
|
ylimits=lims,
|
|
ytick_size=60,
|
|
# figure=1,
|
|
)
|
|
plt.savefig(f'{attr}_{dn}.png')
|
|
|
|
# TODO use proper names?
|
|
# plt.savefig('res.png')
|
|
# fig.show()
|