-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathinsight.py
109 lines (95 loc) · 3.98 KB
/
insight.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
from bitdeli.insight import insight, segment, segment_label
from bitdeli.widgets import Text, Table
from discodb.query import Q, Literal, Clause
from collections import namedtuple
CAPTION = """
## What is the proportion of active users compared to inactive users?
"""
LABEL = """
### **{label}** ({size:,} users)
"""
COLORS = {'least active': 'rgb(255, 36, 0)',
'barely active': 'rgb(255, 197, 11)',
'moderately active': 'rgb(179, 220, 108)',
'very active': 'rgb(0, 163, 89)',
'most active': 'rgb(118, 192, 255)'}
def num(x):
return '{0:,}'.format(int(x))
def table_data(model, counter):
keys = sorted(model, key=lambda x: int(x.split()[0]))
sizes = [counter(model, key) for key in keys]
total = float(sum(sizes))
for i, (key, size) in enumerate(zip(keys, sizes)):
mi, ma, label = key.split(' ', 2)
crange = num(mi) if mi == ma else '%s-%s' % (num(mi), num(ma))
txt = crange + (' event' if crange == '1' else ' events')
perc = '%.1f%%' % (100. * size / total)
yield 'c%d' % i, txt, label, size, perc, key
def make_table(model, counter, segment_id):
data = list(table_data(model, counter))
def columns():
for col, txt, label, size, perc, key in data:
if size:
yield {'name': col,
'label': label.capitalize(),
'width': perc,
'sortable': False,
'cell': 'markdown'}
def row():
for col, txt, label, size, perc, key in data:
if size:
t = '*%s*\n\n'\
'**%s** (%s) users' % (txt, perc, num(size))
yield col, {'label': t,
'background': COLORS[label],
'segment_id': '%s|%s' % (segment_id, key)}
return Table(size=(12, 2),
fixed_width=False,
data={'columns': list(columns()), 'rows': [dict(row())]})
@insight
def view(model, params):
def test_segment():
import random
random.seed(21)
labels = ['First Segment'] #, 'Second']
segments = [frozenset(random.sample(model.unique_values(), 100))]
#frozenset(random.sample(model.unique_values(), 200))]
return namedtuple('SegmentInfo', ('model', 'segments', 'labels'))\
(model, segments, labels)
#model = test_segment()
has_segments = hasattr(model, 'segments')
omodel = model.model if has_segments else model
yield Text(size=(12, 'auto'),
label='Showing user activity',
data={'text': CAPTION})
yield Text(size=(12, 'auto'),
data={'text': LABEL.format(label='All users',
size=len(omodel.unique_values()))})
yield make_table(omodel, lambda model, key: len(model[key]), '')
if has_segments:
for i, (segment, label) in enumerate(zip(model.segments,
model.labels)):
def segcounter(model, key):
return sum(1 for uid in model[key] if uid in segment)
yield Text(size=(12, 'auto'),
data={'text': LABEL.format(label=label,
size=len(segment))})
yield make_table(model.model, segcounter, i)
@segment
def segment(model, params):
segid, key = params['value']['segment_id'].split('|', 1)
omodel = model.model if hasattr(model, 'segments') else model
if segid:
segment = model.segments[int(segid)]
return (uid for uid in omodel[key] if uid in segment)
else:
return omodel[key]
@segment_label
def label(segment, model, params):
segid, key = params['value']['segment_id'].split('|', 1)
label = key.split(' ', 2)[2]
if segid:
seglabel = model.labels[int(segid)]
return '%s who are %s' % (seglabel, label)
else:
return '%s users' % label.capitalize()