0
# Partition Management
1
2
Create and manipulate district partitions representing assignments of geographic units to electoral districts. Partitions track updatable attributes and support efficient manipulation operations.
3
4
## Capabilities
5
6
### Basic Partition Creation
7
8
Create partitions with district assignments and updatable attributes that are automatically computed and cached.
9
10
```python { .api }
11
class Partition:
12
def __init__(
13
self,
14
graph: Graph,
15
assignment: Union[Dict[NodeId, DistrictId], str],
16
updaters: Dict[str, UpdaterFunction] = None
17
) -> None:
18
"""
19
Create a new partition of a graph into districts.
20
21
Parameters:
22
- graph (Graph): The underlying graph
23
- assignment (Union[Dict, str]): District assignments as dict or column name
24
- updaters (Dict[str, UpdaterFunction], optional): Functions to compute attributes
25
26
Returns:
27
None
28
"""
29
30
def __getitem__(self, key: str) -> Any:
31
"""
32
Access partition attributes computed by updaters.
33
34
Parameters:
35
- key (str): Name of the attribute
36
37
Returns:
38
Any: The computed attribute value
39
"""
40
41
def flip(self, flips: Dict[NodeId, DistrictId]) -> "Partition":
42
"""
43
Create a new partition with specified node assignments changed.
44
45
Parameters:
46
- flips (Dict[NodeId, DistrictId]): Node ID to new district ID mappings
47
48
Returns:
49
Partition: New partition with flipped assignments
50
"""
51
52
def crosses_parts(self, edge: Tuple[NodeId, NodeId]) -> bool:
53
"""
54
Check if an edge crosses district boundaries.
55
56
Parameters:
57
- edge (Tuple[NodeId, NodeId]): Edge as (node1, node2) tuple
58
59
Returns:
60
bool: True if edge crosses districts, False otherwise
61
"""
62
```
63
64
Usage example:
65
```python
66
from gerrychain import Partition, Graph
67
from gerrychain.updaters import Tally, cut_edges
68
69
# Create basic partition
70
graph = Graph.from_file("precincts.shp")
71
partition = Partition(
72
graph,
73
assignment="district", # Use 'district' column from shapefile
74
updaters={
75
"population": Tally("population"),
76
"cut_edges": cut_edges
77
}
78
)
79
80
# Access attributes
81
total_pop = sum(partition["population"].values())
82
num_cut_edges = len(partition["cut_edges"])
83
84
# Create new partition with flipped assignments
85
new_partition = partition.flip({node_id: new_district})
86
```
87
88
### Geographic Partition Creation
89
90
Create partitions with geographic data and spatial capabilities, extending basic partitions with coordinate reference system support and file I/O.
91
92
```python { .api }
93
class GeographicPartition(Partition):
94
@classmethod
95
def from_file(
96
cls,
97
filename: str,
98
district_column: str,
99
adjacency: str = "rook",
100
updaters: Dict[str, UpdaterFunction] = None,
101
**kwargs
102
) -> "GeographicPartition":
103
"""
104
Create a GeographicPartition from a shapefile or GeoJSON.
105
106
Parameters:
107
- filename (str): Path to geographic data file
108
- district_column (str): Column containing district assignments
109
- adjacency (str): Adjacency type - "rook" or "queen"
110
- updaters (Dict[str, UpdaterFunction], optional): Attribute updaters
111
- **kwargs: Additional arguments passed to Graph.from_file
112
113
Returns:
114
GeographicPartition: New geographic partition
115
"""
116
117
@classmethod
118
def from_districtr_file(
119
cls,
120
graph: Graph,
121
assignment_file: str,
122
updaters: Dict[str, UpdaterFunction] = None
123
) -> "GeographicPartition":
124
"""
125
Create a GeographicPartition from a Districtr assignment file.
126
127
Parameters:
128
- graph (Graph): The underlying graph
129
- assignment_file (str): Path to Districtr JSON assignment file
130
- updaters (Dict[str, UpdaterFunction], optional): Attribute updaters
131
132
Returns:
133
GeographicPartition: New geographic partition from Districtr data
134
"""
135
```
136
137
Usage example:
138
```python
139
from gerrychain import GeographicPartition
140
from gerrychain.updaters import Tally, cut_edges
141
142
# From shapefile
143
partition = GeographicPartition.from_file(
144
"precincts.shp",
145
district_column="district",
146
adjacency="queen",
147
updaters={
148
"population": Tally("population"),
149
"cut_edges": cut_edges
150
}
151
)
152
153
# From Districtr file
154
graph = Graph.from_file("precincts.shp")
155
partition = GeographicPartition.from_districtr_file(
156
graph,
157
"assignment.json",
158
updaters={"population": Tally("population")}
159
)
160
```
161
162
### Partition Assignment Operations
163
164
Manipulate and query district assignments efficiently.
165
166
```python { .api }
167
def get_assignment(
168
nodes: Iterable[NodeId],
169
assignment: Union[Dict[NodeId, DistrictId], str]
170
) -> Dict[NodeId, DistrictId]:
171
"""
172
Extract assignment mapping for specified nodes.
173
174
Parameters:
175
- nodes (Iterable[NodeId]): Nodes to get assignments for
176
- assignment (Union[Dict, str]): Assignment dict or column name
177
178
Returns:
179
Dict[NodeId, DistrictId]: Assignment mapping for specified nodes
180
"""
181
```
182
183
### Subgraph Views
184
185
Create views of partition subgraphs for efficient district-level analysis.
186
187
```python { .api }
188
class SubgraphView:
189
def __init__(self, partition: Partition, districts: List[DistrictId]) -> None:
190
"""
191
Create a view of partition subgraph for specified districts.
192
193
Parameters:
194
- partition (Partition): The partition
195
- districts (List[DistrictId]): Districts to include in view
196
197
Returns:
198
None
199
"""
200
```
201
202
### Advanced Usage Patterns
203
204
Common patterns for working with partitions in analysis workflows:
205
206
```python
207
# Multi-step partition modification
208
partition = GeographicPartition.from_file("precincts.shp", "district")
209
210
# Chain multiple flips
211
step1 = partition.flip({node1: district1})
212
step2 = step1.flip({node2: district2})
213
final = step2.flip({node3: district3})
214
215
# Batch operations for efficiency
216
flips = {node1: district1, node2: district2, node3: district3}
217
result = partition.flip(flips)
218
219
# Check boundary crossings
220
boundary_edges = [
221
edge for edge in graph.edges()
222
if partition.crosses_parts(edge)
223
]
224
225
# Access computed attributes
226
districts = list(partition.parts.keys())
227
district_populations = {
228
dist: partition["population"][dist]
229
for dist in districts
230
}
231
232
# Parent tracking for Markov chains
233
current_partition = initial_partition
234
for step in range(1000):
235
proposed = propose_flip(current_partition)
236
if is_valid(proposed) and accept(proposed):
237
current_partition = proposed
238
# proposed.parent points to current_partition
239
```
240
241
## Types
242
243
```python { .api }
244
Assignment = Dict[NodeId, DistrictId] # Node to district mapping
245
NodeId = Union[int, str] # Graph node identifier
246
DistrictId = int # District identifier
247
UpdaterFunction = Callable[[Partition], Any] # Updater function type
248
```