Skip to content

Index

This module contains neighbourhood calculation methods.

Some embedding methods require a neighbourhood to be defined. This module contains neighbourhood calculation methods - both dedicated to a specific regionalization method and general ones.

Neighbourhood(include_center=False)

Bases: ABC, Generic[IndexType]

Neighbourhood interface.

This class abstracts away getting the neighbours of a region. It allows to get the neighbours at a certain distance or up to a certain distance. It is worth noting, that the distance here is not a metric distance, but a number of hops. This definition makes most sense semantically for grid systems such as H3 or S2 but should work for arbitrary neighbourhoods as well.

The subclasses only need to implement the get_neighbours method, but can also override the get_neighbours_up_to_distance and get_neighbours_at_distance methods for performance reasons. See the H3Neighbourhood class for an example. The class also provides a _handle_center method, which can be used to handle including/excluding the center region.

PARAMETER DESCRIPTION
include_center

Whether to include the region itself in the neighbours.

TYPE: bool DEFAULT: False

Source code in srai/neighbourhoods/_base.py
def __init__(self, include_center: bool = False) -> None:
    """
    Initializes the Neighbourhood.

    Args:
        include_center (bool): Whether to include the region itself in the neighbours.
        This is the default value used for all the methods of the class,
        unless overridden in the function call.
    """
    super().__init__()
    self.include_center = include_center

get_neighbours(index, include_center=None)

abstractmethod

Get the direct neighbours of a region using its index.

PARAMETER DESCRIPTION
index

Unique identifier of the region. Dependant on the implementation.

TYPE: IndexType

include_center

Whether to include the region itself in the neighbours.

TYPE: Optional[bool] DEFAULT: None

RETURNS DESCRIPTION
set[IndexType]

Set[IndexType]: Indexes of the neighbours.

Source code in srai/neighbourhoods/_base.py
@abstractmethod
def get_neighbours(
    self, index: IndexType, include_center: Optional[bool] = None
) -> set[IndexType]:
    """
    Get the direct neighbours of a region using its index.

    Args:
        index (IndexType): Unique identifier of the region.
            Dependant on the implementation.
        include_center (Optional[bool]): Whether to include the region itself in the neighbours.
        If None, the value set in __init__ is used. Defaults to None.

    Returns:
        Set[IndexType]: Indexes of the neighbours.
    """

get_neighbours_up_to_distance(
    index, distance, include_center=None
)

Get the neighbours of a region up to a certain distance.

PARAMETER DESCRIPTION
index

Unique identifier of the region. Dependant on the implementation.

TYPE: IndexType

distance

Maximum distance to the neighbours.

TYPE: int

include_center

Whether to include the region itself in the neighbours.

TYPE: Optional[bool] DEFAULT: None

RETURNS DESCRIPTION
set[IndexType]

Set[IndexType]: Indexes of the neighbours.

Source code in srai/neighbourhoods/_base.py
def get_neighbours_up_to_distance(
    self, index: IndexType, distance: int, include_center: Optional[bool] = None
) -> set[IndexType]:
    """
    Get the neighbours of a region up to a certain distance.

    Args:
        index (IndexType): Unique identifier of the region.
            Dependant on the implementation.
        distance (int): Maximum distance to the neighbours.
        include_center (Optional[bool]): Whether to include the region itself in the neighbours.
        If None, the value set in __init__ is used. Defaults to None.

    Returns:
        Set[IndexType]: Indexes of the neighbours.
    """
    neighbours_with_distances = self._get_neighbours_with_distances(index, distance)
    neighbours: set[IndexType] = (
        seq(neighbours_with_distances).map(operator.itemgetter(0)).to_set()
    )
    neighbours = self._handle_center(
        index,
        distance,
        neighbours,
        at_distance=False,
        include_center_override=include_center,
    )
    return neighbours

get_neighbours_at_distance(
    index, distance, include_center=None
)

Get the neighbours of a region at a certain distance.

PARAMETER DESCRIPTION
index

Unique identifier of the region. Dependant on the implementation.

TYPE: IndexType

distance

Distance to the neighbours.

TYPE: int

include_center

Whether to include the region itself in the neighbours.

TYPE: Optional[bool] DEFAULT: None

RETURNS DESCRIPTION
set[IndexType]

Set[IndexType]: Indexes of the neighbours.

Source code in srai/neighbourhoods/_base.py
def get_neighbours_at_distance(
    self, index: IndexType, distance: int, include_center: Optional[bool] = None
) -> set[IndexType]:
    """
    Get the neighbours of a region at a certain distance.

    Args:
        index (IndexType): Unique identifier of the region.
            Dependant on the implementation.
        distance (int): Distance to the neighbours.
        include_center (Optional[bool]): Whether to include the region itself in the neighbours.
        If None, the value set in __init__ is used. Defaults to None.

    Returns:
        Set[IndexType]: Indexes of the neighbours.
    """
    neighbours_up_to_distance = self._get_neighbours_with_distances(index, distance)
    neighbours_at_distance: set[IndexType] = (
        seq(neighbours_up_to_distance)
        .filter(lambda x: x[1] == distance)
        .map(operator.itemgetter(0))
        .to_set()
    )
    neighbours_at_distance = self._handle_center(
        index,
        distance,
        neighbours_at_distance,
        at_distance=True,
        include_center_override=include_center,
    )
    return neighbours_at_distance

AdjacencyNeighbourhood(regions_gdf, include_center=False)

Bases: Neighbourhood[Hashable]

Adjacency Neighbourhood.

This class allows to get the neighbours of any region based on common border. Additionally, a lookup table is implemented to accelerate repeated queries.

By default, a lookup table will be populated lazily based on queries. A dedicated function generate_neighbourhoods allows for precalculation of all the neighbourhoods at once.

PARAMETER DESCRIPTION
regions_gdf

regions for which a neighbourhood will be calculated.

TYPE: GeoDataFrame

include_center

Whether to include the region itself in the neighbours.

TYPE: bool DEFAULT: False

RAISES DESCRIPTION
ValueError

If regions_gdf doesn't have geometry column.

Source code in srai/neighbourhoods/adjacency_neighbourhood.py
def __init__(self, regions_gdf: gpd.GeoDataFrame, include_center: bool = False) -> None:
    """
    Init AdjacencyNeighbourhood.

    Args:
        regions_gdf (gpd.GeoDataFrame): regions for which a neighbourhood will be calculated.
        include_center (bool): Whether to include the region itself in the neighbours.
        This is the default value used for all the methods of the class,
        unless overridden in the function call.

    Raises:
        ValueError: If regions_gdf doesn't have geometry column.
    """
    super().__init__(include_center)
    if GEOMETRY_COLUMN not in regions_gdf.columns:
        raise ValueError("Regions must have a geometry column.")
    self.regions_gdf = regions_gdf
    self.lookup: dict[Hashable, set[Hashable]] = {}

get_neighbours_up_to_distance(
    index, distance, include_center=None
)

Get the neighbours of a region up to a certain distance.

PARAMETER DESCRIPTION
index

Unique identifier of the region. Dependant on the implementation.

TYPE: IndexType

distance

Maximum distance to the neighbours.

TYPE: int

include_center

Whether to include the region itself in the neighbours.

TYPE: Optional[bool] DEFAULT: None

RETURNS DESCRIPTION
set[IndexType]

Set[IndexType]: Indexes of the neighbours.

Source code in srai/neighbourhoods/_base.py
def get_neighbours_up_to_distance(
    self, index: IndexType, distance: int, include_center: Optional[bool] = None
) -> set[IndexType]:
    """
    Get the neighbours of a region up to a certain distance.

    Args:
        index (IndexType): Unique identifier of the region.
            Dependant on the implementation.
        distance (int): Maximum distance to the neighbours.
        include_center (Optional[bool]): Whether to include the region itself in the neighbours.
        If None, the value set in __init__ is used. Defaults to None.

    Returns:
        Set[IndexType]: Indexes of the neighbours.
    """
    neighbours_with_distances = self._get_neighbours_with_distances(index, distance)
    neighbours: set[IndexType] = (
        seq(neighbours_with_distances).map(operator.itemgetter(0)).to_set()
    )
    neighbours = self._handle_center(
        index,
        distance,
        neighbours,
        at_distance=False,
        include_center_override=include_center,
    )
    return neighbours

get_neighbours_at_distance(
    index, distance, include_center=None
)

Get the neighbours of a region at a certain distance.

PARAMETER DESCRIPTION
index

Unique identifier of the region. Dependant on the implementation.

TYPE: IndexType

distance

Distance to the neighbours.

TYPE: int

include_center

Whether to include the region itself in the neighbours.

TYPE: Optional[bool] DEFAULT: None

RETURNS DESCRIPTION
set[IndexType]

Set[IndexType]: Indexes of the neighbours.

Source code in srai/neighbourhoods/_base.py
def get_neighbours_at_distance(
    self, index: IndexType, distance: int, include_center: Optional[bool] = None
) -> set[IndexType]:
    """
    Get the neighbours of a region at a certain distance.

    Args:
        index (IndexType): Unique identifier of the region.
            Dependant on the implementation.
        distance (int): Distance to the neighbours.
        include_center (Optional[bool]): Whether to include the region itself in the neighbours.
        If None, the value set in __init__ is used. Defaults to None.

    Returns:
        Set[IndexType]: Indexes of the neighbours.
    """
    neighbours_up_to_distance = self._get_neighbours_with_distances(index, distance)
    neighbours_at_distance: set[IndexType] = (
        seq(neighbours_up_to_distance)
        .filter(lambda x: x[1] == distance)
        .map(operator.itemgetter(0))
        .to_set()
    )
    neighbours_at_distance = self._handle_center(
        index,
        distance,
        neighbours_at_distance,
        at_distance=True,
        include_center_override=include_center,
    )
    return neighbours_at_distance

generate_neighbourhoods()

Generate the lookup table for all regions.

Source code in srai/neighbourhoods/adjacency_neighbourhood.py
def generate_neighbourhoods(self) -> None:
    """Generate the lookup table for all regions."""
    for region_id in self.regions_gdf.index:
        if region_id not in self.lookup:
            self.lookup[region_id] = self._get_adjacent_neighbours(region_id)

get_neighbours(index, include_center=None)

Get the direct neighbours of any region using its index.

PARAMETER DESCRIPTION
index

Unique identifier of the region.

TYPE: Hashable

include_center

Whether to include the region itself in the neighbours.

TYPE: Optional[bool] DEFAULT: None

RETURNS DESCRIPTION
set[Hashable]

Set[Hashable]: Indexes of the neighbours.

Source code in srai/neighbourhoods/adjacency_neighbourhood.py
def get_neighbours(
    self, index: Hashable, include_center: Optional[bool] = None
) -> set[Hashable]:
    """
    Get the direct neighbours of any region using its index.

    Args:
        index (Hashable): Unique identifier of the region.
        include_center (Optional[bool]): Whether to include the region itself in the neighbours.
        If None, the value set in __init__ is used. Defaults to None.

    Returns:
        Set[Hashable]: Indexes of the neighbours.
    """
    if self._index_incorrect(index):
        return set()

    if index not in self.lookup:
        self.lookup[index] = self._get_adjacent_neighbours(index)

    neighbours = self.lookup[index]
    neighbours = self._handle_center(
        index, 1, neighbours, at_distance=False, include_center_override=include_center
    )
    return neighbours

H3Neighbourhood(regions_gdf=None, include_center=False)

Bases: Neighbourhood[str]

H3 Neighbourhood.

This class allows to get the neighbours of an H3 region.

If a regions GeoDataFrame is provided, only the neighbours that are in the regions GeoDataFrame will be returned by the methods of this instance. NOTICE: If a region is a part of the k-th ring of a region and is included in the GeoDataFrame, it will be returned by get_neighbours_at_distance method with distance k even when there is no path of length k between the two regions.

PARAMETER DESCRIPTION
regions_gdf

The regions that are being analyzed. The H3Neighbourhood will only look for neighbours among these regions. Defaults to None.

TYPE: Optional[GeoDataFrame] DEFAULT: None

include_center

Whether to include the region itself in the neighbours.

TYPE: bool DEFAULT: False

Source code in srai/neighbourhoods/h3_neighbourhood.py
def __init__(
    self, regions_gdf: Optional[gpd.GeoDataFrame] = None, include_center: bool = False
) -> None:
    """
    Initializes the H3Neighbourhood.

    If a regions GeoDataFrame is provided, only the neighbours
    that are in the regions GeoDataFrame will be returned by the methods of this instance.
    NOTICE: If a region is a part of the k-th ring of a region
        and is included in the GeoDataFrame, it will be returned
        by get_neighbours_at_distance method with distance k
        even when there is no path of length k between the two regions.

    Args:
        regions_gdf (Optional[gpd.GeoDataFrame], optional): The regions that are being analyzed.
            The H3Neighbourhood will only look for neighbours among these regions.
            Defaults to None.
        include_center (bool): Whether to include the region itself in the neighbours.
        This is the default value used for all the methods of the class,
        unless overridden in the function call.
    """
    super().__init__(include_center)
    self._available_indices: Optional[set[str]] = None
    if regions_gdf is not None:
        self._available_indices = set(regions_gdf.index)

get_neighbours(index, include_center=None)

Get the direct neighbours of an H3 region using its index.

PARAMETER DESCRIPTION
index

H3 index of the region.

TYPE: str

include_center

Whether to include the region itself in the neighbours.

TYPE: Optional[bool] DEFAULT: None

RETURNS DESCRIPTION
set[str]

Set[str]: Indexes of the neighbours.

Source code in srai/neighbourhoods/h3_neighbourhood.py
def get_neighbours(self, index: str, include_center: Optional[bool] = None) -> set[str]:
    """
    Get the direct neighbours of an H3 region using its index.

    Args:
        index (str): H3 index of the region.
        include_center (Optional[bool]): Whether to include the region itself in the neighbours.
        If None, the value set in __init__ is used. Defaults to None.

    Returns:
        Set[str]: Indexes of the neighbours.
    """
    return self.get_neighbours_up_to_distance(index, 1, include_center)

get_neighbours_up_to_distance(
    index, distance, include_center=None, unchecked=False
)

Get the neighbours of an H3 region up to a certain distance.

PARAMETER DESCRIPTION
index

H3 index of the region.

TYPE: str

distance

Distance to the neighbours.

TYPE: int

include_center

Whether to include the region itself in the neighbours. If None, the value set in init is used. Defaults to None.

TYPE: Optional[bool] DEFAULT: None

unchecked

Whether to check if the neighbours are in the available indices.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
set[str]

Set[str]: Indexes of the neighbours up to the given distance.

Source code in srai/neighbourhoods/h3_neighbourhood.py
def get_neighbours_up_to_distance(
    self,
    index: str,
    distance: int,
    include_center: Optional[bool] = None,
    unchecked: bool = False,
) -> set[str]:
    """
    Get the neighbours of an H3 region up to a certain distance.

    Args:
        index (str): H3 index of the region.
        distance (int): Distance to the neighbours.
        include_center (Optional[bool]): Whether to include the region itself in the neighbours.
            If None, the value set in __init__ is used. Defaults to None.
        unchecked (bool): Whether to check if the neighbours are in the available indices.

    Returns:
        Set[str]: Indexes of the neighbours up to the given distance.
    """
    if self._distance_incorrect(distance):
        return set()

    neighbours: set[str] = set(h3.grid_disk(index, distance))
    neighbours = self._handle_center(
        index, distance, neighbours, at_distance=False, include_center_override=include_center
    )
    if unchecked:
        return neighbours
    return self._select_available(neighbours)

get_neighbours_at_distance(
    index, distance, include_center=None
)

Get the neighbours of an H3 region at a certain distance.

PARAMETER DESCRIPTION
index

H3 index of the region.

TYPE: str

distance

Distance to the neighbours.

TYPE: int

include_center

Whether to include the region itself in the neighbours.

TYPE: Optional[bool] DEFAULT: None

RETURNS DESCRIPTION
set[str]

Set[str]: Indexes of the neighbours at the given distance.

Source code in srai/neighbourhoods/h3_neighbourhood.py
def get_neighbours_at_distance(
    self, index: str, distance: int, include_center: Optional[bool] = None
) -> set[str]:
    """
    Get the neighbours of an H3 region at a certain distance.

    Args:
        index (str): H3 index of the region.
        distance (int): Distance to the neighbours.
        include_center (Optional[bool]): Whether to include the region itself in the neighbours.
        If None, the value set in __init__ is used. Defaults to None.

    Returns:
        Set[str]: Indexes of the neighbours at the given distance.
    """
    if self._distance_incorrect(distance):
        return set()

    neighbours: set[str] = set(h3.grid_ring(index, distance))
    neighbours = self._handle_center(
        index, distance, neighbours, at_distance=True, include_center_override=include_center
    )
    return self._select_available(neighbours)