if(!require("readxl")) install.packages("readxl")
if(!require("tictoc")) install.packages("tictoc")
if(!require("tidyverse")) install.packages("tidyverse")
if(!require("sf")) install.packages("sf", dependencies = TRUE)
if(!require("leaflet")) install.packages("leaflet")
if(!require("leafgl")) install.packages("leafgl")
library(sf)
library(leaflet)
library(leafgl)
library(readxl)
library(tictoc)
11 shiny and leaflet for korea death rate
In this tutorial, we’ll create a web-based interactive map to visualize Korean death rates by region, disease, year, and gender. We’ll leverage the power of R’s Shiny framework for creating web applications and the leaflet library for mapping. This combination allows users to explore the data dynamically.
11.1 Setting Up Your Environment
1 Installing Required Packages
Before we begin, ensure you have the necessary R packages installed:
- Loading and Preparing Data
For this tutorial, I’ve uploaded a pre-processed version of the data to GitHub as an RDS (R Data Serialization) file ( same to previous chapter).
Download the provided preprocessed data files kdth1.rds (death rate data) and sf_tr.rds (spatial data for Korean regions) from the specified GitHub repository. Load these files into R using readRDS(). Briefly inspect the data using functions like head(), str(), or summary().
<- "https://raw.githubusercontent.com/jinhaslab/opendata/main/data/kdth1.rds"
kdeath1 <- "https://raw.githubusercontent.com/jinhaslab/opendata/main/data/sf_tr.rds"
sf_tr if (!dir.exists("data")) {dir.create("data", recursive = TRUE)}
download.file(kdeath1, "data/kdth1.rds")
download.file(sf_tr, "data/sf_tr.rds")
11.2 Create a Shiny App for Interactive Visualization
Now we can create a Shiny app to allow interactive visualization of the data:
- reusable function
Create a reusable function mapf() in a separate R script file named mapf.R (located in a ‘source’ folder). This function will generate the leaflet map based on user input:
= function(dzchoice, yearchoice, sexchoice){
mapf = kdth1 %>%
rate filter(cause == dzchoice,
== yearchoice,
year == sexchoice
sex
)= sf_tr %>%
sf_tr_m left_join(rate, by=c("CTP_ENG_NM"="region")) %>%
mutate(rate = as.numeric(rate))
=
rate_colors colorNumeric(
palette = "YlOrRd",
domain = sf_tr_m$rate
)= sprintf("Region: %s, <br> Rate: %s",
label_text $CTP_ENG_NM, sf_tr_m$rate
sf_tr_m
)
= 36 ; korea_lng = 128
korea_lat
leaflet(data = sf_tr_m) %>%
addProviderTiles("CartoDB.Positron") %>% # Adds a light-themed base map from CartoDB
setView(lng = korea_lng, lat = korea_lat, zoom = 7) %>%
addPolygons(
fillColor = ~rate_colors(rate),
color = "#444444", # Border color of the polygons
weight = 1, # Border width
opacity = 1,
fillOpacity = 0.7, # Fill opacity of the polygons
smoothFactor = 0.5,
highlightOptions = highlightOptions(
color = "white",
weight = 2,
bringToFront = TRUE
), label = lapply(label_text, htmltools::HTML)
%>%
) addLegend(
pal = rate_colors,
values = sf_tr_m$rate
)
}
- global
if(!require("sf")) install.packages("sf", dependencies = TRUE)
if(!require("leaflet")) install.packages("leaflet")
if(!require("leafgl")) install.packages("leafgl")
if(!require("shinydashboard")) install.packages("shinydashboard")
if (!require("shinyjqui")) install.packages("shinyjqui")
if(!require(shinyjs)) install.packages('shinyjs')
library(tidyverse)
library(sf)
library(leaflet)
library(leafgl)
library(readxl)
library(tictoc)
library(shinydashboard)
library(shinyjqui)
library(shinyjs)
tic()
= readRDS("data/sf_tr.rds")
sf_tr = readRDS("data/kdth1.rds")
kdth1 $CTP_ENG_NM %>% sort()
sf_trtoc()
= kdth1 %>% pull(cause) %>% unique()
dzchoice = kdth1 %>% pull(year) %>% unique()
yearchoice= c("Total", "Male", "Female")
sexchoice
source("source/mapf.R")
- ui
Design the UI of the Shiny app:
We create a dashboardPage with a header, sidebar, and body. The body contains the leaflet map (leafglOutput(“map1”)) and input controls (disease, year, and gender selection) in an absolutePanel.
<- dashboardPage(
ui dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem("Map", tabName = "map1", icon = icon("map"))
)
),dashboardBody(
tabItems(
tabItem(
tabName = "map1",
leafglOutput("map1"),
absolutePanel(
selectInput("dzchoice", "Disease", dzchoice),
selectInput("yearchoice", "Years", yearchoice),
selectInput("sexchoice", "Gender", sexchoice)
)
)
)
) )
- server
Define how the app reacts to user input:
<- function(input, output, session) {
server $map1 <- renderLeaflet({
outputmapf(
dzchoice = input$dzchoice,
yearchoice = input$yearchoice,
sexchoice = input$sexchoice
)
}) }
renderLeaflet: Renders the map generated by the mapf function based on the values the user selects in the UI controls.
11.3 update and customizing shiny
In this tutorial, we’ll take our interactive map to the next level! We’ll customize the user interface (UI) with CSS to give the app a more polished and visually appealing look. We’ll focus on:
- Customizing fonts and styles.
- Creating a draggable and collapsible options panel.
- Making the map responsive to different screen sizes.
1: Setting Up and Customizing the UI
1.1 Include Custom CSS
Create a file named styles.css in a www folder within your Shiny app directory. Paste the following CSS code into it
- Creates the appearance and hover effects for the controls panel (#controls).
.main-header .logo {
font-family: "Georgia", Times, "Times New Roman", serif;
font-weight: bold;
font-size: 24px;
}
[type="number"] {
inputmax-width: 80%;
}
.outer {
divposition: fixed;
top: 41px;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
padding: 0;
}
/* Customize fonts */
, label, input, button, select {
bodyfont-family: 'Helvetica Neue', Helvetica;
font-weight: 200;
}, h2, h3, h4 { font-weight: 400; }
h1
#controls {
/* Appearance */
background-color: white;
padding: 0 20px 20px 20px;
cursor: move;
/* Fade out while not hovering */
opacity: 0.65;
zoom: 0.8;
transition: opacity 500ms 1s;
}#controls:hover {
/* Fade in while hovering */
opacity: 0.95;
transition-delay: 0;
}
/* Position and style citation */
#cite {
position: absolute;
bottom: 10px;
left: 10px;
font-size: 12px;
}
/* If not using map tiles, show a white background */
.leaflet-container {
background-color: white !important;
}
2 Modify the UI
Update your ui.R file to include the custom CSS and apply the necessary changes to your UI elements:
<- dashboardPage(
ui dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem("Map", tabName = "map1", icon = icon("map"))
)
),dashboardBody(
tabItems(
tabItem(
tabName = "map1",
div(class="outer",
$head(
tags# Include our custom CSS
includeCSS("www/styles.css"),
$head(name="viewport", content="width=device-width, initial-scale=1.0")
tags
)),leafglOutput("map1", height="1000px"),
absolutePanel(
id = "controls", class = "panel panel-default", fixed = TRUE,
draggable = TRUE, top = "130", left = "auto", right = "50", bottom = "auto",
width = "330", height = "auto",
HTML('<button data-toggle="collapse" data-target="#demo">Options</button>'),
$div(id='demo', class="collapse",
tagsh2('interractive options'),
selectInput("dzchoice", "Disease", dzchoice),
selectInput("yearchoice", "Years", yearchoice),
selectInput("sexchoice", "Gender", sexchoice)
))
)
)
) )
CSS Inclusion: We use includeCSS(“www/styles.css”) to link our custom CSS file to the Shiny app.
Outer Container (div.outer):
- This div is positioned to fill the available space below the Shiny header and sidebar, allowing the map to occupy the entire viewport.
- It also sets overflow: hidden to prevent content from spilling outside its boundaries.
Viewport Meta Tag: The
tag is essential for making the app responsive on mobile devices.
Collapsible Options:
- The options panel is made collapsible using a Bootstrap collapse element. The “Options” button is used to toggle its visibility. This provides a cleaner look when the options aren’t needed.
- The absolutePanel is made draggable using draggable = TRUE.