Skip to content

fit_graph

cellseg_gsontools.graphs.fit_graph(gdf, type, id_col=None, thresh=None, silence_warnings=True, **kwargs)

Fit a libpysal spatial weights graph to a gdf.

Optionally, a distance threshold can be set for edges that are too long.

This is a wrapper to fit libpysal graph with additional distance threshing.

Note

Allowed graph fitting methods:

  • delaunay
  • knn
  • distband
  • relative_nhood

Parameters:

Name Type Description Default
gdf GeoDataFrame

The input geodataframe.

required
type str

The type of the libpysal graph. Allowed: "delaunay", "knn", "distband", "relative_nhood"

required
id_col str

The unique id column in the gdf. If None, this uses set_uid to set it.

None
thresh float

A distance threshold for too long edges.

None
silence_warnings bool

Flag to silence the warnings.

True
**kwargs Dict[str, Any]

Arbitrary keyword arguments for the Graph init functions.

{}

Returns:

Type Description
W

libpysal.weights.W or None: A libpysal spatial weights object, containing the neighbor graph data. Returns None if the input gdf is empty.

Examples:

Fit a DistanceBand to a gdf with a dist threshold of 120.0.

>>> from cellseg_gsontools.graphs import fit_graph
>>> w = fit_graph(gdf, type="distband", thresh=120)

Fit a delaunay graph to a gdf without a dist threshold.

>>> from cellseg_gsontools.graphs import fit_graph
>>> w = fit_graph(gdf, type="delaunay", thresh=None)
Source code in cellseg_gsontools/graphs.py
def fit_graph(
    gdf: gpd.GeoDataFrame,
    type: str,
    id_col: Optional[str] = None,
    thresh: Optional[float] = None,
    silence_warnings: bool = True,
    **kwargs,
) -> W:
    """Fit a `libpysal` spatial weights graph to a gdf.

    Optionally, a distance threshold can be set for edges that are too long.

    This is a wrapper to fit `libpysal` graph with additional distance threshing.

    Note:
        Allowed graph fitting methods:

        - `delaunay`
        - `knn`
        - `distband`
        - `relative_nhood`

    Parameters:
        gdf (gpd.GeoDataFrame):
            The input geodataframe.
        type (str):
            The type of the libpysal graph. Allowed: "delaunay", "knn", "distband",
            "relative_nhood"
        id_col (str):
            The unique id column in the gdf. If None, this uses `set_uid` to set it.
        thresh (float):
            A distance threshold for too long edges.
        silence_warnings (bool):
            Flag to silence the warnings.
        **kwargs (Dict[str, Any]):
            Arbitrary keyword arguments for the Graph init functions.

    Returns:
        libpysal.weights.W or None:
            A libpysal spatial weights object, containing the neighbor graph data.
            Returns None if the input gdf is empty.

    Examples:
        Fit a DistanceBand to a gdf with a dist threshold of 120.0.
        >>> from cellseg_gsontools.graphs import fit_graph
        >>> w = fit_graph(gdf, type="distband", thresh=120)

        Fit a delaunay graph to a gdf without a dist threshold.
        >>> from cellseg_gsontools.graphs import fit_graph
        >>> w = fit_graph(gdf, type="delaunay", thresh=None)
    """
    allowed = (
        "delaunay",
        "knn",
        "distband",
        "relative_nhood",
    )
    if type not in allowed:
        raise ValueError(f"Illegal graph type given. Got: {type}. Allowed: {allowed}.")

    if gdf is None or gdf.empty:
        return

    # warn if id_col is not provided
    if not silence_warnings:
        _graph_warn(type, id_col)

    # can't fit delaunay or relative nhood graphs with less than 4 points
    if type in ("delaunay", "relative_nhood"):
        if len(gdf) < 4:
            return
    if type == "delaunay":
        # NOTE: neighbor keys start from 0
        w = Delaunay.from_dataframe(
            gdf.centroid,
            silence_warnings=True,
            use_index=True,
            ids=gdf[id_col],
            **kwargs,
        )
    elif type == "relative_nhood":
        # NOTE: neighbor indices start from 0
        w = Relative_Neighborhood.from_dataframe(
            gdf.centroid, silence_warnings=True, **kwargs
        )
    elif type == "knn":
        if "ids" in list(kwargs.keys()):  # drop ids kwarg since it fails
            kwargs.pop("ids")

        # NOTE: neighbor indices equal gdf[`ìd_col`]
        w = KNN.from_dataframe(gdf, silence_warnings=True, ids=id_col, **kwargs)
    elif type == "distband":
        if thresh is None:
            raise ValueError("DistBand requires `thresh` param. Not provided.")

        if "ids" in list(kwargs.keys()):  # drop ids kwarg since it fails
            kwargs.pop("ids")

        # NOTE: neighbor indices equal gdf[`ìd_col`]
        w = DistanceBand.from_dataframe(
            gdf,
            threshold=thresh,
            alpha=-1.0,
            ids=id_col,
            silence_warnings=True,
            **kwargs,
        )

    # convert graph indices to global ids
    if type in ("delaunay", "relative_nhood"):
        w = _graph_to_index(w, gdf)
        if id_col is not None:
            w = _graph_to_global_ids(w, gdf, id_col)

    # # Threshold edges based on distance to center node.
    if thresh is not None and type != "distband":
        w = dist_thresh_weights_sequential(gdf, w, thresh, id_col=id_col)

    return w