# TUGAS BIOSTATISTIKA INTERMEDIETE
# ANALISIS PENGUKURAN BERULANG TEKANAN DARAH SISTOLIK
# Nama         : Muhammad Ridhan Nazmy
# NIM          : 2611018008
# Rpubs        : r_nazmy
# Mata Kuliah  : Biostatistika Intermediete
# Magister Kesehatan Masyarakat Universitas Mulawarman
#
# Sumber data: James dkk. (2019), PLOS Medicine, S1 Data.
# Artikel: https://doi.org/10.1371/journal.pmed.1002870
# Data: https://doi.org/10.1371/journal.pmed.1002870.s007
# Analisis sekunder menggunakan RM ANOVA, Mixed Design ANOVA, dan LMM.

# ======================= PARAMETER ANALISIS =========================
FILE_DATA <- "pmed.1002870.s007.xls"
KELOMPOK_FOKUS <- "Drink powder"
FOLDER_HASIL <- "hasil_analisis_tds"
INSTALL_PAKET_OTOMATIS <- TRUE
SIMULASI_MISSING_TAMBAHAN <- FALSE # Data asli sudah memiliki nilai hilang.
BUKA_HTML_OTOMATIS <- TRUE
TAMPILKAN_GRAFIK_RSTUDIO <- TRUE # Tampilan grafik pada perangkat grafis aktif.

# ======================== PROGRAM UTAMA ==============================
jalankan_analisis <- function() {
  waktu_mulai <- Sys.time()
  paket <- c("readxl", "dplyr", "tidyr", "ggplot2", "afex", "emmeans",
             "rstatix", "car", "effectsize", "lme4", "lmerTest", "pbkrtest",
             "performance", "ggpubr", "knitr", "htmltools", "base64enc")
  belum <- paket[!vapply(paket, requireNamespace, logical(1), quietly = TRUE)]
  if (length(belum)) {
    if (!INSTALL_PAKET_OTOMATIS)
      stop("Paket belum tersedia: ", paste(belum, collapse = ", "))
    message("Menginstal paket: ", paste(belum, collapse = ", "))
    install.packages(belum, repos = "https://cloud.r-project.org")
  }
  gagal_paket <- paket[!vapply(paket, requireNamespace, logical(1), quietly = TRUE)]
  if (length(gagal_paket)) stop("Instalasi gagal: ", paste(gagal_paket, collapse = ", "))
  suppressPackageStartupMessages({
    library(dplyr); library(tidyr); library(ggplot2)
    library(afex); library(emmeans); library(rstatix)
    library(car); library(effectsize); library(lme4); library(lmerTest)
  })
  opsi_lama <- options(contrasts = c("contr.sum", "contr.poly"))
  on.exit(options(opsi_lama), add = TRUE)

  # Resolusi lokasi berkas data berdasarkan direktori script dan direktori kerja.
  sumber <- unlist(lapply(sys.frames(), function(fr) {
    if (!is.null(fr$ofile)) as.character(fr$ofile) else character(0)
  }))
  if (requireNamespace("rstudioapi", quietly = TRUE) && rstudioapi::isAvailable()) {
    aktif <- tryCatch(rstudioapi::getSourceEditorContext()$path,
                     error = function(e) "")
    if (nzchar(aktif)) sumber <- c(sumber, aktif)
  }
  kandidat <- unique(c(FILE_DATA, file.path(dirname(sumber), FILE_DATA)))
  kandidat <- kandidat[file.exists(kandidat)]
  if (!length(kandidat)) stop(
    "Berkas data tidak ditemukan pada direktori script atau direktori kerja.\n",
    "Nama file yang dicari: ", FILE_DATA)
  path_data <- normalizePath(kandidat[1], winslash = "/", mustWork = TRUE)
  folder <- file.path(dirname(path_data), FOLDER_HASIL)
  dir.create(folder, recursive = TRUE, showWarnings = FALSE)
  folder <- normalizePath(folder, winslash = "/", mustWork = TRUE)
  message("Data: ", path_data, "\nHasil: ", folder)

  # Penyusunan laporan HTML, tabel, dan visualisasi.
  isi <- character(0); status <- data.frame()
  tambah <- function(html) isi <<- c(isi, html)
  escape <- function(x) as.character(htmltools::htmlEscape(paste(x, collapse = "\n")))
  narasi <- function(x) tambah(paste0("<p>", escape(x), "</p>"))
  output <- function(x) {
    teks <- capture.output(print(x))
    cat(paste(teks, collapse = "\n"), "\n")
    tambah(paste0("<pre>", escape(teks), "</pre>"))
    invisible(x)
  }
  tabel <- function(x, nama) {
    x <- as.data.frame(x)
    write.csv(x, file.path(folder, paste0(nama, ".csv")), row.names = FALSE,
              na = "", fileEncoding = "UTF-8")
    if (nrow(x)) {
      tambah(paste0("<div class='table'>",
                    as.character(knitr::kable(x, format = "html", digits = 4)), "</div>"))
    } else narasi("Tidak ada baris untuk tabel ini.")
    print(x)
    invisible(x)
  }
  gambar <- function(p, nama, lebar = 10, tinggi = 6) {
    path <- file.path(folder, paste0(nama, ".png"))
    ggplot2::ggsave(path, plot = p, width = lebar, height = tinggi, dpi = 180)
    # Pencetakan eksplisit objek ggplot pada perangkat grafis aktif.
    # Grafik diekspor ke PNG dan disematkan pada laporan HTML.
    if (TAMPILKAN_GRAFIK_RSTUDIO) {
      tryCatch(print(p), error = function(e) {
        message("Tampilan Plots gagal, PNG tetap tersimpan: ", conditionMessage(e))
      })
    }
    tambah(paste0("<figure><img src='", base64enc::dataURI(file = path, mime = "image/png"),
                  "' alt='", escape(nama), "'><figcaption>", escape(nama), "</figcaption></figure>"))
    message("Grafik tersimpan: ", path)
  }
  bagian <- function(judul, f) {
    message("\n>>> ", judul)
    tambah(paste0("<h2>", escape(judul), "</h2>"))
    warnings <- character(0)
    ok <- tryCatch(withCallingHandlers({f(); TRUE}, warning = function(w) {
      warnings <<- c(warnings, conditionMessage(w)); invokeRestart("muffleWarning")
    }), error = function(e) {
      narasi(paste("BAGIAN GAGAL:", conditionMessage(e)))
      message("Bagian gagal: ", conditionMessage(e)); FALSE
    })
    if (length(warnings)) {
      narasi(paste("Peringatan estimasi:", paste(unique(warnings), collapse = "; ")))
    }
    status <<- rbind(status, data.frame(bagian = judul,
      status = if (ok) "Selesai" else "Gagal",
      peringatan = paste(unique(warnings), collapse = "; ")))
    invisible(ok)
  }
  fp <- function(p) {
    if (is.na(p)) return("tidak tersedia")
    if (p < .001) "< 0,001" else paste0("= ", formatC(p, digits = 3, format = "f", decimal.mark = ","))
  }
  ringkas_interaksi <- function(tab, pcol, model) {
    idx <- which(grepl("kelompok:waktu|waktu:kelompok", rownames(tab)))
    if (!length(idx)) {narasi("Efek interaksi tidak teridentifikasi secara otomatis pada tabel model."); return(invisible(NULL))}
    p <- as.numeric(tab[idx[1], pcol])
    narasi(paste0(model, ": interaksi kelompok × waktu memiliki p ", fp(p), ". ",
      if (is.na(p)) "Pengujian tidak dapat disimpulkan." else if (p < .05)
        "Terdapat bukti bahwa pola perubahan TDS berbeda antarkelompok. Perbedaan perubahan antarkelompok dievaluasi melalui kontras interaksi."
      else "Belum ditemukan bukti bahwa pola perubahan TDS berbeda antarkelompok. Ini tidak membuktikan kelompok setara."))
  }

  # ========================= 1. MEMBACA DATA ==========================
  raw <- as.data.frame(readxl::read_excel(path_data, sheet = 1))
  names(raw) <- trimws(names(raw))
  kolom_tds <- c("Systolic BP baseline", "Systolic BP midline", "Systolic BP endline")
  wajib <- c("Study ID", "Intervention", "Age at baseline (years)", "BMI Baseline", kolom_tds)
  if (!all(wajib %in% names(raw))) stop("Kolom tidak ditemukan: ",
    paste(setdiff(wajib, names(raw)), collapse = ", "))
  level_kelompok <- c("Control", "UNIMMAP", "Drink powder")
  label_waktu <- c("M0", "M5", "M12")
  minggu_nilai <- c(0, 5, 12)
  kel <- trimws(as.character(raw[["Intervention"]]))
  if (anyNA(kel) || any(!kel %in% level_kelompok)) stop("Label kelompok tidak dikenali.")
  if (anyNA(raw[["Study ID"]]) || anyDuplicated(raw[["Study ID"]])) stop("Study ID hilang atau duplikat.")
  if (!KELOMPOK_FOKUS %in% level_kelompok) stop("KELOMPOK_FOKUS tidak dikenali.")
  if (!all(vapply(raw[kolom_tds], is.numeric, logical(1)))) stop("TDS harus numerik.")
  if (any(!is.finite(as.matrix(raw[kolom_tds])) & !is.na(as.matrix(raw[kolom_tds]))))
    stop("TDS memiliki nilai tak hingga.")
  dat_wide <- data.frame(id = factor(raw[["Study ID"]]),
    kelompok = factor(kel, levels = level_kelompok),
    usia = raw[["Age at baseline (years)"]], bmi_baseline = raw[["BMI Baseline"]],
    TDS_M0 = raw[[kolom_tds[1]]], TDS_M5 = raw[[kolom_tds[2]]], TDS_M12 = raw[[kolom_tds[3]]])
  tds_names <- c("TDS_M0", "TDS_M5", "TDS_M12")
  dat_wide$lengkap <- complete.cases(dat_wide[tds_names])
  dat_long <- dat_wide |>
    pivot_longer(all_of(tds_names), names_to = "waktu", values_to = "tds") |>
    mutate(waktu = factor(waktu, levels = tds_names, labels = label_waktu),
           minggu = minggu_nilai[as.integer(waktu)]) |>
    arrange(id, waktu)
  wide_cc <- droplevels(dat_wide[dat_wide$lengkap, ])
  long_cc <- droplevels(filter(dat_long, lengkap))
  long_obs <- droplevels(filter(dat_long, !is.na(tds)))
  d1 <- droplevels(filter(long_cc, kelompok == KELOMPOK_FOKUS))
  if (nrow(wide_cc) < 10 || n_distinct(d1$id) < 4) stop("Peserta lengkap terlalu sedikit.")
  write.csv(dat_wide, file.path(folder, "data_wide.csv"), row.names = FALSE, na = "")
  write.csv(dat_long, file.path(folder, "data_long.csv"), row.names = FALSE, na = "")
  write.csv(wide_cc, file.path(folder, "data_complete_case.csv"), row.names = FALSE, na = "")

  bagian("1. Sumber, desain, dan kelengkapan data", function() {
    narasi("James dkk. (2019), PLOS Medicine, DOI 10.1371/journal.pmed.1002870. S1 Data: 10.1371/journal.pmed.1002870.s007. Analisis ini menggunakan luaran sekunder tekanan darah sistolik (mmHg). Populasi penelitian adalah perempuan usia reproduktif.")
    narasi("Desain analisis terdiri atas 3 kelompok dan 3 waktu pengukuran (minggu 0, 5, dan 12). RM ANOVA, Mixed Design ANOVA, dan LMM diterapkan sebagai analisis sekunder. Artikel sumber menggunakan regresi dengan penyesuaian baseline; perbedaan spesifikasi model dapat menghasilkan estimasi dan nilai p yang berbeda.")
    narasi(paste(nrow(dat_wide), "peserta;", nrow(wide_cc), "peserta lengkap untuk ANOVA;",
      nrow(long_obs), "pengukuran tersedia untuk LMM. Nilai hilang asli tidak diimputasi dan tidak dihapus dari berkas sumber."))
    tabel(dat_long |> group_by(kelompok, waktu) |>
      summarise(n_total = n(), n_tersedia = sum(!is.na(tds)),
                n_hilang = sum(is.na(tds)), .groups = "drop"), "01_kelengkapan")
    tabel(dat_wide |> group_by(kelompok) |>
      summarise(n_total = n(), n_lengkap = sum(lengkap),
                n_tidak_lengkap = sum(!lengkap), .groups = "drop"), "01_peserta")
    narasi("ANOVA memakai peserta dengan ketiga TDS tersedia. LMM memakai semua TDS yang teramati, dengan asumsi mekanisme missing yang dapat diabaikan (misalnya MAR bersyarat pada model); asumsi ini tidak otomatis terbukti dari dataset.")
  })

  # ======================= 2. EKSPLORASI ==============================
  bagian("2. Statistik deskriptif dan visualisasi", function() {
    desk <- function(d) d |> group_by(kelompok, waktu) |>
      summarise(n = n(), mean = mean(tds), sd = sd(tds),
        median = median(tds), min = min(tds), max = max(tds),
        se = sd/sqrt(n), lower_ci = mean - qt(.975, n-1)*se,
        upper_ci = mean + qt(.975, n-1)*se, .groups = "drop")
    tabel(desk(long_obs), "02_deskriptif_semua_tersedia")
    tabel(desk(long_cc), "02_deskriptif_complete_case")
    gambar(ggplot(long_obs, aes(minggu, tds, colour = kelompok, group = kelompok)) +
      stat_summary(fun = mean, geom = "line", linewidth = 1) +
      stat_summary(fun = mean, geom = "point", size = 2) +
      stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = .3) +
      scale_x_continuous(breaks = minggu_nilai) + theme_bw(base_size = 12) +
      theme(legend.position = "bottom") +
      labs(title = "TDS: semua pengukuran tersedia", x = "Minggu", y = "TDS (mmHg)", colour = "Kelompok"),
      "02_profil_tds")
    narasi("Interval kepercayaan pada grafik profil adalah CI rerata per sel, bukan CI selisih berpasangan. Peserta yang menyumbang rerata dapat berbeda antarwaktu.")
    gambar(ggplot(long_cc, aes(minggu, tds, group = id)) + geom_line(alpha = .15) +
      stat_summary(aes(group = kelompok), fun = mean, geom = "line", colour = "firebrick", linewidth = 1.1) +
      facet_wrap(~kelompok) + scale_x_continuous(breaks = minggu_nilai) + theme_bw() +
      labs(title = "Lintasan individu: peserta lengkap", x = "Minggu", y = "TDS (mmHg)"), "02_lintasan")
    for (g in level_kelompok) {
      z <- wide_cc[wide_cc$kelompok == g, tds_names]
      narasi(paste("Kovarians dan korelasi dalam kelompok:", g))
      output(round(cov(z), 3)); output(round(cor(z), 3))
      pasangan <- combn(tds_names, 2)
      tabel(data.frame(kelompok = g,
        pasangan = apply(pasangan, 2, paste, collapse = " - "),
        var_selisih = apply(pasangan, 2, function(p) var(z[[p[1]]] - z[[p[2]]]))),
        paste0("02_varians_selisih_", make.names(g)))
    }
    narasi("Matriks dihitung per kelompok agar perbedaan rerata intervensi tidak tercampur dengan kovarians dalam kelompok. Ketidaksamaan varians selisih merupakan petunjuk; uji Mauchly ada pada bagian ANOVA.")
  })

  # ======================== 3. ASUMSI =================================
  bagian("3. Asumsi ANOVA pada peserta lengkap", function() {
    tabel(long_cc |> group_by(kelompok, waktu) |> identify_outliers(tds), "03_outlier")
    tabel(long_cc |> group_by(kelompok, waktu) |> shapiro_test(tds), "03_shapiro")
    gambar(ggpubr::ggqqplot(long_cc, "tds", facet.by = c("kelompok", "waktu")),
           "03_qq_per_sel", 12, 9)
    tabel(long_cc |> group_by(waktu) |> levene_test(tds ~ kelompok), "03_levene")
    tabel(rstatix::box_m(wide_cc[tds_names], wide_cc$kelompok), "03_box_m")
    narasi("p > 0,05 tidak membuktikan normalitas atau kesamaan varians. Observasi yang teridentifikasi sebagai outlier dipertahankan dalam analisis; identifikasi statistik tidak dengan sendirinya membuktikan kesalahan pengukuran. Kelompok lengkap tidak sama besar. Jika Levene/Box M mengindikasikan heterogenitas kuat, ANOVA dan model lmer dengan residual homogen perlu ditinjau; koreksi GG tidak menyelesaikan heterogenitas antarkelompok.")
  })

  # ====================== 4. RM ANOVA SATU ARAH ========================
  aov1 <- NULL; aov2 <- NULL
  bagian("4. RM ANOVA satu kelompok", function() {
    narasi(paste("Kelompok fokus:", KELOMPOK_FOKUS, "—", n_distinct(d1$id), "peserta lengkap."))
    gambar(ggpubr::ggqqplot(d1, "tds", facet.by = "waktu") +
      labs(title = paste("Q–Q TDS per waktu:", KELOMPOK_FOKUS)), "04_qq_kelompok_fokus", 10, 5)
    output(rstatix::anova_test(data = d1, dv = tds, wid = id, within = waktu, effect.size = "pes"))
    aov1 <<- afex::aov_ez(id = "id", dv = "tds", data = d1, within = "waktu",
      anova_table = list(es = c("ges", "pes"), correction = "GG"))
    output(aov1); output(summary(aov1)); output(aov1$Anova)
    tabel(as.data.frame(aov1$anova_table) |> tibble::rownames_to_column("efek"), "04_anova_gg")
    output(effectsize::eta_squared(aov1, partial = TRUE))
    p <- as.numeric(aov1$anova_table[1, "Pr(>F)"])
    narasi(paste0("Efek waktu dengan koreksi GG: p ", fp(p), ". ",
      if (!is.na(p) && p < .05) "Ada bukti perbedaan rerata TDS antarwaktu dalam kelompok fokus."
      else "Belum ada bukti perbedaan rerata TDS antarwaktu dalam kelompok fokus."))
    narasi("Tabel utama memakai GG secara konsisten. Ringkasan memuat hasil tanpa koreksi, Mauchly, serta GG/HF. Perubahan dalam satu kelompok saja tidak membuktikan efek intervensi dibanding kontrol.")
  })
  bagian("4b. Grafik RM ANOVA satu kelompok", function() {
    if (is.null(aov1)) stop("Model RM ANOVA belum tersedia.")
    gambar(afex::afex_plot(aov1, x = "waktu", error = "within") +
      labs(title = paste("RM ANOVA:", KELOMPOK_FOKUS), x = "Waktu", y = "TDS (mmHg)"),
      "04_profil_rm_anova")
    narasi("Error bar within-subject menggambarkan ketidakpastian untuk perbandingan dalam peserta. Interval tersebut bukan CI perbedaan antarkelompok.")
  })
  bagian("5. Post hoc satu kelompok dan tren waktu", function() {
    if (is.null(aov1)) stop("Model RM ANOVA belum tersedia.")
    em <- emmeans::emmeans(aov1, ~ waktu, model = "multivariate")
    tabel(summary(em), "05_emmeans")
    tabel(summary(pairs(em, adjust = "bonferroni"), infer = c(TRUE, TRUE)), "05_pasangan_bonferroni")
    tabel(summary(contrast(em, "trt.vs.ctrl", ref = 1, adjust = "holm"),
                  infer = c(TRUE, TRUE)), "05_vs_baseline_holm")
    # Waktu tidak berjarak sama: koefisien ortogonal berdasarkan minggu asli.
    pol <- poly(minggu_nilai, degree = 2)
    koef <- list(linear_minggu = pol[, 1], kuadratik_minggu = pol[, 2])
    tabel(summary(contrast(em, method = koef, adjust = "holm"), infer = c(TRUE, TRUE)), "05_tren")
    narasi("Tren memakai minggu 0, 5, 12. Koefisien ortogonal dinormalisasi, sehingga estimate linear bukan kemiringan mmHg per minggu. Hanya linear dan kuadratik dapat dihitung; tren kubik tidak tersedia. CI dan p disesuaikan sesuai metode yang tertera pada output.")
  })

  # ====================== 6. NONPARAMETRIK ============================
  bagian("6. Pembanding nonparametrik satu kelompok", function() {
    tabel(rstatix::friedman_test(d1, tds ~ waktu | id), "06_friedman")
    tabel(rstatix::friedman_effsize(d1, tds ~ waktu | id), "06_kendall_w")
    # Penyusunan pasangan pengukuran berdasarkan ID peserta.
    w <- wide_cc[wide_cc$kelompok == KELOMPOK_FOKUS, ]
    ij <- combn(seq_along(tds_names), 2)
    hasil <- lapply(seq_len(ncol(ij)), function(j) {
      a <- ij[1, j]; b <- ij[2, j]
      wt <- wilcox.test(w[[tds_names[a]]], w[[tds_names[b]]], paired = TRUE, exact = FALSE)
      data.frame(waktu_1 = label_waktu[a], waktu_2 = label_waktu[b],
                 n_pasangan = nrow(w), V = unname(wt$statistic), p = wt$p.value)
    }) |> bind_rows() |> mutate(p_bonferroni = p.adjust(p, "bonferroni"))
    tabel(hasil, "06_wilcoxon")
    narasi("Friedman merupakan pembanding untuk efek waktu dalam satu kelompok; bukan pengganti pengujian interaksi kelompok × waktu. Wilcoxon signed-rank juga memiliki asumsi mengenai distribusi selisih. Pilihan metode perlu didasarkan pada desain dan diagnostik, bukan dipilih menurut nilai p yang lebih kecil.")
  })

  # ======================== 7. MIXED ANOVA ============================
  bagian("7. Mixed Design ANOVA kelompok × waktu", function() {
    aov2 <<- afex::aov_ez(id = "id", dv = "tds", data = long_cc,
      between = "kelompok", within = "waktu",
      anova_table = list(es = c("ges", "pes"), correction = "GG"))
    output(aov2); output(summary(aov2)); output(aov2$Anova)
    tabel(as.data.frame(aov2$anova_table) |> tibble::rownames_to_column("efek"), "07_anova_gg")
    output(effectsize::eta_squared(aov2, partial = TRUE))
    ringkas_interaksi(aov2$anova_table, "Pr(>F)", "Mixed Design ANOVA")
    narasi("Efek kelompok adalah perbedaan yang dirata-ratakan atas waktu; efek waktu dirata-ratakan atas kelompok. Interpretasi interaksi didasarkan pada profil kelompok dan kontras perubahan. Baseline p > 0,05 bukan bukti bahwa randomisasi berhasil atau kelompok benar-benar setara.")
  })
  bagian("7b. Visualisasi interaksi kelompok dan waktu", function() {
    if (is.null(aov2)) stop("Model Mixed Design ANOVA belum tersedia.")
    gambar(afex::afex_plot(aov2, x = "waktu", trace = "kelompok", error = "within",
      mapping = c("colour", "shape", "linetype")) +
      labs(title = "Mixed Design ANOVA: kelompok × waktu", x = "Waktu", y = "TDS (mmHg)"),
      "07_interaksi_anova")
    narasi("Visualisasi interaksi menggunakan afex_plot pada peserta dengan pengukuran lengkap. Grafik menyajikan rerata model, profil kelompok, dan error bar within-subject.")
  })

  # ======================= 8. EFEK SEDERHANA ==========================
  bagian("8. Efek sederhana dan post hoc antarkelompok", function() {
    if (is.null(aov2)) stop("Model Mixed Design ANOVA belum tersedia.")
    jt1 <- as.data.frame(joint_tests(aov2, by = "kelompok", model = "multivariate"))
    jt1$p_holm_antar_kelompok <- p.adjust(jt1$p.value, "holm")
    tabel(jt1, "08_efek_waktu_per_kelompok")
    jt2 <- as.data.frame(joint_tests(aov2, by = "waktu", model = "multivariate"))
    jt2$p_holm_antar_waktu <- p.adjust(jt2$p.value, "holm")
    tabel(jt2, "08_efek_kelompok_per_waktu")
    ew <- emmeans(aov2, ~ waktu | kelompok, model = "multivariate")
    tabel(summary(contrast(ew, "trt.vs.ctrl", ref = 1, adjust = "holm"),
                  infer = c(TRUE, TRUE)), "08_perubahan_vs_baseline")
    ek <- emmeans(aov2, ~ kelompok | waktu, model = "multivariate")
    tabel(summary(pairs(ek, adjust = "tukey"), infer = c(TRUE, TRUE)), "08_kelompok_per_waktu")
    narasi("Holm untuk perubahan vs baseline berlaku pada dua perbandingan dalam masing-masing kelompok. Tukey berlaku pada tiga pasangan kelompok dalam masing-masing waktu. Keduanya bukan koreksi gabungan seluruh tabel. Efek sederhana di atas merupakan analisis lanjutan/eksploratif, terutama bila interaksi keseluruhan tidak signifikan.")
  })

  # ===================== 9. KONTRAS INTERAKSI =========================
  bagian("9. Kontras perubahan baseline–akhir dan tren interaksi", function() {
    if (is.null(aov2)) stop("Model Mixed Design ANOVA belum tersedia.")
    e <- emmeans(aov2, ~ waktu * kelompok, model = "multivariate")
    perubahan <- contrast(e, interaction = list(
      waktu = list("M12-M0" = c(-1, 0, 1)), kelompok = "pairwise"), adjust = "holm")
    tabel(summary(perubahan, infer = c(TRUE, TRUE)), "09_selisih_perubahan")
    lin <- poly(minggu_nilai, degree = 2)[, 1]
    tren <- contrast(e, interaction = list(
      waktu = list(linear_minggu = lin), kelompok = "pairwise"), adjust = "holm")
    tabel(summary(tren, infer = c(TRUE, TRUE)), "09_tren_linear_interaksi")
    narasi("Kontras pertama membandingkan (TDS M12 − TDS M0) antarkelompok. Perubahan negatif berarti penurunan TDS. Estimate bertanda positif untuk Control − intervensi berarti perubahan kelompok intervensi lebih negatif (penurunannya lebih besar); interpretasi didasarkan pada CI dan nilai p Holm. Perbedaan signifikansi dalam masing-masing kelompok tidak dengan sendirinya membuktikan perbedaan efek antarkelompok.")
  })

  # ========================== 10. LMM ================================
  lmm <- NULL; lmm_ri <- NULL; lmm_rs <- NULL
  bagian("10. LMM dengan semua pengukuran tersedia", function() {
    # REML cocok untuk estimasi dan KR. Perbandingan AIC di sini mempunyai fixed effects sama.
    lmm_ri <<- lmerTest::lmer(tds ~ kelompok * waktu + (1 | id), data = long_obs,
      REML = TRUE, control = lmerControl(optimizer = "bobyqa"))
    lmm_rs <<- tryCatch(lmerTest::lmer(tds ~ kelompok * waktu + (1 + minggu | id), data = long_obs,
      REML = TRUE, control = lmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 200000))),
      error = function(e) {
        narasi(paste("Random slope gagal diestimasi; memakai random intercept:", conditionMessage(e)))
        NULL
      })
    info_model <- function(m, nama) data.frame(model = nama, n_observasi = nobs(m),
      AIC = AIC(m), BIC = BIC(m), singular = lme4::isSingular(m),
      konvergensi = paste(m@optinfo$conv$lme4$messages, collapse = "; "))
    info_rs <- if (!is.null(lmm_rs)) info_model(lmm_rs, "random_intercept_slope") else NULL
    tabel(bind_rows(info_model(lmm_ri, "random_intercept"), info_rs), "10_perbandingan_model")
    layak <- !is.null(lmm_rs) && !isSingular(lmm_rs) && is.null(lmm_rs@optinfo$conv$lme4$messages)
    pakai_rs <- layak && AIC(lmm_rs) < AIC(lmm_ri)
    lmm <<- if (pakai_rs) lmm_rs else lmm_ri
    narasi(paste("Model yang dipakai:", if (pakai_rs) "random intercept + slope minggu." else "random intercept."))
    narasi("Pemilihan ini memakai AIC dan diagnostik estimasi, bukan uji signifikansi slope acak. AIC merupakan pembanding relatif, bukan bukti bahwa asumsi model terpenuhi. Uji likelihood ratio standar untuk variance component memiliki persoalan batas parameter; tidak dipakai sebagai bukti formal di sini.")
    output(summary(lmm)); output(VarCorr(lmm))
    hasil <- anova(lmm, type = 3, ddf = "Kenward-Roger")
    tabel(as.data.frame(hasil) |> tibble::rownames_to_column("efek"), "10_lmm_kr")
    ringkas_interaksi(hasil, "Pr(>F)", "LMM seluruh pengukuran")
    output(performance::icc(lmm_ri))
    narasi("ICC di atas milik model random intercept. ICC pada model dengan slope acak bergantung pada waktu dan tidak boleh disamakan dengan satu persentase konstan. Faktor waktu pada fixed effects tetap kategorik; minggu numerik hanya digunakan pada random slope.")
    e <- emmeans(lmm, ~ waktu * kelompok, lmer.df = "kenward-roger")
    tabel(summary(contrast(e, interaction = list(waktu = list("M12-M0" = c(-1, 0, 1)),
      kelompok = "pairwise"), adjust = "holm"), infer = c(TRUE, TRUE)), "10_lmm_selisih_perubahan")
    tabel(summary(emmeans(lmm, ~ kelompok | waktu, lmer.df = "kenward-roger")), "10_lmm_rerata")
    narasi("LMM mencakup kelompok, waktu, dan interaksi kelompok × waktu tanpa penyesuaian usia, BMI, status kehamilan, atau status puasa. Estimasi yang diperoleh merupakan hasil model tanpa pengendalian kovariat tersebut.")
  })

  bagian("11. Diagnostik LMM", function() {
    if (is.null(lmm)) stop("LMM belum tersedia.")
    diag <- data.frame(fitted = fitted(lmm), residual = resid(lmm), kelompok = long_obs$kelompok,
                       waktu = long_obs$waktu)
    gambar(ggplot(diag, aes(sample = residual)) + stat_qq() + stat_qq_line() + theme_bw() +
      labs(title = "Q–Q residual LMM"), "11_qq_residual")
    gambar(ggplot(diag, aes(fitted, residual, colour = kelompok)) + geom_point(alpha = .35) +
      geom_hline(yintercept = 0, linetype = 2) + theme_bw() +
      labs(x = "Prediksi", y = "Residual", title = "Residual terhadap prediksi"), "11_residual_prediksi")
    gambar(ggplot(diag, aes(waktu, residual, fill = kelompok)) + geom_boxplot() + theme_bw() +
      labs(title = "Residual menurut kelompok dan waktu"), "11_residual_sel")
    re <- ranef(lmm)$id
    for (nm in names(re)) gambar(ggplot(data.frame(nilai = re[[nm]]), aes(sample = nilai)) +
      stat_qq() + stat_qq_line() + theme_bw() + labs(title = paste("Q–Q efek acak", nm)),
      paste0("11_qq_acak_", make.names(nm)))
    output(performance::check_singularity(lmm))
    output(performance::check_convergence(lmm))
    narasi("Diagnostik mencakup bentuk distribusi residual, observasi ekstrem, dan variasi residual antarsel. Model lmer mengasumsikan residual homogen dan independen bersyarat pada efek acak. Model tidak mensyaratkan sferisitas, tetapi tetap memerlukan evaluasi asumsi residual dan efek acak.")
  })
  bagian("11b. Visualisasi diagnostik LMM tiga panel", function() {
    if (is.null(lmm)) stop("LMM belum tersedia.")
    # Gambar base-R tiga panel: Q-Q residual, Q-Q intercept acak, residual vs prediksi.
    plot_tiga <- function() {
      par_lama <- par(mfrow = c(1, 3), mar = c(4, 4, 3, 1))
      on.exit(par(par_lama), add = TRUE)
      qqnorm(resid(lmm), main = "Q-Q residual"); qqline(resid(lmm))
      qqnorm(ranef(lmm)$id[, 1], main = "Q-Q intercept acak")
      qqline(ranef(lmm)$id[, 1])
      plot(fitted(lmm), resid(lmm), xlab = "Nilai prediksi", ylab = "Residual",
           main = "Residual vs prediksi", pch = 16, col = grDevices::adjustcolor("black", .3))
      abline(h = 0, lty = 2)
    }
    path <- file.path(folder, "11_diagnostik_lmm_tiga_panel.png")
    grDevices::png(path, width = 2400, height = 800, res = 180)
    tryCatch(plot_tiga(), finally = grDevices::dev.off())
    if (TAMPILKAN_GRAFIK_RSTUDIO) plot_tiga()
    tambah(paste0("<figure><img src='", base64enc::dataURI(file = path, mime = "image/png"),
                  "' alt='Diagnostik LMM tiga panel'><figcaption>Diagnostik LMM tiga panel</figcaption></figure>"))
    message("Grafik tersimpan: ", path)
  })
  bagian("11c. Grafik rerata prediksi LMM", function() {
    if (is.null(lmm)) stop("LMM belum tersedia.")
    pred <- as.data.frame(summary(emmeans(lmm, ~ kelompok | waktu,
      lmer.df = "kenward-roger")))
    pred$minggu <- minggu_nilai[as.integer(pred$waktu)]
    gambar(ggplot(pred, aes(minggu, emmean, colour = kelompok, group = kelompok)) +
      geom_line(linewidth = 1) + geom_point(size = 2.5) +
      geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL), width = .3) +
      scale_x_continuous(breaks = minggu_nilai) + theme_bw(base_size = 12) +
      theme(legend.position = "bottom") +
      labs(title = "Rerata prediksi LMM dan 95% CI", x = "Minggu", y = "TDS (mmHg)",
           colour = "Kelompok"), "11_profil_prediksi_lmm")
    narasi("Grafik LMM memakai seluruh pengukuran tersedia. Error bar merupakan CI rerata prediksi per sel, bukan CI selisih antar kelompok.")
  })

  bagian("12. LMM pada peserta lengkap: pembanding ANOVA", function() {
    if (is.null(lmm)) stop("LMM belum tersedia.")
    mcc <- update(lmm, data = long_cc)
    output(summary(mcc))
    tab <- anova(mcc, type = 3, ddf = "Kenward-Roger")
    tabel(as.data.frame(tab) |> tibble::rownames_to_column("efek"), "12_lmm_complete_case")
    ringkas_interaksi(tab, "Pr(>F)", "LMM peserta lengkap")
    narasi("ANOVA dan LMM ini memakai peserta yang sama. Perbedaan dengan LMM semua pengukuran dapat berasal dari tambahan data dan asumsi kovarians. Tabel bukan pengujian formal atas selisih nilai p antar model.")
    if (SIMULASI_MISSING_TAMBAHAN) {
      set.seed(2026)
      dm <- long_cc
      pos <- which(dm$waktu != "M0")
      dm$tds[sample(pos, min(30L, length(pos)))] <- NA_real_
      ms <- update(lmm, data = dm, na.action = na.omit)
      output(anova(ms, type = 3, ddf = "Kenward-Roger"))
      narasi("Output tambahan ini SIMULASI kehilangan pengukuran, bukan hasil data asli. Seed = 2026; maksimal 30 pengukuran pasca-baseline dihilangkan dari peserta lengkap.")
    } else narasi("Simulasi missing tambahan dimatikan karena data jurnal sudah memiliki missing asli.")
  })

  bagian("13. Informasi sesi dan batas interpretasi", function() {
    narasi("Taraf signifikansi ditetapkan pada α = 0,05. Interpretasi hasil mempertimbangkan nilai p, ukuran efek, interval kepercayaan, dan arah perubahan. Nilai p yang ditampilkan sebagai 0 akibat pembulatan dilaporkan sebagai p < 0,001.")
    narasi("Analisis menggunakan tiga waktu pengukuran asli tanpa penambahan pengukuran atau rekonstruksi data. Tren kubik tidak diestimasi karena hanya tersedia tiga waktu pengukuran. Kelayakan model ANOVA dan LMM dievaluasi berdasarkan diagnostik dan asumsi masing-masing model.")
    output(sessionInfo())
  })

  # ======================= 14. MENYIMPAN LAPORAN ======================
  tambah("<h2>Status setiap bagian</h2>")
  tabel(status, "status_analisis")
  tambah("<details><summary>Syntax yang digunakan</summary>")
  file_script <- sumber[file.exists(sumber) & grepl("\\.R$", sumber, ignore.case = TRUE)]
  if (length(file_script)) tambah(paste0("<pre>", escape(readLines(tail(file_script, 1), warn = FALSE)), "</pre>"))
  tambah("</details>")
  css <- "body{font:16px/1.6 Arial,sans-serif;max-width:1100px;margin:40px auto;padding:0 24px;color:#18332e}h1,h2{color:#0b6b4f}h2{border-top:1px solid #d9e4e0;padding-top:24px}pre{background:#f0f5f3;padding:16px;overflow:auto;font-size:13px;color:#182822}.table{overflow:auto}table{border-collapse:collapse;font-size:13px;width:100%}td,th{border:1px solid #d9e4e0;padding:8px;text-align:left}th{background:#e7f2ee}img{max-width:100%}summary{cursor:pointer;font-weight:bold}"
  selesai <- sum(status$status == "Selesai")
  header <- paste0("<!doctype html><html lang='id'><head><meta charset='UTF-8'>",
    "<meta name='viewport' content='width=device-width,initial-scale=1'>",
    "<title>Analisis TDS jurnal — pengukuran berulang</title><style>", css, "</style></head><body>",
    "<h1>Analisis Pengukuran Berulang: Tekanan Darah Sistolik</h1>",
    "<table class='identitas'><tbody>",
    "<tr><th>Nama</th><td>Muhammad Ridhan Nazmy</td></tr>",
    "<tr><th>NIM</th><td>2611018008</td></tr>",
    "<tr><th>Rpubs</th><td>r_nazmy</td></tr>",
    "<tr><th>Mata Kuliah</th><td>Biostatistika Intermediete</td></tr>",
    "<tr><th>Program Studi / Institusi</th><td>Magister Kesehatan Masyarakat Universitas Mulawarman</td></tr>",
    "</tbody></table>",
    "<p>Data James dkk. (2019), PLOS Medicine · 3 kelompok × 3 waktu</p>",
    "<p>Dibuat: ", escape(format(Sys.time())), " · Bagian selesai: ", selesai, "/", nrow(status), "</p>")
  path_html <- file.path(folder, "laporan_analisis_tds.html")
  writeLines(c(header, isi, "</body></html>"), path_html, useBytes = TRUE)
  saveRDS(list(data_wide = dat_wide, data_long = dat_long, aov_satu = aov1,
               aov_campuran = aov2, lmm = lmm, status = status), file.path(folder, "objek_analisis.rds"))
  writeLines(capture.output(sessionInfo()), file.path(folder, "sessionInfo.txt"))
  message("\nLaporan tersedia: ", path_html,
          "\nDurasi: ", round(as.numeric(difftime(Sys.time(), waktu_mulai, units = "secs")), 1), " detik.")
  if (any(status$status == "Gagal")) message("Terdapat bagian analisis yang gagal; rinciannya tercatat dalam status_analisis.csv dan laporan HTML.")
  if (BUKA_HTML_OTOMATIS && interactive()) try(utils::browseURL(path_html), silent = TRUE)
  invisible(list(folder = folder, status = status))
}

# Eksekusi analisis.
hasil_analisis <- jalankan_analisis()
## Registered S3 method overwritten by 'lme4':
##   method           from
##   na.action.merMod car
## Data: /Users/nazmy/Downloads/paket_analisis_tds/pmed.1002870.s007.xls
## Hasil: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds
## 
## >>> 1. Sumber, desain, dan kelengkapan data
##       kelompok waktu n_total n_tersedia n_hilang
## 1      Control    M0     100        100        0
## 2      Control    M5     100         93        7
## 3      Control   M12     100         82       18
## 4      UNIMMAP    M0     105        104        1
## 5      UNIMMAP    M5     105         92       13
## 6      UNIMMAP   M12     105         84       21
## 7 Drink powder    M0      93         93        0
## 8 Drink powder    M5      93         88        5
## 9 Drink powder   M12      93         77       16
##       kelompok n_total n_lengkap n_tidak_lengkap
## 1      Control     100        80              20
## 2      UNIMMAP     105        81              24
## 3 Drink powder      93        77              16
## 
## >>> 2. Statistik deskriptif dan visualisasi
##       kelompok waktu   n     mean       sd   median      min      max       se
## 1      Control    M0 100 115.2733 14.49512 114.0000 87.33334 155.6667 1.449512
## 2      Control    M5  93 107.7061 12.28819 106.6667 81.33334 157.0000 1.274226
## 3      Control   M12  82 107.1870 11.99189 105.6667 84.33334 144.3333 1.324283
## 4      UNIMMAP    M0 104 114.3365 13.43051 113.8333 88.33334 173.3333 1.316970
## 5      UNIMMAP    M5  92 109.2464 11.27824 108.5000 86.66666 160.6667 1.175838
## 6      UNIMMAP   M12  84 107.4524 10.73418 106.6667 89.33334 139.0000 1.171195
## 7 Drink powder    M0  93 115.7670 13.71666 113.6667 85.33334 163.6667 1.422352
## 8 Drink powder    M5  88 108.4091 11.07558 107.3333 88.00000 142.6667 1.180661
## 9 Drink powder   M12  77 105.6234 10.11590 104.3333 89.00000 138.0000 1.152814
##   lower_ci upper_ci
## 1 112.3972 118.1495
## 2 105.1754 110.2368
## 3 104.5521 109.8219
## 4 111.7246 116.9484
## 5 106.9107 111.5820
## 6 105.1229 109.7818
## 7 112.9421 118.5919
## 8 106.0624 110.7558
## 9 103.3273 107.9194
##       kelompok waktu  n     mean       sd   median      min      max       se
## 1      Control    M0 80 115.2458 13.12953 114.5000 88.33334 155.6667 1.467927
## 2      Control    M5 80 107.3375 11.65834 106.6667 81.33334 157.0000 1.303443
## 3      Control   M12 80 107.0708 12.07078 105.6667 84.33334 144.3333 1.349554
## 4      UNIMMAP    M0 81 113.7901 13.86347 112.0000 88.33334 173.3333 1.540385
## 5      UNIMMAP    M5 81 109.1646 11.31544 108.0000 86.66666 160.6667 1.257271
## 6      UNIMMAP   M12 81 107.1811 10.74374 106.0000 89.33334 139.0000 1.193749
## 7 Drink powder    M0 77 116.2078 14.16053 113.6667 85.33334 163.6667 1.613742
## 8 Drink powder    M5 77 108.4026 11.41000 107.3333 88.00000 142.6667 1.300290
## 9 Drink powder   M12 77 105.6234 10.11590 104.3333 89.00000 138.0000 1.152814
##   lower_ci upper_ci
## 1 112.3240 118.1677
## 2 104.7431 109.9319
## 3 104.3846 109.7571
## 4 110.7247 116.8556
## 5 106.6626 111.6667
## 6 104.8054 109.5567
## 7 112.9937 119.4218
## 8 105.8128 110.9924
## 9 103.3273 107.9194

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/02_profil_tds.png

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/02_lintasan.png
##          TDS_M0  TDS_M5 TDS_M12
## TDS_M0  172.385 106.420 106.566
## TDS_M5  106.420 135.917 103.717
## TDS_M12 106.566 103.717 145.704 
##         TDS_M0 TDS_M5 TDS_M12
## TDS_M0   1.000  0.695   0.672
## TDS_M5   0.695  1.000   0.737
## TDS_M12  0.672  0.737   1.000 
##   kelompok         pasangan var_selisih
## 1  Control  TDS_M0 - TDS_M5    95.46266
## 2  Control TDS_M0 - TDS_M12   104.95634
## 3  Control TDS_M5 - TDS_M12    74.18677
##          TDS_M0  TDS_M5 TDS_M12
## TDS_M0  192.196 120.700 109.179
## TDS_M5  120.700 128.039  95.649
## TDS_M12 109.179  95.649 115.428 
##         TDS_M0 TDS_M5 TDS_M12
## TDS_M0   1.000  0.769   0.733
## TDS_M5   0.769  1.000   0.787
## TDS_M12  0.733  0.787   1.000 
##   kelompok         pasangan var_selisih
## 1  UNIMMAP  TDS_M0 - TDS_M5    78.83439
## 2  UNIMMAP TDS_M0 - TDS_M12    89.26609
## 3  UNIMMAP TDS_M5 - TDS_M12    52.16917
##          TDS_M0  TDS_M5 TDS_M12
## TDS_M0  200.521 105.048  92.531
## TDS_M5  105.048 130.188  88.488
## TDS_M12  92.531  88.488 102.331 
##         TDS_M0 TDS_M5 TDS_M12
## TDS_M0   1.000  0.650   0.646
## TDS_M5   0.650  1.000   0.767
## TDS_M12  0.646  0.767   1.000 
##       kelompok         pasangan var_selisih
## 1 Drink powder  TDS_M0 - TDS_M5   120.61215
## 2 Drink powder TDS_M0 - TDS_M12   117.78994
## 3 Drink powder TDS_M5 - TDS_M12    55.54272
## 
## >>> 3. Asumsi ANOVA pada peserta lengkap
##        kelompok waktu  id     usia bmi_baseline lengkap      tds minggu
## 1       Control    M0 219 27.80561     25.05134    TRUE 155.6667      0
## 2       Control    M0 251 44.75565     16.35249    TRUE 147.6667      0
## 3       Control    M5 219 27.80561     25.05134    TRUE 157.0000      5
## 4       Control   M12 219 27.80561     25.05134    TRUE 144.3333     12
## 5       UNIMMAP    M0  17 41.75496     20.26891    TRUE 173.3333      0
## 6       UNIMMAP    M5  17 41.75496     20.26891    TRUE 160.6667      5
## 7       UNIMMAP    M5  78 26.74333     29.67046    TRUE 135.0000      5
## 8       UNIMMAP    M5 100 20.23819     27.16084    TRUE 135.6667      5
## 9       UNIMMAP   M12  17 41.75496     20.26891    TRUE 139.0000     12
## 10 Drink powder    M0 139 39.36208     27.02350    TRUE 159.6667      0
## 11 Drink powder    M0 178 43.75359     22.89886    TRUE 149.3333      0
## 12 Drink powder    M0 193 42.73785     26.27128    TRUE 163.6667      0
## 13 Drink powder    M5 193 42.73785     26.27128    TRUE 142.6667      5
## 14 Drink powder   M12 193 42.73785     26.27128    TRUE 138.0000     12
##    is.outlier is.extreme
## 1        TRUE      FALSE
## 2        TRUE      FALSE
## 3        TRUE      FALSE
## 4        TRUE      FALSE
## 5        TRUE      FALSE
## 6        TRUE       TRUE
## 7        TRUE      FALSE
## 8        TRUE      FALSE
## 9        TRUE      FALSE
## 10       TRUE      FALSE
## 11       TRUE      FALSE
## 12       TRUE      FALSE
## 13       TRUE      FALSE
## 14       TRUE      FALSE
##       kelompok waktu variable statistic            p
## 1      Control    M0      tds 0.9812348 0.2895775831
## 2      Control    M5      tds 0.9527453 0.0049658648
## 3      Control   M12      tds 0.9775393 0.1714387091
## 4      UNIMMAP    M0      tds 0.9381109 0.0007017987
## 5      UNIMMAP    M5      tds 0.9281315 0.0002143989
## 6      UNIMMAP   M12      tds 0.9735596 0.0918928831
## 7 Drink powder    M0      tds 0.9467618 0.0028473693
## 8 Drink powder    M5      tds 0.9749280 0.1316866543
## 9 Drink powder   M12      tds 0.9625858 0.0230943713

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/03_qq_per_sel.png
##   waktu df1 df2  statistic         p
## 1    M0   2 235 0.02160737 0.9786263
## 2    M5   2 235 0.27905977 0.7567450
## 3   M12   2 235 1.25261352 0.2876578
##   statistic   p.value parameter
## 1  11.32126 0.5016055        12
##                                                method
## 1 Box's M-test for Homogeneity of Covariance Matrices
## 
## >>> 4. RM ANOVA satu kelompok

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/04_qq_kelompok_fokus.png
## ANOVA Table (type III tests)
## 
## $ANOVA
##   Effect DFn DFd      F        p p<.05   pes
## 1  waktu   2 152 47.329 1.05e-16     * 0.384
## 
## $`Mauchly's Test for Sphericity`
##   Effect     W        p p<.05
## 1  waktu 0.812 0.000408     *
## 
## $`Sphericity Corrections`
##   Effect   GGe       DF[GG]    p[GG] p[GG]<.05   HFe       DF[HF]    p[HF]
## 1  waktu 0.842 1.68, 127.96 1.89e-14         * 0.859 1.72, 130.53 1.08e-14
##   p[HF]<.05
## 1         *
##  
## Anova Table (Type 3 tests)
## 
## Response: tds
##   Effect           df   MSE         F  ges  pes p.value
## 1  waktu 1.68, 127.96 58.20 47.33 *** .124 .384   <.001
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1
## 
## Sphericity correction method: GG  
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##              Sum Sq num Df Error SS den Df  F value    Pr(>F)    
## (Intercept) 2799061      1  25464.5     76 8353.947 < 2.2e-16 ***
## waktu          4637      2   7446.6    152   47.328 < 2.2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## 
## Mauchly Tests for Sphericity
## 
##       Test statistic    p-value
## waktu        0.81212 0.00040811
## 
## 
## Greenhouse-Geisser and Huynh-Feldt Corrections
##  for Departure from Sphericity
## 
##        GG eps Pr(>F[GG])    
## waktu 0.84184  1.892e-14 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##          HF eps   Pr(>F[HF])
## waktu 0.8587805 1.084174e-14 
## 
## Type III Repeated Measures MANOVA Tests: Pillai test statistic
##             Df test stat approx F num Df den Df    Pr(>F)    
## (Intercept)  1   0.99098   8353.9      1     76 < 2.2e-16 ***
## waktu        1   0.49163     36.3      2     75 9.592e-12 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 
##    efek   num Df   den Df      MSE        F       pes       ges       Pr(>F)
## 1 waktu 1.683673 127.9591 58.19515 47.32852 0.3837598 0.1235027 1.892223e-14
## # Effect Size for ANOVA (Type III)
## 
## Parameter | Eta2 (partial) |       95% CI
## -----------------------------------------
## waktu     |           0.38 | [0.28, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
## 
## >>> 4b. Grafik RM ANOVA satu kelompok
## Bagian gagal: package ggbeeswarm is required.
## 
## >>> 5. Post hoc satu kelompok dan tren waktu
##  waktu   emmean       SE df lower.CL upper.CL
##  M0    116.2078 1.613742 76 112.9938 119.4218
##  M5    108.4026 1.300290 76 105.8128 110.9924
##  M12   105.6234 1.152814 76 103.3273 107.9194
## 
## Confidence level used: 0.95 
##  contrast  estimate        SE df lower.CL  upper.CL t.ratio p.value
##  M0 - M5   7.805195 1.2515556 76 4.741232 10.869157   6.236 <0.0001
##  M0 - M12 10.584416 1.2368264 76 7.556512 13.612319   8.558 <0.0001
##  M5 - M12  2.779221 0.8493139 76 0.699996  4.858446   3.272  0.0048
## 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 3 estimates 
## P value adjustment: bonferroni method for 3 tests 
##  contrast   estimate       SE df  lower.CL  upper.CL t.ratio p.value
##  M5 - M0   -7.805195 1.251556 76 -10.66710 -4.943291  -6.236 <0.0001
##  M12 - M0 -10.584416 1.236826 76 -13.41264 -7.756194  -8.558 <0.0001
## 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 2 estimates 
## P value adjustment: holm method for 2 tests 
##  contrast          estimate        SE df  lower.CL  upper.CL t.ratio p.value
##  linear_minggu    -7.253370 0.8461635 76 -9.188273 -5.318468  -8.572 <0.0001
##  kuadratik_minggu  2.759278 0.7459864 76  1.053449  4.465108   3.699  0.0004
## 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 2 estimates 
## P value adjustment: holm method for 2 tests
## 
## >>> 6. Pembanding nonparametrik satu kelompok
##   .y.  n statistic df            p        method
## 1 tds 77  42.18241  2 6.921591e-10 Friedman test
##   .y.  n   effsize    method magnitude
## 1 tds 77 0.2739118 Kendall W     small
##   waktu_1 waktu_2 n_pasangan      V            p p_bonferroni
## 1      M0      M5         77 2535.0 1.560334e-07 4.681003e-07
## 2      M0     M12         77 2808.5 3.267120e-11 9.801360e-11
## 3      M5     M12         77 2015.0 4.296053e-03 1.288816e-02
## 
## >>> 7. Mixed Design ANOVA kelompok × waktu
## Anova Table (Type 3 tests)
## 
## Response: tds
##           Effect           df    MSE          F   ges   pes p.value
## 1       kelompok       2, 235 353.53       0.01 <.001 <.001    .993
## 2          waktu 1.83, 429.09  47.90 109.06 ***  .084  .317   <.001
## 3 kelompok:waktu 3.65, 429.09  47.90     2.76 *  .005  .023    .032
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1
## 
## Sphericity correction method: GG  
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##                 Sum Sq num Df Error SS den Df    F value  Pr(>F)    
## (Intercept)    8635803      1    83079    235 24427.5864 < 2e-16 ***
## kelompok             5      2    83079    235     0.0072 0.99283    
## waktu             9538      2    20552    470   109.0614 < 2e-16 ***
## kelompok:waktu     483      4    20552    470     2.7635 0.02714 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## 
## Mauchly Tests for Sphericity
## 
##                Test statistic    p-value
## waktu                 0.90466 8.1088e-06
## kelompok:waktu        0.90466 8.1088e-06
## 
## 
## Greenhouse-Geisser and Huynh-Feldt Corrections
##  for Departure from Sphericity
## 
##                 GG eps Pr(>F[GG])    
## waktu          0.91296    < 2e-16 ***
## kelompok:waktu 0.91296    0.03156 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
##                   HF eps   Pr(>F[HF])
## waktu          0.9197368 1.106992e-36
## kelompok:waktu 0.9197368 3.118931e-02 
## 
## Type III Repeated Measures MANOVA Tests: Pillai test statistic
##                Df test stat approx F num Df den Df  Pr(>F)    
## (Intercept)     1   0.99047  24427.6      1    235 < 2e-16 ***
## kelompok        2   0.00006      0.0      2    235 0.99283    
## waktu           1   0.41833     84.1      2    234 < 2e-16 ***
## kelompok:waktu  2   0.04347      2.6      4    470 0.03493 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 
##             efek   num Df   den Df       MSE            F          pes
## 1       kelompok 2.000000 235.0000 353.52665 7.195235e-03 6.123229e-05
## 2          waktu 1.825922 429.0917  47.89593 1.090614e+02 3.169823e-01
## 3 kelompok:waktu 3.651844 429.0917  47.89593 2.763450e+00 2.297831e-02
##            ges       Pr(>F)
## 1 4.908945e-05 9.928308e-01
## 2 8.428043e-02 1.965421e-36
## 3 4.642522e-03 3.155838e-02
## # Effect Size for ANOVA (Type III)
## 
## Parameter      | Eta2 (partial) |       95% CI
## ----------------------------------------------
## kelompok       |       6.12e-05 | [0.00, 1.00]
## waktu          |           0.32 | [0.26, 1.00]
## kelompok:waktu |           0.02 | [0.00, 1.00]
## 
## - One-sided CIs: upper bound fixed at [1.00].
## 
## >>> 7b. Visualisasi interaksi kelompok dan waktu

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/07_interaksi_anova.png
## 
## >>> 8. Efek sederhana dan post hoc antarkelompok
##   model term     kelompok df1 df2 F.ratio      p.value p_holm_antar_kelompok
## 1      waktu      Control   2 235  30.189 2.143183e-12          4.286366e-12
## 3      waktu      UNIMMAP   2 235  17.063 1.204340e-07          1.204340e-07
## 5      waktu Drink powder   2 235  41.855 2.828708e-16          8.486125e-16
##   model term waktu df1 df2 F.ratio   p.value p_holm_antar_waktu
## 1   kelompok    M0   2 235   0.624 0.5368033                  1
## 3   kelompok    M5   2 235   0.516 0.5978404                  1
## 5   kelompok   M12   2 235   0.487 0.6152642                  1
## kelompok = Control:
##  contrast   estimate       SE  df   lower.CL  upper.CL t.ratio p.value
##  M5 - M0   -7.908333 1.106432 235 -10.404285 -5.412382  -7.148 <0.0001
##  M12 - M0  -8.175000 1.138889 235 -10.744169 -5.605831  -7.178 <0.0001
## 
## kelompok = UNIMMAP:
##  contrast   estimate       SE  df   lower.CL  upper.CL t.ratio p.value
##  M5 - M0   -4.625514 1.099581 235  -7.106011 -2.145018  -4.207 <0.0001
##  M12 - M0  -6.609054 1.131837 235  -9.162314 -4.055793  -5.839 <0.0001
## 
## kelompok = Drink powder:
##  contrast   estimate       SE  df   lower.CL  upper.CL t.ratio p.value
##  M5 - M0   -7.805195 1.127780 235 -10.349304 -5.261085  -6.921 <0.0001
##  M12 - M0 -10.584416 1.160863 235 -13.203155 -7.965676  -9.118 <0.0001
## 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 2 estimates 
## P value adjustment: holm method for 2 tests 
## waktu = M0:
##  contrast                 estimate       SE  df  lower.CL upper.CL t.ratio
##  Control - UNIMMAP       1.4557095 2.162558 235 -3.645031 6.556450   0.673
##  Control - Drink powder -0.9619589 2.190291 235 -6.128112 4.204194  -0.439
##  UNIMMAP - Drink powder -2.4176684 2.183650 235 -7.568157 2.732820  -1.107
##  p.value
##   0.7793
##   0.8992
##   0.5106
## 
## waktu = M5:
##  contrast                 estimate       SE  df  lower.CL upper.CL t.ratio
##  Control - UNIMMAP      -1.8271095 1.806734 235 -6.088582 2.434363  -1.011
##  Control - Drink powder -1.0650977 1.829903 235 -5.381220 3.251024  -0.582
##  UNIMMAP - Drink powder  0.7620118 1.824355 235 -3.541024 5.065047   0.418
##  p.value
##   0.5705
##   0.8299
##   0.9084
## 
## waktu = M12:
##  contrast                 estimate       SE  df  lower.CL upper.CL t.ratio
##  Control - UNIMMAP      -0.1102370 1.736527 235 -4.206116 3.985642  -0.063
##  Control - Drink powder  1.4474567 1.758797 235 -2.700949 5.595862   0.823
##  UNIMMAP - Drink powder  1.5576937 1.753464 235 -2.578134 5.693521   0.888
##  p.value
##   0.9978
##   0.6892
##   0.6482
## 
## Confidence level used: 0.95 
## Conf-level adjustment: tukey method for comparing a family of 3 estimates 
## P value adjustment: tukey method for comparing a family of 3 estimates
## 
## >>> 9. Kontras perubahan baseline–akhir dan tren interaksi
##  waktu_custom kelompok_pairwise       estimate       SE  df  lower.CL upper.CL
##  M12-M0       Control - UNIMMAP      -1.565946 1.605653 235 -5.437562 2.305669
##  M12-M0       Control - Drink powder  2.409416 1.626244 235 -1.511850 6.330681
##  M12-M0       UNIMMAP - Drink powder  3.975362 1.621314 235  0.065986 7.884738
##  t.ratio p.value
##   -0.975  0.3304
##    1.482  0.2796
##    2.452  0.0448
## 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 3 estimates 
## P value adjustment: holm method for 3 tests 
##  waktu_custom  kelompok_pairwise        estimate       SE  df  lower.CL
##  linear_minggu Control - UNIMMAP      -0.9066969 1.111020 235 -3.585633
##  linear_minggu Control - Drink powder  1.7981626 1.125268 235 -0.915129
##  linear_minggu UNIMMAP - Drink powder  2.7048595 1.121856 235 -0.000205
##  upper.CL t.ratio p.value
##  1.772239  -0.816  0.4153
##  4.511454   1.598  0.2228
##  5.409924   2.411  0.0500
## 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 3 estimates 
## P value adjustment: holm method for 3 tests
## 
## >>> 10. LMM dengan semua pengukuran tersedia
##                    model n_observasi      AIC      BIC singular konvergensi
## 1       random_intercept         813 5998.540 6050.249    FALSE            
## 2 random_intercept_slope         813 5978.954 6040.064    FALSE            
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: tds ~ kelompok * waktu + (1 + minggu | id)
##    Data: long_obs
## Control: lmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 2e+05))
## 
## REML criterion at convergence: 5953
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -3.4519 -0.5398 -0.0067  0.4443  3.6768 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev. Corr  
##  id       (Intercept) 140.6573 11.8599        
##           minggu        0.1775  0.4213  -0.69 
##  Residual              38.1156  6.1738        
## Number of obs: 813, groups:  id, 298
## 
## Fixed effects:
##                  Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)      110.1369     0.6413 294.1474 171.751  < 2e-16 ***
## kelompok1         -0.2348     0.9043 293.6072  -0.260   0.7953    
## kelompok2          0.4430     0.8955 295.6780   0.495   0.6212    
## waktu1             5.0354     0.3368 427.6135  14.949  < 2e-16 ***
## waktu2            -1.6282     0.3108 281.5937  -5.239 3.17e-07 ***
## kelompok1:waktu1   0.3358     0.4739 425.9012   0.709   0.4790    
## kelompok2:waktu1  -1.1386     0.4731 431.9881  -2.407   0.0165 *  
## kelompok1:waktu2  -0.8889     0.4375 282.2977  -2.032   0.0431 *  
## kelompok2:waktu2   0.6981     0.4378 281.3613   1.595   0.1119    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) klmpk1 klmpk2 waktu1 waktu2 klm1:1 klm2:1 klm1:2
## kelompok1   -0.008                                                 
## kelompok2   -0.036 -0.477                                          
## waktu1       0.179  0.002 -0.015                                   
## waktu2       0.026 -0.003  0.006 -0.386                            
## klmpk1:wkt1  0.002  0.182 -0.082 -0.015  0.009                     
## klmpk2:wkt1 -0.014 -0.081  0.172 -0.020 -0.001 -0.482              
## klmpk1:wkt2 -0.003  0.025 -0.015  0.009 -0.013 -0.384  0.189       
## klmpk2:wkt2  0.006 -0.015  0.031 -0.001 -0.011  0.189 -0.391 -0.487 
##  Groups   Name        Std.Dev. Corr   
##  id       (Intercept) 11.85990        
##           minggu       0.42127 -0.695 
##  Residual              6.17378         
##             efek      Sum Sq     Mean Sq NumDF    DenDF     F value
## 1       kelompok    9.354443    4.677221     2 293.8515   0.1227115
## 2          waktu 8524.950471 4262.475236     2 356.4165 111.6258226
## 3 kelompok:waktu  369.277688   92.319422     4 399.2845   2.4162004
##         Pr(>F)
## 1 8.845641e-01
## 2 2.283297e-38
## 3 4.825819e-02
## # Intraclass Correlation Coefficient
## 
##     Adjusted ICC: 0.710
##   Unadjusted ICC: 0.650 
##  waktu_custom kelompok_pairwise       estimate       SE     df  lower.CL
##  M12-M0       Control - UNIMMAP      -1.361829 1.507993 270.73 -4.994505
##  M12-M0       Control - Drink powder  2.013855 1.542200 268.30 -1.701435
##  M12-M0       UNIMMAP - Drink powder  3.375684 1.534155 270.16 -0.320066
##  upper.CL t.ratio p.value
##  2.270848  -0.903  0.3855
##  5.729145   1.306  0.3855
##  7.071433   2.200  0.0859
## 
## Degrees-of-freedom method: kenward-roger 
## Confidence level used: 0.95 
## Conf-level adjustment: bonferroni method for 3 estimates 
## P value adjustment: holm method for 3 tests 
## waktu = M0:
##  kelompok       emmean       SE     df lower.CL upper.CL
##  Control      115.2733 1.337060 320.91 112.6428 117.9038
##  UNIMMAP      114.4767 1.307271 322.60 111.9048 117.0486
##  Drink powder 115.7670 1.386467 320.91 113.0393 118.4947
## 
## waktu = M5:
##  kelompok       emmean       SE     df lower.CL upper.CL
##  Control      107.3850 1.237272 413.41 104.9529 109.8172
##  UNIMMAP      109.6499 1.223874 427.58 107.2443 112.0554
##  Drink powder 108.4914 1.278896 409.89 105.9774 111.0054
## 
## waktu = M12:
##  kelompok       emmean       SE     df lower.CL upper.CL
##  Control      107.0481 1.158294 302.20 104.7687 109.3274
##  UNIMMAP      107.6133 1.140203 303.55 105.3696 109.8570
##  Drink powder 105.5279 1.198209 300.59 103.1700 107.8859
## 
## Degrees-of-freedom method: kenward-roger 
## Confidence level used: 0.95
## 
## >>> 11. Diagnostik LMM

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/11_qq_residual.png

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/11_residual_prediksi.png

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/11_residual_sel.png

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/11_qq_acak_X.Intercept..png

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/11_qq_acak_minggu.png
## [1] FALSE 
## [1] TRUE
## attr(,"gradient")
## [1] 6.333805e-07
## 
## >>> 11b. Visualisasi diagnostik LMM tiga panel

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/11_diagnostik_lmm_tiga_panel.png
## 
## >>> 11c. Grafik rerata prediksi LMM

## Grafik tersimpan: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/11_profil_prediksi_lmm.png
## 
## >>> 12. LMM pada peserta lengkap: pembanding ANOVA
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: tds ~ kelompok * waktu + (1 + minggu | id)
##    Data: long_cc
## Control: lmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 2e+05))
## 
## REML criterion at convergence: 5189.2
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -3.4598 -0.5478  0.0054  0.4724  3.7376 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev. Corr  
##  id       (Intercept) 135.1888 11.6271        
##           minggu        0.1639  0.4048  -0.66 
##  Residual              37.7729  6.1460        
## Number of obs: 714, groups:  id, 238
## 
## Fixed effects:
##                   Estimate Std. Error        df t value Pr(>|t|)    
## (Intercept)      110.00264    0.70382 235.00008 156.293  < 2e-16 ***
## kelompok1         -0.11792    0.99316 235.00008  -0.119  0.90559    
## kelompok2          0.04263    0.99011 235.00008   0.043  0.96569    
## waktu1             5.07861    0.35774 393.11529  14.196  < 2e-16 ***
## waktu2            -1.70107    0.32582 240.72289  -5.221 3.85e-07 ***
## kelompok1:waktu1   0.28250    0.50480 393.11529   0.560  0.57606    
## kelompok2:waktu1  -1.33376    0.50325 393.11529  -2.650  0.00837 ** 
## kelompok1:waktu2  -0.84615    0.45977 240.72289  -1.840  0.06694 .  
## kelompok2:waktu2   0.82041    0.45836 240.72289   1.790  0.07473 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) klmpk1 klmpk2 waktu1 waktu2 klm1:1 klm2:1 klm1:2
## kelompok1   -0.006                                                 
## kelompok2   -0.015 -0.489                                          
## waktu1       0.206 -0.001 -0.003                                   
## waktu2       0.027  0.000  0.000 -0.432                            
## klmpk1:wkt1 -0.001  0.206 -0.101 -0.006  0.003                     
## klmpk2:wkt1 -0.003 -0.101  0.206 -0.015  0.006 -0.489              
## klmpk1:wkt2  0.000  0.027 -0.013  0.003 -0.006 -0.432  0.211       
## klmpk2:wkt2  0.000 -0.013  0.027  0.006 -0.015  0.211 -0.432 -0.489 
##             efek       Sum Sq      Mean Sq NumDF    DenDF      F value
## 1       kelompok    0.5435703    0.2717852     2 235.0000 7.195235e-03
## 2          waktu 7651.0757931 3825.5378966     2 312.6321 1.010618e+02
## 3 kelompok:waktu  411.9696384  102.9924096     4 351.0272 2.718905e+00
##         Pr(>F)
## 1 9.928308e-01
## 2 1.402839e-34
## 3 2.963512e-02
## 
## >>> 13. Informasi sesi dan batas interpretasi
## R version 4.6.1 (2026-06-24)
## Platform: aarch64-apple-darwin23
## Running under: macOS Tahoe 26.5.2
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.6/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.6/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.1
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: Asia/Singapore
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] lmerTest_3.2-1   effectsize_1.0.3 car_3.1-5        carData_3.0-6   
##  [5] rstatix_1.1.0    emmeans_2.0.4    afex_1.5-1       lme4_2.0-6      
##  [9] Matrix_1.7-6     ggplot2_4.0.3    tidyr_1.3.2      dplyr_1.2.1     
## 
## loaded via a namespace (and not attached):
##  [1] tidyselect_1.2.1    farver_2.1.2        S7_0.2.2           
##  [4] fastmap_1.2.0       bayestestR_0.19.0   rpart_4.1.27       
##  [7] digest_0.6.39       estimability_2.0.0  lifecycle_1.0.5    
## [10] cluster_2.1.8.3     magrittr_2.0.5      compiler_4.6.1     
## [13] rlang_1.3.0         Hmisc_5.3-0         sass_0.4.10        
## [16] tools_4.6.1         yaml_2.3.12         data.table_1.18.6.1
## [19] knitr_1.52          ggsignif_0.6.4      labeling_0.4.3     
## [22] htmlwidgets_1.6.4   plyr_1.8.9          RColorBrewer_1.1-3 
## [25] abind_1.4-8         foreign_0.8-91      withr_3.0.3        
## [28] purrr_1.2.2         numDeriv_2016.8-1.1 stats4_4.6.1       
## [31] nnet_7.3-21         grid_4.6.1          datawizard_1.4.0   
## [34] ggpubr_1.0.0        colorspace_2.1-3    scales_1.4.0       
## [37] MASS_7.3-66         insight_1.5.4       cli_3.6.6          
## [40] mvtnorm_1.4-2       rmarkdown_2.32      ragg_1.5.2         
## [43] reformulas_0.4.4    generics_0.1.4      otel_0.2.0         
## [46] rstudioapi_0.19.0   performance_0.18.2  reshape2_1.4.5     
## [49] parameters_0.29.3   readxl_1.5.0.1      minqa_1.2.8        
## [52] cachem_1.1.0        stringr_1.6.0       splines_4.6.1      
## [55] parallel_4.6.1      cellranger_1.1.0    base64enc_0.1-6    
## [58] vctrs_0.7.3         boot_1.3-32         jsonlite_2.0.0     
## [61] pbkrtest_0.5.5      htmlTable_2.5.0     Formula_1.2-6      
## [64] systemfonts_1.3.2   jquerylib_0.1.4     glue_1.8.1         
## [67] nloptr_2.2.1        stringi_1.8.9       gtable_0.3.6       
## [70] tibble_3.3.1        pillar_1.11.1       htmltools_0.5.9    
## [73] R6_2.6.1            textshaping_1.0.5   Rdpack_2.6.6       
## [76] evaluate_1.0.5      lattice_0.23-1      rbibutils_2.4.1    
## [79] backports_1.5.1     broom_1.0.13        bslib_0.12.0       
## [82] Rcpp_1.1.2          checkmate_2.3.4     gridExtra_2.3.1    
## [85] nlme_3.1-171        xfun_0.61           pkgconfig_2.0.3     
##                                                    bagian  status
## 1                 1. Sumber, desain, dan kelengkapan data Selesai
## 2                 2. Statistik deskriptif dan visualisasi Selesai
## 3                    3. Asumsi ANOVA pada peserta lengkap Selesai
## 4                               4. RM ANOVA satu kelompok Selesai
## 5                       4b. Grafik RM ANOVA satu kelompok   Gagal
## 6                5. Post hoc satu kelompok dan tren waktu Selesai
## 7               6. Pembanding nonparametrik satu kelompok Selesai
## 8                  7. Mixed Design ANOVA kelompok × waktu Selesai
## 9            7b. Visualisasi interaksi kelompok dan waktu Selesai
## 10           8. Efek sederhana dan post hoc antarkelompok Selesai
## 11 9. Kontras perubahan baseline–akhir dan tren interaksi Selesai
## 12               10. LMM dengan semua pengukuran tersedia Selesai
## 13                                     11. Diagnostik LMM Selesai
## 14             11b. Visualisasi diagnostik LMM tiga panel Selesai
## 15                        11c. Grafik rerata prediksi LMM Selesai
## 16         12. LMM pada peserta lengkap: pembanding ANOVA Selesai
## 17              13. Informasi sesi dan batas interpretasi Selesai
##                                                                                                                                       peringatan
## 1                                                                                                                                               
## 2                                                                                                                                               
## 3                                                                                                                                               
## 4                                                                                                                                               
## 5                                                                                                                                               
## 6                                                                                                                                               
## 7                                                                                                                                               
## 8                                                                                                                                               
## 9  Panel(s) show a mixed within-between-design.\nError bars do not allow comparisons across all means.\nSuppress error bars with: error = "none"
## 10                                                                                                                                              
## 11                                                                                                                                              
## 12                                                                                                                                              
## 13                                                                                                                                              
## 14                                                                                                                                              
## 15                                                                                                                                              
## 16                                                                                                                                              
## 17
## 
## Laporan tersedia: /Users/nazmy/Downloads/paket_analisis_tds/hasil_analisis_tds/laporan_analisis_tds.html
## Durasi: 6.1 detik.
## Terdapat bagian analisis yang gagal; rinciannya tercatat dalam status_analisis.csv dan laporan HTML.