def lambda_handler(event, context):
    if 'body' in event.keys():
        event = json.loads(event["body"])
    bucket = "districtr"
    state = event["state"].lower().replace(" ", "_")
    units = event["units"].lower().replace(" ", "")
    # district = event["dist_id"]
    plan_assignment = event["assignment"]
    keys = set(plan_assignment.keys())
    key = "dual_graphs/{}_{}.json".format(state, units)

    try:
        data = s3.get_object(Bucket=bucket, Key=key)
        g = json_graph.adjacency_graph(json.load(data['Body']))
        graph = Graph(g)
        assignment = {
            n: plan_assignment[n] if n in keys else -1
            for n in graph.nodes()
        }
        part = GeographicPartition(graph, assignment)
        return {'statusCode': 200, 'body': json.dumps(plan_evaluation(part))}

    except Exception as e:
        print(e)
        return {
            "error":
            "This state/units ({}, {}) is not supported".format(
                event["state"], event["units"])
        }
def set_up_graph(link):
    """
    The function used to convert online json file to adjacency graph
    Parameters:
        link (string): the link for online json file
    Returns:
        Graph: graph with the information
        mean: the mean value used for partition
    """
    link = "https://people.csail.mit.edu/ddeford//COUNTY/COUNTY_13.json"
    r = requests.get(link)
    data = json.loads(r.content)
    g = json_graph.adjacency_graph(data)
    graph = Graph(g)
    graph.issue_warnings()

    horizontal = []
    node_degree = []

    # find the node with degree 1 or 2 and remove it
    for node in graph.nodes():
        graph.nodes[node]["pos"] = [
            graph.node[node]['C_X'], graph.node[node]['C_Y']
        ]
        horizontal.append(graph.node[node]['C_X'])
        if graph.degree(node) == 1 or graph.degree(node) == 2:
            node_degree.append(node)

    # remove node with degree 1 or 2 since it will impact the outcome of graph
    for i in node_degree:
        graph.remove_node(i)

    # calculate mean value for partition
    mean = sum(horizontal) / len(horizontal)
    return graph, mean
Esempio n. 3
0
 def verify_gerrychain(df):
     try:
         Graph.from_geodataframe(fix_buffer(df))
         print("GerryChain graph created")
         return True
     except Exception as error:
         print("Unable to create GerryChain graph: ", error)
         return False
def graph_from_url():
    link = input("Put graph link: ")
    r = requests.get(link)
    data = json.loads(r.content)
    g = json_graph.adjacency_graph(data)
    graph = Graph(g)
    graph.issue_warnings()

    return graph
def graph_from_url(link):
    r = requests.get(url=link)
    data = json.loads(r.content)
    g = json_graph.adjacency_graph(data)
    graph = Graph(g)
    graph.issue_warnings()
    pos = {}
    for node in graph.nodes():
        pos[node] = [graph.node[node]['C_X'], graph.node[node]['C_Y']]
    return graph
Esempio n. 6
0
def graph_from_url():
    # link = input("Put graph link: ")
    link = "https://people.csail.mit.edu/ddeford//COUNTY/COUNTY_37.json"  # County
    # link = "https://people.csail.mit.edu/ddeford//COUSUB/COUSUB_37.json"  # COUNTY SUB
    r = requests.get(link)
    data = json.loads(r.content)
    g = json_graph.adjacency_graph(data)
    graph = Graph(g)
    graph.issue_warnings()

    return graph
Esempio n. 7
0
def save_graph(place, filename):
    print("Creating rook graph")
    rook = Graph.from_file(filename,
                           adjacency="rook",
                           columns=[col.key for col in place.columns])
    rook.to_json("./graphs/{}_rook.json".format(place.id))

    print("Creating queen graph")
    queen = Graph.from_file(filename,
                            adjacency="queen",
                            columns=[col.key for col in place.columns])
    queen.to_json("./graphs/{}_queen.json".format(place.id))
Esempio n. 8
0
def test_works_when_no_flips_occur():
    graph = Graph([(0, 1), (1, 2), (2, 3), (3, 0)])
    for node in graph:
        graph.nodes[node]["pop"] = node + 1
    partition = Partition(graph, {0: 0, 1: 0, 2: 1, 3: 1}, {"pop": Tally("pop")})

    chain = MarkovChain(lambda p: p.flip({}), [], always_accept, partition, 10)

    expected = {0: 3, 1: 7}

    for partition in chain:
        assert partition["pop"] == expected
def preprocessing(path_to_json):
    """Takes file path to JSON graph, and returns the appropriate 

    Args:
        path_to_json (String): path to graph in JSON format

    Returns:
        graph (Gerrychain Graph): graph in JSON file following cleaning
        dual (Gerrychain Graph): planar dual of graph
    """
    graph = Graph.from_json(path_to_json)
    # For each node in graph, set 'pos' parameter to position
    for node in graph.nodes():
        graph.nodes[node]['pos'] = (graph.nodes[node][config['X_POSITION']],
                                    graph.nodes[node][config['Y_POSITION']])

    save_fig(graph, config['UNDERLYING_GRAPH_FILE'], config['WIDTH'])

    # Cleans graph to be able to find planar dual
    # TODO: why is this necessary?
    #graph = duality_cleaning(graph)

    print('Making Dual')
    dual = facefinder.restricted_planar_dual(graph)
    print('Made Dual')

    return graph, dual
def main(config_data, id):
    try:
        timeBeg = time.time()
        print('Experiment', id, 'has begun')
        # Save configuration into global variable
        global config
        config = config_data

        graph = Graph.from_json(config['INPUT_GRAPH_FILENAME'])

        # List of districts in original graph
        parts = list(
            set([
                graph.nodes[node][config['ASSIGN_COL']]
                for node in graph.nodes()
            ]))
        # Ideal population of districts
        ideal_pop = sum(
            [graph.nodes[node][config['POP_COL']]
             for node in graph.nodes()]) / len(parts)

        election = Election(config['ELECTION_NAME'], {
            'PartyA': config['PARTY_A_COL'],
            'PartyB': config['PARTY_B_COL']
        })

        updaters = {
            'population': Tally(config['POP_COL']),
            'cut_edges': cut_edges,
            config['ELECTION_NAME']: election
        }

        partDict = recursive_tree_part(graph, parts, ideal_pop,
                                       config['POP_COL'], config['EPSILON'],
                                       config['NODE_REPEATS'])
        for node in graph.nodes():
            graph.nodes[node][config['ASSIGN_COL']] = partDict[node]
        part = Partition(graph=graph,
                         assignment=config['ASSIGN_COL'],
                         updaters=updaters)
        for len_ in config['RUN_LENGTHS']:
            for num in range(config['RUNS_PER_LEN']):
                run_chain(part, config['CHAIN_TYPE'], len_, ideal_pop,
                          '{}_{}_{}_{}'.format(config['TAG'], id, len_, num))

        print('Experiment {} completed in {} seconds'.format(
            id,
            time.time() - timeBeg))

    except Exception as e:
        # Print notification if any experiment fails to complete
        track = traceback.format_exc()
        print(track)
        print('Experiment {} failed to complete after {:.2f} seconds'.format(
            id,
            time.time() - timeBeg))
Esempio n. 11
0
def graph_from_url_processing(link):
    r = requests.get(url=link)
    data = json.loads(r.content)
    g = json_graph.adjacency_graph(data)
    graph = Graph(g)
    graph.issue_warnings()
    for node in graph.nodes():
        graph.nodes[node]["pos"] = [graph.nodes[node]['C_X'], graph.nodes[node]['C_Y'] ]
    deg_one_nodes = []
    for v in graph:
        if graph.degree(v) == 1:
            deg_one_nodes.append(v)
    for node in deg_one_nodes:
        graph.remove_node(node)
    return graph
Esempio n. 12
0
    def test_uses_graph_geometries_by_default(self, geodataframe):
        mock_plot = MagicMock()
        gp.GeoDataFrame.plot = mock_plot

        graph = Graph.from_geodataframe(geodataframe)
        partition = Partition(graph=graph,
                              assignment={node: 0
                                          for node in graph})
        partition.plot()
        assert mock_plot.call_count == 1
Esempio n. 13
0
def test():

    graph_path = "./Data/PA_VTDALL.json"
    graph = Graph.from_json(graph_path)
    k = 18
    ep = 0.05
    unit_id = "GEOID10"
    pop_col = "TOT_POP"

    plot_path = "./Data/VTD_FINAL"
    unit_df = gpd.read_file(plot_path)
    division_col = "COUNTYFP10"
    divisions = unit_df[[division_col, 'geometry']].dissolve(by=division_col,
                                                             aggfunc='sum')

    updaters = {"population": updaters.Tally(pop_col, alias="population")}
    cddict = recursive_tree_part(graph,
                                 range(k),
                                 df[pop_col].sum() / k,
                                 pop_col,
                                 .01,
                                 node_repeats=1)
    initial_partition = Partition(graph, cddict, updaters)
    ideal_population = sum(
        initial_partition["population"].values()) / len(initial_partition)
    division_proposal = partial(recom,
                                pop_col=pop_col,
                                pop_target=ideal_population,
                                epsilon=0.05,
                                method=partial(division_bipartition_tree,
                                               division_col=division_col),
                                node_repeats=2)

    chain = MarkovChain(proposal=division_proposal,
                        constraints=[
                            constraints.within_percent_of_ideal_population(
                                initial_partition, 0.05),
                        ],
                        accept=accept.always_accept,
                        initial_state=initial_partition,
                        total_steps=1000)

    t = 0
    snapshot = 100
    for part in chain:
        if t % snapshot == 0:
            draw_graph(graph,
                       part.assignment,
                       unit_df,
                       divisions,
                       './chain_' + str(t) + '.png',
                       geo_id=unit_id)
        t += 1
Esempio n. 14
0
def three_by_three_grid():
    """Returns a graph that looks like this:
    0 1 2
    3 4 5
    6 7 8
    """
    graph = Graph()
    graph.add_edges_from([
        (0, 1),
        (0, 3),
        (1, 2),
        (1, 4),
        (2, 5),
        (3, 4),
        (3, 6),
        (4, 5),
        (4, 7),
        (5, 8),
        (6, 7),
        (7, 8),
    ])
    return graph
Esempio n. 15
0
def test_pa_freeze():
    from gerrychain import (
        GeographicPartition,
        Graph,
        MarkovChain,
        proposals,
        updaters,
        constraints,
        accept,
    )
    import hashlib
    from gerrychain.proposals import recom
    from functools import partial

    graph = Graph.from_json("docs/user/PA_VTDs.json")

    my_updaters = {"population": updaters.Tally("TOTPOP", alias="population")}
    initial_partition = GeographicPartition(graph,
                                            assignment="CD_2011",
                                            updaters=my_updaters)

    ideal_population = sum(
        initial_partition["population"].values()) / len(initial_partition)

    # We use functools.partial to bind the extra parameters (pop_col, pop_target, epsilon, node_repeats)
    # of the recom proposal.
    proposal = partial(recom,
                       pop_col="TOTPOP",
                       pop_target=ideal_population,
                       epsilon=0.02,
                       node_repeats=2)

    pop_constraint = constraints.within_percent_of_ideal_population(
        initial_partition, 0.02)

    chain = MarkovChain(
        proposal=proposal,
        constraints=[pop_constraint],
        accept=accept.always_accept,
        initial_state=initial_partition,
        total_steps=100,
    )

    result = ""
    for count, partition in enumerate(chain):
        result += str(list(sorted(partition.population.values())))
        result += str(len(partition.cut_edges))
        result += str(count) + "\n"

    assert hashlib.sha256(result.encode()).hexdigest(
    ) == "3bef9ac8c0bfa025fb75e32aea3847757a8fba56b2b2be6f9b3b952088ae3b3c"
Esempio n. 16
0
def generate_reports(geometries, population=None):
    adj = maup.adjacencies(geometries,
                           warn_for_overlaps=False,
                           warn_for_islands=False)
    adj.crs = geometries.crs
    graph = Graph(list(adj.index))
    reports = [
        graph_report(geometries, adj),
        degree_report(geometries, adj),
        connectivity_report(graph, geometries),
        topology_report(geometries, adj),
    ]
    if population is not None:
        reports.append(population_report(geometries, population))
    return reports
Esempio n. 17
0
def preprocessing(path_to_json):
    graph = Graph.from_json(path_to_json)
    for node in graph.nodes():
        graph.nodes[node]['pos'] = [ graph.nodes[node]["C_X"], graph.nodes[node]["C_Y"] ]
    graph = duality_cleaning(graph)
    print("making dual")
    dual = restricted_planar_dual(graph)
    print("made dual")
    
    save_fig(graph,"./plots/UnderlyingGraph.png",1)
    
    for node in graph.nodes():
        graph.nodes[node]["population"] = graph.nodes[node]["TOTPOP"]


    return graph, dual
Esempio n. 18
0
    def __init__(self,
                 graph: Graph,
                 initial_state: Partition,
                 total_steps: int,
                 pop_col: str,
                 pop_tol: float,
                 compressed: bool = True,
                 reversible: bool = True,
                 seed: int = None):
        """
        :param graph: the GerryChain graph to compile to a Julia graph.
        :param initial_state: The state to start from.
        :param total_steps: The total steps to take in the chain.
        :param pop_col: The column of the graph with population data.
        :param pop_tol: The population tolerance to use.
        :param compressed: If `True`, plans are represented in `RecomStep`
            format. Otherwise, behavior mimics GerryChain.
        :param reversible: Determines if the reversible version of the chain
            should be used.
        :param seed: The random seed to use for plan generation.
        """
        for node, assignment in initial_state.assignment.items():
            graph.nodes[node]['__district'] = assignment
        graph_data = json_graph.adjacency_data(graph)
        self.graph = Flips.IndexedGraph(graph_data, pop_col)
        # TODO: verify initial state is valid w.r.t. population constraints
        #       (+ more?)
        self.plan = Flips.Plan(self.graph, '__district')
        total_pop = sum(graph.nodes[node][pop_col] for node in graph.nodes)
        districts = list(initial_state.assignment.values())
        n_districts = max(districts) - min(districts) + 1
        district_pop = total_pop / n_districts
        self.min_pop = int(ceil((1 - pop_tol) * district_pop))
        self.max_pop = int(floor((1 + pop_tol) * district_pop))
        self.reversible = reversible
        self.compressed = compressed

        self._curr_parent = initial_state
        self.total_steps = total_steps
        self._curr_step = 0
        self._buf = deque()  # https://stackoverflow.com/a/4426727/8610749
        self.data = None
        if seed is None:
            self._twister = Random.MersenneTwister()
        else:
            self._twister = Random.MersenneTwister(seed)
Esempio n. 19
0
def make_dual_graph(st, year):
    """
    Takes a 2-letter state postal code abbreviation (e.g. GA for Georgia), makes a dual graph of its shapefile, and writes the dual graph to a JSON
    
    Arguments:
    st -- 2 letter state postal code
    """

    # Fold state postal code to lowercase:
    st = st.lower()

    ##2016 Census Tract- TigerLine File for the appropriate state, follow link to download
    geo = gpd.read_file("./data/" + st + "_" + str(year) + "_tract.shp")
    graph = Graph.from_geodataframe(
        geo
    )  #if graph is successfully generated, we should be able to run chain
    graph.add_data(geo, columns=geo.columns)
    #nx.is_connected(graph) # if returns true, graph is connected
    graph.to_json("./data/" + st + "_tract.json")
Esempio n. 20
0
def preprocessing(path_to_json, output_directory):
    """Takes file path to JSON graph, and returns the appropriate

    Args:
        path_to_json ([String]): path to graph in JSON format
        output_directory: path of directory to save output in 
    Returns:
        graph (Gerrychain Graph): graph in JSON file following cleaning
        dual (Gerrychain Graph): planar dual of graph
    """
    graph = Graph.from_json(path_to_json)
    # For each node in graph, set 'pos' keyword to position
    for node in graph.nodes():
        graph.nodes[node]['pos'] = (graph.nodes[node][config['X_POSITION']],
                                    graph.nodes[node][config['Y_POSITION']])

    save_fig(graph, output_directory + '/UnderlyingGraph.png', config['WIDTH'])
    #restricted planar dual does not include unbounded face
    dual = facefinder.restricted_planar_dual(graph)

    return graph, dual
def preprocessing(path_to_json):
    """Takes file path to JSON graph, and returns the appropriate

    Args:
        path_to_json ([String]): path to graph in JSON format

    Returns:
        graph (Gerrychain Graph): graph in JSON file following cleaning
        dual (Gerrychain Graph): planar dual of graph
    """
    graph = Graph.from_json(path_to_json)
    # For each node in graph, set 'pos' keyword to position
    for node in graph.nodes():
        graph.nodes[node]['pos'] = (graph.nodes[node][config['X_POSITION']],
                                    graph.nodes[node][config['Y_POSITION']])

    save_fig(graph, config['UNDERLYING_GRAPH_FILE'], config['WIDTH'])

    dual = facefinder.restricted_planar_dual(graph)

    return graph, dual
def load_graph_from_shp(file_path, write_path, id_key, adjacency):
    global graph
    print("Loading graph...")
    start = time.perf_counter()
    graph = Graph.from_file(file_path, adjacency=adjacency)
    end = time.perf_counter()
    print("Took " + str((end - start)) + " seconds to create the graph.")
    print("This state has " + str(len(graph.nodes)) + " blocks")

    # write matrix
    adj_mat = np.zeros((len(graph.nodes), len(graph.nodes)))
    if id_key not in graph.nodes[0].keys():
        print(id_key, "not found in node attributes.")
        print("Attributes: ", graph.nodes[0].keys())
    ids = [graph.nodes[i][id_key] for i in range(len(graph.nodes))]
    for e in graph.edges:
        adj_mat[e[0], e[1]] = 1
        adj_mat[e[1], e[0]] = 1
    print("Writing adjacency matrix and IDs to file...")
    with open(write_path, 'w') as outfile:
        json.dump({"order": ids, "adj": adj_mat.tolist()}, outfile)
    print("Done! JSON written to " + write_path)
Esempio n. 23
0
def slow_reversible_propose(partition):

    flip = random.choice(list(partition["b_nodes"]))
    
    return partition.flip({flip[0]: flip[1]})

#graph = Graph.from_file("./State_Data/VA_Trimmed.shp")


#with open("./State_Data/VA_Trimmedj.json", 'w') as outfile:
#    json.dump(json_graph.adjacency_data(graph), outfile)

#graph.to_json("./State_Data/VA_Trimmed.json")

graph = Graph.from_json("./State_Data/VA_Trimmed.json")

df = gpd.read_file("./State_Data/VA_Trimmed.shp")

print("loaded data")
#print("nodes",len(graph.nodes()))
#print("edges",len(graph.edges()))


for node in graph.nodes():
    graph.nodes[node]["nBVAP"] = graph.nodes[node]["VAPERSONS"] - graph.nodes[node]["VAPBLACK"]

"""
updater = { "population": updaters.Tally("TAPERSONS", alias="population"),
"cut_edges",cut_edges,
"BVAP":Election("BVAP",{"BVAP":"VAPBLACK","nBVAP":"nBVAP"}),
Esempio n. 24
0
import json
from gerrychain import (
    Election,
    Graph,
    MarkovChain,
    Partition,
    accept,
    constraints,
    updaters,
)
from gerrychain.tree import recursive_tree_part
import numpy as np
import pickle
import wasserplan

graph = Graph.from_json("NC_VTD.json")


def get_partition(partition_file, fid_to_geoid_file, geoidcol):
    fid_to_node = get_fid_to_node(fid_to_geoid_file, geoidcol)
    fid_to_district = {}
    f = open(partition_file, 'r')
    for line in f:
        lineitems = line.rstrip("\n").split("\t")
        fid, district = int(lineitems[0]) + 1, int(lineitems[1])
        fid_to_district[fid] = district
    assignment = {}
    for fid in fid_to_district:
        assignment[
            fid_to_node[fid]] = fid_to_district[fid] - 1  #make 0-indexed
    return assignment
Esempio n. 25
0
from numpy import linalg as LA
import matplotlib.pyplot as plt
from sklearn.cluster import SpectralClustering
from sklearn import metrics
from networkx.algorithms.community import greedy_modularity_communities
from networkx.algorithms.community import label_propagation_communities
from gerrychain import Graph

import geopandas as gpd

G = nx.karate_club_graph()
n = 34
G = nx.grid_graph([5, 5])
n = 25

G = Graph.from_json("./County05.json")
n = len(list(G.nodes()))
df = gpd.read_file("./County05.shp")

AM = nx.adjacency_matrix(G)
NLM = (nx.normalized_laplacian_matrix(G)).todense()
LM = (nx.laplacian_matrix(G)).todense()
'''
Labels = [G.nodes[i]['club'] != 'Mr. Hi' for i in G.nodes()]


plt.figure()
plt.title("Data Labels")
nx.draw(G, node_color=Labels )
plt.show()
'''
Esempio n. 26
0
def example_partition():
    graph = Graph.from_networkx(networkx.complete_graph(3))
    assignment = {0: 1, 1: 1, 2: 2}
    partition = Partition(graph, assignment, {"cut_edges": cut_edges})
    return partition
import matplotlib.pyplot as plt
import random
import numpy as np
from gerrychain import Graph
import geopandas as gpd
from gerrychain.tree import recursive_tree_part
from gerrychain.partition import Partition
from gerrychain.updaters import Tally, cut_edges

g = nx.grid_graph([10, 10])

g = nx.karate_club_graph()

ns = 50

g = Graph.from_json("./Data/BG05.json")
df = gpd.read_file("./Data/BG05.shp")
centroids = df.centroid
c_x = centroids.x
c_y = centroids.y
shape = True

nlist = list(g.nodes())
n = len(nlist)

totpop = 0
for node in g.nodes():
    g.node[node]["TOTPOP"] = int(g.node[node]["TOTPOP"])

    totpop += g.node[node]["TOTPOP"]
    # fill-in unspecified configs using default values
    for ckey in available_config.keys():
        if ckey not in config.keys():
            print("Using default value", ckey, "=", default_config[ckey],
                  "since no option was selected.")
            config[ckey] = default_config[ckey]

    # initialize dictionary to store this run's results
    result = config
    result['run'] = key

    # read input data
    state = config['state']
    code = state_codes[state]
    level = config['level']
    G = Graph.from_json("../data/" + level + "/dual_graphs/" + level + code +
                        ".json")
    DG = nx.DiGraph(G)  # bidirected version of G
    df = gpd.read_file("../data/" + level + "/shape_files/" + state + "_" +
                       level + ".shp")

    # set parameters
    k = number_of_congressional_districts[state]
    population = [G.nodes[i]['TOTPOP'] for i in G.nodes()]
    deviation = 0.01
    U = math.floor((1 + deviation / 2) * (sum(population) / k))
    L = math.ceil((1 - deviation / 2) * (sum(population) / k))
    ideal = math.floor(sum(population) / k)

    print("k =", k)
    result['k'] = k
    result['n'] = G.number_of_nodes()
    "SEN16R",
    "SEN16L",
]
for x in df.columns:
    if x in variables:
        df[x] = df[x].astype(int)
#county_col = "COUNTYFP10"
pop_col = "TOTPOP"

df["CPOP"] = df["TOTPOP"] - df["NCPOP"]
ccol = "CPOP"
uid = "ID"

num_districts = 14

graph = Graph.from_geodataframe(df, ignore_errors=True)
graph.add_data(df, list(df))
graph = nx.relabel_nodes(graph, df[uid])

elections = [
    Election("PRES16", {
        "Democratic": "PRES16D",
        "Republican": "PRES16R"
    }),
    Election("SEN16", {
        "Democratic": "SEN16D",
        "Republican": "SEN16R"
    })
]

#my_updaters = {"population" : updaters.Tally("TOTPOP", alias="population")}
Esempio n. 30
0
test_05["polsbypopper"]

plt.hist(test_05["eg"], bins=50)

# load actual gerrychain results
sen_05 = np.load(
    "/Users/hopecj/projects/gerryspam/MO/res_0817/MO_state_senate_300000_0.05.p"
)
sen_01 = np.load(
    "/Users/hopecj/projects/gerryspam/MO/res_0817/MO_state_senate_100000_0.01.p"
)
sen_05.keys()  # shows "columns" available
print(sen_05["mean_median_ussen16"])  # results from chain

# open enacted map
graph = Graph.from_file(
    "/Users/hopecj/projects/gerryspam/MO/dat/final_prec/prec_labeled.shp")
elections = [
    Election("USSEN16", {
        "Dem": "G16USSDKAN",
        "Rep": "G16USSRBLU"
    }),
    Election("PRES16", {
        "Dem": "G16PREDCLI",
        "Rep": "G16PRERTRU"
    })
]

mo_updaters = {
    "population": Tally("POP10", alias="population"),
    "cut_edges": cut_edges
}