1. Choropleth Map

# install.packages(c("sf","leaflet","RColorBrewer","dplyr","ggplot2","tidyr","ggstream","scales","htmlwidgets"))

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(leaflet)
## Warning: package 'leaflet' was built under R version 4.5.1
library(RColorBrewer)
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(ggplot2)
library(tidyr)
library(ggstream)
## Warning: package 'ggstream' was built under R version 4.5.1
library(scales)
library(htmlwidgets)
## Warning: package 'htmlwidgets' was built under R version 4.5.1
# Baca file GeoJSON 
geo_path <- "Pemalang.geojson"
pemalang <- tryCatch(
  sf::st_read(geo_path, quiet = TRUE),
  error = function(e) stop("Gagal membaca Pemalang.geojson. Pastikan file ada di working directory.")
)

# Tampilkan struktur kolom sederhana
print(head(pemalang))
## Simple feature collection with 1 feature and 12 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 109.1856 ymin: -7.248885 xmax: 109.5992 ymax: -6.77493
## Geodetic CRS:  WGS 84
##   ID_0   COUNTRY      NAME_1 NL_NAME_1        ID_2   NAME_2 VARNAME_2 NL_NAME_2
## 1  IDN Indonesia Jawa Tengah      <NA> IDN.10.23_1 Pemalang      <NA>      <NA>
##      TYPE_2 ENGTYPE_2 CC_2   HASC_2                       geometry
## 1 Kabupaten   Regency 3327 ID.JT.PL MULTIPOLYGON (((109.2517 -7...
print(names(pemalang))
##  [1] "ID_0"      "COUNTRY"   "NAME_1"    "NL_NAME_1" "ID_2"      "NAME_2"   
##  [7] "VARNAME_2" "NL_NAME_2" "TYPE_2"    "ENGTYPE_2" "CC_2"      "HASC_2"   
## [13] "geometry"
# Jika tidak ada kolom numeric untuk peta, bikin kolom contoh 'value' (untuk choropleth)
if(!"value" %in% names(pemalang)){
  set.seed(2025)
  pemalang$value <- sample(50:400, size = nrow(pemalang), replace = TRUE)
  message("Kolom 'value' tidak ditemukan. Dibuat kolom contoh 'value' (random) untuk demo.")
}
## Kolom 'value' tidak ditemukan. Dibuat kolom contoh 'value' (random) untuk demo.
# Palet warna
pal <- colorBin("YlOrRd", domain = pemalang$value, bins = 6, na.color = "#CCCCCC")

labels <- paste0(
  "<strong>", ifelse("name" %in% names(pemalang), pemalang$name, paste("Unit", seq_len(nrow(pemalang)))),
  "</strong><br/>Value: ", formatC(pemalang$value, format="d", big.mark=",")
) %>% lapply(htmltools::HTML)

m <- leaflet(pemalang) %>%
  addProviderTiles("CartoDB.Positron") %>%
  addPolygons(
    fillColor = ~pal(value),
    weight = 0.6,
    opacity = 1,
    color = "white",
    dashArray = "3",
    fillOpacity = 0.8,
    highlightOptions = highlightOptions(weight = 2, color = "#666", dashArray = "", fillOpacity = 0.9, bringToFront = TRUE),
    label = labels,
    labelOptions = labelOptions(direction = "auto")
  ) %>%
  addLegend(pal = pal, values = ~value, opacity = 0.8, title = "Value", position = "bottomright")

m  # interaktif, akan tampil pada knitted HTML
# saveWidget(m, "pemalang_choropleth.html", selfcontained = TRUE)

2. Polar Area Chart (Coxcomb / Rose Chart)

# Buat data demo untuk polar chart
polar_df <- tibble::tibble(
  category = paste0("Kec.", seq_len(8)),
  value = sample(50:300, 8)
) %>%
  arrange(value) %>%
  mutate(category = factor(category, levels = category))

polar_df
## # A tibble: 8 × 2
##   category value
##   <fct>    <int>
## 1 Kec.2       59
## 2 Kec.7       76
## 3 Kec.4      162
## 4 Kec.6      181
## 5 Kec.1      236
## 6 Kec.5      253
## 7 Kec.3      254
## 8 Kec.8      264
# Plot: bar -> polar
p_polar <- ggplot(polar_df, aes(x = category, y = value)) +
  geom_col(alpha = 0.9) +
  coord_polar(theta = "x") +
  labs(title = "Polar Area Chart (Coxcomb)", x = NULL, y = NULL) +
  theme_minimal(base_size = 14) +
  theme(
    axis.text.y = element_blank(),
    axis.ticks = element_blank(),
    panel.grid = element_blank(),
    axis.text.x = element_text(size = 11, face = "bold")
  )

p_polar

Hasil visualisasi Polar Area Chart (Coxcomb) menunjukkan adanya variasi nilai antar kecamatan. Kecamatan 3, Kecamatan 5, dan Kecamatan 8 memiliki sektor yang paling panjang, menandakan nilai tertinggi dibandingkan kecamatan lainnya. Kecamatan 1, Kecamatan 6, dan Kecamatan 4 berada pada posisi menengah, sedangkan Kecamatan 2 dan Kecamatan 7 tampak memiliki nilai paling rendah karena luas sektornya relatif kecil. Temuan ini mengindikasikan adanya ketimpangan distribusi antar kecamatan, di mana beberapa kecamatan mendominasi dengan nilai besar, sementara yang lain relatif rendah. Interpretasi lebih lanjut akan sangat bergantung pada konteks data yang digunakan, apakah nilai tersebut merepresentasikan jumlah penduduk, hasil produksi, atau indikator lain yang menjadi fokus analisis.

3. Stream Graph (ggstream)

# Contoh data time-series untuk stream graph
set.seed(2025)
months <- seq.Date(from = as.Date("2024-01-01"), by = "month", length.out = 24)
series_names <- paste0("Sektor_", 1:5)

stream_df <- expand.grid(month = months, series = series_names) %>%
  as_tibble() %>%
  arrange(series, month) %>%
  mutate(value = round(abs(rnorm(n(), mean = 100, sd = 60))) + sample(0:50, n(), replace = TRUE))

# Tampilkan ringkasan
stream_df %>% group_by(series) %>% summarize(total = sum(value)) %>% arrange(desc(total))
## # A tibble: 5 × 2
##   series   total
##   <fct>    <dbl>
## 1 Sektor_1  3468
## 2 Sektor_2  2971
## 3 Sektor_3  2920
## 4 Sektor_4  2752
## 5 Sektor_5  2692
# Plot stream
p_stream <- ggplot(stream_df, aes(x = month, y = value, fill = series)) +
  geom_stream(type = "proportional") +   # type can be "ridge", "proportional", or "mirror"
  labs(title = "Stream Graph - Contoh Perkembangan Sektor (bulan)", x = "Bulan", y = "Value") +
  theme_minimal(base_size = 12) +
  scale_x_date(date_labels = "%Y-%m", date_breaks = "3 months") +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

p_stream

Stream graph ini memperlihatkan bahwa Sektor_1 adalah sektor dominan selama hampir dua tahun pengamatan, diikuti oleh Sektor_2. Sementara itu, Sektor_3 dan Sektor_4 menunjukkan dinamika naik-turun yang cukup signifikan, sedangkan Sektor_5 tetap relatif kecil kontribusinya. Dengan kata lain, struktur kontribusi antar sektor relatif stabil, meskipun sektor menengah (3 & 4) memiliki pola fluktuatif.

4. Violin Plot

# Data contoh: distribusi nilai per kecamatan
set.seed(123)
violin_df <- tibble::tibble(
  kecamatan = rep(paste0("Kec.", 1:6), each = 100),
  value = c(
    rnorm(100, mean = 80, sd = 15),
    rnorm(100, mean = 95, sd = 20),
    rnorm(100, mean = 70, sd = 10),
    rnorm(100, mean = 110, sd = 25),
    rnorm(100, mean = 90, sd = 18),
    rnorm(100, mean = 100, sd = 22)
  )
)
p_violin <- ggplot(violin_df, aes(x = kecamatan, y = value, fill = kecamatan)) +
  geom_violin(trim = FALSE, alpha = 0.8) +
  geom_boxplot(width = 0.1, outlier.size = 0.5, alpha = 0.6) +
  theme_minimal(base_size = 14) +
  labs(title = "Violin Plot Distribusi Nilai per Kecamatan", x = "Kecamatan", y = "Value") +
  theme(legend.position = "none")

p_violin

Berdasarkan violin plot, terlihat bahwa distribusi nilai antar kecamatan memiliki pola yang berbeda. Kecamatan 4 menunjukkan nilai median paling tinggi dengan sebaran yang luas, sedangkan Kecamatan 3 memiliki median paling rendah dengan variasi nilai yang relatif sempit. Sementara itu, Kecamatan 1, 2, 5, dan 6 berada pada kisaran menengah dengan sebaran data yang cukup bervariasi. Hal ini mengindikasikan adanya perbedaan tingkat nilai dan keragaman data antar kecamatan.

5. Chord Diagram

# install.packages("circlize") jika belum ada
library(circlize)
## Warning: package 'circlize' was built under R version 4.5.1
## ========================================
## circlize version 0.4.16
## CRAN page: https://cran.r-project.org/package=circlize
## Github page: https://github.com/jokergoo/circlize
## Documentation: https://jokergoo.github.io/circlize_book/book/
## 
## If you use it in published research, please cite:
## Gu, Z. circlize implements and enhances circular visualization
##   in R. Bioinformatics 2014.
## 
## This message can be suppressed by:
##   suppressPackageStartupMessages(library(circlize))
## ========================================
# Data relasi contoh antar kecamatan (matriks adjacency)
set.seed(42)
mat <- matrix(sample(50:200, 36, replace = TRUE), nrow = 6, ncol = 6)
rownames(mat) <- colnames(mat) <- paste0("Kec.", 1:6)

mat
##       Kec.1 Kec.2 Kec.3 Kec.4 Kec.5 Kec.6
## Kec.1    98   177   159   138    52   199
## Kec.2   114    96    69    76   107   107
## Kec.3   123    73   163   158    91   185
## Kec.4   195   120   160    54    73    85
## Kec.5   171   149   180   141    92   117
## Kec.6    98   138    90   153   192   195
# Reset circlize plot
circos.clear()
chordDiagram(mat, transparency = 0.25, grid.col = RColorBrewer::brewer.pal(6,"Set2"))
title("Chord Diagram Relasi Antar Kecamatan")

Berdasarkan chord diagram, terlihat bahwa seluruh kecamatan memiliki relasi satu sama lain dengan tingkat keterhubungan yang bervariasi. Kecamatan 2, Kecamatan 4, dan Kecamatan 6 tampak memiliki interaksi yang lebih dominan dibanding kecamatan lainnya, sedangkan kecamatan lain tetap terhubung namun dengan intensitas yang lebih kecil. Hal ini menunjukkan adanya pola hubungan yang kompleks antar kecamatan dalam data yang dianalisis.

6. Multiple Series 3D Bar Chart

library(plotly)
## Warning: package 'plotly' was built under R version 4.5.1
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
months <- month.abb[1:12]
series <- c("Sektor A","Sektor B","Sektor C")

bar3d_df <- expand.grid(month = months, series = series) %>%
  mutate(value = sample(50:200, n(), replace = TRUE))
bar3d_df
##    month   series value
## 1    Jan Sektor A   158
## 2    Feb Sektor A   141
## 3    Mar Sektor A    53
## 4    Apr Sektor A   148
## 5    May Sektor A   163
## 6    Jun Sektor A    55
## 7    Jul Sektor A   183
## 8    Aug Sektor A   179
## 9    Sep Sektor A   165
## 10   Oct Sektor A    52
## 11   Nov Sektor A   167
## 12   Dec Sektor A   198
## 13   Jan Sektor B    51
## 14   Feb Sektor B   151
## 15   Mar Sektor B   187
## 16   Apr Sektor B    89
## 17   May Sektor B    54
## 18   Jun Sektor B    82
## 19   Jul Sektor B   152
## 20   Aug Sektor B   158
## 21   Sep Sektor B   122
## 22   Oct Sektor B   125
## 23   Nov Sektor B    58
## 24   Dec Sektor B    84
## 25   Jan Sektor C    65
## 26   Feb Sektor C   150
## 27   Mar Sektor C   118
## 28   Apr Sektor C   167
## 29   May Sektor C   179
## 30   Jun Sektor C   131
## 31   Jul Sektor C   162
## 32   Aug Sektor C   195
## 33   Sep Sektor C   118
## 34   Oct Sektor C   159
## 35   Nov Sektor C   153
## 36   Dec Sektor C    89
library(plotly)
library(dplyr)

months <- month.abb[1:12]
series <- c("Sektor A","Sektor B","Sektor C")

bar3d_df <- expand.grid(month = months, series = series) %>%
  mutate(value = sample(50:200, n(), replace = TRUE))

# encode month & series sebagai angka unik
bar3d_df <- bar3d_df %>%
  mutate(
    x = as.numeric(factor(month, levels = month.abb[1:12])),
    y = as.numeric(factor(series, levels = unique(series))),
    z = value
  )

# plot 3D scatter (simulasi bar chart)
p_bar3d <- plot_ly(
  bar3d_df,
  x = ~x,
  y = ~y,
  z = ~z,
  type = "scatter3d",
  mode = "markers",
  marker = list(size = 8, color = ~z, colorscale = "Viridis", showscale = TRUE),
  text = ~paste("Month:", month, "<br>Series:", series, "<br>Value:", value),
  hoverinfo = "text"
) %>%
  layout(
    scene = list(
      xaxis = list(title = "Bulan", tickvals = 1:12, ticktext = month.abb[1:12]),
      yaxis = list(title = "Sektor", tickvals = 1:3, ticktext = unique(series)),
      zaxis = list(title = "Value")
    ),
    title = "Multiple Series 3D Scatter (Bar-like) Chart"
  )

p_bar3d