1 Conflict Across South Sudan

ACLED’s conflict event data from South Sudan dates from July 14, 2011. As of April 14, 2022 it includes 8,296 unique conflict events. Using R, it is relatively straightforward to generate a map of South Sudan that plots these conflict events without switching across software platforms.

The code to make these maps is embedded in the code buttons. If you want a comprehensive guide to generating maps in R check out https://geocompr.robinlovelace.net/. The authors, Robin Lovelave, Jakub Nowosad, and Jannes Muenchow, deserve tons of credit for making an accessible, open-source guide to analyzing, visualizing, and modeling geographic data in the R statistical programming language.

Point data is useful to see how the points are dispersed across space, but one of the challenges of points is overplotting. The image on the left below shows the points as geocoded by ACLED. I added some opacity to help with the overplotting, but when you have many thousands of points it’s hard to show their exact locations. Another trick is to add jitter - or random noise. Are the exact locations that important? With conflict data, probably not. Many of these points are just administrative center points because there aren’t data collectors attending live conflicts to ping their exact locations. In this case, adding jitter allows us to see more of the points and get a better sense of where conflict concentrates.

#A map of all conflict events plotted
map_points <- ggplot(data = neighbors_v1)+
  geom_sf(fill = "#F8F0E3") +
    geom_sf_label(data = neighbors_v1
                , aes(label = shapeName)) +
  geom_sf(data = states,
          color = "white") +
  geom_sf(data = events_sf
          , aes(color = event_type)
          , alpha = .3)+
  geom_sf_text(data = states
                , aes(label = shapeName)
                , color = "#565656") +
  geom_sf(data = SSudan
          , color = "#000000"
          , width = 4
          , fill = NA) +
  geom_sf(data = places_SS)+
  geom_sf_text(data = places_SS
                , aes(label = NAME_ID)
                , nudge_x = .2
                , nudge_y = -.1
                , check_overlap = T
                , color = "#000000")+
  geom_sf(data = water
          , color = "steel blue"
          , width = 4) +
  geom_sf(data = lakes
          , color = "steel blue"
          , width = 10)+
  coord_sf(xlim = c(bbox[[1]], bbox[[3]])
           , ylim = c(bbox[[2]], bbox[[4]]))+
  theme.plot()+
  labs(title = "South Sudan"
         , subtitle = "Conflict Events as geocoded (2011-2022)"
         , caption = "Author: Brian Calhoon; Sources: ACLED, rgeoboundaries, rnaturalearth"
       , x = ""
       , y = "")+
  theme(axis.text = element_blank())

#A map of the country with all conflict events plotted and jittered
map_jitter <- ggplot(data = neighbors_v1)+
  geom_sf(fill = "#F8F0E3") +
    geom_sf_label(data = neighbors_v1
                , aes(label = shapeName)) +
  geom_sf(data = states,
          color = "white") +
  geom_sf(data = st_jitter(events_sf, amount = 500) #Adding in the jittering to see all the points
          , aes(color = event_type)
          , alpha = .3)+
  geom_sf_text(data = states
                , aes(label = shapeName)
                , color = "#565656") +
  geom_sf(data = SSudan
          , color = "#000000"
          , width = 4
          , fill = NA) +
  geom_sf(data = places_SS)+
  geom_sf_text(data = places_SS
                , aes(label = NAME_ID)
                , nudge_x = .2
                , nudge_y = -.1
                , check_overlap = T
                , color = "#000000")+
  geom_sf(data = water
          , color = "steel blue"
          , width = 4) +
  geom_sf(data = lakes
          , color = "steel blue"
          , width = 10)+
  coord_sf(xlim = c(bbox[[1]], bbox[[3]])
           , ylim = c(bbox[[2]], bbox[[4]]))+
  theme.plot()+
  labs(title = "South Sudan"
         , subtitle = "Conflict Events Jittered (2011-2022)"
         , caption = "Author: Brian Calhoon; Sources: ACLED, rgeoboundaries, rnaturalearth"
       , x = ""
       , y = "")+
  theme(axis.text = element_blank())


patch <- patchwork::wrap_elements(map_points - map_jitter)

patch
<<<<<<< HEAD Conflict events in South Sudan since its inception as a country. ======= Conflict events in South Sudan since its inception as a country viewed as points. >>>>>>> 18589c716ac5059b78bece630e4e4f44acde1314

Figure 1.1: Conflict events in South Sudan since its inception as a country viewed as points.

Points aren’t the only way to view data. By aggregating data into gridded shapes or administrative units it can help show the differences in how common conflict occurs in a given administrative boundary (figure on the right) or a grid laid over the country (figure on the left).

#Same map but rasterized

raster_template <- rast(ext(SSudan), resolution = 20000,
                       crs = st_crs(events_sf)$wkt)

raster1 <- rasterize(vect(events_sf)
                    , raster_template
                    ,  fun = "length")

raster2 <- terra::as.data.frame(raster1
                                , xy=TRUE
                                , cells = TRUE) %>% 
  select(cell, x, y, Events = lyr.1) %>% 
  mutate(events_logged = log(Events))


map_raster <- ggplot(data = neighbors_v1)+
  geom_sf(fill = "#F8F0E3") +
  geom_sf_label(data = neighbors_v1
                , aes(label = shapeName)) +
  geom_sf(data = states,
          color = "white") +
  geom_tile(data = raster2 #the raster object
          , aes(x = x
                , y = y
                , fill = events_logged))+
  geom_sf_text(data = states
               , aes(label = shapeName)
               , color = "#565656") +
  geom_sf(data = SSudan
          , color = "#000000"
          , size = 1
          , fill = NA) +
  geom_sf(data = places_SS)+
  geom_sf_text(data = places_SS
               , aes(label = NAME_ID)
               , nudge_x = .2
               , nudge_y = -.1
               , check_overlap = T
               , color = "#000000")+
  geom_sf(data = water
          , color = "steel blue") +
  geom_sf(data = lakes
          , color = "steel blue")+
  coord_sf(xlim = c(bbox[[1]], bbox[[3]])
           , ylim = c(bbox[[2]], bbox[[4]]))+
  theme.plot()+
  scale_fill_gradient(low = "#ffc6c4"
                      , high = "#672044"
                      , trans =  "log10")+
  labs(title = "South Sudan"
       , subtitle = "Logged-count of conflict events,\n 20 km grids (2011-2022)"
       , caption = "Author: Brian Calhoon; Sources: ACLED, rgeoboundaries, rnaturalearth, terra"
       , x = ""
       , y = "")+
  theme(axis.text = element_blank())

#choropleth map by districts
choro <- st_join(districts, events_sf, left = T) %>% 
  group_by(shapeName) %>% 
  summarize(attacks = log1p(sum(!is.na(event_id_cnty))))

map_choro <- ggplot(data = neighbors_v1)+
  geom_sf(fill = "#F8F0E3") +
  geom_sf(data = choro
                  , aes(fill = attacks)
          , color = "white") +
  #geom_sf_label(data = neighbors_v1
  #              , aes(label = shapeName)) +
   geom_sf(data = water
          , color = "steel blue") +
  geom_sf(data = lakes
          , color = "steel blue")+
  coord_sf(xlim = c(bbox[[1]], bbox[[3]])
           , ylim = c(bbox[[2]], bbox[[4]]))+
  theme.plot()+
  scale_fill_gradient(low = "#ffc6c4"
                      , high = "#672044"
                      , trans =  "log10")+
  labs(title = "South Sudan"
       , subtitle = "Logged-count of conflict events\nby district (2011-2022)"
       , caption = "Author: Brian Calhoon; Sources: ACLED, rgeoboundaries, rnaturalearth"
       , x = ""
       , y = "")+
  theme(axis.text = element_blank())


patch2 <- patchwork::wrap_elements(map_raster - map_choro)

patch2
Conflict events in South Sudan since its inception as a country aggregated.

Figure 1.2: Conflict events in South Sudan since its inception as a country aggregated.

Another useful approach when dealing with geography and change over time is to facet by years. For this map I switched to the tmap package. Martijn Tennekes and Jakub Nowosad wrote a book on making maps in tmap, https://r-tmap.github.io/tmap-book/, and it’s amazing how intuitive it is.

a <- st_join(districts, events_sf, left = T) %>% 
  group_by(shapeName, year) %>% 
  summarize(attacks = log1p(sum(!is.na(event_id_cnty))))

tmap::tmap_mode("plot")+
  tmap::tm_shape(a
                 , is.master = T) +
  tmap::tm_polygons("attacks"
                    , title = "ACLED\nevents (logged)"
                    , border.col = "grey"
                    , style = "cont") +
  tmap::tm_facets("year") + 
  tmap::tm_shape(st_union(a))+
  tmap::tm_borders(col = "black")+
  tmap::tm_layout(main.title = "Conflict Concentration by Year, 2011 - 2021"
<<<<<<< HEAD
                  , legend.outside.position = "bottom", legend.position = c(0, 0)) #.8, 1.1
Conflict varies over time across South Sudan. With events concentrating over time in Central Equatoria. ======= , legend.outside.position = "bottom", legend.position = c(.8, 1.1))
Conflict varies over time across South Sudan. With events concentrating over time in Central Equatoria. >>>>>>> 18589c716ac5059b78bece630e4e4f44acde1314

Figure 1.3: Conflict varies over time across South Sudan. With events concentrating over time in Central Equatoria.

<<<<<<< HEAD

2 An interactive map

Below is a map that you can explore for yourself. If you hover over one of the dots a label will appear, and if you click on it additional information about the event will appear.

tmap::tmap_mode("view")
tmap::tm_basemap(c(StreetMap = "OpenStreetMap",
             TopoMap = "OpenTopoMap")) +
  tmap::tm_tiles(c(TonerHybrid = "Stamen.TonerHybrid"))+
  tmap::tm_shape(events_sf, is.master = TRUE) + 
  tmap::tm_dots(col = "event_type"
          , id = "event_type"
          , popup.vars=c("Event date" = "event_date"
                         , "Sub-event Type"="sub_event_type"
                         , "Actors"= "actor1"
                         , "Actors" = "actor2"
                         , "Fatalities" = "fatalities"
                         , "Sources" = "source")
          , popup.format=list() 
          , group = "Events"
          , jitter = .2
          , alpha = .3
          , palette = my_pal)

Now that we have a count of the types of conflict, let’s look at the which types are occurring in which states.

#Here we're going to map 6 plots. So, I iterate over a list of six ggplots using purr::map()

#My type vector
type <- unique(events$event_type)

#My function for filtering by type
type_fun <- function(x){
  events %>% 
    filter(event_type == {{x}}) %>% 
    group_by(admin1, event_type) %>% 
    summarize(Count = n())
}
=======

R also allows us to animate this data over time on a map.

map_anim <- ggplot(data = neighbors_v1)+
  geom_sf(fill = "#F8F0E3") +
    geom_sf_label(data = neighbors_v1
                , aes(label = shapeName)) +
  geom_sf(data = states,
          color = "white") +
  geom_sf_text(data = states
                , aes(label = shapeName)
                , color = "#565656") +
  geom_sf(data = SSudan
          , color = "#000000"
          , size = .75
          , fill = NA) +
  geom_sf(data = places_SS)+
  geom_sf_text(data = places_SS
                , aes(label = NAME_ID)
                , nudge_x = .2
                , nudge_y = -.1
                , check_overlap = T
                , color = "#000000")+
  geom_sf(data = events_sf #Adding in the jittering to see all the points
          , aes(geometry = st_jitter(geometry, amount = 500)
          ,  color = event_type)
          , alpha = .3)+
  geom_text(data = events_sf
            , aes(x = min(st_coordinates(geometry)[,1])
                  , y = max(st_coordinates(geometry)[,2])
                  , label = paste0("Year: ",{as.integer(year)}))
            , size = 20
            , color = "#565656"
            , hjust = 0
            , vjust = 1)+
  coord_sf(xlim = c(bbox[[1]], bbox[[3]])
           , ylim = c(bbox[[2]], bbox[[4]]))+
  theme.plot()+
  labs(title = "South Sudan"
         , subtitle = "Conflict Events Jittered (2011-2022)"
         , caption = "Author: Brian Calhoon; Sources: ACLED, rgeoboundaries, rnaturalearth"
       , x = ""
       , y = "")+
  theme(axis.text = element_blank()) +
  gganimate::transition_time(events_sf$year) +
  shadow_mark(color = "#565656"
              , size = .75
              , alpha = .1)
>>>>>>> 18589c716ac5059b78bece630e4e4f44acde1314

num_years <- max(events_sf$year) - min(events_sf$year) +1

SS_ACLED_anim <-  gganimate::animate(map_anim
                , width = 800
                , height = 700
                , nframes = num_years
                , fps = 1)

anim_save("SS_ACLED_anim.gif")

SS_ACLED_anim