Tidy Tuesday United Nations

The Tidy Tuesday data for this week is the data about votes in the United Nations General Assembly. Three tables show how each country voted in all assemblies from 1946 to 2019, it also informs what each voted issue was about.

I’ll show two visualizations of the data. First, we will show some light on how much consensus there is for each type of issue. And in the second visualization we will build a network of alliances based on how many times pairs of countries voted the same way.


Load data

dat_list <- tidytuesdayR::tt_load('2021-03-23')
##  Downloading file 1 of 3: `unvotes.csv`
##  Downloading file 2 of 3: `roll_calls.csv`
##  Downloading file 3 of 3: `issues.csv`
dat <- as.data.table(dat_list$unvotes)
dat <- dat[as.data.table(dat_list$issues), on = "rcid"]
dat <- dat[as.data.table(dat_list$roll_calls), on = "rcid"]

# numeric variable pro_vote to count votes more easily
dat[, pro_vote := ifelse(vote == 'yes', 1,0)]
# number of countries
n_countries <- length(dat[, unique(country)])-1

According to Wikipedia, some decisions in the General Assembly are defined by two-thirds majority while others are by simple majority. Therefore, I’ll consider a matter as approved if it has simple majority of ‘yes’ and ‘no’ votes, I’ll consider ‘abstain’ votes as absence in the Assembly. To investigate consensus on different matters we look at the distributions of votes with the majority on different occasions. Putting it simply: if there are higher rates of votes with the majority for a given matter, this means there is usually more consensus in the Assembly for that matter (it is more commmon for countries to agree on that given matter).

# make a quorum variable from non-abstain votes on each issue
dat[vote != 'abstain', quorum := .N, by = unres]

# make a "issue pass" varible to map which issues were approved
dat[, issue_pass := fifelse(sum(pro_vote, na.rm = T) > (quorum/2),1,0), by = unres]
# same as above but as factor
dat[, f_issue_pass := factor(issue_pass, c(0, 1), c("Denied", "Passed"))]
# make variable mapping which countries voted with the majority in each issue
dat[, majority := fifelse(
      (f_issue_pass == "Passed" & vote == "yes") | (f_issue_pass == "Denied" & vote == "no"),


    .(majority = sum(majority, na.rm = T)),
    by = .(unres, issue)][majority < 500] %>%
   ggplot(aes(issue, majority, fill = issue))+
      geom_jitter(width = .2, colour = "grey70")+
      geom_boxplot(width = .4, alpha = .7, size = 1) +
      stat_summary(fun = mean, geom = 'point',
                   shape = 23, fill = 'white')+
      scale_x_discrete(labels = c("Arms \ncontrol",
              "Economic \ndevelopment",
              "Human \nrights",
              "Nuclear \nweapons",
      guides(fill = F) +
   labs(title = "Votes in consesus for issue type ",
        y = "Majority (n votes)",
        x = "Issue")


For the network representation we first choose some countries. Then, the overall idea is to make a matrix of joint votes and construct the graph representation.

countries <- c( 
      "South Africa",
      "United States",
      "United Kingdom",
# drop some unused columns
dat[, `:=` (importantvote = NULL,
            amend = NULL,
            para = NULL,
            short = NULL,
            descr = NULL)]
# make empty matrix
adj_mat <- matrix(rep(0,length(countries)^2),
       nrow = length(countries), 
       dimnames = list(countries,countries))

#function to increment link between countries every joint vote
make_link <- function(from, to){
   adj_mat[from,to] <<- adj_mat[from,to] + 1
   adj_mat[to, from] <<- adj_mat[to,from] + 1

# function to apply make_link to each resolution data.table
link_over_dt <- function(dt){
   yes <- dt[vote == 'yes', country]
   no <- dt[vote == 'no', country]
   abstain <- dt[vote == 'abstain', country]
   if (length(yes)>1) { 
         yes <- data.frame(from = t(combn(yes,2))[,1],
                           to = t(combn(yes,2))[,2])
         Map(make_link, yes$from, yes$to)
   if (length(no)>1) { 
         no <- data.frame(from = t(combn(no,2))[,1],
                          to = t(combn(no,2))[,2])
         Map(make_link, no$from, no$to)
   if (length(abstain)>1) { 
         abstain <- data.frame(from = t(combn(abstain,2))[,1],
                               to = t(combn(abstain,2))[,2])
         Map(make_link, abstain$from, abstain$to)

# apply to data.tables to increment matrix
dat[country %in% countries, link_over_dt(.SD), by = unres]

Now I make a scaled matrix of votes together to facilitate comparison among country pairs. So 1 is actually the the value for the pair that voted most times together.

adj_mat_prop <- adj_mat/ max(adj_mat)

Make graph:

un_graph <- as_tbl_graph(adj_mat_prop, directed = F) %E>% 
   filter(weight > .5) %>%
   mutate(weight = weight*3) %>% 
   ggraph(layout = "kk")+
   geom_edge_link0(aes(edge_width = weight,
                       edge_alpha = weight/3),
                   edge_colour = "#00acee")+
   coord_cartesian(clip = "off")+
   guides(edge_colour = F,
          edge_width = F,
          edge_alpha = F)

Add flags:

add_flag <- function(p, country){
   flag <- readPNG(paste0(here(),"/figs/",country,".png"), native = T)
   flag_x <- as.data.table(un_graph$data)[name == country, x]
   flag_y <- as.data.table(un_graph$data)[name == country, y]
   p+annotation_raster(flag, flag_x -.15, flag_x +.15, 
                        flag_y-.15, flag_y+.15)

un_graph <- Reduce(add_flag, countries,init = un_graph)

Add UN logo.

un_logo <- readJPEG(paste0(here(),"/figs/UN.jpg"), native = T)
un_graph +
   annotation_raster(un_logo, 1.3, 2, -1.3, -.5)+
   annotate("text", x = -1.5, y = -1.3,
            label = "Flag icons by Freepik ", size = 3)

There we have it! I am showing only links between countries that voted together at least half the number of times the pair that agreed more. It is nice to see the network shows the known polarization between USA and China, that Latin America seems to be pretty tight and that the long-standing alliance between Israel and USA also captured. A interesting fact is that not all G8 is always in agreement. The most curious feature of the network, I think, is Russia placed right in the center of the Latin-american cluster.

See you in the next post!

Mateus Silvestrin
Mateus Silvestrin

PhD in Neuroscience and Cognition. My thesis was about the neural correlates of time perception, developed in the Timing Lab at the Federal University of ABC. I am currently a post-doc (FAPESP grant) at the Social and Cognitive Neuroscience Lab at the Mackenzie Presbyterian University, where I study associations between affect and moral judgement. I also colaborate with the Developmental, Affective and Social Neuroscience Lab.