From: Date: Fri, 10 Aug 2007 22:47:33 +0000 (-0400) Subject: Added a new bar graph, that counts how many points the borda system of X-Git-Url: https://projects.mako.cc/source/selectricity/commitdiff_plain/09c67d9323c7d379d4c6de5dc0457b6de16cff14?ds=sidebyside Added a new bar graph, that counts how many points the borda system of voting has asssigned to every candidate, it shows the margins fo victory and loss clearly. Also had to make modifications to the RubyVote libary. There was an error in BordaVote that prevented it from working correctly, which has been fixed. Also added an attr_reader to BordaResult for ranked_candidates. About to delete the Gruff Plugin v 0.1.2 and replace it with Gruff gem v 0.2.8. --- diff --git a/app/controllers/election_controller.rb b/app/controllers/election_controller.rb index e950153..df0aa7c 100644 --- a/app/controllers/election_controller.rb +++ b/app/controllers/election_controller.rb @@ -196,15 +196,15 @@ class ElectionController < ApplicationController if incoming_voters.email == 0 new_voter.contacted = 1 - elsif incoming_voters.email == 1 - email_voter( new_voter ) - new_voter.contacted = 1 - else - new_voter.contacted = 0 - end + elsif incoming_voters.email == 1 + email_voter( new_voter ) + new_voter.contacted = 1 + else + new_voter.contacted = 0 + end # the new voter should be in good shape. save add to the election - new_voter.save + new_voter.save @election.voters << new_voter end end diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb index 9ab2a4c..7b593cc 100644 --- a/app/controllers/graph_controller.rb +++ b/app/controllers/graph_controller.rb @@ -11,21 +11,20 @@ class GraphController < ApplicationController line.font = File.expand_path('/usr/X11R6/lib/X11/fonts/TTF/Vera.ttf', RAILS_ROOT) - line.data("#{@election.name}", data ) + line.data( "#{@election.name}", data ) line.labels = labels line.x_axis_label = "Date" line.y_axis_label = "Number of Votes" line.minimum_value = 0.0 - line.draw send_data(line.to_blob, :disposition => 'inline', :type => 'image/png') end #will place votes in a fixed number of intervals, and shows votes over time def votes_per_interval @election = Election.find(params[:id]) - data, labels = get_votes_per_interval_data(@election) + data, labels, scale = get_votes_per_interval_data(@election) line = Gruff::Line.new("700x400") line.theme = { :background_colors => ['#73BF26', '#ffffff'] } @@ -36,11 +35,10 @@ class GraphController < ApplicationController line.data("#{@election.name}", data ) line.labels = labels - line.x_axis_label = "Intervals" + line.x_axis_label = scale line.y_axis_label = "Number of Votes" line.minimum_value = 0.0 - line.draw send_data(line.to_blob, :disposition => 'inline', :type => 'image/png') end @@ -50,19 +48,28 @@ class GraphController < ApplicationController def borda_bar @election = Election.find(params[:id]) + pref_tally = make_preference_tally(@election) + + @borda_result = BordaVote.new(pref_tally).result + data, labels = get_borda_points(@borda_result) - #Get the list of candidates from the election, and calculate how RubyVote - #gave each one points - @election.candidates.each do |candidate| + bar = Gruff::Bar.new("700x400") + bar.theme = { :background_colors => ['#73BF26', '#ffffff'] } + bar.title = "Points Per Candidate" + bar.font = File.expand_path('/usr/X11R6/lib/X11/fonts/TTF/Vera.ttf', + RAILS_ROOT) + + bar.data("#{@election.name}", data) + bar.labels = labels - #Tabulate how many points each candidate received - #Make the name of each candidate a label under the correspoding column - #done! + bar.y_axis_label = "Points" + bar.x_axis_label = "Candidate" + bar.minimum_value = 0.0 + send_data(bar.to_blob, :disposition => 'inline', :type => 'image/png') end - private - + # generate the data and labels for each graph def get_votes_per_day_data(election) voter_days = Array.new @@ -111,6 +118,7 @@ class GraphController < ApplicationController labels_hash = Hash.new buckets = Hash.new total_per_interval = Array.new + interval_type = "" starttime = election.startdate timedelta = Time.now - starttime @@ -142,18 +150,52 @@ class GraphController < ApplicationController labels_hash[0] = starttime.min.to_s labels_hash[(numcols/2)-1] = (starttime + (timedelta/2)).min.to_s labels_hash[numcols-1] = Time.now.min.to_s + interval_type = "Minutes" elsif timedelta < 2.days #more than 2 hours means use hours for labels labels_hash[0] = starttime.hour.to_s labels_hash[(numcols/2)-1] = (starttime + (timedelta/2)).hour.to_s labels_hash[numcols-1] = Time.now.hour.to_s + interval_type = "Hours" else #more than 2 days means use dates for labels labels_hash[0] = (Date.parse(starttime.to_s)).to_s labels_hash[(numcols/2)-1] = (Date.parse(starttime + (timedelta/2))).to_s labels_hash[numcols-1] = (Date.today).to_s + interval_type = "Days" end # Make sure to return an array for data and hash for labels - return total_per_interval, labels_hash + return total_per_interval, labels_hash, interval_type + end + + def get_borda_points(result) + #points holds how mnay points each candidate has received in array form + #becasue Gruff::Bar#data takes only an array + points = Array.new + labels = Hash.new + + #Populate points with an sorted array from election.votes hash + #biggest to smallest will go from left to right + points = result.election.votes.sort do |a, b| + b[1] <=> a[1] + end.collect {|i| i[1]} + + #make the labels + result.ranked_candidates.each_with_index do |candidate, index| + labels[index] = Candidate.find(candidate).name + end + + return points, labels + end + + #most vote result objects require an array of vote arrays, which this will make + def make_preference_tally(election) + preference_tally = Array.new + @election.voters.each do |voter| + next unless voter.voted? + preference_tally << voter.vote.rankings.sort.collect \ + { |ranking| ranking.candidate.id } + end + return preference_tally end end diff --git a/app/controllers/quickvote_controller.rb b/app/controllers/quickvote_controller.rb index d842f63..0b745af 100644 --- a/app/controllers/quickvote_controller.rb +++ b/app/controllers/quickvote_controller.rb @@ -63,7 +63,7 @@ class QuickvoteController < ApplicationController # if the voter has not voted we destroy them if @voter and not @voter.voted? @voter.destroy - @voter = nil + @voter = nil end # if the voter does not exist or has has been destroyed, lets @@ -73,12 +73,12 @@ class QuickvoteController < ApplicationController @voter = QuickVoter.new @voter.election = QuickVote.find_all( [ "name = ?", params[:votename] ] )[0] @voter.session_id = session.session_id - - # create new vote and make it the defaulted sorted list + + # create new vote and make it the defaulted sorted list @voter.vote = Vote.new - @voter.save - @voter.vote.set_defaults! - @voter.reload + @voter.save + @voter.vote.set_defaults! + @voter.reload end else redirect_to :controller => 'site' @@ -91,14 +91,14 @@ class QuickvoteController < ApplicationController # find out who the voter is for this election @voter = QuickVoter.find_all(["session_id = ? and election_id = ?", - session.session_id, election.id])[0] - + session.session_id, election.id])[0] + if not @voter # we have not seen this voter before. something is wrong, try # again redirect_to quickvote_url( :votename => params[:votename] ) - elsif @voter.voted? + elsif @voter.voted? # this person has already voted, we try again flash[:notice] = "You have already voted!" redirect_to quickvote_url( :votename => params[:votename] ) @@ -108,8 +108,7 @@ class QuickvoteController < ApplicationController @voter.ipaddress = request.env["REMOTE_ADDR"] @voter.save - # save the time the vote was made for statistical use, it doesn't - #work here unless I use a method that will save it to the db + # save the time the vote was made for statistical use @voter.vote.time = Time.now # toggle the confirmation bit @@ -143,7 +142,7 @@ class QuickvoteController < ApplicationController ############################################################### def results - @election = QuickVote.find_all( ["name = ?", params[:votename]] )[0] + @election = QuickVote.find_all(["name = ?", params[:votename]] )[0] # initalize the tallies to empty arrays preference_tally = Array.new diff --git a/app/controllers/site_controller.rb b/app/controllers/site_controller.rb index e86624e..a33a1fa 100644 --- a/app/controllers/site_controller.rb +++ b/app/controllers/site_controller.rb @@ -16,7 +16,7 @@ class SiteController < ApplicationController b.enddate <=> a.enddate end else - # if we have no record of them, set the session id back to + # if we have no record of them, set the user back to # nothing and start again session[:user] = nil diff --git a/app/views/quickvote/results.rhtml b/app/views/quickvote/results.rhtml index 030d246..5fdfc3c 100644 --- a/app/views/quickvote/results.rhtml +++ b/app/views/quickvote/results.rhtml @@ -163,7 +163,7 @@ by several other names.

<%= image_tag( graph_url( :action => 'votes_per_day', :id => @election ) ) %>
-<%= image_tag( graph_url(:action => 'votes_per_interval', :id => @election)) %> - +<%= image_tag( graph_url( :action => 'votes_per_interval', :id => @election ))%>
+<%= image_tag( graph_url( :action => 'borda_bar', :id => @election ) ) %> diff --git a/lib/rubyvote/positional.rb b/lib/rubyvote/positional.rb index 11e8a49..3de3fb2 100644 --- a/lib/rubyvote/positional.rb +++ b/lib/rubyvote/positional.rb @@ -42,7 +42,12 @@ class BordaVote < ElectionVote def tally_vote(vote) points = candidates.length - 1 vote.each do |candidate| - @votes[candidate] = points + #if the candidate exist, add the points, otherwise assign them + if @votes.has_key?(candidate) + @votes[candidate] += points + else + @votes[candidate] = points + end points -= 1 end end @@ -58,6 +63,8 @@ class BordaVote < ElectionVote end class BordaResult < ElectionResult + attr_reader :ranked_candidates + def initialize(voteobj=nil) super(voteobj) votes = @election.votes