]> git.donarmstrong.com Git - neurodebian.git/blob - survey/makestats
More figure stuff.
[neurodebian.git] / survey / makestats
1 #!/usr/bin/python
2
3 from glob import glob
4 import json
5 import sys
6 import pylab as pl
7 import numpy as np
8
9 # some meaningful groups of OSes
10 redhat_family = ["rhel", "centos", "fedora", "scilinux"]
11 debian_family = ["debian", "ubuntu", "biolinux"]
12 suse_family = ["suse", "slel"]
13 other_linux_family = ["gentoo", "mandriva", "arch", "slackware", "otherlinux"]
14 other_family = ["starbsd", "unix", "qnx", "beos", "solaris", "other"]
15
16 os_cat_names = {
17         'win': 'Windows',
18         'mac': 'Mac OS',
19         'linux': 'GNU/Linux',
20         'otheros': 'Other OS'
21         }
22
23 os_family = {
24         'win': ["windows"],
25         'mac': ["macosx"],
26         'linux': redhat_family + debian_family + suse_family + other_linux_family,
27         'otheros': other_family
28         }
29 # end the reverse mapping
30 os_family_rev = {}
31 for ost in os_family:
32     for os in os_family[ost]:
33         os_family_rev[os] = ost
34
35
36 class DB(dict):
37     def __init__(self, srcdir):
38         # eats the whole directory
39         datafilenames = glob('%s/*.json' % srcdir)
40         for dfn in datafilenames:
41             rawdata = json.load(open(dfn))
42             self[rawdata['timestamp']] = rawdata
43
44         self.os_dict = load_list2dict('oslist.txt')
45
46     def get_unique(self, key):
47         # return a set of all (unique) values for a field id
48         uniq = set()
49         for d in self.values():
50             if key in d:
51                 el = d[key]
52                 if isinstance(el, list):
53                     uniq = uniq.union(el)
54                 else:
55                     uniq = uniq.union((el,))
56         return uniq
57
58     def get_not_none(self, key):
59         # return a list of all values of a specific field id
60         # the second return value is count of submission that did not have data
61         # for this field id
62         val = []
63         missing = 0
64         for d in self.values():
65             if key in d:
66                 el = d[key]
67                 if isinstance(el, list):
68                     val.extend(el)
69                 else:
70                     if el == 'none':
71                         missing += 1
72                     else:
73                         val.append(el)
74             else:
75                 missing += 1
76         return val, missing
77
78     def get_counts(self, key):
79         # return a dict with field values as keys and respective submission 
80         # count as value
81         vals = self.get_not_none(key)[0]
82         uniq = np.unique(vals)
83         counts = dict(zip(uniq, [vals.count(u) for u in uniq]))
84         return counts
85
86     def select_match(self, key, values):
87         # return a db with all submissions were a field id has one of the
88         # supplied values
89         match = {}
90         for k, v in self.items():
91             if not key in v:
92                 continue
93             el = v[key]
94             if isinstance(el, list):
95                 if len(set(values).intersection(el)):
96                     match[k] = v
97             elif el in values:
98                 match[k] = v
99         return match
100
101     def get_nice_name(self, id):
102         srcs = [self.os_dict, os_cat_names]
103         for src in srcs:
104             if id in src:
105                 return src[id]
106         # not found, nothing nicer
107         return id
108
109
110 def load_list2dict(name):
111     d = {}
112     lfile = open(name)
113     for line in lfile:
114         kv = line.split(':')
115         d[kv[0]] = kv[1].strip().strip('"')
116     return d
117
118 def mkpic_os_per_env(db, destdir):
119     envs = ['pers_os', 'man_os', 'virt_host_os', 'virt_guest_os']
120     env_names = ['Personal', 'Managed', 'Virt. Host', 'Virt. Guest']
121     env_stats = {}
122     offset = 0
123     for env in envs:
124         counts = db.get_counts(env)
125         stats = dict(zip(os_family.keys(), [0] * len(os_family)))
126         for os in counts:
127             stats[os_family_rev[os]] += counts[os]
128         total_count = np.sum(stats.values())
129         for osf in stats:
130             stats[osf] = float(stats[osf]) / total_count
131         env_stats[env] = stats
132     # make stacked barplot
133     pl.figure(figsize=(6.4, 4.8), facecolor='w', edgecolor='k')
134     x = np.arange(len(envs))
135     bottoms = np.zeros(len(envs))
136     os_order = ['linux', 'mac', 'win', 'otheros']
137     colors = ['#B63537', '#4E4DA0', '#008200', 'gray']
138     for i, os in enumerate(os_order):
139         stat = [env_stats[e][os] for e in envs]
140         pl.bar(x, stat, bottom=bottoms, color=colors[i],
141                label=db.get_nice_name(os), width=0.8)
142         bottoms += stat
143     pl.legend(loc='lower right')
144     pl.xticks(x + 0.4,  [db.get_nice_name(e) for e in env_names])
145     pl.xlim(-0.25, len(envs))
146     pl.title("Operating system preference by environment")
147     pl.ylabel("Fraction of submissions")
148     pl.savefig('%s/ospref_by_env.png' % destdir, format='png')
149
150 def mkpic_submissions_per_datamod(db, destdir):
151     # simple demo
152     dmd = load_list2dict('datamodlist.txt')
153     spd = db.get_counts('bg_datamod')
154     spd = sorted(spd.items(), cmp=lambda x, y: cmp(x[1], y[1]))[::-1]
155     x = np.arange(len(spd))
156     pl.figure(figsize=(6.4, 4.8), facecolor='w', edgecolor='k')
157     pl.title('Submissions per data modality')
158     pl.bar(x, [s[1] for s in spd])
159     pl.xticks(x + 0.5,  [dmd[k[0]] for k in spd], rotation=-10)
160     pl.ylabel('Survey submissions per data modality\n(multiple choices per submission possible)')
161     pl.savefig('%s/submissions_per_datamod.png' % destdir, format='png')
162
163 def main(srcdir, destdir):
164     db = DB(srcdir)
165     for pic in [mkpic_submissions_per_datamod, mkpic_os_per_env]:
166         pic(db, destdir)
167
168 if __name__ == '__main__':
169     main(sys.argv[1], sys.argv[2])