Hackathon Q1 - 2024#
Context#
Overall goal#
Setting up a workflow to enable running RA2CE with multiple flood scenarios in an efficient way, on a larger geographical scale and post-processing the outcomes effectively into meaningful results
User questions#
UQ1 Which roads are most likely to get hit by flooding from this hurricane given its projected flood maps?
UQ2 Where are the flood impacts most disruptive in terms of accessibility? (detour length) = multi-link redundancy
[UQ3] Which areas/locations are most likely to be unreachable because of this hurricane given its possible tracks? (OD analysis) (to be refined)
[UQ4] Optional if damages module works: What is the range of minimum and maximum damages that might occur because of this hurricane given its possible tracks?
Results#
You can inspect the generated results directly by running the “visualize” snippets of each user question:
Hackathon requirements#
Being able to run RA2CE on a large scale with a complex network
This should be coded generically so that we could do this ‘anywhere’
But computational time increases a lot with the scale and complexity of the network – how to handle?
How to determine the extent of the network with different flood maps?
Splitting up in smaller subsets? How would that change workflow and results?
Running RA2CE in the cloud with multiple flood maps (100+) in different formats and storing the results
Being able to handle netcdf / data array / zar data formats?
Storing the different RA2CE runs and data efficiently
Skipping the second hazard overlay with the segmented graph as it increases computational time?
Running multiple flood maps that represent a time series and then adding a time dimension in RA2CE results / analysis
Having a script that handles and post-processes multiple results
Processing and storing results for all scenario runs and consolidate/merge them
Determining what the most interesting information is and how to communicate/visualize this
Visualization outputs such as statistics or ranges
Generic workflow#
The workflow to be run (with slight modifications) to solve all the user questions is as described in the following diagram:
Generic hackathon workflow |
User Question 1#
UQ1 Description#
UQ1: Which roads are most likely to get hit by flooding from this hurricane given its projected flood maps?
Input: road extent (OSM), 100+ flood maps from SFINCS in Beira/Qualimane area and a RA2CE folder setup with .ini files.
Proposed workflow: multiple flood maps – for every flood map a seperate RA2CE run - for every scenario seperate results – save the results in an efficient way – postprocess into meaningful results.
Expected output: flood depths on edges for every scenario.
Expected post-processed results: per edge an indication of ‘likelihood’ of flooding (e.g. in 90 / 100 scenario’s this edge gets hit (% hits)).
Acceptance level: Tackle user question 1 on Tuesday.
Which questions for user questions 2,3,4 are also relevant for question 1?
Input#
Collection of hazard files in
.tif
format.Boundary box (coordinates) of the network extent.
ra2ce network configuration file in
.ini
file.
UQ1 workflow#
Based on the generic workflow we create our own Argo worfklow. This configuration file can also be found at user_question_1\hackathon_workflow.yaml
.
[ ]:
# Content of `user_question_1\hackathon_workflow.yaml`
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: ra2ce-hackathon-uq1-
spec:
entrypoint: scenario-workflow
templates:
- name: scenario-workflow
steps:
- - name: define-subdirs
template: read-members
- - name: run-scenario
template: run-scenario
arguments:
parameters:
- name: member
value: "{{item}}"
withParam: "{{steps.define-subdirs.outputs.result}}"
- - name: post-processing
template: post-processing
- name: read-members
script:
image: 798877697266.dkr.ecr.eu-west-1.amazonaws.com/boto3:latest
workingDir: /data
command: [python]
source: |
import boto3
import json
bucket = 'ra2ce-data'
prefix = 'sfincs_floodmaps_sub/'
client = boto3.client('s3')
result = client.list_objects(Bucket=bucket, Prefix=prefix, Delimiter='/')
members = []
for o in result.get('Contents'):
mem = o.get('Key').split('/')[1].split('.')[0]
if mem != "":
members.append(mem)
print(json.dumps(members))
- name: run-scenario
container:
image: containers.deltares.nl/ra2ce/ra2ce:latest
command: ["python", "/scripts/user_question_1/hazard_overlay_cloud_run.py"]
nodeSelector:
beta.kubernetes.io/instance-type: "m5.xlarge"
inputs:
parameters:
- name: member
artifacts:
- name: input
path: /input/{{inputs.parameters.member}}.tif
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: sfincs_floodmaps_sub/{{inputs.parameters.member}}.tif
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
- name: data
path: /data
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: beira_qualimane_sfincs_fm/data
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
- name: scripts
path: /scripts
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: beira_qualimane_sfincs_fm/scripts
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
outputs:
artifacts:
- name: ra2ce-output
path: /data
s3:
bucket: ra2ce-data
endpoint: s3.amazonaws.com
region: eu-west-1
key: beira_qualimane_sfincs_fm/output_q1/{{inputs.parameters.member}}/
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
- name: post-processing
container:
image: containers.deltares.nl/ra2ce/ra2ce:latest
command: ["python", "/scripts/user_question_1/post_processing.py"]
nodeSelector:
beta.kubernetes.io/instance-type: "m5.xlarge"
inputs:
artifacts:
- name: output
path: /data
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: beira_qualimane_sfincs_fm/output_q1
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
- name: scripts
path: /scripts
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: beira_qualimane_sfincs_fm/scripts
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
outputs:
artifacts:
- name: pp_output
path: /output
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: beira_qualimane_sfincs_fm/postprocessing_output_q1
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
UQ1 Pre-processing#
Preprocessing has three steps: - the creation of a network, - creating the buckets by splitting the floodmaps on different directories, - and the optional reprojection.
Network creation#
Preparing initial data#
[ ]:
# This script contains the first two sections of `hazard_overlay_preprocessing.ipynb`
# General imports
import geopandas as gpd
import pandas as pd
from pathlib import Path
from shapely import geometry, Polygon
from osgeo import gdal, osr
from shutil import copyfile
# RA2CE imports and constants
from ra2ce.network.network_config_data.enums.network_type_enum import NetworkTypeEnum
from ra2ce.network.network_config_data.enums.road_type_enum import RoadTypeEnum
from ra2ce.network.network_config_data.network_config_data import NetworkConfigData, NetworkSection
from ra2ce.network.network_wrappers.osm_network_wrapper.osm_network_wrapper import OsmNetworkWrapper
from ra2ce.network.exporters.geodataframe_network_exporter import GeoDataFrameNetworkExporter
from ra2ce.network.exporters.multi_graph_network_exporter import MultiGraphNetworkExporter
INPUT_FOLDER = Path('P:\moonshot2-casestudy\SFINCS\models')
INPUT_FLOODMAP_FOLDER = 'floodmaps_wgs84'
OUTPUT_FOLDER = Path('P:\moonshot2-casestudy\RA2CE')
OUTPUT_FLOODMAP_FOLDER = 'floodmaps'
Determine the polygon of the total extent of the regions#
The extent of each region is read from file region.geojson
and appended in a GeoDataFrame. From this GeoDataFrame a Polygon is extracted.
[ ]:
# This script contains the third section of `hazard_overlay_preprocessing.ipynb`
# Loop over region folders and concatenate the extents
_combined_gdf = gpd.GeoDataFrame()
for _region in [f for f in INPUT_FOLDER.iterdir() if f.is_dir()]:
_extent_file = _region.joinpath('gis', 'region.geojson')
assert _extent_file.is_file()
_gdf = gpd.read_file(_extent_file)
_combined_gdf = pd.concat([_combined_gdf, _gdf.to_crs(4326)], ignore_index=True)
# Extract polygon of the total extent spanning the concatenated regions
_total_extent = _combined_gdf.total_bounds
_polygon = Polygon(geometry.box(*_total_extent))
# Write polygon (not required)
_polygon_file = INPUT_FOLDER.joinpath('polygon.geojson')
_polygon_gdf = gpd.GeoDataFrame(index=[0], geometry=[_polygon], crs='epsg:4326')
_polygon_gdf.to_file(_polygon_file, driver='GeoJSON')
# Write the combined extent to a new file (not required)
_combined_extent_file = INPUT_FOLDER.joinpath('combined_extent.geojson')
_combined_geojson = _combined_gdf.to_json()
with open(_combined_extent_file, 'w') as f:
f.write(_combined_geojson)
Create network#
The network is downloaded from OSM based on the given polygon.
[ ]:
# Read network from polygon
_road_type_list = [RoadTypeEnum.MOTORWAY, RoadTypeEnum.MOTORWAY_LINK, RoadTypeEnum.TRUNK, RoadTypeEnum.TRUNK_LINK, RoadTypeEnum.PRIMARY, RoadTypeEnum.PRIMARY_LINK, RoadTypeEnum.SECONDARY, RoadTypeEnum.SECONDARY_LINK, RoadTypeEnum.TERTIARY, RoadTypeEnum.TERTIARY_LINK]
_network_section = NetworkSection(network_type=NetworkTypeEnum.DRIVE, road_types=_road_type_list, save_gpkg=True)
_config_data = NetworkConfigData(network=_network_section, static_path=OUTPUT_FOLDER.joinpath('static'))
_network_wrapper = OsmNetworkWrapper.with_polygon(_config_data, _polygon)
Export the network to file#
[ ]:
[_graph, _gdf] = _network_wrapper.get_network()
# Export the graph
_exporter = MultiGraphNetworkExporter(basename='base_graph', export_types=['gpkg', 'pickle'])
_exporter.export(export_path=Path(OUTPUT_FOLDER).joinpath('static', 'output_graph'), export_data=_graph)
# Export the network
_exporter = GeoDataFrameNetworkExporter(basename='base_network', export_types=['gpkg', 'pickle'])
_exporter.export(export_path=Path(OUTPUT_FOLDER).joinpath('static', 'output_graph'), export_data=_gdf)
Re-projecting#
It might be possible that we require to pre-process the hazard files due to a different projection than WGS-84.
This can be done either locally or “in the cloud”. Do not forget this step is optional and is not always required to be run.
The following snippet displays the content of the preprocessing python script in user_question_1\convert_floodmaps_to_wgs84.py
[ ]:
# user_question_1\convert_floodmaps_to_wgs84.py
import sys
import gc
import xarray as xr
from pathlib import Path
# Input and output folder paths
_input_folder = Path(sys.argv[0])
_output_folder = Path(sys.argv[1])
# Iterate over each input GeoTIFF file
for _input_tiff in list(_input_folder.glob("*.tif")):
_output_tiff = _output_folder.joinpath(_input_tiff.name)
_input_dataarray = xr.open_dataarray(_input_tiff)
_input_as_wgs84 = _input_dataarray.raster.reproject(dst_crs=4326)
_input_as_wgs84.raster.to_raster(_output_tiff, driver="GTiff", compress="lzw")
# Clean up
del _input_dataarray, _input_as_wgs84
gc.collect()
Creating the buckets#
We create buckets online with each containing our network configuration, network extent and only one hazard file. This way we spread the computation of each hazard overlay for enhanced performance.
Preparing the floodmaps#
[ ]:
# This script is the last section of `hazard_overlay_preprocessing.ipynb`
# Reproject and save the floodmaps
_output_folder = OUTPUT_FOLDER.joinpath(OUTPUT_FLOODMAP_FOLDER)
if not _output_folder.exists():
_output_folder.mkdir(parents=True)
def check_projection(file) -> bool:
_input_ds = gdal.Open(str(file))
_source_proj = _input_ds.GetProjection()
_srs = osr.SpatialReference(wkt=_source_proj)
if not _srs.IsProjected:
return False
return _srs.GetAttrValue('geogcs') == 'WGS 84'
for _region in [f for f in INPUT_FOLDER.iterdir() if f.is_dir()]:
_models_dir = _region.joinpath(INPUT_FLOODMAP_FOLDER)
for _floodmap in _models_dir.iterdir():
_output_file = _output_folder.joinpath(_floodmap.name)
if not check_projection(_floodmap):
raise ValueError(f'Floodmap {_floodmap} is not in the right projection')
copyfile(_floodmap, _output_file)
UQ1 Processing#
Running the hazard overlay#
In each bucket, we do a simple ra2ce run by modifying the NetworkConfigData.hazard.hazard_map
property so that instead of having ‘n’ defined hazard files, contains only the name of the available hazard file for its executing “bucket”.
The script to be run (user_question_1\hazard_overlay_cloud_run.py
) is as follows:
[ ]:
# user_question_1\hazard_overlay_cloud_run.py
from pathlib import Path
from ra2ce.ra2ce_handler import Ra2ceHandler
"""
This script runs a network WITHOUT an analysis,
as we are only interested to retrieve the HAZARD overlay.
"""
# Create one network configuration per provided hazard.
# We assume the whole input directory will be mounted in `/data`
_root_dir = Path("/data")
assert _root_dir.exists()
_network_file = _root_dir.joinpath("network.ini")
assert _network_file.exists()
_tif_data_directory = Path("/input")
assert _tif_data_directory.exists()
# Run analysis
_handler = Ra2ceHandler(_network_file, analysis=None)
_handler.input_config.network_config.config_data.hazard.hazard_map = [
list(_tif_data_directory.glob("*.tif"))[0]
]
# Try to get only RELEVANT info messages.
import warnings
warnings.filterwarnings("ignore")
_handler.configure()
_handler.run_analysis()
UQ1 Post-processing#
Unifying the outputs#
Because we ran ra2ce with one container per hazard file, it means we have our output spread over different containers. We then unify all the available outputs and export its content into both a .json
(geojson) and a .feather
file.
This script can be found as user_question_1\post_processing.py
:
[ ]:
# user_question_1\post_processing.py
from pathlib import Path
import pandas as pd
import geopandas as gpd
# set the required parameters
cloud_output_folder = Path('/data')
event_names = [folder.stem for folder in cloud_output_folder.iterdir() if folder.is_dir()]
# save as a .py script
aggregate_wl = "max" # this we should get from network_config or analysis_config
aggregate_wls = {
"max": "ma",
"mean": "me",
"min": "mi"
}
aggregate_wl_column = aggregate_wls[aggregate_wl]
event_wl_column = "EV1_" + aggregate_wl_column
event_fraction_column = "EV1_fr"
fid_column = "rfid"
for i, event_name in enumerate(event_names):
overlay_output_path = cloud_output_folder / event_name / "static" / "output_graph" / "base_graph_hazard_edges.gpkg"
overlay_output_gdf = gpd.read_file(overlay_output_path)
# Define the mapping of EV1_ column names to event_name
column_mapping = {event_wl_column: f"{event_name}_" + aggregate_wl_column, event_fraction_column: f"{event_name}_fr"}
overlay_output_gdf = overlay_output_gdf.rename(columns=column_mapping)
if i == 0:
# create the base gdf that aggregate all results
result_gdf = overlay_output_gdf
else:
filtered_overlay_output_gdf = overlay_output_gdf[[fid_column, f"{event_name}_" + aggregate_wl_column, f"{event_name}_fr"]]
result_gdf = pd.merge(
result_gdf,
filtered_overlay_output_gdf,
left_on=fid_column,
right_on=fid_column,
)
gdf = result_gdf
gdf.to_file('/output/result_gdf.geojson', driver="GeoJSON")
gdf.to_feather('/output/result_gdf.feather')
Expected result#
During the hackathon the above steps where run through the cloud infrastructure, delivering us a geojson file (user_question_1\result_gdf.json
) which we summarized, due to its large size, in the following snippet:
[ ]:
{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "u": 2312756550, "v": 9435564285, "key": 0, "ref": "N324", "highway": "secondary", "oneway": false, "reversed": [ false, true ], "length": 32701.151, "rfid_c": [ 32, 34, 36, 38, 40, 44, 46, 48, 54, 56, 1092, 68, 70, 74, 76, 78, 80, 84, 90, 92, 94, 96, 98, 100, 104, 106, 108, 110, 112, 114, 120, 122, 124, 1661, 126, 1663, 128, 1665, 1666, 130, 1668, 132, 134, 1671, 136, 138, 140, 141, 144, 146, 148, 150, 152, 154, 156, 158, 1183, 160, 1185, 162, 1187, 164, 1189, 166, 168, 170, 172, 174, 176, 178, 180, 182, 3255, 184, 3257, 186, 3259, 3260, 189, 3262, 188, 3264, 192, 3266, 194, 3268, 196, 3270, 3271, 200, 198, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 1767, 1769, 1805, 1807, 1809, 1811, 1875, 1878, 1880, 1882, 1884, 1885, 1888, 1890, 1892, 1894, 1896, 1898, 1900, 1902, 1904, 1906, 1908, 1910, 1912, 1914, 1916, 1918, 1920, 1922, 1924, 1926, 1928, 1930, 1932, 1934, 1936, 981 ], "rfid": 10, "bridge": "yes", "avgspeed": 59.0, "time": 1995.0, "TC_0064_ma": 0.0, "TC_0064_fr": 0.0, "junction": "nan", "lanes": "nan", "name": "nan", "maxspeed": "nan", "access": "nan", "width": "nan", "tunnel": "nan", "osmid_original": [ 1021406339, 622806373, 622806374, 622806375, 622806376, 222294054, 617604301, 219115766, 219115775 ], "TC_0098_ma": 0.0, "TC_0098_fr": 0.0, "TC_0120_ma": 0.0, "TC_0120_fr": 0.0, "TC_0142_ma": 0.360931396484375, "TC_0142_fr": 0.0094489253302677528, "TC_0145_ma": 0.0, "TC_0145_fr": 0.0, "TC_0147_ma": 0.2004547119140625, "TC_0147_fr": 0.0017436712422498476, "TC_0166_ma": 0.0, "TC_0166_fr": 0.0, "TC_0184_ma": 0.0, "TC_0184_fr": 0.0, "TC_0209_ma": 0.0, "TC_0209_fr": 0.0, "TC_0228_ma": 0.0, "TC_0228_fr": 0.0, "TC_0229_ma": 0.0, "TC_0229_fr": 0.0, "TC_0240_ma": 0.0, "TC_0240_fr": 0.0, "TC_0329_ma": 0.0, "TC_0329_fr": 0.0, "TC_0333_ma": 0.0, "TC_0333_fr": 0.0, "TC_0356_ma": 0.0, "TC_0356_fr": 0.0, "TC_0379_ma": 0.51285552978515625, "TC_0379_fr": 0.023181703594162224, "TC_0388_ma": 0.0, "TC_0388_fr": 0.0, "TC_0400_ma": 0.0, "TC_0400_fr": 0.0, "TC_0420_ma": 0.0, "TC_0420_fr": 0.0, "TC_0434_ma": 0.0, "TC_0434_fr": 0.0, "TC_0438_ma": 0.0, "TC_0438_fr": 0.0, "TC_0444_ma": 0.0, "TC_0444_fr": 0.0, "TC_0451_ma": 0.0, "TC_0451_fr": 0.0, "TC_0467_ma": 0.0, "TC_0467_fr": 0.0, "TC_0505_ma": 0.0, "TC_0505_fr": 0.0, "TC_0527_ma": 0, "TC_0527_fr": 0.0, "TC_0535_ma": 0.0, "TC_0535_fr": 0.0, "TC_0541_ma": 0.0, "TC_0541_fr": 0.0, "TC_0554_ma": 0.0, "TC_0554_fr": 0.0, "TC_0558_ma": 0.0, "TC_0558_fr": 0.0, "TC_0587_ma": 0.0, "TC_0587_fr": 0.0, "TC_0625_ma": 0.0, "TC_0625_fr": 0.0, "TC_0631_ma": 0.0, "TC_0631_fr": 0.0, "TC_0637_ma": 0.16949844360351562, "TC_0637_fr": 0.0046076563923134204, "TC_0642_ma": 0.0, "TC_0642_fr": 0.0, "TC_0653_ma": 0.0, "TC_0653_fr": 0.0, "TC_0673_ma": 0.25518035888671875, "TC_0673_fr": 0.0066475256222551056, "TC_0689_ma": 0.0, "TC_0689_fr": 0.0, "TC_0729_ma": 0.0, "TC_0729_fr": 0.0, "TC_0731_ma": 0.0, "TC_0731_fr": 0.0, "TC_0750_ma": 0.0, "TC_0750_fr": 0.0, "TC_0803_ma": 0.0, "TC_0803_fr": 0.0, "TC_0814_ma": 0, "TC_0814_fr": 0.0, "TC_0815_ma": 0.16817092895507812, "TC_0815_fr": 0.0046076563923134204, "TC_0821_ma": 0.0, "TC_0821_fr": 0.0, "TC_0862_ma": 0.0, "TC_0862_fr": 0.0, "TC_0866_ma": 0.26370620727539062, "TC_0866_fr": 0.0054298714754633859, "TC_0875_ma": 0.0, "TC_0875_fr": 0.0, "TC_0920_ma": 0.0, "TC_0920_fr": 0.0 }, "geometry": { "type": "LineString", "coordinates": [ [ 39.137194, -16.832636 ], [ 39.1371437, -16.8326518 ], [ 39.1371132, -16.8326794 ], [ 39.1369741, -16.8328745 ], [ 39.1366267, -16.8334123 ], [ 39.136506, -16.8336999 ], [ 39.1364311, -16.8338932 ], [ 39.1361949, -16.8348038 ], [ 39.1357362, -16.8364776 ], [ 39.1355056, -16.8368987 ], [ 39.1353023, -16.8370004 ], [ 39.1350738, -16.8369684 ], [ 39.1345319, -16.8370039 ], [ 39.1337648, -16.8368524 ], [ 39.1334268, -16.8367523 ], [ 39.1330829, -16.8367434 ], [ 39.1327085, -16.8368687 ], [ 39.1310482, -16.8374011 ], [ 39.1274561, -16.8386137 ], [ 39.1208716, -16.8407742 ], [ 39.1182101, -16.8416181 ], [ 39.1152827, -16.8425892 ], [ 39.1115917, -16.8437746 ], [ 39.1096912, -16.8444536 ], [ 39.1022113, -16.8469119 ], [ 39.0944196, -16.8494248 ], [ 39.0943056, -16.8494689 ], [ 39.0941483, -16.8495183 ], [ 39.0939665, -16.8495819 ], [ 39.0937766, -16.8495923 ], [ 39.0935568, -16.8495637 ], [ 39.0932692, -16.8493897 ], [ 39.0902279, -16.847071 ], [ 39.0886028, -16.8459545 ], [ 39.087968, -16.8456507 ], [ 39.0855569, -16.8450996 ], [ 39.0845616, -16.8449492 ], [ 39.0838926, -16.8449646 ], [ 39.0834292, -16.8450533 ], [ 39.0824097, -16.8453503 ], [ 39.0788635, -16.8465999 ], [ 39.0776802, -16.8470814 ], [ 39.0759981, -16.8476734 ], [ 39.0745005, -16.8482498 ], [ 39.0734424, -16.8485277 ], [ 39.0689341, -16.8492033 ], [ 39.0649995, -16.8499947 ], [ 39.0628454, -16.8503453 ], [ 39.0610358, -16.8506179 ], [ 39.0606126, -16.8507383 ], [ 39.0554768, -16.8535026 ], [ 39.0525413, -16.8551644 ], [ 39.0500941, -16.8565197 ], [ 39.047061, -16.8582126 ], [ 39.046247, -16.8587215 ], [ 39.0354329, -16.8686812 ], [ 39.0339373, -16.8701001 ], [ 39.0320823, -16.8717448 ], [ 39.0314904, -16.872137 ], [ 39.0311382, -16.8723004 ], [ 39.0305902, -16.8724172 ], [ 39.0300749, -16.8724359 ], [ 39.0296894, -16.8723315 ], [ 39.028943, -16.8719533 ], [ 39.0267135, -16.8708386 ], [ 39.025173, -16.8697148 ], [ 39.0225867, -16.8667573 ], [ 39.0200935, -16.863839 ], [ 39.0178661, -16.8611622 ], [ 39.0164661, -16.8597913 ], [ 39.0148383, -16.8584645 ], [ 39.0137281, -16.8574891 ], [ 39.0126177, -16.856607 ], [ 39.0112606, -16.8552943 ], [ 39.0102452, -16.8542297 ], [ 39.0088561, -16.8524017 ], [ 39.0080964, -16.8512867 ], [ 39.0056434, -16.8485431 ], [ 39.0047725, -16.8476679 ], [ 38.9970797, -16.8423751 ], [ 38.9952291, -16.8411456 ], [ 38.9915802, -16.8389086 ], [ 38.9874645, -16.8359321 ], [ 38.9837594, -16.8331127 ], [ 38.9797207, -16.8295614 ], [ 38.9760362, -16.8261918 ], [ 38.9749893, -16.8253027 ], [ 38.9747789, -16.8251602 ], [ 38.9713304, -16.8239175 ], [ 38.9692777, -16.8229252 ], [ 38.9650132, -16.8205871 ], [ 38.9619701, -16.8183815 ], [ 38.961108, -16.8176299 ], [ 38.9581572, -16.8145155 ], [ 38.9543546, -16.81034 ], [ 38.9475448, -16.8035362 ], [ 38.9454228, -16.8017265 ], [ 38.9417331, -16.7983839 ], [ 38.9414238, -16.7981761 ], [ 38.9411688, -16.7980696 ], [ 38.9370629, -16.7966188 ], [ 38.9342252, -16.7954016 ], [ 38.9322771, -16.7946545 ], [ 38.9306564, -16.7941008 ], [ 38.9282553, -16.792988 ], [ 38.9273822, -16.7925439 ], [ 38.9257778, -16.79152 ], [ 38.9235896, -16.790031 ], [ 38.9217342, -16.7889287 ], [ 38.9212267, -16.7887249 ], [ 38.9207083, -16.7885995 ], [ 38.919395, -16.7884001 ], [ 38.9159268, -16.7879089 ], [ 38.9138784, -16.7876128 ], [ 38.9127607, -16.7873219 ], [ 38.9123591, -16.7871686 ], [ 38.9118002, -16.7869244 ], [ 38.9111979, -16.786649 ], [ 38.9103129, -16.7861005 ], [ 38.9097174, -16.785755 ], [ 38.9083823, -16.7852157 ], [ 38.907728, -16.7850387 ], [ 38.907199, -16.7849816 ], [ 38.9057204, -16.7849712 ], [ 38.9049688, -16.7850751 ], [ 38.9035499, -16.7853452 ], [ 38.9018461, -16.785714 ], [ 38.9010051, -16.7858959 ], [ 38.9002726, -16.7862024 ], [ 38.8989676, -16.7868206 ], [ 38.8981347, -16.7871167 ], [ 38.8967348, -16.7875712 ], [ 38.8930587, -16.7888231 ], [ 38.8926951, -16.7888725 ], [ 38.8922287, -16.7888543 ], [ 38.8896919, -16.7886747 ], [ 38.886702, -16.7884608 ], [ 38.8853816, -16.7884456 ], [ 38.880539, -16.7886388 ], [ 38.8796807, -16.7886803 ] ] } },
{ "type": "Feature", "properties": { "u": 2312756550, "v": 2283157832, "key": 0, "ref": "N324", "highway": "secondary", "oneway": false, "reversed": "False", "length": 35108.418, "rfid_c": [ 3, 5, 7, 11, 13, 15, 19, 21, 24, 25, 27, 29, 41, 49, 51, 57, 59, 62, 63, 65, 71, 81, 85, 87, 101, 9836, 115, 117, 230, 1672, 1674, 1676, 1678, 1680, 1682, 1684, 1686, 1688, 1178, 1690, 1180, 1692, 1694, 1696, 1698, 1700, 1702, 1704, 1706, 1708, 1710, 1712, 1714, 1716, 1718, 1720, 1722, 1724, 1726, 1728, 1730, 1732, 1734, 1736, 1738, 9420, 1740, 9422, 1742, 9424, 1744, 9426, 1746, 9428, 1748, 9430, 1750, 9432, 1752, 9434, 1754, 9436, 1756, 9438, 1758, 9440, 1760, 9442, 1762, 9444, 1764, 9446, 10982, 9448, 10984, 10986, 9450, 10988, 9452, 10990, 9454, 10992, 9456, 10994, 9458, 10996, 9460, 10998, 9462, 11000, 9464, 11002, 9466, 9468, 11004, 11006, 9470, 11008, 9472, 11010, 9474, 11012, 9476, 11014, 9478, 11016, 9480, 11018, 9482, 11020, 9484, 11022, 9486, 11024, 9488, 11026, 9490, 9492, 9494, 9500, 9502, 9504, 9510, 1843, 1845, 9526, 1847, 9528, 1849, 1851, 9532, 1853, 9535, 1855, 1857, 9538, 1859, 9540, 1861, 9542, 1863, 9545, 1865, 9547, 1867, 9549, 1869, 9551, 1871, 9553, 1873, 9555, 9557, 9559, 9561, 9563, 9565, 9567, 9571, 9573, 9579, 9581, 9583, 9585, 9591, 11128, 9593, 11130, 9595, 9597, 9599, 9603, 9609, 1937, 1939, 9621, 1941, 1943, 9625, 1945, 9629, 9631, 9634, 9635, 9637, 9639, 9645, 9649, 9651, 9653, 9655, 982, 984, 986, 988, 990, 992, 994, 996 ], "rfid": 63, "bridge": "yes", "avgspeed": 59.0, "time": 2142.0, "TC_0064_ma": 0.0, "TC_0064_fr": 0.0, "junction": "nan", "lanes": "nan", "name": "nan", "maxspeed": "nan", "access": "nan", "width": "nan", "tunnel": "nan", "osmid_original": [ 622773825, 622773827, 222294053, 222294054, 219115757, 219115763, 219115770, 219115772, 219115773 ], "TC_0098_ma": 0.0, "TC_0098_fr": 0.0, "TC_0120_ma": 0.0, "TC_0120_fr": 0.0, "TC_0142_ma": 0.23963165283203125, "TC_0142_fr": 0.0069957230103332236, "TC_0145_ma": 0.0, "TC_0145_fr": 0.0, "TC_0147_ma": 0.11718368530273438, "TC_0147_fr": 0.00087339052119900717, "TC_0166_ma": 0.0, "TC_0166_fr": 0.0, "TC_0184_ma": 0.0, "TC_0184_fr": 0.0, "TC_0209_ma": 0.0, "TC_0209_fr": 0.0, "TC_0228_ma": 0.0, "TC_0228_fr": 0.0, "TC_0229_ma": 0.0, "TC_0229_fr": 0.0, "TC_0240_ma": 0.0, "TC_0240_fr": 0.0, "TC_0329_ma": 0.0, "TC_0329_fr": 0.0, "TC_0333_ma": 0.0, "TC_0333_fr": 0.0, "TC_0356_ma": 0.0, "TC_0356_fr": 0.0, "TC_0379_ma": 0.88681221008300781, "TC_0379_fr": 0.021559251267715285, "TC_0388_ma": 0.0, "TC_0388_fr": 0.0, "TC_0400_ma": 0.0, "TC_0400_fr": 0.0, "TC_0420_ma": 0.0, "TC_0420_fr": 0.0, "TC_0434_ma": 0.0, "TC_0434_fr": 0.0, "TC_0438_ma": 0.0, "TC_0438_fr": 0.0, "TC_0444_ma": 0.0, "TC_0444_fr": 0.0, "TC_0451_ma": 0.0, "TC_0451_fr": 0.0, "TC_0467_ma": 0.0, "TC_0467_fr": 0.0, "TC_0505_ma": 0.0, "TC_0505_fr": 0.0, "TC_0527_ma": 0, "TC_0527_fr": 0.0, "TC_0535_ma": 0.0, "TC_0535_fr": 0.0, "TC_0541_ma": 0.0, "TC_0541_fr": 0.0, "TC_0554_ma": 0.0, "TC_0554_fr": 0.0, "TC_0558_ma": 0.0, "TC_0558_fr": 0.0, "TC_0587_ma": 0.0, "TC_0587_fr": 0.0, "TC_0625_ma": 0.0, "TC_0625_fr": 0.0, "TC_0631_ma": 0.0, "TC_0631_fr": 0.0, "TC_0637_ma": 0.12184333801269531, "TC_0637_fr": 0.0040787747774758479, "TC_0642_ma": 0.0, "TC_0642_fr": 0.0, "TC_0653_ma": 0.0, "TC_0653_fr": 0.0, "TC_0673_ma": 0.19067573547363281, "TC_0673_fr": 0.0058483074494670257, "TC_0689_ma": 0.0, "TC_0689_fr": 0.0, "TC_0729_ma": 0.0, "TC_0729_fr": 0.0, "TC_0731_ma": 0.0, "TC_0731_fr": 0.0, "TC_0750_ma": 0.0, "TC_0750_fr": 0.0, "TC_0803_ma": 0.0, "TC_0803_fr": 0.0, "TC_0814_ma": 0, "TC_0814_fr": 0.0, "TC_0815_ma": 0.11027336120605469, "TC_0815_fr": 0.0012757311553735769, "TC_0821_ma": 0.0, "TC_0821_fr": 0.0, "TC_0862_ma": 0.0, "TC_0862_fr": 0.0, "TC_0866_ma": 0.11719322204589844, "TC_0866_fr": 0.0049521652986748554, "TC_0875_ma": 0.0, "TC_0875_fr": 0.0, "TC_0920_ma": 0.0, "TC_0920_fr": 0.0 }, "geometry": { "type": "LineString", "coordinates": [ [ 38.5808761, -16.8126744 ], [ 38.5817182, -16.8128379 ], [ 38.5824952, -16.8128752 ], [ 38.5841725, -16.8128918 ], [ 38.5857502, -16.8129104 ], [ 38.5865055, -16.8128462 ], [ 38.5900851, -16.8123842 ], [ 38.5933228, -16.8119409 ], [ 38.5949719, -16.8117586 ], [ 38.595645, -16.811626 ], [ 38.5968937, -16.8113069 ], [ 38.5991618, -16.8106523 ], [ 38.5998024, -16.8105114 ], [ 38.6015836, -16.8102504 ], [ 38.6020684, -16.8102255 ], [ 38.6025207, -16.8103312 ], [ 38.6029514, -16.8105176 ], [ 38.6032717, -16.8107331 ], [ 38.6037453, -16.8111861 ], [ 38.6045616, -16.8118787 ], [ 38.6050983, -16.8122247 ], [ 38.6056869, -16.8125189 ], [ 38.6076542, -16.8134532 ], [ 38.6084095, -16.8136998 ], [ 38.6089701, -16.8138344 ], [ 38.6096669, -16.8139712 ], [ 38.6103703, -16.8140147 ], [ 38.6110542, -16.8139836 ], [ 38.6129192, -16.8139009 ], [ 38.613898, -16.8139836 ], [ 38.6144499, -16.8141307 ], [ 38.6150723, -16.8144033 ], [ 38.6177348, -16.8159768 ], [ 38.6188129, -16.8166561 ], [ 38.6192912, -16.8170642 ], [ 38.6197915, -16.817554 ], [ 38.6201272, -16.8178827 ], [ 38.6207754, -16.8184995 ], [ 38.6212518, -16.8189457 ], [ 38.6217801, -16.8193078 ], [ 38.6244247, -16.8205839 ], [ 38.6274481, -16.8219139 ], [ 38.627749, -16.8219491 ], [ 38.6281645, -16.8218952 ], [ 38.6291254, -16.8215865 ], [ 38.6296145, -16.8213048 ], [ 38.6329474, -16.8192249 ], [ 38.6361158, -16.8174474 ], [ 38.6372066, -16.8167555 ], [ 38.6381892, -16.8160263 ], [ 38.6385571, -16.8158647 ], [ 38.6421448, -16.8144328 ], [ 38.6435301, -16.8140745 ], [ 38.6471264, -16.8136867 ], [ 38.6474891, -16.8136091 ], [ 38.6502017, -16.8127891 ], [ 38.6512744, -16.8124197 ], [ 38.6538212, -16.8111232 ], [ 38.6544077, -16.8109274 ], [ 38.6569081, -16.8108055 ], [ 38.6584169, -16.8106356 ], [ 38.6590009, -16.8105278 ], [ 38.6616644, -16.8100618 ], [ 38.6622293, -16.8099023 ], [ 38.6632746, -16.8094527 ], [ 38.6657137, -16.80816 ], [ 38.6676636, -16.8068216 ], [ 38.6688366, -16.8061566 ], [ 38.6709359, -16.8048679 ], [ 38.6719293, -16.8042402 ], [ 38.672215, -16.8040806 ], [ 38.6733988, -16.80366 ], [ 38.6742775, -16.8034591 ], [ 38.6753466, -16.8032312 ], [ 38.6759547, -16.8031607 ], [ 38.677777, -16.8029971 ], [ 38.679372, -16.8028645 ], [ 38.6798503, -16.8027961 ], [ 38.6807074, -16.8025537 ], [ 38.6819691, -16.8021787 ], [ 38.6823673, -16.8021062 ], [ 38.6848454, -16.8019218 ], [ 38.685328, -16.8019404 ], [ 38.6864988, -16.8021497 ], [ 38.6871719, -16.8023797 ], [ 38.6912276, -16.8041179 ], [ 38.6917947, -16.8042733 ], [ 38.6929265, -16.8045364 ], [ 38.6937857, -16.8046524 ], [ 38.6945735, -16.8047084 ], [ 38.6956491, -16.8046794 ], [ 38.6989128, -16.8044743 ], [ 38.6995577, -16.8045074 ], [ 38.7015607, -16.8047735 ], [ 38.7025854, -16.8050171 ], [ 38.703159, -16.8052222 ], [ 38.7051868, -16.806256 ], [ 38.7064998, -16.8071007 ], [ 38.7077732, -16.8080241 ], [ 38.7083482, -16.808279 ], [ 38.7120366, -16.8094817 ], [ 38.7125885, -16.8097076 ], [ 38.7141359, -16.8104741 ], [ 38.717235, -16.8125893 ], [ 38.7178259, -16.8129167 ], [ 38.7183712, -16.8131404 ], [ 38.7187954, -16.8132709 ], [ 38.7192824, -16.8133745 ], [ 38.7199619, -16.8134077 ], [ 38.7204294, -16.8133621 ], [ 38.7257923, -16.8121108 ], [ 38.7303991, -16.8111074 ], [ 38.7316403, -16.8108665 ], [ 38.7318105, -16.8108328 ], [ 38.7326309, -16.8106394 ], [ 38.7360512, -16.8099197 ], [ 38.7388149, -16.8093492 ], [ 38.7433945, -16.808235 ], [ 38.7458606, -16.8076325 ], [ 38.7479388, -16.8070715 ], [ 38.7501038, -16.8064092 ], [ 38.7529656, -16.8055187 ], [ 38.7544295, -16.8050698 ], [ 38.7558239, -16.8046246 ], [ 38.7616694, -16.8026719 ], [ 38.7648898, -16.8015785 ], [ 38.7685334, -16.8002539 ], [ 38.7713197, -16.7993059 ], [ 38.7804653, -16.7958139 ], [ 38.7837399, -16.794449 ], [ 38.7859076, -16.7935997 ], [ 38.7891714, -16.792166 ], [ 38.7923945, -16.7905608 ], [ 38.7989817, -16.7872102 ], [ 38.8000316, -16.7865167 ], [ 38.8026009, -16.7845452 ], [ 38.804112, -16.7833426 ], [ 38.8043345, -16.7832049 ], [ 38.8048391, -16.7829815 ], [ 38.8096086, -16.7811062 ], [ 38.8119857, -16.7800968 ], [ 38.8158649, -16.778545 ], [ 38.8202152, -16.7767034 ], [ 38.8212095, -16.7762981 ], [ 38.8213547, -16.7761877 ], [ 38.8213832, -16.7760618 ], [ 38.821375, -16.7759643 ], [ 38.8212204, -16.7754137 ], [ 38.8208989, -16.7743655 ], [ 38.8208433, -16.7741058 ], [ 38.8208284, -16.7738187 ], [ 38.8208948, -16.7734096 ], [ 38.8211797, -16.7724238 ], [ 38.8215025, -16.7714744 ], [ 38.821687, -16.7711244 ], [ 38.821862, -16.7708692 ], [ 38.8220709, -16.7707159 ], [ 38.8224128, -16.7704613 ], [ 38.8227709, -16.7702626 ], [ 38.823011, -16.7700782 ], [ 38.823205, -16.7699353 ], [ 38.8233976, -16.7698743 ], [ 38.823829, -16.7698535 ], [ 38.8242766, -16.7698483 ], [ 38.824472, -16.7698717 ], [ 38.8245723, -16.7699249 ], [ 38.8247107, -16.7700951 ], [ 38.8250471, -16.770773 ], [ 38.8254569, -16.7713794 ], [ 38.8256478, -16.7715985 ], [ 38.8258261, -16.7719744 ], [ 38.826106, -16.7724773 ], [ 38.8266166, -16.7733265 ], [ 38.8273301, -16.7744019 ], [ 38.82771, -16.7748149 ], [ 38.8285646, -16.7752877 ], [ 38.8292591, -16.775589 ], [ 38.8301083, -16.775854 ], [ 38.8309574, -16.7761215 ], [ 38.831983, -16.7765579 ], [ 38.8339174, -16.7777112 ], [ 38.8356049, -16.778719 ], [ 38.8366412, -16.7792645 ], [ 38.8373331, -16.7795451 ], [ 38.8381334, -16.7797555 ], [ 38.8387357, -16.7798516 ], [ 38.8405154, -16.7800853 ], [ 38.8432258, -16.7803607 ], [ 38.8460093, -16.7806568 ], [ 38.8481363, -16.7808256 ], [ 38.8489909, -16.780862 ], [ 38.8497696, -16.7809711 ], [ 38.8529167, -16.7820594 ], [ 38.8538798, -16.7824023 ], [ 38.854578, -16.7826157 ], [ 38.8557925, -16.7830465 ], [ 38.8575397, -16.783779 ], [ 38.8598837, -16.7846491 ], [ 38.8625344, -16.7856361 ], [ 38.8643494, -16.7863011 ], [ 38.8645909, -16.7864154 ], [ 38.8647048, -16.7865193 ], [ 38.8648622, -16.7866725 ], [ 38.8650683, -16.7869244 ], [ 38.8652732, -16.7870881 ], [ 38.8653966, -16.7871296 ], [ 38.865467, -16.7871285 ], [ 38.8656942, -16.7871025 ], [ 38.8659946, -16.787042 ], [ 38.8661807, -16.7870231 ], [ 38.8663535, -16.787042 ], [ 38.8667423, -16.7871582 ], [ 38.8693115, -16.7879582 ], [ 38.8704591, -16.7883089 ], [ 38.8716257, -16.7886465 ], [ 38.8721087, -16.78874 ], [ 38.8724803, -16.7887608 ], [ 38.8753914, -16.788818 ], [ 38.8765879, -16.7887894 ], [ 38.8796807, -16.7886803 ] ] } },
{ ... },
{ "type": "Feature", "properties": { "u": 4791770241, "v": 4791770247, "key": 0, "ref": "nan", "highway": "secondary_link", "oneway": true, "reversed": "False", "length": 50.769, "rfid_c": [ 641472, 641473, 641793, 641475, 641796, 641469, 641470, 641471 ], "rfid": 6268, "bridge": "nan", "avgspeed": 59.0, "time": 3.0, "TC_0064_ma": 0.0, "TC_0064_fr": 0.0, "junction": "nan", "lanes": "nan", "name": "nan", "maxspeed": "nan", "access": "nan", "width": "nan", "tunnel": "nan", "osmid_original": "486589275", "TC_0098_ma": 0.0, "TC_0098_fr": 0.0, "TC_0120_ma": 0.0, "TC_0120_fr": 0.0, "TC_0142_ma": 0.0, "TC_0142_fr": 0.0, "TC_0145_ma": 0.0, "TC_0145_fr": 0.0, "TC_0147_ma": 0.0, "TC_0147_fr": 0.0, "TC_0166_ma": 0.0, "TC_0166_fr": 0.0, "TC_0184_ma": 0.0, "TC_0184_fr": 0.0, "TC_0209_ma": 0.0, "TC_0209_fr": 0.0, "TC_0228_ma": 0.0, "TC_0228_fr": 0.0, "TC_0229_ma": 0.0, "TC_0229_fr": 0.0, "TC_0240_ma": 0.0, "TC_0240_fr": 0.0, "TC_0329_ma": 0.0, "TC_0329_fr": 0.0, "TC_0333_ma": 0.0, "TC_0333_fr": 0.0, "TC_0356_ma": 0.0, "TC_0356_fr": 0.0, "TC_0379_ma": 0.0, "TC_0379_fr": 0.0, "TC_0388_ma": 0.0, "TC_0388_fr": 0.0, "TC_0400_ma": 0.0, "TC_0400_fr": 0.0, "TC_0420_ma": 0.0, "TC_0420_fr": 0.0, "TC_0434_ma": 0.0, "TC_0434_fr": 0.0, "TC_0438_ma": 0.0, "TC_0438_fr": 0.0, "TC_0444_ma": 0.0, "TC_0444_fr": 0.0, "TC_0451_ma": 0.0, "TC_0451_fr": 0.0, "TC_0467_ma": 0.0, "TC_0467_fr": 0.0, "TC_0505_ma": 0.0, "TC_0505_fr": 0.0, "TC_0527_ma": 0, "TC_0527_fr": 0.0, "TC_0535_ma": 0.0, "TC_0535_fr": 0.0, "TC_0541_ma": 0.0, "TC_0541_fr": 0.0, "TC_0554_ma": 0.0, "TC_0554_fr": 0.0, "TC_0558_ma": 0.0, "TC_0558_fr": 0.0, "TC_0587_ma": 0.0, "TC_0587_fr": 0.0, "TC_0625_ma": 0.0, "TC_0625_fr": 0.0, "TC_0631_ma": 0.0, "TC_0631_fr": 0.0, "TC_0637_ma": 0.0, "TC_0637_fr": 0.0, "TC_0642_ma": 0.0, "TC_0642_fr": 0.0, "TC_0653_ma": 0.0, "TC_0653_fr": 0.0, "TC_0673_ma": 0.0, "TC_0673_fr": 0.0, "TC_0689_ma": 0.0, "TC_0689_fr": 0.0, "TC_0729_ma": 0.0, "TC_0729_fr": 0.0, "TC_0731_ma": 0.0, "TC_0731_fr": 0.0, "TC_0750_ma": 0.0, "TC_0750_fr": 0.0, "TC_0803_ma": 0.0, "TC_0803_fr": 0.0, "TC_0814_ma": 0, "TC_0814_fr": 0.0, "TC_0815_ma": 0.0, "TC_0815_fr": 0.0, "TC_0821_ma": 0.0, "TC_0821_fr": 0.0, "TC_0862_ma": 0.0, "TC_0862_fr": 0.0, "TC_0866_ma": 0.0, "TC_0866_fr": 0.0, "TC_0875_ma": 0.0, "TC_0875_fr": 0.0, "TC_0920_ma": 0.0, "TC_0920_fr": 0.0 }, "geometry": { "type": "LineString", "coordinates": [ [ 32.7750115, -15.6132508 ], [ 32.7749806, -15.6131661 ], [ 32.7749761, -15.6131362 ], [ 32.7749799, -15.6131034 ], [ 32.775004, -15.6130498 ], [ 32.7750349, -15.6130117 ], [ 32.7750821, -15.6129876 ], [ 32.7751442, -15.6129826 ], [ 32.7752301, -15.6130036 ] ] } },
{ "type": "Feature", "properties": { "u": 4791770247, "v": 4791770248, "key": 0, "ref": "N301", "highway": "secondary", "oneway": true, "reversed": "False", "length": 36.976, "rfid_c": [ 641474, 639862 ], "rfid": 6267, "bridge": "nan", "avgspeed": 59.0, "time": 2.0, "TC_0064_ma": 0.0, "TC_0064_fr": 0.0, "junction": "nan", "lanes": "nan", "name": "nan", "maxspeed": "nan", "access": "nan", "width": "nan", "tunnel": "nan", "osmid_original": "171468493", "TC_0098_ma": 0.0, "TC_0098_fr": 0.0, "TC_0120_ma": 0.0, "TC_0120_fr": 0.0, "TC_0142_ma": 0.0, "TC_0142_fr": 0.0, "TC_0145_ma": 0.0, "TC_0145_fr": 0.0, "TC_0147_ma": 0.0, "TC_0147_fr": 0.0, "TC_0166_ma": 0.0, "TC_0166_fr": 0.0, "TC_0184_ma": 0.0, "TC_0184_fr": 0.0, "TC_0209_ma": 0.0, "TC_0209_fr": 0.0, "TC_0228_ma": 0.0, "TC_0228_fr": 0.0, "TC_0229_ma": 0.0, "TC_0229_fr": 0.0, "TC_0240_ma": 0.0, "TC_0240_fr": 0.0, "TC_0329_ma": 0.0, "TC_0329_fr": 0.0, "TC_0333_ma": 0.0, "TC_0333_fr": 0.0, "TC_0356_ma": 0.0, "TC_0356_fr": 0.0, "TC_0379_ma": 0.0, "TC_0379_fr": 0.0, "TC_0388_ma": 0.0, "TC_0388_fr": 0.0, "TC_0400_ma": 0.0, "TC_0400_fr": 0.0, "TC_0420_ma": 0.0, "TC_0420_fr": 0.0, "TC_0434_ma": 0.0, "TC_0434_fr": 0.0, "TC_0438_ma": 0.0, "TC_0438_fr": 0.0, "TC_0444_ma": 0.0, "TC_0444_fr": 0.0, "TC_0451_ma": 0.0, "TC_0451_fr": 0.0, "TC_0467_ma": 0.0, "TC_0467_fr": 0.0, "TC_0505_ma": 0.0, "TC_0505_fr": 0.0, "TC_0527_ma": 0, "TC_0527_fr": 0.0, "TC_0535_ma": 0.0, "TC_0535_fr": 0.0, "TC_0541_ma": 0.0, "TC_0541_fr": 0.0, "TC_0554_ma": 0.0, "TC_0554_fr": 0.0, "TC_0558_ma": 0.0, "TC_0558_fr": 0.0, "TC_0587_ma": 0.0, "TC_0587_fr": 0.0, "TC_0625_ma": 0.0, "TC_0625_fr": 0.0, "TC_0631_ma": 0.0, "TC_0631_fr": 0.0, "TC_0637_ma": 0.0, "TC_0637_fr": 0.0, "TC_0642_ma": 0.0, "TC_0642_fr": 0.0, "TC_0653_ma": 0.0, "TC_0653_fr": 0.0, "TC_0673_ma": 0.0, "TC_0673_fr": 0.0, "TC_0689_ma": 0.0, "TC_0689_fr": 0.0, "TC_0729_ma": 0.0, "TC_0729_fr": 0.0, "TC_0731_ma": 0.0, "TC_0731_fr": 0.0, "TC_0750_ma": 0.0, "TC_0750_fr": 0.0, "TC_0803_ma": 0.0, "TC_0803_fr": 0.0, "TC_0814_ma": 0, "TC_0814_fr": 0.0, "TC_0815_ma": 0.0, "TC_0815_fr": 0.0, "TC_0821_ma": 0.0, "TC_0821_fr": 0.0, "TC_0862_ma": 0.0, "TC_0862_fr": 0.0, "TC_0866_ma": 0.0, "TC_0866_fr": 0.0, "TC_0875_ma": 0.0, "TC_0875_fr": 0.0, "TC_0920_ma": 0.0, "TC_0920_fr": 0.0 }, "geometry": { "type": "LineString", "coordinates": [ [ 32.7750115, -15.6132508 ], [ 32.7748811, -15.6131478 ], [ 32.7747438, -15.6130408 ] ] } },
{ "type": "Feature", "properties": { "u": 4791770254, "v": 4791770260, "key": 0, "ref": "nan", "highway": "secondary_link", "oneway": true, "reversed": "False", "length": 41.625, "rfid_c": [ 641483, 641484, 641485, 641486, 641487, 641489, 641787, 641788 ], "rfid": 6272, "bridge": "nan", "avgspeed": 59.0, "time": 3.0, "TC_0064_ma": 0.0, "TC_0064_fr": 0.0, "junction": "nan", "lanes": "nan", "name": "nan", "maxspeed": "nan", "access": "nan", "width": "nan", "tunnel": "nan", "osmid_original": "486589277", "TC_0098_ma": 0.0, "TC_0098_fr": 0.0, "TC_0120_ma": 0.0, "TC_0120_fr": 0.0, "TC_0142_ma": 0.0, "TC_0142_fr": 0.0, "TC_0145_ma": 0.0, "TC_0145_fr": 0.0, "TC_0147_ma": 0.0, "TC_0147_fr": 0.0, "TC_0166_ma": 0.0, "TC_0166_fr": 0.0, "TC_0184_ma": 0.0, "TC_0184_fr": 0.0, "TC_0209_ma": 0.0, "TC_0209_fr": 0.0, "TC_0228_ma": 0.0, "TC_0228_fr": 0.0, "TC_0229_ma": 0.0, "TC_0229_fr": 0.0, "TC_0240_ma": 0.0, "TC_0240_fr": 0.0, "TC_0329_ma": 0.0, "TC_0329_fr": 0.0, "TC_0333_ma": 0.0, "TC_0333_fr": 0.0, "TC_0356_ma": 0.0, "TC_0356_fr": 0.0, "TC_0379_ma": 0.0, "TC_0379_fr": 0.0, "TC_0388_ma": 0.0, "TC_0388_fr": 0.0, "TC_0400_ma": 0.0, "TC_0400_fr": 0.0, "TC_0420_ma": 0.0, "TC_0420_fr": 0.0, "TC_0434_ma": 0.0, "TC_0434_fr": 0.0, "TC_0438_ma": 0.0, "TC_0438_fr": 0.0, "TC_0444_ma": 0.0, "TC_0444_fr": 0.0, "TC_0451_ma": 0.0, "TC_0451_fr": 0.0, "TC_0467_ma": 0.0, "TC_0467_fr": 0.0, "TC_0505_ma": 0.0, "TC_0505_fr": 0.0, "TC_0527_ma": 0, "TC_0527_fr": 0.0, "TC_0535_ma": 0.0, "TC_0535_fr": 0.0, "TC_0541_ma": 0.0, "TC_0541_fr": 0.0, "TC_0554_ma": 0.0, "TC_0554_fr": 0.0, "TC_0558_ma": 0.0, "TC_0558_fr": 0.0, "TC_0587_ma": 0.0, "TC_0587_fr": 0.0, "TC_0625_ma": 0.0, "TC_0625_fr": 0.0, "TC_0631_ma": 0.0, "TC_0631_fr": 0.0, "TC_0637_ma": 0.0, "TC_0637_fr": 0.0, "TC_0642_ma": 0.0, "TC_0642_fr": 0.0, "TC_0653_ma": 0.0, "TC_0653_fr": 0.0, "TC_0673_ma": 0.0, "TC_0673_fr": 0.0, "TC_0689_ma": 0.0, "TC_0689_fr": 0.0, "TC_0729_ma": 0.0, "TC_0729_fr": 0.0, "TC_0731_ma": 0.0, "TC_0731_fr": 0.0, "TC_0750_ma": 0.0, "TC_0750_fr": 0.0, "TC_0803_ma": 0.0, "TC_0803_fr": 0.0, "TC_0814_ma": 0, "TC_0814_fr": 0.0, "TC_0815_ma": 0.0, "TC_0815_fr": 0.0, "TC_0821_ma": 0.0, "TC_0821_fr": 0.0, "TC_0862_ma": 0.0, "TC_0862_fr": 0.0, "TC_0866_ma": 0.0, "TC_0866_fr": 0.0, "TC_0875_ma": 0.0, "TC_0875_fr": 0.0, "TC_0920_ma": 0.0, "TC_0920_fr": 0.0 }, "geometry": { "type": "LineString", "coordinates": [ [ 32.7757113, -15.6138013 ], [ 32.7757155, -15.613735 ], [ 32.7757248, -15.6136963 ], [ 32.775747, -15.613651 ], [ 32.7757671, -15.6136232 ], [ 32.775802, -15.6135968 ], [ 32.7758445, -15.6135798 ], [ 32.7758854, -15.6135747 ], [ 32.775945, -15.6135767 ] ] } }
]}
UQ1 Results visualization#
Last, we can now manually download the results ( .json
and .feather
) and visualize them locally. We will break down here the snippets within the jupyter notebook at user_question_1\visualise_unified_cloud_results.ipynb
.
UQ1 Results - Show the base graph network#
[ ]:
import geopandas as gpd
import matplotlib.pyplot as plt
from pathlib import Path
import folium
import pandas as pd
root_dir = Path("user_question_1")
assert root_dir.exists()
path_csv = root_dir.joinpath("event_weights.csv")
file_path_result = root_dir.joinpath("result_gdf.json")
gdf = gpd.read_file(file_path_result, driver="JSON")
gdf
UQ1 Results - Import scenario names and their weights#
[ ]:
# import the scenario names and their respective weights:
scenarios_weights_df = pd.read_csv(path_csv)
number_of_scenarios = len(scenarios_weights_df)
aggregate_wl = "max" # this we should get from network_config or analysis_config
aggregate_wls = {
"max": "ma",
"mean": "me",
"min": "mi"
}
aggregate_wl_column = aggregate_wls[aggregate_wl]
columns_to_count = []
columns_to_count_fraction = []
for name in scenarios_weights_df['name'].to_list():
actual = name + f"_{aggregate_wl_column}"
actual_fraction = name + "_fr"
if actual in gdf.columns:
columns_to_count.append(actual)
columns_to_count_fraction.append(actual_fraction)
weights_dict = {}
for _, row in scenarios_weights_df.iterrows():
weights_dict[row['name'] + f"_{aggregate_wl_column}"] = row['weight']
UQ1 Results - Modify the dataframe#
[ ]:
# Parametrization
threshold = 0.5 # would be nice to make this threshold into a slider.
fraction_threshold = 0.0
color_on_probability = False
# Add a new column with the count of non-zero values across specified columns
gdf['count'] = 0
for i, row in gdf.iterrows():
row_count = 0
for hazard_depth, hazard_fraction in zip(columns_to_count, columns_to_count_fraction):
if row[hazard_fraction] > fraction_threshold:
if row[hazard_depth] > threshold:
row_count += 1
gdf.at[i, 'count'] = row_count
for index, row in gdf.iterrows():
total_weight = 0
for col in columns_to_count:
if row[col] > threshold:
# Find the corresponding weight and add to total
weight = weights_dict[col]
total_weight += weight
gdf.at[index, 'cum_pf'] = total_weight
temp = gdf[gdf['count'] > 0]
temp
UQ1 Results - Create a color map#
[ ]:
from branca.colormap import LinearColormap
# Create a Folium pop_diff_map centered around the mean of the geometry
center = [
gdf['geometry'].centroid.y.mean(),
gdf['geometry'].centroid.x.mean()
]
pop_diff_map = folium.Map(location=center, zoom_start=5, control_scale=True, tiles="cartodbpositron")
if color_on_probability:
var = 'cum_pf'
else:
var = "count"
vmin=(gdf[var]).min()
vmax=(gdf[var]).max()
# Classify values into ranges
ranges = [vmin, vmin+((vmax-vmin)/4), vmin+2*((vmax-vmin)/4), vmin+3*((vmax-vmin)/4) , vmax]
ranges=sorted(ranges)
# Create a colormap from green to green to red using the overall min and max values
colormap = LinearColormap(colors=['lightgreen', 'orange', 'darkred'],
vmin=0,
vmax=vmax
)
colormap.caption = 'Affected people-Optimal routes length difference (people x km)'
# Add target_optimal_routes_with_hazard_gdf with created Colormap to feature_group
for idx, row in gdf.iterrows():
value = row['count']
cum_pf = row['cum_pf']
# color = 'blue' if (row['count'] > 0) else 'lightgrey'
if row[var] == 0:
color = 'lightgrey'
else:
color = colormap(row[var])
# Extracting coordinates from MultiLineString
coordinates = []
if row['geometry'].geom_type == 'MultiLineString':
for line in row['geometry']:
coords = [(coord[1], coord[0]) for coord in line.coords]
coordinates.extend(coords)
else:
coordinates = [(coord[1], coord[0]) for coord in row['geometry'].coords]
# Create a popup with data
popup_content = f"Nb scenario disrupting {value}/{len(columns_to_count)}, cumulative pf: {cum_pf}"
popup = folium.Popup(popup_content, max_width=300)
folium.PolyLine(
locations=coordinates,
color=color,
weight=3,
opacity=1,
popup=popup
).add_to(pop_diff_map)
# from branca.colormap import LinearColormap
# colormap = branca.colormap.linear.YlOrRd_09.scale(0, 8500)
colormap = colormap.to_step(index=ranges)
colormap.caption = 'Number of scenarios for which link is disrupted'
colormap.add_to(pop_diff_map)
#pop_diff_map.save(root_dir / "map_figure.html")
pop_diff_map
User Question 2#
UQ2 Description#
Disclaimer!: This user question requires further work to be fully complete. Take the following sections as an initial approach.
UQ2: Where are the flood impacts most disruptive in terms of accessibility? (detour length) = multi-link redundancy .
The difference between this and UQ.1 lays mostly in the post-processing (and therefore interpretation) of the results. The information regarding handling of the input (preprocessing) and processing of the data (cloud workflow) is defined in the aforementioned chapter.
Input: tbd
Expected output: tbd
Expected post-processed results: tbd
Acceptance level: tbd
UQ2 workflow#
For this user question we will do a slight modification from the UQ.1 workflow. This file can also be found at user_question_2\hackathon_workflow.yaml
.
[ ]:
# Content of `user_question_2\hackathon_workflow.yaml`
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: ra2ce-hackathon-uq2-
spec:
entrypoint: scenario-workflow
templates:
- name: scenario-workflow
steps:
- - name: define-subdirs
template: read-members
- - name: run-scenario
template: run-scenario
arguments:
parameters:
- name: member
value: "{{item}}"
withParam: "{{steps.define-subdirs.outputs.result}}"
- - name: post-processing
template: post-processing
- name: read-members
script:
image: 798877697266.dkr.ecr.eu-west-1.amazonaws.com/boto3:latest
workingDir: /data
command: [python]
source: |
import boto3
import json
bucket = 'ra2ce-data'
prefix = 'sfincs_floodmaps_sub/'
client = boto3.client('s3')
result = client.list_objects(Bucket=bucket, Prefix=prefix, Delimiter='/')
members = []
for o in result.get('Contents'):
mem = o.get('Key').split('/')[1].split('.')[0]
if mem != "":
members.append(mem)
print(json.dumps(members))
- name: run-scenario
container:
image: containers.deltares.nl/ra2ce/ra2ce:latest
command: ["python", "/scripts/user_question_2/hazard_overlay_cloud_run_analysis.py"]
nodeSelector:
beta.kubernetes.io/instance-type: "m5.xlarge"
inputs:
parameters:
- name: member
artifacts:
- name: input
path: /input/{{inputs.parameters.member}}.tif
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: sfincs_floodmaps_sub/{{inputs.parameters.member}}.tif
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
- name: data
path: /data
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: beira_qualimane_sfincs_fm/data
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
- name: scripts
path: /scripts
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: beira_qualimane_sfincs_fm/scripts
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
outputs:
artifacts:
- name: ra2ce-output
path: /data
s3:
bucket: ra2ce-data
endpoint: s3.amazonaws.com
region: eu-west-1
key: beira_qualimane_sfincs_fm/output_q2/{{inputs.parameters.member}}/
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
- name: post-processing
container:
image: containers.deltares.nl/ra2ce/ra2ce:latest
command: ["python", "/scripts/user_question_2/post_processing.py"]
#command: [sh, "-c", "for I in $(seq 1 1000) ; do echo $I ; sleep 1s; done"]
nodeSelector:
beta.kubernetes.io/instance-type: "m5.xlarge"
inputs:
artifacts:
- name: output
path: /data
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: beira_qualimane_sfincs_fm/output_q2
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
- name: scripts
path: /scripts
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: beira_qualimane_sfincs_fm/scripts
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
outputs:
artifacts:
- name: pp_output
path: /output
s3:
endpoint: s3.amazonaws.com
bucket: ra2ce-data
key: beira_qualimane_sfincs_fm/postprocessing_output_q2
region: eu-west-1
accessKeySecret:
name: my-s3-credentials
key: accessKey
secretKeySecret:
name: my-s3-credentials
key: secretKey
archive:
none: {}
UQ2 Pre-processing#
Same as in UQ1 preprocessing
UQ2 Processing#
Yet another slight modification of the step in the preprocessing of UQ.1 that can be found at user_question_2\hazard_overlay_cloud_run_analysis.py
.
[ ]:
# user_question_2\hazard_overlay_cloud_run_analysis.py
import logging
from pathlib import Path
from ra2ce.ra2ce_handler import Ra2ceHandler
"""
This script runs a network WITHOUT an analysis,
as we are only interested to retrieve the HAZARD overlay.
"""
# Create one network configuration per provided hazard.
# We assume the whole input directory will be mounted in `/data`
_root_dir = Path("/data")
assert _root_dir.exists()
_network_file = _root_dir.joinpath("network.ini")
assert _network_file.exists()
_analysis_file = _root_dir.joinpath("analysis.ini")
assert _analysis_file.exists()
_tif_data_directory = Path("/input")
assert _tif_data_directory.exists()
# Run analysis
_handler = Ra2ceHandler(_network_file, _analysis_file)
_handler.input_config.network_config.config_data.hazard.hazard_map = [
list(_tif_data_directory.glob("*.tif"))[0]
]
# Try to get only RELEVANT info messages.
import warnings
warnings.filterwarnings("ignore")
_handler.configure()
_handler.run_analysis()
UQ2 Post-processing#
As seen in the workflow, the results are still stored in the cloud. In particular, each of the hazard file combinations with our network has been stored at a different directory.
In this user question 2, we will generate a unified overlay result and unified redundancy result. The two of them will be represented in both .geojson
and feather
formats.
Check the contents of the user_question_2\post_processing.py
file:
[ ]:
# user_question_2\post_processing.py
from pathlib import Path
import pandas as pd
import geopandas as gpd
# set the required parameters
cloud_output_folder = Path("/data")
event_names = [
folder.stem for folder in cloud_output_folder.iterdir() if folder.is_dir()
]
# save as a .py script
aggregate_wl = "max" # this we should get from network_config or analysis_config
aggregate_wls = {"max": "ma", "mean": "me", "min": "mi"}
aggregate_wl_column = aggregate_wls[aggregate_wl]
event_wl_column = "EV1_" + aggregate_wl_column
event_fraction_column = "EV1_fr"
fid_column = "rfid"
for i, event_name in enumerate(event_names):
overlay_output_path = (
cloud_output_folder
/ event_name
/ "static"
/ "output_graph"
/ "base_graph_hazard_edges.gpkg"
)
overlay_output_gdf = gpd.read_file(overlay_output_path)
output_path = (
cloud_output_folder
/ event_name
/ "output"
/ "multi_link_redundancy"
/ "example_redundancy_multi.gpkg"
)
output_gdf = gpd.read_file(output_path)
# Column mapping
column_mapping_overlay = {
event_wl_column: f"{event_name}_" + aggregate_wl_column,
event_fraction_column: f"{event_name}_fr",
}
overlay_output_gdf = overlay_output_gdf.rename(columns=column_mapping_overlay)
column_mapping = {
"diff_length": f"{event_name}_diff_length",
"connected": f"{event_name}_connected",
}
output_gdf = output_gdf.rename(columns=column_mapping)
output_gdf.fillna(0, inplace=True)
if i == 0:
# create the base gdf that aggregate all results
overlay_result_gdf = overlay_output_gdf
redundancy_result_gdf = output_gdf
else:
filtered_overlay_output_gdf = overlay_output_gdf[
[fid_column, f"{event_name}_" + aggregate_wl_column, f"{event_name}_fr"]
]
overlay_result_gdf = pd.merge(
overlay_result_gdf,
filtered_overlay_output_gdf,
left_on=fid_column,
right_on=fid_column,
)
filtered_output_gdf = output_gdf[
[fid_column, f"{event_name}_diff_length", f"{event_name}_connected"]
]
redundancy_result_gdf = pd.merge(
redundancy_result_gdf,
filtered_output_gdf,
left_on=fid_column,
right_on=fid_column,
)
# Ensure output directory exists
_output_path = Path("/output")
_output_path.mkdir()
overlay_result_gdf.to_file("/output/overlay_result.geojson", driver="GeoJSON")
overlay_result_gdf.to_feather("/output/overlay_result.feather")
redundancy_result_gdf.to_file("/output/redundancy_result.geojson", driver="GeoJSON")
redundancy_result_gdf.to_feather("/output/redundancy_result.feather")
UQ2 Results visualization#
Disclaimer!: This part is not fully validated and it might require future work.
[ ]:
import geopandas as gpd
import matplotlib.pyplot as plt
from pathlib import Path
import folium
import pandas as pd
from branca.colormap import LinearColormap
root_dir = Path("user_question_2")
path_result = root_dir.joinpath("example_redundancy_multi.gpkg")
path_csv = root_dir.joinpath("event_weights.csv")
gdf = gpd.read_file(path_result, driver="JSON")
gdf = gdf.rename(columns={"diff_length": "TC_0002_diff_length"})
gdf.fillna(0, inplace=True)
gdf.head()
UQ2 Results - import scenario names and their weights#
[ ]:
# import the scenario names and their respective weights:
scenarios_weights_df = pd.read_csv(path_csv)
number_of_scenarios = len(scenarios_weights_df)
columns_to_count = []
for name in scenarios_weights_df['name'].to_list():
actual = name + "_diff_length"
print(actual)
if actual in gdf.columns:
columns_to_count.append(actual)
weights_dict = {}
highest_weight = 0
for _, row in scenarios_weights_df.iterrows():
weights_dict[row['name']+ "_diff_length"] = row['weight']
if row['weight'] > highest_weight:
highest_weight = row['weight']
most_likely_event = row['name']+ "_diff_length"
print(scenarios_weights_df['name'].to_list())
print(columns_to_count)
print(weights_dict)
print(most_likely_event, highest_weight)
UQ2 Results - modify the dataframe#
[ ]:
# Parametrization:
result_type = "max_detour" #One of "max_detour" , "most_likely_event" , "most_likely_detour" , "expected_detour"
# Add a new column with the count of non-zero values across specified columns
gdf['total_risk'] = 0
for index, row in gdf.iterrows():
total_risk = 0
for col in columns_to_count:
weight = weights_dict[col]
risk = weight * row[col]
total_risk += risk
gdf.at[index, 'total_risk'] = total_risk
UQ2 Results - create a color map#
[ ]:
### RESULT map for total risk
# Create a Folium pop_diff_map centered around the mean of the geometry
center = [
gdf['geometry'].centroid.y.mean(),
gdf['geometry'].centroid.x.mean()
]
pop_diff_map = folium.Map(location=center, zoom_start=5, control_scale=True, tiles="cartodbpositron")
var = 'total_risk'
vmin=(gdf[var]).min()
vmax=(gdf[var]).max()
# Classify values into ranges
ranges = [vmin, vmin+((vmax-vmin)/4), vmin+2*((vmax-vmin)/4), vmin+3*((vmax-vmin)/4) , vmax]
ranges=sorted(ranges)
# Create a colormap from green to green to red using the overall min and max values
colormap = LinearColormap(colors=['lightgreen', 'orange', 'darkred'],
vmin=0,
vmax=vmax
)
# Add target_optimal_routes_with_hazard_gdf with created Colormap to feature_group
for idx, row in gdf.iterrows():
value = row[var]
# color = 'blue' if (row['count'] > 0) else 'lightgrey'
if row[var] == 0:
color = 'lightgrey'
else:
color = colormap(row[var])
# Extracting coordinates from MultiLineString
coordinates = []
if row['geometry'].geom_type == 'MultiLineString':
for line in row['geometry']:
coords = [(coord[1], coord[0]) for coord in line.coords]
coordinates.extend(coords)
else:
coordinates = [(coord[1], coord[0]) for coord in row['geometry'].coords]
# Create a popup with data
popup_content = f"total risk: {value} meters"
popup = folium.Popup(popup_content, max_width=300)
folium.PolyLine(
locations=coordinates,
color=color,
weight=3,
opacity=1,
popup=popup
).add_to(pop_diff_map)
# from branca.colormap import LinearColormap
# colormap = branca.colormap.linear.YlOrRd_09.scale(0, 8500)
colormap = colormap.to_step(index=ranges)
colormap.caption = 'Total risk (m)'
colormap.add_to(pop_diff_map)
#pop_diff_map.save(root_dir / "map_figure.html")
pop_diff_map
[ ]:
##
from branca.colormap import LinearColormap
# Create a Folium pop_diff_map centered around the mean of the geometry
center = [
gdf['geometry'].centroid.y.mean(),
gdf['geometry'].centroid.x.mean()
]
pop_diff_map = folium.Map(location=center, zoom_start=5, control_scale=True, tiles="cartodbpositron")
var = most_likely_event
vmin=(gdf[var]).min()
vmax=(gdf[var]).max()
# Classify values into ranges
ranges = [vmin, vmin+((vmax-vmin)/4), vmin+2*((vmax-vmin)/4), vmin+3*((vmax-vmin)/4) , vmax]
ranges=sorted(ranges)
# Create a colormap from green to green to red using the overall min and max values
colormap = LinearColormap(colors=['lightgreen', 'orange', 'darkred'],
vmin=0,
vmax=vmax
)
# Add target_optimal_routes_with_hazard_gdf with created Colormap to feature_group
for idx, row in gdf.iterrows():
value = row[var]
# color = 'blue' if (row['count'] > 0) else 'lightgrey'
if row[var] == 0:
color = 'lightgrey'
else:
color = colormap(row[var])
# Extracting coordinates from MultiLineString
coordinates = []
if row['geometry'].geom_type == 'MultiLineString':
for line in row['geometry']:
coords = [(coord[1], coord[0]) for coord in line.coords]
coordinates.extend(coords)
else:
coordinates = [(coord[1], coord[0]) for coord in row['geometry'].coords]
# Create a popup with data
popup_content = f"Diff length = {value} m (event {var})"
popup = folium.Popup(popup_content, max_width=300)
folium.PolyLine(
locations=coordinates,
color=color,
weight=3,
opacity=1,
popup=popup
).add_to(pop_diff_map)
# from branca.colormap import LinearColormap
# colormap = branca.colormap.linear.YlOrRd_09.scale(0, 8500)
colormap = colormap.to_step(index=ranges)
colormap.caption = 'Diff length (m)'
colormap.add_to(pop_diff_map)
#pop_diff_map.save(root_dir / "map_figure.html")
pop_diff_map