# install.packages(c("drc", "ggplot2", "dplyr"))
library(drc)
## Loading required package: MASS
## 
## 'drc' has been loaded.
## Please cite R and 'drc' if used for a publication,
## for references type 'citation()' and 'citation('drc')'.
## 
## Attaching package: 'drc'
## The following objects are masked from 'package:stats':
## 
##     gaussian, getInitial
library(ggplot2)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:MASS':
## 
##     select
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
# 1. Concentration series and example data
conc_vec <- c(0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30, 60)

# Agonist: response goes up with concentration
agonist_df <- data.frame(
  assay_type = "Agonist: upward curve",
  conc_uM = rep(conc_vec, each = 3),
  response = c(2,4,3, 5,4,6, 8,7,9, 12,15,13, 20,22,19, 35,38,36,
               55,58,52, 78,81,76, 92,95,90, 98,101,96, 99,102,97)
)

# Antagonist: response goes down with concentration
antagonist_df <- data.frame(
  assay_type = "Antagonist: downward curve",
  conc_uM = rep(conc_vec, each = 3),
  response = c(100,98,101, 96,97,95, 94,92,93, 88,86,87, 76,73,75, 58,55,57,
               38,35,36, 20,18,19, 9,8,10, 4,3,5, 2,1,3)
)

all_df <- bind_rows(agonist_df, antagonist_df)
# 2. Fit a four-parameter Hill curve (LL.4)
#    b = Hill slope, c = bottom, d = top, e = EC50/IC50
fit_hill_curve <- function(dat, endpoint_name = "EC50") {
  dat <- filter(dat, !is.na(conc_uM), !is.na(response), conc_uM > 0)
  
  fit <- drm(response ~ conc_uM, data = dat,
             fct = LL.4(names = c("b", "c", "d", endpoint_name)))
  co <- coef(fit)
  
  # R-squared
  pred <- predict(fit, newdata = dat)
  r2 <- 1 - sum((dat$response - pred)^2) / sum((dat$response - mean(dat$response))^2)
  
  # Smooth curve for plotting
  pred_df <- data.frame(
    conc_uM = 10^seq(log10(min(dat$conc_uM)), log10(max(dat$conc_uM)), length.out = 300)
  )
  pred_df$response <- predict(fit, newdata = pred_df)
  
  list(
    pred_df      = pred_df,
    hill_signed  = unname(co[1]),   # b (upward often negative, downward often positive)
    hill_abs     = abs(unname(co[1])),
    endpoint_val = unname(co[4]),   # EC50 / IC50
    r_squared    = r2
  )
}

agonist_fit    <- fit_hill_curve(agonist_df,    "EC50")
antagonist_fit <- fit_hill_curve(antagonist_df, "IC50")
# 3. Fitted curves for plotting
pred_all <- bind_rows(
  mutate(agonist_fit$pred_df,    assay_type = "Agonist: upward curve"),
  mutate(antagonist_fit$pred_df, assay_type = "Antagonist: downward curve")
)
# 4. Annotation table: one column per metric + combined label column
annotation_df <- data.frame(
  assay_type    = c("Agonist: upward curve", "Antagonist: downward curve"),
  endpoint_name = c("EC50", "IC50"),
  endpoint_val  = c(agonist_fit$endpoint_val, antagonist_fit$endpoint_val),
  hill_signed   = c(agonist_fit$hill_signed,  antagonist_fit$hill_signed),
  hill_abs      = c(agonist_fit$hill_abs,     antagonist_fit$hill_abs),
  r_squared     = c(agonist_fit$r_squared,    antagonist_fit$r_squared),
  x = 0.0015,
  y = 95
)

# Build combined label from the split columns
annotation_df$label <- sprintf(
  "%s = %.2f uM\nHill slope = %.2f\n|Hill slope| = %.2f\nR2 = %.2f",
  annotation_df$endpoint_name, annotation_df$endpoint_val,
  annotation_df$hill_signed,   annotation_df$hill_abs,
  annotation_df$r_squared
)

print(annotation_df)
##                   assay_type endpoint_name endpoint_val hill_signed  hill_abs
## 1      Agonist: upward curve          EC50    0.8359492  -0.7552557 0.7552557
## 2 Antagonist: downward curve          IC50    0.4595101   0.7136681 0.7136681
##   r_squared      x  y
## 1 0.9968642 0.0015 95
## 2 0.9990373 0.0015 95
##                                                                label
## 1 EC50 = 0.84 uM\nHill slope = -0.76\n|Hill slope| = 0.76\nR2 = 1.00
## 2  IC50 = 0.46 uM\nHill slope = 0.71\n|Hill slope| = 0.71\nR2 = 1.00
write.csv(annotation_df, "annotation_df.csv", row.names = FALSE)
# 5. Plot data points + fitted curves
p <- ggplot() +
  geom_point(data = all_df, aes(conc_uM, response), size = 2, alpha = 0.7) +
  geom_line(data = pred_all, aes(conc_uM, response), linewidth = 1) +
  geom_label(data = annotation_df, aes(x, y, label = label),
             hjust = 0, vjust = 1, size = 3.5) +
  scale_x_log10() +
  facet_wrap(~ assay_type) +
  labs(x = "Concentration (uM, log scale)", y = "Response (%)",
       title = "Four-parameter Hill curve fitting") +
  theme_bw()

print(p)

# ggsave("Hill_slope_example.png", p, width = 8, height = 4, dpi = 300)