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)

Gallery generated by Sphinx-Gallery