Skip to content

Geo neighbors

Find neighboring geographical units within a specified radius.

Using libpysal DistanceBand (fast, requires projected coordinates for accuracy).

build_neighbour_network(neighbours)

Build a NetworkX graph from a neighbour dictionary.

Parameters:

Name Type Description Default
neighbours dict[str, list[str]]

Mapping of unit ID to list of neighbour unit IDs.

required

Returns:

Type Description
Graph

nx.Graph: Undirected graph with units as nodes and neighbour relationships as edges.

Example

neighbours = {"A": ["B", "C"], "B": ["A"], "C": ["A"]} G = build_neighbour_network(neighbours) print(G.number_of_nodes(), G.number_of_edges()) 3 2

Source code in may/social_networks/builder_functions/geo/geo_neighbors.py
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
def build_neighbour_network(
        neighbours: dict[str, list[str]]
        ) -> "nx.Graph":
    """
    Build a NetworkX graph from a neighbour dictionary.

    Args:
        neighbours (dict[str, list[str]]): Mapping of unit ID to list of neighbour unit IDs.

    Returns:
        nx.Graph: Undirected graph with units as nodes and neighbour relationships as edges.

    Example:
        >>> neighbours = {"A": ["B", "C"], "B": ["A"], "C": ["A"]}
        >>> G = build_neighbour_network(neighbours)
        >>> print(G.number_of_nodes(), G.number_of_edges())
        3 2
    """
    import networkx as nx

    # Build graph
    G = nx.Graph()

    # Add all nodes
    for unit_name in neighbours.keys():
        G.add_node(unit_name)

    # Add edges (undirected, so only add once)
    for unit_name, unit_neighbours in neighbours.items():
        for neighbour_name in unit_neighbours:
            if not G.has_edge(unit_name, neighbour_name):
                G.add_edge(unit_name, neighbour_name)

    logger.info(f"Built network: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges")

    return G

find_neighbours(*args, method='libpysal', **kwargs)

Find neighbouring geographical units within a specified radius.

Parameters:

Name Type Description Default
*args

Arguments passed to the underlying neighbour finder method.

()
method str

Method for finding neighbours. Options: 'libpysal' (fast, uses Euclidean distance), 'balltree' (accurate, uses haversine).

'libpysal'
**kwargs

Keyword arguments passed to the underlying method, typically: - geo_units (list[GeographicalUnit]): Units with coordinates. - radius_km (float): Search radius in kilometers.

{}

Returns:

Type Description
dict[id, list[id]]

dict[str, list[str]]: Mapping of unit ID to list of neighbour unit IDs.

Example

from may.geography import Geography geo = Geography(data_dir="data/geography") geo.load_from_csv() units = list(geo.get_units_by_level("SGU").values()) neighbours = find_neighbours(units, radius_km=10.0, method='libpysal')

Source code in may/social_networks/builder_functions/geo/geo_neighbors.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
def find_neighbours(*args, method='libpysal', **kwargs) -> dict[id, list[id]]:
    """
    Find neighbouring geographical units within a specified radius.

    Args:
        *args: Arguments passed to the underlying neighbour finder method.
        method (str): Method for finding neighbours. Options: 'libpysal' (fast,
            uses Euclidean distance), 'balltree' (accurate, uses haversine).
        **kwargs: Keyword arguments passed to the underlying method, typically:
            - geo_units (list[GeographicalUnit]): Units with coordinates.
            - radius_km (float): Search radius in kilometers.

    Returns:
        dict[str, list[str]]: Mapping of unit ID to list of neighbour unit IDs.

    Example:
        >>> from may.geography import Geography
        >>> geo = Geography(data_dir="data/geography")
        >>> geo.load_from_csv()
        >>> units = list(geo.get_units_by_level("SGU").values())
        >>> neighbours = find_neighbours(units, radius_km=10.0, method='libpysal')
    """
    find_neighbours_method = neighbour_finders[method]
    if find_neighbours_method is None:
        raise ValueError(f"Unknown method: {method}")
    return find_neighbours_method(*args, **kwargs)        

register_neighbour_finder(name)

Decorator to register a neighbour finding method in the neighbour_finders registry.

Parameters:

Name Type Description Default
name str

Name to register the neighbour finder under.

required

Returns:

Name Type Description
Callable

Decorator function that registers the wrapped function.

Example

@register_neighbour_finder("my_method") ... def find_neighbours_my_method(geo_units, radius_km): ... return {} neighbours = neighbour_finders"my_method"

Source code in may/social_networks/builder_functions/geo/geo_neighbors.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
def register_neighbour_finder(name: str):
    """
    Decorator to register a neighbour finding method in the neighbour_finders registry.

    Args:
        name (str): Name to register the neighbour finder under.

    Returns:
        Callable: Decorator function that registers the wrapped function.

    Example:
        >>> @register_neighbour_finder("my_method")
        ... def find_neighbours_my_method(geo_units, radius_km):
        ...     return {}
        >>> neighbours = neighbour_finders["my_method"](units, 10.0)
    """
    def decorator(func: GraphCreator):
        @wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            return func(*args, **kwargs)
        neighbour_finders[name] = wrapper
        return wrapper
    return decorator