data.frame(analysis =c("Vulnerability index"),problem =c("Results and conclussions based on aggregated data can be limited and biased"),suggestion =c("Find non-spatial data that can be added using municipality, neighbor or sector ID"))
analysis
1 Vulnerability index
problem
1 Results and conclussions based on aggregated data can be limited and biased
suggestion
1 Find non-spatial data that can be added using municipality, neighbor or sector ID
Using the dilate and erode method described in the slide 95/187 (link) could remove small islands that increase the computational costs. A use case of this technique is observed when simplifying coastlines (link)
--- Using DuckdbINSTALL spatial;LOAD spatial;----- Importing buildings & flood extent from file to duckdb---- BuildingsCREATETABLE porto_buildings ASSELECTid, st_geomfromwkb(geometry) as geomFROM'porto_buildings_overture.parquet';--- Floodig CREATETABLE flood ASSELECT*FROM st_read('flooding_porto_cleaned.geojson');---- Filtering building in flood extentCREATETABLE flood_building ASSELECT buildings.*FROM porto_buildings AS buildings, flood WHERE st_intersects(buildings.geom, flood.geom);--- Export dataCOPY flood_building TO'flood_building_v2.gpkg'WITH (FORMAT GDAL, DRIVER 'GPKG');COPY porto_buildings TO'porto_buildings.gpkg'WITH (FORMAT GDAL, DRIVER 'GPKG');
5.4 Alternative route
Show the code
CREATETABLE second_path_net ASWITH first_path AS (SELECT*FROM pgr_dijkstra('SELECT id, source, target, cost FROM porto_alegre_net_pre_component_one',7249, 7268,true))SELECT*FROM porto_alegre_net_pre_component_oneWHERE porto_alegre_net_pre_component_one.idNOTIN (select edge from first_path);SELECT*FROM pgr_dijkstra('SELECT id, source, target, cost FROM second_path_net',7249, 7268,true)-----2CREATETABLE pkt_2000 ASWITH hospital AS (SELECT h.ds_cnes, net.id, h.geomFROM hospital_rs_geoportal as hLEFTJOIN LATERAL (SELECTid, the_geomFROM porto_alegre_net_pre_component_one_vertices_pgr as netORDERBY h.geom <-> net.the_geomLIMIT1) AS net ONTRUEWHERE h.ds_cnes ='IRMANDADE DA SANTA CASA DE MISERICORDIA DE PORTO ALEGRE'),origin AS(SELECT*FROM porto_alegre_net_pre_component_one_vertices_pgr WHEREid=7268)SELECT j.path_id, j.node, j.edge, b.cost, b.the_geom FROM pgr_KSP('SELECT id, source, target, cost FROM porto_alegre_net_pre_component_one', (SELECTidFROM hospital), (SELECTidFROM origin),2000) as jleftJOIN porto_alegre_net_pre_component_one AS bON j.edge = b.id;CREATETABLE road_without_first ASSELECT*FROM porto_alegre_net_pre_component_one WHEREidNOTIN (SELECT edge FROM pkt_2000 WHERE path_id =1);-----3WITH paths AS (SELECT path_id, edge, agg_cost,SUM(agg_cost) OVER (PARTITIONBY path_id ORDERBY seq ROWSBETWEENUNBOUNDEDPRECEDINGANDCURRENTROW) AS cum_sum,SUM(agg_cost) OVER (PARTITIONBY path_id) AS total_costFROM your_table),filtered_paths AS (SELECT path_id, edge, agg_cost, cum_sum, total_costFROM pathsWHERE cum_sum >0.25* total_cost -- remove the first 25%AND cum_sum <0.75* total_cost -- remove the last 25%)SELECT path_id, edge, agg_cost FROM filtered_paths;----5WITH hospital AS (SELECT h.ds_cnes, net.id, h.geomFROM hospital_rs_geoportal as hLEFTJOIN LATERAL (SELECTid, the_geomFROM porto_alegre_net_pre_component_one_vertices_pgr as netORDERBY h.geom <-> net.the_geomLIMIT1) AS net ONTRUEWHERE h.ds_cnes ='IRMANDADE DA SANTA CASA DE MISERICORDIA DE PORTO ALEGRE'),origin AS(SELECT*FROM porto_alegre_net_pre_component_one_vertices_pgr WHEREid=7268),table_ksp AS (SELECT j.seq, j.path_id, j.path_seq, j.node, j.edge, j.agg_cost,j.cost, b.the_geom, b.target, b.source, b.idFROM pgr_KSP('SELECT id, source, target, cost FROM porto_alegre_net_pre_component_one', (SELECTidFROM hospital), (SELECTidFROM origin, extract_ksp_segmentsWHERE origin.idNOTIN (SELECTidFROM extract_ksp_segmentsWHERE path_id =1)),3) as jleftJOIN porto_alegre_net_pre_component_one AS bON j.edge = b.id)SELECT*FROM table_ksp;
This second one does work without creating two segments of networks. It just increased the costs dinamically. This is inspired by post and post
Show the code
---- Obtain the shortest path as usualCREATETABLE first_path_dijkstra ASSELECT seq, path_seq, start_vid, end_vid, node, edge, net.the_geom FROM pgr_dijkstra(' SELECT id, source, target, cost FROM porto_alegre_net_largest',9372,1084) AS pathLEFTJOIN porto_alegre_net_pre_component_one AS netON path.edge = net.id;---- detected the shortest path and then increased cost two foldCREATETABLE dijkstra_second_route ASWITH pgr_ksp_table AS (SELECT*FROM pgr_ksp(' SELECT id, source, target, cost FROM porto_alegre_net_largest',9372,1084,3,true)), ----node 9372, network = source, target)second_route AS (SELECT net.*,CASEWHEN route.node = net.sourceTHEN net.cost*2ELSE net.costENDAS cost_updatedFROM porto_alegre_net_largest AS netLEFTJOIN pgr_ksp_table AS route ON route.edge= net.id) SELECT*FROM second_route;---- Create spatial index CREATEINDEX idx_ ON dijkstra_second_route USING gist(the_geom);CREATEINDEX dijkstra_second_route_source_source ON dijkstra_second_route USING btree(source);CREATEINDEX dijkstra_second_route_source_target ON dijkstra_second_route USING btree(target);---- obtain the second shortest path, since the first-path has now higher CREATETABLE second_path_dikstra ASSELECT seq, path_seq, start_vid, end_vid, node, edge, net.the_geom FROM pgr_Dijkstra(' SELECT id, source, target, cost_updated AS cost FROM dijkstra_second_route',9372,1084) AS pathLEFTJOIN dijkstra_second_route AS net ON path.edge = net.id
Using this strategy, the following code create 3 alternative routes obtaining the final table “paths_linestring_table”.
Show the code
CREATETABLE first_path_6211 ASSELECT seq, path_seq, start_vid, end_vid, node, edge, net.the_geom,1AS pathFROM pgr_dijkstra(' SELECT id, source, target, cost FROM porto_alegre_net_largest',6211,ARRAY(SELECTidFROM hospital_rs_node_v2), directed :=TRUE) AS pathLEFTJOIN porto_alegre_net_largest AS netON path.edge = net.id;---- detected the shortest path and then increased cost two foldDROPTABLE dijkstra_second_route_6211;CREATETABLE dijkstra_second_route_6211 ASWITH pgr_doubled_dijkstra AS (SELECT*FROM pgr_dijkstra(' SELECT id, source, target, cost FROM porto_alegre_net_largest',6211,ARRAY(SELECTidFROM hospital_rs_node_v2), directed:=true)), ----node 9372, network = source, target)second_route AS (SELECT net.*,CASEWHEN route.node = net.sourceTHEN net.cost*20ELSE net.costENDAS cost_updatedFROM porto_alegre_net_largest AS netLEFTJOIN pgr_doubled_dijkstra AS route ON route.edge= net.id) SELECT*FROM second_route;---- Create spatial index CREATEINDEX idx_second_6211 ON dijkstra_second_route_6211 USING gist(the_geom);CREATEINDEX idx_second_6211_source ON dijkstra_second_route_6211 USING btree(source);CREATEINDEX idx_second_6211_target ON dijkstra_second_route_6211 USING btree(target);---- obtain the second shortest path, since the first-path has now higher DROPTABLE second_path_dikstra_6211;CREATETABLE second_path_dikstra_6211 ASSELECT seq, path_seq, start_vid, end_vid, node, edge, net.the_geom,2AS pathFROM pgr_Dijkstra(' SELECT id, source, target, cost_updated AS cost FROM dijkstra_second_route_6211',6211,ARRAY(SELECTidFROM hospital_rs_node_v2)) AS pathLEFTJOIN dijkstra_second_route_6211 AS net ON path.edge = net.id;select*from second_path_dikstra_6211;----- 3 pathSELECT*FROM dijkstra_second_route_6211; DROPTABLE dijkstra_third_route_6211;CREATETABLE dijkstra_third_route_6211 ASWITH pgr_doubled_dijkstra AS (SELECT*FROM pgr_dijkstra(' SELECT id, source, target, cost_updated AS cost FROM dijkstra_second_route_6211',6211,ARRAY(SELECTidFROM hospital_rs_node_v2), directed:=true)), ----node 9372, network = source, target)second_route AS (SELECT net.*,CASEWHEN route.node = net.sourceTHEN net.cost_updated *20ELSE net.cost_updatedENDAS cost_updated_ndFROM dijkstra_second_route_6211 AS netLEFTJOIN pgr_doubled_dijkstra AS route ON route.edge= net.id) SELECT*FROM second_route;----DROPTABLE third_path_dikstra_6211 ;CREATETABLE third_path_dikstra_6211 ASSELECT seq, path_seq, start_vid, end_vid, node, edge, net.the_geom,3AS pathFROM pgr_Dijkstra(' SELECT id, source, target, cost_updated_nd AS cost FROM dijkstra_third_route_6211',6211,ARRAY(SELECTidFROM hospital_rs_node_v2)) AS pathLEFTJOIN dijkstra_third_route_6211 AS net ON path.edge = net.id;select*from dijkstra_third_route_6211; CREATETABLE three_alternative_paths ASSELECT*FROM first_path_6211UNIONSELECT*FROM second_path_dikstra_6211UNIONSELECT*FROM third_path_dikstra_6211CREATETABLE three_alternative_paths_20 ASSELECT*FROM first_path_6211UNIONSELECT*FROM second_path_dikstra_6211UNIONSELECT*FROM third_path_dikstra_6211CREATETABLE ernesto_three_alternatives ASSELECTalternative_paths.*,hospitals.ds_cnes,hospitals.cd_cnesFROMthree_alternative_paths AS alternative_pathsJOIN hospital_rs_node_v2 AS hospitalsON hospitals.id= alternative_paths.end_vidWHERE end_vid =1743;CREATETABLE ernesto_three_alternatives_20 ASSELECTalternative_paths.*,hospitals.ds_cnes,hospitals.cd_cnesFROMthree_alternative_paths_20 AS alternative_pathsJOIN hospital_rs_node_v2 AS hospitalsON hospitals.id= alternative_paths.end_vidWHERE end_vid =1743;CREATETABLE paths_linestring_table ASWITH paths_linestring AS (SELECT start_vid, end_vid, path, st_union(the_geom) AS line_geomFROM three_alternative_paths_20GROUPBY path, start_vid, end_vid)SELECT paths_linestring.*, hospitals.ds_cnes,round(st_length(line_geom::geography)::numeric/1000,2) AS distanceFROM paths_linestringJOIN hospital_rs_node_v2 AS hospitalsON hospitals.id= paths_linestring.end_vid
This code created the table to represent these values
library(sfnetworks)net <- sf::read_sf(eisenberg_connection,"porto_alegre_net_largest") |> sfnetworks::as_sfnetwork() from <- sf::read_sf(eisenberg_connection,"points_cardiologia") |>st_as_sf()to <- sf::read_sf(eisenberg_connection,"hospital_rs_node_v2") |>st_as_sf()first_destinations <-st_network_paths(net, from =from[1,], to = to[20,])
Show the code
library(DBI)library(glue)library(RPostgres)eisenberg_connection <- DBI::dbConnect(RPostgres::Postgres(),user="docker",password ="docker",host ="localhost",dbname="gis",port =25432)## Test 2to <- sf::read_sf(eisenberg_connection,"hospital_rs_node_v2") |>st_as_sf()table_end_v2 <-glue_sql("CREATE TABLE table_end_v2 (start_vid integer, end_vid integer, path smallint, length float, cost float, the_geom geometry)")table_end_db <-dbGetQuery(conn=eisenberg_connection,table_end_v2 )isochrones_sampling_points <-st_read(eisenberg_connection, "isochrones_snapped")df_isochrone_points <- isochrones_sampling_points DBI::dbWriteTable(eisenberg_connection,"isochrones_sampling_points",isochrones_sampling_points)# we have the id of the hospital, then we nned all the points that are in the isochrone of the hospital. How do we get this?idx_hospital <-15for (idx_hospital in1:length(unique(isochrones_sampling_points$cd_cnes))){tic(glue("hospital run {idx_hospital}/{length(unique(isochrones_sampling_points$cd_cnes))}")) code_hospital<-unique(isochrones_sampling_points$cd_cnes)[idx_hospital] points_for_isochrone <-filter(isochrones_sampling_points, cd_cnes == code_hospital)alternative_routes(df_isochrone_points=points_for_isochrone)toc() }#| eval: false#| eval: false#idx <- 1tic.clear()#| eval: falselibrary(tictoc)## data= isochrones_sampling_pointsalternative_routes <-function(df_isochrone_points){for (idx in1:length(df_isochrone_points$id)) {tic(glue("run {idx}/{length(df_isochrone_points$id)}")) hospital_name <- df_isochrone_points$cd_cnes[idx] origin_id <- df_isochrone_points$id[idx] table_name_1 <-glue("first_path_point_{as.character(idx)}") table_name_2 <-glue("second_path_point_{as.character(idx)}") table_name_3 <-glue("second_route_point_{as.character(idx)}") table_name_4 <-glue("third_path_point_{as.character(idx)}") table_name_5 <-glue("third_route_point_{as.character(idx)}") table_name_6 <-glue("three_alternative_routes_point_{as.character(idx)}") table_name_7 <-glue("table_end_point_{as.character(idx)}")dbExecute(glue_sql("DROP TABLE IF EXISTS {`table_name_1`}", .con=eisenberg_connection),conn=eisenberg_connection)# Assuming you have an open PostgreSQL connection in con query_1 <-glue_sql("CREATE TABLE {`table_name_1`} ASSELECT seq, path_seq, start_vid, end_vid, net.the_geom, node, edge, 1 AS path FROM pgr_dijkstra(' SELECT id, source, target, cost FROM porto_alegre_net_largest', ARRAY(SELECT id FROM isochrones_snapped WHERE id ={origin_id}), ARRAY(SELECT id AS end_id FROM hospital_rs_node_v2 WHERE cd_cnes = {hospital_name}), directed:=TRUE) AS pathLEFT JOIN porto_alegre_net_largest AS netON path.edge = net.id", .con = eisenberg_connection)# Send the query result_q1 <-dbGetQuery(conn= eisenberg_connection, query_1)# dijkstra_second_routedbExecute(glue_sql("DROP TABLE IF EXISTS {`table_name_2`}", .con=eisenberg_connection),conn=eisenberg_connection) query_2 <-glue_sql("CREATE TABLE {`table_name_2`} ASWITH pgr_doubled_dijkstra AS ( SELECT * FROM pgr_dijkstra(' SELECT id, source, target, cost FROM porto_alegre_net_largest', ARRAY(SELECT id FROM isochrones_snapped WHERE id = {origin_id}), ARRAY(SELECT id FROM hospital_rs_node_v2 WHERE cd_cnes = {hospital_name}), directed := TRUE -- This clause should be inside the pgr_dijkstra function )), -- Corrected closing of pgr_dijkstra CTEsecond_route AS ( SELECT net.*, CASE WHEN route.node = net.source THEN net.cost * 20 ELSE net.cost END AS cost_updated FROM porto_alegre_net_largest AS net LEFT JOIN pgr_doubled_dijkstra AS route ON route.edge = net.id) SELECT * FROM second_route", .con = eisenberg_connection) result_2 <-dbGetQuery(conn= eisenberg_connection, query_2)## Calculate teh second routedbExecute(glue_sql("DROP TABLE IF EXISTS {`table_name_3`}", .con=eisenberg_connection),conn=eisenberg_connection) query_3 <-glue_sql("CREATE TABLE {`table_name_3`} ASSELECT seq, path_seq, start_vid, end_vid, node, edge, net.the_geom, 2 AS pathFROM pgr_dijkstra(' SELECT id, source, target, cost_updated AS cost FROM {`table_name_2`}', ARRAY(SELECT id FROM isochrones_snapped WHERE id = {origin_id}), ARRAY(SELECT id FROM hospital_rs_node_v2 WHERE cd_cnes = {hospital_name}), directed:=TRUE ) AS pathLEFT JOIN {`table_name_2`} AS net ON path.edge = net.id;", .con = eisenberg_connection)# Run the CREATE TABLE querydbExecute(conn = eisenberg_connection, query_3) select_query <-glue_sql("SELECT * FROM {`table_name_3`} ;",.con=eisenberg_connection) # Fetch the data result_3 <-dbGetQuery(conn = eisenberg_connection, select_query)dbExecute(glue_sql("DROP TABLE IF EXISTS {`table_name_4`}", .con=eisenberg_connection),conn=eisenberg_connection)# Third route query_4 <-glue_sql("CREATE TABLE {`table_name_4`} ASWITH pgr_doubled_dijkstra AS (SELECT *FROM pgr_dijkstra(' SELECT id, source, target, cost_updated AS cost FROM {`table_name_2`}', ARRAY(SELECT id FROM isochrones_snapped WHERE id = {origin_id}), ARRAY(SELECT id FROM hospital_rs_node_v2 WHERE cd_cnes = {hospital_name}), directed:=TRUE)), ----node 9372, network = source, target)second_route AS ( SELECT net.*, CASE WHEN route.node = net.source THEN net.cost_updated * 20 ELSE net.cost_updated END AS cost_updated_nd FROM {`table_name_2`} AS net LEFT JOIN pgr_doubled_dijkstra AS route ON route.edge= net.id) SELECT * FROM second_route", .con=eisenberg_connection); result_4 <-dbGetQuery(conn = eisenberg_connection, query_4)dbExecute(glue_sql("DROP TABLE IF EXISTS {`table_name_5`}", .con=eisenberg_connection),conn=eisenberg_connection)# third route query_5 <-glue_sql("CREATE TABLE {`table_name_5`} ASSELECT seq, path_seq, start_vid, end_vid, node, edge, net.the_geom, 3 AS path FROM pgr_Dijkstra(' SELECT id, source, target, cost_updated_nd AS cost FROM {`table_name_4`}', ARRAY(SELECT id FROM isochrones_snapped WHERE id = {origin_id}), ARRAY(SELECT id FROM hospital_rs_node_v2 WHERE cd_cnes = {hospital_name}), directed:=TRUE) AS path LEFT JOIN {`table_name_4`} AS net ON path.edge = net.id;", .con= eisenberg_connection) result <-dbGetQuery(conn = eisenberg_connection, query_5)dbExecute(glue_sql("DROP TABLE IF EXISTS {`table_name_6`}", .con=eisenberg_connection),conn=eisenberg_connection) alterantive_point_1 <-glue_sql("CREATE TABLE {`table_name_6`} AS SELECT start_vid, end_vid,path, the_geom, edge FROM {`table_name_1`}UNIONSELECT start_vid, end_vid,path, the_geom, edge FROM {`table_name_3`}UNIONSELECT start_vid, end_vid,path, the_geom, edge FROM {`table_name_5`}", .con = eisenberg_connection) result_6 <-dbGetQuery(conn = eisenberg_connection, alterantive_point_1)dbExecute(glue_sql("DROP TABLE IF EXISTS {`table_name_7`}", .con=eisenberg_connection),conn=eisenberg_connection) table_end_point_1 <-glue_sql("CREATE TABLE {`table_name_7`} ASSELECT alternative.*, ceil(st_length(alternative.the_geom::geography)/1000) As length, original.cost AS cost FROM {`table_name_6`} AS alternative LEFT JOIN porto_alegre_net_largest AS original ON alternative.edge = original.id WHERE edge!= -1", .con=eisenberg_connection) result_7 <-dbGetQuery(conn=eisenberg_connection,table_end_point_1 ) calculations <-glue_sql(" INSERT INTO table_end_v2 (start_vid, end_vid, path, length, cost, the_geom) SELECT start_vid, end_vid, path, sum(length) AS length, sum(cost) AS cost, st_union(the_geom) as the_geom FROM {`table_name_7`} GROUP BY start_vid, end_vid, path ORDER BY path ASC", .con=eisenberg_connection)dbExecute(conn=eisenberg_connection, calculations)toc() }}
Show the code
result |> dplyr::select(c(start_vid, end_vid,path, length, cost)) |>group_by(start_vid,end_vid,path) |>summarise(length=sum(length),cost=sum(cost))
Show the code
SELECT*FROM pgr_dijkstra(' SELECT id, source, target, cost FROM porto_alegre_net_largest',ARRAY(SELECTidFROM points_cardiologia LIMIT1),ARRAY(SELECTidAS end_id FROM hospital_rs_node_v2 WHERE ds_cnes ='HOSPITAL SAO CAMILOESTEIO'), directed:=TRUE)
---- bairrosDROPTABLE bairro_porto_cleaned ;createtable bairro_porto_cleaned ASselectdistincton (cd_geocodb) cd_geocodb, tipo, nm_bairro, st_union(st_transform(geom,4326)) AS the_geomfrom barrios_brasil where nm_bairro ISNOTNULLGROUPBY cd_geocodb, tipo, nm_bairro;---- subdistricts cd_geocods createtable subdistricts_porto_cleaned ASselectdistincton (cd_geocods) cd_geocods, tipo, nm_bairro, nm_subdist, st_union(st_transform(geom,4326)) AS the_geomfrom barrios_brasil GROUPBY cd_geocods, tipo, nm_bairro,nm_subdist;---- districtscreatetable districts_porto_cleaned ASselectdistincton (cd_geocodd) cd_geocodd, tipo, nm_distrit, st_union(st_transform(geom,4326)) AS the_geomfrom barrios_brasil GROUPBY cd_geocodd, tipo, nm_distrit;---SELECT*FROM bairro_porto_cleaned;SELECT*FROM barrios_brasil;SELECT*FROM districts_porto_cleaned;----- Municipalitiescreatetable municipalities_porto_cleaned ASselectdistincton (cd_geocodm) cd_geocodm, tipo, nm_municip, st_union(st_transform(geom,4326)) AS the_geomfrom barrios_brasil GROUPBY cd_geocodm, tipo, nm_municip;----- centrality para barriosCREATETABLE table_barrios_mean ASWITH centrality_barrios AS (SELECT cd_geocodb, bairros.nm_bairro, bairros.tipo, centrality.*, bairros.the_geom AS polygonFROM centrality_weighted_100_bidirect_cleaned AS centrality LEFTJOIN bairro_porto_cleaned AS bairrosON st_intersects(centrality.the_geom, bairros.the_geom))SELECT cd_geocodb AS bairro_id, nm_bairro AS bairro_name, tipo AS bairro_type,sum(st_length(the_geom)) AS total_length,avg(centrality) AS mean_centrality,percentile_disc(0.5) WITHIN GROUP (ORDERBY centrality) ASmedian, polygonFROM centrality_barrios WHERE nm_bairro ISNOTNULLGROUPBY cd_geocodb, nm_bairro, tipo, polygon
5.9.1 Data
Show the code
CREATETABLE centrality_both_sankey ASWITH centrality_both_sankey AS (SELECT centrality_pre.bidirectid, centrality_pre.centrality AS centrality_pre, centrality_post.centrality AS centrality_post, centrality_pre.the_geom AS pre_geom, centrality_post.the_geom AS post_geomFROM centrality_weighted_100_bidirect_cleaned AS centrality_preFULLOUTERJOIN centrality_weighted_100_bidirect_cleaned_post AS centrality_postON centrality_pre.bidirectid = centrality_post.bidirectid)SELECT bidirectid, centrality_pre, centrality_post,COALESCE(ST_Length(pre_geom::geography)/100, ST_Length(post_geom::geography)/1000) AS geom_lengthFROM centrality_both_sankey;
5.9.2 plot
Show the code
library(tidyverse)library(ggsankey)### Flow Chartcentrality_both_sankey <- DBI::dbReadTable(eisenberg_connection, "centrality_both_sankey")df_centrality_both_sankey <- centrality_both_sankey |>mutate(pre_scenario=as.factor(case_when( centrality_pre ==0~"[0]", centrality_pre >0& centrality_pre <=146~"[1-146]", centrality_pre >=146& centrality_pre <=345~"[146-345]", centrality_pre >=345& centrality_pre <=633~"[345-633]", centrality_pre >=633~"[633-1644]",TRUE~"[0]")),post_scenario=as.factor(case_when( centrality_post ==0~"[0]", centrality_post >0& centrality_post <=146~"[1-146]", centrality_post >=146& centrality_post <=345~"[146-345]", centrality_post >=345& centrality_post <=633~"[345-633]", centrality_post >=633~"[633-1644]",TRUE~"[0]"))) # HeiGIt --- Create a long format dataset for ggsankeydf_centrality_both_sankey_long <- df_centrality_both_sankey |>mutate(pre_scenario =as.character(pre_scenario),post_scenario =as.character(post_scenario)) |> ggsankey::make_long(5:6) # Create an initial Sankey diagram (not used in final plot, but used to extract data)mycolour <-c("#edf8fb","#b3cde3","#8c96c6","#8856a7","#810f7c")names(mycolour) <-c(unique(df_centrality_both_sankey_long$node)[3],unique(df_centrality_both_sankey_long$node)[1],unique(df_centrality_both_sankey_long$node)[2],unique(df_centrality_both_sankey_long$node)[4],unique(df_centrality_both_sankey_long$node)[5])auxiliar_data <-df_centrality_both_sankey_long |>group_by(node, x) |>count()df_centrality_both_sankey_long$node <-factor(df_centrality_both_sankey_long$node, levels=c("[0]","[1-146]","[146-345]","[345-633]","[633-1644]")) p <-ggplot(df_centrality_both_sankey_long, aes(x = x,next_x = next_x,node = node,next_node = next_node,fill =factor(node),label = node)) +geom_sankey(flow.alpha =0.6) +geom_sankey_text() +scale_fill_manual(values = mycolour) +geom_sankey_label( fill="white", alpha=.7) +theme_minimal() +theme(legend.position ="none",plot.background =element_rect(fill ="grey99", color =NA) )# Extract flow, node, and label data from the Sankey diagrammoves_flows <-layer_data(p, 1) %>%mutate(height = flow_end_ymax - flow_end_ymin)moves_nodes <-layer_data(p, 2)moves_labels <-layer_data(p, 3)f1 <-"Graphik"f1b <-"Graphik Compact"f2 <-"Publico Headline"# Apply factor levels to ensure matching with mycolourmoves_nodes$label <-factor(moves_nodes$label, levels =names(mycolour))moves_flows$label <-factor(moves_flows$label, levels =names(mycolour))p1 <-ggplot() +# Add flow polygons, highlighting the most common moves and using the correct fill mappinggeom_polygon(data = moves_flows, aes(x, y, group = group, fill = label)) +# Add node rectangles with color based on the labelgeom_rect(data = moves_nodes, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill ="white"), fill="white") +# Manually scale the fill using the mycolour palettescale_fill_manual(values = mycolour) +# Add labels for the most common movesgeom_text(data = moves_labels,aes(x, y, label = label),family = f1b,color ="black",size =6) +labs(title ="Changes on Connectivity",subtitle ="Porto Alegre Settlement",caption ="Source: OpenStreetMap · Graphic: Ricardo Ruiz Sánchez inspired by Georgios Karamanis" ) +theme_void(base_family = f1) +theme(legend.position ="none",plot.background =element_rect(fill ="white", color =NA),plot.margin =margin(10, 10, 10, 10),plot.title =element_text(size =30, face ="bold", family = f2),plot.subtitle =element_text(size =15, lineheight =1, color ="#676162"),plot.caption =element_text(hjust =0, size =12, "#676162") )ggsave("plot_flow_chart.jpg", plot= p1, dpi=300, width=10, height=15)## Length roads### pre-lengthdf_length_pre <- centrality_both_sankey |>select(bidirectid, centrality_pre, geom_length) |>rename(centrality = centrality_pre) |>mutate(category_centrality=as.factor(case_when( centrality ==0~"[0]", centrality >0& centrality <=146~"[1-146]", centrality >=146& centrality <=345~"[146-345]", centrality >=345& centrality <=633~"[345-633]", centrality >=633~"[633-1644]",TRUE~"[0]"))) |> dplyr::select(c(geom_length, category_centrality)) |>group_by(category_centrality) |>summarise(total_lenth=sum(geom_length))df_length_pre$event <-"Road length (%)"df_length_pre$pct <-as.numeric(round(df_length_pre$total_lenth/(sum(df_length_pre$total_lenth)),4))## pre-length-plotggplot(df_length_pre, aes(x = event, y = pct, fill = category_centrality)) +geom_col() +coord_flip() +scale_fill_manual(values = mycolour) +#theme_minimal() + ggthemes::theme_clean() +labs(x="", y="") +theme(legend.position ="none",legend.text =element_text(size =7),legend.title =element_text(size =7),legend.background =element_blank(),plot.background =element_blank(),plot.caption =element_text(face ="italic",size =8,color ="grey30" ) ) +guides (fill =guide_legend(nrow =2, byrow =TRUE) ) ## Centralities valuesdf_barplots_sankey <- df_centrality_both_sankey |>pivot_longer(cols=c("post_scenario","pre_scenario"),names_to ="event",values_to ="quartile")centrality_both_longer <- centrality_both |>pivot_longer(cols=c(pre_scenario, post_scenario),names_to ="quartile",values_to ="category") df_barplots_sankey <- centrality_both_longer |> dplyr::select(c(centrality, quartile, category)) |>group_by(quartile, category) |>summarise(centrality=sum(centrality)) |>mutate(total_perc = centrality/sum(centrality))ggplot(df_barplots_sankey, aes(x = quartile, y = total_perc, fill = category)) +geom_col() +scale_x_discrete(labels=c("centrality_post"="Post-flooding", "centrality_pre"="Pre-flooding")) +coord_flip() +scale_fill_manual(values = mycolour) +labs(x ="Event",y ="Centrality (%)",title ="Share of centrality per range in the two scenarios" ) +#theme_minimal() + ggthemes::theme_clean() +theme(legend.position ="bottom",legend.text =element_text(size =7),legend.title =element_text(size =7),legend.background =element_blank(),plot.background =element_blank(),plot.caption =element_text(face ="italic",size =8,color ="grey30" ) ) +guides (fill =guide_legend(nrow =1, byrow =TRUE) )