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:

ra2ce_cloud.drawio.png

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