layers

Compute land-use accessibility, mixed-use diversity, and statistical aggregations over the street network. Data points (land uses, numerical attributes) are assigned to the nearest street edges and then summarised within walking-distance catchments around each node, measured along the actual street network rather than as straight-line distances. Because these summaries are computed at the same node locations used for centrality, you can directly compare how well-connected a location is with how accessible different amenities are from that location. An optional decay_fn parameter controls how distance affects the weighting; see the cityseer.decay module for preset helpers. decay_fn also accepts a {label: expression} dict to compute several decay variants in a single network traversal, with each label appended to that variant’s output column names.

For practical worked examples, see the Cityseer Examples site, including the OSM Accessibility, Mixed Uses, and Statistical Aggregations recipes.

build_data_map

build_data_map
(
data_gdf : geopandas.geodataframe.GeoDataFrame
network_structure : NetworkStructure
max_netw_assign_dist : float = 100.0
data_id_col : str | None = None
barriers_gdf : geopandas.geodataframe.GeoDataFrame | None = None
n_nearest_candidates : int = 50
)->[ DataMap ]

Assign a GeoDataFrame to a rustalgos.graph.NetworkStructure. A NetworkStructure provides the backbone for the calculation of land-use and statistical aggregations over the network. Points will be assigned to the closest street edge. Polygons will be assigned to the closest n_nearest_candidates adjacent street edges.

Parameters

data_gdf
GeoDataFrame

A GeoDataFrame representing data points. The coordinates of data points should correspond as precisely as possible to the location of the feature in space; or, in the case of buildings, should ideally correspond to the location of the building entrance.

network_structure
None

max_netw_assign_dist
float

The maximum distance to consider when assigning respective data points to the nearest adjacent network nodes.

data_id_col
str

An optional column name for data point keys. This is used for deduplicating points representing a shared source of information. For example, where a single greenspace is represented by many entrances as datapoints, only the nearest entrance (from a respective location) will be considered (during aggregations) when the points share a datapoint identifier.

barriers_gdf
GeoDataFrame

A GeoDataFrame representing barriers. These barriers will be considered during the assignment of data points to the network.

n_nearest_candidates
int

The number of nearest street edge candidates to consider when assigning data points to the network. This is used to determine the best assignments based on proximity. Edges are sorted by distance and the closest n_nearest_candidates are considered.

Returns

data_map
rustalgos.data.DataMap

compute_accessibilities

compute_accessibilities
(
data_gdf : geopandas.geodataframe.GeoDataFrame
landuse_column_label : str
accessibility_keys : list[str]
nodes_gdf : geopandas.geodataframe.GeoDataFrame
network_structure : NetworkStructure
max_netw_assign_dist : float = 100.0
distances : list[int] | None = None
minutes : list[float] | None = None
data_id_col : str | None = None
barriers_gdf : geopandas.geodataframe.GeoDataFrame | None = None
angular : bool = False
n_nearest_candidates : int = 50
speed_m_s : float = 1.33333
decay_fn : str | dict[str, str] | None = None
)->[ GeoDataFrame GeoDataFrame ]

Compute land-use accessibilities for the specified land-use classification keys over the street network. The landuses are aggregated and computed over the street network relative to the network nodes, with the implication that the measures are generated from the same locations as those used for centrality computations.

Parameters

data_gdf
GeoDataFrame

A GeoDataFrame representing data points. The coordinates of data points should correspond as precisely as possible to the location of the feature in space; or, in the case of buildings, should ideally correspond to the location of the building entrance.

landuse_column_label
str

The column label from which to take landuse categories, e.g. a column labelled “landuse_categories” might contain “shop”, “pub”, “school”, etc.

accessibility_keys
tuple[str]

Land-use keys for which to compute accessibilities. The keys should be selected from the same land-use schema used for the landuse_labels parameter, e.g. “pub”.

nodes_gdf
None

A GeoDataFrame representing nodes. Best generated with the io.network_structure_from_nx function. The outputs of calculations will be written to this GeoDataFrame, which is then returned from the function.

network_structure
None

max_netw_assign_dist
float

The maximum distance to consider when assigning respective data points to the nearest adjacent network nodes.

distances
list[int]

Distance thresholds in metres for the network traversal. Metrics are computed for each threshold independently. If not provided, the minutes parameter must be provided instead.

minutes
list[float]

Walking time thresholds in minutes. Converted to distance thresholds using speed_m_s. If not provided, the distances parameter must be provided instead.

data_id_col
str

An optional column name for data point keys. This is used for deduplicating points representing a shared source of information. For example, where a single greenspace is represented by many entrances as datapoints, only the nearest entrance (from a respective location) will be considered (during aggregations) when the points share a datapoint identifier.

barriers_gdf
GeoDataFrame

A GeoDataFrame representing barriers. These barriers will be considered during the assignment of data points to the network.

angular
bool

Whether to use a simplest-path heuristic in-lieu of a shortest-path heuristic when calculating aggregations and distances.

n_nearest_candidates
int

The number of nearest candidates to consider when assigning respective data points to the nearest adjacent streets.

speed_m_s
float

Walking speed in metres per second used to convert minutes to distance thresholds.

decay_fn
str | dict[str, str]

An optional decay function expression using the variable p, where p is the normalised distance from 0 (source) to 1 (cutoff threshold). Controls how distance affects the accessibility count weighting. When omitted (None), the legacy default computes both an unweighted (_nw) and a decay-weighted (_wt) column; pass a single expression such as "1" (flat) to compute one unsuffixed column. For distance-weighted metrics, provide an expression such as "exp(-4 * p)" for exponential decay, or use the cityseer.decay module helpers to generate expressions from absolute distance units; see cityseer.decay for details and examples. Pass a dict of {label: expression} to compute several decays in a single network traversal; each label is appended to that variant’s output column names (a plain string or None adds no suffix).

Returns

nodes_gdf
GeoDataFrame

The input node_gdf parameter is returned with additional columns populated with the calculated metrics. Two columns will be returned for each input landuse class and distance combination; a count of reachable locations, and the smallest distance to the nearest location.

data_gdf
GeoDataFrame

The input data_gdf is returned with two additional columns: nearest_assigned and next_nearest_assign.

Notes

from cityseer.metrics import networks, layers
from cityseer.tools import mock, graphs, io

# prepare a mock graph
G = mock.mock_graph()
G = graphs.nx_simple_geoms(G)
nodes_gdf, edges_gdf, network_structure = io.network_structure_from_nx(G)
print(nodes_gdf.head())
landuses_gdf = mock.mock_landuse_categorical_data(G)
print(landuses_gdf.head())
nodes_gdf, landuses_gdf = layers.compute_accessibilities(
    data_gdf=landuses_gdf,
    landuse_column_label="categorical_landuses",
    accessibility_keys=["a", "c"],
    nodes_gdf=nodes_gdf,
    network_structure=network_structure,
    distances=[200, 400, 800],
)
print(nodes_gdf.columns)
# the default emits an unweighted (_nw) and a weighted (_wt) column;
# pass a single decay_fn (e.g. "1") to compute just one and save time
print(nodes_gdf["cc_c_400_nw"])
# nearest distance to landuse (decay-independent: one column)
print(nodes_gdf["cc_c_nearest_max_800"])

For worked examples with real-world data, see the OSM Accessibility recipe.

compute_mixed_uses

compute_mixed_uses
(
data_gdf : geopandas.geodataframe.GeoDataFrame
landuse_column_label : str
nodes_gdf : geopandas.geodataframe.GeoDataFrame
network_structure : NetworkStructure
max_netw_assign_dist : float = 100.0
compute_hill : bool | None = True
compute_shannon : bool | None = False
compute_gini : bool | None = False
distances : list[int] | None = None
minutes : list[float] | None = None
data_id_col : str | None = None
barriers_gdf : geopandas.geodataframe.GeoDataFrame | None = None
angular : bool = False
n_nearest_candidates : int = 50
speed_m_s : float = 1.33333
decay_fn : str | dict[str, str] | None = None
)->[ GeoDataFrame GeoDataFrame ]

Compute landuse metrics. This function wraps the underlying rust optimised functions for aggregating and computing various mixed-use. These are computed simultaneously for any required combinations of measures (and distances). By default, hill measures will be computed, but the available flags e.g. compute_hill or compute_shannon can be used to configure which classes of measures should run.

See the accompanying paper on arXiv for additional information about methods for computing mixed-use measures at the pedestrian scale.

The data is aggregated and computed over the street network, with the implication that mixed-use and land-use accessibility aggregations are generated from the same locations as for centrality computations, which can therefore be correlated or otherwise compared. The outputs of the calculations are written to the corresponding node indices in the same node_gdf GeoDataFrame used for centrality methods, and which will display the calculated metrics under correspondingly labelled columns.

Parameters

data_gdf
GeoDataFrame

A GeoDataFrame representing data points. The coordinates of data points should correspond as precisely as possible to the location of the feature in space; or, in the case of buildings, should ideally correspond to the location of the building entrance.

landuse_column_label
str

The column label from which to take landuse categories, e.g. a column labelled “landuse_categories” might contain “shop”, “pub”, “school”, etc., landuse categories.

nodes_gdf
None

A GeoDataFrame representing nodes. Best generated with the io.network_structure_from_nx function. The outputs of calculations will be written to this GeoDataFrame, which is then returned from the function.

network_structure
None

max_netw_assign_dist
float

The maximum distance to consider when assigning respective data points to the nearest adjacent network nodes.

compute_hill
bool

Compute Hill diversity. This is the recommended form of diversity index. Computed for q of 0, 1, and 2.

compute_shannon
bool

Compute shannon entropy. Hill diversity of q=1 is generally preferable.

compute_gini
bool

Compute the gini form of diversity index. Hill diversity of q=2 is generally preferable.

distances
list[int]

Distance thresholds in metres for the network traversal. Metrics are computed for each threshold independently. If not provided, the minutes parameter must be provided instead.

minutes
list[float]

Walking time thresholds in minutes. Converted to distance thresholds using speed_m_s. If not provided, the distances parameter must be provided instead.

data_id_col
str

An optional column name for data point keys. This is used for deduplicating points representing a shared source of information. For example, where a single greenspace is represented by many entrances as datapoints, only the nearest entrance (from a respective location) will be considered (during aggregations) when the points share a datapoint identifier.

barriers_gdf
GeoDataFrame

A GeoDataFrame representing barriers. These barriers will be considered during the assignment of data points to the network.

angular
bool

Whether to use a simplest-path heuristic in-lieu of a shortest-path heuristic when calculating aggregations and distances.

n_nearest_candidates
int

The number of nearest candidates to consider when assigning respective data points to the nearest adjacent streets.

speed_m_s
float

Walking speed in metres per second used to convert minutes to distance thresholds.

decay_fn
str | dict[str, str]

An optional decay function expression using the variable p, where p is the normalised distance from 0 (source) to 1 (cutoff threshold). Controls how distance affects the Hill diversity weighting. When omitted (None), the legacy default computes both an unweighted (_nw) and a decay-weighted (_wt) variant; pass a single expression such as "1" (flat) to compute one unsuffixed variant. For distance-weighted metrics, provide an expression such as "exp(-4 * p)" for exponential decay, or use the cityseer.decay module helpers to generate expressions from absolute distance units; see cityseer.decay for details and examples. Pass a dict of {label: expression} to compute several decays in a single network traversal; each label is appended to that variant’s output column names (a plain string or None adds no suffix).

Returns

nodes_gdf
GeoDataFrame

The input node_gdf parameter is returned with additional columns populated with the calculated metrics.

data_gdf
GeoDataFrame

The input data_gdf is returned with two additional columns: nearest_assigned and next_nearest_assign.

Notes

keyformulanotes
hillq0, q1(iSpiq)1/(1q)limq1exp(iS pi log pi)q\geq{0},\ q\neq{1} \\ \big(\sum_{i}^{S}p_{i}^q\big)^{1/(1-q)} \\ lim_{q\to1} \\ exp\big(-\sum_{i}^{S}\ p_{i}\ log\ p_{i}\big)Hill diversity: this is the preferred form of diversity metric because it adheres to the replication principle and uses units of effective species instead of measures of information or uncertainty. The q parameter controls the degree of emphasis on the richness of species as opposed to the balance of species. Over-emphasis on balance can be misleading in an urban context, for which reason research finds support for using q=0: this reduces to a simple count of distinct land-uses.
shannoniS pi log pi -\sum_{i}^{S}\ p_{i}\ log\ p_{i}Shannon diversity (or_information entropy_) is one of the classic diversity indices. Note that it is preferable to use Hill Diversity with q=1, which is effectively a transformation of Shannon diversity into units of effective species.
gini1iSpi2 1 - \sum_{i}^{S} p_{i}^2Gini-Simpson is another classic diversity index. It can behave problematically because it does not adhere to the replication principle and places emphasis on the balance of species, which can be counter-productive for purposes of measuring mixed-uses. Note that where an emphasis on balance is desired, it is preferable to use Hill Diversity with q=2, which is effectively a transformation of Gini-Simpson diversity into units of effective species.

hill at q=0 is generally the best choice for granular landuse data, or else q=1 or q=2 for increasingly crude landuse classifications schemas.

A worked example:

from cityseer.metrics import networks, layers
from cityseer.tools import mock, graphs, io

# prepare a mock graph
G = mock.mock_graph()
G = graphs.nx_simple_geoms(G)
nodes_gdf, edges_gdf, network_structure = io.network_structure_from_nx(G)
print(nodes_gdf.head())
landuses_gdf = mock.mock_landuse_categorical_data(G)
print(landuses_gdf.head())
nodes_gdf, landuses_gdf = layers.compute_mixed_uses(
    data_gdf=landuses_gdf,
    landuse_column_label="categorical_landuses",
    nodes_gdf=nodes_gdf,
    network_structure=network_structure,
    distances=[200, 400, 800],
)
# the data is written to the GeoDataFrame
print(nodes_gdf.columns)
# the default emits _nw and _wt; pass a single decay_fn to compute just one and save time
print(nodes_gdf["cc_hill_q0_800_nw"])

Be cognisant that mixed-use and land-use accessibility measures are sensitive to the classification schema that has been used. Meaningful comparisons from one location to another are only possible where the same schemas have been applied.

For a worked example, see the Mixed Uses recipe.

compute_stats

compute_stats
(
data_gdf : geopandas.geodataframe.GeoDataFrame
stats_column_labels : list[str]
nodes_gdf : geopandas.geodataframe.GeoDataFrame
network_structure : NetworkStructure
max_netw_assign_dist : float = 100.0
distances : list[int] | None = None
minutes : list[float] | None = None
data_id_col : str | None = None
barriers_gdf : geopandas.geodataframe.GeoDataFrame | None = None
angular : bool = False
n_nearest_candidates : int = 50
speed_m_s : float = 1.33333
decay_fn : str | dict[str, str] | None = None
measures : list[str] | None = None
)->[ GeoDataFrame GeoDataFrame ]

Compute numerical statistics over the street network. This function wraps the underlying rust optimised function for computing statistical measures. The data is aggregated and computed over the street network relative to the network nodes, with the implication that statistical aggregations are generated from the same locations as for centrality computations, which can therefore be correlated or otherwise compared.

Parameters

data_gdf
GeoDataFrame

A GeoDataFrame representing data points. The coordinates of data points should correspond as precisely as possible to the location of the feature in space; or, in the case of buildings, should ideally correspond to the location of the building entrance.

stats_column_labels
list[str]

The column labels corresponding to the columns in data_gdf from which to take numerical information.

nodes_gdf
None

A GeoDataFrame representing nodes. Best generated with the io.network_structure_from_nx function. The outputs of calculations will be written to this GeoDataFrame, which is then returned from the function.

network_structure
None

max_netw_assign_dist
float

The maximum distance to consider when assigning respective data points to the nearest adjacent network nodes.

distances
list[int]

Distance thresholds in metres for the network traversal. Metrics are computed for each threshold independently. If not provided, the minutes parameter must be provided instead.

minutes
list[float]

Walking time thresholds in minutes. Converted to distance thresholds using speed_m_s. If not provided, the distances parameter must be provided instead.

data_id_col
str

An optional column name for data point keys. This is used for deduplicating points representing a shared source of information. For example, where a single greenspace is represented by many entrances as datapoints, only the nearest entrance (from a respective location) will be considered (during aggregations) when the points share a datapoint identifier.

barriers_gdf
GeoDataFrame

A GeoDataFrame representing barriers. These barriers will be considered during the assignment of data points to the network.

angular
bool

Whether to use a simplest-path heuristic in-lieu of a shortest-path heuristic when calculating aggregations and distances.

n_nearest_candidates
int

The number of nearest candidates to consider when assigning respective data points to the nearest adjacent streets.

speed_m_s
float

Walking speed in metres per second used to convert minutes to distance thresholds.

decay_fn
str | dict[str, str]

An optional decay function expression using the variable p, where p is the normalised distance from 0 (source) to 1 (cutoff threshold). Controls how distance affects the statistical weighting. When omitted (None), the legacy default computes both an unweighted (_nw) and a decay-weighted (_wt) variant; pass a single expression such as "1" (flat) to compute one unsuffixed variant. For distance-weighted metrics, provide an expression such as "exp(-4 * p)" for exponential decay, or use the cityseer.decay module helpers. Values are clamped to [0, 1]. Supported functions include exp, ln, log, log10, sqrt, abs, floor, ceil, round, sin, cos, tan, and the ^ operator (min/max are not supported; to negate a power write -((x)^2) not -(x)^2). When multiple distances are specified, p is normalised independently per threshold. See cityseer.decay for details and examples. Pass a dict of {label: expression} to compute several decays in a single network traversal; each label is appended to that variant’s output column names (a plain string or None adds no suffix).

measures
list[str]

An optional subset of statistical measures to compute, chosen from "sum", "mean", "count", "var", "median", "mad", "max", and "min". Defaults to None, which computes all of them. Restricting the set keeps the output GeoDataFrame smaller and skips the weighted median / MAD sort when neither "median" nor "mad" is requested.

Returns

nodes_gdf
GeoDataFrame

The input node_gdf parameter is returned with additional columns populated with the calculated metrics.

data_gdf
GeoDataFrame

The input data_gdf is returned with two additional columns: nearest_assigned and next_nearest_assign.

Notes

Default exponential decay at multiple scales:

from cityseer.metrics import networks, layers
from cityseer.tools import mock, graphs, io

# prepare a mock graph
G = mock.mock_graph()
G = graphs.nx_simple_geoms(G)
nodes_gdf, edges_gdf, network_structure = io.network_structure_from_nx(G)
print(nodes_gdf.head())
numerical_gdf = mock.mock_numerical_data(G, num_arrs=3)
print(numerical_gdf.head())
nodes_gdf, numerical_gdf = layers.compute_stats(
    data_gdf=numerical_gdf,
    stats_column_labels=["mock_numerical_1"],
    nodes_gdf=nodes_gdf,
    network_structure=network_structure,
    distances=[200, 400, 800],
)
print(nodes_gdf.columns)
# mean at 400m; the default emits _nw and _wt. Pass a single decay_fn for just one,
# and measures=[...] to compute only the statistics you need — both save time
print(nodes_gdf["cc_mock_numerical_1_mean_400_nw"])

Custom decay using the p variable directly (Gaussian peaking at 400m within a 1200m cutoff):

nodes_gdf, numerical_gdf = layers.compute_stats(
    data_gdf=numerical_gdf,
    stats_column_labels=["mock_numerical_1"],
    nodes_gdf=nodes_gdf,
    network_structure=network_structure,
    distances=[1200],
    decay_fn="exp(-((p - 0.333)^2) / (2 * 0.125^2))",  # Gaussian peaking at 400m
)

Using the cityseer.decay helper module for the same Gaussian curve:

from cityseer import decay

nodes_gdf, numerical_gdf = layers.compute_stats(
    data_gdf=numerical_gdf,
    stats_column_labels=["mock_numerical_1"],
    nodes_gdf=nodes_gdf,
    network_structure=network_structure,
    distances=[1200],
    decay_fn=decay.gaussian(peak=400, cutoff=1200, std=150),
)

Flat (unweighted) metrics:

nodes_gdf, numerical_gdf = layers.compute_stats(
    data_gdf=numerical_gdf,
    stats_column_labels=["mock_numerical_1"],
    nodes_gdf=nodes_gdf,
    network_structure=network_structure,
    distances=[800],
    decay_fn="1",
)

The following stat types will be available for each stats_key for each of the computed distances:

  • max and min
  • sum
  • mean
  • count
  • median
  • variance
  • mad (median absolute deviation)

The decay function (default exponential, or custom via decay_fn) controls how distance affects the weighting. Use decay_fn="1" for flat (unweighted) metrics.

For a worked example, see the Statistical Aggregations recipe.