Skip to content

line_metric

Compute a set of line metrics for every row of the gdf.

Parameters:

Name Type Description Default
gdf GeoDataFrame

The input GeoDataFrame.

required
metrics Tuple[str, ...]

A Tuple/List of line metrics.

required
parallel bool

Flag whether to use parallel apply operations when computing the diversities.

True
num_processes int

The number of processes to use when parallel=True. If -1, this will use all available cores.

1
col_prefix str

Prefix for the new column names.

None
create_copy bool

Flag whether to create a copy of the input gdf or not.

True
Note

Allowed shape metrics are:

  • tortuosity
  • average_turning_angle
  • length
  • major_axis_len
  • minor_axis_len
  • major_axis_angle
  • minor_axis_angle

Raises:

Type Description
ValueError

If an illegal metric is given.

Returns:

Type Description
GeoDataFrame

gpd.GeoDataFrame: The input geodataframe with computed shape metric columns added.

Examples:

>>> from shapely.geometry import LineString
>>> from histolytics.spatial_geom.line_metrics import line_metric
>>> import geopandas as gpd
>>> lines = [
...     LineString([(i, i) for i in range(12)]),
...     LineString([(i, 0 if i % 2 == 0 else 1) for i in range(12)]),
...     LineString([(0, i) for i in range(12)]),
>>> ]
>>> gdf = gpd.GeoDataFrame(geometry=lines)
>>> gdf = line_metric(gdf, metrics=["tortuosity", "length"], parallel=True)
>>> print(gdf.head(3))
                                                geometry  tortuosity     length
    0  LINESTRING (0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6,...    1.000000  15.556349
    1  LINESTRING (0 0, 1 1, 2 0, 3 1, 4 0, 5 1, 6 0,...    1.408406  15.556349
    2  LINESTRING (0 0, 0 1, 0 2, 0 3, 0 4, 0 5, 0 6,...    1.000000  11.000000
Source code in src/histolytics/spatial_geom/line_metrics.py
def line_metric(
    gdf: gpd.GeoDataFrame,
    metrics: Tuple[str, ...],
    parallel: bool = True,
    num_processes: int = 1,
    col_prefix: str = None,
    create_copy: bool = True,
) -> gpd.GeoDataFrame:
    """Compute a set of line metrics for every row of the gdf.

    Parameters:
        gdf (gpd.GeoDataFrame):
            The input GeoDataFrame.
        metrics (Tuple[str, ...]):
            A Tuple/List of line metrics.
        parallel (bool):
            Flag whether to use parallel apply operations when computing the diversities.
        num_processes (int):
            The number of processes to use when parallel=True. If -1,
            this will use all available cores.
        col_prefix (str):
            Prefix for the new column names.
        create_copy (bool):
            Flag whether to create a copy of the input gdf or not.

    Note:
        Allowed shape metrics are:

        - `tortuosity`
        - `average_turning_angle`
        - `length`
        - `major_axis_len`
        - `minor_axis_len`
        - `major_axis_angle`
        - `minor_axis_angle`

    Raises:
        ValueError:
            If an illegal metric is given.

    Returns:
        gpd.GeoDataFrame:
            The input geodataframe with computed shape metric columns added.

    Examples:
        >>> from shapely.geometry import LineString
        >>> from histolytics.spatial_geom.line_metrics import line_metric
        >>> import geopandas as gpd
        >>> lines = [
        ...     LineString([(i, i) for i in range(12)]),
        ...     LineString([(i, 0 if i % 2 == 0 else 1) for i in range(12)]),
        ...     LineString([(0, i) for i in range(12)]),
        >>> ]
        >>> gdf = gpd.GeoDataFrame(geometry=lines)
        >>> gdf = line_metric(gdf, metrics=["tortuosity", "length"], parallel=True)
        >>> print(gdf.head(3))
                                                        geometry  tortuosity     length
            0  LINESTRING (0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6,...    1.000000  15.556349
            1  LINESTRING (0 0, 1 1, 2 0, 3 1, 4 0, 5 1, 6 0,...    1.408406  15.556349
            2  LINESTRING (0 0, 0 1, 0 2, 0 3, 0 4, 0 5, 0 6,...    1.000000  11.000000

    """
    if not isinstance(metrics, (list, tuple)):
        raise ValueError(f"`metrics` must be a list or tuple. Got: {type(metrics)}.")

    allowed = list(LINE_SHAPE_LOOKUP.keys())
    if not all(m in allowed for m in metrics):
        raise ValueError(
            f"Illegal metric in `metrics`. Got: {metrics}. Allowed metrics: {allowed}."
        )

    if create_copy:
        gdf = gdf.copy()

    if col_prefix is None:
        col_prefix = ""
    else:
        col_prefix += "_"

    met = list(metrics)
    if "length" in metrics:
        gdf[f"{col_prefix}length"] = gdf.length
        met.remove("length")

    met = list(metrics)
    for metric in met:
        gdf[metric] = gdf_apply(
            gdf,
            LINE_SHAPE_LOOKUP[metric],
            columns=["geometry"],
            parallel=parallel,
            num_processes=num_processes,
        )

    return gdf