Visualization

Trust in Arab Government vs. Trust in Arab Armies

A short tutorial on multi-panel or faceted plotly graphics in R, without ggplotly(), with data from the Arab Barometer III survey project.

The Arab Barometer Wave III survey includes a number of questions about trust in different government institutions. Respondents were given the following prompt: “I will name a number of institutions, and I would like you to tell me to what extent you trust each of them.” In each of the twelve states included in the survey, the public was significantly more likely to trust “the armed forces (the army)” than to trust “the government (the cabinet).”

In some states, like in Kuwait, for example, the level of trust in both institutions was relatively high. But in many other states, the difference in the level of trust between both institutions was extreme. For example, in Egypt, only 21% stated that they trusted the government to a “medium extent” or “great extent,” but 91% stated that they trusted the army. Likewise, in Lebanon, only 14% stated that they trusted the government, but 81% stated that they trusted the army.

I could think of a few hypotheses that might plausibly explain variation in support for each institution across these countries, but rather than write an article on the topic of Arab confidence in national armed forces, I’d like to use this data to explore some features of the interface between R and plotly – mainly faceting and including chloropleth maps.

Example Plot

Making the Plot

I’m using pre-summarized data, which can be downloaded here, because most real-life sample surveys rely on complex design elements, for example, estimates that need to be weighted, or standard errors that need to account for clustering. Few vizualization options in R – ggplot and plotly included – easily accomodate complex samples, so it is usually necessary to work with pre-summarized data, for example, estimates and standard errors calculated with Thomas Lumley’s excellent survey package.

The basic syntax of a plotly plot is to use the plot_ly() function to make the plot, and then the layout() function to apply additional aesthetics like titles and margins. However, it’s not always clear which options go in which functions, and plotly’s R API documentation can be a little confusing, because so many examples rely on ggplot. Editing specific plot elements can also be difficult, because plotly’s JSON format needs to be worked with in R though a number of nested lists. The plot here has three pannels, and the process of getting to the final plot can be broken down into about five sequential steps:

  1. Defining some global options, like fonts, margins, colors, and map projections.
  2. Plot the first frame: I mapped trust in government first.
  3. Plot the second frame: I plotted points with confidence intervals second.
  4. Plot the third frame: I mapped trust in armies last.
  5. Bring the three plots together, applying some additional aesthetics.

Global Options

library(plotly)
Error in library(plotly): there is no package called 'plotly'
library(magrittr)
library(reshape2)

# get the data
df<-read.csv("http://rnotr.com/assets/files/trust_gov_army.csv", header=TRUE)

# line property for between countries
l <- list(color = toRGB("white"), width = .5)
Error in eval(expr, envir, enclos): could not find function "toRGB"
# basic map aesthetics
g <- list(
  scope = 'world', # other options are continents
  showframe = F, # i.e., map border
  showland = T,
  landcolor = toRGB("grey90") # for countries with no data
)
Error in eval(expr, envir, enclos): could not find function "toRGB"
# additional map properties
g1 <- c(
  g, # note that we're adding to the above list
  resolution = 50,
  showcoastlines = T,
  showcountries = T,
  countrycolor = toRGB("white"),
  coastlinecolor = toRGB("white"),
  projection = list(type = 'Mercator'),
  # zoom to MENA
  list(lonaxis = list(range = c(-17, 60))),
  list(lataxis = list(range = c(3, 42))),
  list(domain = list(x = c(0, 1), y = c(0, 1)))
)
Error in eval(expr, envir, enclos): object 'g' not found
# palette, fonts, margins, etc.
pal<-c("#FFFFFF", "#45B29D") # low and high values for greens
m<-list(l = 25, r=25, b = 25, t = 25) # margins
# three fonts lists: for plot text, title text, and axis text
f <- list(family = "", size = 10, color = toRGB("grey20"))
Error in eval(expr, envir, enclos): could not find function "toRGB"
tf <- list(family = "", size = 16, color = toRGB("grey20"))
Error in eval(expr, envir, enclos): could not find function "toRGB"
at<-list(family = "", size = 12, color = toRGB("grey20"))
Error in eval(expr, envir, enclos): could not find function "toRGB"

Trust in Government

# first the plot
# note that values are mapped to 'z' not 'x' or 'y'
# note that line breaks use '<br>' rather than '\n'
# note the 'geo' argument at the end of plot_ly; this needs to be different from the other map
p <- plot_ly(df, z = trust_gov, locations = CODE, type = 'choropleth', locationmode = 'country abbreviations',
             text = paste("Country: ", NAME, "<br>Trust government to medium<br>or great extend: ",round(trust_gov,1),"%"), hoverinfo = "text",
             color = trust_gov, colors = pal, marker = list(line = l), autocolorscale=FALSE, zmin=0, zmax=100,
             colorbar = list(title = 'Mean', outlinecolor=toRGB("grey90")), showscale=FALSE, geo = 'geo') %>%
# add layout
# note reference to map attributes defined previously
  layout(title = 'Trust in Government', geo = g1, font = f, titlefont=tf, margin=m) 
Error in eval(expr, envir, enclos): could not find function "plot_ly"

Points and Error Bars

# order data frame by difference in trust between institutions
df<-df[with(df, order(-(trust_gov-trust_army))), ]
# add first trace, which is trust in government
# note error bars defined in list 'error_x'
p2 <- plot_ly(df, y = NAME, x = trust_gov, error_x = list(array = 1.96*se_trust_gov, color="#45B29D"),
              mode = "markers",  text = paste("Estimate and 95% CI for trust in ", NAME, "'s government: ",
              round(trust_gov,1),"&plusmn;",round(1.96*se_trust_gov,1),"%"), hoverinfo = "text",
              marker = list(color="#45B29D")) 
Error in eval(expr, envir, enclos): could not find function "plot_ly"
# add second trace, which is trust in army
# use a different color for army (orange)
p2.5  <- add_trace(p2, y = NAME, x = trust_army, error_x = list(array = 1.96*se_trust_army, color="#E27A3F"),
          text = paste("Estimate and 95% CI for trust in ", NAME, "'s army: ",round(trust_army,1),"&plusmn;",
          round(1.96*se_trust_army,1),"%"), hoverinfo = "text", mode="markers", marker = list(color="#E27A3F")) %>%
# add layout
layout(title = "95% Confidence Intervals", font = f, titlefont=tf, xaxis=list(title="Percent trusting institution to medium or great extent"), yaxis=list(title=""), 
         margin = m, showlegend = FALSE) 
Error in eval(expr, envir, enclos): could not find function "add_trace"

Trust in Army

# same as trust in government but with orange color palette
# note different 'geo' in plot_ly
pal3<-c("#FFFFFF", "#E27A3F")
p3 <- plot_ly(df, z = trust_army, locations = CODE, type = 'choropleth', locationmode = 'country abbreviations',
             text = paste("Country: ", NAME, "<br>Trust army to medium or <br>great extend: ",round(trust_army,1),"%"), hoverinfo = "text",
             color = trust_gov, colors = pal3, marker = list(line = l), autocolorscale=FALSE, zmin=0, zmax=100,
             colorbar = list(title = 'Mean', outlinecolor=toRGB("grey90")), showscale=FALSE, geo = 'geo1')  %>%
  layout(title = 'Trust in Army', geo = g1, font = f, titlefont=tf, margin=m)  
Error in eval(expr, envir, enclos): could not find function "plot_ly"

Combining the Panels

First we combine the two maps into a single subplot, and then we create a second subplot by combining the points and error bars with the first subplot of maps. Note that when creating subplots, the previous layouts are overwritten. So, we have to apply a new layout to the final plot. I provide a title with a link to the source data, with a basic HTML tag. I suppress the legend, which is arguably a bad idea, but I’m going to rely on the hovertext and the fact that colors codes are consistent across the plots. Because my previous layouts were overwritten, including plot and axis titles, I have to add these again. But, the catch is: a plot can only have one title. So, I have to add subtitles for each of the subplots as plot annotations. Annotations take an x and y value, which are percents away from the anchor points, which in this plot, is the bottom-left corner; it took some trial and error to get these in appropriate positions. Finally, my left margin is greater than my right margin, to keep country names from being clipped. Append %>% plotly_POST("Trust in Government vs. Trust in Army in Twelve Arab States") to post to plot.ly.

s1 <- subplot(plotly_build(p), plotly_build(p3), nrows = 2, margin = 0.05) 
s2 <- plotly_build(subplot(p2.5, s1, nrows = 1, margin = 0.05))
s2 %>% layout(title="Trust in Government vs. Trust in Army in Twelve Arab States:<br>Results from the <a href=\"http://www.arabbarometer.org\">Arab Barometer Wave III</a> Survey", 
  titlefont = tf, showlegend=FALSE, margin = list(l = 80, r=30, b = 60, t = 90),
  xaxis=list(title="Percent trusting institution to medium or great extent"),font=at) %>% 
  layout(annotations = list(
    list(x = .69, y = .47, 
         xref = "paper", yref = "paper", 
         xanchor = "left", yanchor = "bottom",
         ax = 0, ay = 0,
         text = "Trust in Government (above)",
         font = at,
         showarrow=FALSE),
    list(x = .71, y = -.08, 
         xref = "paper", yref = "paper", 
         xanchor = "left", yanchor = "bottom",
         ax = 0, ay = 0,
         text = "Trust in Army (above)",
         font = at,
         showarrow=FALSE)
  )) 

Dialogue & Discussion