Load data

Code
library(tidyverse)
library(marginaleffects)
library(lme4)
library(scales)
library(sf)
library(patchwork)
library(rnaturalearth)

clrs <- MoMAColors::moma.colors("ustwo")

theme_ngo <- function() {
  theme_minimal(base_family = "Lexend") +
    theme(panel.grid.minor = element_blank(),
      plot.background = element_rect(fill = "white", color = NA),
      plot.title = element_text(face = "bold"),
      axis.title = element_text(face = "bold"),
      strip.text = element_text(face = "bold"),
      strip.background = element_rect(fill = "grey80", color = NA),
      legend.title = element_text(face = "bold"))
}

world <- ne_countries(scale = 50) |> 
  st_transform(crs = st_crs("EPSG:8857"))

panel <- qs2::qs_read(here::here("data/data-processed/panel.qs2"))

panel_lags <- panel |>
  group_by(iso3) |>
  arrange(year) |>
  mutate(
    ccsi_lag = lag(ccsi),
    ccsi_lag2 = lag(ccsi, 2),
    ccsi_cumsum_lag3 = lag(cumsum(ccsi), 3),
    barriers_total_lag = lag(barriers_total),
    barriers_total_lag2 = lag(barriers_total, 2),
    barriers_total_cumsum_lag3 = lag(cumsum(barriers_total), 3),
    advocacy_lag = lag(advocacy),
    advocacy_lag2 = lag(advocacy, 2),
    advocacy_cumsum_lag3 = lag(cumsum(advocacy), 3),
    polyarchy_lag = lag(polyarchy),
    corruption_lag = lag(corruption),
    rule_law_lag = lag(rule_law),
    civil_liberties_lag = lag(civil_liberties),
    physical_violence_lag = lag(physical_violence)
  ) |>
  ungroup() |> 
  filter(year > 1990) |> 
  drop_na(ccsi_lag) |> 
  replace_na(list(n_neighbor_projects = 0)) |> 
  drop_na()

Illustrations

All projects in some countries

Code
# projects <- qs2::qs_read("data/data-processed/recipients_projects.qs2")

# projects_s_asia <- projects |>
#   mutate(
#     region = countrycode(iso_a3, origin = "iso3c", destination = "region")
#   ) |>
#   filter(region == "South Asia") |>
#   st_drop_geometry() |>
#   unnest_wider(project_details) |>
#   unnest(projects_in_country) |> 
#   select(iso_a3, name, project_id, geometry) |> 
#   st_set_geometry("geometry")

# qs2::qs_save(projects_s_asia, "data/data-processed/projects_s_asia.qs2")
Code
projects_s_asia <- qs2::qs_read(here::here("data/data-processed/projects_s_asia.qs2"))

world_with_regions <- world |> 
  mutate(is_south_asia = region_wb == "South Asia")

# Make a little bounding box with these specific coordinates to to zoom in
bbox <- st_bbox(
  c(xmin = 60, xmax = 100, ymin = -1, ymax = 45),
  crs = st_crs("EPSG:4326")
) |>
  st_as_sfc() |>
  st_transform("+proj=eqearth") |>
  st_bbox()

ggplot() + 
  geom_sf(data = world_with_regions, aes(fill = is_south_asia), color = "white", linewidth = 0.5) +
  geom_sf(data = projects_s_asia, size = 0.05) +
  scale_fill_manual(values = c("grey75", clrs[3]), guide = "none") +
  coord_sf(
    crs = "+proj=eqearth",
    xlim = c(bbox["xmin"], bbox["xmax"]),
    ylim = c(bbox["ymin"], bbox["ymax"]),
    datum = NA
  ) +
  theme_void() +
  theme(panel.background = element_rect(fill = "#d9f0ff"))

Projects in border area

Code
# projects <- qs2::qs_read("data/data-processed/recipients_projects.qs2")

# uganda_projects <- projects |> 
#   filter(iso_a3 == "UGA")

# qs2::qs_save(uganda_projects, "data/data-processed/uganda_projects.qs2")
Code
uganda <- world |> filter(admin == "Uganda")

# Find all neighboring countries
neighbors <- st_filter(world, uganda, .predicate = st_touches)
Code
uganda_projects <- qs2::qs_read(here::here("data/data-processed/uganda_projects.qs2"))

uganda_neighbor_projects <- uganda_projects |> 
  st_drop_geometry() |> 
  unnest_wider(project_details) |> 
  unnest(projects_outside_border_long) |> 
  st_set_geometry("geometry") |> 
  filter(year == 2019)

uganda_buffer <- uganda_projects |> 
  st_drop_geometry() |> 
  unnest_wider(project_details) |> 
  pull(border_buffer)
Code
# Make a little bounding box with these specific coordinates to to zoom in
bbox <- st_bbox(
  c(xmin = 28, xmax = 38, ymin = -3, ymax = 5.5),
  crs = st_crs("EPSG:4326")
) |>
  st_as_sfc() |>
  st_transform("+proj=eqearth") |>
  st_bbox()

ggplot() +
  geom_sf(data = neighbors, fill = "#facba6", color = "white") +
  geom_sf(data = uganda_buffer, fill = clrs[5], alpha = 0.5) +
  geom_sf(data = uganda, fill = clrs[1]) +
  geom_sf(data = uganda_neighbor_projects, size = 0.75) +
  coord_sf(
    crs = "+proj=eqearth",
    xlim = c(bbox["xmin"], bbox["xmax"]),
    ylim = c(bbox["ymin"], bbox["ymax"])
  ) +
  theme_void() +
  theme(panel.background = element_rect(fill = "#d9f0ff"))

Project distance from capital

Code
# projects <- qs2::qs_read("data/data-processed/recipients_projects.qs2")

# jordan_projects <- projects |> 
#   filter(iso_a3 == "JOR")

# qs2::qs_save(jordan_projects, "data/data-processed/jordan_projects.qs2")
Code
jordan_projects <- qs2::qs_read(here::here(
  "data/data-processed/jordan_projects.qs2"
))

jordan_internal_projects <- jordan_projects |>
  st_drop_geometry() |>
  unnest_wider(project_details) |>
  unnest(projects_in_country_long) |>
  st_set_geometry("geometry") |>
  filter(year == 2019)

jordan <- world |> filter(iso_a3 == "JOR")

# Create LINESTRINGs between each project and the capital
jordan_with_lines <- jordan_internal_projects |>
  mutate(
    line_geom = map2(capital_geom, geometry, \(cap, proj) {
      st_linestring(rbind(
        st_coordinates(cap),
        st_coordinates(proj)
      ))
    })
  ) |>
  mutate(line_geom = st_sfc(line_geom, crs = st_crs(jordan))) |>
  st_set_geometry("line_geom")

# Extract Amman
jordan_capital <- jordan_internal_projects |>
  slice(1) |>
  select(capital_name, capital_geom) |>
  st_set_geometry("capital_geom")

ggplot() +
  geom_sf(data = jordan, fill = "grey95", color = "black") +
  geom_sf(data = jordan_with_lines, alpha = 0.3, color = "grey50") +
  geom_sf(data = jordan_internal_projects, color = clrs[1], size = 1) +
  geom_sf(data = jordan_capital, color = clrs[4], size = 3) +
  theme_void()

Project entropy

Code
library(entropy)
calc_entropy_from_points <- function(projects, grid) {
  project_counts <- st_join(projects, grid) |>
    st_drop_geometry() |>
    count(grid_id) |>
    complete(grid_id = 1:nrow(grid), fill = list(n = 0))

  shannon <- entropy::entropy(project_counts$n, method = "ML")
  normalized <- shannon / log(nrow(grid))

  return(list(shannon = shannon, normalized = normalized))
}
Code
# Make up a fake country
country <- st_polygon(list(
  matrix(c(
    0, 1,  # Bottom left
    9, 0,  # Bottom right
    10, 8, # Right side
    8, 10, # Top right
    1, 9,  # Top left
    0, 1   # Close the polygon
  ), ncol = 2, byrow = TRUE)
)) |> 
  st_sfc(crs = 4326) |>
  st_sf()

# Make a grid that's cropped to the country
grid <- st_make_grid(country, n = c(5, 5), square = TRUE) |>
  st_sf() |>
  mutate(grid_id = row_number()) |>
  st_intersection(country) |> 
  st_make_valid()

# Create some fake projects with different kinds of dispersement
n_projects <- 100

withr::with_seed(1234, {
  low_entropy_projects <- tibble(
    x = rnorm(n_projects, mean = 5, sd = 0.5),
    y = rnorm(n_projects, mean = 5, sd = 0.5)
  ) |>
    st_as_sf(coords = c("x", "y"), crs = 4326)

  high_entropy_projects <- tibble(
    x = runif(n_projects, min = 0.5, max = 9.5),
    y = runif(n_projects, min = 0.5, max = 9.5)
  ) |>
    st_as_sf(coords = c("x", "y"), crs = 4326)
})

entropy_low <- calc_entropy_from_points(low_entropy_projects, grid)
entropy_high <- calc_entropy_from_points(high_entropy_projects, grid)
Code
p_low <- ggplot() +
  geom_sf(data = grid, fill = "grey95", color = "grey80", linewidth = 0.3) +
  geom_sf(data = country, fill = NA, color = "black", linewidth = 1) +
  geom_sf(
    data = low_entropy_projects,
    color = clrs[6],
    alpha = 0.6,
    size = 2
  ) +
  labs(title = glue::glue("Low entropy\n({round(entropy_low$normalized, 3)})")) +
  theme_ngo() +
  theme(
    panel.grid = element_blank(),
    axis.text = element_blank(),
    plot.title = element_text(hjust = 0.5)
  )

p_high <- ggplot() +
  geom_sf(data = grid, fill = "grey95", color = "grey80", linewidth = 0.3) +
  geom_sf(data = country, fill = NA, color = "black", linewidth = 1) +
  geom_sf(
    data = high_entropy_projects,
    color = clrs[1],
    alpha = 0.6,
    size = 2
  ) +
  labs(title = glue::glue("High entropy\n({round(entropy_high$normalized, 3)})")) +
  theme_ngo() +
  theme(
    panel.grid = element_blank(),
    axis.text = element_blank(),
    plot.title = element_text(hjust = 0.5)
  )

(p_low | p_high)

Outcome 1 = projects in neighbors

(TODO: different buffer sizes)

Treatment: CCSI

Treatment models and weights:

Code
# Treatment given history + confounders
denom_model_ccsi <- lm(
  ccsi ~ ccsi_lag + ccsi_lag2 + ccsi_cumsum_lag3 + 
         polyarchy_lag + corruption_lag + rule_law_lag + 
         civil_liberties_lag + physical_violence_lag + 
         factor(year),
  data = panel_lags
)

# Treatment given history only
num_model_ccsi <- lm(
  ccsi ~ ccsi_lag + ccsi_lag2 + ccsi_cumsum_lag3 + factor(year),
  data = panel_lags
)

panel_lags_weights_ccsi <- panel_lags |>
  mutate(
    num_pred = predict(num_model_ccsi),
    denom_pred = predict(denom_model_ccsi),
    num_resid = ccsi - num_pred,
    denom_resid = ccsi - denom_pred,
    num_density = dnorm(ccsi, mean = num_pred, sd = sd(num_resid)),
    denom_density = dnorm(ccsi, mean = denom_pred, sd = sd(denom_resid)),
    iptw_ratio = num_density / denom_density
  ) |>
  group_by(iso3) |>
  mutate(iptw = cumprod(iptw_ratio)) |>
  ungroup()

summary(panel_lags_weights_ccsi$iptw)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.229   0.914   0.983   1.020   1.037   3.076

Outcome model:

Code
neighbor_model_msm <- lmer(
  n_neighbor_projects ~ ccsi_lag + factor(year) + (1 | iso3),
  data = panel_lags_weights_ccsi,
  weights = iptw
)

neighbor_model_slope <- avg_slopes(neighbor_model_msm, variables = "ccsi_lag")
neighbor_model_slope
## 
##  Estimate Std. Error     z Pr(>|z|)    S 2.5 % 97.5 %
##      -638        145 -4.41   <0.001 16.6  -922   -355
## 
## Term: ccsi_lag
## Type: response
## Comparison: dY/dX

plot_predictions(neighbor_model_msm, condition = "ccsi_lag") +
  annotate(
    geom = "label",
    x = 0.98,
    y = 1600,
    label = paste0(
      "Slope: ",
      round(-neighbor_model_slope$estimate, 1),
      "*"
    ),
    hjust = 0
  ) +
  scale_x_reverse() +
  scale_y_continuous(labels = label_comma()) +
  labs(
    x = "Reversed civil society index\n(Lower values = more restrictive environment)",
    y = "Predicted number of projects within 50 km\nof the border in neighboring countries",
    title = "Effect of civil society environment on\naid projects in neighboring countries"
  ) +
  theme_ngo()

Treatment: Laws

Treatment models and weights:

Code
# Treatment given history + confounders
denom_model_barriers <- lm(
  barriers_total ~ barriers_total_lag + barriers_total_lag2 + barriers_total_cumsum_lag3 + 
         polyarchy_lag + corruption_lag + rule_law_lag + 
         civil_liberties_lag + physical_violence_lag + 
         factor(year),
  data = panel_lags
)

# Treatment given history only
num_model_barriers <- lm(
  barriers_total ~ barriers_total_lag + barriers_total_lag2 + barriers_total_cumsum_lag3 + factor(year),
  data = panel_lags
)

# Get predicted values and residuals and stabilized weights
panel_lags_weights_barriers <- panel_lags |>
  mutate(
    num_pred = predict(num_model_barriers),
    denom_pred = predict(denom_model_barriers),
    num_resid = barriers_total - num_pred,
    denom_resid = barriers_total - denom_pred,
    num_density = dnorm(barriers_total, mean = num_pred, sd = sd(num_resid)),
    denom_density = dnorm(barriers_total, mean = denom_pred, sd = sd(denom_resid)),
    iptw_ratio = num_density / denom_density
  ) |>
  group_by(iso3) |>
  mutate(iptw = cumprod(iptw_ratio)) |>
  ungroup()

summary(panel_lags_weights_barriers$iptw)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0302  0.8092  0.9553  1.0395  1.0749  4.9704
Code
# Treatment given history + confounders
denom_model_advocacy <- lm(
  advocacy ~ advocacy_lag + advocacy_lag2 + advocacy_cumsum_lag3 + 
         polyarchy_lag + corruption_lag + rule_law_lag + 
         civil_liberties_lag + physical_violence_lag + 
         factor(year),
  data = panel_lags
)

# Treatment given history only
num_model_advocacy <- lm(
  advocacy ~ advocacy_lag + advocacy_lag2 + advocacy_cumsum_lag3 + factor(year),
  data = panel_lags
)

# Get predicted values and residuals
panel_lags_weights_advocacy <- panel_lags |>
  mutate(
    num_pred = predict(num_model_advocacy),
    denom_pred = predict(denom_model_advocacy),
    num_resid = advocacy - num_pred,
    denom_resid = advocacy - denom_pred
  ) |>
  # Get stabilized weights
  mutate(
    num_density = dnorm(advocacy, mean = num_pred, sd = sd(num_resid)),
    denom_density = dnorm(advocacy, mean = denom_pred, sd = sd(denom_resid)),
    iptw_ratio = num_density / denom_density,
    iptw = cumprod(iptw_ratio)
  )

panel_lags_weights_advocacy <- panel_lags |>
  mutate(
    num_pred = predict(num_model_advocacy),
    denom_pred = predict(denom_model_advocacy),
    num_resid = advocacy - num_pred,
    denom_resid = advocacy - denom_pred,
    num_density = dnorm(advocacy, mean = num_pred, sd = sd(num_resid)),
    denom_density = dnorm(advocacy, mean = denom_pred, sd = sd(denom_resid)),
    iptw_ratio = num_density / denom_density
  ) |>
  group_by(iso3) |>
  mutate(iptw = cumprod(iptw_ratio)) |>
  ungroup()

summary(panel_lags_weights_advocacy$iptw)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.235   0.902   0.983   1.001   1.043   3.517

Outcome model:

Code
neighbor_model_msm_barriers <- lmer(
  n_neighbor_projects ~ barriers_total_lag + factor(year) + (1 | iso3),
  data = panel_lags_weights_barriers,
  weights = iptw
)

neighbor_model_slope_barriers <- avg_slopes(neighbor_model_msm_barriers, variables = "barriers_total_lag")
neighbor_model_slope_barriers
## 
##  Estimate Std. Error    z Pr(>|z|)   S 2.5 % 97.5 %
##      45.7         20 2.29    0.022 5.5  6.59   84.8
## 
## Term: barriers_total_lag
## Type: response
## Comparison: dY/dX

plot_predictions(neighbor_model_msm_barriers, condition = "barriers_total_lag") +
  annotate(
    geom = "label",
    x = 0,
    y = 1500,
    label = paste0(
      "Slope: ",
      round(neighbor_model_slope_barriers$estimate, 1),
      "*"
    ),
    hjust = 0
  ) +
  scale_y_continuous(labels = label_comma()) +
  labs(
    x = "Number of NGO laws",
    y = "Predicted number of projects within 50 km\nof the border in neighboring countries",
    title = "Effect of NGO laws on\naid projects in neighboring countries"
  ) +
  theme_ngo()

Code
neighbor_model_msm_advocacy <- lmer(
  n_neighbor_projects ~ advocacy_lag + factor(year) + (1 | iso3),
  data = panel_lags_weights_advocacy,
  weights = iptw
)

neighbor_model_slope_advocacy <- avg_slopes(neighbor_model_msm_advocacy, variables = "advocacy_lag")
neighbor_model_slope_advocacy
## 
##  Estimate Std. Error    z Pr(>|z|)   S 2.5 % 97.5 %
##       138       68.2 2.02   0.0438 4.5  3.82    271
## 
## Term: advocacy_lag
## Type: response
## Comparison: dY/dX

plot_predictions(neighbor_model_msm_advocacy, condition = "advocacy_lag") +
  annotate(
    geom = "label",
    x = 0,
    y = 1400,
    label = paste0(
      "Slope: ",
      round(neighbor_model_slope_advocacy$estimate, 1),
      "*"
    ),
    hjust = 0
  ) +
  scale_y_continuous(labels = label_comma()) +
  labs(
    x = "Number of advocacy-focused anti-NGO laws",
    y = "Predicted number of projects within 50 km\nof the border in neighboring countries",
    title = "Effect of advocacy-focused anti-NGO laws on\naid projects in neighboring countries"
  ) +
  theme_ngo()

Outcome 2 = projects within country

Treatment: CCSI

Outcome 1: Distance from capital

Code
distance_model_msm <- lmer(
  mean_dist_z ~ ccsi_lag + factor(year) + (1 | iso3),
  data = panel_lags_weights_ccsi,
  weights = iptw
)

distance_model_slope <- avg_slopes(distance_model_msm, variables = "ccsi_lag")
distance_model_slope
## 
##  Estimate Std. Error     z Pr(>|z|)   S  2.5 % 97.5 %
##   -0.0506     0.0382 -1.32    0.186 2.4 -0.126 0.0243
## 
## Term: ccsi_lag
## Type: response
## Comparison: dY/dX

plot_predictions(distance_model_msm, condition = "ccsi_lag") +
  annotate(
    geom = "label",
    x = 0.98,
    y = 0.025,
    label = paste0(
      "Slope: ",
      round(-distance_model_slope$estimate, 3)
    ),
    hjust = 0
  ) +
  scale_x_reverse() +
  labs(
    x = "Reversed civil society index\n(Lower values = more restrictive environment)",
    y = "Average standardized\ndistance from capital",
    title = "Effect of civil society environment on\naverage distance of projects from capital"
  ) +
  theme_ngo()

Outcome 2: Entropy

Code
entropy_model_msm <- lmer(
  normalized_entropy ~ ccsi_lag + factor(year) + (1 | iso3),
  data = panel_lags_weights_ccsi,
  weights = iptw
)

entropy_model_slope <- avg_slopes(entropy_model_msm, variables = "ccsi_lag")
entropy_model_slope
## 
##  Estimate Std. Error    z Pr(>|z|)    S  2.5 % 97.5 %
##     0.125     0.0189 6.59   <0.001 34.4 0.0876  0.162
## 
## Term: ccsi_lag
## Type: response
## Comparison: dY/dX

plot_predictions(entropy_model_msm, condition = "ccsi_lag") +
  annotate(
    geom = "label",
    x = 0.4,
    y = 0.78,
    label = paste0(
      "Slope: ",
      round(-entropy_model_slope$estimate, 3),
      "*"
    ),
    hjust = 0
  ) +
  scale_x_reverse() +
  labs(
    x = "Reversed civil society index\n(Lower values = more restrictive environment)",
    y = "Standardized entropy of projects",
    title = "Effect of civil society environment on\nentropy of project distribution"
  ) +
  theme_ngo()

Treatment: Laws

Outcome 1: Distance from capital

Code
distance_model_msm_barriers <- lmer(
  mean_dist_z ~ barriers_total_lag + factor(year) + (1 | iso3),
  data = panel_lags_weights_barriers,
  weights = iptw
)

distance_model_slope_barriers <- avg_slopes(distance_model_msm_barriers, variables = "barriers_total_lag")
distance_model_slope_barriers
## 
##  Estimate Std. Error     z Pr(>|z|)   S   2.5 %   97.5 %
##  -0.00983    0.00524 -1.88   0.0606 4.0 -0.0201 0.000439
## 
## Term: barriers_total_lag
## Type: response
## Comparison: dY/dX

plot_predictions(distance_model_msm_barriers, condition = "barriers_total_lag") +
  annotate(
    geom = "label",
    x = 5,
    y = 0,
    label = paste0(
      "Slope: ",
      round(distance_model_slope_barriers$estimate, 4)
    ),
    hjust = 0
  ) +
  labs(
    x = "Number of NGO laws",
    y = "Average standardized\ndistance from capital",
    title = "Effect of NGO laws on\naverage distance of projects from capital"
  ) +
  theme_ngo()

Code
distance_model_msm_advocacy <- lmer(
  mean_dist_z ~ advocacy_lag + factor(year) + (1 | iso3),
  data = panel_lags_weights_advocacy,
  weights = iptw
)

distance_model_slope_advocacy <- avg_slopes(distance_model_msm_advocacy, variables = "advocacy_lag")
distance_model_slope_advocacy
## 
##  Estimate Std. Error      z Pr(>|z|)   S   2.5 % 97.5 %
##  -0.00363     0.0188 -0.194    0.847 0.2 -0.0404 0.0332
## 
## Term: advocacy_lag
## Type: response
## Comparison: dY/dX

plot_predictions(distance_model_msm_advocacy, condition = "advocacy_lag") +
  annotate(
    geom = "label",
    x = 0,
    y = 0.02,
    label = paste0(
      "Slope: ",
      round(distance_model_slope_advocacy$estimate, 3),
      "*"
    ),
    hjust = 0
  ) +
  labs(
    x = "Number of advocacy-focused anti-NGO laws",
    y = "Average standardized\ndistance from capital",
    title = "Effect of advocacy-focused anti-NGO laws on\naverage distance of projects from capital"
  ) +
  theme_ngo()

Outcome 2: Entropy

Code
entropy_model_msm_barriers <- lmer(
  normalized_entropy ~ barriers_total_lag + factor(year) + (1 | iso3),
  data = panel_lags_weights_barriers,
  weights = iptw
)

entropy_model_slope_barriers <- avg_slopes(entropy_model_msm_barriers, variables = "barriers_total_lag")
entropy_model_slope_barriers
## 
##  Estimate Std. Error     z Pr(>|z|)    S   2.5 %  97.5 %
##   -0.0111     0.0024 -4.62   <0.001 18.0 -0.0158 -0.0064
## 
## Term: barriers_total_lag
## Type: response
## Comparison: dY/dX

plot_predictions(entropy_model_msm_barriers, condition = "barriers_total_lag") +
  annotate(
    geom = "label",
    x = 5,
    y = 0.75,
    label = paste0(
      "Slope: ",
      round(entropy_model_slope_barriers$estimate, 3),
      "*"
    ),
    hjust = 0
  ) +
  labs(
    x = "Number of NGO laws",
    y = "Standardized entropy of projects",
    title = "Effect of NGO laws on\nentropy of project distribution"
  ) +
  theme_ngo()

Code
entropy_model_msm_advocacy <- lmer(
  normalized_entropy ~ advocacy_lag + factor(year) + (1 | iso3),
  data = panel_lags_weights_advocacy,
  weights = iptw
)

entropy_model_slope_advocacy <- avg_slopes(entropy_model_msm_advocacy, variables = "advocacy_lag")
entropy_model_slope_advocacy
## 
##  Estimate Std. Error    z Pr(>|z|)   S   2.5 %   97.5 %
##   -0.0172     0.0082 -2.1   0.0359 4.8 -0.0333 -0.00113
## 
## Term: advocacy_lag
## Type: response
## Comparison: dY/dX

plot_predictions(entropy_model_msm_advocacy, condition = "advocacy_lag") +
  annotate(
    geom = "label",
    x = 1,
    y = 0.75,
    label = paste0(
      "Slope: ",
      round(entropy_model_slope_advocacy$estimate, 3),
      "*"
    ),
    hjust = 0
  ) +
  labs(
    x = "Number of advocacy-focused anti-NGO laws",
    y = "Standardized entropy of projects",
    title = "Effect of advocacy-focused anti-NGO laws on\nentropy of project distribution"
  ) +
  theme_ngo()