#0 Add font, library

## Them font chu
library(showtext)
## Loading required package: sysfonts
## Loading required package: showtextdb
font_add("Times New Roman", "times.ttf")  # Đường dẫn tới file font Times New Roman
font_add("Arial", "arial.ttf")
font_add("Times New Roman Bold", "timesbd.ttf")
showtext_auto()

# 1
library(ggplot2)
library(viridis)
## Loading required package: viridisLite
library(ggthemes)
library(rsm)

# Bảng màu dùng chung
viridis_col_120 <- viridis(120, option = "D")  # Mặc định: viridis (xanh tím → vàng)
viridis_col_full <- viridis(120, option = "turbo")
viridis_col_simple <- viridis_col_full[1:90]  # Chọn từ vị trí 1 đến 90
my_col <- c("#0000FF", "#00FFFF", "#00FF00", "#FFFF00", "#FF8000", "#FF0000")

#1 Chuẩn bị mô hình ##1.1. Mô hình QHTN Box Behnken

library(rsm)

# Box-Wilson Design bbd

QHTN <- bbd(
    k = 3,            # 3 yếu tố
   n0 = 3,            # 3 điểm trung tâm
    block = FALSE,     # No blocks 
    randomize = FALSE, # Not randomized
    coding = list(
        x1 ~ (KcTam_e - 25)/10,
        x2 ~ (Gocluon_R - 5)/2,
        x3 ~ (HsMasat_μ - 0.15)/0.05
    )
)

print(QHTN)
##    run.order std.order KcTam_e Gocluon_R HsMasat_μ
## 1          1         1      15         3      0.15
## 2          2         2      35         3      0.15
## 3          3         3      15         7      0.15
## 4          4         4      35         7      0.15
## 5          5         5      15         5      0.10
## 6          6         6      35         5      0.10
## 7          7         7      15         5      0.20
## 8          8         8      35         5      0.20
## 9          9         9      25         3      0.10
## 10        10        10      25         7      0.10
## 11        11        11      25         3      0.20
## 12        12        12      25         7      0.20
## 13        13        13      25         5      0.15
## 14        14        14      25         5      0.15
## 15        15        15      25         5      0.15
## 
## Data are stored in coded form using these coding formulas ...
## x1 ~ (KcTam_e - 25)/10
## x2 ~ (Gocluon_R - 5)/2
## x3 ~ (HsMasat_μ - 0.15)/0.05

##1.2. Thí nghiệm thực tế và đưa dữ liệu vào R

## Ở đây mình chạy số liệu mô phỏng về LucF và Hệ số Ci

library(readxl)
data <- read_excel("~/1.Detai_Caohoc/MrXuan/Bao2/DataQHTN_ECAPPC_211025.xlsx",     sheet = "BoxBehnken", col_types = c("numeric", 
        "numeric", "numeric", "numeric", 
        "numeric"))
head(data)
## # A tibble: 6 × 5
##   KCTam_e GocLuon_R HesoMS_f LucF_Y1 CiBD_Y2
##     <dbl>     <dbl>    <dbl>   <dbl>   <dbl>
## 1      15         3     0.15    124.   0.499
## 2      35         3     0.15    131.   0.340
## 3      15         7     0.15    116.   0.485
## 4      35         7     0.15    117.   0.578
## 5      15         5     0.1     111.   0.544
## 6      35         5     0.1     113.   0.457
# Kiểm tra số dòng của QHTN và data_excel
if (nrow(data) != nrow(QHTN)) {
    stop("Số dòng của dữ liệu Excel không khớp với số dòng của QHTN!")}

# Gắn cột y1 và y2 từ data vào QHTN
QHTN$LucF_Y1 <- data$LucF_Y1
QHTN$CiBD_Y2 <- data$CiBD_Y2

# In kết quả để kiểm tra
print(QHTN)
##    run.order std.order KcTam_e Gocluon_R HsMasat_μ  LucF_Y1   CiBD_Y2
## 1          1         1      15         3      0.15 123.7659 0.4994021
## 2          2         2      35         3      0.15 130.7823 0.3400517
## 3          3         3      15         7      0.15 116.1473 0.4849841
## 4          4         4      35         7      0.15 116.7619 0.5778713
## 5          5         5      15         5      0.10 110.9146 0.5444828
## 6          6         6      35         5      0.10 113.0822 0.4565588
## 7          7         7      15         5      0.20 133.1021 0.6148683
## 8          8         8      35         5      0.20 133.7514 0.5768149
## 9          9         9      25         3      0.10 121.8491 0.3216295
## 10        10        10      25         7      0.10 107.1278 0.4771377
## 11        11        11      25         3      0.20 133.2195 0.3620474
## 12        12        12      25         7      0.20 130.8387 0.5030914
## 13        13        13      25         5      0.15 124.2060 0.4579854
## 14        14        14      25         5      0.15 125.6337 0.4834678
## 15        15        15      25         5      0.15 127.0610 0.5089501
## 
## Data are stored in coded form using these coding formulas ...
## x1 ~ (KcTam_e - 25)/10
## x2 ~ (Gocluon_R - 5)/2
## x3 ~ (HsMasat_μ - 0.15)/0.05

#2. Tính toán Hàm hồi quy ##2.1. Force F (ton)

#=============================================================================
# Box Behnken - Y1 Force F (ton)
#=============================================================================

ket_qua_model <- rsm((LucF_Y1) ~ FO(x1, x2, x3)+TWI(x1,x2,x3)+PQ(x1,x2,x3), 
                     data = QHTN)
summary(ket_qua_model)
## 
## Call:
## rsm(formula = (LucF_Y1) ~ FO(x1, x2, x3) + TWI(x1, x2, x3) + 
##     PQ(x1, x2, x3), data = QHTN)
## 
##              Estimate Std. Error  t value  Pr(>|t|)    
## (Intercept) 125.63356    1.06778 117.6587 8.411e-10 ***
## x1            1.30600    0.65388   1.9973 0.1022901    
## x2           -4.84264    0.65388  -7.4060 0.0007064 ***
## x3            9.74223    0.65388  14.8991 2.465e-05 ***
## x1:x2        -1.60043    0.92472  -1.7307 0.1440592    
## x1:x3        -0.37958    0.92472  -0.4105 0.6984543    
## x2:x3         3.08516    0.92472   3.3363 0.0206360 *  
## x1^2         -2.15771    0.96248  -2.2418 0.0750438 .  
## x2^2         -1.61149    0.96248  -1.6743 0.1549243    
## x3^2         -0.76328    0.96248  -0.7930 0.4637111    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Multiple R-squared:  0.9837, Adjusted R-squared:  0.9545 
## F-statistic: 33.63 on 9 and 5 DF,  p-value: 0.000602
## 
## Analysis of Variance Table
## 
## Response: (LucF_Y1)
##                 Df Sum Sq Mean Sq F value    Pr(>F)
## FO(x1, x2, x3)   3 960.54  320.18 93.6077 8.194e-05
## TWI(x1, x2, x3)  3  48.89   16.30  4.7649   0.06283
## PQ(x1, x2, x3)   3  25.86    8.62  2.5204   0.17199
## Residuals        5  17.10    3.42                  
## Lack of fit      3  13.03    4.34  2.1309   0.33523
## Pure error       2   4.08    2.04                  
## 
## Stationary point of response surface:
##        x1        x2        x3 
##  1.735140 -3.565064 -1.254566 
## 
## Stationary point in original units:
##     KcTam_e   Gocluon_R   HsMasat_μ 
## 42.35139736 -2.13012879  0.08727168 
## 
## Eigenanalysis:
## eigen() decomposition
## $values
## [1]  0.5655325 -1.9867145 -3.1112960
## 
## $vectors
##          [,1]       [,2]       [,3]
## x1  0.2338790  0.8179920 -0.5255375
## x2 -0.6178802 -0.2922928 -0.7299240
## x3 -0.7506828  0.4954331  0.4370600
# pred.r_squared
PRESS <- sum((residuals(ket_qua_model)/(1-lm.influence(ket_qua_model)$hat))^2)
SST   <- sum((ket_qua_model$fitted.values + residuals(ket_qua_model) - mean(ket_qua_model$model[,1]))^2)
predR2 <- 1 - PRESS/SST
#cat("Predicted R-squared:", round(predR2, 4), "\n")
cat(sprintf("Std. Dev.: %.4f   Mean: %.4f   C.V.%%: %.2f%%   Predicted R-squared: %.4f\n", 
            sigma(ket_qua_model), mean(ket_qua_model$model[,1]), 
            sigma(ket_qua_model)/mean(ket_qua_model$model[,1])*100, round(predR2, 4)))
## Std. Dev.: 1.8494   Mean: 123.2162   C.V.%: 1.50%   Predicted R-squared: 0.7932

##2.2. Ci coefficient

#============================================================================
# Box Behnken - Y2 Ci coefficient
#============================================================================

ket_qua_modelY2_Full <- rsm((CiBD_Y2) ~ FO(x1, x2, x3)+TWI(x1,x2,x3)+PQ(x1,x2,x3), 
                     data = QHTN)
summary(ket_qua_modelY2_Full)
## 
## Call:
## rsm(formula = (CiBD_Y2) ~ FO(x1, x2, x3) + TWI(x1, x2, x3) + 
##     PQ(x1, x2, x3), data = QHTN)
## 
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  0.4834678  0.0170112 28.4206 1.01e-06 ***
## x1          -0.0240551  0.0104172 -2.3092 0.068978 .  
## x2           0.0649942  0.0104172  6.2391 0.001549 ** 
## x3           0.0321267  0.0104172  3.0840 0.027345 *  
## x1:x2        0.0630594  0.0147321  4.2804 0.007860 ** 
## x1:x3        0.0124676  0.0147321  0.8463 0.436011    
## x2:x3       -0.0036160  0.0147321 -0.2455 0.815863    
## x1^2         0.0621571  0.0153337  4.0536 0.009790 ** 
## x2^2        -0.0700476  0.0153337 -4.5682 0.006012 ** 
## x3^2         0.0025563  0.0153337  0.1667 0.874129    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Multiple R-squared:  0.9577, Adjusted R-squared:  0.8817 
## F-statistic: 12.59 on 9 and 5 DF,  p-value: 0.006147
## 
## Analysis of Variance Table
## 
## Response: (CiBD_Y2)
##                 Df   Sum Sq   Mean Sq F value   Pr(>F)
## FO(x1, x2, x3)   3 0.046680 0.0155601 17.9234 0.004168
## TWI(x1, x2, x3)  3 0.016580 0.0055267  6.3661 0.036856
## PQ(x1, x2, x3)   3 0.035099 0.0116997 13.4768 0.007857
## Residuals        5 0.004341 0.0008681                 
## Lack of fit      3 0.003042 0.0010140  1.5616 0.413323
## Pure error       2 0.001299 0.0006494                 
## 
## Stationary point of response surface:
##         x1         x2         x3 
##  0.4472715  0.8402609 -6.7802361 
## 
## Stationary point in original units:
##    KcTam_e  Gocluon_R  HsMasat_μ 
## 29.4727146  6.6805218 -0.1890118 
## 
## Eigenanalysis:
## eigen() decomposition
## $values
## [1]  0.06977228  0.00219940 -0.07730586
## 
## $vectors
##          [,1]        [,2]        [,3]
## x1 0.97226548 -0.07353920  0.22201762
## x2 0.21815796 -0.05701057 -0.97424684
## x3 0.08430269  0.99566148 -0.03938625
# pred.r_squared
PRESS <- sum((residuals(ket_qua_modelY2_Full)/(1-lm.influence(ket_qua_modelY2_Full)$hat))^2)
SST   <- sum((ket_qua_modelY2_Full$fitted.values + residuals(ket_qua_modelY2_Full) - mean(ket_qua_modelY2_Full$model[,1]))^2)
predR2 <- 1 - PRESS/SST
#cat("Predicted R-squared:", round(predR2, 4), "\n")

cat(sprintf("Std. Dev.: %.4f   Mean: %.4f   C.V.%%: %.2f%%   Predicted R-squared: %.4f\n", 
            sigma(ket_qua_modelY2_Full), mean(ket_qua_modelY2_Full$model[,1]), 
            sigma(ket_qua_modelY2_Full)/mean(ket_qua_modelY2_Full$model[,1])*100, round(predR2, 4)))
## Std. Dev.: 0.0295   Mean: 0.4806   C.V.%: 6.13%   Predicted R-squared: 0.4976
### Fit Modified model ========================================================
ket_qua_modelY2 <- rsm(
  CiBD_Y2 ~
    x1 + x2 + x3 +                      # FO
    x1:x2 + x1:x3 +                     # TWI (bỏ x2:x3)
    I(x1^2) + I(x2^2),                  # PQ (bỏ x3^2)
  data = QHTN
)
## Warning in rsm(CiBD_Y2 ~ x1 + x2 + x3 + x1:x2 + x1:x3 + I(x1^2) + I(x2^2), : No FO() terms in model; cannot use RSM methods
## An 'lm' object has been returned.
summary(ket_qua_modelY2)
## 
## Call:
## rsm(formula = CiBD_Y2 ~ x1 + x2 + x3 + x1:x2 + x1:x3 + I(x1^2) + 
##     I(x2^2), data = QHTN)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.027055 -0.013295 -0.001573  0.012339  0.029473 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  0.485041   0.012067  40.195 1.54e-09 ***
## x1          -0.024055   0.008881  -2.709  0.03026 *  
## x2           0.064994   0.008881   7.318  0.00016 ***
## x3           0.032127   0.008881   3.617  0.00854 ** 
## I(x1^2)      0.061960   0.013034   4.754  0.00207 ** 
## I(x2^2)     -0.070244   0.013034  -5.389  0.00102 ** 
## x1:x2        0.063059   0.012560   5.021  0.00153 ** 
## x1:x3        0.012468   0.012560   0.993  0.35395    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.02512 on 7 degrees of freedom
## Multiple R-squared:  0.957,  Adjusted R-squared:  0.914 
## F-statistic: 22.25 on 7 and 7 DF,  p-value: 0.0002823
anova(ket_qua_modelY2)
## Analysis of Variance Table
## 
## Response: CiBD_Y2
##           Df   Sum Sq  Mean Sq F value    Pr(>F)    
## x1         1 0.004629 0.004629  7.3360 0.0302641 *  
## x2         1 0.033794 0.033794 53.5547 0.0001602 ***
## x3         1 0.008257 0.008257 13.0851 0.0085404 ** 
## I(x1^2)    1 0.016748 0.016748 26.5410 0.0013214 ** 
## I(x2^2)    1 0.018327 0.018327 29.0438 0.0010202 ** 
## x1:x2      1 0.015906 0.015906 25.2068 0.0015294 ** 
## x1:x3      1 0.000622 0.000622  0.9853 0.3539501    
## Residuals  7 0.004417 0.000631                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# ====== THÊM PHẦN LACK OF FIT VÀ PURE ERROR ===================================
### Tính Lack of Fit và Pure Error cho mô hình modified

# 1. Lấy residual
resid <- residuals(ket_qua_modelY2)

# 2. Tính SSE (model error)
SSE <- sum(resid^2)

# 3. Tính Pure Error từ các điểm trùng (replicate) – dùng x1,x2,x3 thật
df_data <- QHTN
df_data$Y <- QHTN$CiBD_Y2

# Nhóm theo các điểm thiết kế trùng nhau
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
pure_error_data <- df_data %>%
  group_by(x1, x2, x3) %>%
  mutate(n = n()) %>%
  filter(n > 1) %>%        # chỉ tính các điểm lặp
  summarise(SS = sum((Y - mean(Y))^2),
            df = n() - 1)
## `summarise()` has grouped output by 'x1', 'x2'. You can override using the
## `.groups` argument.
SSPE <- sum(pure_error_data$SS)
df_PE <- sum(pure_error_data$df)

# 4. df tổng error của mô hình
n <- nrow(QHTN)
p <- length(coef(ket_qua_modelY2))
df_E <- n - p

# 5. Lack of fit
SSLOF <- SSE - SSPE
df_LOF <- df_E - df_PE

F_LOF <- (SSLOF / df_LOF) / (SSPE / df_PE)
p_LOF <- 1 - pf(F_LOF, df_LOF, df_PE)

cat("Lack of Fit vs Pure Error\n")
## Lack of Fit vs Pure Error
cat(sprintf("SSLOF = %.4f   df_LOF = %d\n", SSLOF, df_LOF))
## SSLOF = 0.0031   df_LOF = 5
cat(sprintf("SSPE  = %.4f   df_PE  = %d\n", SSPE, df_PE))
## SSPE  = 0.0013   df_PE  = 2
cat(sprintf("F-value = %.4f   p-value = %.6f\n\n", F_LOF, p_LOF))
## F-value = 0.9605   p-value = 0.581217
# ==============================================================================


# pred.r_squared
PRESS <- sum((residuals(ket_qua_modelY2)/(1-lm.influence(ket_qua_modelY2)$hat))^2)
SST   <- sum((ket_qua_modelY2$fitted.values + residuals(ket_qua_modelY2) - mean(ket_qua_modelY2$model[,1]))^2)
predR2 <- 1 - PRESS/SST
#cat("Predicted R-squared:", round(predR2, 4), "\n")

cat(sprintf("Std. Dev.: %.4f   Mean: %.4f   C.V.%%: %.2f%%   Predicted R-squared: %.4f\n", 
            sigma(ket_qua_modelY2), mean(ket_qua_modelY2$model[,1]), 
            sigma(ket_qua_modelY2)/mean(ket_qua_modelY2$model[,1])*100, round(predR2, 4)))
## Std. Dev.: 0.0251   Mean: 0.4806   C.V.%: 5.23%   Predicted R-squared: 0.7557

#3. Đồ thị ##3.1. Đồ thị của Force F (Ton) ###3.1.1. Đồ thị Diagnostics

#11111111111111111111111111111111111111111111111111111111111111111111111111111
#Biểu đồ 1
#===============================
# NORMAL PROBABILITY PLOT – MÀU GIỐNG HỆT contour(rsm, image=TRUE)
#===============================
library(ggplot2)
library(showtext)
showtext_auto()

# 1. Externally Studentized Residuals
esr <- rstudent(ket_qua_model)

# 2. Tạo data frame + lấy giá trị Y1 để tô màu (hoặc Y2 nếu bạn muốn)
n <- length(esr)
df_plot <- data.frame(
  ESR        = sort(esr),
  Theoretical= qnorm((1:n - 0.375)/(n + 0.25)),   # Blom's formula
  Y1         = QHTN$LucF_Y1[order(esr)]           # Tô màu theo Lực F
  # Y2       = QHTN$CiBD_Y2[order(esr)]           # ← đổi thành Y2 nếu cần
)

# 3. Biểu đồ – màu giống hệt contour(rsm, image=TRUE)
F1 <- ggplot(df_plot, aes(x = ESR, y = Theoretical)) +
  
  # Điểm được tô màu theo Y1, dùng đúng palette của rsm
  geom_point(aes(fill = Y1), 
             shape = 22, size = 2, color = "black", stroke = 0.5) +
  
  # Đường hồi quy đỏ kéo dài từ đầu đến cuối
  geom_smooth(method = "lm", se = FALSE, 
              color = "red", linewidth = 1, fullrange = TRUE) +
  
  # ←←←←←← QUAN TRỌNG: Dùng đúng palette terrain.colors của rsm
  scale_fill_gradientn(
    colours = viridis_col_simple,     # ←←←←←← giống hệt contour(rsm, image=TRUE)
    name = expression(bold("Lực F (Y1)"))
  ) +
  
  # Trục x
  scale_x_continuous(
    name = "Externally Studentized Residuals",
    limits = c(-3.2, 3.2), breaks = -3:3
  ) +
  
  # Trục y: Normal % Probability chuẩn
  scale_y_continuous(
    name = "Normal % Probability",
    breaks = qnorm(c(0.01,0.05,0.1,0.2,0.3,0.5,0.7,0.8,0.9,0.95,0.99)),
    labels = c("1","5","10","20","30","50","70","80","90","95","99"),
    limits = qnorm(c(0.005, 0.995))
  ) +
  
  ggtitle("Normal Probability Plot of Residuals") +
  theme_bw(base_family = "Times New Roman", base_size = 16) +
  guides(fill = guide_colourbar(title.position = "top", title.hjust = 0.5))+
  theme(
    panel.grid.major.x = element_blank(),  # Loại bỏ đường lưới dọc
    panel.grid.minor.x = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.minor.y = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.major.y = element_blank(),  # Loại bỏ đường lưới dọc
    axis.ticks = element_line(linewidth = 0.5), #nét gạchight (tick marks) trên trục x và y
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  # Thêm viền đen
    axis.text = element_text(color = "black", size = 72),  # Chữ trên trục màu đen
    axis.title = element_text(color = "black", size = 72))+   # Tiêu đề trục màu đen
  theme(plot.title = element_text(family = "Times New Roman Bold", size = 18L, hjust = 0.5),
        axis.title.y = element_text(family = "Times New Roman", size = 36L, vjust = 2), 
        axis.title.x = element_text(family = "Times New Roman", size = 36L, , vjust = -2), 
        axis.text.y = element_text(family = "Times New Roman", size = 36L), 
        axis.text.x = element_text(family = "Times New Roman", size = 36L))+
  theme(legend.title = element_text(family = "Times New Roman", size = 36L),
        legend.text = element_text(family = "Times New Roman", size = 36L),
        aspect.ratio = 1,
        plot.margin = margin(10, 10, 10, 10))+
  theme(legend.position = "none",           #Xoá legend
        plot.title = element_blank())      #Xoá title

# Hiển thị
print(F1)
## `geom_smooth()` using formula = 'y ~ x'

#png("F1.png", width = 8, height = 8, units = "cm", res = 600)
#plot(F1, main = "My Base R Plot")
#dev.off()


#2222222222222222222222222222222222222222222222222222222222222222222222222222
library(ggplot2)
library(showtext)
showtext_auto()

model <- ket_qua_model

# ========== TỰ ĐỘNG TÍNH GIỚI HẠN ĐÚNG NHƯ DESIGN-EXPERT ==========
n  <- nrow(QHTN)
p  <- length(coef(model))
df <- n - p - 1
alpha <- 0.05

critical_t   <- qt(1 - alpha/(2*n), df)   # Bonferroni critical value
lower_limit  <- -critical_t
upper_limit  <- +critical_t

cat(sprintf("Số quan sát n = %d, số tham số p = %d → df = %d\n", n, p, df))
## Số quan sát n = 15, số tham số p = 10 → df = 4
cat(sprintf("Giới hạn Bonferroni (α=0.05): ± %.4f\n", critical_t))
## Giới hạn Bonferroni (α=0.05): ± 6.2541
# Ví dụ: bạn sẽ thấy ±5.8, ±6.1, hoặc ±6.25 tùy model → khớp 100% với Design-Expert!
# =================================================================

esr <- rstudent(model)
run_order <- 1:length(esr)

df_run <- data.frame(
  Run = run_order,
  ESR = esr,
  Y1  = QHTN$LucF_Y1
)

F2 <- ggplot(df_run, aes(x = Run, y = ESR)) +
  geom_hline(yintercept = 0, color = "black", linewidth = 0.8) +
  
  # Đường giới hạn TỰ ĐỘNG, CHÍNH XÁC NHƯ DESIGN-EXPERT
  geom_hline(yintercept = lower_limit, color = "red", linetype = "solid", linewidth = 1) +
  geom_hline(yintercept = upper_limit, color = "red", linetype = "solid", linewidth = 1) +
  
  # Ghi chú giá trị giới hạn lên đồ thị (rất chuyên nghiệp)
  annotate("text", x = 1, y = upper_limit, 
           label = sprintf("%.3f", upper_limit), 
           vjust = -0.8, hjust = 0, color = "red", size = 12, family = "Times New Roman") +
  annotate("text", x = 1, y = lower_limit, 
           label = sprintf("%.3f", lower_limit), 
           vjust = 1.8, hjust = 0, color = "red", size = 12, family = "Times New Roman") +
  
  geom_point(aes(fill = Y1), shape = 22, size = 2, color = "black", stroke = 0.5) +
  geom_line(color = "black", linewidth = 0.5) +
  
  scale_fill_gradientn(colours = viridis_col_simple,
                       name = expression(bold("Lực F (Y1)"))) +
  
  scale_x_continuous(name = "Run Number",
                     breaks = seq(1, max(run_order), by = 2),      # chỉ hiện số lẻ: 1,3,5,...,15
                     minor_breaks = 1:max(run_order),              # vẫn có gạch ngắn ở tất cả các số
                     expand = c(0.02, 0))+                           # sát viền đẹp hơn
  scale_y_continuous(name = "Externally Studentized Residuals",
                     limits = c(-8.2, 8.2),
                     #labels = function(x) sprintf("%.2f", x),
                     breaks = round(seq(-8, 8, 2), 1)) +
  
  ggtitle("Residuals vs. Run Order\n(Externally Studentized Residuals with Bonferroni Limits)") +
  
  theme_bw(base_family = "Times New Roman", base_size = 16) +
  theme(
    panel.grid.major.x = element_blank(),  # Loại bỏ đường lưới dọc
    panel.grid.minor.x = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.minor.y = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.major.y = element_blank(),  # Loại bỏ đường lưới dọc
    axis.ticks = element_line(linewidth = 0.5), #nét gạchight (tick marks) trên trục x và y
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  # Thêm viền đen
    axis.text = element_text(color = "black", size = 12),  # Chữ trên trục màu đen
    axis.title = element_text(color = "black", size = 12))+   # Tiêu đề trục màu đen
  theme(plot.title = element_text(family = "Times New Roman Bold", size = 18L, hjust = 0.5),
        axis.title.y = element_text(family = "Times New Roman", size = 36L, vjust = 2), 
        axis.title.x = element_text(family = "Times New Roman", size = 36L, , vjust = -2), 
        axis.text.y = element_text(family = "Times New Roman", size = 36L), 
        axis.text.x = element_text(family = "Times New Roman", size = 36L))+
  theme(legend.title = element_text(family = "Times New Roman", size = 36L),
        legend.text = element_text(family = "Times New Roman", size = 36L),
    aspect.ratio = 1,
    plot.margin = margin(10, 10, 10, 10))+
  theme(legend.position = "none",           #Xoá legend
        plot.title = element_blank())      #Xoá title

print(F2)

#png("F2.png", width = 8, height = 8, units = "cm", res = 600)
#plot(F2, main = "My Base R Plot")
#dev.off()


#3333333333333333333333333333333333333333333333333333333333333333333333333333
# Biểu đồ 3
# PREDICTED vs ACTUAL
# ===============================
library(ggplot2)
library(showtext)
showtext_auto()

model <- ket_qua_model
actual    <- QHTN$LucF_Y1                    # hoặc CiBD_Y2 nếu bạn đang làm Y2
predicted <- predict(model)

df_pred <- data.frame(
  Actual    = actual,
  Predicted = predicted,
  Y1        = actual                         # tô màu theo giá trị thực tế
)

# ---- Tự động xác định min–max và tạo breaks đẹp ----
range_val <- range(c(df_pred$Actual, df_pred$Predicted))   # min và max chung
min_val   <- floor(range_val[1]  / 5) * 5                   # làm tròn xuống
max_val   <- ceiling(range_val[2] / 5) * 5                 # làm tròn lên
break_seq <- seq(min_val, max_val, by = 5)                 # bạn thay 5 → 10, 20… tùy thích

# ---- Biểu đồ hoàn hảo ----
F3 <- ggplot(df_pred, aes(x = Actual, y = Predicted)) +
  
  # Đường hồi quy + vùng tin cậy 95%
  geom_abline(intercept = 0, slope = 1, color = "black", linewidth = 0.5, linetype = "solid") +
  # Các điểm tô màu giống contour(rsm)
  geom_point(aes(fill = Y1), shape = 22, size = 2, color = "black", stroke = 0.5) +
  
  # Palette terrain.colors giống hệt 2 đồ thị trước
  scale_fill_gradientn(colours = viridis_col_simple,
                       name = expression(bold("Force F (ton)"))) +
  
  # Trục x, y: tự động min–max, nhưng breaks tùy chỉnh
  scale_x_continuous(name = "Actual",
                     limits = c(min_val, max_val),
                     breaks = break_seq) +
  scale_y_continuous(name = "Predicted",
                     limits = c(min_val, max_val),
                     breaks = break_seq) +
  
  ggtitle("Predicted vs. Actual Values") +
  
  theme_bw(base_family = "Times New Roman", base_size = 12) +
  theme(
    panel.grid.major.x = element_blank(),  # Loại bỏ đường lưới dọc
    panel.grid.minor.x = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.minor.y = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.major.y = element_blank(),  # Loại bỏ đường lưới dọc
    axis.ticks = element_line(linewidth = 0.5), #nét gạchight (tick marks) trên trục x và y
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  # Thêm viền đen
    axis.text = element_text(color = "black", size = 12),  # Chữ trên trục màu đen
    axis.title = element_text(color = "black", size = 12))+   # Tiêu đề trục màu đen
  theme(plot.title = element_text(family = "Times New Roman Bold", size = 12L, hjust = 0.5),
        axis.title.y = element_text(family = "Times New Roman", size = 36L, vjust = 2), 
        axis.title.x = element_text(family = "Times New Roman", size = 36L, , vjust = -2), 
        axis.text.y = element_text(family = "Times New Roman", size = 36L), 
        axis.text.x = element_text(family = "Times New Roman", size = 36L),
        aspect.ratio = 1,
        plot.margin = margin(10, 10, 10, 10))+
  theme(legend.position = "right",           # hoặc "bottom" nếu muốn nằm dưới
        legend.title = element_text(family = "Times New Roman", size = 36L, hjust = 0.5),     # tiêu đề legend
        legend.text  = element_text(family = "Times New Roman", size = 36L),                    # số trên thanh màu
        legend.key.height = unit(0.5, "cm"),   # chiều cao thanh màu (tăng/giảm thoải mái)
        legend.key.width  = unit(0.5, "cm"),   # độ dày thanh màu
        #legend.background = element_rect(fill = "white", color = "black", linewidth = 0.5), # viền legend
        legend.margin = margin(10, 10, 10, 10))+ # khoảng cách bên trong legend
  theme(plot.title = element_blank())      #Xoá title

# Xem trước
print(F3)

#png("F3.png", width = 16, height = 8, units = "cm", res = 600)
#plot(F3, main = "My Base R Plot")
#dev.off()

###3.1.2. Đồ thị One Factor

#44444444444444444444444444444444444444444444444444444444444444444444444444444
# Biểu đồ 4
# ===============================
# ONE FACTOR PLOT: Ảnh hưởng của R → Lực F
# Trục Y tự động min–max + tùy chỉnh khoảng cách chia (ví dụ: mỗi 10)
# ===============================
library(ggplot2)
library(dplyr)
library(showtext)
showtext_auto()

model <- ket_qua_model

# ---- 1. Tạo lưới dự báo cho R từ 3 → 7 mm (giữ x1 = x3 = 0) ----
R_real <- seq(3, 7, length.out = 200)
grid <- data.frame(
  x1 = 0,
  x2 = (R_real - 5)/2,      # chuyển sang coded
  x3 = 0
)

# Dự báo + 95% Confidence Interval
pred <- suppressWarnings(
  predict(model, newdata = grid, interval = "confidence", level = 0.95)
)
grid_df <- data.frame(
  R_real = R_real,
  fit    = pred[,"fit"],
  lwr    = pred[,"lwr"],
  upr    = pred[,"upr"]
)

# ---- 2. Lấy đúng 3 điểm trung tâm thực nghiệm (R = 5 mm) ----
center_points <- data %>%
  filter(GocLuon_R == 5 & KCTam_e == 25 ) %>%
  select(GocLuon_R, LucF_Y1)

# ---- 3. TỰ ĐỘNG xác định min–max trục Y + tùy chỉnh breaks ----
all_y_values <- c(grid_df$lwr, grid_df$upr, center_points$LucF_Y1)
min_y <- floor(min(all_y_values) / 10) * 10      # làm tròn xuống đến bội số 10
max_y <- ceiling(max(all_y_values) / 10) * 10    # làm tròn lên đến bội số 10

# TỰ DO CHỈNH khoảng cách chia tại đây:
break_step <- 10                                 # ← Thay 10 → 20, 50, 5… tùy bạn
y_breaks <- seq((min_y)-10, max_y, by = break_step)

# ---- 4. Biểu đồ đẹp hơn cả Design-Expert ----
F4 <- ggplot() +
  
  # Vùng 95% Confidence Interval
  geom_ribbon(data = grid_df,
              aes(x = R_real, ymin = lwr, ymax = upr),
              fill = "gray", alpha = 0.3) +
  
  # Đường dự báo trung bình
  geom_line(data = grid_df,
            aes(x = R_real, y = fit),
            color = "black", linewidth = 0.5) +
  
  # Chỉ 3 điểm đỏ ở tâm (R = 5)
  geom_point(data = center_points,
             aes(x = GocLuon_R, y = LucF_Y1),
             color = "darkred", size = 1.2, shape = 19) +
  
  # Trục X
  scale_x_continuous(name = "Corner radius R (mm)",
                     breaks = seq(3, 7, by = 1)) +
  
  # Trục Y: tự động min–max + bạn tùy chỉnh khoảng cách chia
  scale_y_continuous(name = "Force F (ton)",
                     limits = c((min_y)-10, max_y),
                     breaks = y_breaks) +          # ← Tùy chỉnh ở đây!
  
  ggtitle("One Factor Plot: Effect of R on Lực F\n(x1 = 0, x3 = 0)") +
  
  # Theme đồng bộ tuyệt đối với tất cả biểu đồ trước
  theme_bw(base_family = "Times New Roman", base_size = 12) +
  theme(
    panel.grid.major.x = element_blank(),  # Loại bỏ đường lưới dọc
    panel.grid.minor.x = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.minor.y = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.major.y = element_blank(),  # Loại bỏ đường lưới dọc
    axis.ticks = element_line(linewidth = 0.5), #nét gạchight (tick marks) trên trục x và y
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  # Thêm viền đen
    axis.text = element_text(color = "black", size = 12),  # Chữ trên trục màu đen
    axis.title = element_text(color = "black", size = 12))+   # Tiêu đề trục màu đen
  theme(plot.title = element_text(family = "Times New Roman Bold", size = 18L, hjust = 0.5),
        axis.title.y = element_text(family = "Times New Roman", size = 36L, vjust = 2), 
        axis.title.x = element_text(family = "Times New Roman", size = 36L, , vjust = -2), 
        axis.text.y = element_text(family = "Times New Roman", size = 36L), 
        axis.text.x = element_text(family = "Times New Roman", size = 36L))+
  theme(legend.title = element_text(family = "Times New Roman", size = 36L),
        legend.text = element_text(family = "Times New Roman", size = 36L),
        aspect.ratio = 1,
        plot.margin = margin(10, 10, 10, 10))+
  theme(legend.position = "none",           #Xoá legend
        plot.title = element_blank())      #Xoá title

# Xem trước
print(F4)

#png("F4.png", width = 8, height = 8, units = "cm", res = 600)
#plot(F4, main = "My Base R Plot")
#dev.off()



#5555555555555555555555555555555555555555555555555555555555555555555555555555
# Biểu đồ 5
# ===============================
# Biểu đồ One Factor: Ảnh hưởng của Hệ số ma sát μ → Lực F
# Hoàn toàn giống format F4 của bạn (8x8 cm, font 72, không title/legend)
# ===============================
library(ggplot2)
library(dplyr)
library(showtext)
showtext_auto()

model <- ket_qua_model   # hoặc ket_qua_model_opt

# ---- 1. Tạo lưới dự báo cho μ từ 0.10 → 0.20 (giữ x1=x2=0) ----
mu_real <- seq(0.10, 0.20, length.out = 200)
grid <- data.frame(
  x1 = 0,
  x2 = 0,
  x3 = (mu_real - 0.15)/0.05   # chuyển sang coded: (μ - 0.15)/0.05
)

# Dự báo + 95% Confidence Interval
pred <- suppressWarnings(
  predict(model, newdata = grid, interval = "confidence", level = 0.95)
)

grid_df <- data.frame(
  mu_real = mu_real,
  fit = pred[,"fit"],
  lwr = pred[,"lwr"],
  upr = pred[,"upr"]
)

# 3. LẤY ĐIỂM TRUNG TÂM – DÙNG round() ĐỂ TRÁNH LỖI LÀM TRÒN
center_points <- data %>%
  mutate(mu_round = round(HesoMS_f, 3)) %>%     # làm tròn 3 chữ số
  filter(mu_round == 0.150 & KCTam_e == 25) %>%                  # chắc chắn bắt được 0.15
  select(mu_real = HesoMS_f, LucF_Y1)          # đổi tên cột cho khớp

# Kiểm tra nhanh: phải ra đúng 3 dòng
print(center_points)
## # A tibble: 3 × 2
##   mu_real LucF_Y1
##     <dbl>   <dbl>
## 1    0.15    124.
## 2    0.15    126.
## 3    0.15    127.
# ---- 3. TỰ ĐỘNG min–max trục Y + chia mỗi 10 ----
all_y <- c(grid_df$lwr, grid_df$upr, center_points$LucF_Y1)
min_y <- floor(min(all_y) / 10) * 10
max_y <- ceiling(max(all_y) / 10) * 10
break_step <- 10
y_breaks <- seq(min_y - 10, max_y, by = break_step)

# ---- 4. Biểu đồ giống hệt F4 của bạn ----
F5 <- ggplot() +
  geom_ribbon(data = grid_df,
              aes(x = mu_real, ymin = lwr, ymax = upr),
              fill = "gray", alpha = 0.3) +
  geom_line(data = grid_df,
            aes(x = mu_real, y = fit),
            color = "black", linewidth = 0.5) +
  geom_point(data = center_points,
             aes(x = mu_real, y = LucF_Y1),
             color = "darkred", size = 1.2, shape = 19) +
  
  scale_x_continuous(name = "Friction coefficient μ",
                     breaks = seq(0.10, 0.20, by = 0.02)) +
  scale_y_continuous(name = "Force F (ton)",
                     limits = c(min_y - 10, max_y),
                     breaks = y_breaks) +
  
  theme_bw(base_family = "Times New Roman", base_size = 12) +
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),
    axis.ticks = element_line(linewidth = 0.5),
    axis.text = element_text(color = "black", size = 36L, family = "Times New Roman"),
    axis.title = element_text(color = "black", size = 36L, family = "Times New Roman"),
    axis.title.y = element_text(vjust = 2),
    axis.title.x = element_text(vjust = -2),
    plot.margin = margin(10, 10, 10, 10),
    legend.position = "none",
    plot.title = element_blank()
  )

# Xem trước
print(F5)

# Lưu file đúng chuẩn bạn đang dùng
#png("F5.png", width = 8, height = 8, units = "cm", res = 600)
#print(F5)
#dev.off()

###3.1.3. Đồ thị Contour Plot

#666666666666666666666666666666666666666666666666666666666666666666666666666
#png("F6.png", width = 8, height = 8, units = "cm", res = 600)

library(viridis)
# Tạo dải 120 màu (giống col_dx_120 của bạn)
viridis_col_120 <- viridis(120, option = "D")  # Mặc định: viridis "D" (xanh tím → vàng)  "turbo" là tím-đỏ
cividis_col_120  <- viridis(120, option = "E")  # Xanh → vàng (colorblind-safe nhất)
my_col <- c("#0000FF", "#00FFFF", "#00FF00", "#FFFF00", "#FF8000", "#FF0000")
col_dx_120 <- colorRampPalette(my_col)(120)

viridis_col_full <- viridis(120, option = "turbo")
viridis_col_simple <- viridis_col_full[1:90]  # Chọn từ vị trí 1 đến 90


par(family = "Times New Roman", ps = 36, cex = 1,  
    mar = c(4, 3.5, 1, 0.5), oma = c(0, 0, 0, 0), mgp = c(3, 0.6, 0), las = 1, tcl = -0.3)      # Muốn export ra 600Dpi thì ps=72

# Tạo lưới đều
R_vals  <- seq(3, 7, length.out = 300)
mu_vals <- seq(0.1, 0.2, length.out = 300)

# Mở rộng thêm 0.15 ở mỗi đầu → tạo đoạn thừa rõ rệt
xlim <- c(2.9, 7.1)   # thay vì c(3,7)
ylim <- c(0.097, 0.203) # thay vì c(0.10, 0.20)

grid <- expand.grid(x2 = (R_vals - 5)/2, x3 = (mu_vals - 0.15)/0.05)
grid$x1 <- 0
grid$yhat <- predict(ket_qua_model, grid)

zmat <- matrix(grid$yhat, 300, 300)

# Vẽ nền gradient đúng màu bạn muốn
image(R_vals, mu_vals, zmat, col = viridis_col_simple, xlim = xlim, ylim = ylim,
      xlab = "", ylab = "", axes = TRUE, useRaster = TRUE)

# Vẽ đường đồng mức + nhãn số
contour(R_vals, mu_vals, zmat, add = TRUE,
        col = "black", lwd = 1, labcex = 1, drawlabels = TRUE, method = "flattest")

# Trục + nhãn
# Vẽ trục (chỉ vạch, không chữ)
#axis(1, tcl = -0.3, mgp = c(3, 0.6, 0))
#axis(2, tcl = -0.3, mgp = c(3, 0.8, 0), las = 1)
# THÊM NHÃN TRỤC ĐÚNG NHƯ BẠN MUỐN (đẹp, điều chỉnh được line, cex, font)
title(xlab = "Corner radius R (mm)",
      line = 1.6,        # chỉnh độ cao trục X ở đây
      cex.lab = 1,       # đúng 12 pt
      family = "Times New Roman")

title(ylab = "Friction coefficient μ",
      line = 2.4,        # chỉnh độ cao trục Y ở đây
      cex.lab = 1,       # đúng 12 pt
      family = "Times New Roman")

# Tiêu đề slice (bạn tự đặt, không còn "Slice at x1 = 0")
mtext("Slice at Distance e = 25 mm", 
      family = "Times New Roman",
      side = 1, line = 2.8, cex = 1, font = 1)   # font = 2 → in đậm

#dev.off()

###3.1.4. Đồ thị 3D Surface Plot

#===================================================================CHUẨN MẪU
#777777777777777777777777777777777777777777777777777777v22222222222222222222
## Biểu đồ 3D Surface ảnh hưởng e & R tới Ci

#png("F7v2.png", width = 8, height = 8, units = "cm", res = 600)
viridis_col_full <- viridis(120, option = "turbo")
viridis_col_simple <- viridis_col_full[1:90]  # Chọn từ vị trí 1 đến 90

par(
  family = "Times New Roman",
  ps =36,
  cex = 1,
  mar = c(2.6, 2.6, 0.1, 0.1),  #(Dưới, Trái, Trên, Phải)
  mgp = c(0.5, 0.02, 0.7)     #(title, tick lable, tick mark)
)

# Tạo lưới đều
e_vals  <- seq(15, 35, length.out = 300)
R_vals  <- seq(3, 7, length.out = 300)
mu_vals <- seq(0.1, 0.2, length.out = 300)

grid <- expand.grid(x3 = (mu_vals - 0.15)/0.05, x2 = (R_vals - 5)/2)
grid$x1 <- 0
grid$yhat <- predict(ket_qua_model, grid)

zmat <- matrix(grid$yhat, 300, 300)
min_z <- min(zmat)
max_z <- max(zmat)

# Tạo màu trống phía trên, dưới
Color_Tren <- ((140-max_z)/(max_z - min_z))*90
Color_Duoi <-((min_z-90)/(max_z - min_z))*90


# Thêm các màu trống cả phía trước và phía sau
viridis_col_extended <- c(
  rep(viridis_col_simple[1], Color_Duoi),      # Thêm 36 màu giống màu đầu tiên (phía dưới)
  viridis_col_simple,                 # Dải màu chính từ thấp đến cao
  rep(viridis_col_simple[90], Color_Tren)   # Thêm 36 màu giống màu cuối cùng (phía trên)
)

# Tạo các mức contour cách nhau 0.05
levels_05 <- seq(
  floor(min_z/0.05)*0.05,
  ceiling(max_z/0.05)*0.05,
  by = 0.05)

# Vẽ đồ thị không có trục
res <- persp(
  ket_qua_model,
  ~ x2 + x3,
  at = c(x1 = 0),
  zlim = c(90, 140),   # ← thêm khoảng trống !!!
  axes = FALSE,
  #sub = NULL,                 # ẩn Slice at
  col = viridis_col_extended,
  contours = "colors",
  #contours = list(col = "colors", levels = my_levels),  # <<< QUAN TRỌNG
  color.legend = TRUE,
  expand = 1,
  theta = -28,
  phi = 20
)
## Warning in persp.default(dat$x, dat$y, dat$z, zlim = dat$zlim, theta = theta, :
## "color.legend" is not a graphical parameter
## Warning in persp.default(dat$x, dat$y, dat$z, xlab = dat$labs[1], ylab =
## dat$labs[2], : "color.legend" is not a graphical parameter
## Warning in title(sub = dat$labs[5], ...): "axes" is not a graphical parameter
## Warning in title(sub = dat$labs[5], ...): "color.legend" is not a graphical
## parameter
## Warning in title(sub = dat$labs[5], ...): "expand" is not a graphical parameter
# Tạo lưới và các giá trị tick
x2_seq_coded <- seq(min(QHTN$x2), max(QHTN$x2), length.out = 80)
x3_seq_coded <- seq(min(QHTN$x3), max(QHTN$x3), length.out = 80)
#e_seq_coded <- seq(min(data$KCTam_e), max(data$KCTam_e), length.out = 80)
R_seq_coded <- seq(min(data$GocLuon_R), max(data$GocLuon_R), length.out = 80)
f_seq_coded <- seq(min(data$HesoMS_f), max(data$HesoMS_f), length.out = 80)
grid <- expand.grid(x2 = x2_seq_coded, x3 = x3_seq_coded, x1 = 0)
grid_real <- expand.grid(x1 = 25, x2 = R_seq_coded, x3 = f_seq_coded)
grid$F_pred <- predict(ket_qua_model, newdata = grid)
z_mat <- matrix(grid$F_pred, nrow = length(x2_seq_coded), ncol = length(x3_seq_coded))


x_ticks1 <- c("–","–","–","–","–")
x_ticks2 <- c("3","4","5","6","7")
y_ticks1 <- c("–","–","–","–","–","–")
y_ticks2 <- c("0.10","0.12","0.14","0.16","0.18","0.20")
z_ticks1 <- c("","–","–","–","–","–")
z_ticks2 <- c("","100","110","120","130","140")
par(xpd = NA)

#################################################### TRỤC X
###X11 Vẽ tick marks cho trục x2 với phép xoay toàn bộ trục
rotation_angle <- -73  # Góc xoay của toàn bộ trục x2 (độ)
angle_rad <- rotation_angle * pi / 180

offset1 <- 0.403
for(i in seq_along(x_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base11_x <- 0.247   #giảm là lên
  base11_y <- -0.239  #giảm là sang trái
  tick_offset <- (i/length(x_ticks1)) * offset1
  
  x_before <- base11_x
  y_before <- base11_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = x_ticks1[i], 
       cex = 1, 
       srt = rotation_angle)
}

###X12 Vẽ tick labels cho trục x2 với phép xoay toàn bộ trục
for(i in seq_along(x_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base12_x <- base11_x +0.03   #giảm là lên
  base12_y <- base11_y  #giảm là sang trái
  tick_offset <- (i/length(x_ticks1)) * offset1
  
  x_before <- base12_x
  y_before <- base12_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = x_ticks2[i], 
       cex = 1, 
       srt = 0)
}

############ CÁCH 2: VẼ GẠCH TICK MARK BẰNG ĐIỂM
#for(i in seq_along(x_ticksmark)) {
# Tọa độ gốc của tick trước khi xoay
#tick_offset <- (i/length(x_ticksmark)) * 0.4

#x_before <- base_x
#y_before <- base_y + tick_offset

# Tính tọa độ sau khi xoay
#rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
#rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)

#Vẽ tick mark tại vị trí đã xoay
#tmx21=rotated_x-0.062           #giảm là sang trái
#tmx22=rotated_y+0.01           #giảm là xuống
#segments(tmx21, tmx22, 
#tmx21+0.008, tmx22-0.012, 
#col = "black", lwd = 1.2)}

#################################################### TRỤC Y
###Y21 Vẽ tick marks cho trục x3 với phép xoay toàn bộ trục
rotation_angle <- 37  # Góc xoay của toàn bộ trục x3 (độ)
angle_rad <- rotation_angle * pi / 180
offset2 <- 0.236

for(i in seq_along(y_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base21_x <- -0.239        #giảm là sang trái
  base21_y <- -0.2115         #giảm là xuống
  tick_offset <- (i/length(y_ticks1)) * offset2
  
  x_before <- base21_x
  y_before <- base21_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = y_ticks1[i], 
       cex = 1, 
       srt = rotation_angle)
}

###Y22 Vẽ tick labels cho trục x3 với phép xoay toàn bộ trục
for(i in seq_along(y_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base22_x <- base21_x -0.04        #giảm là sang trái
  base22_y <- base21_y +0.01         #giảm là xuống
  tick_offset <- (i/length(y_ticks1)) * offset2
  
  x_before <- base22_x
  y_before <- base22_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay CÁCH 2
  #segments(rotated_x - 0.05, rotated_y, 
  #rotated_x + 0.05, rotated_y, 
  #col = "black", lwd = 1.2)
  
  # Vẽ tick label tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = y_ticks2[i], 
       cex = 1, 
       srt = rotation_angle-37)
}

#################################################### TRỤC Z
###Z31 Vẽ tick marks cho trục z với phép xoay toàn bộ trục
rotation_angle <- 4.2  # Góc xoay của toàn bộ trục z (độ)
angle_rad <- rotation_angle * pi / 180
offset3 <- 0.3568

for(i in seq_along(z_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base31_x <- -0.217    #giảm là sang trái
  base31_y <- -0.163     #giảm là xuống
  tick_offset <- (i/length(z_ticks1)) * offset3
  
  x_before <- base31_x
  y_before <- base31_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = z_ticks1[i], 
       cex = 1, 
       srt = rotation_angle)
}

###Z32 Vẽ tick label cho trục z với phép xoay toàn bộ trục
for(i in seq_along(z_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base32_x <- base31_x -0.04    #giảm là sang trái
  base32_y <- base31_y    #giảm là xuống
  tick_offset <- (i/length(z_ticks1)) * offset3
  
  x_before <- base32_x
  y_before <- base32_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay CÁCH 2
  #segments(rotated_x - 0.05, rotated_y, 
  #rotated_x + 0.05, rotated_y, 
  #col = "black", lwd = 1.2)
  
  # Vẽ tick label tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = z_ticks2[i], 
       cex = 1, 
       srt = 0)
}

# Thêm nhãn cho các trục
par(xpd = NA, srt = -55)
text(-0.25, -0.26, "Friction coefficient μ")
par(xpd = NA, srt = 20)
text(0.13, -0.3, "Corner radius R (mm)")
par(xpd = NA, srt = -85)
text(-0.33, 0.02, "Force F (ton)")

#dev.off()

##3.2. Đồ thị của Ci coefficient ###3.2.1. Đồ thị Diagnostics

#111111111111111111111111111111111111111111111111111111111111111111111111111
#Biểu đồ 1
#===============================
# NORMAL PROBABILITY PLOT – MÀU GIỐNG HỆT contour(rsm, image=TRUE)
#===============================
library(ggplot2)
library(showtext)
showtext_auto()

# 1. Externally Studentized Residuals
esr <- rstudent(ket_qua_modelY2)

# 2. Tạo data frame + lấy giá trị Y1 để tô màu (hoặc Y2 nếu bạn muốn)
n <- length(esr)
df_plot <- data.frame(
  ESR        = sort(esr),
  Theoretical= qnorm((1:n - 0.375)/(n + 0.25)),   # Blom's formula
  #Y1         = QHTN$LucF_Y1[order(esr)]           # Tô màu theo Lực F
  Y2       = QHTN$CiBD_Y2[order(esr)]           # ← đổi thành Y2 nếu cần
)

# 3. Biểu đồ – màu giống hệt contour(rsm, image=TRUE)
F21 <- ggplot(df_plot, aes(x = ESR, y = Theoretical)) +
  
  # Điểm được tô màu theo Y2, dùng đúng palette của rsm
  geom_point(aes(fill = Y2), 
             shape = 22, size = 2, color = "black", stroke = 0.5) +
  
  # Đường hồi quy đỏ kéo dài từ đầu đến cuối NORMAL PROBABILITY PLOT là đường best fit
  geom_smooth(method = "lm", se = FALSE, 
              color = "red", linewidth = 1, fullrange = TRUE) +
  
  #geom_abline(intercept = 0, slope = 1, color = "black", linewidth = 0.5, linetype = "solid") +
  
  # Các điểm tô màu giống contour(rsm)
    # ←←←←←← QUAN TRỌNG: Dùng đúng palette terrain.colors của rsm
  scale_fill_gradientn(
    colours = viridis_col_simple,     # ←←←←←← giống hệt contour(rsm, image=TRUE)
    name = expression(bold("Ci (Y2)"))
  ) +
  
  
  # Trục x được chia tự động với định dạng số thập phân 2 chữ số
  #scale_x_continuous(
    #name = "Externally Studentized Residuals",
    #labels = function(x) sprintf("%.2f", x),
    #n.breaks = 6  # Có thể thêm để gợi ý số lượng chia, nhưng không bắt buộc) +
  
  # Trục x
  scale_x_continuous(
    name = "Externally Studentized Residuals",
    #labels = function(x) sprintf("%.2f", x),
    limits = c(-2.2, 3.2), breaks = -2:3) +
  
  # Trục y: Normal % Probability chuẩn
  scale_y_continuous(
    name = "Normal % Probability",
    breaks = qnorm(c(0.01,0.05,0.1,0.2,0.3,0.5,0.7,0.8,0.9,0.95,0.99)),
    labels = c("1","5","10","20","30","50","70","80","90","95","99"),
    limits = qnorm(c(0.005, 0.995))
  ) +
  
  ggtitle("Normal Probability Plot of Residuals") +
  theme_bw(base_family = "Times New Roman", base_size = 16) +
  guides(fill = guide_colourbar(title.position = "top", title.hjust = 0.5))+
  theme(
    panel.grid.major.x = element_blank(),  # Loại bỏ đường lưới dọc
    panel.grid.minor.x = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.minor.y = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.major.y = element_blank(),  # Loại bỏ đường lưới dọc
    axis.ticks = element_line(linewidth = 0.5), #nét gạchight (tick marks) trên trục x và y
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  # Thêm viền đen
    axis.text = element_text(color = "black", size = 72),  # Chữ trên trục màu đen
    axis.title = element_text(color = "black", size = 72))+   # Tiêu đề trục màu đen
  theme(plot.title = element_text(family = "Times New Roman Bold", size = 18L, hjust = 0.5),
        axis.title.y = element_text(family = "Times New Roman", size = 36L, vjust = 2), 
        axis.title.x = element_text(family = "Times New Roman", size = 36L, , vjust = -2), 
        axis.text.y = element_text(family = "Times New Roman", size = 36L), 
        axis.text.x = element_text(family = "Times New Roman", size = 36L))+
  theme(legend.title = element_text(family = "Times New Roman", size = 36L),
        legend.text = element_text(family = "Times New Roman", size = 36L),
        aspect.ratio = 1,
        plot.margin = margin(10, 10, 10, 10))+
  theme(legend.position = "none",           #Xoá legend
        plot.title = element_blank())      #Xoá title

# Hiển thị
print(F21)
## `geom_smooth()` using formula = 'y ~ x'

#png("F21.png", width = 8, height = 8, units = "cm", res = 600)
#plot(F21, main = "My Base R Plot")
#dev.off()



#2222222222222222222222222222222222222222222222222222222222222222222222222222
library(ggplot2)
library(showtext)
showtext_auto()

model <- ket_qua_modelY2

# ========== TỰ ĐỘNG TÍNH GIỚI HẠN ĐÚNG NHƯ DESIGN-EXPERT ==========
n  <- nrow(QHTN)
p  <- length(coef(model))
df <- n - p - 1
alpha <- 0.05

critical_t   <- qt(1 - alpha/(2*n), df)   # Bonferroni critical value
lower_limit  <- -critical_t
upper_limit  <- +critical_t

cat(sprintf("Số quan sát n = %d, số tham số p = %d → df = %d\n", n, p, df))
## Số quan sát n = 15, số tham số p = 8 → df = 6
cat(sprintf("Giới hạn Bonferroni (α=0.05): ± %.4f\n", critical_t))
## Giới hạn Bonferroni (α=0.05): ± 4.6979
# Ví dụ: bạn sẽ thấy ±5.8, ±6.1, hoặc ±6.25 tùy model → khớp 100% với Design-Expert!
# =================================================================

esr <- rstudent(model)
run_order <- 1:length(esr)

df_run <- data.frame(
  Run = run_order,
  ESR = esr,
  Y2   = QHTN$CiBD_Y2
  #Y1  = QHTN$LucF_Y1
)

F22 <- ggplot(df_run, aes(x = Run, y = ESR)) +
  geom_hline(yintercept = 0, color = "black", linewidth = 0.8) +
  
  # Đường giới hạn TỰ ĐỘNG, CHÍNH XÁC NHƯ DESIGN-EXPERT
  geom_hline(yintercept = lower_limit, color = "red", linetype = "solid", linewidth = 1) +
  geom_hline(yintercept = upper_limit, color = "red", linetype = "solid", linewidth = 1) +
  
  # Ghi chú giá trị giới hạn lên đồ thị (rất chuyên nghiệp)
  annotate("text", x = 1, y = upper_limit, 
           label = sprintf("%.3f", upper_limit), 
           vjust = -0.8, hjust = 0, color = "red", size = 12, family = "Times New Roman") +
  annotate("text", x = 1, y = lower_limit, 
           label = sprintf("%.3f", lower_limit), 
           vjust = 1.8, hjust = 0, color = "red", size = 12, family = "Times New Roman") +
  
  geom_point(aes(fill = Y2), shape = 22, size = 2, color = "black", stroke = 0.5) +
  geom_line(color = "black", linewidth = 0.5) +
  
  scale_fill_gradientn(colours = viridis_col_simple,
                       name = expression(bold("Ci (Y2)"))) +
  
  scale_x_continuous(name = "Run Number",
                     breaks = seq(1, max(run_order), by = 2),      # chỉ hiện số lẻ: 1,3,5,...,15
                     minor_breaks = 1:max(run_order),              # vẫn có gạch ngắn ở tất cả các số
                     expand = c(0.02, 0))+                           # sát viền đẹp hơn
  scale_y_continuous(name = "Externally Studentized Residuals",
                     limits = c(-6.2, 6.2),
                     #labels = function(x) sprintf("%.2f", x)
                     breaks = round(seq(-6, 6, 2), 1)) +
  
  ggtitle("Residuals vs. Run Order\n(Externally Studentized Residuals with Bonferroni Limits)") +
  
  theme_bw(base_family = "Times New Roman", base_size = 16) +
  theme(
    panel.grid.major.x = element_blank(),  # Loại bỏ đường lưới dọc
    panel.grid.minor.x = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.minor.y = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.major.y = element_blank(),  # Loại bỏ đường lưới dọc
    axis.ticks = element_line(linewidth = 0.5), #nét gạchight (tick marks) trên trục x và y
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  # Thêm viền đen
    axis.text = element_text(color = "black", size = 12),  # Chữ trên trục màu đen
    axis.title = element_text(color = "black", size = 12))+   # Tiêu đề trục màu đen
  theme(plot.title = element_text(family = "Times New Roman Bold", size = 18L, hjust = 0.5),
        axis.title.y = element_text(family = "Times New Roman", size = 36L, vjust = 2), 
        axis.title.x = element_text(family = "Times New Roman", size = 36L, , vjust = -2), 
        axis.text.y = element_text(family = "Times New Roman", size = 36L), 
        axis.text.x = element_text(family = "Times New Roman", size = 36L))+
  theme(legend.title = element_text(family = "Times New Roman", size = 36L),
        legend.text = element_text(family = "Times New Roman", size = 36L),
    aspect.ratio = 1,
    plot.margin = margin(10, 10, 10, 10))+
  theme(legend.position = "none",           #Xoá legend
        plot.title = element_blank())      #Xoá title

print(F22)

#png("F22.png", width = 8, height = 8, units = "cm", res = 600)
#plot(F22, main = "My Base R Plot")
#dev.off()



#333333333333333333333333333333333333333333333333333333333333333333333333333
# Biểu đồ 3
# PREDICTED vs ACTUAL
# =============================== 
library(ggplot2)
library(showtext)
showtext_auto()

model <- ket_qua_modelY2
#actual    <- QHTN$LucF_Y1                    # hoặc CiBD_Y2 nếu bạn đang làm Y2
actual    <- QHTN$CiBD_Y2
predicted <- predict(model)

df_pred <- data.frame(
  Actual    = actual,
  Predicted = predicted,
  Y2        = actual                         # tô màu theo giá trị thực tế
)

# ---- Tự động xác định min–max và tạo breaks đẹp ----
range_val <- range(c(df_pred$Actual, df_pred$Predicted))   # min và max chung
min_val   <- floor(range_val[1]  / 0.1) * 0.1                   # làm tròn xuống
max_val   <- ceiling(range_val[2] / 0.1) * 0.1                 # làm tròn lên
break_seq <- seq(min_val, max_val, by = 0.1)                 # bạn thay 5 → 10, 20… tùy thích

# ---- Biểu đồ hoàn hảo ----
F23 <- ggplot(df_pred, aes(x = Actual, y = Predicted)) +
  
  # Đường hồi quy + vùng tin cậy 95%
  geom_abline(intercept = 0, slope = 1, color = "black", linewidth = 0.5, linetype = "solid") +
  # Các điểm tô màu giống contour(rsm)
  geom_point(aes(fill = Y2), shape = 22, size = 2, color = "black", stroke = 0.5) +
  
  # Palette terrain.colors giống hệt 2 đồ thị trước
  scale_fill_gradientn(colours = viridis_col_simple,
                       name = expression(bold("Ci coefficient"))) +
  
  # Trục x, y: tự động min–max, nhưng breaks tùy chỉnh
  scale_x_continuous(name = "Actual",
                     limits = c(min_val, max_val),
                     breaks = break_seq) +
  scale_y_continuous(name = "Predicted",
                     limits = c(min_val, max_val),
                     breaks = break_seq) +
  
  ggtitle("Predicted vs. Actual Values") +
  
  theme_bw(base_family = "Times New Roman", base_size = 12) +
  theme(
    panel.grid.major.x = element_blank(),  # Loại bỏ đường lưới dọc
    panel.grid.minor.x = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.minor.y = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.major.y = element_blank(),  # Loại bỏ đường lưới dọc
    axis.ticks = element_line(linewidth = 0.5), #nét gạchight (tick marks) trên trục x và y
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  # Thêm viền đen
    axis.text = element_text(color = "black", size = 12),  # Chữ trên trục màu đen
    axis.title = element_text(color = "black", size = 12))+   # Tiêu đề trục màu đen
  theme(plot.title = element_text(family = "Times New Roman Bold", size = 12L, hjust = 0.5),
        axis.title.y = element_text(family = "Times New Roman", size = 36L, vjust = 2), 
        axis.title.x = element_text(family = "Times New Roman", size = 36L, , vjust = -2), 
        axis.text.y = element_text(family = "Times New Roman", size = 36L), 
        axis.text.x = element_text(family = "Times New Roman", size = 36L),
        aspect.ratio = 1,
        plot.margin = margin(10, 10, 10, 10))+
  theme(legend.position = "right",           # hoặc "bottom" nếu muốn nằm dưới
        legend.title = element_text(family = "Times New Roman", size = 36L, hjust = 0.5),     # tiêu đề legend
        legend.text  = element_text(family = "Times New Roman", size = 36L),                    # số trên thanh màu
        legend.key.height = unit(0.5, "cm"),   # chiều cao thanh màu (tăng/giảm thoải mái)
        legend.key.width  = unit(0.5, "cm"),   # độ dày thanh màu
        #legend.background = element_rect(fill = "white", color = "black", linewidth = 0.5), # viền legend
        legend.margin = margin(10, 10, 10, 10))+ # khoảng cách bên trong legend
  theme(plot.title = element_blank())      #Xoá title

# Xem trước
print(F23)

#png("F23.png", width = 16, height = 8, units = "cm", res = 600)
#plot(F23, main = "My Base R Plot")
#dev.off()

###3.2.2. Đồ thị One Factor

#4444444444444444444444444444444444444444444444444444444444444444444444444444
# Biểu đồ 4
# ===============================
# ONE FACTOR PLOT: Ảnh hưởng của e → Ci
# Trục Y tự động min–max + tùy chỉnh khoảng cách chia (ví dụ: mỗi 10)
# ===============================
library(ggplot2)
library(dplyr)
library(showtext)
showtext_auto()

model <- ket_qua_modelY2

# ---- 1. Tạo lưới dự báo cho e từ 15 → 35 mm (giữ x1 = x3 = 0) ----
R_real <- seq(15, 35, length.out = 200)
grid <- data.frame(
  x1 = (R_real - 25)/10,
  x2 = 0,      # chuyển sang coded
  x3 = 0
)

# Dự báo + 95% Confidence Interval
pred <- suppressWarnings(
  predict(model, newdata = grid, interval = "confidence", level = 0.95)
)
grid_df <- data.frame(
  R_real = R_real,
  fit    = pred[,"fit"],
  lwr    = pred[,"lwr"],
  upr    = pred[,"upr"]
)

# ---- 2. Lấy đúng 3 điểm trung tâm thực nghiệm (R = 5 mm) ----
center_points <- data %>%
  filter(KCTam_e == 25 & GocLuon_R == 5) %>%
  select(KCTam_e, CiBD_Y2)

# ---- 3. TỰ ĐỘNG xác định min–max trục Y + tùy chỉnh breaks ----
all_y_values <- c(grid_df$lwr, grid_df$upr, center_points$CiBD_Y2)
min_y <- floor(min(all_y_values) / 0.1) * 0.1      # làm tròn xuống đến bội số 10
max_y <- ceiling(max(all_y_values) / 0.1) * 0.1    # làm tròn lên đến bội số 10

# TỰ DO CHỈNH khoảng cách chia tại đây:
break_step <- 0.1                                 # ← Thay 10 → 20, 50, 5… tùy bạn
y_breaks <- seq((min_y)-0.1, max_y, by = break_step)

# ---- 4. Biểu đồ đẹp hơn cả Design-Expert ----
F24 <- ggplot() +
  
  # Vùng 95% Confidence Interval
  geom_ribbon(data = grid_df,
              aes(x = R_real, ymin = lwr, ymax = upr),
              fill = "gray", alpha = 0.3) +
  
  # Đường dự báo trung bình
  geom_line(data = grid_df,
            aes(x = R_real, y = fit),
            color = "black", linewidth = 0.5) +
  
  # Chỉ 3 điểm đỏ ở tâm (R = 5)
  geom_point(data = center_points,
             aes(x = KCTam_e, y = CiBD_Y2),
             color = "darkred", size = 1.2, shape = 19) +
  
  # Trục X
  scale_x_continuous(name = "Distance e (mm)",
                     breaks = seq(15, 35, by = 5)) +
  
  # Trục Y: tự động min–max + bạn tùy chỉnh khoảng cách chia
  scale_y_continuous(name = "Ci coefficient",
                     limits = c((min_y)-0.1, max_y),
                     breaks = y_breaks) +          # ← Tùy chỉnh ở đây!
  
  ggtitle("One Factor Plot: Effect of R on Ci\n(x1 = 0, x3 = 0)") +
  
  # Theme đồng bộ tuyệt đối với tất cả biểu đồ trước
  theme_bw(base_family = "Times New Roman", base_size = 12) +
  theme(
    panel.grid.major.x = element_blank(),  # Loại bỏ đường lưới dọc
    panel.grid.minor.x = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.minor.y = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.major.y = element_blank(),  # Loại bỏ đường lưới dọc
    axis.ticks = element_line(linewidth = 0.5), #nét gạchight (tick marks) trên trục x và y
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  # Thêm viền đen
    axis.text = element_text(color = "black", size = 36),  # Chữ trên trục màu đen
    axis.title = element_text(color = "black", size = 36))+   # Tiêu đề trục màu đen
  theme(plot.title = element_text(family = "Times New Roman Bold", size = 18L, hjust = 0.5),
        axis.title.y = element_text(family = "Times New Roman", size = 36L, vjust = 2), 
        axis.title.x = element_text(family = "Times New Roman", size = 36L, , vjust = -2), 
        axis.text.y = element_text(family = "Times New Roman", size = 36L), 
        axis.text.x = element_text(family = "Times New Roman", size = 36L))+
  theme(legend.title = element_text(family = "Times New Roman", size = 36L),
        legend.text = element_text(family = "Times New Roman", size = 36L),
        aspect.ratio = 1,
        plot.margin = margin(10, 5, 10, 5))+
  theme(legend.position = "none",           #Xoá legend
        plot.title = element_blank())      #Xoá title

# Xem trước
print(F24)

#png("F24.png", width = 8, height = 8, units = "cm", res = 600)
#plot(F24, main = "My Base R Plot")
#dev.off()




#5555555555555555555555555555555555555555555555555555555555555555555555555555
# Biểu đồ 5
# ===============================
# ONE FACTOR PLOT: Ảnh hưởng của R → Ci
# Trục Y tự động min–max + tùy chỉnh khoảng cách chia (ví dụ: mỗi 10)
# ===============================
library(ggplot2)
library(dplyr)
library(showtext)
showtext_auto()

model <- ket_qua_modelY2

# ---- 1. Tạo lưới dự báo cho R từ 3 → 7 mm (giữ x1 = x3 = 0) ----
R_real <- seq(3, 7, length.out = 200)
grid <- data.frame(
  x1 = 0,
  x2 = (R_real - 5)/2,      # chuyển sang coded
  x3 = 0
)

# Dự báo + 95% Confidence Interval
pred <- suppressWarnings(
  predict(model, newdata = grid, interval = "confidence", level = 0.95)
)
grid_df <- data.frame(
  R_real = R_real,
  fit    = pred[,"fit"],
  lwr    = pred[,"lwr"],
  upr    = pred[,"upr"]
)

# ---- 2. Lấy đúng 3 điểm trung tâm thực nghiệm (R = 5 mm) ----
center_points <- data %>%
  filter(GocLuon_R == 5 & KCTam_e == 25 ) %>%
  select(GocLuon_R, CiBD_Y2)

# ---- 3. TỰ ĐỘNG xác định min–max trục Y + tùy chỉnh breaks ----
all_y_values <- c(grid_df$lwr, grid_df$upr, center_points$CiBD_Y2)
min_y <- floor(min(all_y_values) / 0.1) * 0.1      # làm tròn xuống đến bội số 10
max_y <- ceiling(max(all_y_values) / 0.1) * 0.1    # làm tròn lên đến bội số 10

# TỰ DO CHỈNH khoảng cách chia tại đây:
break_step <- 0.1                                 # ← Thay 10 → 20, 50, 5… tùy bạn
y_breaks <- seq(min_y, (max_y)+0.1, by = break_step)

# ---- 4. Biểu đồ đẹp hơn cả Design-Expert ----
F25 <- ggplot() +
  
  # Vùng 95% Confidence Interval
  geom_ribbon(data = grid_df,
              aes(x = R_real, ymin = lwr, ymax = upr),
              fill = "gray", alpha = 0.3) +
  
  # Đường dự báo trung bình
  geom_line(data = grid_df,
            aes(x = R_real, y = fit),
            color = "black", linewidth = 0.5) +
  
  # Chỉ 3 điểm đỏ ở tâm (R = 5)
  geom_point(data = center_points,
             aes(x = GocLuon_R, y = CiBD_Y2),
             color = "darkred", size = 1.2, shape = 19) +
  
  # Trục X
  scale_x_continuous(name = "Corner radius R (mm)",
                     breaks = seq(3, 7, by = 1)) +
  
  # Trục Y: tự động min–max + bạn tùy chỉnh khoảng cách chia
  scale_y_continuous(name = "Ci coefficient",
                     limits = c(min_y, (max_y)+0.1),
                     breaks = y_breaks) +          # ← Tùy chỉnh ở đây!
  
  ggtitle("One Factor Plot: Effect of R on Ci\n(x1 = 0, x3 = 0)") +
  
  # Theme đồng bộ tuyệt đối với tất cả biểu đồ trước
  theme_bw(base_family = "Times New Roman", base_size = 12) +
  theme(
    panel.grid.major.x = element_blank(),  # Loại bỏ đường lưới dọc
    panel.grid.minor.x = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.minor.y = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.major.y = element_blank(),  # Loại bỏ đường lưới dọc
    axis.ticks = element_line(linewidth = 0.5), #nét gạchight (tick marks) trên trục x và y
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  # Thêm viền đen
    axis.text = element_text(color = "black", size = 36),  # Chữ trên trục màu đen
    axis.title = element_text(color = "black", size = 36))+   # Tiêu đề trục màu đen
  theme(plot.title = element_text(family = "Times New Roman Bold", size = 18L, hjust = 0.5),
        axis.title.y = element_text(family = "Times New Roman", size = 36L, vjust = 2), 
        axis.title.x = element_text(family = "Times New Roman", size = 36L, , vjust = -2), 
        axis.text.y = element_text(family = "Times New Roman", size = 36L), 
        axis.text.x = element_text(family = "Times New Roman", size = 36L))+
  theme(legend.title = element_text(family = "Times New Roman", size = 36L),
        legend.text = element_text(family = "Times New Roman", size = 36L),
        aspect.ratio = 1,
        plot.margin = margin(10, 5, 10, 5))+
  theme(legend.position = "none",           #Xoá legend
        plot.title = element_blank())      #Xoá title

# Xem trước
print(F25)

#png("F25.png", width = 8, height = 8, units = "cm", res = 600)
#plot(F25, main = "My Base R Plot")
#dev.off()



#6666666666666666666666666666666666666666666666666666666666666666666666666666
# Biểu đồ 6
# ===============================
# Biểu đồ One Factor: Ảnh hưởng của Hệ số ma sát μ → Ci
# Hoàn toàn giống format F4 của bạn (8x8 cm, font 72, không title/legend)
# ===============================
library(ggplot2)
library(dplyr)
library(showtext)
showtext_auto()

model <- ket_qua_modelY2   # hoặc ket_qua_model_opt

# ---- 1. Tạo lưới dự báo cho μ từ 0.10 → 0.20 (giữ x1=x2=0) ----
mu_real <- seq(0.10, 0.20, length.out = 200)
grid <- data.frame(
  x1 = 0,
  x2 = 0,
  x3 = (mu_real - 0.15)/0.05   # chuyển sang coded: (μ - 0.15)/0.05
)

# Dự báo + 95% Confidence Interval
pred <- suppressWarnings(
  predict(model, newdata = grid, interval = "confidence", level = 0.95)
)

grid_df <- data.frame(
  mu_real = mu_real,
  fit = pred[,"fit"],
  lwr = pred[,"lwr"],
  upr = pred[,"upr"]
)

# 3. LẤY ĐIỂM TRUNG TÂM – DÙNG round() ĐỂ TRÁNH LỖI LÀM TRÒN
center_points <- data %>%
  mutate(mu_round = round(HesoMS_f, 3)) %>%     # làm tròn 3 chữ số
  filter(mu_round == 0.150 & KCTam_e == 25) %>%                  # chắc chắn bắt được 0.15
  select(mu_real = HesoMS_f, CiBD_Y2)          # đổi tên cột cho khớp

# Kiểm tra nhanh: phải ra đúng 3 dòng
print(center_points)
## # A tibble: 3 × 2
##   mu_real CiBD_Y2
##     <dbl>   <dbl>
## 1    0.15   0.458
## 2    0.15   0.483
## 3    0.15   0.509
# ---- 3. TỰ ĐỘNG xác định min–max trục Y + tùy chỉnh breaks ----
all_y_values <- c(grid_df$lwr, grid_df$upr, center_points$CiBD_Y2)
min_y <- floor(min(all_y_values) / 0.1) * 0.1      # làm tròn xuống đến bội số 10
max_y <- ceiling(max(all_y_values) / 0.1) * 0.1    # làm tròn lên đến bội số 10


# TỰ DO CHỈNH khoảng cách chia tại đây:
break_step <- 0.1                             # ← Thay 10 → 20, 50, 5…tùy bạn
y_breaks <- seq((min_y)-0.1, (max_y +0.1), by = break_step)


# ---- 4. Biểu đồ giống hệt F4 của bạn ----
F26 <- ggplot() +
  geom_ribbon(data = grid_df,
              aes(x = mu_real, ymin = lwr, ymax = upr),
              fill = "gray", alpha = 0.3) +
  geom_line(data = grid_df,
            aes(x = mu_real, y = fit),
            color = "black", linewidth = 0.5) +
  geom_point(data = center_points,
             aes(x = mu_real, y = CiBD_Y2),
             color = "darkred", size = 1.2, shape = 19) +
  
  scale_x_continuous(name = "Friction coefficient μ",
                     breaks = seq(0.10, 0.20, by = 0.02)) +
  scale_y_continuous(name = "Ci coefficient",
                     limits = c((min_y)-0.1, (max_y +0.1)),
                     breaks = y_breaks) +
  
  ggtitle("One Factor Plot: Effect of mu on Ci\n(x1 = 0, x3 = 0)") +
  
  # Theme đồng bộ tuyệt đối với tất cả biểu đồ trước
  theme_bw(base_family = "Times New Roman", base_size = 12) +
  theme(
    panel.grid.major.x = element_blank(),  # Loại bỏ đường lưới dọc
    panel.grid.minor.x = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.minor.y = element_blank(),  # Loại bỏ đường lưới dọc nhỏ
    panel.grid.major.y = element_blank(),  # Loại bỏ đường lưới dọc
    axis.ticks = element_line(linewidth = 0.5), #nét gạchight (tick marks) trên trục x và y
    panel.border = element_rect(color = "black", fill = NA, linewidth = 0.5),  # Thêm viền đen
    axis.text = element_text(color = "black", size = 36),  # Chữ trên trục màu đen
    axis.title = element_text(color = "black", size = 36))+   # Tiêu đề trục màu đen
  theme(plot.title = element_text(family = "Times New Roman Bold", size = 18L, hjust = 0.5),
        axis.title.y = element_text(family = "Times New Roman", size = 36L, vjust = 2), 
        axis.title.x = element_text(family = "Times New Roman", size = 36L, , vjust = -2), 
        axis.text.y = element_text(family = "Times New Roman", size = 36L), 
        axis.text.x = element_text(family = "Times New Roman", size = 36L))+
  theme(legend.title = element_text(family = "Times New Roman", size = 36L),
        legend.text = element_text(family = "Times New Roman", size = 36L),
        aspect.ratio = 1,
        plot.margin = margin(10, 5, 10, 5))+
  theme(legend.position = "none",           #Xoá legend
        plot.title = element_blank())      #Xoá title

# Xem trước
print(F26)

#png("F26.png", width = 8, height = 8, units = "cm", res = 600)
#plot(F26, main = "My Base R Plot")
#dev.off()

###3.2.3. Đồ thị Contour Plot

#7777777777777777777777777777777777777777777777777777777777777777777777777777
## Biểu đồ contour ảnh hưởng e & R tới Ci

#png("F27v2.png", width = 8, height = 8, units = "cm", res = 600)

library(viridis)
# Tạo dải 120 màu (giống col_dx_120 của bạn)
viridis_col_120 <- viridis(120, option = "D")  # Mặc định: viridis "D" (xanh tím → vàng)  "turbo" là tím-đỏ
cividis_col_120  <- viridis(120, option = "E")  # Xanh → vàng (colorblind-safe nhất)
my_col <- c("#0000FF", "#00FFFF", "#00FF00", "#FFFF00", "#FF8000", "#FF0000")
col_dx_120 <- colorRampPalette(my_col)(120)

viridis_col_full <- viridis(120, option = "turbo")
viridis_col_simple <- viridis_col_full[1:90]  # Chọn từ vị trí 1 đến 90

par(family = "Times New Roman", ps = 36, cex = 1,
    mar = c(4, 3, 1, 1), oma = c(0, 0, 0, 0), mgp = c(3, 0.6, 0), las = 1, tcl = -0.3)

# Tạo lưới đều
e_vals  <- seq(15, 35, length.out = 300)
R_vals  <- seq(3, 7, length.out = 300)
mu_vals <- seq(0.1, 0.2, length.out = 300)

# Mở rộng thêm 0.15 ở mỗi đầu → tạo đoạn thừa rõ rệt
xlim <- c(14.5, 35.5)   # thay vì c(15,35)
ylim <- c(2.9, 7.1)   # thay vì c(3,7)


grid <- expand.grid(x1 = (e_vals - 25)/10, x2 = (R_vals - 5)/2)
grid$x3 <- 0
grid$yhat <- predict(ket_qua_modelY2, grid)

zmat <- matrix(grid$yhat, 300, 300)

# Vẽ nền gradient đúng màu bạn muốn
image(e_vals, R_vals, zmat, col = viridis_col_simple, xlim = xlim, ylim = ylim,
      xlab = "", ylab = "", axes = TRUE, useRaster = TRUE)


min_z <- min(zmat)
max_z <- max(zmat)
levels_05 <- seq(
  floor(min_z/0.05)*0.05,
  ceiling(max_z/0.05)*0.05,
  by = 0.05)

# Vẽ đường đồng mức + nhãn số
contour(e_vals, R_vals, zmat, add = TRUE,
        col = "black", lwd = 1, labcex = 1, drawlabels = TRUE, method = "flattest")
        #levels = levels_05)    # ★★★ ép mức đồng mức theo bước 0.05)

# Trục + nhãn
# Vẽ trục (chỉ vạch, không chữ)
#axis(1, tcl = -0.3, mgp = c(3, 0.6, 0))
#axis(2, tcl = -0.3, mgp = c(3, 0.8, 0), las = 1)

# THÊM NHÃN TRỤC ĐÚNG NHƯ BẠN MUỐN (đẹp, điều chỉnh được line, cex, font)
title(xlab = "Distance e (mm)",
      line = 1.6,        # chỉnh độ cao trục X ở đây
      cex.lab = 1,       # đúng 12 pt
      family = "Times New Roman")

title(ylab = "Corner radius R (mm)",
      line = 1.6,        # chỉnh độ cao trục Y ở đây
      cex.lab = 1,       # đúng 12 pt
      family = "Times New Roman")

# Tiêu đề slice (bạn tự đặt, không còn "Slice at x1 = 0")
mtext("Slice at Friction coefficient μ = 0.15", 
      family = "Times New Roman",
      side = 1, line = 2.8, cex = 1, font = 1)   # font = 2 → in đậm

#dev.off()

###3.2.4. Đồ thị 3D Surface Plot

#===================================================================CHUẨN MẪU
#8888888888888888888888888888888888888888888888888888888888888888888888888888
## Biểu đồ 3D Surface ảnh hưởng e & R tới Ci

#png("F28v2.png", width = 8, height = 8, units = "cm", res = 600)
viridis_col_simple <- viridis(120, option = "D")
viridis_col_full <- viridis(120, option = "turbo")
viridis_col_simple <- viridis_col_full[1:90]  # Chọn từ vị trí 1 đến 90

par(
  family = "Times New Roman",
  ps = 36,
  cex = 1,
  mar = c(2.6, 2.6, 0.1, 0.1),  #(Dưới, Trái, Trên, Phải)
  mgp = c(0.5, 0.02, 0.7)     #(title, tick lable, tick mark)
)

# Tạo lưới đều
e_vals  <- seq(15, 35, length.out = 300)
R_vals  <- seq(3, 7, length.out = 300)
mu_vals <- seq(0.1, 0.2, length.out = 300)

grid <- expand.grid(x1 = (e_vals - 25)/10, x2 = (R_vals - 5)/2)
grid$x3 <- 0
grid$yhat <- predict(ket_qua_modelY2, grid)

zmat <- matrix(grid$yhat, 300, 300)
min_z <- min(zmat)
max_z <- max(zmat)

Color_Tren <- ((0.7-max_z)/(max_z - min_z))*90
Color_Duoi <-((min_z-0.2)/(max_z - min_z))*90


# Thêm các màu trống cả phía trước và phía sau
viridis_col_extended <- c(
  rep(viridis_col_simple[1], Color_Duoi),      # Thêm 36 màu giống màu đầu tiên (phía dưới)
  viridis_col_simple,                 # Dải màu chính từ thấp đến cao
  rep(viridis_col_simple[90], Color_Tren)   # Thêm 36 màu giống màu cuối cùng (phía trên)
)

# Tạo các mức contour cách nhau 0.05
levels_05 <- seq(
  floor(min_z/0.05)*0.05,
  ceiling(max_z/0.05)*0.05,
  by = 0.05)


# Vẽ đồ thị không có trục
res <- persp(
  ket_qua_modelY2,
  ~ x1 + x2,
  at = c(x3 = 0),
  zlim = c(0.2, 0.7),   # ← thêm khoảng trống !!!
  axes = FALSE,
  #sub = NULL,                 # ẩn Slice at
  col = viridis_col_extended,
  #contours = "colors",
  contours = list(levels = levels_05, col = "colors"),  # Mức bước 0.05, màu tự động
  color.legend = TRUE,
  expand = 1,
  theta = -28,
  phi = 20
)
## Warning in persp.default(dat$x, dat$y, dat$z, zlim = dat$zlim, theta = theta, :
## "color.legend" is not a graphical parameter
## Warning in persp.default(dat$x, dat$y, dat$z, xlab = dat$labs[1], ylab =
## dat$labs[2], : "color.legend" is not a graphical parameter
## Warning in title(sub = dat$labs[5], ...): "axes" is not a graphical parameter
## Warning in title(sub = dat$labs[5], ...): "color.legend" is not a graphical
## parameter
## Warning in title(sub = dat$labs[5], ...): "expand" is not a graphical parameter
# Tạo lưới và các giá trị tick
x1_seq_coded <- seq(min(QHTN$x1), max(QHTN$x1), length.out = 80)
x2_seq_coded <- seq(min(QHTN$x2), max(QHTN$x2), length.out = 80)
e_seq_coded <- seq(min(data$KCTam_e), max(data$KCTam_e), length.out = 80)
R_seq_coded <- seq(min(data$GocLuon_R), max(data$GocLuon_R), length.out = 80)
#f_seq_coded <- seq(min(data$HesoMS_f), max(data$HesoMS_f), length.out = 80)
grid <- expand.grid(x1 = x1_seq_coded, x2 = x2_seq_coded, x3 = 0)
grid_real <- expand.grid(x1 = e_seq_coded, x2 = R_seq_coded, x3 = 0.15)
grid$F_pred <- predict(ket_qua_modelY2, newdata = grid)
z_mat <- matrix(grid$F_pred, nrow = length(x1_seq_coded), ncol = length(x2_seq_coded))

x_ticks1 <- c("–","–","–","–","–")
x_ticks2 <- c("15","20","25","30","35")
y_ticks1 <- c("–","–","–","–","–")
y_ticks2 <- c("3","4","5","6","7")
#y_ticks1 <- c("–","–","–","–","–","–")
#y_ticks2 <- c("0.10","0.12","0.14","0.16","0.18","0.20")
z_ticks1 <- c("","–","–","–","–","–")
z_ticks2 <- c("","0.3","0.4","0.5","0.6","0.7")
par(xpd = NA)

#################################################### TRỤC X
###X11 Vẽ tick marks cho trục x2 với phép xoay toàn bộ trục
rotation_angle <- -73  # Góc xoay của toàn bộ trục x2 (độ)
angle_rad <- rotation_angle * pi / 180

offset1 <- 0.403
for(i in seq_along(x_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base11_x <- 0.247   #giảm là lên
  base11_y <- -0.239  #giảm là sang trái
  tick_offset <- (i/length(x_ticks1)) * offset1
  
  x_before <- base11_x
  y_before <- base11_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = x_ticks1[i], 
       cex = 1, 
       srt = rotation_angle)
}

###X12 Vẽ tick labels cho trục x2 với phép xoay toàn bộ trục
for(i in seq_along(x_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base12_x <- base11_x +0.03   #giảm là lên
  base12_y <- base11_y  #giảm là sang trái
  tick_offset <- (i/length(x_ticks1)) * offset1
  
  x_before <- base12_x
  y_before <- base12_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = x_ticks2[i], 
       cex = 1, 
       srt = 0)
}

############ CÁCH 2: VẼ GẠCH TICK MARK BẰNG ĐIỂM
#for(i in seq_along(x_ticksmark)) {
# Tọa độ gốc của tick trước khi xoay
#tick_offset <- (i/length(x_ticksmark)) * 0.4

#x_before <- base_x
#y_before <- base_y + tick_offset

# Tính tọa độ sau khi xoay
#rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
#rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)

#Vẽ tick mark tại vị trí đã xoay
#tmx21=rotated_x-0.062           #giảm là sang trái
#tmx22=rotated_y+0.01           #giảm là xuống
#segments(tmx21, tmx22, 
#tmx21+0.008, tmx22-0.012, 
#col = "black", lwd = 1.2)}

#################################################### TRỤC Y
###Y21 Vẽ tick marks cho trục x3 với phép xoay toàn bộ trục
rotation_angle <- 37  # Góc xoay của toàn bộ trục x3 (độ)
angle_rad <- rotation_angle * pi / 180
offset2 <- 0.245

for(i in seq_along(y_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base21_x <- -0.239        #giảm là sang trái
  base21_y <- -0.22         #giảm là xuống
  tick_offset <- (i/length(y_ticks1)) * offset2
  
  x_before <- base21_x
  y_before <- base21_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = y_ticks1[i], 
       cex = 1, 
       srt = rotation_angle)
}

###Y22 Vẽ tick labels cho trục x3 với phép xoay toàn bộ trục
for(i in seq_along(y_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base22_x <- base21_x -0.04        #giảm là sang trái
  base22_y <- base21_y +0.01         #giảm là xuống
  tick_offset <- (i/length(y_ticks1)) * offset2
  
  x_before <- base22_x
  y_before <- base22_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay CÁCH 2
  #segments(rotated_x - 0.05, rotated_y, 
  #rotated_x + 0.05, rotated_y, 
  #col = "black", lwd = 1.2)
  
  # Vẽ tick label tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = y_ticks2[i], 
       cex = 1, 
       srt = rotation_angle-37)
}

#################################################### TRỤC Z
###Z31 Vẽ tick marks cho trục z với phép xoay toàn bộ trục
rotation_angle <- 4.2  # Góc xoay của toàn bộ trục z (độ)
angle_rad <- rotation_angle * pi / 180
offset3 <- 0.3568

for(i in seq_along(z_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base31_x <- -0.217    #giảm là sang trái
  base31_y <- -0.163     #giảm là xuống
  tick_offset <- (i/length(z_ticks1)) * offset3
  
  x_before <- base31_x
  y_before <- base31_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = z_ticks1[i], 
       cex = 1, 
       srt = rotation_angle)
}

###Z32 Vẽ tick label cho trục z với phép xoay toàn bộ trục
for(i in seq_along(z_ticks1)) {
  # Tọa độ gốc của tick trước khi xoay
  base32_x <- base31_x -0.04    #giảm là sang trái
  base32_y <- base31_y    #giảm là xuống
  tick_offset <- (i/length(z_ticks1)) * offset3
  
  x_before <- base32_x
  y_before <- base32_y + tick_offset
  
  # Tính tọa độ sau khi xoay
  rotated_x <- x_before * cos(angle_rad) - y_before * sin(angle_rad)
  rotated_y <- x_before * sin(angle_rad) + y_before * cos(angle_rad)
  
  # Vẽ tick mark tại vị trí đã xoay CÁCH 2
  #segments(rotated_x - 0.05, rotated_y, 
  #rotated_x + 0.05, rotated_y, 
  #col = "black", lwd = 1.2)
  
  # Vẽ tick label tại vị trí đã xoay
  text(rotated_x, rotated_y, 
       labels = z_ticks2[i], 
       cex = 1, 
       srt = 0)
}

# Thêm nhãn cho các trục
par(xpd = NA, srt = -55)
text(-0.23, -0.24, "Corner radius R (mm)")
par(xpd = NA, srt = 20)
text(0.13, -0.3, "Distance e (mm)")
par(xpd = NA, srt = -85)
text(-0.32, 0.01, "Ci coefficient")

#dev.off()

#4. Optimization (Tối ưu) ##4.1. Tính toán giá trị tối ưu

#==============================================================================
#********************************************************** TỐI ƯU HOÁ ***** 
#==============================================================================
# Multi-response optimization using desirability package
library(desirability)
# ----------------------------
# USER SETTINGS
# ----------------------------
goal_y1 <- "min" # LucF_Y1
goal_y2 <- "min" # CiBD_Y2
importance_y1 <- 3
importance_y2 <- 5
shape_y1 <- 1.0
shape_y2 <- 1.0
# Đảm bảo các giá trị thấp/cao không bị NA
y1_low <- min(QHTN$LucF_Y1); y1_target <- NA; y1_high <- max(QHTN$LucF_Y1)
y2_low <- 0.2; y2_target <- NA; y2_high <- max(QHTN$CiBD_Y2)
grid_n <- 11
top_start_n <- 6
# ----------------------------
if (!exists("ket_qua_model") || !exists("ket_qua_modelY2")) stop("Models not found")
x1_rng <- range(QHTN$x1); x2_rng <- range(QHTN$x2); x3_rng <- range(QHTN$x3)
e_min <- x1_rng[1]*10 + 25; e_max <- x1_rng[2]*10 + 25
R_min <- x2_rng[1]*2 + 5; R_max <- x2_rng[2]*2 + 5
mu_min <- x3_rng[1]*0.05 + 0.15; mu_max <- x3_rng[2]*0.05 + 0.15

cat(sprintf(" e: %.3f — %.3f\n R: %.3f — %.3f\n mu: %.4f — %.4f\n\n", e_min, e_max, R_min, R_max, mu_min, mu_max))
##  e: 15.000 — 35.000
##  R: 3.000 — 7.000
##  mu: 0.1000 — 0.2000
# ----------------------------
# Define individual desirability functions
if (goal_y1 == "max") {
  y1D <- dMax(y1_low, y1_high, scale = shape_y1)
} else if (goal_y1 == "min") {
  y1D <- dMin(y1_low, y1_high, scale = shape_y1)
} else {
  y1D <- dTarget(y1_low, y1_target, y1_high, scale = shape_y1)
}
if (goal_y2 == "max") {
  y2D <- dMax(y2_low, y2_high, scale = shape_y2)
} else if (goal_y2 == "min") {
  y2D <- dMin(y2_low, y2_high, scale = shape_y2)
} else {
  y2D <- dTarget(y2_low, y2_target, y2_high, scale = shape_y2)
}

# LƯU Ý: Loại bỏ định nghĩa overallD do lỗi

cat("Using desirability bounds:\n")
## Using desirability bounds:
cat(sprintf(" Y1 (low, target, high) = %.4f, %s, %.4f\n", y1_low, ifelse(is.na(y1_target),"NA",format(y1_target, digits=6)), y1_high))
##  Y1 (low, target, high) = 107.1278, NA, 133.7514
cat(sprintf(" Y2 (low, target, high) = %.4f, %s, %.4f\n\n", y2_low, ifelse(is.na(y2_target),"NA",format(y2_target, digits=6)), y2_high))
##  Y2 (low, target, high) = 0.2000, NA, 0.6149
# ----------------------------
# Overall desirability function (TÍNH THỦ CÔNG)
overall_D_point <- function(par_real) {
  e <- par_real[1]; R_real <- par_real[2]; mu_real <- par_real[3]
  x1c <- (e - 25)/10; x2c <- (R_real - 5)/2; x3c <- (mu_real - 0.15)/0.05
  newd <- data.frame(x1 = x1c, x2 = x2c, x3 = x3c)
  y1 <- predict(ket_qua_model, newd)
  y2 <- predict(ket_qua_modelY2, newd)
  
  d1 <- predict(y1D, y1)
  d2 <- predict(y2D, y2)
  
  # Tính Desirability Tổng thể (D) theo công thức Geometric Mean
  # D = (d1^w1 * d2^w2)^(1 / (w1 + w2))
  D_val <- (d1^importance_y1 * d2^importance_y2)^(1 / (importance_y1 + importance_y2))
  
  list(D = as.numeric(D_val), d1 = as.numeric(d1), d2 = as.numeric(d2), y1 = y1, y2 = y2,
       coded = c(x1 = x1c, x2 = x2c, x3 = x3c), real = c(e = e, R = R_real, mu = mu_real))
}
# ----------------------------
# Coarse grid search (TÍNH D thủ công)
e_grid <- seq(e_min, e_max, length.out = grid_n)
R_grid <- seq(R_min, R_max, length.out = grid_n)
mu_grid <- seq(mu_min, mu_max, length.out = grid_n)
grid_coarse <- expand.grid(e = e_grid, R = R_grid, mu = mu_grid)
coded_coarse <- data.frame(x1 = (grid_coarse$e - 25)/10, x2 = (grid_coarse$R - 5)/2, x3 = (grid_coarse$mu - 0.15)/0.05)
grid_coarse$y1 <- predict(ket_qua_model, coded_coarse)
grid_coarse$y2 <- predict(ket_qua_modelY2, coded_coarse)

# Tính d1, d2 và D cho lưới thô
grid_coarse$d1 <- predict(y1D, grid_coarse$y1)
grid_coarse$d2 <- predict(y2D, grid_coarse$y2)
grid_coarse$D <- (grid_coarse$d1^importance_y1 * grid_coarse$d2^importance_y2)^(1 / (importance_y1 + importance_y2))

ord <- order(grid_coarse$D, decreasing = TRUE)
best_starts <- grid_coarse[ord[1:top_start_n], c("e","R","mu","y1","y2","d1","d2","D")]

cat("Top coarse candidates (real variables):\n")
## Top coarse candidates (real variables):
print(best_starts)
##     e R  mu       y1        y2        d1        d2         D
## 10 33 3 0.1 122.6922 0.2776648 0.4153889 0.8127966 0.6319158
## 11 35 3 0.1 122.5727 0.2800541 0.4198801 0.8070373 0.6316558
## 9  31 3 0.1 122.6392 0.2802323 0.4173812 0.8066079 0.6300338
## 8  29 3 0.1 122.4135 0.2877566 0.4258572 0.7884712 0.6258426
## 7  27 3 0.1 122.0153 0.3002378 0.4408167 0.7583865 0.6187688
## 6  25 3 0.1 121.4444 0.3176758 0.4622598 0.7163539 0.6078369
# ----------------------------
# Optimization
obj_neg <- function(par_real) -overall_D_point(par_real)$D
best_list <- list()
for (i in 1:min(nrow(best_starts), top_start_n)) {
  init <- as.numeric(best_starts[i, c("e","R","mu")])
  lower <- c(e_min, R_min, mu_min); upper <- c(e_max, R_max, mu_max)
  opt <- tryCatch(optim(init, obj_neg, method = "L-BFGS-B", lower = lower, upper = upper, control = list(maxit = 500)),
                  error = function(e) list(par = init, value = NA))
  res_info <- overall_D_point(opt$par)
  best_list[[i]] <- list(par = opt$par, info = res_info)
}

Dvals <- sapply(best_list, function(z) z$info$D)
best_idx <- which.max(Dvals)
best_final <- best_list[[best_idx]]

cat("\n=== BEST SOLUTION ===\n")
## 
## === BEST SOLUTION ===
print(best_final$info)
## $D
## [1] 0.6320734
## 
## $d1
## [1] 0.4163485
## 
## $d2
## [1] 0.811996
## 
## $y1
##        1 
## 122.6667 
## 
## $y2
##         1 
## 0.2779969 
## 
## $coded
##         x1         x2         x3 
##  0.8768963 -1.0000000 -1.0000000 
## 
## $real
##        e        R       mu 
## 33.76896  3.00000  0.10000
cat(sprintf("\nOverall D = %.6f\n", best_final$info$D))
## 
## Overall D = 0.632073
cat("Real variables (e, R, mu):\n"); print(best_final$info$real)
## Real variables (e, R, mu):
##        e        R       mu 
## 33.76896  3.00000  0.10000
cat("Coded variables (x1,x2,x3):\n"); print(best_final$info$coded)
## Coded variables (x1,x2,x3):
##         x1         x2         x3 
##  0.8768963 -1.0000000 -1.0000000
cat("Predicted responses (y1,y2):\n"); print(round(c(best_final$info$y1, best_final$info$y2),6))
## Predicted responses (y1,y2):
##          1          1 
## 122.666683   0.277997
cat("Individual desirabilities (d1,d2):\n"); print(round(c(best_final$info$d1, best_final$info$d2),6))
## Individual desirabilities (d1,d2):
## [1] 0.416348 0.811996

##4.2. Plot tối ưu

#===========================================================================
#                 VẼ BỘ BIỂU ĐỒ SOLUTION (Desirability Plots)
#===========================================================================
# Thêm thư viện cần thiết
library(ggplot2)
library(ggpubr) # Để dùng ggarrange
library(showtext)

# === 1. LẤY GIÁ TRỊ TỐI ƯU TRỰC TIẾP TỪ KẾT QUẢ TÍNH TOÁN ===
# Giả định: biến 'best_final' đã được tính toán ở phần code trước.
if (!exists("best_final")) {
  stop("Lỗi: Biến 'best_final' (kết quả tối ưu) không tồn tại. Vui lòng chạy phần code tối ưu hóa trước.")
}

e_opt <- best_final$info$real['e']
R_opt <- best_final$info$real['R']
mu_opt <- best_final$info$real['mu']
F_opt <- best_final$info$y1
Ci_opt <- best_final$info$y2
D_opt <- best_final$info$D

# === 2. CÁC GIỚI HẠN ===

# Khoảng giới hạn của các biến/đáp ứng
e_min <- 15; e_max <- 35
R_min <- 3; R_max <- 7
mu_min <- 0.1; mu_max <- 0.2
F_min <- 107.128; F_max <- 133.751 # Khoảng giá trị thực nghiệm của Y1
Ci_min <- 0.2; Ci_max <- 0.614868 # Khoảng giá trị cho D-function của Y2


# TẠO HÀM VẼ TỪNG BIỂU ĐỒ (Dạng 'stepped' cho biến rời rạc hoặc 'sloped' cho đáp ứng)


#============================================================================

# ----------------------------
# USER SETTING: KÍCH THƯỚC CHỮ
# ----------------------------  *5.5 để export png 16x12 600dpi
SIZE_TEXT <- 4.3*2.5  # Điều chỉnh giá trị này để thay đổi cỡ chữ toàn bộ
# ----------------------------

# Thêm thư viện cần thiết
library(ggplot2)
library(ggpubr) 
library(showtext) 
# Đảm bảo đã load font Times New Roman

# === DỮ LIỆU TỐI ƯU (Giả định đã có) ===
if (!exists("best_final")) {
  stop("Lỗi: Biến 'best_final' (kết quả tối ưu) không tồn tại. Vui lòng chạy phần code tối ưu hóa trước.")
}

e_opt <- best_final$info$real['e']; R_opt <- best_final$info$real['R']
mu_opt <- best_final$info$real['mu']; F_opt <- best_final$info$y1
Ci_opt <- best_final$info$y2; D_opt <- best_final$info$D

# Khoảng giới hạn của các biến/đáp ứng
e_min <- 15; e_max <- 35
R_min <- 3; R_max <- 7
mu_min <- 0.1; mu_max <- 0.2
F_min <- 107.128; F_max <- 133.751 
Ci_min <- 0.2; Ci_max <- 0.614868 


#111111111111111111111111111111111111111111111111111111111111111111111111111
# Hàm cho các yếu tố (A, B, C) - Dạng stepped 
# ĐÃ SỬA: Thêm size_t vào tham số mặc định
plot_factor <- function(var_name, var_label, var_opt, var_min, var_max, size_t = SIZE_TEXT) {
  
  Y_PADDING <- 1 
  var_range <- var_max - var_min
  EXPANSION_FACTOR <- 0.1
  var_min_line <- var_min - EXPANSION_FACTOR * var_range
  var_max_line <- var_max + EXPANSION_FACTOR * var_range
  Y_SCALE_COMPRESSION <- 0.8
  Y_MAX_LIMIT <- 1.3 
  
  df_line_precise <- data.frame(
    x = c(var_min_line, var_min, var_min, var_max, var_max, var_max_line),
    y = c(0, 0, Y_SCALE_COMPRESSION, Y_SCALE_COMPRESSION, 0, 0)
  )
  
  ggplot() +
    geom_hline(yintercept = -Y_PADDING, color = "gray40", linewidth = 0.5) +
    geom_line(data = df_line_precise, aes(x = x, y = y), 
              color = "gray40", linewidth = 0.7) +
    geom_point(aes(x = var_opt, y = Y_SCALE_COMPRESSION), color = "red", size = 2) +
    
    annotate("text", x = var_min, y = 0, label = format(var_min, digits = 2), 
             hjust = 0, vjust = 1.5, family = "Times New Roman", size = size_t) +
    annotate("text", x = var_max, y = 0, label = format(var_max, digits = 2), 
             hjust = 1, vjust = 1.5, family = "Times New Roman", size = size_t) +
    
    annotate("text", x = mean(c(var_min, var_max)), y = -Y_PADDING / 2-0.1,         # khoảng cách đến lề dưới khung Box
             label = paste0(var_label, " = ", format(round(var_opt, 3))), 
#format(resp_opt, digits = 6, nsmall = 4) 
#digits = 3 là Tối thiểu $3$ chữ số có nghĩa
#nsmall = 4 là Tối thiểu $4$ chữ số sau dấu phẩy
             hjust = 0.5, vjust = 0.5, family = "Times New Roman", size = size_t) + 
    
    scale_x_continuous(limits = c(var_min_line, var_max_line), expand = c(0, 0)) +
    scale_y_continuous(limits = c(-Y_PADDING, Y_MAX_LIMIT), expand = c(0, 0)) +
    labs(x = NULL, y = NULL) +
    theme_minimal() +
    theme(
      plot.title = element_blank(), axis.title.x = element_blank(), 
      axis.title.y = element_blank(), axis.text.x = element_blank(), 
      axis.text.y = element_blank(), plot.caption = element_blank(), 
      panel.border = element_rect(colour = "black", fill=NA, linewidth=0.5), 
      panel.grid.major = element_blank(), panel.grid.minor = element_blank(), 
      plot.margin = margin(5, 5, 5, 5, "pt") 
    )
}


#222222222222222222222222222222222222222222222222222222222222222222222222222
# Hàm cho các đáp ứng (Y1, Y2) - Dạng sloped
# ĐÃ SỬA: Thêm size_t vào tham số mặc định
plot_response <- function(resp_label, resp_opt, resp_min, resp_max, color_opt="blue", size_t = SIZE_TEXT) {
  
  Y_PADDING <- 1           #Khoảng cách đường ngang dưới với lề dưới khung Box
  resp_range <- resp_max - resp_min
  EXPANSION_FACTOR <- 0.2 
  resp_min_line <- resp_min - EXPANSION_FACTOR * resp_range
  resp_max_line <- resp_max + EXPANSION_FACTOR * resp_range
  Y_MAX_LIMIT <- 1.6        #Khoảng cách đường ngang trên với lề trên khung Box
  
  df_line_precise <- data.frame(
    x = c(resp_min_line, resp_min, resp_max, resp_max_line),
    y = c(1, 1, 0, 0)
  )
  
  x_rel_opt <- (resp_opt - resp_min) / resp_range
  y_opt_pos <- 1 - x_rel_opt 
  
  ggplot() +
    geom_hline(yintercept = -Y_PADDING, color = "gray40", linewidth = 0.5) +
    geom_line(data = df_line_precise, aes(x = x, y = y), 
              color = "gray40", linewidth = 0.7) +
    geom_point(aes(x = resp_opt, y = y_opt_pos), color = color_opt, size = 2) +
    
    annotate("text", x = resp_min, y = 1, label = format(resp_min, digits = 3), 
             hjust = 1, vjust = -0.5, family = "Times New Roman", size = size_t) +
    annotate("text", x = resp_max, y = 0, label = format(resp_max, digits = 3), 
             hjust = 0, vjust = -0.5, family = "Times New Roman", size = size_t) +
    
    annotate("text", x = mean(c(resp_min, resp_max)), y = -Y_PADDING / 2 -0.1, 
             label = paste0(resp_label, " = ", format(resp_opt, digits = 6, nsmall = 4)), 
             hjust = 0.5, vjust = 0.5, family = "Times New Roman", size = size_t) + 
    
    scale_x_continuous(limits = c(resp_min_line, resp_max_line), expand = c(0, 0)) +
    scale_y_continuous(limits = c(-Y_PADDING, Y_MAX_LIMIT), expand = c(0, 0)) +
    labs(x = NULL, y = NULL) +
    theme_minimal() +
    theme(
      plot.title = element_blank(), axis.title.x = element_blank(), 
      axis.title.y = element_blank(), axis.text.x = element_blank(), 
      axis.text.y = element_blank(), plot.caption = element_blank(), 
      panel.border = element_rect(colour = "black", fill=NA, linewidth=0.5), 
      panel.grid.major = element_blank(), panel.grid.minor = element_blank(), 
      plot.margin = margin(5, 5, 5, 5, "pt") 
    )
}


# === GỌI HÀM VÀ GỘP BIỂU ĐỒ ===

plot_A <- plot_factor("A", "Distance e (mm)", e_opt, e_min, e_max)
plot_B <- plot_factor("B", "Corner radius R (mm)", R_opt, R_min, R_max)
plot_C <- plot_factor("C", "Friction coefficient μ", mu_opt, mu_min, mu_max)
plot_F <- plot_response("Force F (ton)", F_opt, F_min, F_max, color_opt="blue")
plot_Ci <- plot_response("Ci coefficient", Ci_opt, Ci_min, Ci_max, color_opt="blue")


# 6. TẠO BIỂU ĐỒ TRỐNG VÀ THÊM NHÃN DESIRABILITY VÀO BÊN TRONG BOX
plot_empty_with_desirability <- ggplot() + 
  theme_void() + 
  #theme(panel.border = element_rect(colour = "black", fill=NA, linewidth=0.5),
        #plot.margin = margin(5, 5, 5, 5, "pt")) +
  
  # Font và Size cho nhãn Desirability (Chính giữa Box)
  annotate("text", 
           x = 0.5, y = 0.5, 
           label = paste0("Desirability = ", format(D_opt, digits=3), 
                          "\nSolution 1 out of 57"), 
           hjust = 0.5, vjust = 0.5, 
           family = "Times New Roman", size = SIZE_TEXT,
           lineheight = 1)    #Khi export 16x12 600dpi thì chỉnh cái này

# TẠO KHUNG CHUNG VÀ GỘP BIỂU ĐỒ (ggarrange)
solution_plot <- ggpubr::ggarrange(
  plot_A, plot_B,
  plot_C, plot_F,
  plot_Ci, plot_empty_with_desirability, 
  ncol = 2, nrow = 3, 
  align = "hv",
  widths = c(1, 1), 
  heights = c(1, 1, 1),
  common.legend = FALSE
)


# In hoặc lưu biểu đồ với độ rộng yêu cầu (ví dụ: 16cm)
print(solution_plot)

#png("solution2_plot.png", width = 16, height = 12, units = "cm", res = 600)
#plot(solution_plot, main = "My Base R Plot")
#dev.off()

# Nếu cần in ra code hoàn chỉnh cho môi trường R:
# cat(sprintf("Độ rộng mong muốn là 16. Sử dụng ggsave:\nggsave(\"solution_plot.png\", final_plot, width = 16, height = 15, units = \"cm\")\n"))