library(gDRcore)
library(gDRtestData)
library(gDRutils)
library(SummarizedExperiment)
library(BumpyMatrix)
library(data.table)
The standard gDR pipeline fits dose-response curves using a fixed
4-parameter log-logistic model (fit_SE()). Sometimes you need something
different: an alternative curve model, custom synergy metrics, Bayesian
estimates, or bespoke pharmacology metrics for your assay.
apply_fit() and apply_fits() let you plug any R function
into the gDR SE/MAE pipeline without touching the pipeline internals.
Key properties:
"Metrics", "scores", "excess", …).fit_source
overwrites rather than duplicates.apply_fits() applies N fit functions in a single BumpyMatrix
traversal — efficient when you have several metrics to compute on the same
data.We use a small synthetic single-agent SE from gDRtestData.
mae <- gDRutils::get_synthetic_data("finalMAE_small.qs2")
sa_se <- mae[["single-agent"]]
sa_se
#> class: SummarizedExperiment
#> dim: 10 10
#> metadata(5): identifiers experiment_metadata Keys fit_parameters
#> .internal
#> assays(5): RawTreated Controls Normalized Averaged Metrics
#> rownames(10): G00002_drug_002_moa_A_72 G00003_drug_003_moa_A_72 ...
#> G00010_drug_010_moa_A_72 G00011_drug_011_moa_B_72
#> rowData names(4): Gnumber DrugName drug_moa Duration
#> colnames(10): CL00011_cellline_BA_tissue_x_26
#> CL00012_cellline_CA_tissue_x_30 ... CL00019_cellline_JB_tissue_z_58
#> CL00020_cellline_KB_tissue_z_62
#> colData names(4): clid CellLineName Tissue ReferenceDivisionTime
The Averaged assay is the input to custom fit functions. Each cell of the
BumpyMatrix contains one data.table per (drug × cell line) pair:
avg_cell <- BumpyMatrix::unsplitAsDataFrame(
assay(sa_se, "Averaged"),
row.field = "row", column.field = "column"
)
head(avg_cell[avg_cell$row == avg_cell$row[1] &
avg_cell$column == avg_cell$column[1], ])
#> DataFrame with 6 rows and 6 columns
#> row column normalization_type
#> <character> <character> <factor>
#> 1_RV G00002_drug_002_moa_.. CL00011_cellline_BA_.. RV
#> 1_GR G00002_drug_002_moa_.. CL00011_cellline_BA_.. GR
#> 2_RV G00002_drug_002_moa_.. CL00011_cellline_BA_.. RV
#> 2_GR G00002_drug_002_moa_.. CL00011_cellline_BA_.. GR
#> 3_RV G00002_drug_002_moa_.. CL00011_cellline_BA_.. RV
#> 3_GR G00002_drug_002_moa_.. CL00011_cellline_BA_.. GR
#> Concentration x x_std
#> <numeric> <numeric> <numeric>
#> 1_RV 0.00100000 0.924967 0.01066130
#> 1_GR 0.00100000 0.944433 0.00805874
#> 2_RV 0.00316228 0.739100 0.01484621
#> 2_GR 0.00316228 0.793100 0.01302152
#> 3_RV 0.01000000 0.435933 0.03071503
#> 3_GR 0.01000000 0.481333 0.03811841
Each cell has four columns:
| Column | Description |
|---|---|
normalization_type |
"GR" or "RV" |
Concentration |
drug concentration (µM) |
x |
averaged normalized response (GR value or relative viability) |
x_std |
standard deviation across replicates |
A fit function must satisfy this interface:
fit_fn(avg_dt) -> named list (or single-row data.frame / data.table)
avg_dt is a data.table containing the rows for one combination of
slicing column values (by default: one normalization_type) for one
(drug × cell line) cell.
The returned named list becomes one row in the output assay. Column names
are the names of the list elements. fit_source is stamped automatically
by the generic layer — do not include it in the return value.
# The simplest possible fit_fn: compute mean and SD of the response
summary_fn <- function(avg_dt) {
list(
x_mean = mean(avg_dt$x, na.rm = TRUE),
x_sd = sd(avg_dt$x, na.rm = TRUE),
n = NROW(avg_dt)
)
}
Apply the summary function to every (drug × cell line × normalization_type)
triplet and write results to a custom assay named "custom_summary".
sa_out <- apply_fit(
sa_se,
fit_fn = summary_fn,
data_type = "single-agent",
output_assay = "custom_summary",
fit_source = "demo"
)
assayNames(sa_out)
#> [1] "RawTreated" "Controls" "Normalized" "Averaged"
#> [5] "Metrics" "custom_summary"
summary_df <- BumpyMatrix::unsplitAsDataFrame(
assay(sa_out, "custom_summary"),
row.field = "row", column.field = "column"
)
head(summary_df)
#> DataFrame with 6 rows and 7 columns
#> row column x_mean x_sd n
#> <character> <character> <numeric> <numeric> <integer>
#> 1 G00002_drug_002_moa_.. CL00011_cellline_BA_.. 0.491452 0.221336 9
#> 2 G00002_drug_002_moa_.. CL00011_cellline_BA_.. 0.466411 0.214770 9
#> 3 G00003_drug_003_moa_.. CL00011_cellline_BA_.. 0.417704 0.273562 9
#> 4 G00003_drug_003_moa_.. CL00011_cellline_BA_.. 0.419170 0.256418 9
#> 5 G00004_drug_004_moa_.. CL00011_cellline_BA_.. 0.843222 0.107986 9
#> 6 G00004_drug_004_moa_.. CL00011_cellline_BA_.. 0.803893 0.133827 9
#> fit_source normalization_type
#> <character> <character>
#> 1 demo GR
#> 2 demo RV
#> 3 demo GR
#> 4 demo RV
#> 5 demo GR
#> 6 demo RV
One row per (drug × cell line × normalization_type) triplet. The native
"Metrics" assay is untouched — because we chose a custom assay name.
You can also write directly to "Metrics" — for example when replacing the
standard gDR Hill fit with your own model:
# SE straight from the pipeline — already has a native "Metrics" assay
# (fit_source = "gDR")
"Metrics" %in% assayNames(sa_se)
#> [1] TRUE
# Apply a custom fit to the same assay, coexisting alongside gDR rows
custom_hill <- apply_fit(
sa_se,
fit_fn = fit_drug_response_metrics,
data_type = "single-agent",
output_assay = "Metrics",
fit_source = "custom_hill" # distinct key keeps native "gDR" rows intact
)
metrics_df <- BumpyMatrix::unsplitAsDataFrame(
assay(custom_hill, "Metrics"),
row.field = "row", column.field = "column"
)
unique(metrics_df$fit_source) # both "gDR" and "custom_hill"
#> [1] "gDR" "custom_hill"
With merge = "merge" (default) the upsert key is fit_source + normalization_type, so native rows (fit_source = "gDR") are preserved.
Use merge = "replace" only if you intend to overwrite the whole assay.
Calling again with the same fit_source replaces those rows rather than
appending:
n_before <- NROW(BumpyMatrix::unsplitAsDataFrame(
assay(sa_out, "custom_summary"),
row.field = "row", column.field = "column"
))
# Call again — same fit_source, same data
sa_out2 <- apply_fit(
sa_out,
fit_fn = summary_fn,
data_type = "single-agent",
output_assay = "custom_summary",
fit_source = "demo"
)
n_after <- NROW(BumpyMatrix::unsplitAsDataFrame(
assay(sa_out2, "custom_summary"),
row.field = "row", column.field = "column"
))
stopifnot(n_before == n_after) # no duplicate rows
message("Row count before: ", n_before, " — after: ", n_after, " (no change)")
Different fit_source values live side by side in the same assay:
extra_fn <- function(avg_dt) list(x_max = max(avg_dt$x, na.rm = TRUE))
sa_two <- sa_out |>
apply_fit(extra_fn, "single-agent",
output_assay = "custom_summary",
fit_source = "extremes")
sources <- unique(BumpyMatrix::unsplitAsDataFrame(
assay(sa_two, "custom_summary"),
row.field = "row", column.field = "column"
)$fit_source)
message("fit_source values in assay: ", paste(sources, collapse = ", "))
fit_drug_response_metrics() is a reference single-agent fit function that
replicates the standard fit_SE() / logisticFit() output exactly.
| Property | Value |
|---|---|
| Model | 3-parameter log-logistic (drc::LL.3u, x_0 fixed at 1) |
| Equivalent to | fit_SE() / gDRutils::logisticFit() |
x_mean |
Predicted from fitted curve (matches logisticFit behaviour) |
fit_type value |
"DRC3pHillFitModelFixS0" or "DRCConstantFitResult" |
| Output columns | Full Metrics assay schema including p_value, rss, x_AOC_range, x_max, x_sd_avg |
fit_drug_response_metrics() is numerically identical to fit_SE().
The fit is deterministic — drc::drm does not use random number generation,
so set.seed() has no effect. Differences between the two are purely
algorithmic:
drc::LL.3u model, x_0 = 1, identical priors and concentration boundsx_mean: predicted from the fitted curve over the observed concentration rangepcutoff = 0.05 fallback: when the F-test gives p_value ≥ pcutoff, the
result is replaced by a flat DRCConstantFitResult (same as logisticFit())n_point_cutoff = 4: fewer unique concentrations → constant fit without
attempting the sigmoidal model"Metrics" assayThese parameters can be overridden if your data requires it:
# Loosen the significance threshold or force the sigmoidal fit
fit_drug_response_metrics(avg_dt, pcutoff = 0.1)
fit_drug_response_metrics(avg_dt, force_fit = TRUE)
# Different range for x_AOC_range computation
fit_drug_response_metrics(avg_dt, range_conc = c(1e-3, 10))
hill_out <- apply_fit(
sa_se,
fit_fn = fit_drug_response_metrics,
data_type = "single-agent",
output_assay = "custom_hill",
fit_source = "hill_ref"
)
hill_df <- BumpyMatrix::unsplitAsDataFrame(
assay(hill_out, "custom_hill"),
row.field = "row", column.field = "column"
)
head(hill_df[, c("row", "column", "normalization_type",
"ec50", "xc50", "h", "r2", "fit_type")])
#> DataFrame with 6 rows and 8 columns
#> row column normalization_type ec50
#> <character> <character> <character> <numeric>
#> 1 G00002_drug_002_moa_.. CL00011_cellline_BA_.. GR 0.00451256
#> 2 G00002_drug_002_moa_.. CL00011_cellline_BA_.. RV 0.00379589
#> 3 G00003_drug_003_moa_.. CL00011_cellline_BA_.. GR 0.00471408
#> 4 G00003_drug_003_moa_.. CL00011_cellline_BA_.. RV 0.00396299
#> 5 G00004_drug_004_moa_.. CL00011_cellline_BA_.. GR 0.01715280
#> 6 G00004_drug_004_moa_.. CL00011_cellline_BA_.. RV 0.01654638
#> xc50 h r2 fit_type
#> <numeric> <numeric> <numeric> <character>
#> 1 0.00895622 1.91190 0.988441 DRC3pHillFitModelFixS0
#> 2 0.00725317 1.82703 0.992470 DRC3pHillFitModelFixS0
#> 3 0.00659147 2.27009 0.990529 DRC3pHillFitModelFixS0
#> 4 0.00565558 2.34960 0.995851 DRC3pHillFitModelFixS0
#> 5 Inf 3.14371 0.991428 DRC3pHillFitModelFixS0
#> 6 Inf 3.15994 0.991887 DRC3pHillFitModelFixS0
ec50 is the raw model parameter (concentration at half-maximal effect);
xc50 is the capped version (capped at capping_fold × max(Concentration))
as reported in the native "Metrics" assay.
An optional summary_fn is called once per (drug × cell line) cell on
all rows produced by fit_fn for that cell (one row per normalization type).
It is the right place for metrics that aggregate across normalization types —
for example, whether the result is synergistic across both GR and RV.
# Aggregate: mean xc50 and flag whether both norm types fitted successfully
hill_summary_fn <- function(fit_dt) {
list(
mean_xc50 = mean(fit_dt$xc50, na.rm = TRUE),
mean_r2 = mean(fit_dt$r2, na.rm = TRUE),
all_converged = all(fit_dt$fit_type == "DRC3pHillFitModelFixS0", na.rm = TRUE)
)
}
hill_with_summary <- apply_fit(
sa_se,
fit_fn = fit_drug_response_metrics,
data_type = "single-agent",
output_assay = "custom_hill",
summary_fn = hill_summary_fn,
summary_assay = "custom_hill_summary",
fit_source = "hill_ref"
)
assayNames(hill_with_summary)
#> [1] "RawTreated" "Controls" "Normalized"
#> [4] "Averaged" "Metrics" "custom_hill"
#> [7] "custom_hill_summary"
sumdf <- BumpyMatrix::unsplitAsDataFrame(
assay(hill_with_summary, "custom_hill_summary"),
row.field = "row", column.field = "column"
)
head(sumdf[, c("row", "column", "mean_xc50", "mean_r2", "all_converged")])
#> DataFrame with 6 rows and 5 columns
#> row column mean_xc50 mean_r2
#> <character> <character> <numeric> <numeric>
#> 1 G00002_drug_002_moa_.. CL00011_cellline_BA_.. 0.00810470 0.990455
#> 2 G00003_drug_003_moa_.. CL00011_cellline_BA_.. 0.00612352 0.993190
#> 3 G00004_drug_004_moa_.. CL00011_cellline_BA_.. Inf 0.991658
#> 4 G00005_drug_005_moa_.. CL00011_cellline_BA_.. Inf 0.977308
#> 5 G00006_drug_006_moa_.. CL00011_cellline_BA_.. Inf 0.997368
#> 6 G00007_drug_007_moa_.. CL00011_cellline_BA_.. Inf 0.850211
#> all_converged
#> <logical>
#> 1 TRUE
#> 2 TRUE
#> 3 TRUE
#> 4 TRUE
#> 5 TRUE
#> 6 TRUE
One row per (drug × cell line) — regardless of how many normalization types were fitted.
Before describing the new extension API, it helps to understand what the
standard fit_SE.combinations() function does. It is a single loop over
each (drug-combo × cell-line) pair that executes five sequential steps,
each writing to a separate assay:
| Step | Key functions | Output assay | Description |
|---|---|---|---|
| 1 | fit_combo_cotreatments(), fit_combo_codilutions() |
Metrics |
Fit SA dose-response curves at each co-treatment concentration; produces ec50, h, x_inf, x_0 per SA series |
| 2 | map_ids_to_fits() |
(internal) | Predict smooth single-agent responses at every combo concentration using the SA fits from step 1; average col/row/codilution predictions |
| 3 | calculate_HSA(), calculate_Bliss(), calculate_excess() |
excess |
Compute expected response (HSA = min of SAs; Bliss = product/GR formula); compute per-point excess = expected − observed |
| 4 | calculate_Loewe() |
isobolograms, all_iso_points |
Compute combination index (CI) via isobologram analysis; CI < 1 = synergy |
| 5 | calculate_score() |
scores |
Reduce per-point excess to a scalar: mean of top-10-percentile values → bliss_score, hsa_score, CIScore_50, CIScore_80 |
The key insight: step 2 (smooth) depends on step 1 (SA fits), and steps 3–5 all depend on step 2. The boundaries between steps are clean, which means they can be extracted as independent public functions.
Roadmap (GDR-3486): a future refactoring will expose each step as a
standalone apply_combo_*() function, making fit_SE.combinations() a
thin wrapper over them. apply_combo_scores() (step 5) is already
available as part of GDR-3352.
Two approaches are available, depending on whether you have SA fits or only raw averaged data.
apply_combo_scores() is a high-level function that reproduces the Bliss and
HSA scoring logic of fit_SE.combinations() exactly, using fitted SA curves
from the Metrics assay to generate smooth single-agent predictions.
| Property | Value |
|---|---|
| Requires | Averaged + Metrics assay (with dilution_drug, ec50, h, …) |
| Equivalent to | fit_SE.combinations() Bliss and HSA scores |
| Accuracy | cor > 0.998 with fit_SE.combinations on real data |
| Use when | Replacing or extending fit_SE.combinations for standard data |
# Use the small synthetic combo dataset which has both Averaged and Metrics
combo_mae <- gDRutils::get_synthetic_data("finalMAE_combo_matrix_small")
combo_name <- gDRutils::get_supported_experiments("combo")
combo_se_full <- combo_mae[[combo_name]]
# combo_se_full already has Metrics from fit_SE.combinations
combo_scored <- apply_combo_scores(combo_se_full)
assayNames(combo_scored)
#> [1] "RawTreated" "Controls" "Normalized" "Averaged"
#> [5] "excess" "all_iso_points" "isobolograms" "scores"
#> [9] "Metrics"
scores_df <- BumpyMatrix::unsplitAsDataFrame(
assay(combo_scored, "scores"),
row.field = "row", column.field = "column"
)
scores_df[, c("row", "column", "normalization_type", "bliss_score", "hsa_score")]
#> DataFrame with 24 rows and 5 columns
#> row column normalization_type
#> <character> <character> <character>
#> 1 G00004_drug_004_moa_.. CL00016_cellline_GB_.. GR
#> 2 G00004_drug_004_moa_.. CL00016_cellline_GB_.. RV
#> 3 G00004_drug_004_moa_.. CL00016_cellline_GB_.. GR
#> 4 G00004_drug_004_moa_.. CL00016_cellline_GB_.. RV
#> 5 G00005_drug_005_moa_.. CL00016_cellline_GB_.. GR
#> ... ... ... ...
#> 20 G00005_drug_005_moa_.. CL00017_cellline_HB_.. RV
#> 21 G00006_drug_006_moa_.. CL00017_cellline_HB_.. GR
#> 22 G00006_drug_006_moa_.. CL00017_cellline_HB_.. RV
#> 23 G00006_drug_006_moa_.. CL00017_cellline_HB_.. GR
#> 24 G00006_drug_006_moa_.. CL00017_cellline_HB_.. RV
#> bliss_score hsa_score
#> <numeric> <numeric>
#> 1 0.008339057 0.008339057
#> 2 0.002358668 0.002358668
#> 3 0.000674575 0.000674575
#> 4 0.000298478 0.000298478
#> 5 0.009101157 0.009101157
#> ... ... ...
#> 20 0.000151856 0.000151856
#> 21 0.031880296 0.031880296
#> 22 0.012769276 0.012769276
#> 23 0.024087057 0.024087057
#> 24 0.005341883 0.005341883
bliss_score > 0 and hsa_score > 0 indicate synergy.
bliss_fit_fn() and hss_fit_fn() are lower-level fit functions for
apply_fit() that compute synergy scores directly from the raw Averaged data,
without requiring prior SA curve fits.
| Property | Value |
|---|---|
| Requires | Averaged assay only |
| SA response | Raw single-agent edge points (no curve smoothing) |
| Use when | Prototyping, custom models, or when SA fits are unavailable |
# Build a minimal synthetic combination SE (Averaged only, no Metrics needed)
combo_dt <- data.table::CJ(
row = c("DrugA", "DrugB"),
column = "CellLine1",
normalization_type = c("GR", "RV"),
Concentration = c(0, 0.1, 1.0),
Concentration_2 = c(0, 0.1, 1.0)
)
set.seed(42L)
combo_dt[, x := pmax(0.05,
1 - 0.3 * Concentration / (Concentration + 0.5) -
0.2 * Concentration_2 / (Concentration_2 + 0.5) +
rnorm(.N, 0, 0.03))]
data_cols <- setdiff(names(combo_dt), c("row", "column"))
combo_bumpy <- BumpyMatrix::splitAsBumpyMatrix(
combo_dt[, data_cols, with = FALSE],
row = combo_dt$row, col = combo_dt$column
)
combo_se <- SummarizedExperiment(assays = list(Averaged = combo_bumpy))
bliss_out <- apply_fit(
combo_se,
fit_fn = bliss_fit_fn,
data_type = "combination",
output_assay = "custom_bliss",
fit_source = "bliss"
)
bliss_df <- BumpyMatrix::unsplitAsDataFrame(
assay(bliss_out, "custom_bliss"),
row.field = "row", column.field = "column"
)
bliss_df[, c("row", "column", "normalization_type",
"bliss_score", "bliss_excess_mean", "n_combo_points")]
#> DataFrame with 4 rows and 6 columns
#> row column normalization_type bliss_score bliss_excess_mean
#> <character> <character> <character> <numeric> <numeric>
#> 1 DrugA CellLine1 GR 0.0404576 0.02194040
#> 2 DrugA CellLine1 RV 0.1790833 0.07174050
#> 3 DrugB CellLine1 GR 0.1083000 0.02410753
#> 4 DrugB CellLine1 RV 0.0473357 0.00199227
#> n_combo_points
#> <integer>
#> 1 4
#> 2 4
#> 3 4
#> 4 4
hss_out <- apply_fit(
combo_se,
fit_fn = hss_fit_fn,
data_type = "combination",
output_assay = "custom_hss",
fit_source = "hss"
)
hss_df <- BumpyMatrix::unsplitAsDataFrame(
assay(hss_out, "custom_hss"),
row.field = "row", column.field = "column"
)
hss_df[, c("row", "column", "normalization_type",
"hss_score", "hss_excess_mean")]
#> DataFrame with 4 rows and 5 columns
#> row column normalization_type hss_score hss_excess_mean
#> <character> <character> <character> <numeric> <numeric>
#> 1 DrugA CellLine1 GR 0.118126 0.0711634
#> 2 DrugA CellLine1 RV 0.232106 0.0971858
#> 3 DrugB CellLine1 GR 0.197907 0.0726057
#> 4 DrugB CellLine1 RV 0.166576 0.0480229
When several fit functions operate on the same input assay, use
apply_fits() to traverse each BumpyMatrix cell once and apply
all functions in that single pass.
combo_multi <- apply_fits(
combo_se,
fit_fns = list(
custom_bliss = bliss_fit_fn,
custom_hss = hss_fit_fn
),
data_type = "combination",
fit_source = "synergy_panel"
)
assayNames(combo_multi)
#> [1] "Averaged" "custom_bliss" "custom_hss"
Both assays are written in one traversal — equivalent to chaining two
apply_fit() calls but without the overhead of a second unsplit +
iteration.
The functions are pipe-friendly — each call returns the updated SE:
result_se <- combo_se |>
apply_fit(bliss_fit_fn, "combination",
output_assay = "custom_bliss",
fit_source = "bliss") |>
apply_fit(hss_fit_fn, "combination",
output_assay = "custom_hss",
fit_source = "hss") |>
apply_fit(
function(dt) list(n_obs = NROW(dt)),
"combination",
output_assay = "combo_diagnostics",
fit_source = "qc"
)
assayNames(result_se)
#> [1] "Averaged" "custom_bliss" "custom_hss"
#> [4] "combo_diagnostics"
By default, a failed cell emits a warning and is skipped
(on_error = "warn"). Use on_error = "stop" to halt immediately and
propagate the error — useful when debugging a new fit function.
buggy_fn <- function(dt) {
if (dt$normalization_type[1] == "GR") stop("GR not supported")
list(x_rv = mean(dt$x, na.rm = TRUE))
}
se_partial <- withCallingHandlers(
apply_fit(
sa_se, buggy_fn, "single-agent",
output_assay = "rv_only",
fit_source = "rv_fn",
on_error = "warn"
),
warning = function(w) {
message("[caught] ", conditionMessage(w))
invokeRestart("muffleWarning")
}
)
# Only RV rows are written; GR cells were skipped with a warning
rv_df <- BumpyMatrix::unsplitAsDataFrame(
assay(se_partial, "rv_only"),
row.field = "row", column.field = "column"
)
unique(rv_df$normalization_type)
#> [1] "RV"
# Single fit → one output assay
apply_fit(
se,
fit_fn,
data_type = "single-agent", # or "combination", "time-course"
slicing_cols = NULL, # NULL → data_type default
slicing_values = NULL, # NULL → all unique values found
input_assay = NULL, # NULL → data_type default ("Averaged")
output_assay, # REQUIRED — your assay name
summary_fn = NULL, # optional cell-level aggregator
summary_assay = NULL,
merge = "merge", # or "replace"
on_error = "warn", # or "stop"
fit_source # REQUIRED — upsert key tag
)
# Multiple fits → one BumpyMatrix pass
apply_fits(
se,
fit_fns, # named list: name = output assay, value = fit function
data_type = "single-agent",
fit_source,
...
)
| Input | data.table — one BumpyMatrix cell, filtered to one slicing_cols value |
| Output | Named list → one row in output_assay; or named list of named lists for multi-assay pattern |
| fit_source | Stamped by the generic layer — do not include in the return value |
| slicing columns | The caller’s value (e.g. normalization_type) IS available in the data.table — no need to filter again |
| Input | data.table — all rows written by fit_fn for one (row × column) cell |
| Output | Named list → one row in summary_assay |
| When to use | Aggregated metrics that span normalization types (e.g. “converged in at least one type?”) |
apply_fit())| Function | Model | Equivalent to | Key output columns |
|---|---|---|---|
fit_drug_response_metrics() |
3p LL.3u, x_0 = 1 |
fit_SE() / logisticFit() |
ec50, xc50, h, r2, x_mean, x_AOC, fit_type = "DRC3pHillFitModelFixS0" |
fit_drug_response_metrics_4p() |
4p LL.4, x_0 free |
— (extended variant) | ec50, xc50, h, r2, x_0, x_mean, fit_type = "DRC4pHillFitModel" |
| Function | Level | Requires | Equivalent to | Key output columns |
|---|---|---|---|---|
apply_combo_scores(se) |
SE-level (recommended) | Averaged + Metrics |
fit_SE.combinations() Bliss & HSA |
bliss_score, hsa_score |
bliss_fit_fn() |
triplet fit_fn |
Averaged only |
— (simplified, no SA fits) | bliss_score, bliss_excess_mean, n_combo_points |
hss_fit_fn() |
triplet fit_fn |
Averaged only |
— (simplified, no SA fits) | hss_score, hss_excess_mean, n_combo_points |
When to use which:
- Use apply_combo_scores() when you have a fully fitted SE (after fit_SE.combinations() or
apply_fit_to_se()) and want scores numerically consistent with the standard gDR pipeline.
- Use bliss_fit_fn() / hss_fit_fn() when prototyping a new scoring approach,
when SA fits are unavailable, or when embedding score computation inside a larger custom fit_fn.
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 LTS
#>
#> Matrix products: default
#> BLAS: /home/biocbuild/bbs-3.24-bioc/R/lib/libRblas.so
#> LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0 LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_GB LC_COLLATE=C
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: America/New_York
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats4 stats graphics grDevices utils datasets methods
#> [8] base
#>
#> other attached packages:
#> [1] data.table_1.18.4 BumpyMatrix_1.21.0
#> [3] SummarizedExperiment_1.43.0 Biobase_2.73.2
#> [5] GenomicRanges_1.65.1 Seqinfo_1.3.0
#> [7] IRanges_2.47.2 S4Vectors_0.51.6
#> [9] BiocGenerics_0.59.12 generics_0.1.4
#> [11] MatrixGenerics_1.25.0 matrixStats_1.5.0
#> [13] gDRutils_1.11.9 gDRtestData_1.11.7
#> [15] gDRcore_1.11.8 BiocStyle_2.41.0
#>
#> loaded via a namespace (and not attached):
#> [1] xfun_0.60 bslib_0.12.0
#> [3] lattice_0.23-1 tools_4.6.1
#> [5] parallel_4.6.1 sandwich_3.1-3
#> [7] drc_3.0-1 Matrix_1.7-6
#> [9] checkmate_2.3.4 RColorBrewer_1.1-3
#> [11] RcppParallel_6.2.0 lifecycle_1.0.5
#> [13] farver_2.1.2 compiler_4.6.1
#> [15] codetools_0.2-20 carData_3.0-6
#> [17] htmltools_0.5.9 sass_0.4.10
#> [19] yaml_2.3.12 Formula_1.2-6
#> [21] car_3.1-5 jquerylib_0.1.4
#> [23] MASS_7.3-66 BiocParallel_1.47.0
#> [25] DelayedArray_0.39.5 cachem_1.1.0
#> [27] abind_1.4-8 multcomp_1.4-31
#> [29] qs2_0.2.2 gtools_3.9.5
#> [31] digest_0.6.39 mvtnorm_1.4-2
#> [33] bookdown_0.47 splines_4.6.1
#> [35] fastmap_1.2.0 grid_4.6.1
#> [37] cli_3.6.6 SparseArray_1.13.2
#> [39] S4Arrays_1.13.0 dichromat_2.0-1
#> [41] survival_3.8-9 TH.data_1.1-5
#> [43] scales_1.4.0 backports_1.5.1
#> [45] plotrix_3.8-14 rmarkdown_2.31
#> [47] XVector_0.53.0 otel_0.2.0
#> [49] zoo_1.9-0 stringfish_0.19.2
#> [51] evaluate_1.0.5 knitr_1.51
#> [53] MultiAssayExperiment_1.39.0 rlang_1.3.0
#> [55] Rcpp_1.1.2 glue_1.8.1
#> [57] BiocManager_1.30.27 jsonlite_2.0.0
#> [59] R6_2.6.1