Each election should only have one set of results; use UNIQUE to enforce.
[conservancy:voting.git] / bin / membership-graph.py
1 #!/usr/bin/env python
2 '''
3 Simple script which takes CSV Data either from stdin or a given filename and plots a graph out of that.
4 You might want to retrieve CSV Data by executing the following command:
5
6 mysql -h button-back -u anonvoting -p foundation -B -e 'SELECT DATE_FORMAT(first_added, "%Y-%m") AS date, COUNT(*) as joined FROM foundationmembers GROUP BY date;' | sed 's/\t/","/g;s/^/"/;s/$/"/;s/\n//g' | awk 'FNR>1'
7
8 mysql -h button-back -u anonvoting -p foundation -B -e "SET @start = '2009-01-01', @end = '2009-08-30'; SELECT DATE_FORMAT(DATE_ADD(last_renewed_on, INTERVAL 2 YEAR), '%Y-%m') as date, COUNT(*) as dropped_out FROM foundationmembers WHERE last_renewed_on >= DATE_SUB(@start, INTERVAL 2 YEAR) AND last_renewed_on <= DATE_SUB(@end, INTERVAL 2 YEAR) GROUP BY date;"  | sed 's/\t/","/g;s/^/"/;s/$/"/;s/\n//g' | awk 'FNR>1'
9 '''
10
11 #    This program is free software: you can redistribute it and/or modify
12 #    it under the terms of the GNU General Public License as published by
13 #    the Free Software Foundation, either version 3 of the License, or
14 #    (at your option) any later version.
15 #
16 #    This program is distributed in the hope that it will be useful,
17 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
18 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 #    GNU General Public License for more details.
20 #
21 #    You should have received a copy of the GNU General Public License
22 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
24 import logging
25 import pylab
26 from pylab import figure, title, bar, xticks, yticks, gca, savefig
27 import sys
28
29 __author__ = "Tobias Mueller"
30 __license__ = "GPLv3+"
31 __email__ = "tobiasmue@gnome.org"
32
33 plot_title = "New Foundation Members"
34 figwidth = 40
35 figheight = 3
36
37 def bar_date_graph(name_value_dict, graph_title="", output_name="bargraph.png", show=False):
38   fig = figure(
39                #figsize=(figwidth, figheight)
40                )
41
42   title(graph_title,
43         #size="x-small"
44         )
45
46   sortedkeys, sortedvalues = zip(*sorted(zip(name_value_dict.keys(),
47                                  name_value_dict.values()), reverse=False))
48   for i, value in zip(range(len(sortedvalues)), sortedvalues):
49       bar(i + 0.25, value, color="#73d216")
50
51   pylab.xticks(pylab.arange(0.65, len(sortedkeys)),
52         [("%s: %d" % (name, value))
53           for name, value in zip(sortedkeys, sortedvalues)],
54           #size="xx-large",
55           )
56
57   yticks(
58          #size="xx-large"
59          )
60
61   gca().yaxis.grid(which="major")
62
63   fig.autofmt_xdate()
64
65   savefig(output_name)
66   
67   if show:
68       pylab.show()
69
70 def normalize(*args):
71     out = []
72     for a in args:
73         cleaned = a.strip(' "')
74         #cleaned = int(a)
75         out.append(cleaned)
76         
77     return out
78
79 if __name__=="__main__":
80     from optparse import OptionParser
81     parser = OptionParser("usage: %prog [options] INFILE")
82     parser.add_option("-l", "--loglevel", dest="loglevel",
83                       help="Sets the loglevel to one of debug, info, warn,"
84                       " error, critical", default="error")
85     parser.add_option("-o", "--output",
86                       dest="output", default="bargraph.png",
87                       help="file to create with the plotted graph")
88     parser.add_option("-s", "--show",
89                       dest="show", default="False", action="store_true",
90                       help="display the graph after it has been drawn")
91     parser.add_option("-t", "--title",
92                       dest="title", default="New Foundation Members",
93                       help="set the title of the graph")
94
95     (options, args) = parser.parse_args()
96     loglevel = {'debug': logging.DEBUG, 'info': logging.INFO,
97                  'warn': logging.WARN, 'error': logging.ERROR,
98              'critical': logging.CRITICAL}.get(options.loglevel, "error")
99     logging.basicConfig(level=loglevel)
100     log = logging.getLogger("MembershipGraph Main")
101
102     output_fname = options.output
103
104     if len(args) > 0:
105         fname = args[0]
106         if fname == '-':
107             infile = sys.stdin
108         else:
109             infile = file(fname, 'r')
110     else:
111         path = sys.stdin
112         
113     
114     
115     
116     values = {}
117     date = None
118     first = None
119     
120     lines = infile.readlines()
121     for line in lines:
122       l = line.strip().split(",")
123       if l and l[0] and l[1]:
124           x, y = normalize(l[0], l[1])
125           print x, y
126           if not first:
127               first = x
128           last = x
129           values[x] = int(y)
130     
131     date = first
132     while date != last:
133       year, month = date.split("-")
134       month = int(month)
135       year = int(year)
136       month += 1
137       if month > 12:
138         month = 1
139         year += 1
140     
141       date = "-".join([str(year), str('%02d' % month)])
142     
143       if date not in values:
144         values[date] = 0
145     
146     bar_date_graph(values, options.title, output_fname, show=options.show)