Note
Go to the end to download the full example code.
Network skimming#
In this example, we show how to perform network skimming for Coquimbo, a city in La Serena Metropolitan Area in Chile.
See also
Several functions, methods, classes and modules are used in this example:
# Imports
from uuid import uuid4
from tempfile import gettempdir
from os.path import join
from aequilibrae.utils.create_example import create_example
# We create the example project inside our temp folder
fldr = join(gettempdir(), uuid4().hex)
project = create_example(fldr, "coquimbo")
import logging
import sys
When the project opens, we can tell the logger to direct all messages to the terminal as well
logger = project.logger
stdout_handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter("%(asctime)s;%(levelname)s ; %(message)s")
stdout_handler.setFormatter(formatter)
logger.addHandler(stdout_handler)
Network Skimming#
import numpy as np
Let’s build all graphs
project.network.build_graphs()
# We get warnings that several fields in the project are filled with ``NaN``s.
# This is true, but we won't use those fields.
2025-06-17 01:06:18,804;WARNING ; Field(s) speed, travel_time, capacity, osm_id, lanes has(ve) at least one NaN value. Check your computations
/home/runner/work/aequilibrae/aequilibrae/aequilibrae/paths/graph.py:248: UserWarning: Found centroids not present in the graph!
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
127 128 129 130 131 132 133]
warnings.warn("Found centroids not present in the graph!\n" + str(centroids[~present_centroids]))
2025-06-17 01:06:18,881;WARNING ; Field(s) speed, travel_time, capacity, osm_id, lanes has(ve) at least one NaN value. Check your computations
2025-06-17 01:06:18,973;WARNING ; Field(s) speed, travel_time, capacity, osm_id, lanes has(ve) at least one NaN value. Check your computations
2025-06-17 01:06:19,060;WARNING ; Field(s) speed, travel_time, capacity, osm_id, lanes has(ve) at least one NaN value. Check your computations
/home/runner/work/aequilibrae/aequilibrae/aequilibrae/paths/graph.py:248: UserWarning: Found centroids not present in the graph!
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
127 128 129 130 131 132 133]
warnings.warn("Found centroids not present in the graph!\n" + str(centroids[~present_centroids]))
We grab the graph for cars
graph = project.network.graphs["c"]
# we also see what graphs are available
project.network.graphs.keys()
# let's say we want to minimize the distance
graph.set_graph("distance")
# And will skim distance while we are at it, other fields like ``free_flow_time`` or ``travel_time``
# can be added here as well
graph.set_skimming(["distance"])
# But let's say we only want a skim matrix for nodes 28-40, and 49-60 (inclusive),
# these happen to be a selection of western centroids.
graph.prepare_graph(np.array(list(range(28, 41)) + list(range(49, 91))))
2025-06-17 01:06:19,354;WARNING ; Field(s) speed, travel_time, capacity, osm_id, lanes has(ve) at least one NaN value. Check your computations
And run the skimming
skm = graph.compute_skims()
: 0%| | 0/55 [00:00<?, ?it/s]
1/55 : 2%|▏ | 1/55 [00:00<00:00, 314.23it/s]
2/55 : 4%|▎ | 2/55 [00:00<00:00, 584.49it/s]
3/55 : 5%|▌ | 3/55 [00:00<00:00, 819.89it/s]
4/55 : 7%|▋ | 4/55 [00:00<00:00, 1011.04it/s]
5/55 : 9%|▉ | 5/55 [00:00<00:00, 1165.93it/s]
6/55 : 11%|█ | 6/55 [00:00<00:00, 1314.97it/s]
7/55 : 13%|█▎ | 7/55 [00:00<00:00, 1451.82it/s]
8/55 : 15%|█▍ | 8/55 [00:00<00:00, 1569.80it/s]
9/55 : 16%|█▋ | 9/55 [00:00<00:00, 1672.15it/s]
10/55 : 18%|█▊ | 10/55 [00:00<00:00, 1766.69it/s]
11/55 : 20%|██ | 11/55 [00:00<00:00, 1850.97it/s]
12/55 : 22%|██▏ | 12/55 [00:00<00:00, 1930.26it/s]
13/55 : 24%|██▎ | 13/55 [00:00<00:00, 2003.45it/s]
14/55 : 25%|██▌ | 14/55 [00:00<00:00, 2070.24it/s]
15/55 : 27%|██▋ | 15/55 [00:00<00:00, 2128.30it/s]
16/55 : 29%|██▉ | 16/55 [00:00<00:00, 2186.67it/s]
17/55 : 31%|███ | 17/55 [00:00<00:00, 2240.62it/s]
18/55 : 33%|███▎ | 18/55 [00:00<00:00, 2283.65it/s]
19/55 : 35%|███▍ | 19/55 [00:00<00:00, 2332.76it/s]
20/55 : 36%|███▋ | 20/55 [00:00<00:00, 2377.52it/s]
21/55 : 38%|███▊ | 21/55 [00:00<00:00, 2418.93it/s]
22/55 : 40%|████ | 22/55 [00:00<00:00, 2448.64it/s]
23/55 : 42%|████▏ | 23/55 [00:00<00:00, 2488.24it/s]
24/55 : 44%|████▎ | 24/55 [00:00<00:00, 2522.13it/s]
25/55 : 45%|████▌ | 25/55 [00:00<00:00, 2547.99it/s]
26/55 : 47%|████▋ | 26/55 [00:00<00:00, 2576.48it/s]
27/55 : 49%|████▉ | 27/55 [00:00<00:00, 2604.20it/s]
28/55 : 51%|█████ | 28/55 [00:00<00:00, 2632.90it/s]
29/55 : 53%|█████▎ | 29/55 [00:00<00:00, 2662.58it/s]
30/55 : 55%|█████▍ | 30/55 [00:00<00:00, 2677.79it/s]
31/55 : 56%|█████▋ | 31/55 [00:00<00:00, 2706.51it/s]
32/55 : 58%|█████▊ | 32/55 [00:00<00:00, 2722.30it/s]
33/55 : 60%|██████ | 33/55 [00:00<00:00, 2740.13it/s]
34/55 : 62%|██████▏ | 34/55 [00:00<00:00, 2750.20it/s]
35/55 : 64%|██████▎ | 35/55 [00:00<00:00, 2772.60it/s]
36/55 : 65%|██████▌ | 36/55 [00:00<00:00, 2781.57it/s]
37/55 : 67%|██████▋ | 37/55 [00:00<00:00, 2803.78it/s]
38/55 : 69%|██████▉ | 38/55 [00:00<00:00, 2815.52it/s]
39/55 : 71%|███████ | 39/55 [00:00<00:00, 2837.04it/s]
40/55 : 73%|███████▎ | 40/55 [00:00<00:00, 2844.37it/s]
41/55 : 75%|███████▍ | 41/55 [00:00<00:00, 2862.82it/s]
42/55 : 76%|███████▋ | 42/55 [00:00<00:00, 2872.90it/s]
43/55 : 78%|███████▊ | 43/55 [00:00<00:00, 2887.58it/s]
44/55 : 80%|████████ | 44/55 [00:00<00:00, 2897.26it/s]
45/55 : 82%|████████▏ | 45/55 [00:00<00:00, 2911.36it/s]
46/55 : 84%|████████▎ | 46/55 [00:00<00:00, 2919.45it/s]
47/55 : 85%|████████▌ | 47/55 [00:00<00:00, 2933.91it/s]
48/55 : 87%|████████▋ | 48/55 [00:00<00:00, 2941.69it/s]
49/55 : 89%|████████▉ | 49/55 [00:00<00:00, 2956.45it/s]
50/55 : 91%|█████████ | 50/55 [00:00<00:00, 2957.78it/s]
51/55 : 93%|█████████▎| 51/55 [00:00<00:00, 2974.35it/s]
52/55 : 95%|█████████▍| 52/55 [00:00<00:00, 2980.86it/s]
53/55 : 96%|█████████▋| 53/55 [00:00<00:00, 3005.94it/s]
54/55 : 98%|█████████▊| 54/55 [00:00<00:00, 3029.55it/s]
55/55 : 100%|██████████| 55/55 [00:00<00:00, 3044.36it/s]
Saving Outputs : 100%|██████████| 55/55 [00:00<00:00, 2961.51it/s]
Building network skims directly from the graph is more straightforward, though
we could alternatively use the class NetworkSkimming
to achieve the same result.
# from aequilibrae.paths import NetworkSkimming
# skm = NetworkSkimming(graph)
# skm.execute()
The result is an AequilibraEMatrix object
skims = skm.results.skims
# Which we can manipulate directly from its temp file, if we wish
skims.matrices[:3, :3, :]
array([[[ 0. ],
[4166.92919206],
[5532.32681478]],
[[3733.4499255 ],
[ 0. ],
[3311.30654014]],
[[5446.26074416],
[3596.12274848],
[ 0. ]]])
Or access each matrix, lets just look at the first 3x3
skims.distance[:3, :3]
array([[ 0. , 4166.92919206, 5532.32681478],
[3733.4499255 , 0. , 3311.30654014],
[5446.26074416, 3596.12274848, 0. ]])
We can save it to the project if we want
skm.save_to_project("base_skims")
2025-06-17 01:06:19,457;WARNING ; Matrix Record has been saved to the database
We can also retrieve this skim record to write something to its description
matrices = project.matrices
mat_record = matrices.get_record("base_skims")
mat_record.description = "minimized distance while also skimming distance for just a few nodes"
mat_record.save()
project.close()
This project at /tmp/174a883e747443d7b0ce8814f963981b is already closed
Total running time of the script: (0 minutes 0.993 seconds)