A little US election results mashup

NEM 2008-11-05: Flagging a little watching the results from the 2008 US Presidential election trickle in, when I stumbled upon this article [1 ] at Ars Technica describing how to grab a live JSON feed of the results from Google/Amazon. So, here's code to periodically poll the feed and show the overall candidate votes and electoral college votes in a little table. Would love someone to combine this with TkWorld or something similar to show the results graphically on a map of the US, but must sleep soon... :-)

package require http
package require json

variable DATA_URL http://election2008.s3.amazonaws.com/votes/us-pres.json

# Main routine - fetches data, decodes it, then displays it :-)[NEM] 2008-11-05: Flagging a little watching the results from the 2008 US
Presidential election trickle in, when I stumbled upon this article
[http://arstechnica.com/journals/linux.ars/2008/11/04/code-your-own-election-mashup-with-googles-json-data]
at Ars Technica describing how to grab a live [JSON] feed of the results from
Google/Amazon. So, here's code to periodically poll the feed and show the
overall candidate votes and electoral college votes in a little table. Would
love someone to combine this with [TkWorld] or something similar to show the
results graphically on a map of the US, but must sleep soon... :-)

package require http package require json

variable DATA_URL http://election2008.s3.amazonaws.com/votes/us-pres.json

# Main routine - fetches data, decodes it, then displays it :-) proc refresh url { display [decode [fetch $url] }

# Fetch the data proc fetch url {

    set t [http::geturl $url]
    if {[http::ncode $t] == 200} {
        set data [http::data $t]
    } else {
        set data {}
    }
    http::cleanup $t
    return $data

}

# Decode the JSON data and extract some summary information proc decode data {

    set data [json::json2dict $data]
    set ret [list]
    foreach candidate [dict get $data totals races President "" votes] {
        set name [dict get $data candidates [dict get $candidate id]]
        set name [lindex [split $name "|"] 2]
        set vote [dict get $candidate votes]
        set electoral [dict get $candidate electoral]
        lappend ret $name $vote $electoral
    }
    return $ret

}

# Display the data in a neat table proc display data {

    puts "Time: [clock format [clock seconds]]"
    puts [string repeat "-" 60]
    puts [format "%-30s | %10s | %10s" "Candidate" "Votes" "Electoral"]
    puts [string repeat "-" 60]
    foreach {name votes electoral} $data {
        puts [format "%-30s | %10d | %10d" $name $votes $electoral]
    }
    puts [string repeat "-" 60]
    puts ""

}

# Set up a repeating event proc every {interval units action} {

    uplevel #0 $action
    after [$units $interval] [namespace code [info level 0]]

}

# Convert times from various units to milliseconds proc seconds t { expr {$t * 1000} } proc minutes t { expr {seconds $t * 60} } proc hours t { expr {minutes $t * 60} }

# Main routine - parse arguments and start everything running proc election {interval units} {

    variable DATA_URL
    every $interval $units [list refresh $DATA_URL]
    vwait forever

}

election {*}$argv

To use just run the script like: tclsh election.tcl 5 minutes

<<categories>> Toys

proc refresh url { display [decode [fetch $url]] }

# Fetch the data
proc fetch url {
    set t [http::geturl $url]
    if {[http::ncode $t] == 200} {
        set data [http::data $t]
    } else {
        set data {}
    }
    http::cleanup $t
    return $data
}

# Decode the JSON data and extract some summary information
proc decode data {
    set data [json::json2dict $data]
    set ret [list]
    foreach candidate [dict get $data totals races President "" votes] {
        set name [dict get $data candidates [dict get $candidate id]]
        set name [lindex [split $name "|"] 2]
        set vote [dict get $candidate votes]
        set electoral [dict get $candidate electoral]
        lappend ret $name $vote $electoral
    }
    return $ret
}

# Display the data in a neat table
proc display data {
    puts "Time: [clock format [clock seconds]]"
    puts [string repeat "-" 60]
    puts [format "%-30s | %10s | %10s" "Candidate" "Votes" "Electoral"]
    puts [string repeat "-" 60]
    foreach {name votes electoral} $data {
        puts [format "%-30s | %10d | %10d" $name $votes $electoral]
    }
    puts [string repeat "-" 60]
    puts ""
}

# Set up a repeating event
proc every {interval units action} {
    uplevel #0 $action
    after [$units $interval] [info level 0]
}

# Convert times from various units to milliseconds
proc seconds t { expr {$t * 1000} }
proc minutes t { expr {[seconds $t] * 60} }
proc hours   t { expr {[minutes $t] * 60} }

# Main routine - parse arguments and start everything running
proc election {interval units} {
    variable DATA_URL
    every $interval $units [list refresh $DATA_URL]
    vwait forever
}

election {*}$argv

To use just run the script like: tclsh election.tcl 5 minutes