Skip to content

Commit

Permalink
Merge pull request #472 from Olink-Proteomics/develop_product_bridgin…
Browse files Browse the repository at this point in the history
…g_downstream

Convert output of cross-product bridge to be used in downstream functions
  • Loading branch information
dtopouza authored Jan 24, 2025
2 parents 92ef373 + f162903 commit 2f285ae
Show file tree
Hide file tree
Showing 6 changed files with 423 additions and 10 deletions.
17 changes: 15 additions & 2 deletions OlinkAnalyze/R/olink_normalization.R
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@
#' subset normalization.
#' @param reference_medians Dataset with columns "OlinkID" and "Reference_NPX".
#' Required for reference median normalization.
#' @param format Boolean that controls whether the normalized dataset will be
#' formatted for input to downstream analysis. Only applicable for cross-product
#' bridge normalization.
#'
#' @return Tibble or ArrowObject with the normalized dataset.
#'
Expand Down Expand Up @@ -222,7 +225,8 @@
#' overlapping_samples_df1 = overlap_samples_product,
#' df1_project_nr = "proj_ht",
#' df2_project_nr = "proj_3k",
#' reference_project = "proj_ht"
#' reference_project = "proj_ht",
#' format = FALSE
#' )
#' }
#'
Expand All @@ -233,7 +237,8 @@ olink_normalization <- function(df1,
df1_project_nr = "P1",
df2_project_nr = "P2",
reference_project = "P1",
reference_medians = NULL) {
reference_medians = NULL,
format = FALSE) {

# check input ----
lst_check <- olink_norm_input_check(
Expand Down Expand Up @@ -306,6 +311,14 @@ olink_normalization <- function(df1,
not_ref_cols = lst_check$not_ref_cols
)

if (format == TRUE) {
df_norm <- olink_normalization_product_format(bridged_df = df_norm,
df1 = df1,
df1_project_nr = df1_project_nr,
df2 = df2,
df2_project_nr = df2_project_nr)
}

} else if (lst_check$norm_mode == olink_norm_modes$subset) {
# subset normalization ----

Expand Down
142 changes: 142 additions & 0 deletions OlinkAnalyze/R/olink_normalization_product.R
Original file line number Diff line number Diff line change
Expand Up @@ -640,3 +640,145 @@ olink_normalization_qs <- function(lst_df,

return(df_qq_norm)
}



#' Formatting the output of olink_normalization_product for seamless use with
#' downstream OA functions.
#'
#' @author
#' Danai G. Topouza
#'
#' @description
#' Replaces the NPX values of the non-reference project by the Median Centered
#' or QS Normalized NPX, according to the Bridging Recommendation. Edits the
#' BridgingRecommendation column to indicate whether an assay is NotBridgeable,
#' NotOverlapping, MedianCentering, or QuantileSmoothing bridged. Replaces
#' OlinkID by the concatenation of the Explore HT and Explore 3072 OlinkIDs to
#' record the OlinkIDs from both projects for bridgeable assays. Assays that are
#' NotBridgeable or NotOverlapping retain their original non-reference OlinkIDs
#' and NPX values. Replaces SampleID with the concatenation of SampleID and
#' Project to make unique sample IDs for downstream analysis. Removes internal
#' and external controls. Removes MedianCenteredNPX, QSNormalizedNPX,
#' OlinkID_E3072 columns.
#'
#' @param bridged_df A "tibble" of Olink data in long format resulting from the
#' olink_normalization_product function.
#' @param df1 First dataset to be used for normalization, pre-normalization.
#' Must match df1 used in olink_normalization product bridging.
#' @param df2 Second dataset to be used for normalization, pre-normalization.
#' Must match df2 used in olink_normalization product bridging.
#' @param df1_project_nr Project name of first dataset. Must match name used in
#' olink_normalization product bridging.
#' @param df2_project_nr Project name of second dataset. Must match name used in
#' olink_normalization product bridging.
#'
#' @return A "tibble" of Olink data in long format containing both input
#' datasets with the bridged NPX quantifications, with the above
#' modifications.
#'
#' @examples
#' \donttest{
#' # Bridge samples
#' bridge_samples <- intersect(
#' x = unique(OlinkAnalyze:::data_ht_small$SampleID),
#' y = unique(OlinkAnalyze:::data_3k_small$SampleID)
#' ) |>
#' (\(x) x[!grepl("CONTROL", x)])()
#'
#' # Run olink_normalization_product
#' npx_br_data <- olink_normalization(
#' df1 = OlinkAnalyze:::data_ht_small,
#' df2 = OlinkAnalyze:::data_3k_small,
#' overlapping_samples_df1 = bridge_samples,
#' df1_project_nr = "Explore HT",
#' df2_project_nr = "Explore 3072",
#' reference_project = "Explore HT")
#'
#' # Format output
#' npx_br_data_format <- OlinkAnalyze:::olink_normalization_product_format(
#' bridged_df = npx_br_data,
#' df1 = OlinkAnalyze:::data_ht_small,
#' df2 = OlinkAnalyze:::data_3k_small,
#' df1_project_nr = "Explore HT",
#' df2_project_nr = "Explore 3072")
#'
#' }

olink_normalization_product_format <- function(bridged_df,
df1,
df1_project_nr,
df2,
df2_project_nr) {

# Extract data from NotBridgeable assays
df_not_bridgeable <- bridged_df |>
dplyr::mutate(SampleID = paste0(.data[["SampleID"]],
"_",
.data[["Project"]])) |>
dplyr::filter(.data[["SampleType"]] == "SAMPLE") |> # Remove controls
dplyr::filter(.data[["AssayType"]] == "assay") |>
dplyr::filter(.data[["BridgingRecommendation"]] == "NotBridgeable") |>
dplyr::mutate(OlinkID = case_when(
Panel == "Explore_HT" ~ OlinkID,
Panel != "Explore_HT" ~ OlinkID_E3072
)) |>
dplyr::select(!c(.data[["MedianCenteredNPX"]],
.data[["QSNormalizedNPX"]],
.data[["OlinkID_E3072"]]))# Remove extra columns


# Extract data from non-overlapping assays
df1_no_overlap <- df1 |>
dplyr::filter(.data[["SampleType"]] == "SAMPLE") |> # Remove controls
dplyr::filter(!(.data[["OlinkID"]] %in%
unlist(eHT_e3072_mapping |>
dplyr::select(dplyr::starts_with("OlinkID_"))))) |>
dplyr::mutate(Project = df1_project_nr) |>
dplyr::mutate(SampleID =
paste0(.data[["SampleID"]],"_",df1_project_nr)) |>
dplyr::mutate(BridgingRecommendation = "NotOverlapping")

df2_no_overlap <- df2 |>
dplyr::filter(.data[["SampleType"]] == "SAMPLE") |> # Remove controls
dplyr::filter(!(.data[["OlinkID"]] %in%
unlist(eHT_e3072_mapping |>
dplyr::select(dplyr::starts_with("OlinkID_"))))) |>
dplyr::mutate(Project = df2_project_nr) |>
dplyr::mutate(SampleID =
paste0(.data[["SampleID"]],"_",df2_project_nr)) |>
dplyr::mutate(BridgingRecommendation = "NotOverlapping")

### Keep the data following BridgingRecommendation
df_format <- bridged_df |>
dplyr::filter(.data[["SampleType"]] == "SAMPLE") |> # Remove controls
dplyr::mutate(SampleID = paste0(.data[["SampleID"]],
"_",
.data[["Project"]])) |>
dplyr::filter(!.data[["BridgingRecommendation"]] == "NotBridgeable") |>
dplyr::mutate(NPX = case_when(
.data[["BridgingRecommendation"]] == "MedianCentering" ~
.data[["MedianCenteredNPX"]],
.data[["BridgingRecommendation"]] == "QuantileSmoothing" ~
.data[["QSNormalizedNPX"]],
.default = .data[["NPX"]])) |>
dplyr::filter(.data[["AssayType"]] == "assay") |>
dplyr::mutate(OlinkID = paste0(.data[["OlinkID"]],
"_",
.data[["OlinkID_E3072"]])) |>
dplyr::select(!c(.data[["MedianCenteredNPX"]],
.data[["QSNormalizedNPX"]],
.data[["OlinkID_E3072"]]))# Remove extra columns

df_full <- rbind(df_format,
df_not_bridgeable,
df1_no_overlap,
df2_no_overlap)

# Sort by Project
df_full <- df_full |>
dplyr::arrange(.data[["Project"]], .data[["SampleID"]])

return(df_full)
}

10 changes: 8 additions & 2 deletions OlinkAnalyze/man/olink_normalization.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 80 additions & 0 deletions OlinkAnalyze/man/olink_normalization_product_format.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion OlinkAnalyze/tests/testthat/helper-get_example_olink_data.R
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# load example datasets for Olink Explore products
get_example_data <- function(filename) {
ref_norm_res_file <- test_path("data", filename)
print(ref_norm_res_file)
#check that file exists
expect_true(file.exists(ref_norm_res_file))
expect_true(file.exists(ref_norm_res_file),label = ref_norm_res_file)
# read rds data
readRDS(file = ref_norm_res_file)
}
Loading

0 comments on commit 2f285ae

Please sign in to comment.