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 inx
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:
- Mastering shiny, a book by Hadley Wickham.
- R Shiny app tutorial, a series of videos by Abhinav Agrawal.
- Shiny tutorial, a series of videos by Garrett Grolemund.
- Shiny gallery, from RStudio.
- Building Shiny applications, by Dr. Benjamin Soltoff.
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