Last active
August 10, 2022 08:59
-
-
Save rlucioni/8bdb1092579041ce739c to your computer and use it in GitHub Desktop.
Senate Vote Scraper and Graph Builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
from itertools import combinations | |
import requests | |
import networkx as nx | |
def get_senate_vote(vote): | |
# Year can be replaced to fetch votes from different years (e.g., 2013). 1989 is used | |
# as an example. | |
url = "https://www.govtrack.us/data/congress/101/votes/1989/s{}/data.json".format(vote) | |
page = requests.get(url).text | |
try: | |
data = json.loads(page) | |
return data | |
except ValueError: | |
raise Exception("Not a valid vote number.") | |
def get_all_votes(): | |
vote_num = 1 | |
vote_dicts = [] | |
while True: | |
try: | |
vote_dict = get_senate_vote(vote_num) | |
vote_dicts.append(vote_dict) | |
vote_num += 1 | |
except Exception: | |
break | |
return vote_dicts | |
def vote_graph(data): | |
graph = nx.Graph() | |
# Set to contain all senator display names - these will be our nodes | |
all_senators = set() | |
# List to contain roll_call dicts, one for each vote | |
roll_calls = [] | |
for vote in data: | |
# Dict with keys for each vote class; values are lists of senator display names | |
roll_call = {} | |
for key, value in vote['votes'].iteritems(): | |
senators = [] | |
for senator in value: | |
if senator == 'VP': | |
continue | |
senators.append(senator['display_name']) | |
roll_call[key] = senators | |
# Add any new senators to the set | |
all_senators.update(senators) | |
roll_calls.append(roll_call) | |
# All combinations of 2 senator display names | |
all_senator_pairs = combinations(all_senators, 2) | |
common_votes = {} | |
for pair in all_senator_pairs: | |
common_votes[pair] = 0 | |
for vote in roll_calls: | |
yea_pairs = combinations(vote['Yea'], 2) | |
for pair in yea_pairs: | |
try: | |
common_votes[pair] += 1 | |
except KeyError: | |
# Flip senator names so we can find the pair in the common_votes db | |
common_votes[(pair[1],pair[0])] += 1 | |
nay_pairs = combinations(vote['Nay'], 2) | |
for pair in nay_pairs: | |
try: | |
common_votes[pair] += 1 | |
except KeyError: | |
common_votes[(pair[1],pair[0])] += 1 | |
for senator in all_senators: | |
party = senator.split()[1][1] | |
# Use color names that Graphviz understands | |
if party == 'D': | |
graph.add_node(senator, color='blue') | |
elif party == 'R': | |
graph.add_node(senator, color='red') | |
else: | |
graph.add_node(senator, color='black') | |
for pair, votes in common_votes.iteritems(): | |
# Don't draw an edge for senators with 0 votes in common | |
if votes == 0: | |
continue | |
graph.add_edge(pair[0], pair[1], weight=votes, difference=1.0/votes) | |
return graph | |
vote_data = get_all_votes() | |
votes = vote_graph(vote_data) | |
nx.write_gexf(votes, 'votes-101-1989.gexf') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment