---
title: "Automated Bibliometric Analysis"
author: "Author"
date: "`r Sys.Date()`"
output: 
  html_document:
    theme: flatly
    toc: true
    toc_float:
      collapsed: true
    df_print: paged
    code_folding: hide
params:
  topik:
    label: "Research Topic"
    value: "Webinar Bibliometrix"
    input: text
  query_pencarian:
    label: "Search Query"
    value: 'TITLE-ABS-KEY("bibliometrix" OR "bibliometric analysis")'
    input: text
  file_data:
    label: "Select Data File"
    value: "/Users/muhammadyogaprabowo/Downloads/Webinar Bibliometrix R/Data/Scopus/scopus_export_Jun 13-2026_477af4e9-d5a2-48dc-85ea-859825fdc5a4.csv"
    input: file
  sumber_db:
    label: "Database Source"
    value: "scopus"
    input: select
    choices: ["scopus", "dimensions", "isi"]
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  echo = TRUE,
  warning = FALSE,
  message = FALSE,
  fig.width = 8,
  fig.height = 4.5,
  dpi = 300
)
```

## 1. Search Metadata & Configuration

Data and configuration are managed using document parameters. You can change them via the **"Knit with Parameters"** option in RStudio.

**Search Information:**

- **Topic:** `r params$topik`
- **Database:** `r toupper(params$sumber_db)`
- **Search Query:** `r params$query_pencarian`
- **Data File:** `r basename(params$file_data)`

```{r konfigurasi}
FILE_DATA <- params$file_data
SUMBER_DB <- params$sumber_db
NAMA_TOPIK <- params$topik
QUERY_PENCARIAN <- params$query_pencarian

# Folder Output untuk menyimpan hasil visualisasi dan data (akan dibuat jika belum ada)
DIR_OUTPUT <- "output_analisis"

if (!dir.exists(DIR_OUTPUT)) {
  dir.create(DIR_OUTPUT, recursive = TRUE)
}
```

## 2. Installation & Library Loading

```{r library}
# MENGGUNAKAN writexl ALIH-ALIH openxlsx UNTUK MENCEGAH CORRUPT
pkgs <- c("bibliometrix", "dplyr", "ggplot2", "igraph", "writexl", "htmlwidgets", "showtext", "kableExtra")
for (p in pkgs) { 
  if (!requireNamespace(p, quietly = TRUE)) install.packages(p) 
}
invisible(lapply(pkgs, library, character.only = TRUE))

# Warna tema standar ala Scopus langsung didefinisikan di fungsi terkait

# Mendefinisikan tema APA standar dengan font Helvetica
theme_apa <- function(base_size = 11, base_family = "Helvetica") {
  theme_classic(base_size = base_size, base_family = base_family) +
    theme(
      text             = element_text(family = base_family),
      axis.text        = element_text(color = "black", family = base_family),
      panel.background = element_rect(fill = "white", colour = NA),
      plot.background  = element_rect(fill = "white", colour = NA),
      panel.border     = element_blank(),
      axis.line        = element_line(color = "black")
    )
}

# Set theme secara global agar Helvetica diterapkan ke semua ggplot
theme_set(theme_apa())
```

## 3. Data Import & Cleaning

```{r import_clean}
cat(sprintf("Importing data from %s format...\n", toupper(SUMBER_DB)))

if (tolower(SUMBER_DB) == "dimensions" && grepl("\\.csv$", FILE_DATA, ignore.case = TRUE)) {
  # FIX: Dimensions CSV often has a metadata row at line 1 which crashes convert2df.
  first_line <- readLines(FILE_DATA, n = 1)
  if (grepl("^\"?About the data", first_line) || grepl("^\"?Exported", first_line)) {
    lines <- readLines(FILE_DATA)
    tmp_file <- tempfile(fileext = ".csv")
    cat(lines[-1], file = tmp_file, sep = "\n")
    M <- convert2df(tmp_file, dbsource = SUMBER_DB, format = "csv")
    unlink(tmp_file)
  } else {
    M <- convert2df(FILE_DATA, dbsource = SUMBER_DB, format = "csv")
  }
} else {
  M <- convert2df(FILE_DATA, dbsource = SUMBER_DB, format = ifelse(grepl("\\.csv$", FILE_DATA, ignore.case = TRUE), "csv", "plaintext"))
}
M <- as.data.frame(M)
n_awal <- nrow(M)

if ("DI" %in% names(M)) {
  M$DI_clean <- tolower(trimws(M$DI))
  M <- M[!(duplicated(M$DI_clean) & !is.na(M$DI_clean) & M$DI_clean != ""), ]
  M$DI_clean <- NULL
}

if ("TI" %in% names(M)) {
  M$TI_clean <- tolower(trimws(M$TI))
  M <- M[!duplicated(M$TI_clean), ]
  M$TI_clean <- NULL
}

if ("AU" %in% names(M)) M$AU[is.na(M$AU) | trimws(M$AU) == ""] <- "UNKNOWN"
if ("PY" %in% names(M)) M$PY[is.na(M$PY)] <- as.integer(format(Sys.Date(), "%Y"))
if ("TC" %in% names(M)) M$TC[is.na(M$TC)] <- 0

class(M) <- c("bibliometrixDB", "data.frame")
cat(sprintf("Cleaning complete: %d to %d unique documents\n", n_awal, nrow(M)))
```

## 4. Main Descriptive Analysis

```{r analisis_utama, results='hide'}
results <- biblioAnalysis(M, sep = ";")
summary_results <- summary(object = results, k = 10, pause = FALSE)

list_tabel <- list()

main_info <- as.data.frame(summary_results$MainInformationDF, stringsAsFactors = FALSE)
names(main_info) <- c("Indicator", "Value")
list_tabel[["Main Information"]] <- main_info

annual_prod <- as.data.frame(summary_results$AnnualProduction, stringsAsFactors = FALSE)
names(annual_prod) <- c("Year", "Articles")
annual_prod$Articles <- as.numeric(as.character(annual_prod$Articles))
list_tabel[["Annual Production"]] <- annual_prod

top_authors <- as.data.frame(summary_results$MostProdAuthors, stringsAsFactors = FALSE)
names(top_authors) <- c("Author", "Articles", "Fractional_Articles")
top_authors$Articles <- as.numeric(as.character(top_authors$Articles))
top_authors$Fractional_Articles <- as.numeric(as.character(top_authors$Fractional_Articles))
list_tabel[["Most Productive Authors"]] <- top_authors

if (!is.null(summary_results$MostRelSources)) {
  top_sources <- as.data.frame(summary_results$MostRelSources, stringsAsFactors = FALSE)
  names(top_sources) <- c("Journal", "Articles")
  top_sources$Articles <- as.numeric(as.character(top_sources$Articles))
  list_tabel[["Most Relevant Sources"]] <- top_sources
}

if (!is.null(summary_results$MostCitedPapers)) {
  # Paksa ke format dataframe murni untuk mencegah masalah di Excel
  top_cited <- as.data.frame(summary_results$MostCitedPapers, stringsAsFactors = FALSE)
  list_tabel[["Most Cited Articles"]] <- top_cited
}
```

### Table: Main Information
```{r}
library(knitr)
library(kableExtra)

format_tabel <- function(df) {
  kable(df, format = "html") %>%
    kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), 
                  full_width = FALSE, position = "left") %>%
    row_spec(0, bold = TRUE, color = "white", background = "#007398") # Scopus blue header
}

format_tabel(list_tabel[["Main Information"]])
```

### Table: Annual Production
```{r}
format_tabel(head(list_tabel[["Annual Production"]], 15))
```

### Table: Most Productive Authors
```{r}
format_tabel(head(list_tabel[["Most Productive Authors"]], 15))
```

### Table: Most Relevant Sources
```{r}
if (!is.null(list_tabel[["Most Relevant Sources"]])) {
  format_tabel(head(list_tabel[["Most Relevant Sources"]], 15))
}
```

### Table: Most Cited Articles
```{r}
if (!is.null(list_tabel[["Most Cited Articles"]])) {
  format_tabel(head(list_tabel[["Most Cited Articles"]], 15))
}
```

## 5. Visualization Results

(Following APA Style, there are no hardcoded plot titles. Titles should be provided in the manuscript's figure captions.)

### A. Annual Scientific Production Trend

```{r plot_tahunan}
p_annual <- ggplot(annual_prod, aes(x = as.numeric(as.character(Year)), y = Articles)) +
  geom_line(color = "#007398", linewidth = 1.2) +
  geom_point(color = "#e9711c", size = 3) +
  geom_area(fill = "#007398", alpha = 0.1) +
  scale_x_continuous(breaks = as.numeric(as.character(annual_prod$Year))) +
  labs(x = "Year", y = "Number of Articles") # Dihapus bagian Title

print(p_annual)
ggsave(file.path(DIR_OUTPUT, paste0(gsub(" ", "_", NAMA_TOPIK), "_01_Annual_Production.png")), plot = p_annual, width = 8, height = 4.5, dpi = 300)
```

### B. Most Productive Authors

```{r plot_penulis}
top20_au <- head(top_authors, 20)
p_authors <- ggplot(top20_au, aes(x = reorder(Author, Articles), y = Articles)) +
  geom_bar(stat = "identity", fill = "#007398") +
  coord_flip() +
  scale_y_continuous(breaks = function(x) { brks <- pretty(x); brks[brks %% 1 == 0] }) +
  labs(x = "Author", y = "Number of Articles")

print(p_authors)
ggsave(file.path(DIR_OUTPUT, paste0(gsub(" ", "_", NAMA_TOPIK), "_02_Top_Authors.png")), plot = p_authors, width = 8, height = 4.5, dpi = 300)
```

### C. Most Relevant Sources

```{r plot_jurnal}
if (!is.null(list_tabel[["Most Relevant Sources"]])) {
  top10_so <- head(list_tabel[["Most Relevant Sources"]], 10)
  top10_so$Journal <- stringr::str_wrap(top10_so$Journal, width = 30)
  
  p_sources <- ggplot(top10_so, aes(x = reorder(Journal, Articles), y = Articles)) +
    geom_bar(stat = "identity", fill = "#007398") +
    coord_flip() +
    scale_y_continuous(breaks = function(x) { brks <- pretty(x); brks[brks %% 1 == 0] }) +
    labs(x = "Journal", y = "Number of Articles")
    
  print(p_sources)
  ggsave(file.path(DIR_OUTPUT, paste0(gsub(" ", "_", NAMA_TOPIK), "_02b_Top_Journals.png")), plot = p_sources, width = 8, height = 4.5, dpi = 300)
}
```

### D. Most Cited Articles

```{r plot_sitasi}
if (!is.null(list_tabel[["Most Cited Articles"]])) {
  top10_tc <- head(list_tabel[["Most Cited Articles"]], 10)
  col_tc <- if ("Total Citations" %in% names(top10_tc)) "Total Citations" else "TC"
  
  if (col_tc %in% names(top10_tc)) {
    top10_tc$TC_Num <- as.numeric(as.character(top10_tc[[col_tc]]))
    top10_tc$Article_Short <- stringr::str_wrap(top10_tc$Paper, width = 35)
    
    p_cited <- ggplot(top10_tc, aes(x = reorder(Article_Short, TC_Num), y = TC_Num)) +
      geom_bar(stat = "identity", fill = "#e9711c") +
      coord_flip() +
      scale_y_continuous(breaks = function(x) { brks <- pretty(x); brks[brks %% 1 == 0] }) +
      labs(x = "Article", y = "Total Citations")
      
    print(p_cited)
    ggsave(file.path(DIR_OUTPUT, paste0(gsub(" ", "_", NAMA_TOPIK), "_02c_Top_Citations.png")), plot = p_cited, width = 8, height = 4.5, dpi = 300)
  }
}
```

### E. Keyword Co-occurrence Network

```{r plot_keyword}
if ("DE" %in% names(M) && !all(is.na(M$DE))) {
  NetKW <- biblioNetwork(M, analysis = "co-occurrences", network = "author_keywords", sep = ";")
  
  par(family = "Helvetica")
  invisible(networkPlot(NetKW, n = 40, type = "fruchterman", size = TRUE,
              edgesize = 3, labelsize = 0.7, cluster = "louvain",
              remove.isolates = TRUE, Title = "")) # Title dikosongkan (tidak di-hardcode)
  
  png(file.path(DIR_OUTPUT, paste0(gsub(" ", "_", NAMA_TOPIK), "_03_Keyword_Network.png")), width = 8, height = 4.5, units = "in", res = 300, family = "Helvetica")
  par(family = "Helvetica")
  invisible(networkPlot(NetKW, n = 40, type = "fruchterman", size = TRUE,
              edgesize = 3, labelsize = 0.7, cluster = "louvain",
              remove.isolates = TRUE, Title = "")) # Title dikosongkan
  invisible(dev.off())
}
```

### F. Country Collaboration Network

```{r plot_collab}
if ("AU_CO" %in% names(M) && !all(is.na(M$AU_CO))) {
  NetCollab <- biblioNetwork(M, analysis = "collaboration", network = "countries", sep = ";")
  
  png(file.path(DIR_OUTPUT, paste0(gsub(" ", "_", NAMA_TOPIK), "_03b_Collab_Network.png")), width = 8, height = 4.5, units = "in", res = 300, family = "Helvetica")
  par(family = "Helvetica")
  invisible(networkPlot(NetCollab, n = 30, type = "circle", size = TRUE,
              edgesize = 3, labelsize = 0.7, cluster = "louvain",
              remove.isolates = TRUE, Title = "")) 
  invisible(dev.off())
  
  par(family = "Helvetica")
  invisible(networkPlot(NetCollab, n = 30, type = "circle", size = TRUE,
              edgesize = 3, labelsize = 0.7, cluster = "louvain",
              remove.isolates = TRUE, Title = "")) 
}
```

### G. Author Co-citation Network

```{r plot_cocitation}
if ("CR" %in% names(M) && !all(is.na(M$CR)) && sum(M$CR != "", na.rm = TRUE) > 5) {
  tryCatch({
    NetCoCit <- biblioNetwork(M, analysis = "co-citation", network = "authors", sep = ";")
    
    if (nrow(NetCoCit) > 0) {
      png(file.path(DIR_OUTPUT, paste0(gsub(" ", "_", NAMA_TOPIK), "_03c_CoCitation_Network.png")), width = 8, height = 4.5, units = "in", res = 300, family = "Helvetica")
      par(family = "Helvetica")
      invisible(networkPlot(NetCoCit, n = 30, type = "fruchterman", size = TRUE,
                  edgesize = 3, labelsize = 0.7, cluster = "louvain",
                  remove.isolates = TRUE, Title = ""))
      invisible(dev.off())
      
      par(family = "Helvetica")
      invisible(networkPlot(NetCoCit, n = 30, type = "fruchterman", size = TRUE,
                  edgesize = 3, labelsize = 0.7, cluster = "louvain",
                  remove.isolates = TRUE, Title = ""))
    } else {
      cat("_Catatan: Data referensi (CR) terlalu sedikit untuk membentuk jaringan ko-sitasi._\n")
    }
  }, error = function(e) {
    cat("_Catatan: Gagal memproses jaringan ko-sitasi. Hal ini biasanya terjadi jika file ekspor dari database tidak menceklis opsi 'References' secara lengkap saat diunduh._\n")
  })
} else {
  cat("_Catatan: Analisis ko-sitasi tidak ditampilkan karena data referensi (CR) kosong atau tidak mencukupi._\n")
}
```

### H. Thematic Map

```{r plot_thematic}
if ("DE" %in% names(M) && !all(is.na(M$DE))) {
  TM <- thematicMap(M, field = "DE", n = 150, minfreq = 3, size = 0.5, repel = TRUE)
  
  p_thematic <- TM$map
  p_thematic$labels$title <- NULL # Hapus title bawaan thematicMap agar tidak hardcode
  
  print(p_thematic)
  ggsave(file.path(DIR_OUTPUT, paste0(gsub(" ", "_", NAMA_TOPIK), "_04_Thematic_Map.png")), plot = p_thematic, width = 8, height = 4.5, dpi = 300)
}
```

### I. Sankey Diagram (Three-Fields Plot)

```{r plot_sankey, fig.height=4.5, fig.width=8, out.width="100%"}
sankey_plot <- threeFieldsPlot(M, fields = c("SO", "AU", "DE"), n = c(15, 15, 15))
sankey_plot

sankey_html <- file.path(DIR_OUTPUT, paste0(gsub(" ", "_", NAMA_TOPIK), "_05_Sankey.html"))
saveWidget(sankey_plot, file = sankey_html, selfcontained = TRUE)
```

## 6. Tabular Data Export

```{r export_excel}
file_excel <- file.path(DIR_OUTPUT, paste0(gsub(" ", "_", NAMA_TOPIK), "_All_Data.xlsx"))
write_xlsx(list_tabel, path = file_excel)

cat("🎉 ANALYSIS COMPLETE!\n")
cat(sprintf("All tabular data has been saved to: %s\n", file_excel))
```
