9ab2a4c1a5a8ccacfb463c0ac7046755e7be19c2
[selectricity] / app / controllers / graph_controller.rb
1 require 'date'
2 class GraphController < ApplicationController
3   # produce a graph of votes per day during an election
4   def votes_per_day
5     @election = Election.find(params[:id])
6     data, labels = get_votes_per_day_data(@election)
7     
8     line = Gruff::Line.new("700x400")
9     line.theme = { :background_colors => ['#73BF26', '#ffffff'] }
10     line.title = "Voters Per Day"
11     line.font = File.expand_path('/usr/X11R6/lib/X11/fonts/TTF/Vera.ttf',
12                                  RAILS_ROOT)
13
14     line.data("#{@election.name}", data )
15     line.labels = labels
16
17     line.x_axis_label = "Date"
18     line.y_axis_label = "Number of Votes"
19     line.minimum_value = 0.0
20
21     line.draw
22     send_data(line.to_blob, :disposition => 'inline', :type => 'image/png')
23   end
24   
25   #will place votes in a fixed number of intervals, and shows votes over time
26   def votes_per_interval
27     @election = Election.find(params[:id])
28     data, labels = get_votes_per_interval_data(@election)
29     
30     line = Gruff::Line.new("700x400")
31     line.theme = { :background_colors => ['#73BF26', '#ffffff'] }
32     line.title = "Voters Over Time"
33     line.font = File.expand_path('/usr/X11R6/lib/X11/fonts/TTF/Vera.ttf',
34                                RAILS_ROOT)
35     
36     line.data("#{@election.name}", data )
37     line.labels = labels
38     
39     line.x_axis_label = "Intervals"
40     line.y_axis_label = "Number of Votes"
41     line.minimum_value = 0.0
42                                
43     line.draw
44     send_data(line.to_blob, :disposition => 'inline', :type => 'image/png')  
45   end
46  
47   def quickvote_bar
48     @election = Election.find(params[:id])
49   end
50   
51   def borda_bar
52     @election = Election.find(params[:id])
53     
54     #Get the list of candidates from the election, and calculate how RubyVote
55     #gave each one points
56     @election.candidates.each do |candidate|
57     
58     #Tabulate how many points each candidate received
59     #Make the name of each candidate a label under the correspoding column
60     #done!
61   end
62   
63  
64  private 
65  
66   # generate the data and labels for each graph
67   def get_votes_per_day_data(election)
68     voter_days = Array.new
69     unique_days = Array.new
70     total_per_day = Array.new
71     election_days = Hash.new
72     
73     #turn election startdate into date object, and create the range of election
74     startdate = Date.parse(election.startdate.to_s)
75     election_range = startdate..Date.today
76     
77     # create a hash with all the dates of the election in String format
78     # referenced by their order in the election
79     election_range.each_with_index do |day, index|
80       election_days[index] = day.to_s
81     end
82     
83     # Now I need to create an array with all the times votes were made
84     election.votes.each do |vote|
85         voter_days << Date.parse(vote.time.to_s)
86     end
87     voter_days.sort!
88     
89     # Now I need to count how many times each each date appears in voter_days,
90     # and put that number into a votes_per_day array, the 'data' for the graph    
91     #Create an array of unique days from voter_days
92     voter_days.each do |day|
93       unless unique_days.any? {|date| date.eql?(day)}
94         unique_days << day
95       end
96     end
97     unique_days.sort!
98     
99     #find all dates where those days = date at current index, put size of returned
100     #array into total_per_day
101     unique_days.each_with_index do |date, index|
102       total_per_day << (voter_days.select {|day| day.eql?(date)}).size
103     end    
104
105     # return the data and the labels
106     return total_per_day, election_days
107    
108   end
109   
110   def get_votes_per_interval_data(election)
111     labels_hash = Hash.new
112     buckets = Hash.new
113     total_per_interval = Array.new
114     
115     starttime = election.startdate
116     timedelta = Time.now - starttime
117     numcols = 10
118     interval_length = timedelta/numcols
119     
120     # Make a hash, buckets, indexed by time intervals and containing empty arrays
121     # The time object must come first in addition! 
122     # i would start at 0, i+1 goes from 0 up till numcols
123     numcols.times {|i| buckets[starttime + ((i+1)*interval_length)] = []}
124      
125     # Put votes into bucket according to the time interval to which they belong,
126     # referenced by their key
127     # Will build a graph over time, as each successive interval wil lhave more
128     # vote objects  
129     election.votes.each do |vote|
130       buckets.keys.sort.each do |inter|
131         if vote.time < inter
132           buckets[inter] << vote
133         end
134       end
135     end
136   
137     total_per_interval = buckets.keys.sort.collect {|key| buckets[key].size}
138     
139     # Create the hash for the labels. Each graph has ten columns, and three
140     # will be labeled
141     if timedelta < 2.hours #under two hours use minutes for labels
142       labels_hash[0] = starttime.min.to_s
143       labels_hash[(numcols/2)-1] = (starttime + (timedelta/2)).min.to_s
144       labels_hash[numcols-1] = Time.now.min.to_s
145     elsif timedelta < 2.days #more than 2 hours means use hours for labels
146       labels_hash[0] = starttime.hour.to_s
147       labels_hash[(numcols/2)-1] = (starttime + (timedelta/2)).hour.to_s
148       labels_hash[numcols-1] = Time.now.hour.to_s
149     else #more than 2 days means use dates for labels
150       labels_hash[0] = (Date.parse(starttime.to_s)).to_s
151       labels_hash[(numcols/2)-1] = (Date.parse(starttime + (timedelta/2))).to_s
152       labels_hash[numcols-1] = (Date.today).to_s
153     end
154     
155     # Make sure to return an array for data and hash for labels
156     return total_per_interval, labels_hash   
157   end
158
159 end

Benjamin Mako Hill || Want to submit a patch?