Use Markov chain Monte Carlo to analyze districting plans and gerrymanders
—
Create and manipulate geographic graphs representing electoral districts, precincts, or other geographic units. GerryChain extends NetworkX graphs with geographic capabilities and adjacency operations.
Create graphs from shapefiles, GeoDataFrames, or existing NetworkX graphs with geographic data and adjacency relationships.
class Graph:
@classmethod
def from_file(
cls,
filename: str,
adjacency: str = "rook"
) -> "Graph":
"""
Create a Graph from a shapefile or GeoJSON file.
Parameters:
- filename (str): Path to shapefile (.shp) or GeoJSON file
- adjacency (str): Adjacency type - "rook" or "queen"
Returns:
Graph: New graph with geographic data and adjacency edges
"""
@classmethod
def from_geodataframe(
cls,
dataframe,
adjacency: str = "rook"
) -> "Graph":
"""
Create a Graph from a GeoPandas GeoDataDF.
Parameters:
- dataframe (GeoDataFrame): GeoPandas dataframe with geometry
- adjacency (str): Adjacency type - "rook" or "queen"
Returns:
Graph: New graph with geographic data and adjacency edges
"""
@classmethod
def from_networkx(cls, graph) -> "Graph":
"""
Create a Graph from an existing NetworkX graph.
Parameters:
- graph: NetworkX graph object
Returns:
Graph: New GerryChain Graph wrapping the NetworkX graph
"""
@classmethod
def from_json(cls, json_file: str) -> "Graph":
"""
Load a Graph from a JSON file.
Parameters:
- json_file (str): Path to JSON file
Returns:
Graph: Loaded graph
"""Usage example:
from gerrychain import Graph
# From shapefile
graph = Graph.from_file("precincts.shp", adjacency="queen")
# From GeoDataFrame
import geopandas as gpd
gdf = gpd.read_file("districts.geojson")
graph = Graph.from_geodataframe(gdf, adjacency="rook")Join additional data to graph nodes and create lookup mappings for efficient data access.
def join(self, other_dataframe, columns: List[str] = None) -> None:
"""
Join additional data to graph nodes.
Parameters:
- other_dataframe (DataFrame): Data to join to graph nodes
- columns (List[str], optional): Specific columns to join
Returns:
None: Modifies graph in place
"""
def lookup(self, key: str, target_column: str) -> Dict:
"""
Create a lookup mapping from key column to target column.
Parameters:
- key (str): Column name to use as lookup key
- target_column (str): Column name for lookup values
Returns:
Dict: Mapping from key values to target values
"""
def to_json(
self,
json_file: str,
*,
include_geometries_as_geojson: bool = False
) -> None:
"""
Save graph to JSON file.
Parameters:
- json_file (str): Path to output JSON file
- include_geometries_as_geojson (bool): Whether to include geometries as GeoJSON
Returns:
None: Saves graph to file
"""
def issue_warnings(self) -> None:
"""
Check graph for common issues and warn about problems.
Returns:
None: Prints warnings to console
"""Usage example:
import pandas as pd
# Join election data
election_data = pd.read_csv("election_results.csv")
graph.join(election_data, columns=["SEN18D", "SEN18R"])
# Create lookup for population by district
pop_lookup = graph.lookup("GEOID", "population")Access graph structure, node data, and adjacency relationships.
def neighbors(self, node_id: NodeId) -> List[NodeId]:
"""
Get neighbors of a specific node.
Parameters:
- node_id (NodeId): ID of the node
Returns:
List[NodeId]: List of neighboring node IDs
"""Handle coordinate reference systems and geometric transformations for spatial analysis.
def reprojected(geometry, crs_from: str, crs_to: str):
"""
Reproject geometric data between coordinate reference systems.
Parameters:
- geometry: Geometric data to reproject
- crs_from (str): Source CRS (e.g., "EPSG:4326")
- crs_to (str): Target CRS (e.g., "EPSG:3857")
Returns:
Reprojected geometry
"""
class GeometryError(Exception):
"""Raised when geometric operations fail."""Add and modify adjacency relationships between geographic units.
def add_edges_from_file(graph: Graph, filename: str) -> None:
"""
Add adjacency edges from an external file.
Parameters:
- graph (Graph): Graph to modify
- filename (str): Path to adjacency file
Returns:
None: Modifies graph in place
"""
def neighbors_of_component(graph: Graph, component: Set[NodeId]) -> Set[NodeId]:
"""
Find all neighbors of a connected component.
Parameters:
- graph (Graph): The graph
- component (Set[NodeId]): Set of nodes forming a component
Returns:
Set[NodeId]: Set of neighboring nodes outside the component
"""
def neighbors_of_node(graph: Graph, node_id: NodeId) -> Set[NodeId]:
"""
Find neighbors of a single node.
Parameters:
- graph (Graph): The graph
- node_id (NodeId): ID of the node
Returns:
Set[NodeId]: Set of neighboring node IDs
"""NodeId = Union[int, str] # Graph node identifier
AdjacencyType = Literal["rook", "queen"] # Spatial adjacency typesInstall with Tessl CLI
npx tessl i tessl/pypi-gerrychain