Custom data demo¶
Note - this script can also be opened in interactive Python if you wanted to
play around. On the GitHub it is in docs/notebooks.
To run this on your local machine, you will need to install the optional dependencies
for doc:
pip install swmmanywhere[doc]
Introduction¶
This script demonstrates how to use swmmanywhere when you have custom data.
Since this is a notebook, we will define config
as a dictionary rather than a yaml file, but the same principles apply.
Initial setup¶
We will use the same example as the extended demo, but with a custom elevation dataset. Let's start by rerunning it.
In [1]:
Copied!
# Imports
from __future__ import annotations
import tempfile
from pathlib import Path
import folium
import geopandas as gpd
from swmmanywhere.logging import set_verbose
from swmmanywhere.swmmanywhere import swmmanywhere
from swmmanywhere.utilities import plot_map
# Create temporary directory
temp_dir = tempfile.TemporaryDirectory(dir=".")
base_dir = Path(temp_dir.name)
# Define minimum viable config
bbox = (1.52740, 42.50524, 1.54273, 42.51259)
config = {
"base_dir": base_dir,
"project": "my_first_swmm",
"bbox": bbox,
"run_settings": {"duration": 3600},
"parameter_overrides": {
"topology_derivation": {
"allowable_networks": ["drive"],
"omit_edges": ["bridge"],
},
"outfall_derivation": {
"outfall_length": 5,
"river_buffer_distance": 30,
},
},
}
set_verbose(True) # Set verbosity
# Run SWMManywhere
outputs = swmmanywhere(config)
model_dir = outputs[0].parent
# Imports
from __future__ import annotations
import tempfile
from pathlib import Path
import folium
import geopandas as gpd
from swmmanywhere.logging import set_verbose
from swmmanywhere.swmmanywhere import swmmanywhere
from swmmanywhere.utilities import plot_map
# Create temporary directory
temp_dir = tempfile.TemporaryDirectory(dir=".")
base_dir = Path(temp_dir.name)
# Define minimum viable config
bbox = (1.52740, 42.50524, 1.54273, 42.51259)
config = {
"base_dir": base_dir,
"project": "my_first_swmm",
"bbox": bbox,
"run_settings": {"duration": 3600},
"parameter_overrides": {
"topology_derivation": {
"allowable_networks": ["drive"],
"omit_edges": ["bridge"],
},
"outfall_derivation": {
"outfall_length": 5,
"river_buffer_distance": 30,
},
},
}
set_verbose(True) # Set verbosity
# Run SWMManywhere
outputs = swmmanywhere(config)
model_dir = outputs[0].parent
/opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html from .autonotebook import tqdm as notebook_tqdm
2025/10/10 14:35:28 | Creating project structure.
2025/10/10 14:35:28 | Project structure created at tmpq9xfrgih
2025/10/10 14:35:28 | Project name: my_first_swmm
2025/10/10 14:35:28 | Bounding box: (1.5274, 42.50524, 1.54273, 42.51259),
number: 1
2025/10/10 14:35:28 | Model number: 1
2025/10/10 14:35:28 | Loading and setting parameters.
2025/10/10 14:35:28 | Setting topology_derivation allowable_networks to ['drive']
2025/10/10 14:35:28 | Setting topology_derivation omit_edges to ['bridge']
2025/10/10 14:35:28 | Setting outfall_derivation outfall_length to 5
2025/10/10 14:35:28 | Setting outfall_derivation river_buffer_distance to 30
2025/10/10 14:35:28 | Allowable networks have been changed, removing old street graph.
2025/10/10 14:35:28 | Running downloads.
2025/10/10 14:35:28 | downloading elevation to tmpq9xfrgih/my_first_swmm/bbox_1/download/elevation.tif
2025/10/10 14:35:35 | downloading buildings to tmpq9xfrgih/my_first_swmm/bbox_1/download/building.geoparquet
2025/10/10 14:35:48 | downloading network to tmpq9xfrgih/my_first_swmm/bbox_1/download/street.parquet
2025/10/10 14:36:51 | downloading river network to tmpq9xfrgih/my_first_swmm/bbox_1/download/river.parquet
2025/10/10 14:36:52 | Iterating graphs.
2025/10/10 14:36:52 | Iterating graph functions.
2025/10/10 14:36:52 | graphfcn: assign_id completed.
2025/10/10 14:36:52 | graphfcn: fix_geometries completed.
2025/10/10 14:36:52 | graphfcn: remove_non_pipe_allowable_links completed.
/opt/hostedtoolcache/Python/3.11.13/x64/lib/python3.11/site-packages/networkx/readwrite/json_graph/node_link.py:290: FutureWarning: The default value will be changed to `edges="edges" in NetworkX 3.6. To make this warning go away, explicitly set the edges kwarg, e.g.: nx.node_link_graph(data, edges="links") to preserve current behavior, or nx.node_link_graph(data, edges="edges") for forward compatibility. warnings.warn(
2025/10/10 14:36:52 | graphfcn: calculate_streetcover completed.
2025/10/10 14:36:52 | graphfcn: remove_parallel_edges completed.
2025/10/10 14:36:53 | graphfcn: to_undirected completed.
2025/10/10 14:36:53 | graphfcn: split_long_edges completed.
2025/10/10 14:36:53 | graphfcn: merge_street_nodes completed.
2025/10/10 14:36:53 | graphfcn: assign_id completed.
2025/10/10 14:36:58 | graphfcn: clip_to_catchments completed.
2025/10/10 14:36:59 | graphfcn: calculate_contributing_area completed.
2025/10/10 14:36:59 | graphfcn: set_elevation completed.
2025/10/10 14:36:59 | graphfcn: double_directed completed.
2025/10/10 14:37:00 | graphfcn: fix_geometries completed.
2025/10/10 14:37:00 | graphfcn: set_surface_slope completed.
2025/10/10 14:37:00 | graphfcn: set_chahinian_slope completed.
2025/10/10 14:37:00 | graphfcn: set_chahinian_angle completed.
2025/10/10 14:37:00 | graphfcn: calculate_weights completed.
2025/10/10 14:37:00 | No outfalls found for subgraph containing
858, using this node as outfall.
2025/10/10 14:37:00 | No outfalls found for subgraph containing
823, using this node as outfall.
2025/10/10 14:37:00 | No outfalls found for subgraph containing
507, using this node as outfall.
2025/10/10 14:37:00 | No outfalls found for subgraph containing
674, using this node as outfall.
2025/10/10 14:37:00 | No outfalls found for subgraph containing
754, using this node as outfall.
2025/10/10 14:37:00 | No outfalls found for subgraph containing
779, using this node as outfall.
2025/10/10 14:37:00 | No outfalls found for subgraph containing
1255, using this node as outfall.
2025/10/10 14:37:00 | No outfalls found for subgraph containing
1535, using this node as outfall.
2025/10/10 14:37:00 | graphfcn: identify_outfalls completed.
2025/10/10 14:37:01 | Total graph weight 264.28645874589057.
2025/10/10 14:37:01 | graphfcn: derive_topology completed.
0%| | 0/395 [00:00<?, ?it/s]
11%|█ | 42/395 [00:00<00:00, 415.47it/s]
22%|██▏ | 88/395 [00:00<00:00, 433.94it/s]
33%|███▎ | 132/395 [00:00<00:00, 407.61it/s]
44%|████▍ | 173/395 [00:00<00:00, 344.30it/s]
53%|█████▎ | 209/395 [00:00<00:00, 323.32it/s]
62%|██████▏ | 243/395 [00:00<00:00, 291.37it/s]
69%|██████▉ | 273/395 [00:00<00:00, 283.80it/s]
77%|███████▋ | 304/395 [00:00<00:00, 287.43it/s]
85%|████████▍ | 334/395 [00:01<00:00, 286.69it/s]
92%|█████████▏| 363/395 [00:01<00:00, 256.55it/s]
99%|█████████▊| 390/395 [00:01<00:00, 259.13it/s]
100%|██████████| 395/395 [00:01<00:00, 297.39it/s]
2025/10/10 14:37:02 | graphfcn: pipe_by_pipe completed.
2025/10/10 14:37:02 | graphfcn: fix_geometries completed.
2025/10/10 14:37:02 | graphfcn: assign_id completed.
2025/10/10 14:37:02 | Saving final graph and writing inp file.
Skipping field osmid: unsupported OGR type: 1
Skipping field highway: unsupported OGR type: 5
Skipping field lanes: unsupported OGR type: 5
Skipping field maxspeed: unsupported OGR type: 5
Skipping field name: unsupported OGR type: 5
Skipping field reversed: unsupported OGR type: 1
2025/10/10 14:37:03 | Running the synthetic model.
2025/10/10 14:37:03 | tmpq9xfrgih/my_first_swmm/bbox_1/model_1/model_1.inp initialised in pyswmm
2025/10/10 14:37:03 | Starting simulation for: tmpq9xfrgih/my_first_swmm/bbox_1/model_1/model_1.inp
0%| | 0/3600 [00:00<?, ?it/s]
13%|█▎ | 483.0/3600 [00:00<00:00, 4815.13it/s]
27%|██▋ | 965.0/3600 [00:00<00:01, 2388.51it/s]
35%|███▌ | 1268.0/3600 [00:00<00:01, 2160.15it/s]
44%|████▍ | 1580.0/3600 [00:00<00:00, 2406.82it/s]
56%|█████▌ | 2021.0/3600 [00:00<00:00, 2948.13it/s]
75%|███████▍ | 2695.0/3600 [00:00<00:00, 4001.00it/s]
2025/10/10 14:37:04 | Model run complete.
3605.0it [00:00, 3748.40it/s]
2025/10/10 14:37:04 | Writing synthetic results.
2025/10/10 14:37:04 | No real network provided, returning SWMM .inp file.
Plotting output¶
Now we can plot the output. To highlight the differences in the supplied data that we are about to demonstrate, we also plot the subbasins.
In [2]:
Copied!
m = plot_map(model_dir)
subbasins = gpd.read_file(model_dir / "subbasins.geoparquet")
folium.GeoJson(subbasins, fill_opacity=0, color="blue", weight=2).add_to(m)
m
m = plot_map(model_dir)
subbasins = gpd.read_file(model_dir / "subbasins.geoparquet")
folium.GeoJson(subbasins, fill_opacity=0, color="blue", weight=2).add_to(m)
m
Skipping field osmid: unsupported OGR type: 1
Skipping field highway: unsupported OGR type: 5
Skipping field lanes: unsupported OGR type: 5
Skipping field maxspeed: unsupported OGR type: 5
Skipping field name: unsupported OGR type: 5
Skipping field reversed: unsupported OGR type: 1
Out[2]:
Make this Notebook Trusted to load map: File -> Trust Notebook