-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathhamster_brains2.py
executable file
·143 lines (102 loc) · 4.6 KB
/
hamster_brains2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python
# - coding: utf-8 -
# Copyright (C) 2014 Toms Baugis <[email protected]>
"""Base template"""
import datetime as dt
import itertools
from gi.repository import Gtk as gtk
from gi.repository import GObject as gobject
from collections import defaultdict
from lib import graphics
from lib import layout
from hamster.client import Storage
from hamster_stats import Stats, minutes
class SparkBars(layout.Widget):
def __init__(self, items=None, width = None, height=None, **kwargs):
layout.Widget.__init__(self, **kwargs)
self.width = width or 100
self.height = height or 20
self.bar_width = 10
self.fill_color = "#777"
self.items = items or []
self.connect("on-render", self.on_render)
def on_render(self, sprite):
# simplify math by rolling down to the bottom
self.graphics.save_context()
self.graphics.translate(0, self.height)
gap = 1
max_width = min(self.width, len(self.items) * (self.bar_width + gap))
pixels = graphics.full_pixels(max_width, [1] * len(self.items), gap)
max_val = max(self.items)
for val, width in zip(self.items, pixels):
height = max(1, round(val * 1.0 / max_val * self.height))
self.graphics.rectangle(0, 0, width, -height)
self.graphics.translate(width + gap, 0)
self.graphics.fill(self.fill_color)
self.graphics.restore_context()
class Scene(graphics.Scene):
def __init__(self):
graphics.Scene.__init__(self)
self.storage = Storage()
self._load_end_date = dt.datetime.now()
self.facts = []
self.label = layout.Label("Loading...", y=100,
color="#666",
size=50)
self.add_child(layout.VBox(self.label))
gobject.timeout_add(10, self.load_facts)
def load_facts(self):
# chunk size
end = self._load_end_date
start = end - dt.timedelta(days=30)
self.facts = self.storage.get_facts(start, end) + self.facts
self._load_end_date = start - dt.timedelta(days=1)
# limiter
if end > dt.datetime.now() - dt.timedelta(days=365):
self.label.text = "Loading %d..." % len(self.facts)
gobject.timeout_add(10, self.load_facts)
else:
self.on_facts_loaded()
def on_facts_loaded(self):
self.clear()
main = layout.VBox(padding=10, spacing=10)
self.add_child(main)
first_row = layout.HBox(spacing=10, expand=False)
main.add_child(first_row)
activity_weekdays = layout.HBox([layout.VBox(spacing=15, expand=False),
layout.VBox(spacing=15, expand=False),
layout.VBox(spacing=15)
], spacing=20)
first_row.add_child(activity_weekdays)
activity_weekdays[0].add_child(layout.Label("Category", expand=False, x_align=0))
activity_weekdays[1].add_child(layout.Label("Hour of the day", expand=False, x_align=0))
stats = Stats(self.facts, lambda fact: (fact.category, ""))
by_hour = stats.by_hour()
for activity in sorted(stats.groups.keys()):
label = layout.Label("%s@%s" % (activity[1], activity[0]),
color="#333", size=12, x_align=0, y_align=0.5)
label.max_width = 150
activity_weekdays[0].add_child(label)
activity_weekdays[1].add_child(SparkBars(by_hour[activity], 150))
activity_weekdays[0].add_child(layout.Label("Activity", expand=False, x_align=0))
activity_weekdays[1].add_child(layout.Label("Hour of the day", expand=False, x_align=0))
stats = Stats(self.facts, lambda fact: (fact.category, fact.activity))
by_hour = stats.by_hour()
for activity in sorted(stats.groups.keys()):
label = layout.Label("%s@%s" % (activity[1], activity[0]),
color="#333", size=12, x_align=0, y_align=0.5)
label.max_width = 150
activity_weekdays[0].add_child(label)
activity_weekdays[1].add_child(SparkBars(by_hour[activity], 150))
class BasicWindow:
def __init__(self):
window = gtk.Window()
window.set_default_size(600, 500)
window.connect("delete_event", lambda *args: gtk.main_quit())
window.add(Scene())
window.show_all()
if __name__ == '__main__':
window = BasicWindow()
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL) # gtk3 screws up ctrl+c
gtk.main()