This section involves analysing data from a publicly available dataset and building a dashboard on R shiny with the data. The "Causes of Death in Africa from 1990 - 2019" dashboard is designed to provide an interactive visualization of the causes of death over the specified period.
The dashboard tries to provide an interactive platform for exploring causes of death across African countries, from 1990-2019. The dashboard allows users to understand causes of death in more detail by exploring specific causes of death in any African country over chosen periods.
The dashboard serves users with different backgrounds; individuals involved in planning and implementing health policies can use the dashboard to identify critical areas of concern and to monitor the impact of health interventions over time. Also, professionals engaged in health research can explore the data for trends and insights that may inform academic studies, or further investigations into specific causes of death. In addition, NGOs focused on improving health outcomes in Africa can use this dashboard to target their efforts more effectively, understanding where their resources and programs might have the most significant impact.
Data used in this analysis was gotten from two sources:
Causes of death- https://ourworldindata.org/causes-of-death
List of countries - https://statisticstimes.com/geography/countries-by-continents.php
After installing and loading the packages, the initial dataset, “annual-number-of-deaths-by-cause.csv”, was read into the R environment using the read.csv() function. This dataset contains annual deaths segmented by different causes of death all countries in the world over a range of years. I used the head() function to look at the first few rows of the dataset, providing insight into its structure, column names, and the nature of the data contained within. I used gsub() function to simplify the column names to extract only the names of the disease to enhance readability, specifically "Deaths...|...Sex..Both...Age..All.Ages..Number." in the column names were removed.
The next thing I did was to transformed the dataset from a wide format to a long format using the pivot_longer() function from the tidyverse package. This restructuring process consolidates the various causes of death into a single column (cause_of_death), with the corresponding death counts placed in another column (death_count). Then I checked for null values in each column using colSums(is.na()) and there was none.
The next step was to scrap the web for Additional data pertaining to African countries, their ISO-alpha3 codes, and respective regions using the rvest package. I used read_html(), html_table(), and filter() to extract and filter the relevant table from the webpage, focusing specifically on African countries. Then I merged the death dataset and the supplementary country data using the inner_join() function. I then used the select() function to exclude redundant columns, ensuring a clean, integrated dataset.
The final step in data preparation involved renaming the "Entity" column to "Country" to more accurately reflect its contents. This is accomplished using the rename() function, resulting in the final dataset, african_death_causes, which was used for analysis and visualization in the Shiny app.
R Code for Building the R shiny Dashboard
#install and load package
install.packages("tidyverse")
install.packages("shiny")
install.packages("shinydashboard")
install.packages("leaflet")
install.packages("plotly")
library(tidyverse)
library(shiny)
library(rvest)
library(shinydashboard)
library(leaflet)
library(plotly)
#DATA TRANSFORMATION
#read the dataset
death_causes <- read.csv("~/annual-number-of-deaths-by-cause.csv")
#view the first few rows
head(death_causes)
# Trim column names to simplify them
names(death_causes) <- gsub("Deaths...|...Sex..Both...Age..All.Ages..Number.", "", names(death_causes))
names(death_causes) <- gsub ("\\.s ", "'s", names(death_causes))
names(death_causes) <- gsub ("\\.", " ", names(death_causes))
# Convert to long format to put the causes of death in one column and the no of deaths in another
death_causes <- death_causes %>%
pivot_longer(
cols = -c(Entity, Code, Year),
names_to = "cause_of_death",
values_to = "death_count"
)
# View the first few rows of the transformed dataset
head(death_causes)
#check for null values in each column
colSums(is.na(death_causes))
#WEBSCRAPPING TO GET THE LIST OF AFRICAN COUNTRIES, CODE AND REGIONS
# The URL of the page to scrape
url <- "https://statisticstimes.com/geography/countries-by-continents.php"
# Read the HTML content of the page
page <- read_html(url)
# to extract the table containing the countries and their details
countrytable <- page %>%
html_table(fill = TRUE) %>%
.[[3]] # To get the 3rd table as it is the one I need
# to filter for African countries
african_countries <- countrytable %>%
filter(Continent == "Africa")
# to select the required columns
african_countries <- african_countries %>%
select(`Country or Area`, `ISO-alpha3 Code`, `Region 1`)
african_countries <- african_countries %>%
rename(
Country = `Country or Area`,
Code = `ISO-alpha3 Code`,
Region = `Region 1`
)
# to view the results
african_countries
#check for null values in each column
colSums(is.na(african_countries))
#NOW I HAVE 2 TABLES death_causes and african countries, but i want to filter
#down to only African countries
african_death_causes <- death_causes %>%
inner_join(african_countries, by = "Code") %>%
select(-Country, -Code) # To remove the duplicate Country column if present
#change Entity column to Country
african_death_causes <- african_death_causes %>%
rename(Country = Entity)
# View the first columns of the final table
head(african_death_causes)
#BUILDING THE SHINY APP
# Define UI
ui<- dashboardPage(
dashboardHeader(title = "Causes of Deaths in Africa"),
dashboardSidebar(
sliderInput("yearRange", "Select Year Range:",
min = 1990,
max = 2019,
value = c(1990, 2019),
step = 1,
sep = ""),
selectInput("countryInput", "Select a Country:",
choices = c("All African Countries", unique(african_death_causes$Country)),
selected = "All African Countries"),
selectInput("diseaseInput", "Select a Disease:",
choices = c("All", unique(african_death_causes$cause_of_death)),
selected = "All")
),
dashboardBody(
fluidRow(
column(12, uiOutput("dynamicTextbox")) # This will display the dynamic text box
),
fluidRow(
column(12,
box(title = "Summary",
status = "primary",
width = 12,
solidHeader = TRUE,
valueBoxOutput("totalDeaths", width = 6),
valueBoxOutput("avgDeathsPerYear", width = 6)
)
)
),
fluidRow(
column(12,
box(title = "Trend of Deaths From 1990 - 2019",
status = "primary",
solidHeader = TRUE,
width = 12,
plotlyOutput("trendPlot", height = 200)
)
)
,
fluidRow(
column(12,
box(title = "Top 5 Causes of Death",
status = "primary",
width = 12,
solidHeader = TRUE,
plotlyOutput("topCausesPlot", height = 200)
)
),
fluidRow(
column(12,
box( title = "Distribution of Deaths by Region",
status = "primary",
solidHeader = TRUE,
width = 12,
plotlyOutput("deathsByRegionPlot", height = 200) # Use plotOutput for a chart or tableOutput for a table
)
)
)))))
# Server Logic
server <- function(input, output) {
# Filter data based on inputs
filteredData <- reactive({
african_death_causes %>%
filter(Year >= input$yearRange[1], Year <= input$yearRange[2],
if(input$countryInput != "All African Countries") Country == input$countryInput else TRUE,
if(input$diseaseInput != "All") cause_of_death == input$diseaseInput else TRUE)
})
# Total Deaths card
output$totalDeaths <- renderValueBox({
totalDeathsInMillions <- sum(filteredData()$death_count) / 1e6 # Convert to millions
# format the number with two decimal places
formattedTotal <- sprintf("%.2f", totalDeathsInMillions)
valueBox(paste(formattedTotal, "Million"), "Total Deaths", color = "blue")
})
#Average Yearly Deaths
output$avgDeathsPerYear <- renderValueBox({
dataByYear <- filteredData() %>%
group_by(Year) %>%
summarise(YearlyDeaths = sum(death_count))
avgDeaths <- mean(dataByYear$YearlyDeaths) / 1e6 # Convert to millions for consistency
# format the number with two decimal places
formattedAvg <- sprintf("%.2f", avgDeaths)
valueBox(paste(formattedAvg, "Million"), "Average Deaths per Year", color = "blue")
})
# Death Trend Plot
output$trendPlot <- renderPlotly({
# Prepare the data for plotting
trendData <- filteredData() %>%
group_by(Year) %>%
summarise(TotalDeaths = sum(death_count))
# Plotting the trend of deaths over time using a line chart
p <- ggplot(trendData, aes(x = Year, y = TotalDeaths)) +
geom_line(color = "steelblue", size = 1) + # Adjust the line thickness with 'size'
geom_point(color = "steelblue", size = 1.5, alpha = 0.6) + # Adjust point size and transparency with 'size' and 'alpha'
theme_minimal() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) + # Remove gridlines
labs( x = "Year", y = "Total Deaths") +
scale_y_continuous(labels = scales::comma) # Format the y-axis labels with commas
ggplotly(p)
})
# Top 5 Causes of Death Plot
output$topCausesPlot <- renderPlotly({
topCauses <- filteredData() %>%
group_by(cause_of_death) %>%
summarise(TotalDeaths = sum(death_count)) %>%
top_n(5, TotalDeaths) %>%
arrange(desc(TotalDeaths))
# Generate the bar chart
p <- ggplot(topCauses, aes(x = reorder(cause_of_death, -TotalDeaths), y = TotalDeaths, fill = cause_of_death)) +
geom_bar(stat = "identity", fill ="steelblue") +
coord_flip() +
theme_minimal() +
theme( panel.grid.major.y = element_blank()) + # Remove gridlines
labs(x = "", y = "Number of Deaths") +
scale_y_continuous(labels = scales::comma) # Use comma formatting for the y-axis labels
ggplotly(p)
})
#Distribution of death by region
output$deathsByRegionPlot <- renderPlotly({
dataByRegion <- filteredData() %>%
group_by(Region) %>%
summarise(TotalDeaths = sum(death_count)) %>%
arrange(desc(TotalDeaths))
# Generate the bar chart
p <- ggplot(dataByRegion, aes(x = reorder(Region, -TotalDeaths), y = TotalDeaths)) +
geom_bar(stat = "identity", fill = "steelblue") +
theme_minimal() +
theme(panel.grid.major.x = element_blank()) + # Remove gridlines
labs(x = "Region", y = "Total Deaths") +
scale_y_continuous(labels = scales::comma) # Use comma formatting for the y-axis labels
ggplotly(p)
})
output$dynamicTextbox <- renderUI({
# Construct the dynamic text based on the current filter settings
selectedYearRange <- paste(input$yearRange[1], "to", input$yearRange[2])
selectedCountry <- ifelse(input$countryInput == "All", "all countries", input$countryInput)
selectedDisease <- ifelse(input$diseaseInput == "All", "all diseases", input$diseaseInput)
dynamicText <- paste("Analyzing causes of death in", selectedCountry,
"from", selectedYearRange, "focusing on", selectedDisease, ".")
# Return a box or wellPanel with the constructed text
box(
title = "CAUSES OF DEATH IN AFRICA FROM 1990 - 2019",
status = "primary",
solidHeader = TRUE,
width = 12,
dynamicText # dynamic text based on selected filters
)
})
}
# Run the app
shinyApp(ui = ui, server = server)