library(tidyverse)
library(scales)
library(sf)
library(patchwork)
library(countrycode)
library(readxl)
library(validate)
library(pander)
library(here)
source(here("lib", "graphic-functions.R"))
# qwraps2::lazyload_cache_dir("figures_cache/html")
options(dplyr.summarise.inform = FALSE)
# Load CIVICUS data
# Downloaded from HTML page at https://monitor.civicus.org/
<- read_csv(here("data", "civicus_monitor_2017.csv"), na = "Null") %>%
civicus mutate(Rating = factor(Rating, levels = c("Open", "Narrowed", "Obstructed",
"Repressed", "Closed"),
ordered = TRUE),
iso3 = countrycode(Country, "country.name", "iso3c"))
# Load global shapefiles
# Get Admin 0 file from http://www.naturalearthdata.com/downloads/110m-cultural-vectors/
<- st_read(here("data", "ne_110m_admin_0_countries",
world_shapes "ne_110m_admin_0_countries.shp"),
quiet = TRUE) %>%
# Ignore Antarctica
filter(ISO_A3 != "ATA")
# Use the Robinson map projection
= "ESRI:54030"
projection
# Join CIVICUS data with map data
<- world_shapes %>%
map_with_civicus # Fix some Natural Earth ISO weirdness
mutate(ISO_A3 = ifelse(ISO_A3 == "-99", as.character(ISO_A3_EH), as.character(ISO_A3))) %>%
mutate(ISO_A3 = case_when(
$ISO_A3 == "GRL" ~ "DNK",
.$NAME == "Norway" ~ "NOR",
.TRUE ~ ISO_A3
%>%
)) left_join(civicus, by = c("ISO_A3" = "iso3"))
<- ggplot() +
plot_civicus_map geom_sf(data = map_with_civicus, aes(fill = Rating), size = 0.15, color = "black") +
coord_sf(crs = st_crs(projection), datum = NA) +
scale_fill_manual(values = c("grey90", "grey70", "grey45",
"grey20", "black"),
na.translate = FALSE, name = "Civic space") +
theme_ngo_map(9)
plot_civicus_map
# Save the map
ggsave(plot_civicus_map, filename = here("output", "civicus_map.pdf"),
width = 5.5, height = 3, units = "in", device = cairo_pdf)
ggsave(plot_civicus_map, filename = here("output", "civicus_map.png"),
width = 5.5, height = 3, units = "in", dpi = 300, type = "cairo")
# ggsave(plot_civicus_map, filename = here("output", "civicus_map.tiff"),
# width = 5.5, height = 3, units = "in", type = "cairo", dpi = 600)
# https://darinchristensen.com/replication/JoD_Replication.zip
<- tribble(
dcjw_indexes ~barrier, ~question, ~question_clean,
"Entry", "q_2b", "NGO registration burdensome",
"Entry", "q_2d", "Registration barriers different if foreign funds involved",
"Funding", "q_3b", "Prior approval required\nfor foreign funds",
"Funding", "q_3c", "Foreign funds channeled\nthrough government",
"Funding", "q_3d", "Foreign funds restricted",
"Funding", "q_3e", "Foreign funds prohibited",
"Funding", "q_3f", "Foreign funds prohibted\nfor some types of NGOs",
"Advocacy", "q_4a", "NGOs restricted from politics",
"Advocacy", "q_4c", "Political barriers different\nif foreign funds involved"
)
# Original DCJW data
<- read_excel(here("data", "dcjw-ngo-laws", "DCJW_NGO_Laws.xlsx"))[,1:50] %>%
dcjw_raw select(-c(contains("source"), contains("burden"), contains("subset"), Coder, Date))
<- dcjw_raw %>%
dcjw_tidy gather(key, value, -Country) %>%
separate(key, c("question", "var.name"), 4) %>%
filter(!is.na(Country)) %>%
mutate(var.name = ifelse(var.name == "", "value", gsub("_", "", var.name))) %>%
spread(var.name, value) %>%
# Get rid of rows where year is missing and regulation was not imposed
filter(!(is.na(year) & value == 0)) %>%
# Some entries have multiple years; for now just use the first year
mutate(year = str_split(year, ",")) %>% unnest(year) %>%
group_by(Country, question) %>% slice(1) %>% ungroup() %>%
mutate(value = as.integer(value), year = as.integer(year)) %>%
# If year is missing but some regulation exists, assume it has always already
# existed (since 1950, arbitrarily)
mutate(year = ifelse(is.na(year), 1950, year))
<- dcjw_tidy %>%
dcjw_potential_panel filter(question %in% dcjw_indexes$question) %>%
expand(Country, question, year = min(.$year, na.rm = TRUE):2015)
<- dcjw_potential_panel %>%
dcjw_full_panel left_join(dcjw_tidy, by = c("Country", "question", "year")) %>%
# Bring most recent legislation forward
group_by(Country, question) %>%
mutate(value = zoo::na.locf(value, na.rm = FALSE)) %>%
ungroup() %>%
mutate(value = ifelse(is.na(value), 0, value)) %>%
mutate(value = case_when(
# Recode 0-2 questions as 0-1
$question == "q_3e" & .$value == 1 ~ 0.5,
.$question == "q_3e" & .$value == 2 ~ 1,
.$question == "q_3f" & .$value == 1 ~ 0.5,
.$question == "q_3f" & .$value == 2 ~ 1,
.$question == "q_4a" & .$value == 1 ~ 0.5,
.$question == "q_4a" & .$value == 2 ~ 1,
.TRUE ~ .$value
%>%
)) spread(question, value) %>%
mutate(
entry = rowSums(
select(., one_of(filter(dcjw_indexes, barrier == "Entry")$question))),
funding = rowSums(
select(., one_of(filter(dcjw_indexes, barrier == "Funding")$question))),
advocacy = rowSums(
select(., one_of(filter(dcjw_indexes, barrier == "Advocacy")$question)))
%>%
) # Lop off the ancient observations
filter(year >= 1980)
<- dcjw_full_panel %>% distinct(Country) %>% nrow()
n_countries
<- dcjw_full_panel %>%
df_barriers_summary group_by(Country, year) %>%
summarize_at(vars(one_of(dcjw_indexes$question)), list(~. > 0)) %>%
group_by(year) %>%
summarize_at(vars(-Country), list(~sum(.))) %>%
gather(question, value, -year) %>%
left_join(dcjw_indexes, by = "question") %>%
arrange(desc(value)) %>%
mutate(barrier = paste0("Barriers to ", str_to_lower(barrier))) %>%
mutate(question_clean = fct_inorder(question_clean, ordered = TRUE))
<- ggplot(
plot_entry filter(df_barriers_summary, barrier == "Barriers to entry"),
aes(x = year, y = value, color = question_clean, linetype = question_clean)
+
) geom_line(size = 0.5) +
expand_limits(y = c(0, 60)) +
scale_y_continuous(sec.axis =
sec_axis(~ . / n_countries,
labels = percent_format(accuracy = 1)),
expand = c(0, 0)) +
scale_colour_manual(values = c("black", "grey80", "grey50"), name = NULL) +
scale_linetype_manual(values = c("solid", "solid", "21"), name = NULL) +
guides(color = guide_legend(nrow = 2)) +
labs(x = NULL, y = "Number of countries") +
theme_ngo() +
theme(legend.justification = "left") +
facet_wrap(~ barrier)
<- ggplot(
plot_funding filter(df_barriers_summary, barrier == "Barriers to funding"),
aes(x = year, y = value, color = question_clean, linetype = question_clean)
+
) geom_line(size = 0.5) +
expand_limits(y = c(0, 35)) +
scale_y_continuous(sec.axis =
sec_axis(~ . / n_countries,
labels = percent_format(accuracy = 1)),
expand = c(0, 0),
breaks = seq(0, 35, 5)) +
scale_colour_manual(values = c("black", "grey80", "grey50", "black", "grey80"), name = NULL) +
scale_linetype_manual(values = c("solid", "solid", "solid", "21", "21"), name = NULL) +
guides(color = guide_legend(nrow = 3),
linetype = guide_legend(nrow = 3)) +
labs(x = NULL, y = "Number of countries") +
theme_ngo() +
theme(legend.justification = "left") +
facet_wrap(~ barrier)
<- ggplot(
plot_advocacy filter(df_barriers_summary, barrier == "Barriers to advocacy"),
aes(x = year, y = value, color = question_clean)
+
) geom_line(size = 0.5) +
expand_limits(y = c(0, 25)) +
scale_y_continuous(sec.axis =
sec_axis(~ . / n_countries,
labels = percent_format(accuracy = 1)),
expand = c(0, 0)) +
scale_colour_manual(values = c("black", "grey80"), name = NULL) +
guides(color = guide_legend(nrow = 1)) +
labs(x = NULL, y = "Number of countries") +
theme_ngo() +
theme(legend.justification = "left") +
facet_wrap(~ barrier)
When loading the V-Dem CSV, readr::read_csv()
chokes on a bunch of rows for whatever reason and gives a ton of warnings, but it still works. Loading the Stata version of V-Dem doesn’t create the warnings, but it’s slower and it results in the same data. So I just load from CSV and make sure it has the right number of rows and columns in the end.
# V-Dem data
<- read_csv(here("data", "Country_Year_V-Dem_Extended_CSV_v8",
vdem_raw "V-Dem-CY+Others-v8.csv"))
# Check that the data loaded correctly
%>%
vdem_raw check_that(n_rows = nrow(.) == 26537, n_cols = ncol(.) == 4641) %>%
summary() %>%
mutate(expression = expression %>% map_chr(pandoc.verbatim.return)) %>%
pandoc.table()
name | items | passes | fails | nNA | error | warning | expression |
---|---|---|---|---|---|---|---|
n_rows | 1 | 1 | 0 | 0 | FALSE | FALSE | nrow(.) == 26537 |
n_cols | 1 | 1 | 0 | 0 | FALSE | FALSE | ncol(.) == 4641 |
<- vdem_raw %>%
vdem_small select(country_name, year, ccode = COWcode, v2x_regime, v2csreprss, v2cseeorgs) %>%
# Autocracy = closed autocracies and electoral autocracies with V-Dem's RoW index
mutate(autocracy = v2x_regime <= 1,
csre = v2csreprss + v2cseeorgs)
<- vdem_small %>%
generally_autocracies filter(year > 1980, year <= 2018) %>%
group_by(ccode) %>%
summarize(prop_autocracy = sum(autocracy, na.rm = TRUE) / n(),
generally_autocracy = prop_autocracy >= 0.5)
<- vdem_small %>%
df_csre_summary filter(!is.na(autocracy), year >= 1980, year <= 2018) %>%
left_join(generally_autocracies, by = "ccode") %>%
group_by(year, generally_autocracy) %>%
nest() %>%
mutate(cis = data %>% map(~ mean_cl_normal(.$csre))) %>%
unnest(cis) %>%
mutate(fake_facet_title = "Civil society regulatory environment",
generally_autocracy = factor(generally_autocracy, levels = c(FALSE, TRUE),
labels = c("Democracies", "Autocracies"), ordered = TRUE))
<- ggplot(df_csre_summary, aes(x = year, y = y)) +
plot_csre geom_ribbon(aes(ymin = ymin, ymax = ymax, fill = generally_autocracy), alpha = 0.2) +
geom_line(aes(color = generally_autocracy), size = 0.5) +
annotate(geom = "text", x = 2013, y = -2.2, hjust = "right", size = 2,
label = "Larger values = more open civil society") +
scale_colour_manual(values = c("black", "grey75"), name = NULL) +
scale_fill_manual(values = c("black", "grey75"), name = NULL) +
scale_linetype_manual(values = c("solid", "solid", "21")) +
labs(y = "Average CSRE", x = NULL) +
theme_ngo() +
theme(legend.justification = "left") +
facet_wrap(~ fake_facet_title)
<-
barriers_summary + plot_funding) / (plot_advocacy + plot_csre)) &
((plot_entry theme(legend.text = element_text(size = rel(0.8)),
axis.title.y = element_text(margin = margin(r = 3), size = rel(0.8)),
legend.box.margin = margin(t = -0.5, unit = "lines"))
barriers_summary
ggsave(barriers_summary, filename = here("output", "fig-barriers-summary.pdf"),
width = 5.5, height = 4.5, units = "in", device = cairo_pdf)
ggsave(barriers_summary, filename = here("output", "fig-barriers-summary.png"),
width = 5.5, height = 4.5, units = "in", dpi = 300, type = "cairo")
# ggsave(barriers_summary, filename = here("output", "fig-barriers-summary.tiff"),
# width = 5.5, height = 4.5, units = "in", type = "cairo", dpi = 600)
<- read_csv(here("data", "predicted-donors",
predicted_oda "predicted_h1_barriers_individual.csv"))
<- read_csv(here("data", "predicted-donors",
predicted_contention "predicted_h2_barriers_individual.csv"))
<- predicted_oda %>%
df_oda_predict gather(barrier, barrier_value, advocacy_within) %>%
group_by(cowcode, barrier_value, barrier) %>%
summarise_at(vars(predicted), list(~mean(.))) %>%
mutate(fake_facet_title = "Barriers to advocacy and aid")
<- df_oda_predict %>%
df_oda_predict_mean group_by(barrier, barrier_value) %>%
summarise(predicted = mean(predicted)) %>%
mutate(cowcode = 1) # Fake country so the line plots
<- ggplot(df_oda_predict,
plot_oda_predict aes(x = barrier_value, y = expm1(predicted), group = cowcode)) +
geom_vline(xintercept = 0, colour = "black", size = 0.5) +
geom_smooth(method = "lm", size = 0.1, alpha = 0.1,
colour = "grey30") +
geom_smooth(data = df_oda_predict_mean, size = 1.5,
method = "lm", colour = "black") +
labs(x = "Change from average number of anti-advocacy barriers",
y = "Predicted ODA in the following year") +
scale_y_continuous(labels = dollar) +
theme_ngo() +
facet_wrap(~ fake_facet_title)
# Inverse logit, with the ability to account for adjustments
# via http://stackoverflow.com/a/23845527/120898
<- function(f, a) {
inv_logit <- (1 - 2 * a)
a * (1 + exp(f)) + (exp(f) - 1)) / (2 * a * (1 + exp(f)))
(a
}
<- predicted_contention %>%
df_contention_predict gather(barrier, barrier_value, advocacy_within) %>%
group_by(cowcode, barrier_value, barrier) %>%
summarise_at(vars(predicted), list(~mean(.))) %>%
mutate(predicted_fixed = inv_logit(predicted, a = 0.001)) %>%
mutate(fake_facet_title = "Barriers to advocacy\nand contentiousness of aid")
<- df_contention_predict %>%
df_contention_predict_mean group_by(barrier, barrier_value) %>%
summarise(predicted = mean(predicted)) %>%
mutate(cowcode = 1, # Fake country so the line plots
predicted_fixed = inv_logit(predicted, a = 0.001))
<- ggplot(df_contention_predict,
plot_contention_predict aes(x = barrier_value, y = predicted_fixed, group = cowcode)) +
geom_vline(xintercept = 0, colour = "black", size = 0.5) +
geom_smooth(method = "lm", size = 0.1, alpha = 0.1,
colour = "grey30") +
geom_smooth(data = df_contention_predict_mean, size = 1.5,
method = "lm", colour = "black") +
labs(x = "Change from average number of anti-advocacy barriers",
y = "Predicted proportion of\ncontentious aid in the following year") +
scale_y_continuous(labels = percent_format(accuracy = 1)) +
theme_ngo() +
facet_wrap(~ fake_facet_title)
<-
plot_predict_both + plot_contention_predict + plot_layout(ncol = 2)) &
(plot_oda_predict theme(axis.title.x = element_text(size = rel(0.8)),
axis.title.y = element_text(margin = margin(r = 3), size = rel(0.8)))
plot_predict_both
ggsave(plot_predict_both, filename = here("output", "fig-predict-both.pdf"),
width = 5.5, height = 2.5, units = "in", device = cairo_pdf)
ggsave(plot_predict_both, filename = here("output", "fig-predict-both.png"),
width = 5.5, height = 2.5, units = "in", dpi = 300, type = "cairo")
# ggsave(plot_predict_both, filename = here("output", "fig-predict-both.tiff"),
# width = 5.5, height = 2.5, units = "in", type = "cairo", dpi = 600)