library(sf)
## Linking to GEOS 3.13.1, GDAL 3.11.0, PROJ 9.6.0; sf_use_s2() is TRUE
library(ggplot2)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(scales)
library(tibble)
# Baca shapefile 
peta <- st_read("C:/Users/HP/Downloads/32.03_kecamatan.geojson")
## Reading layer `32.03_kecamatan' from data source 
##   `C:\Users\HP\Downloads\32.03_kecamatan.geojson' using driver `GeoJSON'
## Simple feature collection with 32 features and 4 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XYZ
## Bounding box:  xmin: 106.776 ymin: -7.505205 xmax: 107.4848 ymax: -6.602203
## z_range:       zmin: 0 zmax: 0
## Geodetic CRS:  WGS 84
peta
## Simple feature collection with 32 features and 4 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XYZ
## Bounding box:  xmin: 106.776 ymin: -7.505205 xmax: 107.4848 ymax: -6.602203
## z_range:       zmin: 0 zmax: 0
## Geodetic CRS:  WGS 84
## First 10 features:
##    kd_propinsi kd_dati2 kd_kecamatan  nm_kecamatan
## 1           32       03          001       Cianjur
## 2           32       03          002 Warungkondang
## 3           32       03          003       Cibeber
## 4           32       03          004        Cilaku
## 5           32       03          005     Ciranjang
## 6           32       03          006  Bojongpicung
## 7           32       03          007  Karangtengah
## 8           32       03          008         Mande
## 9           32       03          009      Sukaluyu
## 10          32       03          010         Pacet
##                          geometry
## 1  MULTIPOLYGON Z (((107.1268 ...
## 2  MULTIPOLYGON Z (((107.0884 ...
## 3  MULTIPOLYGON Z (((107.1299 ...
## 4  MULTIPOLYGON Z (((107.1876 ...
## 5  MULTIPOLYGON Z (((107.2621 ...
## 6  MULTIPOLYGON Z (((107.2552 ...
## 7  MULTIPOLYGON Z (((107.1787 ...
## 8  MULTIPOLYGON Z (((107.1506 ...
## 9  MULTIPOLYGON Z (((107.2208 ...
## 10 MULTIPOLYGON Z (((107.0747 ...
# Simulasi data PM2.5 untuk tiap kecamatan
set.seed(100)
data <- data.frame(
  Kecamatan = peta$nm_kecamatan, # kolom nama kecamatan
  PM25 = sample(20:90, length(peta$nm_kecamatan), replace = TRUE)
)
data
##        Kecamatan PM25
## 1        Cianjur   42
## 2  Warungkondang   89
## 3        Cibeber   23
## 4         Cilaku   74
## 5      Ciranjang   89
## 6   Bojongpicung   26
## 7   Karangtengah   26
## 8          Mande   74
## 9       Sukaluyu   62
## 10         Pacet   80
## 11      Cugenang   31
## 12 Cikalongkulon   70
## 13     Sukaresmi   37
## 14    Sukanagara   44
## 15       Campaka   21
## 16       Takokak   70
## 17    Kadupandak   87
## 18     Pagelaran   87
## 19     Tanggeung   71
## 20      Cibinong   67
## 21 Sindangbarang   51
## 22     Agrabinta   58
## 23        Cidaun   35
## 24     Naringgul   85
## 25  Campakamulya   89
## 26        Cikadu   64
## 27      Gekbrong   49
## 28       Cipanas   49
## 29        Cijati   48
## 30         Leles   50
## 31     Haurwangi   73
## 32     Pasirkuda   60
# Gabungkan data dengan peta
peta_data <- left_join(peta, data, by=c("nm_kecamatan"="Kecamatan"))
peta_data
## Simple feature collection with 32 features and 5 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XYZ
## Bounding box:  xmin: 106.776 ymin: -7.505205 xmax: 107.4848 ymax: -6.602203
## z_range:       zmin: 0 zmax: 0
## Geodetic CRS:  WGS 84
## First 10 features:
##    kd_propinsi kd_dati2 kd_kecamatan  nm_kecamatan PM25
## 1           32       03          001       Cianjur   42
## 2           32       03          002 Warungkondang   89
## 3           32       03          003       Cibeber   23
## 4           32       03          004        Cilaku   74
## 5           32       03          005     Ciranjang   89
## 6           32       03          006  Bojongpicung   26
## 7           32       03          007  Karangtengah   26
## 8           32       03          008         Mande   74
## 9           32       03          009      Sukaluyu   62
## 10          32       03          010         Pacet   80
##                          geometry
## 1  MULTIPOLYGON Z (((107.1268 ...
## 2  MULTIPOLYGON Z (((107.0884 ...
## 3  MULTIPOLYGON Z (((107.1299 ...
## 4  MULTIPOLYGON Z (((107.1876 ...
## 5  MULTIPOLYGON Z (((107.2621 ...
## 6  MULTIPOLYGON Z (((107.2552 ...
## 7  MULTIPOLYGON Z (((107.1787 ...
## 8  MULTIPOLYGON Z (((107.1506 ...
## 9  MULTIPOLYGON Z (((107.2208 ...
## 10 MULTIPOLYGON Z (((107.0747 ...

1. Choropleth Map

Choropleth map adalah peta tematik yang menampilkan data kuantitatif menggunakan gradasi warna sesuai dengan batas wilayah tertentu. Visualisasi ini sangat berguna dalam statistika lingkungan untuk melihat perbedaan spasial, misalnya distribusi polusi udara, curah hujan, atau kualitas air pada wilayah yang berbeda.

# Plot choropleth
ggplot(peta_data) +
  geom_sf(aes(fill=PM25), color="white") +
  geom_sf_text(aes(label = nm_kecamatan), size = 2, color = "white") +
  scale_fill_gradient(low="pink", high="navy", name="PM2.5") +
  theme_minimal() +
  labs(title="Choropleth Map PM2.5 - Kabupaten Cianjur")
## Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may not
## give correct results for longitude/latitude data

Interpretasi: Warna ungu tua = PM2.5 lebih tinggi Warna pink = lebih rendah. Terlihat ada kantong nilai tinggi di bagian tengah–selatan dan sebagian utara, sedangkan bagian tenggara lebih rendah. Artinya, udara berpotensi lebih kotor di area yang berwarna ungu tua dibanding yang pink.

Kesimpulan: Peta menunjukkan pola PM2.5 yang tidak merata: konsentrasi lebih tinggi terkumpul di tengah–selatan dan sebagian utara, sementara tenggara relatif lebih rendah. Area berwarna ungu tua sebaiknya jadi prioritas pemantauan dan mitigasi (cek sumber seperti lalu lintas, industri, atau pembakaran).

2. Lollipop Chart

Lollipop chart adalah grafik perbandingan kategori dimana titik mewakili nilai dan garis tipis menghubungkan titik ke sumbu, dan lebih ringkas untuk menonjolkan peringkat dan gap antar kategori.

rank_df <- peta_data %>%
  st_drop_geometry() %>%
  arrange(desc(PM25)) %>%
  mutate(nm = factor(nm_kecamatan, levels = rev(nm_kecamatan)))

ggplot(rank_df, aes(x = PM25, y = nm)) +
  geom_segment(aes(x = 0, xend = PM25, y = nm, yend = nm), linewidth = 0.5, color = "red") +
  geom_point(size = 3, color = "orange") +
  labs(title = "Lollipop Chart Ranking PM2.5 per Kecamatan",
       x = "PM2.5 (µg/m³)", y = NULL,
       subtitle = "Menonjolkan urutan & gap antar kecamatan") +
  theme_minimal(base_size = 11)

Interpretasi: - Fungsi grafik: mengurutkan kecamatan dari PM2.5 terendah (bawah) ke tertinggi (atas). Titik oranye = nilai tiap kecamatan; garis merah memudahkan melihat gap antar nilai.

Kesimpulan: Sebaran PM2.5 antarkecamatan tidak merata dan membentuk tiga klaster: rendah (~25–35), menengah (~50–70), dan tinggi (~80–90). Terdapat loncatan di kisaran 60–65 µg/m³ yang memisahkan kelompok menengah dan tinggi; karenanya kecamatan di atas ambang ini (terutama yang di ujung kanan) layak jadi prioritas pemantauan/mitigasi. Kecamatan dengan nilai rendah dapat dijadikan pembanding (baseline).

3. Donut Chart

Donut chart adalah versi pie chart dengan bagian tengah berlubang. Dipakai untuk menampilkan proporsi/komposisi kategori terhadap keseluruhan, biasanya dengan persentase pada tiap irisan.

# Contoh data WQI per curug 
curug <- tribble(
  ~curug,        ~WQI,
  "Citambur",     82,
  "Cikondang",    74,
  "Ngebul",       68,
  "Luhur",        56,
  "Cibeureum",    79,
  "Ciismun",      85
)

# Kategorisasi WQI (contoh umum): ≥80 Baik; 60–79 Sedang; ≤59 Buruk
sumcat <- curug %>%
  mutate(kategori = case_when(
    WQI >= 80 ~ "Baik",
    WQI >= 60 ~ "Sedang",
    TRUE      ~ "Buruk"
  )) %>%
  count(kategori) %>%
  mutate(prop = n / sum(n))

# Donut chart
ggplot(sumcat, aes(x = 2, y = prop, fill = kategori)) +
  geom_col(width = 1, color = "white") +
  coord_polar(theta = "y") +
  xlim(0.5, 2.5) +                        # bikin lubang donut
  geom_text(aes(label = percent(prop, 1)),
            position = position_stack(vjust = 0.5),
            color = "white", size = 4) +
  labs(
    title = "Donut Chart: Kategori Kualitas Air Curug di Cianjur",
    subtitle = "Contoh WQI: ≥80 Baik, 60–79 Sedang, ≤59 Buruk",
    fill = "Kategori"
  ) +
  theme_void() +
  theme(legend.position = "bottom")

Interpretasi: - Sedang: 50% → setengah curug kualitas airnya cukup, perlu monitoring rutin.

Kesimpulan: Komposisi kualitas air curug Cianjur didominasi kategori Sedang (50%), disusul Baik (33%) dan Buruk (17%). Lokasi Buruk perlu jadi prioritas pemulihan (telusuri sumber polutan, bersih-bersih rutin, edukasi pengunjung). Lokasi Sedang butuh peningkatan bertahap agar naik ke Baik, sementara lokasi Baik dijaga konsistensinya melalui monitoring berkala.