5 min read

Tidy Tuesday Shiny App: Nuclear Explosions

1 Introduction

It’s been a long time since my last post, but I’m here again: this time with a Shiny App. Shiny is defined as a “Web Application Framework for R”.

From ?shiny:

Shiny makes it incredibly easy to build interactive web applications with R. Automatic “reactive” binding between inputs and outputs and extensive prebuilt widgets make it possible to build beautiful, responsive, and powerful applications with minimal effort.

Although you will write them in R, Shiny Apps are a whole new world. One word in the definition above deserves special attention, specially if you don’t have experience in web development: reactive.

Reactivity: The key idea of reactive programming is to specify a graph of dependencies so that when an input changes, all related outputs are automatically updated. Also, check this 2 minutes video.

It turns out reactivity is a fundamental concept in Shiny development. In fact, most powerful shiny apps relies heavily on this concept. Although mastering the concept will take some time, investing time and effort to grasp its foundations will pay off soon.

2 The data

2.1 Brief description

The data is from Stockholm International Peace Research Institute and shows the annual numbers of nuclear tests conducted since 1945. There are 16 variables where we can find, among others, the country and region where the tests where performed. We can also find an estimate of the lower and upper yield in kilotones of TNT, the purpose of the tests (military exercise, peaceful nuclear explosion, weapons development program, etc.), and additional information.

While the list draws on a wide range of sources, the core data are those compiled by FOA (Swedish National Defence Research Institute). More information on this topic and related datasets can be found on this article, by Max Roser and Mohamed Nagdy.

Before moving on, let’s load some libraries we will need to work with the data.

# required libraries
library(plyr)
library(dplyr)
library(tidyr)
library(stringr)

We now can import the data:

# import data
ne_original <- readr::read_csv("https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-08-20/nuclear_explosions.csv")
## Parsed with column specification:
## cols(
##   date_long = col_double(),
##   year = col_double(),
##   id_no = col_double(),
##   country = col_character(),
##   region = col_character(),
##   source = col_character(),
##   latitude = col_double(),
##   longitude = col_double(),
##   magnitude_body = col_double(),
##   magnitude_surface = col_double(),
##   depth = col_double(),
##   yield_lower = col_double(),
##   yield_upper = col_double(),
##   purpose = col_character(),
##   name = col_character(),
##   type = col_character()
## )

2.2 Sources

Check the GitHub repository.

3 What I learned along the way

3.1 The use of %in% from base R

This in an interface to the match() function, which returns a vector of the positions of matches of its first argument in its second. Let’s see an example (taken from ?'%in%'):

# create two vectors
a <- 1:5
b <- 3:8

# print vector "a"
a
## [1] 1 2 3 4 5
# print vector "b"
b
## [1] 3 4 5 6 7 8
# check which elements from vector "a" are also in vector "b"
a %in% b
## [1] FALSE FALSE  TRUE  TRUE  TRUE

3.2 The use of mapvalues() from {plyr}

There are some regions that have been written differently, possibly due to the fact that the data is coming from different sources, as we can see below:

# "UKRAINE" in the USSR is written as "UKEAINE" and "UKRAINE"
ne_original %>% 
  select(country, region, source) %>% 
  filter(str_detect(region, "^UK"))
## # A tibble: 2 x 3
##   country region  source
##   <chr>   <chr>   <chr> 
## 1 USSR    UKRAINE DOE   
## 2 USSR    UKEAINE MTM
# "FANGATAUFAA" in France is written as "FANGATAUFAA" and "FANGATAUFA"
ne_original %>% 
  select(country, region, source) %>% 
  filter(str_detect(region, "^FANGATAUFA"))
## # A tibble: 14 x 3
##    country region      source
##    <chr>   <chr>       <chr> 
##  1 FRANCE  FANGATAUFA  DOE   
##  2 FRANCE  FANGATAUFA  UGS   
##  3 FRANCE  FANGATAUFA  UGS   
##  4 FRANCE  FANGATAUFA  DOE   
##  5 FRANCE  FANGATAUFA  WTN   
##  6 FRANCE  FANGATAUFA  WTN   
##  7 FRANCE  FANGATAUFA  WTN   
##  8 FRANCE  FANGATAUFA  WTN   
##  9 FRANCE  FANGATAUFAA WTN   
## 10 FRANCE  FANGATAUFA  WTN   
## 11 FRANCE  FANGATAUFA  WTN   
## 12 FRANCE  FANGATAUFA  WTN   
## 13 FRANCE  FANGATAUFA  WTN   
## 14 FRANCE  FANGATAUFA  WTN

An easy way to fix these cases is with the function mapvalues() from {plyr} package. From ?mapvalues() we can see that the function takes on the following arguments: mapvalues(x, from, to, warn_missing = TRUE)

  • x: the factor or vector to modify
  • from: a vector of the items to replace
  • to: a vector of replacement values
  • warn_missing: print a message if any of the old values are not actually present in x

Let’s see it in action:

# impute corrections for "UKRAINE"
ne <- ne %>% 
  mutate(region = mapvalues(region, 
                            from = "UKEAINE", 
                            to = "UKRAINE"))

# impute corrections for "FANGATAUFA"
ne <- ne %>% 
  mutate(region = mapvalues(region, 
                            from = c("FANGATAUFAA", "MUEUEOA"), 
                            to = c("FANGATAUFA", "MURUROA")))

3.3 Timelines with {timevis} package

This package by Dean Attali makes possible to create awesome interactive timelines. You can use the mouse to “navigate” in time and to zoom in and out using the scroll. There are also more advanced features, like customizing how it looks with css or displaying groups of elements.

Lastly, {timevis} package is based on the vis.js Timeline module and the {htmlwidgets} R package; you can find more info in its GitHub repository.

4 Useful resources

In no particular order, resources I found useful are:

5 Conclusion

You can check the Shiny app in the link below:
https://canovasjm.shinyapps.io/nuclear_explosions/
and the code here:
https://github.com/canovasjm/tt-2019-08-20-nuclear