# Install required packages
packages <- c("tidyverse", "drc", "broom", "ggpubr")
installed <- packages %in% rownames(installed.packages())
if (any(!installed)) install.packages(packages[!installed])

library(tidyverse)
library(drc)
library(broom)
library(ggpubr)

IC50 DATA

# Create dataframe from provided IC50 data
data_raw <- tribble(
  ~Concentration, ~Rep1, ~Rep2, ~Rep3, ~Rep4, ~Rep5,
  0,    94.99, 100, 95.87, NA, NA,
  0.5,  93.3, 91.28, 73.1, NA, 98.53,
  1,    74.95, 75.96, 77.31, 64.9, NA,
  1.5,  65.1, 56.42, 55.24, 51.54, NA,
  2,    23.8, 39.8, 26.74, NA, 19.2,
  2.5,  15.4, 14.7, 26.3, 17.8, NA,
  3,    8.7, 8.8, 7.2, 6.54, NA
)

data_summary <- data_raw %>%
  pivot_longer(-Concentration, names_to = "Replicate", values_to = "Response") %>%
  group_by(Concentration) %>%
  summarise(Mean = mean(Response, na.rm = TRUE), SD = sd(Response, na.rm = TRUE))
# Fit 4-parameter logistic model for IC50
model_ic50 <- drm(Mean ~ Concentration, data = data_summary, fct = LL.4(names = c("Slope", "Lower", "Upper", "IC50")))
ic50_est <- ED(model_ic50, 50, interval = "delta")
## 
## Estimated effective doses
## 
##        Estimate Std. Error   Lower   Upper
## e:1:50  1.84087    0.37576 0.64504 3.03671
# Extract IC50 and CI
ic50_value <- round(ic50_est[1,1], 3)
ic50_lower <- round(ic50_est[1,2], 3)
ic50_upper <- round(ic50_est[1,3], 3)

# Prepare predictions for plotting
new_data_ic50 <- data.frame(Concentration = seq(min(data_summary$Concentration), max(data_summary$Concentration), length.out = 300))
pred_ic50 <- cbind(new_data_ic50, predict(model_ic50, newdata = new_data_ic50, interval = "confidence"))
ggplot() +
  geom_ribbon(data = pred_ic50, aes(x = Concentration, ymin = Lower, ymax = Upper), fill = "gray80", alpha = 0.5) +
  geom_line(data = pred_ic50, aes(x = Concentration, y = Prediction), color = "firebrick", linewidth = 1.2) +
  geom_point(data = data_summary, aes(x = Concentration, y = Mean), size = 3, color = "navyblue") +
  geom_errorbar(data = data_summary, aes(x = Concentration, ymin = Mean - SD, ymax = Mean + SD), width = 0.05, color = "navyblue") +
  geom_vline(xintercept = ic50_value, linetype = "dashed", color = "black", linewidth = 0.7) +
  annotate("text", x = ic50_value, y = max(data_summary$Mean)*0.9,
           label = paste0("IC50 = ", ic50_value, " (95% CI: ", ic50_lower, "–", ic50_upper, ")"),
           size = 4, hjust = -0.1, color = "black", fontface = "italic") +
  scale_x_continuous(trans = "log10", breaks = scales::trans_breaks("log10", function(x) 10^x)) +
  scale_y_continuous(limits = c(0, 110)) +
  labs(title = expression(bold("Dose–Response Curve with 95% Confidence Band")),
       subtitle = expression(italic("Four-parameter logistic model fit (IC50)")),
       x = "Concentration (log scale)",
       y = "Response (%)") +
  theme_classic(base_size = 14) +
  theme(plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
        plot.subtitle = element_text(size = 12, hjust = 0.5, color = "gray30"),
        axis.title = element_text(face = "bold"),
        panel.grid.major = element_line(color = "gray90", linetype = "dotted"))
## Warning in scale_x_continuous(trans = "log10", breaks = scales::trans_breaks("log10", : log-10 transformation introduced infinite values.
## log-10 transformation introduced infinite values.
## log-10 transformation introduced infinite values.
## log-10 transformation introduced infinite values.

CC50 DATA

# Data for cytotoxicity (CC50)
cc50_data <- tribble(
  ~Concentration, ~Rep1, ~Rep2, ~Rep3,
  1, 99.1, 92.8, 94.2,
  1.5, 80.1, 88.7, 93.8,
  2, 95, 71, 79.3,
  2.5, 63.1, 69.7, 78.4,
  5, 64.3, 63.1, 57.3,
  10, 52.3, 49.8, 56.9,
  20, 45.2, 49, 46.9
)

cc50_summary <- cc50_data %>%
  pivot_longer(-Concentration, names_to = "Replicate", values_to = "Response") %>%
  group_by(Concentration) %>%
  summarise(Mean = mean(Response, na.rm = TRUE), SD = sd(Response, na.rm = TRUE))
# Fit model for CC50
model_cc50 <- drm(Mean ~ Concentration, data = cc50_summary, fct = LL.4(names = c("Slope", "Lower", "Upper", "CC50")))
cc50_est <- ED(model_cc50, 50, interval = "delta")
## 
## Estimated effective doses
## 
##        Estimate Std. Error   Lower   Upper
## e:1:50   1.5434     1.4290 -3.0043  6.0912
cc50_value <- round(cc50_est[1,1], 3)
cc50_lower <- round(cc50_est[1,2], 3)
cc50_upper <- round(cc50_est[1,3], 3)

# Predictions for CC50
new_data_cc50 <- data.frame(Concentration = seq(min(cc50_summary$Concentration), max(cc50_summary$Concentration), length.out = 300))
pred_cc50 <- cbind(new_data_cc50, predict(model_cc50, newdata = new_data_cc50, interval = "confidence"))
ggplot() +
  geom_ribbon(data = pred_cc50, aes(x = Concentration, ymin = Lower, ymax = Upper), fill = "gray85", alpha = 0.4) +
  geom_line(data = pred_cc50, aes(x = Concentration, y = Prediction), color = "darkgreen", linewidth = 1.2) +
  geom_point(data = cc50_summary, aes(x = Concentration, y = Mean), size = 3, color = "steelblue") +
  geom_errorbar(data = cc50_summary, aes(x = Concentration, ymin = Mean - SD, ymax = Mean + SD), width = 0.05, color = "steelblue") +
  geom_vline(xintercept = cc50_value, linetype = "dashed", color = "black", linewidth = 0.7) +
  annotate("text", x = cc50_value, y = max(cc50_summary$Mean)*0.9,
           label = paste0("CC50 = ", cc50_value, " (95% CI: ", cc50_lower, "–", cc50_upper, ")"),
           size = 4, hjust = -0.1, color = "black", fontface = "italic") +
  scale_x_continuous(trans = "log10", breaks = scales::trans_breaks("log10", function(x) 10^x)) +
  scale_y_continuous(limits = c(0, 110)) +
  labs(title = expression(bold("Cytotoxicity Curve with 95% Confidence Band")),
       subtitle = expression(italic("Four-parameter logistic model fit (CC50)")),
       x = "Concentration (log scale)",
       y = "Cell Viability (%)") +
  theme_classic(base_size = 14) +
  theme(plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
        plot.subtitle = element_text(size = 12, hjust = 0.5, color = "gray30"),
        axis.title = element_text(face = "bold"),
        panel.grid.major = element_line(color = "gray90", linetype = "dotted"))

Aesthetic academic-style IC50 plot
# Assuming 'pred_ic50', 'data_summary', and IC50 estimates already exist

ggplot() +
  geom_ribbon(data = pred_ic50, aes(x = Concentration, ymin = Lower, ymax = Upper),
              fill = "gray85", alpha = 0.4) +
  geom_line(data = pred_ic50, aes(x = Concentration, y = Prediction),
            color = "darkred", linewidth = 1.2) +
  geom_point(data = data_summary, aes(x = Concentration, y = Mean),
             size = 3, color = "royalblue") +
  geom_errorbar(data = data_summary, aes(x = Concentration, ymin = Mean - SD, ymax = Mean + SD),
                width = 0.05, color = "royalblue") +
  geom_vline(xintercept = ic50_value, linetype = "dashed", color = "black", linewidth = 0.7) +
  annotate("text", x = ic50_value, y = max(data_summary$Mean)*0.9,
           label = paste0("IC50 = ", ic50_value, " (95% CI: ", ic50_lower, "–", ic50_upper, ")"),
           size = 4, hjust = -0.1, color = "black", fontface = "italic") +
  scale_x_continuous(trans = "log10", breaks = scales::trans_breaks("log10", function(x) 10^x)) +
  scale_y_continuous(limits = c(0, 110)) +
  labs(title = expression(bold("Inhibition Curve with 95% Confidence Band")),
       subtitle = expression(italic("Four-parameter logistic model fit (IC50)")),
       x = "Concentration (log scale)",
       y = "Response (%)") +
  theme_classic(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
    plot.subtitle = element_text(size = 12, hjust = 0.5, color = "gray30"),
    axis.title = element_text(face = "bold"),
    panel.grid.major = element_line(color = "gray90", linetype = "dotted")
  )
# Publication-quality IC50/CC50 plot for Fisetin
# Assuming variables: pred_ic50, pred_cc50, data_summary, ic50_value, ic50_lower, ic50_upper, cc50_value, cc50_lower, cc50_upper

# Round to 2 decimals
ic50_value <- round(ic50_value, 2)
ic50_lower <- round(ic50_lower, 2)
ic50_upper <- round(ic50_upper, 2)
cc50_value <- round(cc50_value, 2)
cc50_lower <- round(cc50_lower, 2)
cc50_upper <- round(cc50_upper, 2)

# Generate the plot
ggplot() +
  geom_ribbon(data = pred_ic50, aes(x = Concentration, ymin = Lower, ymax = Upper),
              fill = "gray85", alpha = 0.4) +
  geom_line(data = pred_ic50, aes(x = Concentration, y = Prediction),
            color = "darkred", linewidth = 1.3) +
  geom_point(data = data_summary, aes(x = Concentration, y = Mean),
             size = 3, color = "royalblue") +
  geom_errorbar(data = data_summary, aes(x = Concentration, ymin = Mean - SD, ymax = Mean + SD),
                width = 0.05, color = "royalblue") +
  geom_vline(xintercept = ic50_value, linetype = "dashed", color = "black", linewidth = 0.8) +
  annotate("text", x = ic50_value, y = max(data_summary$Mean)*0.85,
           label = paste0("IC50 = ", ic50_value, " (95% CI: ", ic50_lower, "–", ic50_upper, ")"),
           size = 4, hjust = -0.1, color = "black", fontface = "italic") +
  annotate("text", x = ic50_value, y = max(data_summary$Mean)*0.75,
           label = paste0("CC50 = ", cc50_value, " (95% CI: ", cc50_lower, "–", cc50_upper, ")"),
           size = 4, hjust = -0.1, color = "gray20", fontface = "italic") +
  scale_x_continuous(trans = "log10", breaks = c(0.1, 0.5, 1, 2, 3), limits = c(0.1, 3.2)) +
  scale_y_continuous(limits = c(0, 110)) +
  labs(title = expression(bold("Fisetin Inhibition Curve")),
       subtitle = expression(italic("Four-parameter logistic model fit with 95% CI")),
       x = "Concentration (log scale)",
       y = "Response (%)") +
  theme_classic(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
    plot.subtitle = element_text(size = 12, hjust = 0.5, color = "gray30"),
    axis.title = element_text(face = "bold"),
    axis.text.x = element_text(size = 12),
    axis.text.y = element_text(size = 12),
    panel.grid.major = element_line(color = "gray90", linetype = "dotted")
  )

# Refined Fisetin IC50/CC50 plot with Selective Index (SI)
# Assumes: ic50_value, ic50_lower, ic50_upper, cc50_value, cc50_lower, cc50_upper, pred_ic50, data_summary exist

# Compute Selective Index (SI = CC50 / IC50)
SI_value <- round(ic50_value/cc50_value)

# Generate the plot with repositioned annotation and added SI
ggplot() +
  geom_ribbon(data = pred_ic50, aes(x = Concentration, ymin = Lower, ymax = Upper),
              fill = "gray85", alpha = 0.5) +
  geom_line(data = pred_ic50, aes(x = Concentration, y = Prediction),
            color = "darkred", linewidth = 0.6) +
  geom_point(data = data_summary, aes(x = Concentration, y = Mean),
             size = 3, color = "royalblue") +
  geom_errorbar(data = data_summary, aes(x = Concentration, ymin = Mean - SD, ymax = Mean + SD),
                width = 0.05, color = "royalblue") +
  geom_vline(xintercept = ic50_value, linetype = "dashed", color = "black", linewidth = 0.8) +
  annotate("text", x = 0.15, y = 30,
           label = paste0("IC50 = ", ic50_value, " (95% CI: ", ic50_lower, "–", ic50_upper, ")"),
           size = 4, hjust = 0, color = "black", fontface = "italic") +
  annotate("text", x = 0.15, y = 20,
           label = paste0("CC50 = ", cc50_value, " (95% CI: ", cc50_lower, "–", cc50_upper, ")"),
           size = 4, hjust = 0, color = "gray20", fontface = "italic") +
  annotate("text", x = 0.15, y = 10,
           label = paste0("SI = ", SI_value),
           size = 4, hjust = 0.1, color = "darkgreen", fontface = "bold") +
  scale_x_continuous(trans = "log10", breaks = c(0.1, 0.5, 1, 2, 3), limits = c(0.1, 3.2)) +
  scale_y_continuous(limits = c(0, 110)) +
  labs(title = expression(bold("Fisetin Inhibition Curve")),
       subtitle = expression(italic("Four-parameter logistic model fit with 95% CI")),
       x = "Concentration (log scale)",
       y = "Response (%)") +
  theme_classic(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
    plot.subtitle = element_text(size = 12, hjust = 0.5, color = "gray30"),
    axis.title = element_text(face = "bold"),
    axis.text.x = element_text(size = 12),
    axis.text.y = element_text(size = 12),
    panel.grid.major = element_line(color = "gray90", linetype = "dotted")
  )

# Adjusted combined facet figure: CC50 (cytotoxicity) and IC50 (inhibition) for Fisetin
# CC50 x-axis now starts from 1.0 to match IC50 visual style

library(ggpubr)

# ---- CC50 plot ----
plot_cc50 <- ggplot() +
  geom_ribbon(data = pred_cc50, aes(x = Concentration, ymin = Lower, ymax = Upper),
              fill = "gray85", alpha = 0.4) +
  geom_line(data = pred_cc50, aes(x = Concentration, y = Prediction), color = "darkgreen", linewidth = 1.3) +
  geom_point(data = cc50_summary, aes(x = Concentration, y = Mean), size = 3, color = "steelblue") +
  geom_errorbar(data = cc50_summary, aes(x = Concentration, ymin = Mean - SD, ymax = Mean + SD),
                width = 0.05, color = "steelblue") +
  geom_vline(xintercept = cc50_value, linetype = "dashed", color = "black", linewidth = 0.8) +
  annotate("text", x = 3, y = 30,
           label = paste0("CC50 = ", cc50_value, " (95% CI: ", cc50_lower, "–", cc50_upper, ")"),
           size = 4, hjust = 0, color = "black", fontface = "italic") +
  labs(title = expression(bold("A. Fisetin Cytotoxicity (CC50)")),
       x = "Concentration (log scale)", y = "Cell Viability (%)") +
  scale_x_continuous(trans = "log10", breaks = c(1, 2, 3, 5, 10, 20), limits = c(1, 20)) +
  scale_y_continuous(limits = c(0, 110)) +
  theme_classic(base_size = 14) +
  theme(plot.title = element_text(face = "bold", size = 14, hjust = 0),
        axis.title = element_text(face = "bold"),
        panel.grid.major = element_line(color = "gray90", linetype = "dotted"))

# ---- IC50 plot ----
SI_value <- round(cc50_value / ic50_value, 2)

plot_ic50 <- ggplot() +
  geom_ribbon(data = pred_ic50, aes(x = Concentration, ymin = Lower, ymax = Upper),
              fill = "gray85", alpha = 0.4) +
  geom_line(data = pred_ic50, aes(x = Concentration, y = Prediction), color = "darkred", linewidth = 1.3) +
  geom_point(data = data_summary, aes(x = Concentration, y = Mean), size = 3, color = "royalblue") +
  geom_errorbar(data = data_summary, aes(x = Concentration, ymin = Mean - SD, ymax = Mean + SD),
                width = 0.05, color = "royalblue") +
  geom_vline(xintercept = ic50_value, linetype = "dashed", color = "black", linewidth = 0.8) +
  annotate("text", x = 0.1, y = 30,
           label = paste0("IC50 = ", ic50_value, " (95% CI: ", ic50_lower, "–", ic50_upper, ")"),
           size = 4, hjust = 0, color = "black", fontface = "italic") +
  annotate("text", x = 0.1, y = 20,
           label = paste0("CC50 = ", cc50_value, " (95% CI: ", cc50_lower, "–", cc50_upper, ")"),
           size = 4, hjust = 0, color = "gray20", fontface = "italic") +
  annotate("text", x = 0.1, y = 10,
           label = paste0("SI = ", SI_value),
           size = 4, hjust = 0, color = "darkgreen", fontface = "bold") +
  labs(title = expression(bold("B. Fisetin Antiviral Activity (IC50)")),
       x = "Concentration (log scale)", y = "Response (%)") +
  scale_x_continuous(trans = "log10", breaks = c(0.1, 0.5, 1, 2, 3), limits = c(-0.1, 3.2)) +
  scale_y_continuous(limits = c(0, 110)) +
  theme_classic(base_size = 14) +
  theme(plot.title = element_text(face = "bold", size = 14, hjust = 0),
        axis.title = element_text(face = "bold"),
        panel.grid.major = element_line(color = "gray90", linetype = "dotted"))

# ---- Combine in facet style ----
combined_plot <- ggarrange(plot_cc50, plot_ic50, ncol = 1, nrow = 2, labels = c("A", "B"),
                           common.legend = FALSE, align = "v")

combined_plot