NetworkAnalysisRules

Sets the rules for the NetworkAnalysis.

class NetworkAnalysisRules(directed, weight, search_tolerance=250, search_factor=0, split_lines=True, nodedist_multiplier=None, nodedist_kmh=None)[source]

Bases: object

Sets the rules for the network analysis.

To be used as the ‘rules’ parameter in the NetworkAnalysis class.

Parameters:
  • weight (str) – Either a column in the GeoDataFrame of the Network or ‘meters’/’metres’. A ‘minutes’ column can be created with the ‘make_directed_network’ or ‘make_directed_network_norway’ functions.

  • directed (bool) – Whether the lines will be considered traversable in both directions.

  • search_tolerance (int) – distance to search for nodes in the network. Origins and destinations further away from the network than the search_tolerance will not find any paths. Defaults to 250.

  • search_factor (int) –

    number of meters and percent to add to the closest distance to a node when connecting origins and destinations to the network. Defaults to 0, meaning only the closest node is used. If search_factor is 10 and the closest node is 1 meter away, paths will be created from the point and all nodes within 11.1 meters. If the closest node is 100 meters away, paths will be created with all nodes within 120 meters.

    It can be wise to set a higher search_factor only for the origins and destinations that are causing problems in a separate analysis run.

  • split_lines (bool) – If True (default), the closest line to each point will be split in two at the nearest excact point. The weight of the split lines are then adjusted to the new length. If False, the points will be connected to the endpoints of the network lines.

  • nodedist_kmh (int | float | None) – When using “minutes” as weight, this sets the speed in kilometers per hour for the edges between origins/destinations and the network nodes that connect them. Defaults to None, meaning 0 weight is added for the edges.

  • nodedist_multiplier (int | float | None) – When using “meters” as weight, this sets the weight for the edges between origins/destinations and the network nodes that connect them. Defaults to None, meaning 0 weight is added for these edges. If set to 1, the weight will be equal to the straigt line distance.

Examples:

Read testdata.

>>> import sgis as sg
>>> roads = sg.read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/roads_oslo_2022.parquet")
>>> points = sg.read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/points_oslo.parquet")

Let’s start by setting the default rules. ‘weight’ and ‘directed’ have no default values.

>>> rules = sg.NetworkAnalysisRules(weight="minutes", directed=True)
>>> directed_roads = sg.get_connected_components(roads).loc[lambda x: x["connected"] == 1].pipe(sg.make_directed_network_norway, dropnegative=True)
>>> nwa = sg.NetworkAnalysis(network=directed_roads, rules=rules, detailed_log=True)
>>> nwa
NetworkAnalysis(
    network=Network(6364 km, percent_bidirectional=87),
    rules=NetworkAnalysisRules(weight=minutes, directed=True, search_tolerance=250, search_factor=0, split_lines=True, ...),
    log=True, detailed_log=True,
)

Setting ‘split_lines’ to True, means the points will be connected to the closest part of the closest network line. If False, the lines are connected to the closest endpoint of the lines. split_lines defaults to False, since splitting lines takes some time and doesn’t make a huge difference in most cases.

>>> od = nwa.od_cost_matrix(points, points)
>>> nwa.rules.split_lines = True
>>> od = nwa.od_cost_matrix(points, points)
>>> nwa.log[['split_lines', 'percent_missing', 'cost_mean']]
   split_lines  percent_missing  cost_mean
0        False           0.9966  15.270462
1         True           0.8973  15.249900
>>> nwa.rules.split_lines = False

Setting a high search_tolerance will make faraway points find their way to the network.

>>> for i in [100, 250, 500, 1000]:
...     nwa.rules.search_tolerance = i
...     od = nwa.od_cost_matrix(points, points)
>>> nwa.log.iloc[-4:][['percent_missing', 'cost_mean', 'search_tolerance', 'search_factor']]
   percent_missing  cost_mean  search_tolerance  search_factor
2           2.3840  15.235559               100              0
3           0.9966  15.270462               250              0
4           0.7976  15.273579               500              0
5           0.5984  15.268614              1000              0

High search_tolerance won’t affect how the points close to the network are connected to network nodes. Points trapped behind deadend oneway streets, can find their way out with a higher search_factor.

>>> nwa.rules.search_tolerance = 250
>>> for i in [0, 10, 35, 100]:
...     nwa.rules.search_factor = i
...     od = nwa.od_cost_matrix(points, points)
>>> nwa.log.iloc[-4:][['percent_missing', 'cost_mean', 'search_tolerance', 'search_factor']]
   percent_missing  cost_mean  search_tolerance  search_factor
6           0.9966  15.270462               250              0
7           0.5987  15.063283               250             10
8           0.4991  14.636172               250             35
9           0.3994  13.680307               250            100

The remaining 0.4 percent missing are from/to two points, one on an island with no brigde and one at the edge of the road network (would require a larger network). These two points only find themselves, and thus has 999 missing values.

>>> n_missing = od.groupby("origin").minutes.agg(lambda x: x.isna().sum())
>>> n_missing.n_largest(3)
59     999
510    999
0        2
Name: minutes, dtype: int64

By default, the distance from origin/destination to the network nodes is given a weight of 0. This means, if the search_tolerance is high, points far away from the network will get unrealisticly low travel times/distances. The weight from origin/ destination to the network nodes can be set with the ‘nodedist_kmh’ parameter if the weight is ‘minutes’, and the ‘nodedist_multiplier’ if the weight is ‘meters’.

If the weight is ‘minutes’, setting ‘nodedist_kmh’ to 5 means a distance of 1000 meters will get a weight of 12 minutes.

>>> nwa.rules.search_tolerance = 5000
>>> for i in [3, 10, 50]:
...     nwa.rules.nodedist_kmh = i
...     od = nwa.od_cost_matrix(points, points)
...
>>> nwa.log.iloc[-3:][['nodedist_kmh', 'cost_mean']]
   nodedist_kmh  cost_mean
10            3  15.924197
11           10  14.817717
12           50  13.964457

If the weight is ‘meters’, setting nodedist_multiplier=1 will make the distance to nodes count as its straight line distance.

>>> rules = NetworkAnalysisRules(
...     weight="meters",
...     search_tolerance=5000,
... )
>>> nwa = NetworkAnalysis(network=directed_roads, rules=rules)
>>> od = nwa.od_cost_matrix(points, points)
>>> nwa.rules.nodedist_multiplier = 1
>>> od = nwa.od_cost_matrix(points, points)
>>> nwa.log[['nodedist_multiplier', 'cost_mean']]
  nodedist_multiplier     cost_mean
0                None  10228.400228
1                   1  10277.926186
copy()[source]

Return a shallow copy the instance.

Return type:

NetworkAnalysisRules

deepcopy()[source]

Return a deep copy the instance.

Return type:

NetworkAnalysisRules