STAR Voting with Google Forms

 

STAR Voting now has it's own web app for running simple and functional polls. Give it a try on star.vote. More features are being added all the time.

 

With Google Forms it's also fairly easy to set up and run your own STAR Voting elections with additional security features, by copying and pasting in a simple script.

This post is a step-by-step guide that shows how to do that.

 

How to create a STAR Voting election on Google Forms

 

STEP 1: Create a new Google Form for your election

Go to Google Forms and create a new form.

 

 

STEP 2: Name your election and paste in the voter instructions

  • Name your election as you choose.
  • For the voter instructions paste in the following:

    Score candidates from 0-5 stars. If you don't have a preference you can give candidates the same score. Those you leave blank receive a zero.

 

STEP 3: Choose the "Linear Scale" question type for the first entry and set up the 0-5 scale

  • Write in the name of your first candidate.
  • The default question type is "Multiple Choice" but you'll want to change that to the "Linear Scale" option for each question.
  • Set the scale to 0 to 5. Since Google Forms defaults to 1 as the starting value, you'll need to set it manually to 0.
  • Label the scale:
    • 0  "Worst"
    • 5   "Best"

 

 

STEP 4: Duplicate your first entry to create an entry for each candidate

  • Click on the "Duplicate" icon at the bottom of the first entry.
  • Type in the name of your next candidate.
  • Duplicate your entry again and repeat until all candidates for your election are listed.

 

 

STEP 5: Open the Script Editor

  • From the menu at the top of your screen click on "More" (the vertical "..." in the upper left.)
  • Select the "< > Script Editor" option.
  • The script editor will open in another tab. This is where you'll put in the custom code to turn your poll into a STAR Voting election.
  • Name your Script Editor to match your election.

 

 

STEP 6: Replace all the code with the 'STAR Voting Calculator' script

  • Copy the following code and paste it in, replacing the few lines of code already in the code.gs script box.
/** * @NotOnlyCurrentDoc */
function onOpen(e) {
FormApp.getUi()
.createAddonMenu()
.addItem('Add Election', 'addElection')
.addItem('Add Candidate', 'addCandidate')
.addItem('Run Elections', 'runElections')
.addToUi();
}
function onInstall(e) {
onOpen(e);
}
function addElection() {
// Add new election page
form = FormApp.getActiveForm()
page = form.addPageBreakItem()
page.setTitle('Add Election Name')
page.setHelpText("Score candidates from 0-5 stars. If you don't have a preference you can give candidates the same score. Those you leave blank receive a zero.")
}
function addCandidate() {
// Add new candidate to page
form = FormApp.getActiveForm()
candidate = form.addScaleItem()
candidate.setTitle('Add Candidate Name')
candidate.setBounds(0, 5)
candidate.setLabels('Worst', 'Best')
candidate.setHelpText('Add Bio')
}
function runElection() {
// Runs election for candidates found in runElections function
if (num_candidates == 0)
return
// Creates new sheet for election
if (num_elections>0){
result_sheet = spreadsheet.insertSheet(num_elections-1);
}
else{
result_sheet = spreadsheet.insertSheet(0);
}
result_sheet.setName(current_election_name + " Results");
result_range = result_sheet.getDataRange();
result_values = result_range.getValues();

num_ballots = responses.length;

// create empty score list and preference matrix
candidate_scores = [];
pref_matrix = [];
for(i = 0; i < num_candidates; i++)
{
candidate_scores[i] = 0;
pref_matrix[i] = [];
for(j = 0; j < num_candidates; j++)
pref_matrix[i][j] = 0;
}

total_votes = 0;

// Iterate through ballots adding scores to candidate scores
for(b = 0; b < num_ballots; b++)
{
total_votes += 1;
scores = [];
for(z = 0; z < num_candidates; z++)
scores[z] = 0;

for(i = 0; i < num_candidates; i++)
{
scores[i] = parseInt(responses[b].getResponseForItem(candidates[i]).getResponse());
}
for(c = 0; c < num_candidates; c++)
{
candidate_scores[c] += scores[c];
for(d = 0; d < num_candidates; d++)
if(scores[c] > scores[d])
pref_matrix[c][d] += 1;
}
}
function versus(x) { return 'vs. ' + x }
result_sheet.appendRow([ 'Election Results:' ]);
result_sheet.appendRow([ '', 'Total', 'Average Score'].concat(candidate_names.map( versus ) ) );
result_sheet.getRange(2, 2, 1, 2 + num_candidates).setHorizontalAlignment("right");

for(c = 0; c < num_candidates; c++)
{
pref_matrix[c][c] = '';
result_sheet.appendRow([candidate_names[c], candidate_scores[c], candidate_scores[c]/total_votes].concat(pref_matrix[c]));
result_sheet.getRange(3 + c, 3).setNumberFormat("0.00");
result_sheet.getRange(3 + c, 4 + c).setBackgroundRGB(180, 180, 180);
}
// find the top two
top_a = 0;
top_b = 1;

for(c = top_b + 1; c < num_candidates; c++)
{
if(candidate_scores[c] > candidate_scores[top_a])
{
if(candidate_scores[top_a] > candidate_scores[top_b])
top_b = top_a;
top_a = c;
}
else if(candidate_scores[c] > candidate_scores[top_b])
{
top_b = c;
}
}
// Populate sheet with first round results
result_sheet.getRange(3 + top_a, 1, 1, 2).setBackgroundRGB(128, 255, 128);
result_sheet.getRange(3 + top_b, 1, 1, 2).setBackgroundRGB(128, 255, 128);
result_sheet.getRange(3 + top_a, 4 + top_b).setBackgroundRGB(128, 255, 128);
result_sheet.getRange(3 + top_b, 4 + top_a).setBackgroundRGB(128, 255, 128);
result_sheet.appendRow([' ']);
result_sheet.appendRow(['Top two are ' + candidate_names[top_a] + ", with a score of " + candidate_scores[top_a] + ", and " + candidate_names[top_b] + ", with a score of " + candidate_scores[top_b] + ", overall."]);

// Get winner from preference matrix
if(pref_matrix[top_a][top_b] >= pref_matrix[top_b][top_a])
{
winner = top_a;
loser = top_b;
}
else
{
winner = top_b;
loser = top_a;
}

// Populate sheet with final results
result_sheet.appendRow([candidate_names[winner] + " was preferred over " + candidate_names[loser] + ", " + pref_matrix[winner][loser] + " to " + pref_matrix[loser][winner]+ "."] );
result_sheet.appendRow([' ']);
result_sheet.appendRow(['The winner is: ' + candidate_names[winner]]);

}
function runElections() {
// Iterates through form items building list of scale items. When it gets to page break it runs the runElections function on the scale items on that page.
form = FormApp.getActiveForm();
responses = form.getResponses();
if(responses.length == 0)
return;

spreadsheet = SpreadsheetApp.create(form.getTitle() + " Results");
url = spreadsheet.getUrl();
SpreadsheetApp.openByUrl(url);
candidate_names = [];
election_names = [];
candidates = [];
num_elections = 0;
num_candidates = 0;
formItems = form.getItems();
for (var i = 0; i < formItems.length; i++)
{
if (formItems[i].getType() == 'PAGE_BREAK'){
runElection();
current_election_name = formItems[i].getTitle();
num_elections += 1;
candidates = [];
candidate_names = [];
num_candidates = 0;
}
else if (formItems[i].getType() == 'SCALE'){
candidates[num_candidates] = formItems[i];
candidate_names[num_candidates] = formItems[i].getTitle();
num_candidates += 1;
}
}
// run election for candidates on final page
runElection();
}
  • When you're done it will be 177 lines long and will look like this:
  • Choose "Save" from the File menu.

 

 

STEP 8: Set your election settings

  • Go back to the tab with your election and your candidate entries and click the "Settings" icon in the top right corner.
  • For secure elections set the form to collect email addresses, always give vote receipts, and limit voters to one response per email. If desired you can allow voters to edit their vote (up until the poll closes,) or to be able to view the election results as they come in.

 

 

STEP 9: Do a test run before sending out your ballots

We recommend sending yourself a ballot, casting a test vote, and taking a look at the preliminary results if you haven't hosted a STAR election with Google Forms before:

  • Go back to the tab with your election and your candidate entries and click the "Send" button in the top right corner.
  • Select "Send via email" and put in your own email address.
  • Add in your message to voters. Ask people to vote, let them know when the election deadline will be, and include any other information that you'd like to have at the top of the email with the ballot or ballot link.
  • Copy and save the message text somewhere convenient so you won't have to retype it when you send out the ballots for real.
  • Hit send.
  • Go to your inbox, open the email, check that everything looks the way you want it to, and cast a test vote.

Once you've voted, your vote will be listed in the preliminary election results. If you aren't eligible to vote in the election you'll want to delete your test ballot before the election goes live:

  • Go back to the tab with your election.
  • At the top of the page select "Responses."
  • Then click on the green Google Sheets icon near the top right of the page.
  • Click "create new spreadsheet," and then click "Create."
  • Delete your vote if desired.

STEP 10: Send out the ballots!

You can use email to send the ballots out to each eligible voter on your list, you can distribute a link to the ballot form, or you can embed the election form into your website.

  • Go back to the tab with your election itself and your candidate entries and click the "Send" button in the top right corner.
  • Paste your eligible voter email list in the "Email" section. 
  • Select the options you prefer, draft or paste in your message. (Your message should ask voters to vote, let them know the deadline, and inform them of any other relevant information they should know before participating in the election.)
  • Hit "Send."

 

 

STEP 11: Run the election

You'll need to close and re-open the form for the script option to show up in the Google Form. You can find the form easily in the "Recent" files section of your google drive.

  • Close all windows or tabs relating to your election.
  • Go to Google Forms home.
  • Select your election's thumbnail from the list and click to open it.
  • At the top of the screen, click on the puzzle piece icon and then select your election's script editor.
  • Click "Run Election"
  • Google will ask you to authorize the script to run on Google Forms and Google Spreadsheets. Go ahead and allow it.
  • The STAR Voting Calculator script creates a Google Sheet spreadsheet with the results of the election. You can find it most easily in the "Recent" files section in your Google Drive.
  • Open the spreadsheet and see the results!