def PA_partition(): # this is a networkx adjancency data json file with CD, area, population, and vote data graph = construct_graph("./testData/PA_graph_with_data.json") # Add frozen attributes to graph # data = gp.read_file("./testData/frozen.shp") # add_data_to_graph(data, graph, ['Frozen'], 'wes_id') assignment = dict( zip(graph.nodes(), [graph.node[x]['CD'] for x in graph.nodes()])) updaters = { **votes_updaters(['VoteA', 'VoteB']), 'population': Tally('POP100', alias='population'), 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'boundary_nodes': boundary_nodes, 'cut_edges': cut_edges, 'areas': Tally('ALAND10', alias='areas'), 'polsby_popper': polsby_popper, 'cut_edges_by_part': cut_edges_by_part } return Partition(graph, assignment, updaters)
def __init__(self, dimensions=None, with_diagonals=False, assignment=None, updaters=None, parent=None, flips=None): """ :dimensions: tuple (m,n) of the desired dimensions of the grid. :with_diagonals: (optional, defaults to False) whether to include diagonals as edges of the graph (i.e., whether to use 'queen' adjacency rather than 'rook' adjacency). :assignment: (optional) dict matching nodes to their districts. If not provided, partitions the grid into 4 quarters of roughly equal size. :updaters: (optional) dict matching names of attributes of the Partition to functions that compute their values. If not provided, the Grid configures the cut_edges updater for convenience. """ if dimensions: self.dimensions = dimensions graph = create_grid_graph(dimensions, with_diagonals) if not assignment: thresholds = tuple(math.floor(n / 2) for n in self.dimensions) assignment = { node: color_quadrants(node, thresholds) for node in graph.nodes } if not updaters: updaters = { 'cut_edges': cut_edges, 'population': Tally('population'), 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'interior_boundaries': interior_boundaries, 'boundary_nodes': boundary_nodes, 'areas': Tally('area', alias='areas'), 'polsby_popper': polsby_popper, 'cut_edges_by_part': cut_edges_by_part } super().__init__(graph, assignment, updaters) elif parent: self.dimensions = parent.dimensions super().__init__(parent=parent, flips=flips) else: raise Exception("Not a good way to create a Partition")
def example_partition(): df = gp.read_file(os.path.join(TEST_DATA_PATH, "mo_cleaned_vtds.shp")) with open(os.path.join(TEST_DATA_PATH, "MO_graph.json")) as f: graph_json = json.load(f) graph = networkx.readwrite.json_graph.adjacency_graph(graph_json) assignment = get_assignment_dict(df, "GEOID10", "CD") add_data_to_graph( df, graph, ['PR_DV08', 'PR_RV08', 'POP100', 'ALAND10', 'COUNTYFP10'], id_col='GEOID10') updaters = { **votes_updaters(['PR_DV08', 'PR_RV08'], election_name='08'), 'population': Tally('POP100', alias='population'), 'counties': county_splits('counties', 'COUNTYFP10'), 'cut_edges': cut_edges, 'cut_edges_by_part': cut_edges_by_part } return Partition(graph, assignment, updaters)
def test_tally_multiple_columns(): graph = three_by_three_grid() attach_random_data(graph, ['D', 'R']) updaters = {'total': Tally(['D', 'R'], alias='total')} assignment = {i: 1 if i in range(4) else 2 for i in range(9)} partition = Partition(graph, assignment, updaters) expected_total_in_district_one = sum( graph.nodes[i]['D'] + graph.nodes[i]['R'] for i in range(4)) assert partition['total'][1] == expected_total_in_district_one
def set_up_chain(plan, total_steps, adjacency_type='queen'): graph = Graph.load(f"./PA_{adjacency_type}.json").graph assignment = {node: graph.nodes[node][plan] for node in graph.nodes} updaters = { **votes_updaters(elections["2016_Presidential"], election_name="2016_Presidential"), **votes_updaters(elections["2016_Senate"], election_name="2016_Senate"), 'population': Tally('population', alias='population'), 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'interior_boundaries': interior_boundaries, 'boundary_nodes': boundary_nodes, 'cut_edges': cut_edges, 'areas': Tally('area', alias='areas'), 'polsby_popper': polsby_popper, 'cut_edges_by_part': cut_edges_by_part } partition = Partition(graph, assignment, updaters) population_constraint = within_percent_of_ideal_population(partition, 0.01) compactness_constraint = SelfConfiguringLowerBound(L_minus_1_polsby_popper, epsilon=0.1) is_valid = Validator(default_constraints + [population_constraint, compactness_constraint]) return partition, MarkovChain(propose_random_flip, is_valid, always_accept, partition, total_steps)
def example_partition(): df = gp.read_file("./testData/mo_cleaned_vtds.shp") with open("./testData/MO_graph.json") as f: graph_json = json.load(f) graph = networkx.readwrite.json_graph.adjacency_graph(graph_json) assignment = get_assignment_dict(df, "GEOID10", "CD") add_data_to_graph( df, graph, ['PR_DV08', 'PR_RV08', 'POP100', 'ALAND10', 'COUNTYFP10'], id_col='GEOID10') updaters = { **votes_updaters(['PR_DV08', 'PR_RV08'], election_name='08'), 'population': Tally('POP100', alias='population'), 'areas': Tally('ALAND10', alias='areas'), 'counties': county_splits('counties', 'COUNTYFP10'), 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'boundary_nodes': boundary_nodes, 'polsby_popper': polsby_popper, 'cut_edges': cut_edges, 'cut_edges_by_part': cut_edges_by_part } return Partition(graph, assignment, updaters)
def test_Partition_can_update_stats(): graph = networkx.complete_graph(3) assignment = {0: 1, 1: 1, 2: 2} graph.nodes[0]['stat'] = 1 graph.nodes[1]['stat'] = 2 graph.nodes[2]['stat'] = 3 updaters = {'total_stat': Tally('stat', alias='total_stat')} partition = Partition(graph, assignment, updaters) assert partition['total_stat'][2] == 3 flip = {1: 2} new_partition = partition.merge(flip) assert new_partition['total_stat'][2] == 5
def set_up_plan(plan): graph = Graph.load('./PA_queen.json').graph assignment = {node: graph.nodes[node][plan] for node in graph.nodes} updaters = { 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'interior_boundaries': interior_boundaries, 'boundary_nodes': boundary_nodes, 'cut_edges': cut_edges, 'areas': Tally('area', alias='areas'), 'polsby_popper': polsby_popper, 'cut_edges_by_part': cut_edges_by_part } return Partition(graph, assignment, updaters)
graph.node[n]["purple"] = 1 if 0 in n or 9 in n: graph.node[n]["boundary_node"] = True #was true graph.node[n]["boundary_perim"] = 1 else: graph.node[n]["boundary_node"] = False temp += 1 # Get assignment dictionary assignment = get_assignment_dict_from_graph(graph, district_col) # Necessary updaters go here updaters = { 'population': Tally('population'), 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'interior_boundaries': interior_boundaries, 'boundary_nodes': boundary_nodes, 'cut_edges': cut_edges, 'areas': Tally('areas'), 'polsby_popper': polsby_popper, 'cut_edges_by_part': cut_edges_by_part, #'County_Splits': county_splits('County_Splits',county_col) } # Add the vote updaters for multiple plans for i in range(num_elections): updaters = { **updaters,
# , id_col=unique_label) # Desired proposal method proposal_method = propose_random_flip # Desired acceptance method acceptance_method = always_accept # Number of steps to run steps = 1000 print("loaded data") # Necessary updaters go here updaters = { 'population': Tally(pop_col, alias='population'), 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'interior_boundaries': interior_boundaries, 'boundary_nodes': boundary_nodes, 'cut_edges': cut_edges, 'areas': Tally(area_col, alias='areas'), 'polsby_popper': polsby_popper, 'cut_edges_by_part': cut_edges_by_part } # Add the vote updaters for multiple plans for i in range(num_elections): updaters = { **updaters,
# if j >0: # graph.add_edge((i,j),(i+1,j-1)) # graph[(i,j)][(i+1,j-1)]["shared_perim"]=0 district_col="D_CD"#"CD"#"rowCD"#"Dperp_CD"# # Get assignment dictionary assignment = get_assignment_dict_from_graph(graph, district_col) # Necessary updaters go here updaters = {'population': Tally('population'), 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'interior_boundaries': interior_boundaries, 'boundary_nodes': boundary_nodes, 'cut_edges': cut_edges, 'areas': Tally('areas'), 'polsby_popper': polsby_popper, 'cut_edges_by_part': cut_edges_by_part, #'County_Splits': county_splits('County_Splits',county_col) } # Add the vote updaters for multiple plans for i in range(num_elections): updaters = {**updaters, **votes_updaters(election_columns[i], election_names[i])}
# Write graph to file so it never has to be built again! with open(newdir + state_name + '_graph_with_data.json', 'w') as outfile1: outfile1.write(json.dumps(json_graph.adjacency_data(graph))) # Geojson for plotting df_plot = gp.read_file(plot_path) df_plot["initial"] = df_plot[unique_label].map(assignment) df_plot.plot(column="initial", cmap='tab20') plt.axis('off') plt.savefig(newdir + district_col + "_initial.png") plt.close() print("loaded data") # Necessary updaters go here updaters = {'population': Tally(pop_col, alias='population'), 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'interior_boundaries': interior_boundaries, 'boundary_nodes': boundary_nodes, 'cut_edges': cut_edges, 'areas': Tally('areas'), 'polsby_popper': polsby_popper, 'cut_edges_by_part': cut_edges_by_part} # Add the vote updaters for multiple plans for i in range(num_elections): updaters = {**updaters, **votes_updaters(election_columns[i], election_names[i])} # This builds the partition object
['LG_DEM_1_1', 'LG_REP_1_1'],['AG_DEM_1_1','AG_REP_1_1'],['P_DEM_16_y','P_REP_16_y']] add_data_to_graph(df, graph, [cols for pair in election_columns for cols in pair],id_col=unique_label) add_data_to_graph(df, graph, [tree_col]) #df.plot(column=tree_col,cmap="tab20") #plt.show() # Get assignment dictionary assignment = tree_dict#get_assignment_dict_from_graph(graph, tree_col) election_columns = [["VABVAP","VAnBVAP"],["VABlack","VAnBPOP"],['G_DEM_17_y','G_REP_17_y'], ['LG_DEM_1_1', 'LG_REP_1_1'],['AG_DEM_1_1','AG_REP_1_1'],['P_DEM_16_y','P_REP_16_y']] # Necessary updaters go here updaters = {'population': Tally('population'), # 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'interior_boundaries': interior_boundaries, 'boundary_nodes': boundary_nodes, 'cut_edges': cut_edges, # 'areas': Tally('areas'), # 'polsby_popper': polsby_popper, 'cut_edges_by_part': cut_edges_by_part, # 'County_Splits': county_splits('County_Splits',county_col) } # Add the vote updaters for multiple plans for i in range(num_elections): updaters = {**updaters, **votes_updaters(election_columns[i], election_names[i])}
def main(): #graph = construct_graph_from_file("/Users/caranix/Desktop/Alaska_Chain/AK_data.shp", geoid_col="DISTRICT") with open('./alaska_graph.json') as f: data = json.load(f) graph = networkx.readwrite.json_graph.adjacency_graph(data) df = gp.read_file( "/Users/caranix/Desktop/Alaska_Chain/AK_data.shp" ) # assignment = dict(zip(graph.nodes(), [graph.node[x]['HOUSEDIST'] for x in graph.nodes()])) add_data_to_graph(df, graph, [ 'join_Distr', 'POPULATION', 'join_Dem', 'join_Rep', 'perc_Dem', 'perc_Rep', 'AREA' ], id_col='DISTRICT') data = json.dumps(networkx.readwrite.json_graph.adjacency_data(graph)) with open('./alaska_graph.json', 'w') as f: f.write(data) assignment = dict( zip(graph.nodes(), [graph.node[x]['join_Distr'] for x in graph.nodes()])) updaters = { 'population': Tally('POPULATION', alias='population'), 'cut_edges': cut_edges, 'cut_edges_by_part': cut_edges_by_part, **votes_updaters(['join_Dem', 'join_Rep'], election_name='12'), 'perimeters': perimeters, 'exterior_boundaries': exterior_boundaries, 'boundary_nodes': boundary_nodes, 'cut_edges': cut_edges, 'areas': Tally('AREA', alias='areas'), 'polsby_popper': polsby_popper } p = Partition(graph, assignment, updaters) print("Starting Chain") chain = BasicChain(p, 1000000) allAssignments = {0: chain.state.assignment} for step in chain: allAssignments[chain.counter + 1] = step.flips # print(mean_median(step, 'join_Dem%')) # with open("chain_outputnew.json", "w") as f: # f.write(json.dumps(allAssignments)) #efficiency_gap(p) # mean_median(p, 'join_Dem%') scores = { 'Mean-Median': functools.partial(mean_median, proportion_column_name='join_Dem%'), 'Mean-Thirdian': functools.partial(mean_thirdian, proportion_column_name='join_Dem%'), 'Efficiency Gap': functools.partial(efficiency_gap, col1='join_Dem', col2='join_Rep'), 'L1 Reciprocal Polsby-Popper': L1_reciprocal_polsby_popper } initial_scores = {key: score(p) for key, score in scores.items()} table = pipe_to_table(chain, scores) fig, axes = plt.subplots(2, 2) quadrants = { 'Mean-Median': (0, 0), 'Mean-Thirdian': (0, 1), 'Efficiency Gap': (1, 0), 'L1 Reciprocal Polsby-Popper': (1, 1) } for key in scores: quadrant = quadrants[key] axes[quadrant].hist(table[key], bins=50) axes[quadrant].set_title(key) axes[quadrant].axvline(x=initial_scores[key], color='r') plt.show() '''