Kualitas udara menjadi isu penting di wilayah perkotaan, termasuk Kota Semarang yang memiliki aktivitas transportasi dan kepadatan penduduk tinggi. Salah satu polutan utama yang perlu diperhatikan adalah PM2.5 karena berisiko bagi kesehatan. Konsentrasinya dapat berbeda antar kecamatan dan waktu, dipengaruhi faktor lingkungan dan aktivitas manusia. Oleh karena itu, analisis spasial dan temporal diperlukan untuk melihat pola distribusi PM2.5 sebagai dasar kebijakan pengendalian polusi yang lebih tepat sasaran. Sumber: https://rkurniawan.blog/2025/05/01/unduh-file-geojson-batas-administrasi-pemekaran-38-provinsi-indonesia/ file : 33.22_Semarang

library(sf)
## Warning: package 'sf' was built under R version 4.5.1
## 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
peta <- st_read("~/SEMESTER 5/33.22_Semarang/33.22_kecamatan.geojson")
## Reading layer `33.22_kecamatan' from data source 
##   `C:\Users\X1 Carbon\OneDrive\Documents\SEMESTER 5\33.22_Semarang\33.22_kecamatan.geojson' 
##   using driver `GeoJSON'
## Simple feature collection with 19 features and 4 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XYZ
## Bounding box:  xmin: 110.2483 ymin: -7.49708 xmax: 110.6615 ymax: -7.077541
## z_range:       zmin: 0 zmax: 0
## Geodetic CRS:  WGS 84
peta
## Simple feature collection with 19 features and 4 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XYZ
## Bounding box:  xmin: 110.2483 ymin: -7.49708 xmax: 110.6615 ymax: -7.077541
## z_range:       zmin: 0 zmax: 0
## Geodetic CRS:  WGS 84
## First 10 features:
##    kd_propinsi kd_dati2 kd_kecamatan nm_kecamatan
## 1           33       22          001      Getasan
## 2           33       22          002     Tengaran
## 3           33       22          003      Susukan
## 4           33       22          004        Suruh
## 5           33       22          005      Pabelan
## 6           33       22          006      Tuntang
## 7           33       22          007    Banyubiru
## 8           33       22          008        Jambu
## 9           33       22          009     Sumowono
## 10          33       22          010     Ambarawa
##                          geometry
## 1  MULTIPOLYGON Z (((110.4393 ...
## 2  MULTIPOLYGON Z (((110.5316 ...
## 3  MULTIPOLYGON Z (((110.5807 ...
## 4  MULTIPOLYGON Z (((110.5905 ...
## 5  MULTIPOLYGON Z (((110.5297 ...
## 6  MULTIPOLYGON Z (((110.4549 ...
## 7  MULTIPOLYGON Z (((110.4255 ...
## 8  MULTIPOLYGON Z (((110.3665 ...
## 9  MULTIPOLYGON Z (((110.3149 ...
## 10 MULTIPOLYGON Z (((110.4091 ...
set.seed(100)

data <- data.frame(
  Kecamatan = peta$nm_kecamatan,   
  PM25 = sample(20:90, length(peta$nm_kecamatan), replace = TRUE)
)

head(data)
##   Kecamatan PM25
## 1   Getasan   42
## 2  Tengaran   89
## 3   Susukan   23
## 4     Suruh   74
## 5   Pabelan   89
## 6   Tuntang   26
# Gabungkan data dengan peta
peta_data <- left_join(peta, data, by=c("nm_kecamatan"="Kecamatan"))
peta_data
## Simple feature collection with 19 features and 5 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XYZ
## Bounding box:  xmin: 110.2483 ymin: -7.49708 xmax: 110.6615 ymax: -7.077541
## z_range:       zmin: 0 zmax: 0
## Geodetic CRS:  WGS 84
## First 10 features:
##    kd_propinsi kd_dati2 kd_kecamatan nm_kecamatan PM25
## 1           33       22          001      Getasan   42
## 2           33       22          002     Tengaran   89
## 3           33       22          003      Susukan   23
## 4           33       22          004        Suruh   74
## 5           33       22          005      Pabelan   89
## 6           33       22          006      Tuntang   26
## 7           33       22          007    Banyubiru   26
## 8           33       22          008        Jambu   74
## 9           33       22          009     Sumowono   62
## 10          33       22          010     Ambarawa   80
##                          geometry
## 1  MULTIPOLYGON Z (((110.4393 ...
## 2  MULTIPOLYGON Z (((110.5316 ...
## 3  MULTIPOLYGON Z (((110.5807 ...
## 4  MULTIPOLYGON Z (((110.5905 ...
## 5  MULTIPOLYGON Z (((110.5297 ...
## 6  MULTIPOLYGON Z (((110.4549 ...
## 7  MULTIPOLYGON Z (((110.4255 ...
## 8  MULTIPOLYGON Z (((110.3665 ...
## 9  MULTIPOLYGON Z (((110.3149 ...
## 10 MULTIPOLYGON Z (((110.4091 ...

Heatmap

library(tidyr)

# Buat data simulasi PM2.5 per bulan per kecamatan
set.seed(123)
heatmap_data <- expand.grid(
  Bulan = month.name[1:6],   # Januari - Juni
  Kecamatan = peta$nm_kecamatan
)

heatmap_data$PM25 <- sample(20:90, nrow(heatmap_data), replace = TRUE)

# Plot Heatmap
ggplot(heatmap_data, aes(x = Bulan, y = Kecamatan, fill = PM25)) +
  geom_tile(color = "white") +
  scale_fill_gradient(low="lightblue", high="red") +
  theme_minimal() +
  labs(title = "Heatmap PM2.5 per Kecamatan (Jan–Jun)",
       x = "Bulan", y = "Kecamatan", fill = "PM2.5") +
  theme(axis.text.x = element_text(angle=45, hjust=1))

menunjukkan variasi PM2.5 antar kecamatan dari Januari–Juni. Terlihat ada pola fluktuasi: beberapa kecamatan punya puncak polusi di bulan tertentu, artinya polusi tidak seragam sepanjang waktu.

Boxplot per Kecamatan

# Simulasi data harian untuk setiap kecamatan (30 hari)
set.seed(123)
box_data <- data.frame(
  Kecamatan = rep(peta$nm_kecamatan, each=30),
  PM25 = sample(20:90, length(peta$nm_kecamatan)*30, replace=TRUE)
)

# Plot Boxplot
ggplot(box_data, aes(x = Kecamatan, y = PM25, fill = Kecamatan)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "Distribusi PM2.5 per Kecamatan",
       x = "Kecamatan", y = "PM2.5") +
  theme(axis.text.x = element_text(angle=45, hjust=1),
        legend.position="none")

memperjelas perbedaan distribusi PM2.5 antar kecamatan. Ada kecamatan dengan median tinggi dan sebaran lebar (lebih rawan polusi), sementara kecamatan lain lebih rendah dan stabil.

Radar Chart (Spider Plot)

library(fmsb)
## Warning: package 'fmsb' was built under R version 4.5.1
# Ambil 5 kecamatan pertama untuk contoh
radar_data <- data.frame(
  PM25 = sample(20:90, 5),
  Suhu = sample(24:32, 5),         # suhu (°C)
  Kelembaban = sample(60:90, 5),   # %
  Populasi = sample(50000:150000, 5)
)
rownames(radar_data) <- peta$nm_kecamatan[1:5]

# Tambahkan baris max & min (syarat fmsb)
radar_data <- rbind(
  max = c(90, 35, 100, 150000),
  min = c(20, 20, 50, 50000),
  radar_data
)

# Plot Radar Chart
radarchart(radar_data, axistype=1,
           pcol=rainbow(5), plwd=2, plty=1,
           title="Radar Chart Indikator Lingkungan per Kecamatan (Contoh)")
legend("topright", legend=rownames(radar_data)[-c(1,2)],
       col=rainbow(5), lty=1, lwd=2, cex=0.8)

menampilkan perbandingan multi-indikator lingkungan (PM2.5, suhu, kelembaban, populasi). Dari sini terlihat bahwa kondisi tiap kecamatan punya keunggulan dan kerentanan berbeda, sehingga pendekatan kebijakan harus spesifik per wilayah.

Kesimpulan : Berdasarkan tiga visualisasi, kualitas udara di Kota Semarang menunjukkan variasi spasial dan temporal yang jelas. Heatmap memperlihatkan fluktuasi kadar PM2.5 antar kecamatan dari Januari hingga Juni, sementara boxplot menegaskan adanya perbedaan distribusi antar wilayah dengan beberapa kecamatan lebih rawan polusi. Radar chart menambahkan perspektif multi-indikator yang menunjukkan perbedaan karakteristik tiap kecamatan. Secara keseluruhan, kondisi lingkungan di Kota Semarang tidak merata dan dipengaruhi faktor geografis, kepadatan penduduk, serta iklim lokal, sehingga pemantauan berbasis wilayah sangat penting untuk perumusan kebijakan pengendalian polusi.