Multimodal Ageing Biomarkers and Plasma Proteomic Signatures Associated with All-Cause Mortality
The 19 matches
- [1] § Materials and Methods › Physical function ↔ 2_Cox_Mortality_Associations_of_Individual_Ageing_Biomarkers.R, lines 336–375 · score 0.95 · forced vital capacity, forced expiratory ratio, forced expiratory volume, Grip strength, Lung function, physical function
- [2] § Materials and Methods › Physical function ↔ 3_Cox_Mortality_Associations_of_All_Ageing_Biomarkers.R, lines 177–215 · score 0.93 · forced vital capacity, forced expiratory ratio, forced expiratory volume, Grip strength, physical function, dominant hand
- [3] § Materials and Methods › General cognitive function (g) ↔ 7_G_score.R, lines 90–153 · score 0.93 · empirical Bayes, fitted SEM, latent factor, shared variance, FIML, likelihood
- [4] § Results › Plasma proteomic signatures, biological processes, and tissues associated with all-cause mortality ↔ 6_Mortality_Elastic_Net_Cox_for_SomaScan11k_Plasma_Proteins.R, lines 1–42 · score 0.82 · fold cross validation, penalised Cox, plasma proteins, SomaScan, protein mortality, elastic
- [5] § Materials and Methods › Proteomic organ age gaps ↔ 8_Calculating_OrganAgeGaps_LBC1936.R, lines 42–85 · score 0.81 · log10 transformed, Organ age gaps, protein coefficients, SomaScan, predicted ages, chronological age
- [6] § Materials and Methods › Statistical analyses › Survival analyses ↔ 6_Mortality_Elastic_Net_Cox_for_SomaScan11k_Plasma_Proteins.R, lines 1–42 · score 0.79 · fold cross validation, penalised Cox, Plasma protein, Alive, elastic, Cox models
- [7] § Materials and Methods › General cognitive function (g) ↔ 7_G_score.R, lines 43–88 · score 0.79 · Digit Span Backwards, Logical Memory, Verbal Paired Associates, cognitive
- [8] § Results › Epigenetic, neuroimaging, and functional ageing biomarkers outperform proteomic organ ages in associations with all-cause mortality ↔ 3_Cox_Mortality_Associations_of_All_Ageing_Biomarkers.R, lines 217–302 · score 0.78 · eleven proteomic organ, brain age acceleration, proteomic brain age, telomere length, brain age gap, proteomic organ age
- [9] § Materials and Methods › General cognitive function (g) ↔ 7_G_score.R, lines 43–88 · score 0.76 · Digit Symbol Substitution, Symbol Search, Choice Reaction, cognitive
- [10] § Results › Epigenetic, neuroimaging, and functional ageing biomarkers outperform proteomic organ ages in associations with all-cause mortality ↔ 2_Cox_Mortality_Associations_of_Individual_Ageing_Biomarkers.R, lines 377–446 · score 0.72 · brain age acceleration, proteomic brain age, telomere length, brain age gap, proteomic organ age, ageing biomarkers
- [11] § Materials and Methods › Proteomic organ age gaps ↔ 2_Cox_Mortality_Associations_of_Individual_Ageing_Biomarkers.R, lines 377–446 · score 0.72 · Proteomic organ ages, Organ age gaps, intestine, muscle, artery, lung
- [12] § Results › Neuroimaging, cognitive, and physical function biomarkers of ageing independently associate with all-cause mortality ↔ 3_Cox_Mortality_Associations_of_All_Ageing_Biomarkers.R, lines 128–175 · score 0.71 · multivariable Cox, confidence intervals, PH assumption, proportional hazards, Hazard ratios, organ ageing biomarkers
- [13] § Materials and Methods › Statistical analyses ↔ 4_Cox_Mortality_Associations_of_SomaScan11k_Plasma_Proteins.R, lines 96–141 · score 0.68 · zero inflation, log transformed, pack years, variables
- [14] § Materials and Methods › Statistical analyses › Survival analyses ↔ 2_Cox_Mortality_Associations_of_Individual_Ageing_Biomarkers.R, lines 170–225 · score 0.68 · cox.zph, Proportional hazards assumptions, Cox proportional hazards, ageing biomarkers, death, HR
- [15] § Materials and Methods › Statistical analyses › Survival analyses ↔ 4_Cox_Mortality_Associations_of_SomaScan11k_Plasma_Proteins.R, lines 215–268 · score 0.67 · cox.zph, Proportional hazards assumptions, Cox proportional hazards, plasma protein, death, HR
- [16] § Results › Plasma proteomic signatures, biological processes, and tissues associated with all-cause mortality ↔ 3_Cox_Mortality_Associations_of_All_Ageing_Biomarkers.R, lines 128–175 · score 0.65 · confidence intervals, PH assumption, proportional hazards, Hazard ratios, mortality associated, Cox model
- [17] § Materials and Methods › Plasma proteomics ↔ 8_Calculating_OrganAgeGaps_LBC1936.R, lines 42–85 · score 0.62 · log10 transformed, Protein expression, SomaScan, coefficient, SD, proteomic
- [18] § Materials and Methods › Statistical analyses ↔ 1_Ageing_Biomarker_Correlations.R, lines 1–40 · score 0.57 · zero inflation, variables, log, WMH, ICV, transformed
- [19] § Materials and Methods › GrimAge2 acceleration ↔ 4_Cox_Mortality_Associations_of_SomaScan11k_Plasma_Proteins.R, lines 96–141 · score 0.53 · log transformed, pack years, plasma proteins, sex, Cox, mortality
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
R · 931 lines · 25 KB · GPL-3.0 · 4 matches
- # =============================================================
- # ASSOCIATIONS OF INDIVIDUAL AGEING BIOMARKERS WITH ALL-CAUSE MORTALITY
- # =============================================================
- # COHORT:
- # Lothian Birth Cohort 1936
- # COX MODELS:
- # Models are fitted separately for each ageing biomarker.
- #
- # Model 1: Demographics
- # Surv(time_to_death, dead) ~ scale(biomarker_i) + scale(age) + sex
- #
- # Model 2: Demographics and lifestyle-related risk factors
- # Surv(time_to_death, dead) ~ scale(biomarker_i) + scale(age) + sex +
- # scale(Smoking_pack_years) + scale(Alcohol_units) + scale(BMI)
- #
- # Model 3: Demographics, lifestyle-related risk factors, and medical conditions
- # Surv(time_to_death, dead) ~ scale(biomarker_i) + scale(age) + sex +
- # scale(Smoking_pack_years) + scale(Alcohol_units) + scale(BMI) +
- # 7 medical conditions
- # MORTALITY OUTCOMES:
- # All-cause mortality over 16 years of follow-up (time-to-event).
- # dead (0/1) = event status, where 0 = alive/censored and 1 = deceased.
- # time_to_death = time (in years) from baseline (Wave 2) until death or censoring.
- # PREDICTORS:
- # 23 scaled ageing biomarkers measured at wave 2 (age ~ 73 years).
- # COVARIATES:
- # Demographics: age and sex.
- # Lifestyle-related risk factors: smoking pack years, alcohol units per week, and BMI.
- # Medical conditions: hypertension, high cholesterol, diabetes, cardiovascular disease, stroke, neoplasm, and arthritis.
- # =============================================================
- # ------------------------------------
- # Load required libraries
- # ------------------------------------
- library(dplyr)
- library(survival)
- library(pbapply)
- library(forcats)
- library(stringr)
- library(readr)
- library(ggplot2)
- library(ggtext)
- library(ggrepel)
- # ------------------------------------
- # Load scaled ageing biomarker dataset
- # ------------------------------------
- all_age_biomarkers_df_scaled <- read_csv("/CCACE_Shared/Maira/OrganAgeProject/Univariate_aging_biomarkers_mortality_cox/Scaled_aging_biomarkers_mortality_data_LBC1936w2.csv")
- # All ageing biomarkers and continuous covariates have already been scaled to a mean of 0 and standard deviation of 1.
- # ------------------------------------
- # Define output directory
- # ------------------------------------
- OUT_DIR <- "/CCACE_Shared/Maira/OrganAgeProject/Univariate_aging_biomarkers_mortality_cox"
- # ---------------------------
- # 1. Sanity checks and pre-processing
- # ---------------------------
- # Inspect the class of each variable in the dataset.
- data.frame(
- column = names(all_age_biomarkers_df_scaled),
- class = sapply(all_age_biomarkers_df_scaled, class)
- )
- # Exclude diseases with fewer than 50 cases.
- all_age_biomarkers_df_scaled <- all_age_biomarkers_df_scaled %>%
- select(-parkin_w2, -dement_w2)
- # Convert categorical variables to factors.
- factor_vars <- c(
- "sex",
- "hibp_w2",
- "hichol_w2",
- "diab_w2",
- "cvdhist_w2",
- "stroke_w2",
- "neoplas_w2",
- "arthrit_w2"
- )
- all_age_biomarkers_df_scaled[factor_vars] <- lapply(
- all_age_biomarkers_df_scaled[factor_vars],
- factor
- )
- # Convert the mortality outcome to an integer event indicator.
- all_age_biomarkers_df_scaled$dead <- as.integer(as.logical(all_age_biomarkers_df_scaled$dead))
- # ---------------------------
- # 2. Define covariate groups
- # ---------------------------
- # Demographic covariates.
- demographics <- c(
- "ageyrs_w2",
- "sex"
- )
- # Lifestyle-related covariates.
- lifestyle <- c(
- "Smoking_pack_years",
- "Alcohol_units",
- "BMI"
- )
- # Medical conditions.
- diseases <- c(
- "hibp_w2",
- "hichol_w2",
- "diab_w2",
- "cvdhist_w2",
- "stroke_w2",
- "neoplas_w2",
- "arthrit_w2"
- )
- # Ageing biomarkers.
- biomarkers <- c(
- "Telomere_length",
- "Six_meter_walk_time",
- "FEV",
- "FER",
- "FVC",
- "Grip_strength",
- "TBV_to_ICV_ratio",
- "GMV_to_ICV_ratio",
- "WMHV_to_ICV_ratio",
- "g",
- "GrimAge2_acceleration",
- "Adipose_age_gap",
- "Artery_age_gap",
- "Brain_age_gap",
- "Heart_age_gap",
- "Immune_age_gap",
- "Intestine_age_gap",
- "Kidney_age_gap",
- "Liver_age_gap",
- "Lung_age_gap",
- "Muscle_age_gap",
- "Pancreas_age_gap",
- "MRI_brain_age_gap"
- )
- # ---------------------------
- # 3. Define Cox models
- # ---------------------------
- models <- list(
- demographics = demographics,
- demographics_lifestyle = c(demographics, lifestyle),
- demographics_lifestyle_diseases = c(demographics, lifestyle, diseases)
- )
- # ---------------------------
- # 4. Function to run a Cox model
- # ---------------------------
- run_cox_model <- function(biomarker, covariates, model_name) {
- vars_needed <- c(
- "time_to_death",
- "dead",
- biomarker,
- covariates
- )
- # Retain complete cases for all variables included in the model.
- df <- all_age_biomarkers_df_scaled %>%
- select(all_of(vars_needed)) %>%
- na.omit()
- n_subjects <- nrow(df)
- # Construct the model formula.
- formula <- as.formula(
- paste(
- "Surv(time_to_death, dead) ~",
- paste(c(biomarker, covariates), collapse = " + ")
- )
- )
- # Fit the Cox proportional hazards model.
- fit <- coxph(formula, data = df)
- # Extract the coefficient and p-value for the ageing biomarker.
- s <- summary(fit)
- coef_tab <- s$coefficients
- biomarker_row <- which(rownames(coef_tab) == biomarker)
- coef_val <- coef_tab[biomarker_row, "coef"]
- p_val <- coef_tab[biomarker_row, "Pr(>|z|)"]
- ci <- confint(fit, parm = biomarker)
- # Test the proportional hazards assumption using cox.zph().
- ph_test <- cox.zph(fit)
- ph_row <- which(rownames(ph_test$table) == biomarker)
- data.frame(
- biomarker_name = biomarker,
- model = model_name,
- covariates = paste(covariates, collapse = ", "),
- n_subjects = n_subjects,
- HR = exp(coef_val),
- lower_95CI = exp(ci[1]),
- upper_95CI = exp(ci[2]),
- p_value = p_val,
- ph_violation = ph_test$table[ph_row, "p"] < 0.05,
- ph_chisq = ph_test$table[ph_row, "chisq"],
- ph_p = ph_test$table[ph_row, "p"]
- )
- }
- # ---------------------------
- # 5. Run Cox models for all ageing biomarkers
- # ---------------------------
- # The associations of each biomarker with time-to-death are evaluated using all three covariate-adjusted Cox models.
- results_list <- pblapply(
- biomarkers,
- function(biomarker) {
- do.call(
- rbind,
- lapply(
- names(models),
- function(model_name) {
- run_cox_model(
- biomarker = biomarker,
- covariates = models[[model_name]],
- model_name = model_name
- )
- }
- )
- )
- }
- )
- # Combine results across biomarkers and models.
- results_df <- bind_rows(results_list)
- # ---------------------------
- # 6. Multiple testing correction
- # ---------------------------
- # Apply Benjamini-Hochberg false discovery rate correction.
- results_df <- results_df %>%
- group_by(model) %>% # Adjust p-values within each model
- mutate(
- adj_p_benjamini = p.adjust(p_value, method = "BH")
- ) %>%
- ungroup() %>%
- select(
- biomarker_name,
- model,
- covariates,
- n_subjects,
- HR,
- lower_95CI,
- upper_95CI,
- p_value,
- adj_p_benjamini,
- ph_violation,
- ph_chisq,
- ph_p
- )
- write_csv(
- results_df,
- file.path(
- OUT_DIR,
- "mortality_unicox_26biomarkers_fully_adjusted_all_subjects.csv"
- )
- )
- # ---------------------------
- # 7. Invert hazard ratios below 1
- # ---------------------------
- # For biomarkers with HR < 1, invert the HR and confidence intervals (1/HR)
- # to facilitate comparison of effect magnitudes across positively and negatively associated biomarkers.
- # The biomarker name is prefixed with "-" to indicate that its direction has been inverted.
- inverted_univariable_aging_biomarker_results <- results_df %>%
- mutate(
- inverted_HR = ifelse(HR < 1, 1 / HR, HR),
- inverted_lower_95CI = ifelse(HR < 1, 1 / upper_95CI, lower_95CI),
- inverted_upper_95CI = ifelse(HR < 1, 1 / lower_95CI, upper_95CI),
- biomarker_name = ifelse(HR < 1, paste0("-", biomarker_name), biomarker_name)
- ) %>%
- arrange(desc(inverted_HR))
- write_csv(inverted_univariable_aging_biomarker_results, file.path(OUT_DIR, "inverted_univariable_ageing_biomarker_results_all_subjects.csv"))
- # ---------------------------
- # 8. Format results for publication
- # ---------------------------
- # Define the biomarker order based on the demographic-adjusted model.
- biomarker_order_fully_adjusted <- inverted_univariable_aging_biomarker_results %>%
- filter(model == "demographics") %>%
- arrange(desc(inverted_HR)) %>%
- pull(biomarker_name) %>%
- gsub("^-", "", .)
- biomarker_order_fully_adjusted
- # Format results with publication-ready biomarker descriptions, covariate descriptions, and model labels.
- publication_results <- results_df %>%
- mutate(
- inverted_HR = ifelse(HR < 1, 1 / HR, NA),
- inverted_lower_95CI = ifelse(HR < 1, 1 / upper_95CI, NA),
- inverted_upper_95CI = ifelse(HR < 1, 1 / lower_95CI, NA),
- biomarker_name = ifelse(
- HR < 1,
- paste0("-", biomarker_name),
- biomarker_name
- ),
- # Remove the "-" prefix before matching biomarker descriptions.
- biomarker_clean = gsub("^-", "", biomarker_name),
- # Order biomarkers according to the demographic-adjusted model.
- biomarker_clean = factor(
- biomarker_clean,
- levels = biomarker_order_fully_adjusted
- )
- ) %>%
- arrange(biomarker_clean,
- factor(model, levels = c(
- "demographics",
- "demographics_lifestyle",
- "demographics_lifestyle_diseases"
- ))) %>%
- mutate(
- # Assign publication-ready descriptions to each biomarker.
- biomarker_description = recode(
- as.character(biomarker_clean),
- # Cognition.
- "g" = "General cognitive factor",
- # MRI-derived measures of brain structure.
- "TBV_to_ICV_ratio" = "MRI-derived total brain volume to intracranial volume ratio",
- "GMV_to_ICV_ratio" = "MRI-derived grey matter volume to intracranial volume ratio",
- "WMHV_to_ICV_ratio" = "MRI-derived white matter hyperintensity volume to intracranial volume ratio",
- "MRI_brain_age_gap" = "MRI-derived brain age gap",
- # Physical function and lung function.
- "Grip_strength" = "Dominant hand grip strength (kg)",
- "Six_meter_walk_time" = "6-metre walk time (seconds)",
- "FVC" = "Forced vital capacity (L)",
- "FEV" = "Forced expiratory volume in 1 second (L)",
- "FER" = "Forced expiratory ratio (%)",
- # Lifestyle and anthropometric measures.
- "Alcohol_units" = "Alcohol consumption (units per week)",
- "Smoking_pack_years" = "Smoking pack years",
- "BMI" = "Body mass index (kg/m²)",
- # Molecular ageing measures.
- "Telomere_length" = "Leukocyte telomere length (bp)",
- "GrimAge2_acceleration" = "Epigenetic age acceleration",
- # Plasma proteomic organ age gaps.
- "Adipose_age_gap" = "Plasma proteomic adipose age gap",
- "Artery_age_gap" = "Plasma proteomic arterial age gap",
- "Brain_age_gap" = "Plasma proteomic brain age gap",
- "Heart_age_gap" = "Plasma proteomic heart age gap",
- "Immune_age_gap" = "Plasma proteomic immune age gap",
- "Intestine_age_gap" = "Plasma proteomic intestine age gap",
- "Kidney_age_gap" = "Plasma proteomic kidney age gap",
- "Liver_age_gap" = "Plasma proteomic liver age gap",
- "Lung_age_gap" = "Plasma proteomic lung age gap",
- "Muscle_age_gap" = "Plasma proteomic muscle age gap",
- "Pancreas_age_gap" = "Plasma proteomic pancreas age gap"
- ),
- # Provide descriptive labels for each covariate adjustment set.
- covariates = recode(
- covariates,
- "ageyrs_w2, sex" = "Age + sex",
- "ageyrs_w2, sex, Smoking_pack_years, Alcohol_units, BMI" =
- "Age + sex + smoking + alcohol + BMI",
- "ageyrs_w2, sex, Smoking_pack_years, Alcohol_units, BMI, hibp_w2, hichol_w2, diab_w2, cvdhist_w2, stroke_w2, neoplas_w2, arthrit_w2" =
- "Age + sex + smoking + alcohol + BMI + high blood pressure + high cholesterol + diabetes + cardiovascular disease + stroke + neoplasm + arthritis"
- ),
- # Provide descriptive labels for each Cox model.
- model = recode(
- model,
- "demographics" = "Cox model adjusted for demographics",
- "demographics_lifestyle" = "Cox model adjusted for demographics and lifestyle",
- "demographics_lifestyle_diseases" = "Cox model adjusted for demographics, lifestyle and diseases"
- )
- ) %>%
- select(
- biomarker_name,
- biomarker_description,
- model,
- covariates,
- n_subjects,
- HR,
- lower_95CI,
- upper_95CI,
- inverted_HR,
- inverted_lower_95CI,
- inverted_upper_95CI,
- p_value,
- adj_p_benjamini,
- ph_violation,
- ph_chisq,
- ph_p
- )
- write_csv(publication_results, file.path(OUT_DIR, "inverted_univariable_aging_biomarker_publication_results_all_subjects.csv"))
- # ---------------------------
- # 9. Generate forest plots for each model
- # ---------------------------
- # Biomarkers to display in bold in the forest plots.
- bold_labels <- c(
- "Liver age gap", "Immune age gap", "Heart age gap",
- "Pancreas age gap", "Brain age gap", "Muscle age gap",
- "Adipose age gap", "Kidney age gap", "Lung age gap",
- "Intestine age gap", "Artery age gap"
- )
- # Function to generate a forest plot for a single Cox model.
- create_forest_plot <- function(data, model_name) {
- plot_data <- data %>%
- filter(model == model_name) %>%
- filter(!is.na(inverted_HR)) %>%
- mutate(
- biomarker_name = str_replace_all(biomarker_name, "_", " "),
- biomarker_name = fct_reorder(
- biomarker_name,
- inverted_HR
- ),
- fill_color = ifelse(
- adj_p_benjamini > 0.05,
- "white",
- ifelse(
- str_detect(biomarker_name, "-"),
- "#5EC1C0",
- "#FFA69E"
- )
- )
- )
- # Create Markdown-formatted labels for bold organ age gaps.
- y_labels_md <- sapply(levels(plot_data$biomarker_name), function(x) {
- if (str_replace(x, "^-", "") %in% bold_labels) {
- paste0("**", x, "**")
- } else {
- x
- }
- })
- names(y_labels_md) <- levels(plot_data$biomarker_name)
- # Generate the forest plot.
- p <- ggplot(
- plot_data,
- aes(
- x = inverted_HR,
- y = biomarker_name
- )
- ) +
- geom_errorbarh(
- aes(
- xmin = inverted_lower_95CI,
- xmax = inverted_upper_95CI
- ),
- height = 0.2
- ) +
- geom_point(
- aes(fill = fill_color),
- shape = 21,
- size = 4,
- color = "black",
- stroke = 1
- ) +
- scale_fill_identity() +
- geom_vline(
- xintercept = 1,
- linetype = "dashed",
- size = 0.8
- ) +
- labs(
- x = "Hazard ratio (95% CI)",
- y = ""
- ) +
- scale_x_continuous(
- limits = c(0.6, 2.0),
- breaks = seq(0.6, 2.0, by = 0.2)
- ) +
- scale_y_discrete(
- labels = y_labels_md
- ) +
- theme_classic(base_size = 20) +
- theme(
- axis.ticks = element_line(color = "black"),
- panel.grid = element_blank(),
- panel.border = element_blank(),
- axis.line = element_line(color = "black"),
- legend.position = "none",
- plot.title = element_blank(),
- axis.text.y = element_markdown(size = 20),
- axis.text.x = element_text(size = 20)
- )
- return(p)
- }
- # Generate forest plots for each covariate adjustment model.
- p_demographics <- create_forest_plot(
- inverted_univariable_aging_biomarker_results,
- "demographics"
- )
- p_demographics_lifestyle <- create_forest_plot(
- inverted_univariable_aging_biomarker_results,
- "demographics_lifestyle"
- )
- p_demographics_lifestyle_diseases <- create_forest_plot(
- inverted_univariable_aging_biomarker_results,
- "demographics_lifestyle_diseases"
- )
- # Display the individual forest plots.
- p_demographics
- p_demographics_lifestyle
- p_demographics_lifestyle_diseases
- # Save the individual forest plots.
- ggsave(
- file.path(OUT_DIR, "forest_plot_ageing_biomarkers_demographics.png"),
- p_demographics,
- width = 10,
- height = 10,
- dpi = 600
- )
- ggsave(
- file.path(OUT_DIR, "forest_plot_ageing_biomarkers_demographics_lifestyle.png"),
- p_demographics_lifestyle,
- width = 10,
- height = 10,
- dpi = 600
- )
- ggsave(
- file.path(OUT_DIR, "forest_plot_ageing_biomarkers_demographics_lifestyle_diseases.png"),
- p_demographics_lifestyle_diseases,
- width = 10,
- height = 10,
- dpi = 600
- )
- # ---------------------------
- # 10. Combined forest plot: three models per biomarker
- # ---------------------------
- # Biomarkers to display in bold in the combined forest plots.
- bold_labels <- c(
- "Liver age gap", "Immune age gap", "Heart age gap",
- "Pancreas age gap", "Brain age gap", "Muscle age gap",
- "Adipose age gap", "Kidney age gap", "Lung age gap",
- "Intestine age gap", "Artery age gap"
- )
- # Define biomarker order based on the demographics model.
- biomarker_order_demographics <- inverted_univariable_aging_biomarker_results %>%
- filter(model == "demographics") %>%
- arrange(inverted_HR) %>%
- pull(biomarker_name)
- # Function to generate a combined forest plot using a specified biomarker ordering.
- make_forest_plot <- function(biomarker_order) {
- # Prepare data for plotting.
- plot_data <- inverted_univariable_aging_biomarker_results %>%
- filter(!is.na(inverted_HR)) %>%
- mutate(
- # Classify associations according to statistical significance
- # and direction of the original hazard ratio.
- effect_direction = case_when(
- adj_p_benjamini > 0.05 ~ "Not significant",
- HR < 1 ~ "Negative",
- HR >= 1 ~ "Positive"
- ),
- biomarker_name = str_replace_all(biomarker_name, "_", " "),
- biomarker_name = factor(
- biomarker_name,
- levels = str_replace_all(biomarker_order, "_", " ")
- ),
- # Define the display order for the three Cox models.
- model = factor(
- model,
- levels = c(
- "demographics",
- "demographics_lifestyle",
- "demographics_lifestyle_diseases"
- )
- ),
- model_for_dodge = factor(
- model,
- levels = rev(c(
- "demographics",
- "demographics_lifestyle",
- "demographics_lifestyle_diseases"
- ))
- )
- )
- # Create Markdown-formatted labels for bold organ age gaps.
- y_labels_md <- sapply(levels(plot_data$biomarker_name), function(x) {
- if (x %in% bold_labels) {
- paste0("**", x, "**")
- } else {
- x
- }
- })
- names(y_labels_md) <- levels(plot_data$biomarker_name)
- # Generate the combined forest plot.
- p_all_models <- ggplot(
- plot_data,
- aes(
- x = inverted_HR,
- y = biomarker_name,
- shape = model,
- group = model_for_dodge
- )
- ) +
- geom_errorbarh(
- aes(
- xmin = inverted_lower_95CI,
- xmax = inverted_upper_95CI,
- colour = effect_direction
- ),
- height = 0.15,
- linewidth = 0.8,
- position = position_dodge(width = 0.8)
- ) +
- geom_point(
- aes(
- fill = effect_direction
- ),
- size = 3.5,
- colour = "black",
- stroke = 1,
- position = position_dodge(width = 0.8)
- ) +
- scale_fill_manual(
- values = c(
- "Not significant" = "grey",
- "Positive" = "#FFA69E",
- "Negative" = "#5EC1C0"
- ),
- name = "Association"
- ) +
- scale_colour_manual(
- values = c(
- "Not significant" = "grey",
- "Positive" = "#FFA69E",
- "Negative" = "#5EC1C0"
- ),
- guide = "none"
- ) +
- scale_shape_manual(
- values = c(
- "demographics" = 16,
- "demographics_lifestyle" = 17,
- "demographics_lifestyle_diseases" = 4
- ),
- labels = c(
- "Age + sex",
- "Age + sex + lifestyle",
- "Age + sex + lifestyle + diseases"
- ),
- name = "Model"
- ) +
- geom_vline(
- xintercept = 1,
- linetype = "dashed",
- linewidth = 0.8
- ) +
- labs(
- x = "Hazard ratio (95% CI)",
- y = ""
- ) +
- scale_x_continuous(
- limits = c(0.8, 1.8),
- breaks = seq(0.8, 1.8, by = 0.2)
- ) +
- scale_y_discrete(
- labels = y_labels_md
- ) +
- guides(
- fill = guide_legend(
- override.aes = list(
- shape = 21,
- colour = "black",
- size = 4
- )
- ),
- shape = guide_legend(
- override.aes = list(
- fill = "white",
- colour = "black",
- size = 4
- )
- )
- ) +
- theme_classic(base_size = 20) +
- theme(
- axis.ticks = element_line(color = "black"),
- panel.grid = element_blank(),
- panel.border = element_blank(),
- axis.line = element_line(color = "black"),
- legend.position = "right",
- legend.box = "vertical",
- legend.title = element_text(size = 20),
- legend.text = element_text(size = 18),
- axis.text.y = element_markdown(size = 20),
- axis.text.x = element_text(size = 20)
- )
- return(p_all_models)
- }
- # Generate combined forest plot.
- p_demographics <- make_forest_plot(
- biomarker_order_demographics)
- # Save the combined forest plot.
- ggsave(
- file.path(
- OUT_DIR,
- "forest_plot_ageing_biomarkers_demographics_order.png"
- ),
- p_demographics,
- width = 14,
- height = 16,
- dpi = 600
- )
- ggsave(
- file.path(
- OUT_DIR,
- "forest_plot_ageing_biomarkers_demographics_order.pdf"
- ),
- p_demographics,
- width = 14,
- height = 16
- )
- # ---------------------------
- # 11. Compare log(HR) correlation between the full sample and the 460-subject common sample
- # ---------------------------
- # Load Cox results from full sample and 460-subject common sample.
- publication_results_all_subjects <- read_csv("/CCACE_Shared/Maira/OrganAgeProject/Univariate_aging_biomarkers_mortality_cox/inverted_univariable_aging_biomarker_publication_results_all_subjects.csv")
- publication_results_common_subjects <- read_csv("/CCACE_Shared/Maira/OrganAgeProject/Univariate_aging_biomarkers_mortality_cox/inverted_univariable_aging_biomarker_publication_results_460subjects.csv")
- # Restrict the full-sample results to the demographic-adjusted model.
- publication_results_all_subjects <- publication_results_all_subjects %>%
- filter(model == "demographics")
- # Calculate log(HR) for the full sample.
- publication_results_all_subjects <- publication_results_all_subjects %>%
- mutate(logHR = log(HR))
- # Calculate log(HR) for the common sample.
- publication_results_common_subjects <- publication_results_common_subjects %>%
- mutate(logHR = log(HR))
- # Match biomarker estimates between the two datasets.
- merged_df <- publication_results_all_subjects %>%
- select(biomarker_name, logHR_all = logHR) %>%
- inner_join(
- publication_results_common_subjects %>%
- select(biomarker_name, logHR_common = logHR),
- by = "biomarker_name"
- )
- View(merged_df)
- # Calculate the Pearson correlation between log(HR) estimates across the two sample definitions.
- cor_test <- cor.test(
- merged_df$logHR_all,
- merged_df$logHR_common,
- method = "pearson"
- )
- cor_test
- # Compute symmetric axis limits for the correlation plot.
- x_min <- min(merged_df$logHR_all, merged_df$logHR_common, na.rm = TRUE)
- x_max <- max(merged_df$logHR_all, merged_df$logHR_common, na.rm = TRUE)
- axis_limit <- max(abs(x_min), abs(x_max))
- axis_limit <- ceiling(axis_limit * 2) / 2
- # Generate the correlation plot.
- r_plot <- ggplot(merged_df, aes(x = logHR_all, y = logHR_common)) +
- geom_vline(xintercept = 0, color = "black", linewidth = 0.8) +
- geom_hline(yintercept = 0, color = "black", linewidth = 0.8) +
- geom_point(shape = 21,
- fill = "#1E7AB5",
- color = "black",
- size = 4.5,
- stroke = 0.8,
- alpha = 0.9) +
- # Automatically position labels for most biomarkers.
- geom_text_repel(
- data = filter(merged_df,
- !biomarker_name %in% c("MRI_brain_age_gap", "Six_meter_walk_time")),
- aes(label = gsub("_", " ", biomarker_name)),
- size = 4.5,
- max.overlaps = Inf,
- box.padding = 1.0,
- point.padding = 0.3,
- force = 2,
- force_pull = 1,
- min.segment.length = 0,
- segment.color = "grey60",
- segment.size = 0.4,
- segment.alpha = 0.9,
- seed = 42
- ) +
- # Manually adjust the labels for two overlapping biomarkers.
- geom_text_repel(
- data = filter(merged_df,
- biomarker_name %in% c("MRI_brain_age_gap", "Six_meter_walk_time")),
- aes(label = gsub("_", " ", biomarker_name)),
- size = 4.5,
- max.overlaps = Inf,
- box.padding = 1.0,
- point.padding = 0.3,
- force = 2,
- force_pull = 1,
- min.segment.length = 0,
- segment.color = "grey60",
- segment.size = 0.4,
- segment.alpha = 0.9,
- nudge_x = 0.15,
- nudge_y = 0.15,
- seed = 42
- ) +
- geom_abline(slope = 1, intercept = 0,
- linetype = "dashed",
- color = "grey50",
- linewidth = 0.8) +
- scale_x_continuous(limits = c(-axis_limit, axis_limit),
- expand = expansion(mult = c(0, 0.05))) +
- scale_y_continuous(limits = c(-axis_limit, axis_limit),
- expand = expansion(mult = c(0, 0.05))) +
- coord_equal() +
- theme_bw(base_size = 20) +
- theme(
- panel.grid.major = element_line(color = "grey95"),
- panel.grid.minor = element_line(color = "grey95"),
- axis.line = element_line(color = "black"),
- axis.ticks = element_line(color = "black"),
- plot.title = element_blank(),
- axis.text = element_text(size = 20),
- axis.title = element_text(size = 20)
- ) +
- labs(
- x = "log(HR) for maximum sample size",
- y = "log(HR) for common sample size"
- )
- # Save the correlation plot.
- ggsave(filename = file.path(OUT_DIR, "correlation_of_biomarkerlogHRs_on_all_vs_common_subjects.png"),
- plot = r_plot, width = 10, height = 10, dpi = 600)
- ggsave(filename = file.path(OUT_DIR, "correlation_of_biomarkerlogHRs_on_all_vs_common_subjects.pdf"),
- plot = r_plot, width = 10, height = 10, dpi = 600)
2_Cox_Mortality_Associations_of_Individual_Ageing_Biomarkers.R at commit d7bc5df, under GPL-3.0 · at the source
Overview
- Lothian Birth Cohorts, Edinburgh Futures Institute, The University of Edinburgh, Edinburgh, EH3 9EF, UK
- Lothian Birth Cohorts, Department of Psychology, The University of Edinburgh, Edinburgh, EH8 9JZ, UK
- Institute of Genetics and Cancer, The University of Edinburgh, Edinburgh, EH4 2XU, UK
- Institute for Neuroscience and Cardiovascular Research, The University of Edinburgh, Edinburgh, UK
- Scottish Imaging Network, A Platform for Scientific Excellence (SINAPSE) Collaboration, Edinburgh, UK
- Row Fogo Centre for Research into Small Vessel Diseases, Edinburgh, UK
- Alzheimer Scotland Dementia Research Centre, The University of Edinburgh, Edinburgh, UK
- Dementia Network, NHS Research Scotland, Edinburgh, UK
- UK Dementia Research Institute, BHF-UK DRI Centre for Vascular Dementia Research, Edinburgh, UK
- Department of Clinical and Biomedical Sciences, University of Exeter Medical School, University of Exeter, Barrack Road, RILD Building, Royal Devon & Exeter Hospital, Barrack Road, Exeter, Devon, EX2 5DW, UK
- Laboratory of Behavioral Neuroscience, National Institute on Aging, Baltimore, MD, 21224, USA
- Department of Psychology, The University of Texas, Austin, TX 78712, United States
Abstract
Ageing biomarkers can predict mortality risk beyond chronological age. Recently, plasma proteins were used to estimate the biological ages of eleven human organs, including the brain, heart, liver, kidneys, and pancreas. Accelerated organ ageing is linked to higher all-cause mortality; however, systematic benchmarking against established ageing biomarkers is lacking. Here, we pursued two complementary aims. First, we benchmarked proteomic organ ages against multimodal ageing biomarkers for all-cause mortality (444 deaths; ≤17-year follow-up) using Cox regression in 861 Lothian Birth Cohort 1936 (LBC1936) participants. Ageing biomarkers included epigenetic age (GrimAge2), telomere length, neuroimaging, general cognitive function (g), and physical function (grip strength, walk time, and respiratory function). Among proteomic organ ageing biomarkers, accelerated liver (HRperSD [95%CI] = 1.43 [1.30–1.58]), immune (1.42 [1.29–1.57]), and heart (1.38 [1.25–1.53]) ageing were most strongly associated with higher mortality risk. However, GrimAge2 acceleration, total brain volume (TBV), grey matter volume, respiratory function, and g exhibited higher hazard estimates (HRperSD = 1.44–1.62) than organ ageing biomarkers. In a Cox model including all biomarkers, only TBV, white matter hyperintensity volume, g, and walk time associated with mortality. Second, survival analyses of SomaScan 11K plasma proteins identified 202 proteins associated with mortality and enriched for the liver and immune-related biological processes, with the strongest effects observed for GDF15 (HRperSD [95%CI] = 1.53 [1.37–1.72]), CST3 (1.48 [1.29–1.69]), and COL18A1 (1.47 [1.30–1.68]). These findings provide a systematic, cross-modal benchmarking of proteomic organ ages against established ageing biomarkers and highlight plasma proteomic signatures of mortality.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 19 matches between paragraphs and lines of code.
marioni-group/Mortality_Biomarkers_LBC1936
d7bc5df2cd5060660bf084e56a843740320cb4c8, 31 August 2026Availability: 1 check, the latest on 30 September 2026: the link answers
- 30 September 2026: the link answers
10 files
- 1_Ageing_Biomarker_Corre
lations.R , R, 136 lines, 1 match - 2_Cox_Mortality_Associat
ions_of_Individual_Agein , R, 931 lines, 4 matchesg_Biomarkers.R - 3_Cox_Mortality_Associat
ions_of_All_Ageing_Bioma , R, 307 lines, 4 matchesrkers.R - 4_Cox_Mortality_Associat
ions_of_SomaScan11k_Plas , R, 834 lines, 3 matchesma_Proteins.R - 5_GSEA_mortality_plasma_
proteins.R , R, 418 lines - 6_Mortality_Elastic_Net_
Cox_for_SomaScan11k_Plas , R, 176 lines, 2 matchesma_Proteins.R - 7_G_score.R, R, 154 lines, 3 matches
- 8_Calculating_OrganAgeGa
ps_LBC1936.R , R, 431 lines, 2 matches - LICENSE, License, 674 lines
- README.md, Text, 56 lines
lothianbirthcohorts.github.io/longitudinal-g-models
Availability: 1 check, the latest on 30 September 2026: the link answers (HTTP 200)
- 30 September 2026: the link answers (HTTP 200)
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 8 scripts, each with its path and the digest of its content;
- 19 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Data Availability Statement
All data produced in the present study are reported in Supplementary Tables. The code used for analyses is openly accessible at the following GitHub repository: https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 30 September 2026: the first record
Recorded: type, language, journal, dates, 15 authors, 2 funders, 127 references.
Cite
This paper
Pyrgioti, M., Eguiagaray, I. M., Redmond, P., Corley, J., Bastin, M. E., Hernández, M. V., Russ, T. C., Wardlaw, J. M., Hannon, E., Deary, I. J., Walker, K. A., Tucker-Drob, E. M., Cox, S. R., Marioni, R. E., & Harris, S. E. (2026). Multimodal Ageing Biomarkers and Plasma Proteomic Signatures Associated with All-Cause Mortality. medRxiv (preprint). https://
BibTeX
@article{pyrgioti2026mul
author = {Pyrgioti, Maira and Eguiagaray, Ines Mesa and Redmond, Paul and Corley, Janie and Bastin, Mark E. and Hernández, Maria Valdés and Russ, Tom C. and Wardlaw, Joanna M. and Hannon, Eilis and Deary, Ian J. and Walker, Keenan A. and Tucker-Drob, Elliot M. and Cox, Simon R. and Marioni, Riccardo E. and Harris, Sarah E.},
title = {{Multimodal Ageing Biomarkers and Plasma Proteomic Signatures Associated with All-Cause Mortality}},
journal = {medRxiv (preprint)},
year = {2026},
month = mar,
publisher = {medRxiv},
doi = {10.64898/
url = {https://
}
RIS
TY - JOUR
AU - Pyrgioti, Maira
AU - Eguiagaray, Ines Mesa
AU - Redmond, Paul
AU - Corley, Janie
AU - Bastin, Mark E.
AU - Hernández, Maria Valdés
AU - Russ, Tom C.
AU - Wardlaw, Joanna M.
AU - Hannon, Eilis
AU - Deary, Ian J.
AU - Walker, Keenan A.
AU - Tucker-Drob, Elliot M.
AU - Cox, Simon R.
AU - Marioni, Riccardo E.
AU - Harris, Sarah E.
TI - Multimodal Ageing Biomarkers and Plasma Proteomic Signatures Associated with All-Cause Mortality
T2 - medRxiv (preprint)
J2 - medRxiv
PY - 2026
DA - 2026/
PB - medRxiv
DO - 10.64898/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.64898/
"type": "article",
"title": "Multimodal Ageing Biomarkers and Plasma Proteomic Signatures Associated with All-Cause Mortality",
"container-title": "medRxiv (preprint)",
"author": [
{
"family": "Pyrgioti",
"given": "Maira"
},
{
"family": "Eguiagaray",
"given": "Ines Mesa"
},
{
"family": "Redmond",
"given": "Paul"
},
{
"family": "Corley",
"given": "Janie"
},
{
"family": "Bastin",
"given": "Mark E."
},
{
"family": "Hernández",
"given": "Maria Valdés"
},
{
"family": "Russ",
"given": "Tom C."
},
{
"family": "Wardlaw",
"given": "Joanna M."
},
{
"family": "Hannon",
"given": "Eilis"
},
{
"family": "Deary",
"given": "Ian J."
},
{
"family": "Walker",
"given": "Keenan A."
},
{
"family": "Tucker-Drob",
"given": "Elliot M."
},
{
"family": "Cox",
"given": "Simon R."
},
{
"family": "Marioni",
"given": "Riccardo E."
},
{
"family": "Harris",
"given": "Sarah E."
}
],
"container-title-short":
"DOI": "10.64898/
"publisher": "medRxiv",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
10
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.3390/ijms27156925 [code]
- XGBoost-SHAP Interpretable Modeling Identifies and Validates an Eight-Gene Biomarker for Hepatic Encephalopathy Risk Prediction in Cirrhosis.Journal: International journal of molecular sciencesIn common: lavaan, glmnet, survival, 6 other tools, genetics / omics, 1 reference
- [2] doi:10.1016/j.isci.2026.115657 [code]
- Integration of machine learning to develop a disulfidptosis model for predicting glioma prognosis, immunotherapy response, and drug.Journal: iScienceIn common: glmnet, survival, broom, 6 other tools, clinical / translational
- [3] doi:10.1016/j.xcrm.2026.102682 [code]
- TET CpG sequence-context-specifi
c DNA demethylation shapes progression of IDH-mutant gliomas. Journal: Cell reports. MedicineIn common: glmnet, survival, broom, 6 other tools, genetics / omics - [4] doi:10.1038/s42003-026-10957-8 [code]
- Brain defence by the extracellular matrix protein Cochlin.Journal: Communications biologyIn common: glmnet, survival, broom, 6 other tools
- [5] doi:10.1136/svn-2024-003690 [code]
- Associations of accelerated biological ageing with incident dementia, cognitive functions and brain structure: a prospective cohort study based on UK Biobank.Journal: Stroke and vascular neurologyIn common: survival, broom, ggplot2, 1 other tool, clinical / translational, 4 references
- [6] doi:10.1038/s41467-026-71682-8 [code]
- GWAS meta-analysis of cerebrospinal fluid Alzheimer's biomarkers reveals loci regulating lipids, brain volume and autophagy.Journal: Nature communicationsIn common: clusterProfiler, reshape2, data.table, 2 other tools, structural MRI / diffusion, genetics / omics, author Riccardo E Marioni
- [7] doi:10.3390/ijms27093997 [code]
- Coordinated Multicellular Immune Programs and Drug Targets Revealed by Single-Cell Analysis in Driver-Mutated NSCLC.Journal: International journal of molecular sciencesIn common: glmnet, survival, clusterProfiler, 5 other tools, genetics / omics
- [8] doi:10.1038/s41514-026-00456-9 [code]
- Exploring the link between body physiology and cognition: the role of the brain and aging.Journal: npj agingIn common: lavaan, data.table, ggplot2, 1 other tool, 4 references
- [9] doi:10.1038/s41514-026-00391-9 [code]
- Region-specific transcriptional signatures of brain aging in the absence of neuropathology at the single-cell level.Journal: npj agingIn common: broom, reshape2, ggpubr, 3 other tools, genetics / omics, 3 references
- [10] doi:10.1016/j.isci.2026.116439 [code]
- Decoding the role of transcriptomic clocks in the human prefrontal cortex.Journal: iScienceIn common: glmnet, reshape2, data.table, 2 other tools, genetics / omics, 3 references
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 2 repositories of the authors' code, each at its verified commit and with its license, 8 scripts, and 19 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:9586f7a2aae68591…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
