Nama: Fatih Zahrani
NPM:
140610230014
Dosen Pengampu: I Gede Nyoman Mindra
Jaya, M.Si., Ph.D.
S1 Statistika FMIPA UNPAD
Petunjuk
Download folder Dashboard dan jalankan syntax app.R dibawah ini
Link file:
https://drive.google.com/drive/folders/1oV10YffnE1jPM6ByesNhxubHrZA-fA05?usp=sharing
Syntax Dashboard
# ============================================================
# app.R Dashboard Analisis DBD Jawa Barat 2024
# Version: 1.0
# ============================================================
# ----------------------------
# Load libraries
# ----------------------------
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(dplyr)
library(plotly)
library(leaflet)
library(DT)
library(spdep)
library(sf)
library(sp)
library(openxlsx)
library(tidyr)
library(ggplot2)
library(DiagrammeR)
library(viridis)
library(scales)
# ============================================================
# 1. GLOBAL SECTION (Data & Model)
# ============================================================
# --- Load data shapefile dan Excel ---
# CATATAN: Sesuaikan path dengan lokasi file Anda
Indo <- st_read("D:/Kuliah/Sem 5/Epidem/Dashboard/shapefile")
data <- read.xlsx("D:/Kuliah/Sem 5/Epidem/Dashboard/data/DATA EPIDEMIOLOGI.xlsx")
# --- Merge shapefile dan data ---
jabar_merged <- Indo %>%
left_join(data, by = c("WADMKK" = "kab_kota"))
# --- Hitung Prevalensi dan CFR ---
jabar_merged <- jabar_merged %>%
mutate(
Prevalensi = (JK / JP) * 100,
CFR = (KDBD / JK) * 100
)
# --- Total untuk Jawa Barat ---
total_JK <- sum(jabar_merged$JK, na.rm = TRUE)
total_JP <- sum(jabar_merged$JP, na.rm = TRUE)
total_KDBD <- sum(jabar_merged$KDBD, na.rm = TRUE)
prevalensi_jabar <- (total_JK / total_JP) * 100
cfr_jabar <- (total_KDBD / total_JK) * 100
# --- Konversi ke Spatial untuk analisis spasial ---
jabar_sp <- as_Spatial(jabar_merged)
row.names(jabar_sp) <- jabar_sp$WADMKK
# --- Spatial weight matrix ---
W <- poly2nb(jabar_sp, row.names = row.names(jabar_sp), queen = TRUE)
WL <- nb2listw(W, style = "W", zero.policy = TRUE)
cat("??? Semua data berhasil dimuat!\n")
# ============================================================
# 2. UI SECTION
# ============================================================
ui <- dashboardPage(
skin = "blue",
dashboardHeader(title = "Dashboard DBD Jawa Barat 2024", titleWidth = 350),
dashboardSidebar(
width = 270,
sidebarMenu(
menuItem("About Dashboard", tabName = "about", icon = icon("info-circle")),
menuItem("Import Data", tabName = "import", icon = icon("upload")),
menuItem("Data Overview", tabName = "data_overview", icon = icon("table")),
menuItem("Agent-Host-Environment", tabName = "ahe", icon = icon("project-diagram")),
menuItem("Statistika Deskriptif", tabName = "descriptive", icon = icon("chart-bar")),
menuItem("Sebaran DBD", tabName = "spatial", icon = icon("map-marked-alt")),
menuItem("Ukuran Epidemiologi", tabName = "epidemiology", icon = icon("calculator"))
)
),
dashboardBody(
tags$head(
tags$link(rel = "stylesheet", type = "text/css", href = "custom.css")
),
tabItems(
# =====================================================
# 1. TENTANG DASHBOARD
# =====================================================
tabItem(tabName = "about",
fluidRow(
box(width = 12, title = "Selamat Datang di Dashboard DBD Jawa Barat 2024",
status = "primary", solidHeader = TRUE,
h4("???? Tentang Dashboard"),
p("Dashboard ini menyajikan analisis komprehensif mengenai Demam Berdarah Dengue (DBD) di Provinsi Jawa Barat Tahun 2024.
Dashboard dirancang untuk memudahkan pemahaman pola sebaran, faktor risiko, dan ukuran epidemiologi DBD."),
hr(),
h4("Urgensi"),
tags$ul(
tags$li("Jawa Barat merupakan salah satu provinsi dengan jumlah penduduk terbesar di Indonesia,
sehingga potensi penyebaran penyakit menular seperti DBD sangat tinggi."),
tags$li("Berdasarkan data dari Kemenkes RI, Jawa Barat termasuk dalam provinsi dengan insidensi
dan jumlah kasus DBD tertinggi setiap tahunnya.")
),
hr(),
h4(" Sumber Data"),
p(strong("Data Kasus DBD:"), " BPS Provinsi Jawa Barat"),
p(strong("Shapefile:"), " RBI 50K Jawa Barat"),
p(strong("Tahun:"), " 2024"),
p(strong("Jumlah Kabupaten/Kota:"), nrow(data)),
hr(),
h4("???? Tim Penyusun"),
tags$ul(
tags$li("Fatih Zahrani (140610230014)"),
tags$li("Rahma Aulia Putri (140610230037)"),
tags$li("Nafalla Afftanur Rismawanti (140610230044)")
),
p(em("Dashboard Version 1.0 - 2025"))
)
)
),
# =====================================================
# 2. IMPORT DATA
# =====================================================
tabItem(tabName = "import",
fluidRow(
box(width = 12, title = "Upload Data DBD", status = "warning", solidHeader = TRUE,
p("Upload file Excel (.xlsx) dengan format yang sesuai. File harus mengandung kolom:
kab_kota, JK (Jumlah Kasus), JP (Jumlah Penduduk), KDBD (Kematian DBD)."),
fileInput("upload_data", "Pilih File Excel", accept = c(".xlsx")),
actionButton("load_data", "Load Data", class = "btn-primary", icon = icon("upload")),
hr(),
h4("Preview Data yang Diupload:"),
DTOutput("preview_upload")
)
),
fluidRow(
box(width = 12, title = "Template Download", status = "info", solidHeader = TRUE,
p("Jika Anda belum memiliki format data yang sesuai, silakan download template berikut:"),
downloadButton("download_template", "Download Template Excel", class = "btn-success")
)
)
),
# =====================================================
# 3. DATA OVERVIEW
# =====================================================
tabItem(tabName = "data_overview",
fluidRow(
# Menampilkan ringkasan data
valueBoxOutput("total_cases", width = 4), # Total kasus DBD
valueBoxOutput("total_deaths", width = 4), # Total kematian DBD
valueBoxOutput("num_districts", width = 4) # Jumlah kabupaten/kota
),
fluidRow(
box(width = 12, title = "Tabel Data DBD", status = "info", solidHeader = TRUE,
sliderInput("n_rows", "Jumlah Baris:", min = 5, max = 50, value = 10),
downloadButton("download_data", "Download Data (Excel)", class = "btn-primary"),
hr(),
DTOutput("data_table"))
)
),
# =====================================================
# 4. AGENT-HOST-ENVIRONMENT
# =====================================================
tabItem(tabName = "ahe",
fluidRow(
box(width = 12, title = "Faktor Risiko DBD: Agent-Host-Environment",
status = "primary", solidHeader = TRUE,
h4("Diagram Faktor Risiko DBD"),
p("Klik pada kotak faktor untuk melihat penjelasan detail hubungan dengan risiko DBD."),
grVizOutput("ahe_diagram", height = "900px", width = "100%")
)
),
fluidRow(
box(width = 12, title = "Penjelasan Faktor Risiko", status = "info", solidHeader = TRUE,
tabsetPanel(
tabPanel("???? Agent",
br(),
h4("Virus Dengue"),
p(strong("Klasifikasi:"), " Flavivirus, famili Flaviviridae"),
p(strong("Serotipe:"), " DENV-1, DENV-2, DENV-3, DENV-4"),
p("Virus dengue ditularkan ke manusia melalui gigitan nyamuk Aedes betina yang terinfeksi, terutama Aedes aegypti dan Aedes albopictus."),
hr(),
p(strong("Mekanisme:"), " Virus masuk ke tubuh manusia melalui gigitan nyamuk ???
replikasi virus dalam sel ??? viremia ??? manifestasi klinis DBD")
),
tabPanel("???? Host",
br(),
h4("Faktor Host yang Meningkatkan Kerentanan"),
tags$ul(
tags$li(strong("Usia 5-14 tahun:"), " Kelompok usia ini memiliki aktivitas tinggi dan
sistem imun yang masih berkembang, sehingga lebih rentan terinfeksi."),
tags$li(strong("Status Gizi Buruk:"), " Malnutrisi menurunkan sistem imun tubuh,
membuat individu lebih mudah terinfeksi dan mengalami komplikasi."),
tags$li(strong("Golongan Darah AB:"), " Penelitian menunjukkan golongan darah AB
memiliki risiko lebih tinggi terkena DBD berat."),
tags$li(strong("Laki-laki:"), " Secara statistik, laki-laki memiliki risiko sedikit
lebih tinggi, kemungkinan karena faktor aktivitas dan paparan."),
tags$li(strong("Riwayat Infeksi Sebelumnya:"), " Infeksi dengue sebelumnya dengan
serotipe berbeda meningkatkan risiko DBD berat (DHF) melalui antibody-dependent enhancement (ADE).")
)
),
tabPanel(" Environment",
br(),
h4("Faktor Lingkungan yang Meningkatkan Risiko"),
tags$ul(
tags$li(strong("Curah Hujan Tinggi:"), " Meningkatkan habitat jentik Aedes aegypti
karena banyak genangan air ??? populasi nyamuk meningkat ??? risiko penularan DBD naik."),
tags$li(strong("Kenaikan Suhu Global:"), " Suhu 25-30??C optimal untuk perkembangan nyamuk.
Suhu tinggi mempercepat siklus hidup nyamuk dan replikasi virus dalam tubuh nyamuk ??? transmisi lebih cepat."),
tags$li(strong("Rendahnya Pelaksanaan 3M Plus:"), " Tidak menguras tempat penampungan air,
tidak menutup rapat, dan tidak mengubur barang bekas ??? habitat jentik nyamuk tetap ada ??? risiko DBD tinggi."),
tags$li(strong("Kepadatan Penduduk Tinggi:"), " Wilayah padat penduduk meningkatkan kontak antarmanusia
dan nyamuk ??? penyebaran virus lebih cepat ??? wabah lebih mudah terjadi.")
),
hr(),
h4("???? Upaya Pencegahan"),
tags$ul(
tags$li("Gerakan 3M Plus (Menguras, Menutup, Mengubur + Plus)"),
tags$li("Fogging/penyemprotan di area fokus wabah"),
tags$li("Edukasi masyarakat tentang bahaya DBD"),
tags$li("Surveilans dan monitoring kasus secara aktif")
)
)
)
)
)
),
# =====================================================
# 5. STATISTIKA DESKRIPTIF
# =====================================================
tabItem(tabName = "descriptive",
fluidRow(
box(width = 12, title = "Pengaturan Analisis", status = "primary", solidHeader = TRUE,
fluidRow(
column(6,
pickerInput("desc_vars", "Pilih Variabel:",
choices = c(
"Jumlah DBD" = "Jumlah DBD",
"Jumlah Penduduk" = "Jumlah Penduduk",
"Jumlah Kematian DBD" = "Jumlah Kematian DBD",
"Prevalensi" = "Prevalensi",
"CFR" = "CFR"
),
selected = "Jumlah DBD", multiple = TRUE,
options = list(actionsBox = TRUE, liveSearch = TRUE))
)
),
downloadButton("download_desc", "Download Hasil Analisis", class = "btn-success")
)
),
fluidRow(
box(width = 6, title = "Histogram", status = "info", solidHeader = TRUE,
plotlyOutput("desc_histogram", height = "400px")),
box(width = 6, title = "Boxplot", status = "warning", solidHeader = TRUE,
plotlyOutput("desc_boxplot", height = "400px"))
),
fluidRow(
box(width = 12, title = "Statistik Deskriptif", status = "success", solidHeader = TRUE,
DTOutput("desc_summary"))
)
),
# =====================================================
# 6. SEBARAN DBD
# =====================================================
tabItem(tabName = "spatial",
fluidRow(
valueBoxOutput("total_kasus", width = 4),
valueBoxOutput("total_kematian", width = 4),
valueBoxOutput("total_wilayah", width = 4)
),
fluidRow(
box(width = 12, title = "Peta Sebaran Kasus DBD", status = "danger", solidHeader = TRUE,
leafletOutput("map_kasus", height = "500px"))
),
fluidRow(
box(width = 12, title = "Analisis Autokorelasi Spasial", status = "primary", solidHeader = TRUE,
tabsetPanel(
tabPanel("Moran's I & Geary's C",
br(),
fluidRow(
valueBoxOutput("moranI_box", width = 6),
valueBoxOutput("gearyC_box", width = 6)
),
plotlyOutput("moran_plot", height = "500px")
),
tabPanel("LISA Cluster Map",
br(),
p("Local Indicators of Spatial Association (LISA) menunjukkan cluster spasial lokal."),
leafletOutput("lisa_map", height = "600px")
),
tabPanel("Getis-Ord Gi*",
br(),
p("Identifikasi hot spots dan cold spots berdasarkan z-score."),
leafletOutput("getisord_map", height = "600px")
)
)
)
)
),
# =====================================================
# 7. UKURAN EPIDEMIOLOGI
# =====================================================
tabItem(tabName = "epidemiology",
fluidRow(
valueBoxOutput("prev_jabar_box", width = 6),
valueBoxOutput("cfr_jabar_box", width = 6)
),
# PREVALENSI
fluidRow(
box(width = 12, title = "Analisis Prevalensi", status = "info", solidHeader = TRUE,
collapsible = TRUE,
tabsetPanel(
tabPanel("Peta Prevalensi",
br(),
leafletOutput("map_prevalensi", height = "500px")
),
tabPanel("Prevalensi per Wilayah",
br(),
pickerInput("prev_cities", "Pilih Kabupaten/Kota:",
choices = NULL, multiple = TRUE,
options = list(actionsBox = TRUE, liveSearch = TRUE)),
fluidRow(
column(6, DTOutput("prev_table")),
column(6, plotlyOutput("prev_bar", height = "400px"))
)
)
)
)
),
# CFR
fluidRow(
box(width = 12, title = "Analisis Case Fatality Rate (CFR)", status = "warning", solidHeader = TRUE,
collapsible = TRUE,
tabsetPanel(
tabPanel("Peta CFR",
br(),
leafletOutput("map_cfr", height = "500px")
),
tabPanel("CFR per Wilayah",
br(),
pickerInput("cfr_cities", "Pilih Kabupaten/Kota:",
choices = NULL, multiple = TRUE,
options = list(actionsBox = TRUE, liveSearch = TRUE)),
fluidRow(
column(6, DTOutput("cfr_table")),
column(6, plotlyOutput("cfr_bar", height = "400px"))
)
)
)
)
)
)
)
)
)
# ============================================================
# 3. SERVER SECTION
# ============================================================
server <- function(input, output, session) {
# ============================================================
# REACTIVE VALUES
# ============================================================
# Update choices untuk picker inputs
observe({
city_choices <- data$kab_kota
updatePickerInput(session, "desc_cities", choices = city_choices)
updatePickerInput(session, "prev_cities", choices = city_choices)
updatePickerInput(session, "cfr_cities", choices = city_choices)
})
# ============================================================
# 2. AGENT-HOST-ENVIRONMENT
# ============================================================
output$ahe_diagram <- renderGrViz({
grViz("
digraph AHE {
graph [rankdir = TB, bgcolor = transparent, splines = ortho, nodesep = 0.8, ranksep = 1.2]
node [shape = box, style = 'filled,rounded', fontname = 'Arial', fontsize = 11, width = 2.5, height = 0.8]
edge [color = '#555555', penwidth = 2, fontname = 'Arial', fontsize = 10]
# Subgraph Environment
subgraph cluster_env {
label = 'ENVIRONMENT'
style = filled
color = '#E8F5E9'
fontsize = 14
fontname = 'Arial Bold'
ENV1 [label = 'Kepadatan\\nPenduduk\\nTinggi', fillcolor = '#81C784', fontcolor = white]
ENV2 [label = 'Curah Hujan\\nTinggi', fillcolor = '#81C784', fontcolor = white]
ENV3 [label = 'Kenaikan Suhu\\nGlobal', fillcolor = '#81C784', fontcolor = white]
ENV4 [label = 'Rendahnya\\n3M Plus', fillcolor = '#81C784', fontcolor = white]
}
# Nodes lain
GENANGAN [label = 'Genangan Air', fillcolor = '#64B5F6', fontcolor = white]
NYAMUK [label = 'Populasi Nyamuk\\nAedes Meningkat', fillcolor = '#FF7043', fontcolor = white]
VIRUS [label = 'Virus Dengue', fillcolor = '#E53935', fontcolor = white, shape = ellipse]
MANUSIA [label = 'Manusia', fillcolor = '#FFA726', fontcolor = white, shape = ellipse]
DBD [label = 'KASUS DBD', fillcolor = '#D32F2F', fontcolor = white, style = 'filled,rounded,bold', penwidth = 3]
# Subgraph Host Factors
subgraph cluster_host {
label = 'HOST FACTORS\\n(Kerentanan)'
style = filled
color = '#FFF3E0'
fontsize = 14
fontname = 'Arial Bold'
HOST1 [label = 'Status Gizi\\nBuruk', fillcolor = '#FFB74D', fontcolor = white]
HOST2 [label = 'Usia\\n5-14 Tahun', fillcolor = '#FFB74D', fontcolor = white]
HOST3 [label = 'Riwayat Infeksi\\nSebelumnya', fillcolor = '#FFB74D', fontcolor = white]
HOST4 [label = 'Laki-laki', fillcolor = '#FFB74D', fontcolor = white]
HOST5 [label = 'Golongan\\nDarah AB', fillcolor = '#FFB74D', fontcolor = white]
}
# Edges Environment
ENV1 -> NYAMUK [label = 'meningkatkan\\npopulasi', fontsize = 9]
ENV1 -> MANUSIA [label = 'meningkatkan\\npenyebaran', fontsize = 9]
ENV2 -> GENANGAN [label = 'menciptakan', fontsize = 9]
ENV3 -> NYAMUK [label = 'mempercepat\\nsiklus hidup', fontsize = 9]
ENV4 -> GENANGAN [label = 'tidak\\nmembersihkan', fontsize = 9]
GENANGAN -> NYAMUK [label = 'tempat\\nperindukan', fontsize = 9]
# Edges Agent-Vector-Host
NYAMUK -> VIRUS [label = 'membawa', fontsize = 9]
VIRUS -> MANUSIA [label = 'transmisi melalui\\ngigitan nyamuk', fontsize = 9]
MANUSIA -> DBD [label = 'infeksi', fontsize = 9]
# Edges Host Factors
HOST1 -> DBD [label = 'meningkatkan\\nkerentanan', fontsize = 9, color = '#F57C00']
HOST2 -> DBD [label = 'meningkatkan\\nkerentanan', fontsize = 9, color = '#F57C00']
HOST3 -> DBD [label = 'meningkatkan\\nkerentanan', fontsize = 9, color = '#F57C00']
HOST4 -> DBD [label = 'meningkatkan\\nkerentanan', fontsize = 9, color = '#F57C00']
HOST5 -> DBD [label = 'meningkatkan\\nkerentanan', fontsize = 9, color = '#F57C00']
}
")
})
# ============================================================
# 3. DATA OVERVIEW
# ============================================================
# ValueBoxes
output$total_cases <- renderValueBox({
valueBox(sum(data$JK), "Total Kasus DBD", icon = icon("virus"), color = "red")
})
output$total_deaths <- renderValueBox({
valueBox(sum(data$KDBD), "Total Kematian DBD", icon = icon("skull-crossbones"), color = "black")
})
output$num_districts <- renderValueBox({
valueBox(length(unique(data$kab_kota)), "Jumlah Kabupaten/Kota", icon = icon("map-marker-alt"), color = "blue")
})
# Data Table & Download
output$data_table <- renderDT({
# Buat salinan data supaya kolom asli tetap
data_display <- data
# Ganti nama kolom sesuai mapping
colnames(data_display)[colnames(data_display) == "no"] <- "No"
colnames(data_display)[colnames(data_display) == "kab_kota"] <- "Kabupaten/Kota"
colnames(data_display)[colnames(data_display) == "JK"] <- "Jumlah DBD"
colnames(data_display)[colnames(data_display) == "JP"] <- "Jumlah Penduduk"
colnames(data_display)[colnames(data_display) == "KDBD"] <- "Jumlah Kematian DBD"
datatable(
head(data_display, input$n_rows),
options = list(scrollX = TRUE, pageLength = 10),
rownames = FALSE
)
})
output$download_data <- downloadHandler(
filename = function() {
paste0("Data_DBD_Jabar_", Sys.Date(), ".xlsx")
},
content = function(file) {
write.xlsx(data, file)
}
)
# ============================================================
# 4. IMPORT DATA
# ============================================================
output$preview_upload <- renderDT({
req(input$upload_data)
df <- read.xlsx(input$upload_data$datapath)
datatable(df, options = list(pageLength = 10, scrollX = TRUE))
})
output$download_template <- downloadHandler(
filename = function() {
"Template_Data_DBD.xlsx"
},
content = function(file) {
template <- data.frame(
'Kabupaten/Kota' = c("Kabupaten A", "Kabupaten B"),
'Jumlah Kasus DBD' = c(100, 150),
'Jumlah Penduduk' = c(50000, 60000),
'Jumlah Kematian DBD' = c(2, 3)
)
write.xlsx(template, file)
}
)
# ============================================================
# 4. STATISTIKA DESKRIPTIF
# ============================================================
desc_data <- reactive({
data # langsung pakai seluruh data tanpa filtering
})
desc_data_renamed <- reactive({
df <- desc_data()
df <- df %>% rename(
"No" = no,
"Kabupaten/Kota" = kab_kota,
"Jumlah DBD" = JK,
"Jumlah Penduduk" = JP,
"Jumlah Kematian DBD" = KDBD
)
df
})
output$desc_histogram <- renderPlotly({
req(input$desc_vars)
df <- desc_data_renamed()
plots <- lapply(input$desc_vars, function(var) {
plot_ly(df, x = ~get(var), type = "histogram", name = var,
marker = list(line = list(color = 'white', width = 1))) %>%
layout(xaxis = list(title = var), yaxis = list(title = "Frekuensi"))
})
subplot(plots, nrows = ceiling(length(input$desc_vars)/2), shareX = FALSE, shareY = FALSE, titleX = TRUE, titleY = TRUE)
})
output$desc_boxplot <- renderPlotly({
req(input$desc_vars)
df <- desc_data_renamed()
plots <- lapply(input$desc_vars, function(var) {
plot_ly(df, y = ~get(var), type = "box", name = var, boxmean = TRUE,
marker = list(color = 'blue')) %>%
layout(yaxis = list(title = var))
})
subplot(plots, nrows = ceiling(length(input$desc_vars)/2), shareX = FALSE, shareY = FALSE)
})
output$desc_summary <- renderDT({
req(input$desc_vars)
df <- desc_data_renamed()
summary_df <- df %>%
select(all_of(input$desc_vars)) %>%
summarise(across(everything(), list(
Min = ~min(., na.rm = TRUE),
Q1 = ~quantile(., 0.25, na.rm = TRUE),
Median = ~median(., na.rm = TRUE),
Mean = ~mean(., na.rm = TRUE),
Q3 = ~quantile(., 0.75, na.rm = TRUE),
Max = ~max(., na.rm = TRUE),
SD = ~sd(., na.rm = TRUE)
))) %>%
pivot_longer(everything(), names_to = "Variable_Stat", values_to = "Value") %>%
separate(Variable_Stat, into = c("Variable", "Statistic"), sep = "_") %>%
pivot_wider(names_from = Statistic, values_from = Value)
datatable(summary_df, options = list(dom = 't', paging = FALSE, ordering = FALSE)) %>%
formatRound(columns = 2:8, digits = 2)
})
output$download_desc <- downloadHandler(
filename = function() {
paste0("Statistik_Deskriptif_", Sys.Date(), ".xlsx")
},
content = function(file) {
write.xlsx(desc_data_renamed(), file)
}
)
# ============================================================
# 5. SEBARAN DBD
# ============================================================
output$total_kasus <- renderValueBox({
valueBox(
value = format(total_JK, big.mark = ","),
subtitle = "Total Kasus DBD",
icon = icon("procedures"),
color = "red"
)
})
output$total_kematian <- renderValueBox({
valueBox(
value = format(total_KDBD, big.mark = ","),
subtitle = "Total Kematian DBD",
icon = icon("heart-broken"),
color = "maroon"
)
})
output$total_wilayah <- renderValueBox({
valueBox(
value = nrow(data),
subtitle = "Kabupaten/Kota",
icon = icon("map"),
color = "orange"
)
})
output$map_kasus <- renderLeaflet({
pal <- colorNumeric("YlOrRd", domain = jabar_merged$JK)
leaflet(jabar_merged) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(JK),
weight = 1,
opacity = 1,
color = "white",
fillOpacity = 0.7,
label = ~paste0(WADMKK, ": ", format(JK, big.mark = ","), " kasus"),
highlightOptions = highlightOptions(weight = 3, color = "#666", fillOpacity = 0.9)
) %>%
addLegend(pal = pal, values = ~JK,
title = "Jumlah Kasus", position = "bottomright")
})
# Moran's I
moran_result <- reactive({
x <- jabar_merged$JK
names(x) <- rownames(jabar_merged)
moran.test(x, WL, zero.policy = TRUE)
})
# Geary's C
geary_result <- reactive({
x <- jabar_merged$JK
names(x) <- rownames(jabar_merged)
geary.test(x, WL, zero.policy = TRUE)
})
output$moranI_box <- renderValueBox({
m <- moran_result()
valueBox(
value = round(m$estimate[1], 4),
subtitle = paste0("Moran's I (p: ", round(m$p.value, 4), ")"),
icon = icon("project-diagram"),
color = if(m$p.value < 0.05) "green" else "red"
)
})
output$gearyC_box <- renderValueBox({
g <- geary_result()
valueBox(
value = round(g$estimate[1], 4),
subtitle = paste0("Geary's C (p: ", round(g$p.value, 4), ")"),
icon = icon("chart-area"),
color = if(g$p.value < 0.05) "green" else "red"
)
})
output$moran_plot <- renderPlotly({
x <- jabar_merged$JK
names(x) <- rownames(jabar_merged)
wx <- lag.listw(WL, x, zero.policy = TRUE)
x_std <- scale(x)[,1]
wx_std <- scale(wx)[,1]
region_names <- data$kab_kota
quadrant <- case_when(
x_std > 0 & wx_std > 0 ~ "Q1: High-High",
x_std < 0 & wx_std > 0 ~ "Q2: Low-High",
x_std < 0 & wx_std < 0 ~ "Q3: Low-Low",
x_std > 0 & wx_std < 0 ~ "Q4: High-Low"
)
df_moran <- data.frame(
x = x_std,
wx = wx_std,
region = region_names,
quadrant = quadrant,
x_original = x,
wx_original = wx
)
colors <- c("Q1: High-High" = "#d62728",
"Q2: Low-High" = "#ff7f0e",
"Q3: Low-Low" = "#1f77b4",
"Q4: High-Low" = "#2ca02c")
plot_ly(df_moran,
x = ~x,
y = ~wx,
color = ~quadrant,
colors = colors,
type = 'scatter',
mode = 'markers',
marker = list(size = 10, line = list(color = 'white', width = 1)),
text = ~paste0("<b>", region, "</b><br>",
"Kasus: ", format(x_original, big.mark = ","), "<br>",
"Spatial Lag: ", round(wx_original, 2), "<br>",
"Kuadran: ", quadrant),
hoverinfo = 'text') %>%
add_lines(x = ~x, y = fitted(lm(wx ~ x, data = df_moran)),
name = "Trend Line",
line = list(color = 'black', width = 2, dash = 'dash'),
hoverinfo = 'skip',
showlegend = TRUE) %>%
layout(
title = list(text = "<b>Moran's I Scatterplot - Kasus DBD</b>", font = list(size = 16)),
xaxis = list(title = "Standardized Kasus DBD", zeroline = TRUE),
yaxis = list(title = "Spatial Lag", zeroline = TRUE),
hovermode = 'closest',
legend = list(x = 0.02, y = 0.98)
)
})
# LISA Map
output$lisa_map <- renderLeaflet({
x <- jabar_merged$JK
names(x) <- rownames(jabar_merged)
lisa <- localmoran(x, WL, zero.policy = TRUE)
x_std <- scale(x)
x_lag_std <- scale(lag.listw(WL, x, zero.policy = TRUE))
lisa_class <- rep("Not Significant", length(x))
sig <- lisa[, 5] < 0.05
lisa_class[sig & x_std > 0 & x_lag_std > 0] <- "High-High"
lisa_class[sig & x_std < 0 & x_lag_std < 0] <- "Low-Low"
lisa_class[sig & x_std > 0 & x_lag_std < 0] <- "High-Low"
lisa_class[sig & x_std < 0 & x_lag_std > 0] <- "Low-High"
jabar_merged$lisa_class <- lisa_class
pal <- colorFactor(c("red", "blue", "pink", "lightblue", "white"),
domain = c("High-High", "Low-Low", "High-Low", "Low-High", "Not Significant"))
leaflet(jabar_merged) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(lisa_class),
weight = 1,
opacity = 1,
color = "black",
fillOpacity = 0.7,
label = ~paste0(WADMKK, ": ", lisa_class, " (", format(JK, big.mark = ","), " kasus)"),
highlightOptions = highlightOptions(weight = 3, fillOpacity = 0.9)
) %>%
addLegend(pal = pal, values = ~lisa_class,
title = "LISA Cluster", position = "bottomright")
})
# Getis-Ord Gi*
output$getisord_map <- renderLeaflet({
x <- jabar_merged$JK
names(x) <- rownames(jabar_merged)
gi_z <- as.numeric(localG(x, WL, zero.policy = TRUE))
jabar_merged$z_Gistar <- gi_z
jabar_merged$hotcold <- case_when(
gi_z >= 1.96 ~ "Hot spot (p???0.05)",
gi_z <= -1.96 ~ "Cold spot (p???0.05)",
TRUE ~ "Not significant"
)
pal <- colorFactor(
palette = c("Hot spot (p???0.05)" = "#b2182b",
"Cold spot (p???0.05)" = "#2166ac",
"Not significant" = "grey85"),
domain = jabar_merged$hotcold
)
leaflet(jabar_merged) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(hotcold),
weight = 1,
opacity = 1,
color = "black",
fillOpacity = 0.7,
label = ~paste0(WADMKK, ": ", hotcold,
" (z = ", round(z_Gistar, 2), ", Kasus: ", format(JK, big.mark = ","), ")"),
highlightOptions = highlightOptions(weight = 3, fillOpacity = 0.9)
) %>%
addLegend(pal = pal, values = ~hotcold,
title = "Getis-Ord Gi*", position = "bottomright")
})
# ============================================================
# 6. UKURAN EPIDEMIOLOGI
# ============================================================
output$prev_jabar_box <- renderValueBox({
valueBox(
value = paste0(round(prevalensi_jabar, 2), "%"),
subtitle = "Prevalensi DBD Jawa Barat",
icon = icon("percentage"),
color = "light-blue"
)
})
output$cfr_jabar_box <- renderValueBox({
valueBox(
value = paste0(round(cfr_jabar, 2), "%"),
subtitle = "CFR DBD Jawa Barat",
icon = icon("heartbeat"),
color = "red"
)
})
# PETA PREVALENSI
output$map_prevalensi <- renderLeaflet({
breaks_prev <- c(0, 0.09, 0.13, 0.20, Inf)
labels_prev <- c("???0.09%", "0.10-0.13%", "0.14-0.20%", ">0.20%")
jabar_merged$Kategori_Prev <- cut(
jabar_merged$Prevalensi,
breaks = breaks_prev,
labels = labels_prev,
right = TRUE,
include.lowest = TRUE
)
pal <- colorFactor(
palette = c("???0.09%" = "#ffffb2",
"0.10-0.13%" = "#fecc5c",
"0.14-0.20%" = "#fd8d3c",
">0.20%" = "#e31a1c"),
domain = jabar_merged$Kategori_Prev
)
leaflet(jabar_merged) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(Kategori_Prev),
weight = 1,
opacity = 1,
color = "black",
fillOpacity = 0.7,
label = ~paste0(WADMKK, ": ", round(Prevalensi, 2), "%"),
highlightOptions = highlightOptions(weight = 3, fillOpacity = 0.9)
) %>%
addLegend(pal = pal, values = ~Kategori_Prev,
title = "Prevalensi (%)", position = "bottomright")
})
# PREVALENSI PER WILAYAH
prev_wilayah <- reactive({
req(input$prev_cities)
jabar_merged %>%
filter(WADMKK %in% input$prev_cities) %>%
select(WADMKK, JK, JP, Prevalensi) %>%
st_drop_geometry() %>%
arrange(desc(Prevalensi))
})
output$prev_table <- renderDT({
req(input$prev_cities)
df <- prev_wilayah()
datatable(
df,
colnames = c("Kabupaten/Kota", "Jumlah Kasus", "Populasi", "Prevalensi (%)"),
options = list(dom = 't', paging = FALSE, ordering = FALSE)
) %>%
formatRound(columns = "Prevalensi", digits = 2) %>%
formatCurrency(columns = c("JK", "JP"), currency = "", digits = 0)
})
output$prev_bar <- renderPlotly({
req(input$prev_cities)
df <- prev_wilayah()
plot_ly(df, x = ~Prevalensi, y = ~reorder(WADMKK, Prevalensi),
type = 'bar', orientation = 'h',
marker = list(color = '#3498db',
line = list(color = 'white', width = 1)),
text = ~paste0(round(Prevalensi, 2), "%"),
textposition = 'outside',
hoverinfo = 'text',
hovertext = ~paste0("<b>", WADMKK, "</b><br>",
"Prevalensi: ", round(Prevalensi, 2), "%<br>",
"Kasus: ", format(JK, big.mark = ","), "<br>",
"Populasi: ", format(JP, big.mark = ","))) %>%
layout(
title = "Prevalensi DBD per Kabupaten/Kota",
xaxis = list(title = "Prevalensi (%)"),
yaxis = list(title = ""),
margin = list(l = 150)
)
})
# PETA CFR
output$map_cfr <- renderLeaflet({
breaks_cfr <- c(0, 0.35, 0.51, 0.74, Inf)
labels_cfr <- c("???0.35%", "0.36-0.51%", "0.52-0.74%", ">0.74%")
jabar_merged$Kategori_CFR <- cut(
jabar_merged$CFR,
breaks = breaks_cfr,
labels = labels_cfr,
right = TRUE,
include.lowest = TRUE
)
pal <- colorFactor(
palette = c("???0.35%" = "#ffffb2",
"0.36-0.51%" = "#fecc5c",
"0.52-0.74%" = "#fd8d3c",
">0.74%" = "#e31a1c"),
domain = jabar_merged$Kategori_CFR
)
leaflet(jabar_merged) %>%
addTiles() %>%
addPolygons(
fillColor = ~pal(Kategori_CFR),
weight = 1,
opacity = 1,
color = "black",
fillOpacity = 0.7,
label = ~paste0(WADMKK, ": ", round(CFR, 2), "%"),
highlightOptions = highlightOptions(weight = 3, fillOpacity = 0.9)
) %>%
addLegend(pal = pal, values = ~Kategori_CFR,
title = "CFR (%)", position = "bottomright")
})
# CFR PER WILAYAH
cfr_wilayah <- reactive({
req(input$cfr_cities)
jabar_merged %>%
filter(WADMKK %in% input$cfr_cities) %>%
select(WADMKK, JK, KDBD, CFR) %>%
st_drop_geometry() %>%
arrange(desc(CFR))
})
output$cfr_table <- renderDT({
req(input$cfr_cities)
df <- cfr_wilayah()
datatable(
df,
colnames = c("Kabupaten/Kota", "Jumlah Kasus", "Kematian", "CFR (%)"),
options = list(dom = 't', paging = FALSE, ordering = FALSE)
) %>%
formatRound(columns = "CFR", digits = 2) %>%
formatCurrency(columns = c("JK", "KDBD"), currency = "", digits = 0)
})
output$cfr_bar <- renderPlotly({
req(input$cfr_cities)
df <- cfr_wilayah()
plot_ly(df, x = ~CFR, y = ~reorder(WADMKK, CFR),
type = 'bar', orientation = 'h',
marker = list(color = '#e74c3c',
line = list(color = 'white', width = 1)),
text = ~paste0(round(CFR, 2), "%"),
textposition = 'outside',
hoverinfo = 'text',
hovertext = ~paste0("<b>", WADMKK, "</b><br>",
"CFR: ", round(CFR, 2), "%<br>",
"Kasus: ", format(JK, big.mark = ","), "<br>",
"Kematian: ", KDBD)) %>%
layout(
title = "Case Fatality Rate per Kabupaten/Kota",
xaxis = list(title = "CFR (%)"),
yaxis = list(title = ""),
margin = list(l = 150)
)
})
}
# ============================================================
# 4. RUN APP
# ============================================================
shinyApp(ui = ui, server = server)