12  Interpreting the integration results

library(targets)
library(moiraine)

## For working with lists
library(purrr)

## For data-frames manipulation
library(dplyr)

## For colour palettes
library(ggplot2)
library(circlize)

## For manipulating patchworks of plots
library(patchwork)

In the previous chapters, we have applied different integration tools to our example multi-omics dataset. In each of these chapters, we have shown some method-specific visualisations that could be used to interpret the integration results. With the moiraine package, it is possible to use method-agnostic functions to inspect and interpret these results. These functionalities make use of the metadata in the MultiDataSet object to enrich plots and other summary outputs with information about the samples and the omics features, and allow users to obtain consistent visualisations across the integration methods used.

_targets.R script
library(targets)
library(tarchetypes)
library(moiraine)

tar_option_set(
  packages = c(
    "moiraine",
    "MOFA2",
    "mixOmics",
    "readr",
    "tibble",
    "tidyr",
    "dplyr",
    "ggplot2",
    "patchwork"
  )
)

list(
# Importing data ---------------------------------------------------------------

  ## Data import using a target factory
  import_dataset_csv_factory(
    files = c(
      system.file("extdata/genomics_dataset.csv", package = "moiraine"),
      system.file("extdata/transcriptomics_dataset.csv", package = "moiraine"),
      system.file("extdata/metabolomics_dataset.csv", package = "moiraine")
    ),
    col_ids = c("marker", "gene_id", "sample_id"),
    features_as_rowss = c(TRUE, TRUE, FALSE),
    target_name_suffixes = c("geno", "transcripto", "metabo")
  ),
  
  ## Genomics features metadata file
  tar_target(
    fmetadata_file_geno,
    system.file("extdata/genomics_features_info.csv", package = "moiraine"),
    format = "file"
  ),
  
  ## Genomics features metadata import
  tar_target(
    fmetadata_geno,
    import_fmetadata_csv(
      fmetadata_file_geno,
      col_id = "marker",
      col_types = c("chromosome" = "c")
    )
  ),
  
  ## Metabolomics features metadata import
  import_fmetadata_csv_factory(
    files = c(
      system.file("extdata/metabolomics_features_info.csv", package = "moiraine")
    ),
    col_ids = c("feature_id"),
    target_name_suffixes = c("metabo")
  ),
  
  ## Transcriptomics features metadata import
  import_fmetadata_gff_factory(
    files = system.file("extdata/bos_taurus_gene_model.gff3", package = "moiraine"),
    feature_types = "genes",
    add_fieldss = c("Name", "description"),
    target_name_suffixes = "transcripto"
  ),
  
  ## Samples metadata import
  import_smetadata_csv_factory(
    files = system.file("extdata/samples_info.csv", package = "moiraine"),
    col_ids = "animal_id",
    target_name_suffixes = "all"
  ),
  
  ## Creating omics sets for each dataset
  create_omics_set_factory(
    datasets = c(data_geno, data_transcripto, data_metabo),
    omics_types = c("genomics", "transcriptomics", "metabolomics"),
    features_metadatas = c(fmetadata_geno, fmetadata_transcripto, fmetadata_metabo),
    samples_metadatas = c(smetadata_all, smetadata_all, smetadata_all)
  ),
  
  ## Creating the MultiDataSet object
  tar_target(
    mo_set,
    create_multiomics_set(
      list(set_geno,
           set_transcripto,
           set_metabo)
    )
  ),

# Inspecting the `MultiDataSet` object -----------------------------------------

  ## Creating a density plot for each dataset
  tar_target(
    density_plots,
    plot_density_data(
      mo_set,
      combined = FALSE,
      scales = "free"
    )
  ),

  ## Plotting the relationship between features mean and standard deviation
  ## for each dataset
  tar_target(
    mean_sd_plots,
    plot_meansd_data(mo_set)
  ),
  
  ## Assessing missing values
  tar_target(
    n_missing_values,
    check_missing_values(mo_set)
  ),

# Modifying the `MultiDataSet` object ------------------------------------------

  ## RNAseq differential expression results file
  tar_target(
    rnaseq_de_res_file,
    system.file(
      "extdata/transcriptomics_de_results.csv",
      package = "moiraine"
    ),
    format = "file"
  ),

  ## Reading the RNAseq differential expression results
  tar_target(
    rnaseq_de_res_df,
    read_csv(rnaseq_de_res_file) |>
      rename(feature_id = gene_id) |>
      mutate(dataset = "rnaseq")
  ),

  ## Adding the differential expression results to the MultiDataSet object
  tar_target(
    mo_set_de,
    add_features_metadata(mo_set, rnaseq_de_res_df)
  ),

# Data pre-processing ----------------------------------------------------------

  ## Applying transformations to the datasets
  transformation_datasets_factory(
    mo_set_de,
    c("rnaseq" = "vst-deseq2",
      "metabolome" = "logx"),
    log_bases = 2,
    pre_log_functions = zero_to_half_min,
    transformed_data_name = "mo_set_transformed"
  ),
  
  ## Density plot for each transformed dataset
  tar_target(
    density_plots_transformed,
    plot_density_data(
      mo_set_transformed,
      combined = FALSE,
      scales = "free"
    )
  ),
  
  ## Plotting the mean-SD trend for transformed each dataset
  tar_target(
    mean_sd_plots_transformed,
    plot_meansd_data(mo_set_transformed)
  ),
  
  ## Summary table of the transformations applied
  tar_target(
    transformation_summary,
    get_table_transformations(transformations_runs_list)
  ),
  
  ## Running a PCA on each dataset
  pca_complete_data_factory(
    mo_set_transformed,
    complete_data_name = "mo_set_complete"
  ),
  
  ## PCA screeplots
  tar_target(
    pca_screeplots,
    plot_screeplot_pca(pca_runs_list)
  ),
  
  ## PCA sample plots
  tar_target(
    pca_sample_plots,
    plot_samples_coordinates_pca(
      pca_runs_list,
      datasets = "snps",
      pcs = 1:3,
      mo_data = mo_set_de,
      colour_upper = "geno_comp_cluster",
      shape_upper = "status",
      colour_lower = "feedlot"
    )
  ),

# Dataset pre-filtering --------------------------------------------------------

  ## Unsupervised feature selection based on MAD score
  feature_preselection_mad_factory(
    mo_set_complete,
    to_keep_ns = c("snps" = 1000, "rnaseq" = 1000),
    with_ties = TRUE,
    filtered_set_target_name = "mo_presel_unsupervised"
  ),
  
  ## Diagnostic plot for MAD-based feature selection
  tar_target(
    preselection_mad_plot,
    plot_feature_preselection_mad(individual_mad_values)
  ),
  
  ## Supervised feature selection based on bruising groups
  feature_preselection_splsda_factory(
    mo_set_complete,
    group = "status",
    to_keep_ns = c("snps" = 1000, "rnaseq" = 1000),
    filtered_set_target_name = "mo_presel_supervised"
  ),
  
  ## Diagnostic plot for sPLS-DA based feature selection
  tar_target(
    preselection_splsda_plot,
    plot_feature_preselection_splsda(individual_splsda_perf)
  ),

# Integration with sPLS --------------------------------------------------------

  ## Creating sPLS input
  tar_target(
    spls_input,
    get_input_spls(
      mo_presel_supervised,
      mode = "canonical",
      datasets = c("rnaseq", "metabolome")
    )
  ),
  
  ## Initial PLS run with no feature selection and large number of components
  tar_target(
    spls_novarsel,
    spls_run(
      spls_input,
      ncomp = 4
    )
  ),
  
  ## Cross-validation for number of components
  tar_target(
    spls_perf_res,
    mixOmics::perf(
      spls_novarsel,
      validation = "Mfold",
      folds = 10,
      nrepeat = 10,
      cpus = 3
    )
  ),
  
  ## Plotting cross-validation results (for number of components)
  ## Can try criterion = 'Q2.total', 'cor.tpred', 'cor.upred', 'RSS.tpred',
  ## 'RSS.upred' (but avoid 'RSS' and 'PRESS')
  tar_target(
    spls_perf_plot,
    plot(spls_perf_res, criterion = "Q2.total")
  ),
  
  ## Selected value for ncomp
  tar_target(
    spls_optim_ncomp,
    spls_get_optim_ncomp(spls_perf_res, min_ncomp = 2)
  ),
  
  ## Cross-validation for number of features to retain
  tar_target(
    spls_tune_res,
    spls_tune(
      spls_input,
      ncomp = spls_optim_ncomp,
      keepX = seq(10, 100, 10),
      keepY = seq(10, 100, 10),
      validation = "Mfold",
      folds = 10,
      nrepeat = 5,
      measure = "cor",
      cpus = 3
    )
  ),
  
  ## Plotting cross-validation results (for number of features)
  tar_target(
    spls_tune_plot,
    spls_plot_tune(spls_tune_res)
  ),
  
  ## Final sPLS run
  tar_target(
    spls_final_run,
    spls_run(
      spls_input,
      ncomp = spls_optim_ncomp,
      keepX = spls_tune_res$choice.keepX,
      keepY = spls_tune_res$choice.keepY
    )
  ),

# Integration with sO2PLS ------------------------------------------------------

  ## Creating sO2PLS input
  tar_target(
    omicspls_input,
    get_input_omicspls(
      mo_presel_supervised,
      datasets = c("rnaseq", "metabolome")
    )
  ),
  
  ## Adjusted cross-validation for number of components
  tar_target(
    so2pls_cv_adj,
    so2pls_crossval_o2m_adjR2(
      omicspls_input,
      a = 1:5,
      ax = seq(0, 10, by = 2),
      ay = seq(0, 10, by = 2),
      nr_folds = 10,
      nr_cores = 6,
      seed = 127
    )
  ),
  tar_target(
    so2pls_cv_adj_res,
    so2pls_get_optim_ncomp_adj(so2pls_cv_adj)
  ),
  
  ## Plotting adjusted cross-validation results
  tar_target(
    so2pls_cv_adj_plot,
    so2pls_plot_cv_adj(so2pls_cv_adj)
  ),
  
  ## Standard cross-validation for number of components
  tar_target(
    so2pls_cv,
    so2pls_crossval_o2m(
      omicspls_input,
      so2pls_cv_adj,
      nr_folds = 10,
      nr_cores = 6,
      seed = 356
    )
  ),
  tar_target(
    so2pls_cv_res,
    so2pls_get_optim_ncomp(so2pls_cv)
  ),
  
  ## Plotting standard cross-validation results
  tar_target(
    so2pls_cv_plot,
    so2pls_plot_cv(so2pls_cv)
  ),
  
  ## Cross-validation for sparsity parameters
  tar_target(
    so2pls_cv_sparsity,
    so2pls_crossval_sparsity(
      omicspls_input,
      n = so2pls_cv_res["n"],
      nx = so2pls_cv_res["nx"],
      ny = so2pls_cv_res["ny"],
      nr_folds = 10,
      keepx_seq = c(seq(5, 30, 5), seq(40, 100, 10)),
      keepy_seq = c(seq(5, 40, 5))
    )
  ),
  tar_target(
    so2pls_cv_sparsity_res,
    so2pls_get_optim_keep(so2pls_cv_sparsity)
  ),
  
  ## Plotting the results of the cross-validation for the number of features
  ## to retain from each dataset for the different joint components
  tar_target(
    so2pls_cv_sparsity_plot,
    so2pls_plot_cv_sparsity(so2pls_cv_sparsity)
  ),
  
  ## Extracting sparsity results in table format
  tar_target(
    so2pls_cv_sparsity_table,
    so2pls_print_cv_sparsity(so2pls_cv_sparsity_res)
  ),
  
  ## Final sO2PLS run
  tar_target(
    so2pls_final_run,
    so2pls_o2m(
      omicspls_input,
      so2pls_cv_res,
      so2pls_cv_sparsity_res
    )
  ),
  
  ## Summary plot of percentage of variance explained
  tar_target(
    so2pls_summary_plot,
    so2pls_plot_summary(so2pls_final_run)
  ),
  
  ## Screeplot
  tar_target(
    so2pls_screeplot,
    so2pls_screeplot(so2pls_final_run)
  ),
  
  ## Comparison of samples score for joint components
  tar_target(
    so2pls_joint_components_comparison_plot,
    so2pls_compare_samples_joint_components(
      so2pls_final_run,
      mo_data = mo_set_de,
      colour_by = "status",
      shape_by = "feedlot"
    )
  ),
  
  ## Coefficient plot for joint components
  tar_target(
    so2pls_joint_components_coefficients_plot,
    so2pls_plot_joint_components_coefficients(so2pls_final_run)
  ),
  
  ## Joint component samples score plot
  tar_target(
    so2pls_joint_components_samples_score_plot,
    so2pls_plot_samples_joint_components(
      so2pls_final_run,
      mo_data = mo_set_de,
      colour_upper = "status",
      scale_colour_upper = scale_colour_brewer(palette = "Paired"),
      shape_upper = "feedlot"
    ) +
      theme(legend.box = "vertical")
  ),
  
  ## Specific components samples score plot
  tar_target(
    so2pls_specific_components_samples_score_plot,
    so2pls_plot_samples_specific_components(
      so2pls_final_run,
      mo_data = mo_set_de,
      colour_upper = "feedlot",
      scale_colour_upper = scale_colour_brewer(palette = "Paired"),
      colour_lower = "rnaseq_batch",
      shape_upper = "gender"
    ) |> 
      map(\(x) x + theme(legend.box = "vertical"))
  ),

# Integration with MOFA --------------------------------------------------------

  ## Creating MOFA input
  tar_target(
    mofa_input,
    get_input_mofa(
      mo_presel_supervised,
      options_list = list(
        data_options = list(scale_views = TRUE),
        model_options = list(likelihoods = c(
          "snps" = "poisson",
          "rnaseq" = "gaussian",
          "metabolome" = "gaussian")
        ),
        training_options = list(seed = 43)
      ),
      only_common_samples = FALSE
    )
  ),
  
  ## Overview plot of the samples in each dataset
  tar_target(
    mofa_input_plot,
    plot_data_overview(mofa_input)
  ),
  
  ## Training MOFA model
  tar_target(
    mofa_trained,
    run_mofa(
      mofa_input,
      save_data = TRUE,
      use_basilisk = TRUE
    )
  ),
  
  ## Formatting MOFA output
  tar_target(
    mofa_output,
    get_output(mofa_trained)
  ),
  
  ## Plots of variance explained
  tar_target(
    mofa_var_explained_plot,
    plot_variance_explained(
      mofa_trained,
      x = "view",  ## datasets on the x-axis
      y = "factor" ## factors on the y-axis
    )
  ),
  tar_target(
    mofa_total_var_explained_plot,
    plot_variance_explained(
      mofa_trained,
      x = "view",
      y = "factor",
      plot_total = TRUE
    )[[2]]
  ),
  
  ## Plot of factors correlation with covariates
  tar_target(
    mofa_factors_covariates_cor_plot,
    mofa_plot_cor_covariates(mofa_trained)
  ),

# Integration with DIABLO ------------------------------------------------------

  ## Creating the DIABLO input
  tar_target(
    diablo_input,
    get_input_mixomics_supervised(
      mo_presel_supervised,
      group = "status"
    )
  ),
  
  ## Running sPLS on each dataset to construct the design matrix
  diablo_pairwise_pls_factory(diablo_input),
  
  ## Initial DIABLO run with no feature selection and large number of components
  tar_target(
    diablo_novarsel,
    diablo_run(
      diablo_input,
      diablo_design_matrix,
      ncomp = 7
    )
  ),
  
  ## Cross-validation for number of components
  tar_target(
    diablo_perf_res,
    mixOmics::perf(
      diablo_novarsel,
      validation = "Mfold",
      folds = 10,
      nrepeat = 10,
      cpus = 3
    )
  ),
  
  ## Plotting cross-validation results (for number of components)
  tar_target(
    diablo_perf_plot,
    diablo_plot_perf(diablo_perf_res)
  ),
  
  ## Selected value for ncomp
  tar_target(
    diablo_optim_ncomp,
    diablo_get_optim_ncomp(diablo_perf_res)
  ),
  
  ## Cross-validation for number of features to retain
  tar_target(
    diablo_tune_res,
    diablo_tune(
      diablo_input,
      diablo_design_matrix,
      ncomp = diablo_optim_ncomp,
      validation = "Mfold",
      folds = 10,
      nrepeat = 5,
      dist = "centroids.dist",
      cpus = 3
    )
  ),
  
  ## Plotting cross-validation results (for number of features)
  tar_target(
    diablo_tune_plot,
    diablo_plot_tune(diablo_tune_res)
  ),
  
  ## Final DIABLO run
  tar_target(
    diablo_final_run,
    diablo_run(
      diablo_input,
      diablo_design_matrix,
      ncomp = diablo_optim_ncomp,
      keepX = diablo_tune_res$choice.keepX
    )
  )
)

12.1 Dimension reduction methods

Despite relying on very different statistical approaches, the different integration methods included in the pipeline all perform dimension reduction of the omics datasets through feature extraction. That is, they construct a small number of latent components/variables/dimensions (that we refer to as latent dimensions in the moiraine package) that capture as much information from the original datasets as possible. A dimension reduction approach typically returns, for each latent dimension constructed, two sets of values:

  • Features weight: the contribution of the features from the different omics datasets to the latent dimension. All methods included in the pipeline construct latent dimensions as linear combinations of the original features, and therefore the features contribution is quantified by their weight in the linear combination for the corresponding latent dimension.

  • Samples score: the projection of the samples onto the latent dimension.

In addition, the fraction or percentage of variance that each latent dimension explains in the different omics datasets is usually calculated.

Interpreting the results of a dimension reduction method involves:

  • Understanding the source of the variation captured by each latent dimension: is a given latent dimension representing an important source of biological variation, such as effect of a treatment, or age of the samples? Or do they show a source of technical variation, for example highlighting a group of outlier samples with different omics profiles from the rest of the observations? Answering these questions allows us to identify which latent dimensions capture the biological phenomenon investigated, or whether there are some sources of noise that should be accounted for in follow-up experiments.

  • Investigating which omics features are driving the latent dimensions: once we have identified some latent dimensions of interest, we can look at the features that contribute the most to these dimensions, in order to understand the molecular mechanisms or pathways involved. This is typically done after looking into the phenomenon captured by the latent dimensions, but can also help to identify it.

12.2 Generating a standardised output

12.2.1 get_output function

In the moiraine package, the output of the different integration methods can be converted to a standardised output containing the pieces of information (features weight, samples score and percentage of variance explained) characteristic of dimension reduction methods, stored in a consistent format. This enables us to use functions for visualisation or analysis that can be applied to the results of any integration method, rather than having to implement one for each object type returned by the different integration packages.

The get_output() function transforms the output from any integration package included in moiraine into an output_dimension_reduction object, which is a list with three tibbles: features_weight, samples_score and variance_explained:

tar_target(
  spls_output,
  get_output(spls_final_run)
)
tar_load(spls_output)
spls_output
#> $features_weight
#> # A tibble: 2,098 × 5
#>    feature_id         dataset latent_dimension weight importance
#>    <chr>              <fct>   <fct>             <dbl>      <dbl>
#>  1 ENSBTAG00000000020 rnaseq  Component 1           0          0
#>  2 ENSBTAG00000000046 rnaseq  Component 1           0          0
#>  3 ENSBTAG00000000056 rnaseq  Component 1           0          0
#>  4 ENSBTAG00000000061 rnaseq  Component 1           0          0
#>  5 ENSBTAG00000000113 rnaseq  Component 1           0          0
#>  6 ENSBTAG00000000149 rnaseq  Component 1           0          0
#>  7 ENSBTAG00000000164 rnaseq  Component 1           0          0
#>  8 ENSBTAG00000000205 rnaseq  Component 1           0          0
#>  9 ENSBTAG00000000212 rnaseq  Component 1           0          0
#> 10 ENSBTAG00000000289 rnaseq  Component 1           0          0
#> # ℹ 2,088 more rows
#> 
#> $samples_score
#> # A tibble: 278 × 3
#>    sample_id latent_dimension score
#>    <chr>     <fct>            <dbl>
#>  1 G1979     Component 1      -3.63
#>  2 G2500     Component 1      -2.46
#>  3 G3030     Component 1      -6.42
#>  4 G3068     Component 1      -6.16
#>  5 G3121     Component 1      -3.39
#>  6 G3315     Component 1       4.98
#>  7 G3473     Component 1       5.29
#>  8 G3474     Component 1       4.97
#>  9 G3550     Component 1      -4.17
#> 10 G3594     Component 1       4.71
#> # ℹ 268 more rows
#> 
#> $variance_explained
#> # A tibble: 4 × 3
#>   latent_dimension dataset    prop_var_expl
#>   <fct>            <fct>              <dbl>
#> 1 Component 1      rnaseq             0.205
#> 2 Component 1      metabolome         0.179
#> 3 Component 2      rnaseq             0.147
#> 4 Component 2      metabolome         0.108
#> 
#> attr(,"class")
#> [1] "output_dimension_reduction"
#> attr(,"method")
#> [1] "sPLS"
tar_target(
  so2pls_output,
  get_output(so2pls_final_run)
)
tar_load(so2pls_output)
so2pls_output
#> $features_weight
#> # A tibble: 2,318 × 5
#>    feature_id         dataset latent_dimension  weight importance
#>    <chr>              <fct>   <fct>              <dbl>      <dbl>
#>  1 ENSBTAG00000000020 rnaseq  joint component 1      0          0
#>  2 ENSBTAG00000000046 rnaseq  joint component 1      0          0
#>  3 ENSBTAG00000000056 rnaseq  joint component 1      0          0
#>  4 ENSBTAG00000000061 rnaseq  joint component 1      0          0
#>  5 ENSBTAG00000000113 rnaseq  joint component 1      0          0
#>  6 ENSBTAG00000000149 rnaseq  joint component 1      0          0
#>  7 ENSBTAG00000000164 rnaseq  joint component 1      0          0
#>  8 ENSBTAG00000000205 rnaseq  joint component 1      0          0
#>  9 ENSBTAG00000000212 rnaseq  joint component 1      0          0
#> 10 ENSBTAG00000000289 rnaseq  joint component 1      0          0
#> # ℹ 2,308 more rows
#> 
#> $samples_score
#> # A tibble: 973 × 3
#>    sample_id latent_dimension   score
#>    <chr>     <fct>              <dbl>
#>  1 G1979     joint component 1  -8.12
#>  2 G2500     joint component 1  -9.81
#>  3 G3030     joint component 1  -9.93
#>  4 G3068     joint component 1 -14.7 
#>  5 G3121     joint component 1  -5.01
#>  6 G3315     joint component 1   9.66
#>  7 G3473     joint component 1   9.79
#>  8 G3474     joint component 1   9.99
#>  9 G3550     joint component 1  -9.70
#> 10 G3594     joint component 1   8.37
#> # ℹ 963 more rows
#> 
#> $variance_explained
#> # A tibble: 8 × 3
#>   latent_dimension                dataset    prop_var_expl
#>   <fct>                           <fct>              <dbl>
#> 1 joint component 1               rnaseq            0.327 
#> 2 joint component 1               metabolome        0.150 
#> 3 rnaseq specific component 1     rnaseq            0.123 
#> 4 metabolome specific component 1 metabolome        0.107 
#> 5 metabolome specific component 2 metabolome        0.0767
#> 6 metabolome specific component 3 metabolome        0.0613
#> 7 metabolome specific component 4 metabolome        0.0605
#> 8 metabolome specific component 5 metabolome        0.0376
#> 
#> attr(,"class")
#> [1] "output_dimension_reduction"
#> attr(,"method")
#> [1] "sO2PLS"
tar_target(
  mofa_output,
  get_output(mofa_trained)
)
tar_load(mofa_output)
mofa_output
#> $features_weight
#> # A tibble: 30,735 × 5
#>    feature_id                  dataset latent_dimension     weight importance
#>    <chr>                       <fct>   <fct>                 <dbl>      <dbl>
#>  1 21-25977541-C-T-rs41974686  snps    Factor 1          0.000374      0.139 
#>  2 22-51403583-A-C-rs210306176 snps    Factor 1          0.0000535     0.0199
#>  3 24-12959068-G-T-rs381471286 snps    Factor 1          0.000268      0.0999
#>  4 8-85224224-T-C-rs43565287   snps    Factor 1         -0.000492      0.183 
#>  5 ARS-BFGL-BAC-16973          snps    Factor 1         -0.000883      0.329 
#>  6 ARS-BFGL-BAC-19403          snps    Factor 1         -0.000500      0.186 
#>  7 ARS-BFGL-BAC-2450           snps    Factor 1          0.000555      0.207 
#>  8 ARS-BFGL-BAC-2600           snps    Factor 1         -0.0000325     0.0121
#>  9 ARS-BFGL-BAC-27911          snps    Factor 1         -0.000568      0.212 
#> 10 ARS-BFGL-BAC-35925          snps    Factor 1          0.000803      0.299 
#> # ℹ 30,725 more rows
#> 
#> $samples_score
#> # A tibble: 2,160 × 3
#>    sample_id latent_dimension score
#>    <chr>     <fct>            <dbl>
#>  1 G1979     Factor 1          1.95
#>  2 G2500     Factor 1          1.98
#>  3 G3030     Factor 1          3.39
#>  4 G3068     Factor 1          3.65
#>  5 G3121     Factor 1          1.57
#>  6 G3315     Factor 1         -1.81
#>  7 G3473     Factor 1         -2.63
#>  8 G3474     Factor 1         -2.30
#>  9 G3550     Factor 1          2.98
#> 10 G3594     Factor 1         -1.88
#> # ℹ 2,150 more rows
#> 
#> $variance_explained
#> # A tibble: 45 × 3
#>    latent_dimension dataset    prop_var_expl
#>    <fct>            <fct>              <dbl>
#>  1 Factor 1         snps           0.000313 
#>  2 Factor 1         rnaseq         0.496    
#>  3 Factor 1         metabolome     0.137    
#>  4 Factor 2         snps           0.239    
#>  5 Factor 2         rnaseq         0.000197 
#>  6 Factor 2         metabolome     0.0108   
#>  7 Factor 3         snps           0.000108 
#>  8 Factor 3         rnaseq         0.199    
#>  9 Factor 3         metabolome     0.0000872
#> 10 Factor 4         snps           0.0000927
#> # ℹ 35 more rows
#> 
#> attr(,"class")
#> [1] "output_dimension_reduction"
#> attr(,"method")
#> [1] "MOFA"
tar_target(
  diablo_output,
  get_output(diablo_final_run)
)
tar_load(diablo_output)
diablo_output
#> $features_weight
#> # A tibble: 8,196 × 5
#>    feature_id                  dataset latent_dimension weight importance
#>    <chr>                       <fct>   <fct>             <dbl>      <dbl>
#>  1 21-25977541-C-T-rs41974686  snps    Component 1           0          0
#>  2 22-51403583-A-C-rs210306176 snps    Component 1           0          0
#>  3 24-12959068-G-T-rs381471286 snps    Component 1           0          0
#>  4 8-85224224-T-C-rs43565287   snps    Component 1           0          0
#>  5 ARS-BFGL-BAC-16973          snps    Component 1           0          0
#>  6 ARS-BFGL-BAC-19403          snps    Component 1           0          0
#>  7 ARS-BFGL-BAC-2450           snps    Component 1           0          0
#>  8 ARS-BFGL-BAC-2600           snps    Component 1           0          0
#>  9 ARS-BFGL-BAC-27911          snps    Component 1           0          0
#> 10 ARS-BFGL-BAC-35925          snps    Component 1           0          0
#> # ℹ 8,186 more rows
#> 
#> $samples_score
#> # A tibble: 540 × 3
#>    sample_id latent_dimension score
#>    <chr>     <fct>            <dbl>
#>  1 G1979     Component 1       1.97
#>  2 G2500     Component 1       1.50
#>  3 G3030     Component 1       3.57
#>  4 G3068     Component 1       3.50
#>  5 G3121     Component 1       2.13
#>  6 G3315     Component 1      -3.26
#>  7 G3473     Component 1      -3.97
#>  8 G3474     Component 1      -3.20
#>  9 G3550     Component 1       2.46
#> 10 G3594     Component 1      -2.38
#> # ℹ 530 more rows
#> 
#> $variance_explained
#> # A tibble: 12 × 3
#>    latent_dimension dataset    prop_var_expl
#>    <fct>            <fct>              <dbl>
#>  1 Component 1      snps             0.0698 
#>  2 Component 1      rnaseq           0.201  
#>  3 Component 1      metabolome       0.171  
#>  4 Component 2      snps             0.0213 
#>  5 Component 2      rnaseq           0.0801 
#>  6 Component 2      metabolome       0.0521 
#>  7 Component 3      snps             0.00898
#>  8 Component 3      rnaseq           0.149  
#>  9 Component 3      metabolome       0.0634 
#> 10 Component 4      snps             0.0136 
#> 11 Component 4      rnaseq           0.0601 
#> 12 Component 4      metabolome       0.0399 
#> 
#> attr(,"class")
#> [1] "output_dimension_reduction"
#> attr(,"method")
#> [1] "DIABLO"

The features_weight tibble contains one row per combination of feature and latent dimension. The ID of the features and the name of the dataset from which they originate are stored in the feature_id and dataset columns, respectively. The latent_dimension column gives the name of the latent dimension; this is a factor column. For each feature and latent dimension, the weight column shows the weight that was attributed to the feature for the corresponding latent dimension. In addition, the importance column contains the features importance score, which is computed as the absolute value of the features weight, divided by the maximum absolute weight across all features from the same omics dataset for the corresponding latent dimension. This importance score allows us to compare the contribution of the features across latent dimensions or integration methods, as the weight can be on different scales and thus cannot be directly compared. The importance scores range from 0 to 1. For any method performing feature selection (e.g. sPLS or DIABLO), features that were not selected for a given latent dimension are assigned a weight and importance score of 0.

The samples score tibble contains for each sample (sample_id) and latent dimension (latent_dimension) the sample’s coordinate for the corresponding latent dimension.

The variance_explained tibble gives for each latent dimension (latent_dimension) the proportion of variance explained (prop_var_expl) for each dataset (dataset). The values in prop_var_expl are between 0 and 1.

In addition, the name of the integration method used to obtain these results is stored in the method attribute of the output_dimension_reduction object:

attr(spls_output, "method")
#> [1] "sPLS"
attr(so2pls_output, "method")
#> [1] "sO2PLS"
attr(mofa_output, "method")
#> [1] "MOFA"
attr(diablo_output, "method")
#> [1] "DIABLO"

For convenience, the get_latent_dimensions() function can be used on an output_dimension_reduction object to see the names of the latent dimensions (the levels used for the latent_dimension column in each tibble):

get_latent_dimensions(spls_output)
#> [1] "Component 1" "Component 2"
get_latent_dimensions(so2pls_output)
#> [1] "joint component 1"               "rnaseq specific component 1"    
#> [3] "metabolome specific component 1" "metabolome specific component 2"
#> [5] "metabolome specific component 3" "metabolome specific component 4"
#> [7] "metabolome specific component 5"
get_latent_dimensions(mofa_output)
#>  [1] "Factor 1"  "Factor 2"  "Factor 3"  "Factor 4"  "Factor 5"  "Factor 6" 
#>  [7] "Factor 7"  "Factor 8"  "Factor 9"  "Factor 10" "Factor 11" "Factor 12"
#> [13] "Factor 13" "Factor 14" "Factor 15"
get_latent_dimensions(diablo_output)
#> [1] "Component 1" "Component 2" "Component 3" "Component 4"
Other methods covered by get_output

Note that both PCA and sPLS-DA (the method used for supervised features preselection in Section 7.3.2) are also dimension reduction methods. Therefore, the get_output() function also converts pcaRes objects (from run_pca() or pcaMethods::pca()) and mixo_splsda objects (from run_splsda() or mixOmics::splsda()) into output_dimension_reduction objects.

12.2.2 Averaging latent dimensions over datasets

While MOFA computes one score per sample for each latent dimension created, sPLS, sO2PLS and DIABLO all compute one score per dataset for each sample and latent dimension. For each latent dimension, the samples score obtained for the different datasets are then compared, to assess the agreement or covariation between datasets. Ideally, these scores should be highly correlated across datasets, since the methods aim at maximising the variation between datasets, but it is not always the case. However, when they are highly correlated, it becomes redundant to interpret each dataset-specific version of the latent dimensions.

Instead, the mixOmics authors proposed a solution for DIABLO, which is to construct a weighted average space in which to represent the samples: for each latent component, the samples score are averaged over the different datasets. The weight attributed to each dataset is determined by how well the corresponding dataset discriminates between the samples group of interest. This way, rather than looking at samples score for each dataset for any given latent component, we can look at an average of them.

The get_output() function uses this idea to construct, for the output of sPLS, sO2PLS and DIABLO a set of average samples score for each latent dimension, rather than returning a set of samples score per dataset. For DIABLO, the average is weighted as explained above, while for sPLS and sO2PLS each dataset is given equal weight in the average. This calculation can be disabled in the get_output() function to extract the dataset-specific samples score, by setting the use_average_dimensions parameter to FALSE. Note that this only affects the samples_score tibble in terms of dimensions, but the name of the latent dimensions will change to reflect the dataset to which they refer.

tar_target(
  spls_output_no_average,
  get_output(spls_final_run, use_average_dimensions = FALSE)
)
tar_load(spls_output_no_average)

get_latent_dimensions(spls_output_no_average)
#> [1] "rnaseq Component 1"     "metabolome Component 1" "rnaseq Component 2"    
#> [4] "metabolome Component 2"

nrow(spls_output$samples_score)
#> [1] 278
nrow(spls_output_no_average$samples_score)
#> [1] 556
tar_target(
  so2pls_output_no_average,
  get_output(so2pls_final_run, use_average_dimensions = FALSE)
)
tar_load(so2pls_output_no_average)

get_latent_dimensions(so2pls_output_no_average)
#> [1] "rnaseq joint component 1"        "metabolome joint component 1"   
#> [3] "rnaseq specific component 1"     "metabolome specific component 1"
#> [5] "metabolome specific component 2" "metabolome specific component 3"
#> [7] "metabolome specific component 4" "metabolome specific component 5"

nrow(so2pls_output$samples_score)
#> [1] 973
nrow(so2pls_output_no_average$samples_score)
#> [1] 1112
tar_target(
  diablo_output_no_average,
  get_output(diablo_final_run, use_average_dimensions = FALSE)
)
tar_load(diablo_output_no_average)
  
get_latent_dimensions(diablo_output_no_average)
#>  [1] "snps Component 1"       "rnaseq Component 1"     "metabolome Component 1"
#>  [4] "snps Component 2"       "rnaseq Component 2"     "metabolome Component 2"
#>  [7] "snps Component 3"       "rnaseq Component 3"     "metabolome Component 3"
#> [10] "snps Component 4"       "rnaseq Component 4"     "metabolome Component 4"

nrow(diablo_output$samples_score)
#> [1] 540
nrow(diablo_output_no_average$samples_score)
#> [1] 1620

12.3 Percentage of variance explained

The first step in interpreting the results of a dimension reduction method is to assess how much variance is explained by the different latent dimensions for each dataset. The function plot_variance_explained() takes as input a output_dimension_reduction object and constructs a dataset-specific screeplot:

plot_variance_explained(so2pls_output, ncol = 1) +
  theme(axis.text.x = element_text(size = 9, angle = 30, hjust = 1))

plot_variance_explained(mofa_output, ncol = 1) +
  theme(axis.text.x = element_text(size = 9, angle = 30, hjust = 1))

plot_variance_explained(diablo_output, ncol = 2)

12.4 Samples plot

To understand the phenomenon driving the variation represented by the different latent components, we can investigate the coordinates of the samples in the space spanned by these latent components, in combination with information that we have about the samples.

We will start by loading the MultiDataSet object and generating some custom colour palettes for different samples covariates of interest, that we will use in the rest of the section.

tar_load(mo_set_complete)

## Choosing colour palettes for the samples covariates
palette_status <- scale_colour_brewer(palette = "Set1")
palette_feedlot <- scale_colour_brewer(palette = "Set2")
palette_geno_comp <- scale_colour_brewer(palette = "Dark2")
palette_rnaseq_batch <- scale_colour_brewer(palette = "Paired")

## For some plots will need both colour and fill
palette_status_fill <- scale_colour_brewer(
  palette = "Set1", 
  aesthetics = c("colour", "fill")
)

12.4.1 Matrix of scatter plots

The plot_samples_score() function shows the samples score in a matrix of scatter plots that represent all possible two-by-two combinations of the latent dimensions. The plots in the resulting matrix are redundant: the lower plots (below the diagonal) are just a rotated version of the upper plots (above the diagonal). The function takes as input an output_dimension_reduction object. In addition, it accepts a MultiDataSet object to extract information about the samples that can then be used to customise the plot. Since the plots are redundant, different properties of the samples can be shown in the upper and lower plots. For example, we will colour the samples according to disease status in the upper plots, while representing some other covariate in the lower plots. We will use the shape of the points to illustrate gender in both upper and lower plots. By default, all latent dimensions are included in the plots, but it is possible to select some of them by passing their names to the latent_dimensions argument. There are more options to further customise the plot, which are shown in the function’s help.

plot_samples_score(
  spls_output,
  mo_data = mo_set_complete,
  colour_upper = "status",
  scale_colour_upper = palette_status,
  shape_upper = "gender",
  colour_lower = "feedlot",
  scale_colour_lower = palette_feedlot
) +
  theme(legend.box = "vertical")

Component 1 clearly splits the control and BRD animals, while component 2 seems to separate two samples from the rest. There is no clear separation of the samples by feedlot or gender.

Here we will focus on the joint components. Since there is only one, instead of a matrix of scatterplot, the function will display the samples score with a violin plot, and the properties selected for the upper plots will be used to customise the points:

plot_samples_score(
  so2pls_output,
  latent_dimensions = "joint component 1",
  mo_data = mo_set_complete,
  colour_upper = "status",
  scale_colour_upper = palette_status,
  shape_upper = "gender",
  colour_lower = "feedlot",
  scale_colour_lower = palette_feedlot
)
#> Warning in plot_samples_score(so2pls_output, latent_dimensions = "joint
#> component 1", : Only one latent dimension to plot; 'colour_diag',
#> 'colour_lower' and 'shape_lower' argument will be ignored.

Joint component 1 separates the BRD and control animals, although some of them overlap.

For clarity we will focus here on the first four factors:

plot_samples_score(
  mofa_output,
  latent_dimensions = paste("Factor", 1:4),
  mo_data = mo_set_complete,
  colour_upper = "status",
  scale_colour_upper = palette_status,
  shape_upper = "gender",
  colour_lower = "geno_comp_cluster",
  scale_colour_lower = palette_geno_comp
) +
  theme(legend.box = "vertical")
#> Warning: Removed 2 rows containing missing values (`geom_point()`).
#> Removed 2 rows containing missing values (`geom_point()`).
#> Removed 2 rows containing missing values (`geom_point()`).
#> Removed 2 rows containing missing values (`geom_point()`).
#> Removed 2 rows containing missing values (`geom_point()`).
#> Removed 2 rows containing missing values (`geom_point()`).

Factor 1 clearly separates the control and BRD animals. Factor 2 separates samples from the genomics composition cluster K1 from the other two clusters. None of the factors are separating the animals by gender, indicating that this covariate does not have a strong effect in the omics measurements.

plot_samples_score(
  diablo_output,
  mo_data = mo_set_complete,
  colour_upper = "status",
  scale_colour_upper = palette_status,
  shape_upper = "gender",
  colour_lower = "rnaseq_batch",
  scale_colour_lower = palette_rnaseq_batch
) +
  theme(legend.box = "vertical")

As DIABLO is a supervised method, it is no surprise that the first component clearly separates the two disease status groups. The second latent component separates samples according to the RNAseq batch. From this plot it is not clear what components 3 and 4 represent.

12.4.2 Scatter plot for pair of latent dimensions

We can also focus on a specific pair of latent dimensions and represent the samples in the space spanned by these two dimensions, with the plot_samples_score_pair() function. The two latent dimensions to plot are selected by passing their names to the function. This function also accepts a MultiDataSet object, whose samples metadata will be used to customise the plot.

plot_samples_score_pair(
  spls_output,
  paste("Component", 1:2),
  mo_data = mo_set_complete,
  colour_by = "status",
  shape_by = "gender"
) +
  palette_status

The two disease status groups are well separated in this space.

To showcase this function, we will look at the first two metabolomics-specific latent components:

plot_samples_score_pair(
  so2pls_output,
  paste("metabolome specific component", 1:2),
  mo_data = mo_set_complete,
  colour_by = "status",
  shape_by = "gender"
) +
  palette_status

These two specific components are not related to disease status or gender.

plot_samples_score_pair(
  mofa_output,
  paste("Factor", 1:2),
  mo_data = mo_set_complete,
  colour_by = "status",
  shape_by = "geno_comp_cluster"
) +
  palette_status
#> Warning: Removed 2 rows containing missing values (`geom_point()`).

We see that these first two factors discriminate the disease status groups and the genomics composition clusters.

plot_samples_score_pair(
  diablo_output,
  paste("Component", 1:2),
  mo_data = mo_set_complete,
  colour_by = "status",
  shape_by = "rnaseq_batch"
) +
  palette_status

We see that these first two components discriminate the disease status groups and the RNAseq batches.

12.4.3 Samples score vs covariate

Lastly, we can plot the samples score for each latent dimension against a samples covariate of interest, with the plot_samples_score_covariate() function. This is useful to focus on one dimension at a time rather than pairs of them. By default, the function displays all latent dimensions, but we can focus on a subset of them through the latent_dimensions arguments. The function needs a MultiDataSet object to extract information about the samples. The plot generated will depend on whether the covariate of interest is categorical or continuous. We will show both options below. In addition to the main covariate of interest that will be displayed on the x-axis, the colour and shape of the points can be further customised according to other samples properties.

First, with a categorical covariate:

plot_samples_score_covariate(
  spls_output,
  mo_set_complete,
  "status",
  colour_by = "status"
) +
  palette_status_fill

For clarity we will focus on the first joint component only.

plot_samples_score_covariate(
  so2pls_output,
  mo_set_complete,
  "status",
  colour_by = "status",
  latent_dimensions = "joint component 1"
) +
  palette_status_fill

For clarity we will focus on the first two factors only.

plot_samples_score_covariate(
  mofa_output,
  mo_set_complete,
  "status",
  colour_by = "status",
  shape_by = "geno_comp_cluster",
  latent_dimensions = paste("Factor", 1:2)
) +
  palette_status_fill
#> Warning: Removed 4 rows containing missing values (`geom_point()`).

For clarity we will focus on the first two components only.

plot_samples_score_covariate(
  diablo_output,
  mo_set_complete,
  "status",
  colour_by = "status",
  shape_by = "rnaseq_batch",
  latent_dimensions = paste("Component", 1:2)
) +
  palette_status_fill

Now, with a continuous covariate:

plot_samples_score_covariate(
  spls_output,
  mo_set_complete,
  "day_on_feed",
  colour_by = "status"
) +
  palette_status_fill

For clarity we will focus on the first joint component only.

plot_samples_score_covariate(
  so2pls_output,
  mo_set_complete,
  "day_on_feed",
  colour_by = "status",
  latent_dimensions = "joint component 1"
) +
  palette_status_fill

For clarity we will focus on the first two factors only.

plot_samples_score_covariate(
  mofa_output,
  mo_set_complete,
  "day_on_feed",
  colour_by = "status",
  shape_by = "geno_comp_cluster",
  latent_dimensions = paste("Factor", 1:2)
) +
  palette_status_fill
#> Warning: Removed 4 rows containing non-finite values (`stat_smooth()`).
#> Warning: Removed 4 rows containing missing values (`geom_point()`).

For clarity we will focus on the first two components only.

plot_samples_score_covariate(
  diablo_output,
  mo_set_complete,
  "day_on_feed",
  colour_by = "status",
  shape_by = "rnaseq_batch",
  latent_dimensions = paste("Component", 1:2)
) +
  palette_status_fill

12.5 Feature plots

Next, we can have a look at the features contributing to each latent dimension.

12.5.1 Features weight distribution

We can start by looking at the distribution of features weight for each latent dimension across the datasets, with the plot_features_weight_distr() function. Again, the function takes an output_dimension_reduction object as first input; by default it will show all latent dimensions and datasets, but they can be specified through the latent_dimensions and datasets arguments. The function shows by default the distribution of the “signed” importance scores, i.e. the features weights normalised by the highest absolute weight value for the corresponding latent dimension and dataset, but we can also show the distribution of importance scores (which are absolute values) and non-transformed features weight (through the features_metric argument). Note that the function returns a patchwork of ggplots.

As sPLS performs feature selection, most of the weights are equal to 0.

plot_features_weight_distr(so2pls_output) +
  ## showing two plots per column (from patchwork package)
  plot_layout(ncol = 2)

As sO2PLS performs feature selection for the joint components, most of the weights are equal to 0 for joint component 1.

We will only look at factors 1 to 4 for clarity:

plot_features_weight_distr(
  mofa_output,
  latent_dimensions = paste("Factor", 1:4)
) +
  ## showing one plot per column (from patchwork package)
  plot_layout(ncol = 1)

We can see for example for factor 1 that only a couple of metabolites have an importance score above 0.5, this small number of features are driving the variation captured by factor 1.

plot_features_weight_distr(
  diablo_output
) +
  ## showing one plot per column (from patchwork package)
  plot_layout(ncol = 1)

As DIABLO performs feature selection, most of the weights are equal to zero.

12.5.2 Comparing features importance between latent components

We can also compare the importance score given to the features between any two latent dimensions with the plot_features_weight_pair() function.

plot_features_weight_pair(
  spls_output,
  paste("Component", 1:2),
  mo_data = mo_set_complete,
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  )
)

All genes and most metabolites selected for the two components are different.

plot_features_weight_pair(
  so2pls_output,
  paste("metabolome specific component", 1:2),
  mo_data = mo_set_complete,
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  )
)

The plot shows an interesting pattern: the weights of the compound for these two specific components are negatively correlated, except for a couple of outliers.

plot_features_weight_pair(
  mofa_output,
  paste("Factor", 1:2),
  mo_data = mo_set_complete,
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  )
)

We can see that the genomic markers are mostly given weights of opposite signs for the first two MOFA factors (e.g. positive weight for factor 1 and negative weight for factor 2). For the transcriptomics and metabolomics datasets, the importance score are mostly uncorrelated between the first two factors.

plot_features_weight_pair(
  diablo_output,
  paste("Component", 1:2),
  mo_data = mo_set_complete,
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  )
)

We can see that different features were selected for the first two latent components from each omics dataset.

These plots allow us to quickly check whether different latent dimensions capture different or related aspects of the data. The top 5 features according to their consensus importance score (see Section 14.9) are highlighted in red.

By default, the function shows the signed importance score of the features, i.e. their importance score to which the sign of their weight was added. This can be changed through the features_metric argument of the function.

12.5.3 Plotting top features weight

We can then investigate which features are assigned the highest weights for each latent dimension. These are the features driving the variation captured by the latent components. This is done with the plot_top_features() function.

By default, the feature IDs will be used as labels in the plot, but by passing a MultiDataSet object to the function we can use a column from the features metadata table instead. To do so, we need to pass a named list to the label_cols argument: the names of the elements in the list should correspond to dataset names in the MultiDataSet object, and the value should be the name of the column in the features metadata table of the corresponding dataset to use as feature label. The number of features displayed is controlled through the top_n argument (the default value is 20). Note that if a lower number of features is selected for a certain dataset and latent dimension, only the selected features will be displayed. Again, the function returns a patchwork of ggplots.

plot_top_features(
  spls_output,
  mo_data = mo_set_complete,
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  )
)

We can see that citric acid and D-mannose have an importance score close to 1 for component 1. Citric acid has a negative weight, meaning that its abundance is negatively correlated with component 1, while D-mannose has a positive weight, so its abundance is positively correlated with component 1. For the second component, only two genes have an importance score above 0.5.

We will focus on joint component 1:

plot_top_features(
  so2pls_output,
  mo_data = mo_set_complete,
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  ),
  latent_dimensions = "joint component 1"
)

While all top 20 genes have an importance score above 0.5 for joint component 1, only citric acid is given a high importance score for joint component 1 in the metabolomics dataset.

We will focus on the first two factors here:

plot_top_features(
  mofa_output,
  mo_data = mo_set_complete,
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  ),
  latent_dimensions = paste("Factor", 1:2)
)

For factor 1, citric acid is the only metabolite with an importance score above 0.75, while in the genomics dataset four markers have a high importance score, and most of the top 20 genes have an importance score aroung 0.7 or higher.

For clarity, we will focus on the first two latent components:

plot_top_features(
  diablo_output,
  mo_data = mo_set_complete,
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  ),
  latent_dimensions = paste("Component", 1:2)
)

For component 1, we can see three markers from the genomics dataset and three genes with a high importance score. From the metabolomics dataset, less than 20 features were retained.

12.5.4 Extracting top features

It is also possible to extract information about the top contributing features as a table with the function get_top_features(). The function offers two options:

  • Return for each dataset the top N features contributing to the latent dimensions of interest. N is specified through the n_features argument;

  • Return for each dataset features whose importance score is at least equal to a certain threshold. The threshold is specified through the min_importance argument.

The first option is preferred when many features contribute to a given factor. The second option has been implemented for cases where some latent dimensions are driven by a small number of features (so for example in the top 10 contributing features, only 3 features would actually have a high importance score). By default, the function returns the top contributing features from all datasets for all latent dimensions, but we can focus on some datasets and/or latent dimensions of interest by passing their names to the datasets and latent_dimensions arguments of the function. Additionally, we can pass to the function a MultiDataSet object (through the mo_data argument); the function will extract information about the features from the features metadata.

We illustrate the two possible options below. For the second option, we add features information to the table:

get_top_features(spls_output, n_features = 3) |> 
  head()
#> # A tibble: 6 × 5
#>   feature_id         dataset    latent_dimension weight importance
#>   <chr>              <fct>      <fct>             <dbl>      <dbl>
#> 1 ENSBTAG00000022715 rnaseq     Component 1      -0.318      1    
#> 2 ENSBTAG00000050618 rnaseq     Component 1      -0.302      0.950
#> 3 ENSBTAG00000018223 rnaseq     Component 1      -0.291      0.916
#> 4 HMDB00094          metabolome Component 1       0.451      1    
#> 5 HMDB00169          metabolome Component 1      -0.327      0.726
#> 6 HMDB00159          metabolome Component 1      -0.312      0.692

get_top_features(
  spls_output,
  min_importance = 0.8,
  mo_data = mo_set_complete
) |> 
  head()
#> # A tibble: 6 × 31
#>   feature_id      dataset latent_dimension weight importance chromosome  p_value
#>   <chr>           <fct>   <fct>             <dbl>      <dbl> <chr>         <dbl>
#> 1 ENSBTAG0000002… rnaseq  Component 1      -0.318      1     26         1.79e-33
#> 2 ENSBTAG0000005… rnaseq  Component 1      -0.302      0.950 26         2.54e-33
#> 3 ENSBTAG0000001… rnaseq  Component 1      -0.291      0.916 16         7.14e-31
#> 4 ENSBTAG0000004… rnaseq  Component 1      -0.266      0.837 15         4.14e-36
#> 5 ENSBTAG0000003… rnaseq  Component 1      -0.264      0.831 7          1.22e-35
#> 6 HMDB00094       metabo… Component 1       0.451      1     <NA>       2.48e-41
#> # ℹ 24 more variables: fdr <dbl>, start <int>, end <int>, width <int>,
#> #   strand <fct>, Name <chr>, description <chr>, log_fc <dbl>, log_cpm <dbl>,
#> #   f <dbl>, de_signif <chr>, de_status <chr>, hmdb_id <chr>, name <chr>,
#> #   chemical_formula <chr>, monisotopic_molecular_weight <dbl>,
#> #   cas_registry_number <chr>, smiles <chr>, inchikey <chr>, kegg_id <chr>,
#> #   direct_parent <chr>, super_class <chr>, t_value <dbl>, padj <dbl>
get_top_features(so2pls_output, n_features = 3) |> 
  head()
#> # A tibble: 6 × 5
#>   feature_id         dataset    latent_dimension  weight importance
#>   <chr>              <fct>      <fct>              <dbl>      <dbl>
#> 1 ENSBTAG00000048835 rnaseq     joint component 1 -0.268      1    
#> 2 ENSBTAG00000049569 rnaseq     joint component 1 -0.266      0.993
#> 3 ENSBTAG00000039037 rnaseq     joint component 1 -0.248      0.925
#> 4 HMDB00094          metabolome joint component 1  0.751      1    
#> 5 HMDB00042          metabolome joint component 1  0.335      0.445
#> 6 HMDB00357          metabolome joint component 1  0.319      0.424

get_top_features(
  so2pls_output,
  min_importance = 0.8,
  mo_data = mo_set_complete
) |> 
  head()
#> # A tibble: 6 × 31
#>   feature_id      dataset latent_dimension weight importance chromosome  p_value
#>   <chr>           <fct>   <fct>             <dbl>      <dbl> <chr>         <dbl>
#> 1 ENSBTAG0000004… rnaseq  joint component… -0.268      1     24         5.43e-27
#> 2 ENSBTAG0000004… rnaseq  joint component… -0.266      0.993 NKLS02001… 1.14e-27
#> 3 ENSBTAG0000003… rnaseq  joint component… -0.248      0.925 NKLS02001… 1.45e-28
#> 4 ENSBTAG0000003… rnaseq  joint component… -0.235      0.876 7          1.22e-35
#> 5 ENSBTAG0000005… rnaseq  joint component… -0.227      0.847 NKLS02000… 1.31e-22
#> 6 ENSBTAG0000002… rnaseq  joint component… -0.216      0.805 26         1.79e-33
#> # ℹ 24 more variables: fdr <dbl>, start <int>, end <int>, width <int>,
#> #   strand <fct>, Name <chr>, description <chr>, log_fc <dbl>, log_cpm <dbl>,
#> #   f <dbl>, de_signif <chr>, de_status <chr>, hmdb_id <chr>, name <chr>,
#> #   chemical_formula <chr>, monisotopic_molecular_weight <dbl>,
#> #   cas_registry_number <chr>, smiles <chr>, inchikey <chr>, kegg_id <chr>,
#> #   direct_parent <chr>, super_class <chr>, t_value <dbl>, padj <dbl>
get_top_features(mofa_output, n_features = 3) |> 
  head()
#> # A tibble: 6 × 5
#>   feature_id             dataset latent_dimension   weight importance
#>   <chr>                  <fct>   <fct>               <dbl>      <dbl>
#> 1 BovineHD0100032240     snps    Factor 1         -0.00268      1    
#> 2 Hapmap55381-rs29025399 snps    Factor 1         -0.00268      1    
#> 3 BovineHD0100032254     snps    Factor 1          0.00249      0.927
#> 4 ENSBTAG00000049569     rnaseq  Factor 1          1.89         1    
#> 5 ENSBTAG00000048835     rnaseq  Factor 1          1.88         0.999
#> 6 ENSBTAG00000039037     rnaseq  Factor 1          1.81         0.961

get_top_features(
  mofa_output,
  min_importance = 0.8,
  mo_data = mo_set_complete
) |> 
  head()
#> # A tibble: 6 × 40
#>   feature_id    dataset latent_dimension   weight importance chromosome position
#>   <chr>         <fct>   <fct>               <dbl>      <dbl> <chr>         <dbl>
#> 1 BovineHD0100… snps    Factor 1         -0.00268      1     1            1.13e8
#> 2 Hapmap55381-… snps    Factor 1         -0.00268      1     1            1.13e8
#> 3 BovineHD0100… snps    Factor 1          0.00249      0.927 1            1.13e8
#> 4 BovineHD2700… snps    Factor 1         -0.00225      0.839 27           3.57e7
#> 5 ENSBTAG00000… rnaseq  Factor 1          1.89         1     NKLS02001…  NA     
#> 6 ENSBTAG00000… rnaseq  Factor 1          1.88         0.999 24          NA     
#> # ℹ 33 more variables: gen_train_score <dbl>, ref <chr>, alt <chr>,
#> #   ilmn_strand <chr>, customer_strand <chr>, norm_id <dbl>, qtl_type <chr>,
#> #   qtl_effect <dbl>, p_value <dbl>, fdr <dbl>, start <int>, end <int>,
#> #   width <int>, strand <fct>, Name <chr>, description <chr>, log_fc <dbl>,
#> #   log_cpm <dbl>, f <dbl>, de_signif <chr>, de_status <chr>, hmdb_id <chr>,
#> #   name <chr>, chemical_formula <chr>, monisotopic_molecular_weight <dbl>,
#> #   cas_registry_number <chr>, smiles <chr>, inchikey <chr>, kegg_id <chr>, …
get_top_features(diablo_output, n_features = 3) |> 
  head()
#> # A tibble: 6 × 5
#>   feature_id         dataset latent_dimension weight importance
#>   <chr>              <fct>   <fct>             <dbl>      <dbl>
#> 1 ARS-BFGL-NGS-27468 snps    Component 1      -0.632      1    
#> 2 BovineHD2300010006 snps    Component 1       0.509      0.807
#> 3 BovineHD0300000351 snps    Component 1       0.337      0.534
#> 4 ENSBTAG00000022715 rnaseq  Component 1       0.465      1    
#> 5 ENSBTAG00000050618 rnaseq  Component 1       0.378      0.813
#> 6 ENSBTAG00000049888 rnaseq  Component 1       0.305      0.655

get_top_features(
  diablo_output,
  min_importance = 0.8,
  mo_data = mo_set_complete
) |> 
  head()
#> # A tibble: 6 × 40
#>   feature_id      dataset latent_dimension weight importance chromosome position
#>   <chr>           <fct>   <fct>             <dbl>      <dbl> <chr>         <dbl>
#> 1 ARS-BFGL-NGS-2… snps    Component 1      -0.632      1     1            1.34e8
#> 2 BovineHD230001… snps    Component 1       0.509      0.807 23           3.43e7
#> 3 ENSBTAG0000002… rnaseq  Component 1       0.465      1     26          NA     
#> 4 ENSBTAG0000005… rnaseq  Component 1       0.378      0.813 26          NA     
#> 5 HMDB00094       metabo… Component 1      -0.716      1     <NA>        NA     
#> 6 BovineHD070000… snps    Component 2      -0.543      1     7            2.11e5
#> # ℹ 33 more variables: gen_train_score <dbl>, ref <chr>, alt <chr>,
#> #   ilmn_strand <chr>, customer_strand <chr>, norm_id <dbl>, qtl_type <chr>,
#> #   qtl_effect <dbl>, p_value <dbl>, fdr <dbl>, start <int>, end <int>,
#> #   width <int>, strand <fct>, Name <chr>, description <chr>, log_fc <dbl>,
#> #   log_cpm <dbl>, f <dbl>, de_signif <chr>, de_status <chr>, hmdb_id <chr>,
#> #   name <chr>, chemical_formula <chr>, monisotopic_molecular_weight <dbl>,
#> #   cas_registry_number <chr>, smiles <chr>, inchikey <chr>, kegg_id <chr>, …

12.5.5 Extracting the selected features

For methods that perform feature selection (i.e. sPLS, sO2PLS and DIABLO), we can extract information about the selected features with the get_selected_features() function. As with get_top_features(), if a MultiDataSet object is passed to the function, it will extract information about the features from the features metadata tables and return them. If applied to the results of a method that does not perform feature selection, all features will be returned.

selected_features <- get_selected_features(spls_output) 

dim(selected_features)
#> [1] 120   5
head(selected_features)
#> # A tibble: 6 × 5
#>   feature_id         dataset latent_dimension weight importance
#>   <chr>              <fct>   <fct>             <dbl>      <dbl>
#> 1 ENSBTAG00000022715 rnaseq  Component 1      -0.318      1    
#> 2 ENSBTAG00000050618 rnaseq  Component 1      -0.302      0.950
#> 3 ENSBTAG00000018223 rnaseq  Component 1      -0.291      0.916
#> 4 ENSBTAG00000049888 rnaseq  Component 1      -0.266      0.837
#> 5 ENSBTAG00000031647 rnaseq  Component 1      -0.264      0.831
#> 6 ENSBTAG00000046158 rnaseq  Component 1      -0.248      0.781
selected_features <- get_selected_features(so2pls_output) 

dim(selected_features)
#> [1] 1394    5
head(selected_features)
#> # A tibble: 6 × 5
#>   feature_id         dataset latent_dimension  weight importance
#>   <chr>              <fct>   <fct>              <dbl>      <dbl>
#> 1 ENSBTAG00000048835 rnaseq  joint component 1 -0.268      1    
#> 2 ENSBTAG00000049569 rnaseq  joint component 1 -0.266      0.993
#> 3 ENSBTAG00000039037 rnaseq  joint component 1 -0.248      0.925
#> 4 ENSBTAG00000031647 rnaseq  joint component 1 -0.235      0.876
#> 5 ENSBTAG00000052012 rnaseq  joint component 1 -0.227      0.847
#> 6 ENSBTAG00000022715 rnaseq  joint component 1 -0.216      0.805
selected_features <- get_selected_features(mofa_output) 

dim(selected_features)
#> [1] 30735     5
head(selected_features)
#> # A tibble: 6 × 5
#>   feature_id             dataset latent_dimension   weight importance
#>   <chr>                  <fct>   <fct>               <dbl>      <dbl>
#> 1 BovineHD0100032240     snps    Factor 1         -0.00268      1    
#> 2 Hapmap55381-rs29025399 snps    Factor 1         -0.00268      1    
#> 3 BovineHD0100032254     snps    Factor 1          0.00249      0.927
#> 4 BovineHD2700010051     snps    Factor 1         -0.00225      0.839
#> 5 Hapmap44084-BTA-48504  snps    Factor 1         -0.00194      0.724
#> 6 BovineHD2100007115     snps    Factor 1          0.00190      0.709
selected_features <- get_selected_features(diablo_output) 

dim(selected_features)
#> [1] 200   5
head(selected_features)
#> # A tibble: 6 × 5
#>   feature_id         dataset latent_dimension weight importance
#>   <chr>              <fct>   <fct>             <dbl>      <dbl>
#> 1 ARS-BFGL-NGS-27468 snps    Component 1      -0.632      1    
#> 2 BovineHD2300010006 snps    Component 1       0.509      0.807
#> 3 BovineHD0300000351 snps    Component 1       0.337      0.534
#> 4 BovineHD1900011146 snps    Component 1      -0.210      0.333
#> 5 BovineHD0900026231 snps    Component 1      -0.191      0.302
#> 6 BovineHD1100030384 snps    Component 1      -0.181      0.286

12.5.6 Features measurements

Finally, we can investigate further some features of interest using the functions shown in Section 4.5. For the example, we will extract the top 3 contributing features from each dataset for the first latent dimension generated with the methods:

spls_top_features <- get_top_features(
  spls_output,
  n_features = 3,
  latent_dimensions = "Component 1"
) |> 
  pull(feature_id)

spls_top_features
#> [1] "ENSBTAG00000022715" "ENSBTAG00000050618" "ENSBTAG00000018223"
#> [4] "HMDB00094"          "HMDB00169"          "HMDB00159"
so2pls_top_features <- get_top_features(
  so2pls_output,
  n_features = 3,
  latent_dimensions = "joint component 1"
) |> 
  pull(feature_id)

so2pls_top_features
#> [1] "ENSBTAG00000048835" "ENSBTAG00000049569" "ENSBTAG00000039037"
#> [4] "HMDB00094"          "HMDB00042"          "HMDB00357"
mofa_top_features <- get_top_features(
  mofa_output,
  n_features = 3,
  latent_dimensions = "Factor 1"
) |> 
  pull(feature_id)

mofa_top_features
#> [1] "BovineHD0100032240"     "Hapmap55381-rs29025399" "BovineHD0100032254"    
#> [4] "ENSBTAG00000049569"     "ENSBTAG00000048835"     "ENSBTAG00000039037"    
#> [7] "HMDB00094"              "HMDB00042"              "HMDB00357"
diablo_top_features <- get_top_features(
  diablo_output,
  n_features = 3,
  latent_dimensions = "Component 1"
) |> 
  pull(feature_id)

diablo_top_features
#> [1] "ARS-BFGL-NGS-27468" "BovineHD2300010006" "BovineHD0300000351"
#> [4] "ENSBTAG00000022715" "ENSBTAG00000050618" "ENSBTAG00000049888"
#> [7] "HMDB00094"          "HMDB00042"          "HMDB00169"

We can use the plot_data_heatmap() function to visualise the measurements for the features across the samples as a heatmap. By passing a MultiDataSet object to the function, we can add information about the samples and the features around the heatmap, and change the label used for the features.

plot_data_heatmap(
  mo_set_complete,
  spls_top_features,
  center = TRUE,
  scale = TRUE,
  show_column_names = FALSE,
  only_common_samples = TRUE,
  samples_info = c("status", "day_on_feed"),
  features_info = c("de_status"),
  colours_list = list(
    "status" = c("Control" = "gold", "BRD" = "lightblue"),
    "day_on_feed" = colorRamp2(c(5, 70), c("white", "pink3")),
    "de_status" = c("downregulated" = "deepskyblue", 
                    "upregulated" = "chartreuse3")
  ),
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  ),
  truncate = 20
)

plot_data_heatmap(
  mo_set_complete,
  so2pls_top_features,
  center = TRUE,
  scale = TRUE,
  show_column_names = FALSE,
  only_common_samples = TRUE,
  samples_info = c("status", "day_on_feed"),
  features_info = c("de_status"),
  colours_list = list(
    "status" = c("Control" = "gold", "BRD" = "lightblue"),
    "day_on_feed" = colorRamp2(c(5, 70), c("white", "pink3")),
    "de_status" = c("downregulated" = "deepskyblue", 
                    "upregulated" = "chartreuse3")
  ),
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  ),
  truncate = 20
)

plot_data_heatmap(
  mo_set_complete,
  mofa_top_features,
  center = TRUE,
  scale = TRUE,
  show_column_names = FALSE,
  only_common_samples = TRUE,
  samples_info = c("status", "day_on_feed"),
  features_info = c("de_status"),
  colours_list = list(
    "status" = c("Control" = "gold", "BRD" = "lightblue"),
    "day_on_feed" = colorRamp2(c(5, 70), c("white", "pink3")),
    "de_status" = c("downregulated" = "deepskyblue", 
                    "upregulated" = "chartreuse3")
  ),
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  ),
  truncate = 20
)

plot_data_heatmap(
  mo_set_complete,
  diablo_top_features,
  center = TRUE,
  scale = TRUE,
  show_column_names = FALSE,
  only_common_samples = TRUE,
  samples_info = c("status", "day_on_feed"),
  features_info = c("de_status"),
  colours_list = list(
    "status" = c("Control" = "gold", "BRD" = "lightblue"),
    "day_on_feed" = colorRamp2(c(5, 70), c("white", "pink3")),
    "de_status" = c("downregulated" = "deepskyblue", 
                    "upregulated" = "chartreuse3")
  ),
  label_cols = list(
    "rnaseq" = "Name",
    "metabolome" = "name"
  ),
  truncate = 20
)

Alternatively, we can display the features’ measurements against some samples covariate, with the plot_data_covariate() function:

plot_data_covariate(
  mo_set_complete,
  "status",
  spls_top_features,
  only_common_samples = TRUE,
  label_cols = list(
    "rnaseq" = "Name", 
    "metabolome" = "name"
  )
)

plot_data_covariate(
  mo_set_complete,
  "status",
  so2pls_top_features,
  only_common_samples = TRUE,
  label_cols = list(
    "rnaseq" = "Name", 
    "metabolome" = "name"
  )
)

plot_data_covariate(
  mo_set_complete,
  "status",
  mofa_top_features,
  only_common_samples = TRUE,
  label_cols = list(
    "rnaseq" = "Name", 
    "metabolome" = "name"
  )
)

plot_data_covariate(
  mo_set_complete,
  "status",
  diablo_top_features,
  only_common_samples = TRUE,
  label_cols = list(
    "rnaseq" = "Name", 
    "metabolome" = "name"
  )
)

12.6 Recap – targets list

For convenience, here is the list of targets that we created in this section:

Targets list for results interpretation

In the targets script, before the targets list, we will add the following code to create the colour palettes used in some of the plots:

## In the preamble of the _targets.R script

## Choosing colour palettes for the samples covariates
palette_status <- scale_colour_brewer(palette = "Set1")
palette_feedlot <- scale_colour_brewer(palette = "Set2")
palette_geno_comp <- scale_colour_brewer(palette = "Dark2")
palette_rnaseq_batch <- scale_colour_brewer(palette = "Paired")
list(
  ## Generating standardised output
  tar_target(
    spls_output,
    get_output(spls_final_run)
  ),
  
  ## Percentage of variance explained
  tar_target(
    spls_plot_variance_explained,
    plot_variance_explained(spls_output)
  ),
  
  ## Samples score matrix plot
  tar_target(
    spls_samples_scores_plot,
    plot_samples_score(
      spls_output,
      mo_data = mo_set_complete,
      colour_upper = "status",
      scale_colour_upper = palette_status,
      shape_upper = "gender",
      colour_lower = "feedlot",
      scale_colour_lower = palette_feedlot
    ) +
      theme(legend.box = "vertical")
  ),
  
  ## Distribution of features weight
  tar_target(
    spls_features_weight_distribution,
    plot_features_weight_distr(spls_output)
  ),
  
  ## Plot of top contributing features
  tar_target(
    spls_top_features_plot,
    plot_top_features(
      spls_output,
      mo_data = mo_set_complete,
      label_cols = list(
        "rnaseq" = "Name",
        "metabolome" = "name"
      )
    )
  ),
  
  ## Table of selected features
  tar_target(
    spls_selected_features,
    get_selected_features(spls_output)
  )
)
list(
  ## Generating standardised output
  tar_target(
    so2pls_output,
    get_output(so2pls_final_run)
  ),
  
  ## Percentage of variance explained
  tar_target(
    so2pls_plot_variance_explained,
    plot_variance_explained(so2pls_output, ncol = 1) +
      theme(axis.text.x = element_text(size = 9, angle = 30, hjust = 1))
  ),
  
  ## Samples score matrix plot
  tar_target(
    so2pls_samples_scores_plot,
    plot_samples_score(
      so2pls_output,
      latent_dimensions = "joint component 1",
      mo_data = mo_set_complete,
      colour_upper = "status",
      scale_colour_upper = palette_status,
      shape_upper = "gender"
    )
  ),
  
  ## Distribution of features weight
  tar_target(
    so2pls_features_weight_distribution,
    plot_features_weight_distr(so2pls_output) +
      plot_layout(ncol = 2)
  ),
  
  ## Plot of top contributing features
  tar_target(
    so2pls_top_features_plot,
    plot_top_features(
      so2pls_output,
      mo_data = mo_set_complete,
      label_cols = list(
        "rnaseq" = "Name",
        "metabolome" = "name"
      )
    )
  ),
  
  ## Table of selected features
  tar_target(
    so2pls_selected_features,
    get_selected_features(
      so2pls_output,
      latent_dimensions = "joint component 1"
    )
  )
)
list(
  ## Generating standardised output
  tar_target(
    mofa_output,
    get_output(mofa_trained)
  ),
  
  ## Percentage of variance explained
  tar_target(
    mofa_plot_variance_explained,
    plot_variance_explained(mofa_output, ncol = 1) +
      theme(axis.text.x = element_text(size = 9, angle = 30, hjust = 1))
  ),
  
  ## Samples score matrix plot
  tar_target(
    mofa_samples_scores_plot,
    plot_samples_score(
      mofa_output,
      latent_dimensions = paste("Factor", 1:4),
      mo_data = mo_set_complete,
      colour_upper = "status",
      scale_colour_upper = palette_status,
      shape_upper = "gender",
      colour_lower = "geno_comp_cluster",
      scale_colour_lower = palette_geno_comp
    ) +
      theme(legend.box = "vertical")
  ),
  
  ## Distribution of features weight
  tar_target(
    mofa_features_weight_distribution,
    plot_features_weight_distr(
      mofa_output,
      latent_dimensions = paste("Factor", 1:4)
    ) +
      plot_layout(ncol = 1)
  ),
  
  ## Plot of top contributing features
  tar_target(
    mofa_top_features_plot,
    plot_top_features(
      mofa_output,
      mo_data = mo_set_complete,
      label_cols = list(
        "rnaseq" = "Name",
        "metabolome" = "name"
      ),
      latent_dimensions = paste("Factor", 1:2)
    )
  ),
  
  ## Table of top contributing features
  tar_target(
    mofa_top_features,
    get_top_features(
      mofa_output,
      min_importance = 0.8,
      mo_data = mo_set_complete
    )
  )
)
list(
  ## Generating standardised output
  tar_target(
    diablo_output,
    get_output(diablo_final_run)
  ),
  
  ## Percentage of variance explained
  tar_target(
    diablo_plot_variance_explained,
    plot_variance_explained(diablo_output, ncol = 2)
  ),
  
  ## Samples score matrix plot
  tar_target(
    diablo_samples_scores_plot,
    plot_samples_score(
      diablo_output,
      mo_data = mo_set_complete,
      colour_upper = "status",
      scale_colour_upper = palette_status,
      shape_upper = "gender",
      colour_lower = "rnaseq_batch",
      scale_colour_lower = palette_rnaseq_batch
    ) +
      theme(legend.box = "vertical")
  ),
  
  ## Distribution of features weight
  tar_target(
    diablo_features_weight_distribution,
    plot_features_weight_distr(
      diablo_output
    ) +
      plot_layout(ncol = 1)
  ),
  
  ## Plot of top contributing features
  tar_target(
    diablo_top_features_plot,
    plot_top_features(
      diablo_output,
      mo_data = mo_set_complete,
      label_cols = list(
        "rnaseq" = "Name",
        "metabolome" = "name"
      ),
      latent_dimensions = paste("Component", 1:2)
    )
  ),
  
  ## Table of top contributing features
  tar_target(
    diablo_selected_features,
    get_selected_features(diablo_output) 
  )
)