How To ¶
Build a Scenario using API ¶
Scenario objects manage how a collection of projects is applied to the networks.
Scenarios are built from a base scenario and a list of project cards.
A project card is a YAML file (or similar) that describes a change to the network. The project card can contain multiple changes, each of which is applied to the network in sequence.
Create a Scenario ¶
Instantiate a scenario by seeding it with a base scenario and optionally some project cards.
from network_wrangler import create_scenario
my_scenario = create_scenario(
base_scenario=my_base_year_scenario,
card_search_dir=project_card_directory,
filter_tags=["baseline2050"],
)
A base_year_scenario
is a dictionary representation of key components of a scenario:
road_net
: RoadwayNetwork instancetransit_net
: TransitNetwork instanceapplied_projects
: list of projects that have been applied to the base scenario so that the scenario knows if there will be conflicts with future projects or if a future project’s pre-requisite is satisfied.conflicts
: dictionary of conflicts for project that have been applied to the base scenario so that the scenario knows if there will be conflicts with future projects.
my_base_year_scenario = {
"road_net": load_from_roadway_dir(STPAUL_DIR),
"transit_net": load_transit(STPAUL_DIR),
"applied_projects": [],
"conflicts": {},
}
Add Projects to a Scenario ¶
In addition to adding projects when you create the scenario, project cards can be added to a
scenario using the add_project_cards
method.
from projectcard import read_cards
project_card_dict = read_cards(card_location, filter_tags=["Baseline2030"], recursive=True)
my_scenario.add_project_cards(project_card_dict.values())
Where card_location
can be a single path, list of paths, a directory, or a glob pattern.
Apply Projects to a Scenario ¶
Projects can be applied to a scenario using the apply_all_projects
method. Before applying
projects, the scenario will check that all pre-requisites are satisfied, that there are no conflicts,
and that the projects are in the planned projects list.
If you want to check the order of projects before applying them, you can use the queued_projects
prooperty.
You can review the resulting scenario, roadway network, and transit networks.
my_scenario.applied_projects
my_scenario.road_net.links_gdf.explore()
my_scenario.transit_net.feed.shapes_gdf.explore()
Write a Scenario to Disk ¶
Scenarios (and their networks) can be written to disk using the write
method which
in addition to writing out roadway and transit networks, will serialize the scenario to
a yaml-like file and can also write out the project cards that have been applied.
my_scenario.write(
"output_dir",
"scenario_name_to_use",
overwrite=True,
projects_write=True,
file_format="parquet",
)
Example Serialized Scenario File
applied_projects: &id001
- project a
- project b
base_scenario:
applied_projects: *id001
roadway:
dir: /Users/elizabeth/Documents/urbanlabs/MetCouncil/NetworkWrangler/working/network_wrangler/examples/small
file_format: geojson
transit:
dir: /Users/elizabeth/Documents/urbanlabs/MetCouncil/NetworkWrangler/working/network_wrangler/examples/small
config:
CPU:
EST_PD_READ_SPEED:
csv: 0.03
geojson: 0.03
json: 0.15
parquet: 0.005
txt: 0.04
IDS:
ML_LINK_ID_METHOD: range
ML_LINK_ID_RANGE: &id002 !!python/tuple
- 950000
- 999999
ML_LINK_ID_SCALAR: 15000
ML_NODE_ID_METHOD: range
ML_NODE_ID_RANGE: *id002
ML_NODE_ID_SCALAR: 15000
ROAD_SHAPE_ID_METHOD: scalar
ROAD_SHAPE_ID_SCALAR: 1000
TRANSIT_SHAPE_ID_METHOD: scalar
TRANSIT_SHAPE_ID_SCALAR: 1000000
MODEL_ROADWAY:
ADDITIONAL_COPY_FROM_GP_TO_ML: []
ADDITIONAL_COPY_TO_ACCESS_EGRESS: []
ML_OFFSET_METERS: -10
conflicts: {}
corequisites: {}
name: first_scenario
prerequisites: {}
roadway:
dir: /Users/elizabeth/Documents/urbanlabs/MetCouncil/NetworkWrangler/working/network_wrangler/tests/out/first_scenario/roadway
file_format: parquet
transit:
dir: /Users/elizabeth/Documents/urbanlabs/MetCouncil/NetworkWrangler/working/network_wrangler/tests/out/first_scenario/transit
file_format: txt
Load a scenario from disk ¶
And if you want to reload scenario that you “wrote”, you can use the load_scenario
function.
from network_wrangler import load_scenario
my_scenario = load_scenario("output_dir/scenario_name_to_use_scenario.yml")
additional examples
You can see additional scenario creating capabilities in the example jupyter notebook Scenario Building Example.ipynb
.
Build a Scenario from a Scenario Configuration File ¶
Scenario configuration for Network Wrangler.
You can build a scenario and write out the output from a scenario configuration file using the code below. This is very useful when you are running a specific scenario with minor variations over again because you can enter your config file into version control. In addition to the completed roadway and transit files, the output will provide a record of how the scenario was run.
Usage
from scenario import build_scenario_from_config
my_scenario = build_scenario_from_config(my_scenario_config)
Where my_scenario_config
can be a:
- Path to a scenario config file in yaml/toml/json (recommended),
- Dictionary which is in the same structure of a scenario config file, or
- A
ScenarioConfig()
instance.
Notes on relative paths in scenario configs
- Relative paths are recognized by a preceeding “.”.
- Relative paths within
output_scenario
forroadway
,transit
, andproject_cards
are interpreted to be relative tooutput_scenario.path
. - All other relative paths are interpreted to be relative to directory of the scenario config file. (Or if scenario config is provided as a dictionary, relative paths will be interpreted as relative to the current working directory.)
Example Scenario Config
name: "my_scenario"
base_scenario:
roadway:
dir: "path/to/roadway_network"
file_format: "geojson"
read_in_shapes: True
transit:
dir: "path/to/transit_network"
file_format: "txt"
applied_projects:
- "project1"
- "project2"
conflicts:
"project3": ["project1", "project2"]
"project4": ["project1"]
projects:
project_card_filepath:
- "path/to/projectA.yaml"
- "path/to/projectB.yaml"
filter_tags:
- "tag1"
output_scenario:
overwrite: True
roadway:
out_dir: "path/to/output/roadway"
prefix: "my_scenario"
file_format: "geojson"
true_shape: False
transit:
out_dir: "path/to/output/transit"
prefix: "my_scenario"
file_format: "txt"
project_cards:
out_dir: "path/to/output/project_cards"
wrangler_config: "path/to/wrangler_config.yaml"
Extended Usage
Load a configuration from a file:
from network_wrangler.configs import load_scenario_config
my_scenario_config = load_scenario_config("path/to/config.yaml")
Access the configuration:
Change Wrangler Configuration ¶
Configuration for parameters for Network Wrangler.
Users can change a handful of parameters which control the way Wrangler runs. These parameters can be saved as a wrangler config file which can be read in repeatedly to make sure the same parameters are used each time.
Usage
At runtime, you can specify configurable parameters at the scenario level which will then also be assigned and accessible to the roadway and transit networks.
Or if you are not using Scenario functionality, you can specify the config when you read in a RoadwayNetwork.
my_config
can be a:
- Path to a config file in yaml/toml/json (recommended),
- List of paths to config files (in case you want to split up various sub-configurations)
- Dictionary which is in the same structure of a config file, or
- A
WranglerConfig()
instance.
If not provided, Wrangler will use reasonable defaults.
Default Wrangler Configuration Values
If not explicitly provided, the following default values are used:
IDS:
TRANSIT_SHAPE_ID_METHOD: scalar
TRANSIT_SHAPE_ID_SCALAR: 1000000
ROAD_SHAPE_ID_METHOD: scalar
ROAD_SHAPE_ID_SCALAR: 1000
ML_LINK_ID_METHOD: range
ML_LINK_ID_RANGE: (950000, 999999)
ML_LINK_ID_SCALAR: 15000
ML_NODE_ID_METHOD: range
ML_NODE_ID_RANGE: (950000, 999999)
ML_NODE_ID_SCALAR: 15000
EDITS:
EXISTING_VALUE_CONFLIC: warn
OVERWRITE_SCOPED: conflicting
MODEL_ROADWAY:
ML_OFFSET_METERS: int = -10
ADDITIONAL_COPY_FROM_GP_TO_ML: []
ADDITIONAL_COPY_TO_ACCESS_EGRESS: []
CPU:
EST_PD_READ_SPEED:
csv: 0.03
parquet: 0.005
geojson: 0.03
json: 0.15
txt: 0.04
Extended usage
Load the default configuration:
Access the configuration:
from network_wrangler.configs import DefaultConfig
DefaultConfig.MODEL_ROADWAY.ML_OFFSET_METERS
>> -10
Modify the default configuration in-line:
from network_wrangler.configs import DefaultConfig
DefaultConfig.MODEL_ROADWAY.ML_OFFSET_METERS = 20
Load a configuration from a file:
from network_wrangler.configs import load_wrangler_config
config = load_wrangler_config("path/to/config.yaml")
Set a configuration value:
CpuConfig
¶
Bases: ConfigItem
CPU Configuration - Will not change any outcomes.
Attributes:
Name | Type | Description |
---|---|---|
EST_PD_READ_SPEED |
dict[str, float]
|
Read sec / MB - WILL DEPEND ON SPECIFIC COMPUTER |
Source code in network_wrangler/configs/wrangler.py
EditsConfig
¶
Bases: ConfigItem
Configuration for Edits.
Attributes:
Name | Type | Description |
---|---|---|
EXISTING_VALUE_CONFLICT |
Literal['warn', 'error', 'skip']
|
Only used if ‘existing’ provided in project card and
|
OVERWRITE_SCOPED |
Literal['conflicting', 'all', 'error']
|
How to handle conflicts with existing values.
Should be one of “conflicting”, “all”, or False.
“conflicting” will only overwrite values where the scope only partially overlaps with
the existing value. “all” will overwrite all the scoped values. “error” will error if
there is any overlap. Default is “conflicting”. Can be changed at the project-level
by setting |
Source code in network_wrangler/configs/wrangler.py
IdGenerationConfig
¶
Bases: ConfigItem
Model Roadway Configuration.
Attributes:
Name | Type | Description |
---|---|---|
TRANSIT_SHAPE_ID_METHOD |
Literal['scalar']
|
method for creating a shape_id for a transit shape. Should be “scalar”. |
TRANSIT_SHAPE_ID_SCALAR |
int
|
scalar value to add to general purpose lane to create a shape_id for a transit shape. |
ROAD_SHAPE_ID_METHOD |
Literal['scalar']
|
method for creating a shape_id for a roadway shape. Should be “scalar”. |
ROAD_SHAPE_ID_SCALAR |
int
|
scalar value to add to general purpose lane to create a shape_id for a roadway shape. |
ML_LINK_ID_METHOD |
Literal['range', 'scalar']
|
method for creating a model_link_id for an associated link for a parallel managed lane. |
ML_LINK_ID_RANGE |
tuple[int, int]
|
range of model_link_ids to use when creating an associated link for a parallel managed lane. |
ML_LINK_ID_SCALAR |
int
|
scalar value to add to general purpose lane to create a model_link_id when creating an associated link for a parallel managed lane. |
ML_NODE_ID_METHOD |
Literal['range', 'scalar']
|
method for creating a model_node_id for an associated node for a parallel managed lane. |
ML_NODE_ID_RANGE |
tuple[int, int]
|
range of model_node_ids to use when creating an associated node for a parallel managed lane. |
ML_NODE_ID_SCALAR |
int
|
scalar value to add to general purpose lane node ides create a model_node_id when creating an associated nodes for parallel managed lane. |
Source code in network_wrangler/configs/wrangler.py
ModelRoadwayConfig
¶
Bases: ConfigItem
Model Roadway Configuration.
Attributes:
Name | Type | Description |
---|---|---|
ML_OFFSET_METERS |
int
|
Offset in meters for managed lanes. |
ADDITIONAL_COPY_FROM_GP_TO_ML |
list[str]
|
Additional fields to copy from general purpose to managed lanes. |
ADDITIONAL_COPY_TO_ACCESS_EGRESS |
list[str]
|
Additional fields to copy to access and egress links. |
Source code in network_wrangler/configs/wrangler.py
WranglerConfig
¶
Bases: ConfigItem
Configuration for Network Wrangler.
Attributes:
Name | Type | Description |
---|---|---|
IDS |
IdGenerationConfig
|
Parameteters governing how new ids are generated. |
MODEL_ROADWAY |
ModelRoadwayConfig
|
Parameters governing how the model roadway is created. |
CPU |
CpuConfig
|
Parameters for accessing CPU information. Will not change any outcomes. |
EDITS |
EditsConfig
|
Parameters governing how edits are handled. |
Source code in network_wrangler/configs/wrangler.py
Review changes beetween networks ¶
Review Added Managed Lanes
from network_wrangler import load_roadway_from_dir
from projectcard import read_card
from pathlib import Path
EXAMPLE_DIR = Path.cwd().parent / "examples"
STPAUL = EXAMPLE_DIR / "stpaul"
STPAUL_ROAD = load_roadway_from_dir(STPAUL)
card_path = STPAUL / "project_cards" / "road.prop_change.managed_lanes.yml"
card = read_card(card_path)
stpaul_build = STPAUL_ROAD.apply(card)
ml_map = STPAUL_ROAD.links_df[STPAUL_ROAD.links_df.managed > 0].explore(
color="blue",
tiles="CartoDB positron",
name="Managed Lanes",
style_kwds={"opacity": 0.6, "weight": 20}
)
added_managed_lanes = stpaul_build.links_df[(stpaul_build.links_df.managed > 0) & (STPAUL_ROAD.links_df.managed == 0)]
added_managed_lanes.explore(
m=ml_map,
color="red",
name="Added Managed Lanes",
style_kwds={"opacity": 0.6, "weight": 20}
)
additional examples
You can see additional scenario review capabilities in the example jupyter notebook Visual Checks.ipynb
.
Review selected facilities ¶
Review selected links
from network_wrangler import load_roadway_from_dir
from pathlib import Path
EXAMPLE_DIR = Path.cwd().parent / "examples"
STPAUL = EXAMPLE_DIR / "stpaul"
STPAUL_ROAD = load_roadway_from_dir(STPAUL)
sel_dict = {
"links": {
"modes": ["walk"],
"name": ["Valley Street"],
},
"from": {"model_node_id": 174762},
"to": {"model_node_id": 43041},
}
STPAUL_ROAD.get_selection(sel_dict).selected_links_df.explore(
color="red", style_kwds={"opacity": 0.6, "weight": 20}
)
additional examples
You can see additional interactive exploration of how selections work and how to review them in the Jupyter notebook Roadway Network Search.ipynb
.
Create your own example data from Open Street Map ¶
This script builds a basic OpenStreetMap (OSM) road network for a specified place.
This script uses the network_wrangler library to build a roadway network from OSM data. It allows you to specify the place name, network type, output path, and file format for the resulting network.
Usage
python build_basic_osm_roadnet.py <place_name> [--type <type>] [--path <path>] [--file_format <file_format>]
Parameters:
Name | Type | Description | Default |
---|---|---|---|
place_name |
str
|
Name of the place to build the road network for. |
required |
--type |
Optional[str]
|
Type of network to build Defaults to |
required |
--path |
Optional[str]
|
Path to write the network. Defaults to current working directory. |
required |
--file_format |
Optional[str]
|
File format for writing the network. Defaults to |
required |
Example
additional examples
You can review the process in this script step-wise and interactively create your own networks from OSM with variation in the underlying assumptions in the Jupyter notebook Create Network from OSM.ipynb
.
Review separated model network managed lanes ¶
Review model network
m_net = stpaul_build.model_net
model_net_map = m_net.gp_links_df.explore(
tiles="CartoDB positron",
color="blue",
style_kwds={"opacity": 0.6, "weight": 10}
)
m_net.ml_links_df.explore(m=model_net_map, color="red", style_kwds={"opacity": 0.6, "weight": 10})
m_net.dummy_links_df.explore(m=model_net_map, color="green", style_kwds={"opacity": 0.6, "weight": 10})
additional examples
You can learn more about visualization of networks in the Jupyter notebook Network Viewer.ipynb
.
{! include-markdown(“https://raw.githubusercontent.com/network-wrangler/projectcard/refs/heads/main/docs/how-to.md”) !}