Food insecurity maps: season models


Maps of the prediction of the latent abilities and the spatial component.

Load required libraries and data

rm(list = ls())
library(day2day)
library(spifa)
library(xtable)
library(tibble)
library(sf)
#> Linking to GEOS 3.10.2, GDAL 3.4.1, PROJ 8.2.1; sf_use_s2() is TRUE
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(tidyr)
library(purrr)
library(ggplot2)
library(patchwork)

path_main <- git_path()
path_data <- file.path(path_main, "data")
path_raw <- file.path(path_data, "raw")
path_processed <- file.path(path_data, "processed")
path_modelled <- file.path(path_data, "modelled")
path_fig <- file.path(path_data, "figures")
path_src <- file.path(path_main, "src")

source(file.path(path_src, "itemnames.R"))
source(file.path(path_src, "ggtheme-publication.R"))
source(file.path(path_src, "maps.R"))

fidata <- file.path(path_processed, "fi-items-ipixuna-urban.gpkg") |>
    st_read(as_tibble = TRUE)
#> Reading layer `fi-items-ipixuna-urban' from data source 
#>   `/home/rstudio/documents/projects/food-insecurity-mapping/data/processed/fi-items-ipixuna-urban.gpkg' 
#>   using driver `GPKG'
#> Simple feature collection with 200 features and 36 fields
#> Geometry type: POINT
#> Dimension:     XY
#> Bounding box:  xmin: -71.70038 ymin: -7.06058 xmax: -71.68109 ymax: -7.03724
#> Geodetic CRS:  WGS 84
ipi_osm <- readRDS(file.path(path_processed, "ipixuna-osm.rds"))
pred_spifa <- readRDS(file.path(path_modelled, "spifa-prediction-ipixuna-urban-season-3gp.rds"))
pred_spifa_sp <- readRDS(file.path(path_modelled, "spifa-predictionsp-ipixuna-urban-season-3gp.rds"))

Get summary

# custom function
fun_sum <- function(data, regex, fun){
    dplyr::select(data, matches(regex)) |>
    st_drop_geometry() |>
    apply(1, fun)
}

# compute summaries
pred_summary <- pred_spifa["id"]
pred_summary[paste0("F", 1:3, "-exceedance-dry")] <- lapply(c("^F1-.+dry$", "^F2-.+dry$", "^F3-.+dry$"),
    function(z) fun_sum(pred_spifa, z, function(x) sum(x > 0) / length(x)))
pred_summary[paste0("F", 1:3, "-exceedance-wet")] <- lapply(c("^F1-.+wet$", "^F2-.+wet$", "^F3-.+wet$"),
    function(z) fun_sum(pred_spifa, z, function(x) sum(x > 0) / length(x)))
pred_summary[paste0("F", 1:3, "-median-dry")] <- lapply(c("^F1-.+dry$", "^F2-.+dry$", "^F3-.+dry$"),
    function(z) fun_sum(pred_spifa, z, median))
pred_summary[paste0("F", 1:3, "-median-wet")] <- lapply(c("^F1-.+wet$", "^F2-.+wet$", "^F3-.+wet$"),
    function(z) fun_sum(pred_spifa, z, median))

# compute summaries
pred_summary_sp <- pred_spifa_sp["id"]
pred_summary_sp[paste0("F", 1:3, "-exceedance-dry")] <- lapply(c("^F1-.+dry$", "^F2-.+dry$", "^F3-.+dry$"),
    function(z) fun_sum(pred_spifa_sp, z, function(x) sum(x > 0) / length(x)))
pred_summary_sp[paste0("F", 1:3, "-exceedance-wet")] <- lapply(c("^F1-.+wet$", "^F2-.+wet$", "^F3-.+wet$"),
    function(z) fun_sum(pred_spifa_sp, z, function(x) sum(x > 0) / length(x)))
pred_summary_sp[paste0("F", 1:3, "-median-dry")] <- lapply(c("^F1-.+dry$", "^F2-.+dry$", "^F3-.+dry$"),
    function(z) fun_sum(pred_spifa_sp, z, median))
pred_summary_sp[paste0("F", 1:3, "-median-wet")] <- lapply(c("^F1-.+wet$", "^F2-.+wet$", "^F3-.+wet$"),
    function(z) fun_sum(pred_spifa_sp, z, median))

Detect high insecure areas

mylabs <- c(
    "F1-exceedance" = "atop('(F1) Severe food insecurity', 'including children')",
    "F2-exceedance" = "atop('(F2) Anxiety and relying on', 'social relations')",
    "F3-exceedance" = "atop('(F3) Adults eating less and', 'going hungry')"
)
myseason <- c("dry" = "Dry~season", "wet" = "Rainy~season")
pred_summary_sp |>
    dplyr::select(id, matches("exceedance")) |>
    tidyr::pivot_longer(matches("exceedance"),
        names_to = c("factor_exceed", "season"), names_pattern = "(F[1-3]-exceedance)-(.+)") |>
    mutate(factor_exceed = mylabs[factor_exceed], season = myseason[season]) |>
    mutate(value = ifelse(value >= 0.75, 1, NA)) |>
    fi_ipi_exceed(osm = ipi_osm, title = "title", license = TRUE) +
    facet_grid(season ~ factor_exceed, labeller = ggplot2::label_parsed) +
    theme_map_Publication2(base_size = 9) +
    theme(legend.position = "none")
#> Warning: The `size` argument of `element_rect()` is deprecated as of ggplot2 3.4.0.
#> ℹ Please use the `linewidth` argument instead.
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

Text to add

text_df <- tibble(
  # text = c(toupper(letters[1:10])),
  text = c("C2", "D2", "B", "A", "C", "F2", "G2", "D", "I2", "J2", "E", "F", "G"),
  x1 = c(-71.695, -71.69, -71.6975, -71.6837, -71.6915, -71.686, -71.698, -71.694,
         -71.6875, -71.6875, -71.6849, -71.699, -71.6915),
  y1 = c(-7.045, -7.045, -7.051, -7.0585, -7.0488, -7.048, -7.057, -7.045, -7.0452,
         -7.0558, -7.0572, -7.0585, -7.0483),
  x2 = c(-71.6975, -71.6845, -71.6993, -71.6817, -71.699, -71.683, -71.699, -71.6975,
         -71.684, -71.682, -71.683, -71.696, -71.699),
  y2 = c(-7.045, -7.044, -7.048, -7.055, -7.049, -7.049, -7.06, -7.045, -7.045,
         -7.055, -7.0535, -7.0565, -7.0483),
  factor = c(rep("F1-median", 4), rep("F2-median", 3), rep("F3-median", 3), rep("F1-median", 2),
        "F3-median"),
  factor_exceed = c(rep(mylabs[[1]], 4), rep(mylabs[[2]], 3),
                    rep(mylabs[[3]], 3), rep(mylabs[[1]], 2), mylabs[[3]]),
  season = myseason[c(rep(NA, 2), "wet", "dry", rep(NA, 6), rep("wet", 3))],
  ) |>
  dplyr::filter(text %in% toupper(letters[1:7])) |>
  st_as_sf(coords = c("x1", "y1"), crs = st_crs(4326)) |>
  st_transform(crs = st_crs(3857))
text_df[c("x1", "y1")] <- st_coordinates(text_df)
text_df <- text_df |>
  st_set_geometry(NULL) |>
  st_as_sf(coords = c("x2", "y2"), crs = st_crs(4326)) |>
  st_transform(crs = st_crs(3857))
text_df[c("x2", "y2")] <- st_coordinates(text_df)
text_df <- text_df |> st_set_geometry(NULL)
text_df <- subset(text_df, !is.na(season))
text_df
#> # A tibble: 5 × 8
#>   text  factor    factor_exceed                               season      x1      y1      x2      y2
#>   <chr> <chr>     <chr>                                       <chr>    <dbl>   <dbl>   <dbl>   <dbl>
#> 1 B     F1-median atop('(F1) Severe food insecurity', 'inclu… Rainy… -7.98e6 -7.87e5 -7.98e6 -7.87e5
#> 2 A     F1-median atop('(F1) Severe food insecurity', 'inclu… Dry~s… -7.98e6 -7.88e5 -7.98e6 -7.87e5
#> 3 E     F1-median atop('(F1) Severe food insecurity', 'inclu… Rainy… -7.98e6 -7.88e5 -7.98e6 -7.87e5
#> 4 F     F1-median atop('(F1) Severe food insecurity', 'inclu… Rainy… -7.98e6 -7.88e5 -7.98e6 -7.88e5
#> 5 G     F3-median atop('(F3) Adults eating less and', 'going… Rainy… -7.98e6 -7.87e5 -7.98e6 -7.87e5
text_dry <- subset(text_df, season == myseason["dry"])
text_wet <- subset(text_df, season == myseason["wet"])

Visualize prediction of latent abilities

gg1 <- fi_ipi(mutate(pred_summary, `F1-median` = `F1-median-dry`), `F1-median`, ipi_osm,
    title = mylabs[[1]], axis.x = FALSE, text_df = text_dry) +
    fi_ipi(mutate(pred_summary, `F2-median` = `F2-median-dry`), `F2-median`, ipi_osm,
    title = mylabs[[2]], axis.y = FALSE, axis.x = FALSE, text_df = text_dry) +
    fi_ipi(mutate(pred_summary, `F3-median` = `F3-median-dry`), `F3-median`, ipi_osm,
    title = mylabs[[3]], axis.y = FALSE, axis.x = FALSE, text_df = text_dry,
    license = FALSE, title2 = "Dry~season") &
    theme_map_Publication(base_size = 9) &
    theme(
    strip.text.x = element_text(margin=margin(l=0, r=0, t=0, b=2)),
    strip.text.y = element_text(margin=margin(l=2, r=0, t=0, b=0))
    )
#> # A tibble: 1 × 8
#>   text  factor    factor_exceed                               season      x1      y1      x2      y2
#>   <chr> <chr>     <chr>                                       <chr>    <dbl>   <dbl>   <dbl>   <dbl>
#> 1 A     F1-median atop('(F1) Severe food insecurity', 'inclu… Dry~s… -7.98e6 -7.88e5 -7.98e6 -7.87e5
#> Warning: `aes_()` was deprecated in ggplot2 3.0.0.
#> ℹ Please use tidy evaluation idioms with `aes()`
#> This warning is displayed once every 8 hours.
#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
#> # A tibble: 0 × 8
#> # ℹ 8 variables: text <chr>, factor <chr>, factor_exceed <chr>, season <chr>, x1 <dbl>, y1 <dbl>,
#> #   x2 <dbl>, y2 <dbl>
#> # A tibble: 0 × 8
#> # ℹ 8 variables: text <chr>, factor <chr>, factor_exceed <chr>, season <chr>, x1 <dbl>, y1 <dbl>,
#> #   x2 <dbl>, y2 <dbl>
gg2 <- fi_ipi(mutate(pred_summary, `F1-median` = `F1-median-wet`), `F1-median`, ipi_osm,
    title = mylabs[[1]], text_df = text_wet) +
    fi_ipi(mutate(pred_summary, `F2-median` = `F2-median-wet`), `F2-median`, ipi_osm,
    title = mylabs[[2]], axis.y = FALSE, text_df = text_wet) +
    fi_ipi(mutate(pred_summary, `F3-median` = `F3-median-wet`), `F3-median`, ipi_osm,
    title = mylabs[[3]], axis.y = FALSE, text_df = text_wet, license = TRUE, title2 = "Rainy~season") &
    theme_map_Publication(base_size = 9) &
    theme(strip.background = element_blank(), strip.text.x = element_blank(),
    strip.text.y = element_text(margin=margin(l=2, r=0, t=0, b=0)))
#> # A tibble: 3 × 8
#>   text  factor    factor_exceed                               season      x1      y1      x2      y2
#>   <chr> <chr>     <chr>                                       <chr>    <dbl>   <dbl>   <dbl>   <dbl>
#> 1 B     F1-median atop('(F1) Severe food insecurity', 'inclu… Rainy… -7.98e6 -7.87e5 -7.98e6 -7.87e5
#> 2 E     F1-median atop('(F1) Severe food insecurity', 'inclu… Rainy… -7.98e6 -7.88e5 -7.98e6 -7.87e5
#> 3 F     F1-median atop('(F1) Severe food insecurity', 'inclu… Rainy… -7.98e6 -7.88e5 -7.98e6 -7.88e5
#> # A tibble: 0 × 8
#> # ℹ 8 variables: text <chr>, factor <chr>, factor_exceed <chr>, season <chr>, x1 <dbl>, y1 <dbl>,
#> #   x2 <dbl>, y2 <dbl>
#> # A tibble: 1 × 8
#>   text  factor    factor_exceed                               season      x1      y1      x2      y2
#>   <chr> <chr>     <chr>                                       <chr>    <dbl>   <dbl>   <dbl>   <dbl>
#> 1 G     F3-median atop('(F3) Adults eating less and', 'going… Rainy… -7.98e6 -7.87e5 -7.98e6 -7.87e5
(gg1 / gg2) & theme(legend.text = element_text(size = rel(0.7)))

ggsave(file.path(path_fig, "osmmap-season-theta-median.pdf"), width = 7, height = 3.8 * 1.7)

myseason <- c("dry" = "Dry~season", "wet" = "Rainy~season")
pred_summary |>
    dplyr::select(id, matches("exceedance")) |>
    tidyr::pivot_longer(matches("exceedance"),
        names_to = c("factor_exceed", "season"), names_pattern = "(F[1-3]-exceedance)-(.+)") |>
    mutate(factor_exceed = mylabs[factor_exceed], season = myseason[season]) |>
    within({value[value < 0.5] <- NA}) |>
    fi_ipi_exceed(osm = ipi_osm, title = "title", text_df = text_df, license = TRUE) +
    facet_grid(season ~ factor_exceed, labeller = ggplot2::label_parsed) +
    theme_map_Publication2(base_size = 9)

ggsave(file.path(path_fig, "osmmap-season-theta-exceedance.pdf"), width = 7, height = 3.7 * 1.7)

Visualize prediction of the spatial component of latent abilities

gg1 <- fi_ipi(mutate(pred_summary_sp, `F1-median` = `F1-median-dry`), `F1-median`, ipi_osm,
    title = mylabs[[1]], axis.x = FALSE, text_df = text_dry) +
    fi_ipi(mutate(pred_summary_sp, `F2-median` = `F2-median-dry`), `F2-median`, ipi_osm,
    title = mylabs[[2]], axis.y = FALSE, axis.x = FALSE, text_df = text_dry) +
    fi_ipi(mutate(pred_summary_sp, `F3-median` = `F3-median-dry`), `F3-median`, ipi_osm,
    title = mylabs[[3]], axis.y = FALSE, axis.x = FALSE, text_df = text_dry,
    license = FALSE, title2 = "Dry~season") &
    theme_map_Publication(base_size = 9) &
    theme(
    strip.text.x = element_text(margin=margin(l=0, r=0, t=0, b=2)),
    strip.text.y = element_text(margin=margin(l=2, r=0, t=0, b=0))
    )
#> # A tibble: 1 × 8
#>   text  factor    factor_exceed                               season      x1      y1      x2      y2
#>   <chr> <chr>     <chr>                                       <chr>    <dbl>   <dbl>   <dbl>   <dbl>
#> 1 A     F1-median atop('(F1) Severe food insecurity', 'inclu… Dry~s… -7.98e6 -7.88e5 -7.98e6 -7.87e5
#> # A tibble: 0 × 8
#> # ℹ 8 variables: text <chr>, factor <chr>, factor_exceed <chr>, season <chr>, x1 <dbl>, y1 <dbl>,
#> #   x2 <dbl>, y2 <dbl>
#> # A tibble: 0 × 8
#> # ℹ 8 variables: text <chr>, factor <chr>, factor_exceed <chr>, season <chr>, x1 <dbl>, y1 <dbl>,
#> #   x2 <dbl>, y2 <dbl>
gg2 <- fi_ipi(mutate(pred_summary_sp, `F1-median` = `F1-median-wet`), `F1-median`, ipi_osm,
    title = mylabs[[1]], text_df = text_wet) +
    fi_ipi(mutate(pred_summary_sp, `F2-median` = `F2-median-wet`), `F2-median`, ipi_osm,
    title = mylabs[[2]], axis.y = FALSE, text_df = text_wet) +
    fi_ipi(mutate(pred_summary_sp, `F3-median` = `F3-median-wet`), `F3-median`, ipi_osm,
    title = mylabs[[3]], axis.y = FALSE, text_df = text_wet, license = TRUE, title2 = "Rainy~season") &
    theme_map_Publication(base_size = 9) &
    theme(strip.background = element_blank(), strip.text.x = element_blank(),
    strip.text.y = element_text(margin=margin(l=2, r=0, t=0, b=0)))
#> # A tibble: 3 × 8
#>   text  factor    factor_exceed                               season      x1      y1      x2      y2
#>   <chr> <chr>     <chr>                                       <chr>    <dbl>   <dbl>   <dbl>   <dbl>
#> 1 B     F1-median atop('(F1) Severe food insecurity', 'inclu… Rainy… -7.98e6 -7.87e5 -7.98e6 -7.87e5
#> 2 E     F1-median atop('(F1) Severe food insecurity', 'inclu… Rainy… -7.98e6 -7.88e5 -7.98e6 -7.87e5
#> 3 F     F1-median atop('(F1) Severe food insecurity', 'inclu… Rainy… -7.98e6 -7.88e5 -7.98e6 -7.88e5
#> # A tibble: 0 × 8
#> # ℹ 8 variables: text <chr>, factor <chr>, factor_exceed <chr>, season <chr>, x1 <dbl>, y1 <dbl>,
#> #   x2 <dbl>, y2 <dbl>
#> # A tibble: 1 × 8
#>   text  factor    factor_exceed                               season      x1      y1      x2      y2
#>   <chr> <chr>     <chr>                                       <chr>    <dbl>   <dbl>   <dbl>   <dbl>
#> 1 G     F3-median atop('(F3) Adults eating less and', 'going… Rainy… -7.98e6 -7.87e5 -7.98e6 -7.87e5
(gg1 / gg2) & theme(legend.text = element_text(size = rel(0.7)))

ggsave(file.path(path_fig, "osmmap-season-thetaspatial-median.pdf"), width = 7, height = 3.8 * 1.7)

myseason <- c("dry" = "Dry~season", "wet" = "Rainy~season")
pred_summary_sp |>
    dplyr::select(id, matches("exceedance")) |>
    tidyr::pivot_longer(matches("exceedance"),
        names_to = c("factor_exceed", "season"), names_pattern = "(F[1-3]-exceedance)-(.+)") |>
    mutate(factor_exceed = mylabs[factor_exceed], season = myseason[season]) |>
    within({value[value < 0.5] <- NA}) |>
    fi_ipi_exceed(osm = ipi_osm, title = "title", text_df = text_df, license = TRUE) +
    facet_grid(season ~ factor_exceed, labeller = ggplot2::label_parsed) +
    theme_map_Publication2(base_size = 9)

ggsave(file.path(path_fig, "osmmap-season-thetaspatial-exceedance.pdf"), width = 7, height = 3.7 * 1.7)

Time to execute the task

Only useful when executed with Rscript.

proc.time()
#>    user  system elapsed 
#>  31.897   2.569  31.923