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"])
        }
Пример #2
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"
Пример #3
0
def run_GerryChain_heuristic(G, population_deviation, k, iterations):

    my_updaters = {"population": updaters.Tally("TOTPOP", alias="population")}
    start = recursive_tree_part(
        G, range(k),
        sum(G.nodes[i]["TOTPOP"] for i in G.nodes()) / k, "TOTPOP",
        population_deviation / 2, 1)
    initial_partition = GeographicPartition(G, start, updaters=my_updaters)

    proposal = partial(recom,
                       pop_col="TOTPOP",
                       pop_target=sum(G.nodes[i]["TOTPOP"]
                                      for i in G.nodes()) / k,
                       epsilon=population_deviation / 2,
                       node_repeats=2)

    compactness_bound = constraints.UpperBound(
        lambda p: len(p["cut_edges"]),
        1.5 * len(initial_partition["cut_edges"]))

    pop_constraint = constraints.within_percent_of_ideal_population(
        initial_partition, population_deviation / 2)

    my_chain = MarkovChain(proposal=proposal,
                           constraints=[pop_constraint, compactness_bound],
                           accept=accept.always_accept,
                           initial_state=initial_partition,
                           total_steps=iterations)

    min_cut_edges = sum(G[i][j]['edge_length'] for i, j in G.edges)
    print("In GerryChain heuristic, current # of cut edges: ", end='')
    print(min_cut_edges, ",", sep='', end=' ')
    for partition in my_chain:
        current_cut_edges = sum(G[i][j]['edge_length']
                                for i, j in partition["cut_edges"])
        print(current_cut_edges, ",", sep='', end=' ')
        if current_cut_edges < min_cut_edges:
            best_partition = partition
            min_cut_edges = current_cut_edges

    print("Best heuristic solution has # cut edges =", min_cut_edges)
    return ([[i for i in G.nodes if best_partition.assignment[i] == j]
             for j in range(k)], min_cut_edges)
Пример #4
0
def run_chain(adj_graph, elections, total_steps=100):
    my_updaters = {
        "population": updaters.Tally("population"),
        "cut_edges": cut_edges,
        "elections": lambda x: [elec.alias for elec in elections],
        "expected_seat_share": expected_seat_share_updater
    }
    election_updaters = {election.name: election for election in elections}
    my_updaters.update(election_updaters)

    initial_partition = GeographicPartition(adj_graph,
                                            assignment="initial_plan",
                                            updaters=my_updaters)
    ideal_population = sum(
        initial_partition["population"].values()) / len(initial_partition)
    proposal = partial(recom,
                       pop_col="population",
                       pop_target=ideal_population,
                       epsilon=0.01,
                       node_repeats=2)
    pop_constraint = constraints.within_percent_of_ideal_population(
        initial_partition, 0.01)
    chain = MarkovChain(proposal=proposal,
                        constraints=[
                            pop_constraint,
                        ],
                        accept=accept.always_accept,
                        initial_state=initial_partition,
                        total_steps=total_steps)

    return pd.DataFrame({
        ix: {
            "cut_edges": len(partition["cut_edges"]),
            "expected_R_seats": partition["expected_seat_share"]
        }
        for ix, partition in enumerate(chain)
    }).T
Пример #5
0
## ## ## ## ## ## ## ## ## ## ## 
## Initial partition
## ## ## ## ## ## ## ## ## ## ## 
print("Creating seed plan")

##################################################################
######## ! if using a random map as the initial partition
##################################################################
# NUM_DISTRICTS=34
# EPS=0.05
total_pop = sum(dat[POP_COL])
ideal_pop = total_pop / NUM_DISTRICTS
cddict = recursive_tree_part(graph=graph, parts=range(NUM_DISTRICTS), 
                                pop_target=ideal_pop, pop_col=POP_COL, epsilon=EPS)

init_partition = GeographicPartition(graph, assignment=cddict, updaters=mo_updaters)
# init_partition["USSEN16"].efficiency_gap() #PRES EG = -0.08, USSEN EG = -0.18

##################################################################
######## ! if using the enacted state senate map as the initial partition
##################################################################
# init_partition = GeographicPartition(graph, assignment="SLDUST", updaters=mo_updaters)
# init_partition["USSEN16"].efficiency_gap() 
# ideal_pop = sum(init_partition['population'].values()) / len(init_partition)

# # show stuff about the initial partition
# init_partition.graph
# init_partition.graph.nodes[0] 
# init_partition['population']

# for district, pop in init_partition["population"].items():
def plan_evaluation(partition):
    graph = partition.graph

    # Naming constants
    county_column = "COUNTY"
    municipality_column = "TOWN"

    # Contiguity
    split_districts = []
    for district in partition.parts.keys():
        if district != -1:
            part_contiguous = nx.is_connected(partition.subgraphs[district])
            if not part_contiguous:
                split_districts.append(district)
    contiguity = (len(split_districts) == 0)

    # Calculate cut edges
    cut_edges = updaters.cut_edges(partition)

    # Polsby Popper
    try:
        polsbypopper = [
            v for _k, v in metrics.polsby_popper(partition).items()
        ]
        polsbypopper_stats = {
            'max': max(polsbypopper),
            'min': min(polsbypopper),
            'mean': statistics.mean(polsbypopper),
            'median': statistics.median(polsbypopper)
        }
        if len(polsbypopper) > 1:
            polsbypopper_stats['variance'] = statistics.variance(polsbypopper)
    except:
        polsbypopper = []
        polsbypopper_stats = "Polsby Popper unavailable for this geometry."

    # county splits

    try:
        county_splits = updaters.county_splits("county_splits",
                                               county_column)(partition)
        county_response = {}
        counties = set([graph.nodes[n][county_column] for n in graph.nodes])
        county_response['num_counties'] = len(counties)
        try:
            county_partition = GeographicPartition(
                graph, county_column,
                {"population": updaters.Tally('TOTPOP', alias="population")})
            county_pop_dict = {
                c: county_partition.population[c]
                for c in counties
            }
            county_response['population'] = county_pop_dict
        except KeyError:
            county_response['population'] = -1
        split_list = {}
        splits = 0
        num_split = 0
        for c in counties:
            s = county_splits[c].contains
            # this is caused by a bug in some states in gerrychain I think
            if -1 in s:
                s.remove(-1)
            if len(s) > 1:
                num_split += 1
                split_list[c] = list(s)
                splits += len(s) - 1
        county_response['splits'] = splits
        county_response['split_list'] = split_list
    except:
        county_response = -1

    # municipality splits
    try:
        municipality_splits = updaters.county_splits(
            "muni_splits", municipality_column)(partition)
        muni_response = {}
        munis = set([graph.nodes[n][municipality_column] for n in graph.nodes])
        muni_response['num_counties'] = len(munis)
        try:
            muni_partition = GeographicPartition(
                graph, municipality_column,
                {"population": updaters.Tally('TOTPOP', alias="population")})
            muni_pop_dict = {m: muni_partition.population[m] for m in munis}
            muni_response['population'] = muni_pop_dict
            muni_response['num_counties'] = len(munis)
        except KeyError:
            muni_response['population'] = -1
        split_list = {}
        splits = 0
        num_split = 0
        for m in munis:
            s = municipality_splits[m].contains
            # this is caused by a bug in some states in gerrychain I think
            if -1 in s:
                s.remove(-1)
            if len(s) > 1:
                num_split += 1
                split_list[m] = list(s)
                splits += len(s) - 1
        muni_response['splits'] = splits
        muni_response['split_list'] = split_list
    except:
        muni_response = -1

    # Build Response dictionary
    response = {
        'cut_edges': len(cut_edges),
        'contiguity': contiguity,
        'split': split_districts,
        'polsbypopper': polsbypopper_stats,
        'pp_scores': polsbypopper,
        'num_units': len(graph.nodes),
        'counties': county_response,
        'municipalities': muni_response
    }
    return response
Пример #7
0
def chain(iterations):
    idef = random.randint(1, 10000)
    graph = Graph.from_json("./PA_VTD.json")

    election = Election("SEN12", {"Dem": "USS12D", "Rep": "USS12R"})

    initial_partition = GeographicPartition(graph,
                                            assignment="2011_PLA_1",
                                            updaters={
                                                "cut_edges":
                                                cut_edges,
                                                "population":
                                                Tally("TOT_POP",
                                                      alias="population"),
                                                "SEN12":
                                                election
                                            })

    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="TOT_POP",
                       pop_target=ideal_population,
                       epsilon=0.02,
                       node_repeats=2)

    chain = MarkovChain(proposal=proposal,
                        constraints=[republican_constraint],
                        accept=contiguous,
                        initial_state=initial_partition,
                        total_steps=iterations + 100)

    count = 0
    metrics = []
    boundary_nodes = []
    boundary_weighted = []
    for partition in chain.with_progress_bar():
        mm = mean_median(partition["SEN12"])
        p = pp(partition)
        bias = partisan_bias(partition["SEN12"])
        gini = partisan_gini(partition["SEN12"])
        gap = efficiency_gap(partition["SEN12"])
        cut = len(partition["cut_edges"])
        if count >= 100:
            metrics.append((mm, p, bias, gini, gap, cut))
            nodes = [0] * 8921
            bnodes = [0] * 8921
            for edge in partition["cut_edges"]:
                nodes[edge[0]] = 1
                nodes[edge[1]] = 1
                bnodes[edge[0]] += 1
                bnodes[edge[1]] += 1
            boundary_nodes.append(nodes)
            boundary_weighted.append(bnodes)
        if count % 100 == 0:
            print(idef, count, mm, p, bias, gini, gap, cut,
                  partition["SEN12"].wins("Rep"))
        count += 1

    return metrics, boundary_nodes, boundary_weighted
Пример #8
0
def chain(iterations):
    idef = random.randint(1, 10000)
    graph = Graph.from_json("../data/PA_init/PA_VTD.json")

    election = Election("SEN12", {"Dem": "USS12D", "Rep": "USS12R"})

    initial_partition = GeographicPartition(
        graph,
        assignment="2011_PLA_1",
        updaters={
            "cut_edges": cut_edges,
            "population": Tally("TOT_POP", alias="population"),
            "SEN12": election
        }
    )

    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="TOT_POP",
                       pop_target=ideal_population,
                       epsilon=0.02,
                       node_repeats=2
                      )

    chain = MarkovChain(
            proposal=proposal,
            constraints=[],
            accept=contiguous,
            initial_state=initial_partition,
            total_steps=85*iterations + 17000
        )

    count = 0
    metrics = []
    boundary_nodes = []
    boundary_weighted = []
    for partition in chain.with_progress_bar(): 
        mm = mean_median(partition["SEN12"])
        p = pp(partition)
        bias = partisan_bias(partition["SEN12"])
        gini = partisan_gini(partition["SEN12"])
        gap = efficiency_gap(partition["SEN12"])
        cut = len(partition["cut_edges"])
        if count >= 17000:
            if count % 85 == 0: 
                metrics.append((mm, p, bias, gini, gap, cut, partition["SEN12"].wins("Rep")))
                nodes = [0]*8921
                bnodes = [0]*8921
                for edge in partition["cut_edges"]:
                    nodes[edge[0]] = 1
                    nodes[edge[1]] = 1
                    bnodes[edge[0]] += 1
                    bnodes[edge[1]] += 1
                boundary_nodes.append(nodes)
                boundary_weighted.append(bnodes)

                assign = {i: partition.assignment[i] for i in partition.assignment}
                shape["CD"] = shape.index.map(assign)
                this_map = shape.dissolve(by='CD')
                this_map.plot(color='white', edgecolor='black')
                plt.axis('off')
                fig = plt.gcf()
                fig.set_size_inches((15,9), forward=False)
                fig.savefig("../images/PA_neutral/" + str(idef) + str(int((count-17000)/85)+1) + ".png", dpi=600, bbox_inches="tight", pad_inches=0)

                plt.close()

            if count % 8500 == 0: 
                print(idef, count, mm, p, bias, gini, gap, cut, partition["SEN12"].wins("Rep"))
        else:
            if count%1000 == 0:
                print(idef, "Mixing...... Iteration", count, "/17000")
        count += 1

    return metrics, boundary_nodes, boundary_weighted, idef
#Use ReCom to build gerrychain and plot.
elections = [
    Election("PRES16", {
        "Dem": "G16DPRS",
        "Rep": "G16RPRS"
    }),
    Election("SEN12", {
        "Dem": "G18DSEN",
        "Rep": "G18RSEN"
    })
]
my_updaters = {"population": updaters.Tally("TOTPOP", alias="population")}
election_updaters = {election.name: election for election in elections}
my_updaters.update(election_updaters)
initial_partition = GeographicPartition(graph,
                                        assignment="CD_16",
                                        updaters=my_updaters)
# The ReCom proposal needs to know the ideal population for the districts so that
# we can improve speed by bailing early on unbalanced partitions.

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.03,
                   node_repeats=2)
compactness_bound = constraints.UpperBound(
Пример #10
0
    Election(
        election_names[i],
        {
            "Dem": election_columns[i][0],
            "Rep": election_columns[i][1]
        },
    ) for i in range(num_elections)
]

election_updaters = {election.name: election for election in elections}

updaters.update(election_updaters)

# ---- Past Districting Plan  -----

districting_partition = GeographicPartition(graph, district_assignment_col,
                                            updaters)

compactness_ref = len(districting_partition["cut_edges"])
county_splits_ref = calc_splits(districting_partition["county_splits"])
racial_vap_ref = districting_partition["racial_demographics"]

# ---- Chain Run ------

# population calculation
pop = 0

for n in graph.nodes:
    pop = pop + graph.nodes[n][pop_col]

# --- Create random initial partition -------
Пример #11
0
            nlist = list(g.nodes())
            n = len(nlist)

            shuffle = False
            num_steps = 10

            pos = nx.kamada_kawai_layout(g)
            if shape:
                pos = {node: (c_x[node], c_y[node]) for node in g.nodes}

            unique_id = 0
            for n in nlist:
                g.node[n]["PP_ID"] = unique_id
                unique_id += 1

            pp_dic = GeographicPartition(g, "PP_ID", {"pp": polsby_popper})

            bg_pp_list = list(pp_dic["pp"].values())
            k = 2
            for n in nlist:
                if bg_pp_list[n] > 0.8:
                    g.node[n]["cddict"] = 0
                elif bg_pp_list[n] < 0.1:
                    g.node[n]["cddict"] = 1
                else:
                    g.node[n]["cddict"] = random.choice([0, 1])

            nx.draw(g,
                    pos=pos,
                    node_color=[g.node[x]["cddict"] for x in nlist],
                    node_size=25)
Пример #12
0
]

# Configure our updaters (everything we want to compute for each plan in the ensemble).

# Population updater, for computing how close to equality the district
# populations are. "TOT_POP" is the population column from our shapefile.
my_updaters = {"population": updaters.Tally("TOT_POP", alias="population")}

# Election updaters, for computing election results using the vote totals
# from our shapefile.
election_updaters = {election.name: election for election in elections}
my_updaters.update(election_updaters)

# Instantiate the initial state of our Markov chain, using the 2011 districting plan.
initial_partition = GeographicPartition(graph,
                                        assignment="2011_PLA_1",
                                        updaters=my_updaters)

# GeographicPartition comes with built-in ``area`` and ``perimeter`` updaters.

# ## Setting up the Markov chain

# The recom proposal needs to know the ideal population for the districts so that
# we can improve speed by bailing early on unbalanced partitions.
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="TOT_POP",
Пример #13
0
    election.name: election
    for election in election_functions
}
my_updaters.update(election_updaters)

#initial partition#######################################################
step_Num = 0
total_population = state_gdf[tot_pop].sum()
ideal_population = total_population / num_districts

if start_map == 'new_seed':
    start_map = recursive_tree_part(graph, range(num_districts),
                                    ideal_population, tot_pop, pop_tol, 3)

initial_partition = GeographicPartition(graph=graph,
                                        assignment=start_map,
                                        updaters=my_updaters)

proposal = partial(recom,
                   pop_col=tot_pop,
                   pop_target=ideal_population,
                   epsilon=pop_tol,
                   node_repeats=3)


#constraints ############################################
def inclusion(partition):
    """
    Returns 'True' if proposed plan has greater than or equal to the number of Black, Latino and 
    distinct effective districts as the enacted map.
    """
Пример #14
0
def run_GerryChain_heuristic(G, population_deviation, k, threshold,
                             iterations):

    my_updaters = {"population": updaters.Tally("TOTPOP", alias="population")}
    start = recursive_tree_part(
        G, range(k),
        sum(G.nodes[i]["TOTPOP"] for i in G.nodes()) / k, "TOTPOP",
        population_deviation / 2, 1)
    initial_partition = GeographicPartition(G, start, updaters=my_updaters)

    proposal = partial(recom,
                       pop_col="TOTPOP",
                       pop_target=sum(G.nodes[i]["TOTPOP"]
                                      for i in G.nodes()) / k,
                       epsilon=population_deviation / 2,
                       node_repeats=2)

    compactness_bound = constraints.UpperBound(
        lambda p: len(p["cut_edges"]),
        1.5 * len(initial_partition["cut_edges"]))

    pop_constraint = constraints.within_percent_of_ideal_population(
        initial_partition, population_deviation / 2)

    my_chain = MarkovChain(proposal=proposal,
                           constraints=[pop_constraint, compactness_bound],
                           accept=accept.always_accept,
                           initial_state=initial_partition,
                           total_steps=iterations)

    min_cut_edges = sum(G[i][j]['edge_length'] for i, j in G.edges)
    print(
        "In GerryChain heuristic, current # of cut edges and minority districts: ",
        end='')
    print(min_cut_edges, ",", sep='', end=' ')
    max_of_minority_districts = -1
    all_maps = []
    pareto_frontier = []
    obj_vals = []
    for partition in my_chain:
        current_cut_edges = sum(G[i][j]['edge_length']
                                for i, j in partition["cut_edges"])
        number_minority_district = 0
        for district in range(k):
            total_pop_district = 0
            total_pop_minority = 0
            for node in partition.graph:
                if partition.assignment[node] == district:
                    total_pop_district += G.node[node]["VAP"]
                    total_pop_minority += G.node[node]["BVAP"]
                    #total_pop_minority += G.node[node]["HVAP"]
                    #total_pop_minority += G.node[node]["AMINVAP"]
                    #total_pop_minority += G.node[node]["ASIANVAP"]
                    #total_pop_minority += G.node[node]["NHPIVAP"]
            if (total_pop_minority > threshold * total_pop_district):
                number_minority_district += 1
        if number_minority_district > max_of_minority_districts:
            max_of_minority_districts = number_minority_district
        if current_cut_edges < min_cut_edges:
            min_cut_edges = current_cut_edges
        print((current_cut_edges, number_minority_district),
              ",",
              sep='',
              end=' ')
        obj_vals.append([current_cut_edges, number_minority_district])
        all_maps.append(
            [partition, current_cut_edges, number_minority_district])

    print("Best heuristic solution has # cut edges =", min_cut_edges)
    print("Best heuristic solution has # minority districts =",
          max_of_minority_districts)

    all_maps.sort(key=lambda x: x[1])
    all_maps.sort(key=lambda x: x[2], reverse=True)
    pareto_frontier.append(all_maps[0])
    least_number_of_cut_edges = all_maps[0][1]
    for i in range(1, len(all_maps)):
        if all_maps[i][1] < least_number_of_cut_edges:
            pareto_frontier.append(all_maps[i])
            least_number_of_cut_edges = all_maps[i][1]

    print("Pareto Frontier: ", pareto_frontier)

    optimal_maps = []
    optimal_cut_edges = []
    optimal_minority_districts = []

    for plan in pareto_frontier:
        optimal_maps.append(
            [[i for i in G.nodes if plan[0].assignment[i] == j]
             for j in range(k)])
        optimal_cut_edges.append(plan[1])
        optimal_minority_districts.append(plan[2])

    return (optimal_maps, optimal_cut_edges, optimal_minority_districts,
            obj_vals)
Пример #15
0
    Election(
        election_names[i],
        {
            "Dem": election_columns[i][0],
            "Rep": election_columns[i][1]
        },
    ) for i in range(num_elections)
]

election_updaters = {election.name: election for election in elections}

updaters.update(election_updaters)

# ---- Proposed Partition -----

prop_partition = GeographicPartition(graph, district_assignment_col, updaters)

# ---- Geographic Metrics ------

# County Splits
num_county_splits = calc_splits(prop_partition["county_splits"])
upper_county = len(prop_partition["county_splits"])

county_partition = GeographicPartition(graph, county_assignment_col, updaters)

if cong:
    threshold_pop = cong_factor * cong_seat_pop
else:
    total_pop = 0
    for n in graph.nodes:
        total_pop = total_pop + graph.nodes[n][pop_col]
    Election(
        election_names[i],
        {
            "Dem": election_columns[i][0],
            "Rep": election_columns[i][1]
        },
    ) for i in range(num_elections)
]

election_updaters = {election.name: election for election in elections}

updaters.update(election_updaters)

# ---- Proposed Partition -----

initial_partition = GeographicPartition(graph, district_assignment_col,
                                        updaters)

# ---- Chain Run ------

pop = 0

for n in graph.nodes:
    pop = pop + graph.nodes[n][pop_col]

proposal = partial(recom,
                   pop_col=pop_col,
                   pop_target=pop / num_dist,
                   epsilon=0.05,
                   node_repeats=3)

compactness_bound = constraints.UpperBound(lambda p: len(p["cut_edges"]),
Пример #17
0
def main(graph_json, shp, n_steps, output_dir, prefix, seed, pop_col, pop_tol,
         plan_col, reproject, election):
    os.makedirs(output_dir, exist_ok=True)
    has_geometry = False
    if not shp and not graph_json:
        print('Specify a shapefile or a NetworkX-format graph '
              'JSON file.',
              file=sys.stderr)
        sys.exit(1)
    elif shp and not graph_json:
        gdf = gpd.read_file(shp)
        if reproject:
            gdf = reprojected(gdf)
        graph = Graph.from_geodataframe(gdf)
        has_geometry = True
    elif graph_json and not shp:
        graph = Graph.from_json(graph_json)
    else:
        graph = Graph.from_json(graph_json)
        gdf = gpd.read_file(shp)
        if reproject:
            gdf = reprojected(gdf)
        print('Appending geometries from shapefile to graph...')
        graph.geometry = gdf.geometry  # TODO: is this always valid?
        has_geometry = True

    my_updaters = {'population': updaters.Tally(pop_col, alias='population')}
    if election:
        election_up = Election('election', {
            'Democratic': election[0],
            'Republican': election[1]
        })
        my_updaters['election'] = election_up
    initial_state = GeographicPartition(graph,
                                        assignment=plan_col,
                                        updaters=my_updaters)

    normal_chain = RecomChain(graph=graph,
                              total_steps=n_steps,
                              initial_state=initial_state,
                              pop_col=pop_col,
                              pop_tol=pop_tol,
                              reversible=False,
                              seed=seed)
    reversible_chain = RecomChain(graph=graph,
                                  total_steps=n_steps,
                                  initial_state=initial_state,
                                  pop_col=pop_col,
                                  pop_tol=pop_tol,
                                  reversible=True,
                                  seed=seed)

    normal_plans = [plan for plan in tqdm(normal_chain)]
    reversible_plans = [plan for plan in tqdm(reversible_chain)]
    cut_edges_fig(output_dir, prefix, normal_plans, reversible_plans)
    longest_boundary_fig(output_dir, prefix, normal_plans, reversible_plans)
    if has_geometry:
        demo_plans(output_dir, '_'.join([prefix, 'recom']), normal_plans,
                   n_steps, n_steps // 25)
        demo_plans(output_dir, '_'.join([prefix, 'reversible_recom']),
                   reversible_plans, n_steps, n_steps // 25)
    if election:
        election_hists(output_dir, 'dem_vote_share', 'election', 'Democratic',
                       normal_plans, reversible_plans)
    acceptance_stats(output_dir, '_'.join([prefix, 'recom']), normal_plans)
    acceptance_stats(output_dir, '_'.join([prefix, 'reversible_recom']),
                     reversible_plans)
Пример #18
0
county_col = "COUNTYFP10"
pop_col = "TOT_POP"
uid = "GEOID10"

graph = Graph.from_geodataframe(df,ignore_errors=True)
print("made graph")
graph.add_data(df,list(df))
graph = nx.relabel_nodes(graph, df[uid])
counties = (set(list(df[county_col])))
countydict = dict(graph.nodes(data=county_col))

starting_partition = GeographicPartition(
    graph,
    assignment="GOV",
    updaters={
        "polsby_popper" : polsby_popper,
        "cut_edges": cut_edges,
        "population": Tally(pop_col, alias="population"),

    }
)

county_edge_count = {}
for i in counties:
    county_graph = graph.subgraph([n for n,v in graph.nodes(data = True) if v[county_col] == i])
    total_edges = len(county_graph.edges())
    county_edge_count[i] = total_edges

def county_splits_dict(partition):
    """
    From a partition, generates a dictionary of counter dictionaries.