Geospatial Shiny dashboard in R: Step by Step walkthrough
In my last post, I promised to share a post that breaks down the design and code used in creating the geospatial dashboard case study. So, what are we waiting for, let's dive in.
First, the case study's code is available on my GitHub repository for reference and download. So, I will do my best to explain the code implementation in detail as much as possible.
app.R
app.R runs the entire Shiny application, incorporating UI elements, geospatial data loading, server logic, and the initiation of the Shiny app. It effectively integrates modular components for displaying an interactive Routine Immunization Dashboard.
The file codes start by importing the R packages required in the Shiny application. These include Shiny for building the web application, bslib
for theming, tidyverse
for data manipulation, bsicons
for Bootstrap icons, thematic
for theming, sf
for handling geospatial data, and leaflet
for interactive maps.
The file’s script also contains code for loading the geospatial data from an RDS file (health_care_facilities_geo.rds). This dataset contains information about healthcare facilities, related to Routine Immunization and cold chain equipment services availability.
health_care_facilities_geo <- read_rds("data/health_care_facilities_geo.rds")
The page structure is defined by the page_fillable()
function from the thematic package, incorporating various HTML tags, images, and Shiny modules (riOverviewUI
and riMapUI
). The UI includes a logo, a title, theming with Bootstrap (bs_theme), and navigation tabs (navset_tab).
ui <- page_fillable(
tags$style(" #riOUI-value_boxes { margin:0px;};"),
h4(tags$img(width = "25px",height="35px",src= "./images/ngr_logo.png"), tags$b("Routine Immunization Dashboard")),
# Set the CSS theme
…),
navset_tab(id = "navTabs",
… ))
The server function contains the logic for the Shiny app. It calls the server functions (riOverviewServer
and riMapServer
) for the respective modules (riOverviewUI and riMapUI).
server <- function(input, output, session) {
riOverviewServer("riOUI", dataset = health_care_facilities_geo)
riMapServer(id = "riMap", dataset = health_care_facilities_geo)
})
The Shiny app is launched by passing the defined UI and server functions.
shinyApp(ui, server)
riOverviewModule.R
The riOverviewModule
is designed to display a summary of geospatial data related to Cold Chain Equipment and Routine Immunization services. The module provides a dynamic and visually appealing overview of key metrics, making it an integral part of the larger Shiny application.
Function Parameters:
id: This parameter is used to namespace the UI elements within the Shiny application.
ns <- NS(id): It creates a namespace for the UI elements using the provided id.
UI Elements:
uiOutput(ns("value_boxes")): This function sets up a placeholder for the UI elements that will be dynamically generated by the server function. The value_boxes identifier is namespaced using the created namespace (ns).
riOverviewServer Function:
The riOverviewServer()
function contains the server logic for the module.
Function Parameters:
id: This parameter is used to match the server function with the UI elements created by riOverviewUI()
.
dataset: The geospatial dataset used to calculate summary values.
Reactive Values:
country_summary_vals: It's a reactiveValues object storing summary values related to Cold Chain Equipment (CCE) and Routine Immunization (RI) services. The summary includes the total count of CCEs, the count of states with CCEs, the count of CCEs with RI services, and the count of CCEs without RI services.
Server Logic:
The reactiveValues
, country_summary_vals, contains a block of code that calculates the summary values based on the provided geospatial dataset and updates it.
Rendered UI:
The block of code below dynamically generates UI elements based on the reactive values.
output$value_boxes <- renderUI({ ... })
It creates three value_box elements, each representing a different summary aspect - CCEs, CCEs with RI services, and CCEs without RI services. The layout_columns function is used to arrange the value_box elements in a column layout. Each value_box is styled with a specific theme (primary, success, danger) to visually represent different categories.
riMapUIModule.R
The riMapModule
contains code designed to display an interactive map with information about the functionality of Cold Chain Equipment in different states. It dynamically updates the map and provides detailed information when a state is clicked. The module enhances the overall user experience by allowing users to explore geospatial data interactively.
The riMapUI()
function is responsible for creating the UI (User Interface) components of the module. Here are the key points:
Function Parameters:
id: This parameter is used to namespace the UI elements within the Shiny application.
ns <- NS(id): It creates a namespace for the UI elements using the provided id.
UI Elements:
A div containing the uiOutput for the selected state. This is where information about the clicked state will be displayed. Inside it is a layout with two columns - a leafletOutput for the map plot, and a panel displaying information about the state's Cold Chain Equipment (CCE) functionality, including a title, description, and dynamic cards.
riMapServer Function:
The riMapServer function contains the server logic for the module.
Function Parameters:
id: This parameter is used to match the server function with the UI elements created by riMapUI.
dataset: The geospatial dataset used to create the map and extract information.
Reactive Calculation of Map Data:
The map_tbl, a
reactive expression calculates summary data for each state, including the number of CCEs, CCEs with RI service, and CCEs without RI service. It also includes the latitude and longitude for map plotting.
Leaflet Map Plotting:
The block of code below, dynamically generates a Leaflet map based on the calculated map_tbl data.
output$map_plot <- renderLeaflet({ ... })
It sets up circle markers representing states with CCEs and adds pop-up labels with information.
Card content generation function:
The create_card_content()
function is used to create the cards that display the different functionality information.
Handling Marker Click Events:
The observe({ ... })
code block responds to a marker click event on the map. It extracts the clicked state's information and updates the UI with cards displaying the breakdown of functionality information.
UI Output for Selected State:
The code block used to update the UI with the name of the selected state in a header style is shown below.
output$selected_state <- renderUI({ ... })
Map Redraw on Marker Click:
The leafletProxy("map_plot", data = st_map_data)
block of codes updates the Leaflet map when a state marker is clicked. It adjusts the map view and adds cluster markers based on the selected state's data.
Thank you for reading thus far. I believe you have learned so much in this post. Try out a project of your own. Share on LinkedIn and tag me. I would love to hear from you. Till I share another post, kindly like, subscribe and share my post.