179 lines
4.6 KiB
Python
Executable file
179 lines
4.6 KiB
Python
Executable file
#!/usr/bin/env python3.6
|
|
from kython import *
|
|
|
|
from backup_config import SLEEPS_FILE, GRAPHS_DIR, PHASES_FILE
|
|
|
|
from datetime import datetime, date, time
|
|
|
|
fromtimestamp = datetime.fromtimestamp
|
|
|
|
XID = str # TODO how to shared with backup thing?
|
|
Phases = Dict[XID, Any]
|
|
|
|
phases: Phases
|
|
with open(PHASES_FILE, 'r') as fo:
|
|
phases = json_load(fo)
|
|
|
|
class SleepEntry:
|
|
def __init__(self, js) -> None:
|
|
self.js = js
|
|
|
|
# TODO @memoize decorator?
|
|
@property
|
|
def date_(self) -> date:
|
|
dates = str(self.js['date'])
|
|
return datetime.strptime(dates, "%Y%m%d").date()
|
|
|
|
@property
|
|
def title(self) -> str:
|
|
return self.js['title']
|
|
|
|
@property
|
|
def xid(self) -> XID:
|
|
return self.js['xid']
|
|
|
|
def _details(self):
|
|
return self.js['details']
|
|
|
|
@property
|
|
def created(self) -> datetime:
|
|
return fromtimestamp(self.js['time_created'])
|
|
|
|
@property
|
|
def completed(self) -> datetime:
|
|
return fromtimestamp(self.js['time_completed'])
|
|
|
|
@property
|
|
def asleep(self) -> datetime:
|
|
return fromtimestamp(self._details()['asleep_time'])
|
|
|
|
@property
|
|
def graph(self) -> str:
|
|
return os.path.join(GRAPHS_DIR, self.xid + ".png")
|
|
|
|
@property
|
|
def phases(self) -> List[datetime]:
|
|
return [fromtimestamp(i['time']) for i in phases[self.xid]]
|
|
|
|
def __str__(self) -> str:
|
|
return f"{self.date_.strftime('%a %d %b')} {self.title}"
|
|
|
|
def __repr__(self) -> str:
|
|
return str(self)
|
|
|
|
def load_sleeps() -> List[SleepEntry]:
|
|
with open(SLEEPS_FILE, 'r') as fo:
|
|
sleeps = json_load(fo)
|
|
return [SleepEntry(js) for js in sleeps]
|
|
import numpy as np # type: ignore
|
|
import matplotlib.pyplot as plt # type: ignore
|
|
# pip install imageio
|
|
from imageio import imread # type: ignore
|
|
from scipy.misc import imresize # type: ignore
|
|
|
|
|
|
def hhmm(time: datetime):
|
|
return time.strftime("%H:%M")
|
|
|
|
|
|
# def xpos(time: datetime) -> float:
|
|
# tick = span / width
|
|
# fromstart = time - sleep.created
|
|
# return fromstart / tick
|
|
|
|
import matplotlib.dates as mdates # type: ignore
|
|
from matplotlib.figure import Figure # type: ignore
|
|
from matplotlib.axes import Axes # type: ignore
|
|
from matplotlib.ticker import MultipleLocator, FixedLocator # type: ignore
|
|
|
|
def plot_one(sleep: SleepEntry, fig: Figure, axes: Axes, xlims=None):
|
|
span = sleep.completed - sleep.created
|
|
print(f"span: {span}")
|
|
|
|
img = imread(sleep.graph)
|
|
# all of them are 300x300 images apparently
|
|
# size = img.shape
|
|
# (height, width, depth) = size
|
|
# size = (height, width * 5, depth)
|
|
# (height, width, depth) = size
|
|
# img = imresize(img, size)
|
|
|
|
# span for image
|
|
xspan = [sleep.created, sleep.completed]
|
|
xspan = [mdates.date2num(i) for i in xspan]
|
|
if xlims is None:
|
|
# TODO soo,
|
|
tt = sleep.created
|
|
hour = tt.hour
|
|
# TODO maybe assert that hour is somewhere between 20 and 8 or something
|
|
start: datetime
|
|
starttime = time(23, 00)
|
|
if hour >= 20:
|
|
# went to bed before midnight
|
|
start = datetime.combine(tt.date(), starttime)
|
|
elif hour <= 8:
|
|
# went to bed after midnight
|
|
start = datetime.combine(tt.date() - timedelta(days=1), starttime)
|
|
pass
|
|
else:
|
|
raise RuntimeError("wtf???")
|
|
end = start + timedelta(hours=10)
|
|
xlims = [start, end]
|
|
|
|
# axes.figure(figsize=(10, 5))
|
|
axes.set_xlim(xlims)
|
|
hhmm_fmt = mdates.DateFormatter('%H:%M')
|
|
axes.xaxis.set_major_formatter(hhmm_fmt)
|
|
ticks = [
|
|
# sleep.created,
|
|
# sleep.asleep,
|
|
# sleep.completed,
|
|
] + sleep.phases
|
|
axes.xaxis.set_ticks(ticks)
|
|
axes.yaxis.set_ticks([])
|
|
axes.tick_params(
|
|
axis='both',
|
|
which='major',
|
|
length=0,
|
|
labelsize=7,
|
|
rotation=30,
|
|
pad=-14, # err... hacky
|
|
)
|
|
|
|
ylims = [0, 50]
|
|
axes.set_ylim(ylims)
|
|
|
|
axes.imshow(
|
|
img,
|
|
zorder=0,
|
|
extent=[
|
|
xspan[0], xspan[1],
|
|
ylims[0], ylims[1],
|
|
],
|
|
aspect='auto',
|
|
)
|
|
# axes.set_title(str(sleep))
|
|
# axes.title.set_size(10)
|
|
|
|
axes.text(xlims[1] - timedelta(hours=1.5), 20, str(sleep),)
|
|
# plt.text(sleep.asleep(), 0, hhmm(sleep.asleep()))
|
|
|
|
sleeps_count = 30
|
|
fig: Figure = plt.figure(figsize=(15, sleeps_count * 1))
|
|
|
|
sleeps = load_sleeps()
|
|
sleeps = sleeps[:sleeps_count]
|
|
|
|
axarr = fig.subplots(nrows=len(sleeps))
|
|
for i, (sleep, axes) in enumerate(zip(sleeps, axarr)):
|
|
# axes: Axes = fig.add_subplot(len(sleeps), 1, i + 1)
|
|
# ok, have to adjust days a bit...
|
|
plot_one(sleep, fig, axes)
|
|
|
|
# TODO use map?
|
|
# pprint(sleeps[:2])
|
|
|
|
plt.tight_layout()
|
|
plt.subplots_adjust(hspace=0.0)
|
|
plt.show()
|
|
|