cjerzak's picture
Update app.R
aee6cdd verified
raw
history blame
8.65 kB
# setwd("~/Downloads")
{
# app.R
options(error = NULL)
# ------------------------------
# 1. Load Packages
# ------------------------------
library(shiny)
library(shinydashboard)
library(leaflet)
library(raster)
library(DT)
library(readr)
library(dplyr) # For data manipulation
library(ggplot2) # For histogram
library(RColorBrewer)
# ------------------------------
# 2. Data & Config
# ------------------------------
# Define time periods corresponding to each band in the GeoTIFF
time_periods <- c("1990–1992", "1993–1995", "1996–1998", "1999–2001", "2002–2004",
"2005–2007", "2008–2010", "2011–2013", "2014–2016", "2017–2019")
# Load GeoTIFF data
wealth_stack <- stack("wealth_map.tif")
# Clean up out-of-range values
wealth_stack[wealth_stack <= 0 | wealth_stack > 1] <- NA
# Load improvement data
improvement_data <- read_csv("poverty_improvement_by_state.csv")
# ------------------------------
# 3. UI
# ------------------------------
ui <- dashboardPage(
# -- Header
dashboardHeader(title = "Africa Living Conditions Explorer"),
# -- Sidebar
dashboardSidebar(
sidebarMenu(id = "tabs",
menuItem("Wealth Map", tabName = "mapTab", icon = icon("map")),
menuItem("Improvement Data", tabName = "improvementTab", icon = icon("table"))
),
# Show inputs only for the map tab
conditionalPanel(
condition = "input.tabs == 'mapTab'",
br(),
selectInput("time_period", "Select Time Period:",
choices = time_periods,
selected = time_periods[1] # Load the first time period by default
),
selectInput("color_palette", "Select Color Palette:",
choices = c("Viridis" = "viridis",
"Plasma" = "plasma",
"Magma" = "magma",
"Inferno"= "inferno",
"Spectral (Brewer)" = "Spectral"),
selected = "viridis"),
sliderInput("opacity", "Map Opacity:", min = 0.2, max = 1, value = 0.8, step = 0.1)
# Removed the 'Update Map' button
)
),
# -- Body
dashboardBody(
tabItems(
# ---------- MAP TAB ----------
tabItem(
tabName = "mapTab",
fluidRow(
# Value Boxes across the top for key stats
valueBoxOutput("highest_iwi_vb", width = 4),
valueBoxOutput("lowest_iwi_vb", width = 4),
valueBoxOutput("avg_iwi_vb", width = 4)
),
fluidRow(
# Map
box(
title = "Wealth Map of Africa", width = 8, solidHeader = TRUE, status = "primary",
leafletOutput("map", height = "550px")
),
# Histogram
box(
title = "IWI Distribution (Selected Period)", width = 4, solidHeader = TRUE, status = "info",
plotOutput("iwi_histogram", height = "250px"),
p("This histogram shows the distribution of the International Wealth Index (IWI) values for the selected time period across Africa.")
)
)
),
# ---------- IMPROVEMENT DATA TAB ----------
tabItem(
tabName = "improvementTab",
fluidRow(
box(
width = 12, title = "Poverty Improvement by State", status = "primary", solidHeader = TRUE,
p("This table shows the estimated improvement in mean IWI between 1990–1992 and 2017–2019 for each province in Africa.
The 'Improvement' column indicates the change in IWI over this period. You can sort or filter the table,
and use the download button to export the data."),
downloadButton("download_data", "Download CSV", icon = icon("download")),
br(), br(),
DTOutput("improvement_table")
)
)
)
)
)
)
# ------------------------------
# 4. Server
# ------------------------------
server <- function(input, output, session) {
# ----------------------------------
# Reactive expression for selected raster layer
# ----------------------------------
selected_raster <- reactive({
req(input$time_period)
band_index <- which(time_periods == input$time_period)
wealth_stack[[band_index]]
})
# ----------------------------------
# Custom color palette function
# (reactive to user-selected palette)
# ----------------------------------
color_pal <- reactive({
palette_choice <- switch(
input$color_palette,
"viridis" = "viridis",
"plasma" = "plasma",
"magma" = "magma",
"inferno" = "inferno",
# Fallback to a Brewer palette for "Spectral"
"Spectral" = "Spectral"
)
colorNumeric(
palette = palette_choice,
domain = c(0, 1),
na.color = "transparent"
)
})
# ----------------------------------
# 1. MAP OUTPUT
# ----------------------------------
output$map <- renderLeaflet({
leaflet() %>%
addProviderTiles(providers$OpenStreetMap) %>%
setView(lng = 20, lat = 0, zoom = 3) %>% # Center on Africa
addLegend(
pal = color_pal(),
values = c(1, 0),
bins = 2,
title = "IWI",
position = "bottomright",
labFormat = labelFormat(
prefix = "",
suffix = "",
between = " &ndash; ",
digits = 3,
big.mark = ","
)
)
})
# Any time one of the controls changes, redraw the raster
observe({
req(input$time_period, input$color_palette, input$opacity)
leafletProxy("map") %>%
clearImages() %>%
addRasterImage(
selected_raster(),
colors = color_pal(),
opacity = input$opacity,
project = TRUE
)
})
# ----------------------------------
# 2. HISTOGRAM OUTPUT
# ----------------------------------
output$iwi_histogram <- renderPlot({
# Extract raster values for histogram
r_vals <- values(selected_raster())
r_vals <- r_vals[!is.na(r_vals)]
ggplot(data.frame(iwi = r_vals), aes(x = iwi)) +
geom_histogram(binwidth = 0.02, fill = "#2c7bb6", color = "white", alpha = 0.7) +
labs(x = "IWI (0 to 1)", y = "Frequency") +
theme_minimal(base_size = 14)
})
# ----------------------------------
# 3. VALUE BOXES FOR KEY STATS
# ----------------------------------
# Compute stats for current raster
raster_stats <- reactive({
r_vals <- values(selected_raster())
r_vals <- r_vals[!is.na(r_vals)]
list(
highest = max(r_vals, na.rm = TRUE),
lowest = min(r_vals, na.rm = TRUE),
average = mean(r_vals, na.rm = TRUE)
)
})
# Highest IWI
output$highest_iwi_vb <- renderValueBox({
valueBox(
value = round(raster_stats()$highest, 3),
subtitle = "Highest IWI",
icon = icon("arrow-up"),
color = "green"
)
})
# Lowest IWI
output$lowest_iwi_vb <- renderValueBox({
valueBox(
value = round(raster_stats()$lowest, 3),
subtitle = "Lowest IWI",
icon = icon("arrow-down"),
color = "red"
)
})
# Average IWI
output$avg_iwi_vb <- renderValueBox({
valueBox(
value = round(raster_stats()$average, 3),
subtitle = "Average IWI",
icon = icon("balance-scale"),
color = "blue"
)
})
# ----------------------------------
# 4. IMPROVEMENT DATA TABLE
# ----------------------------------
output$improvement_table <- renderDT({
datatable(
improvement_data,
filter = "top",
options = list(
scrollX = TRUE,
pageLength = 20,
autoWidth = TRUE
)
)
})
# Download CSV
output$download_data <- downloadHandler(
filename = function() {
paste0("poverty_improvement_", Sys.Date(), ".csv")
},
content = function(file) {
write.csv(improvement_data, file, row.names = FALSE)
}
)
}
# ------------------------------
# 5. Run the App
# ------------------------------
shinyApp(ui = ui, server = server)
}