Skip to content

Commit

Permalink
plot_orientation: support directed graph bearings
Browse files Browse the repository at this point in the history
  • Loading branch information
dhimmel committed Mar 3, 2024
1 parent ca9744b commit ee3d63d
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 12 deletions.
31 changes: 22 additions & 9 deletions osmnx/bearing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

from typing import overload
from warnings import warn

import networkx as nx
import numpy as np
Expand Down Expand Up @@ -169,20 +170,22 @@ def orientation_entropy(


def _extract_edge_bearings(
Gu: nx.MultiGraph,
Gu: nx.MultiGraph | nx.MultiDiGraph,
min_length: float,
weight: str | None,
) -> npt.NDArray[np.float64]:
"""
Extract undirected graph's bidirectional edge bearings.
Extract graph's edge bearings.
For example, if an edge has a bearing of 90 degrees then we will record
A MultiGraph input receives bidirectional bearings.
For example, if an undirected edge has a bearing of 90 degrees then we will record
bearings of both 90 degrees and 270 degrees for this edge.
For MultiDiGraph input, record only one bearing per edge.
Parameters
----------
Gu
Undirected, unprojected graph with `bearing` attributes on each edge.
Unprojected graph with `bearing` attributes on each edge.
min_length
Ignore edges with `length` attributes less than `min_length`. Useful
to ignore the noise of many very short edges.
Expand All @@ -195,10 +198,10 @@ def _extract_edge_bearings(
Returns
-------
bearings
The bidirectional edge bearings of `Gu`.
The edge bearings of `Gu`.
"""
if nx.is_directed(Gu) or projection.is_projected(Gu.graph["crs"]): # pragma: no cover
msg = "Graph must be undirected and unprojected to analyze edge bearings."
msg = "Graph must be unprojected to analyze edge bearings."
raise ValueError(msg)
bearings = []
for u, v, data in Gu.edges(data=True):
Expand All @@ -211,15 +214,25 @@ def _extract_edge_bearings(
# don't weight bearings, just take one value per edge
bearings.append(data["bearing"])

# drop any nulls, calculate reverse bearings, concatenate and return
# drop any nulls
bearings_array = np.array(bearings)
bearings_array = bearings_array[~np.isnan(bearings_array)]
if nx.is_directed(Gu):
# https://github.com/gboeing/osmnx/issues/1137
msg = (
"Extracting directional bearings (one bearing per edge) due to MultiDiGraph input. "
"To extract bidirectional bearings (two bearings per edge, including the reverse bearing), "
"supply an undirected graph instead via `Gu.to_undirected()`."
)
warn(msg, category=UserWarning, stacklevel=2)
return bearings_array
# for undirected graphs, add reverse bearings and return
bearings_array_r = (bearings_array - 180) % 360
return np.concatenate([bearings_array, bearings_array_r])


def _bearings_distribution(
Gu: nx.MultiGraph,
Gu: nx.MultiGraph | nx.MultiDiGraph,
num_bins: int,
min_length: float,
weight: str | None,
Expand All @@ -236,7 +249,7 @@ def _bearings_distribution(
Parameters
----------
Gu
Undirected, unprojected graph with `bearing` attributes on each edge.
Unprojected graph with `bearing` attributes on each edge.
num_bins
Number of bins for the bearing histogram.
min_length
Expand Down
9 changes: 6 additions & 3 deletions osmnx/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ def plot_footprints( # noqa: PLR0913


def plot_orientation( # noqa: PLR0913
Gu: nx.MultiGraph,
Gu: nx.MultiGraph | nx.MultiDiGraph,
*,
num_bins: int = 36,
min_length: float = 0,
Expand All @@ -682,7 +682,10 @@ def plot_orientation( # noqa: PLR0913
xtick_font: dict[str, Any] | None = None,
) -> tuple[Figure, PolarAxes]:
"""
Plot a polar histogram of a spatial network's bidirectional edge bearings.
Plot a polar histogram of a spatial network's edge bearings.
A MultiGraph input receives bidirectional bearings, while a MultiDiGraph
input receives directional bearings (one bearing per edge).
Ignores self-loop edges as their bearings are undefined. See also the
`bearings` module.
Expand All @@ -694,7 +697,7 @@ def plot_orientation( # noqa: PLR0913
Parameters
----------
Gu
Undirected, unprojected graph with `bearing` attributes on each edge.
Unprojected graph with `bearing` attributes on each edge.
num_bins
Number of bins. For example, if `num_bins=36` is provided, then each
bin will represent 10 degrees around the compass.
Expand Down

0 comments on commit ee3d63d

Please sign in to comment.