J. Taroni 2018

Functions and directory set up

# magrittr pipe
`%>%` <- dplyr::`%>%`
source(file.path("util", "plier_util.R"))
source(file.path("util", "test_LV_differences.R"))
# plot and result directory setup for this notebook
plot.dir <- file.path("plots", "24")
dir.create(plot.dir, recursive = TRUE, showWarnings = FALSE)
results.dir <- file.path("results", "24")
dir.create(results.dir, recursive = TRUE, showWarnings = FALSE)

Read in data

Specifically, we’ll look at RNA-seq data that’s been processed various ways (e.g., taking into account experimental design or not, etc.).

Covariate information

covariate.df <- readr::read_tsv(file.path("data", "rtx", 
                                          "RTX_full_covariates.tsv"))
Parsed with column specification:
cols(
  .default = col_character(),
  barcode = col_integer(),
  AGE = col_integer(),
  bcells = col_double(),
  HGB = col_double(),
  `Platelet Count` = col_double(),
  WBC = col_double(),
  Lymphs = col_double(),
  Neutrophils = col_double(),
  Eosinophils = col_double(),
  Tscore = col_integer()
)
See spec(...) for full column specifications.

Counts

# tximport gene-level data -- includes counts, TPM
gene.summary <- readRDS(file.path("data", "rtx", "tximport.RDS"))
# extract count matrix -- we used `countsFromAbundance = "no"` to generate this
count.matrix <- gene.summary$counts
# log2 transform plus some constant, here 1, to account for zeros
log.count <- log2(count.matrix + 1)

VST - blind to experimental design

vst.blind <- readr::read_tsv(file.path("data", "rtx", "VST_blind.pcl"))
Parsed with column specification:
cols(
  .default = col_double(),
  Gene = col_character()
)
See spec(...) for full column specifications.

VST - batch, timepoint, responder status

Note that the experimental design we gave the DESeq2::vst function may ultimately not be the one we’d like to use.

vst.design <- readr::read_tsv(file.path("data", "rtx", "VST_design.pcl"))
Parsed with column specification:
cols(
  .default = col_double(),
  Gene = col_character()
)
See spec(...) for full column specifications.

PCA on full expression matrix

PCAPlotWrapper <- function(exprs, plot.title) {
  # This is only intended to be used in this global environment where we have
  # covariate.df and the magrittr pipe already
  # takes the rituximab expression data (exprs) where rows are genes and columns 
  # are samples and makes a plot of PC1-2 with the title supplied as plot.title
  # argument
  
  # PCA
  pc.results <- prcomp(t(exprs))
  cum.var.exp <- cumsum(pc.results$sdev^2 / sum(pc.results$sdev^2))
  # PC1-2 in form suitable for ggplot2
  pc.df <- as.data.frame(cbind(rownames(pc.results$x), pc.results$x[, 1:2]))
  colnames(pc.df)[1] <- "Sample"
  
  # check that the barcodes are in agreement
  barcode.check <- all(covariate.df$barcode == substr(pc.df[[1]], start = 1, 
                                                      stop = 6))
  if (!barcode.check) {
    stop("Something went wrong, the sample barcodes are not in the same order!")
  }
  
  # now that we've ensured that the barcodes are in the same order, we'll 
  # add in the batch information
  pc.df$Batch <- covariate.df$procbatch
  
  # plot!
  pc.df %>% 
    dplyr::mutate(PC1 = as.numeric(as.character(PC1)),
                  PC2 = as.numeric(as.character(PC2))) %>%
    ggplot2::ggplot(ggplot2::aes(x = PC1, y = PC2, color = Batch, 
                                 shape = Batch)) +
    ggplot2::geom_point(size = 3, alpha = 0.75) +
    ggplot2::labs(x = paste("PC1 (cum. var. exp. =", round(cum.var.exp[1], 3), 
                            ")"), 
                  y =  paste("PC2 (cum. var. exp. =", round(cum.var.exp[2], 3), 
                            ")"),
                  title = plot.title) +
    ggplot2::theme_bw() +
    ggplot2::theme(text = ggplot2::element_text(size = 15)) +
    ggplot2::scale_color_manual(values = c("#000000", "#969696"))
  
}
# the count matrix itself does not have column names because of the way it was
# processed
colnames(log.count) <- colnames(vst.blind)[2:ncol(vst.blind)]
PCAPlotWrapper(exprs = log.count, plot.title = "log2(counts + 1)")

PCAPlotWrapper(exprs = as.matrix(vst.blind[, 2:ncol(vst.blind)]),
               plot.title = "VST (blind)")

PCAPlotWrapper(exprs = as.matrix(vst.design[, 2:ncol(vst.design)]),
               plot.title = "VST")

Gene identifier conversion

All of the gene expression data from the RTX data set uses Ensembl gene IDs. PLIER, on the other hand, uses gene symbols. So we’ll need to do conversion. Let’s continue with variance stabilizing transformed data blinded to experimental design.

mart <- biomaRt::useDataset("hsapiens_gene_ensembl", 
                            biomaRt::useMart("ensembl"))
gene.df <- biomaRt::getBM(filters = "ensembl_gene_id",
                          attributes = c("ensembl_gene_id", "hgnc_symbol"),
                          values = vst.blind$Gene, 
                          mart = mart)

Batch submitting query [=---------------------------------]   3% eta: 26s
Batch submitting query [=---------------------------------]   4% eta: 29s
Batch submitting query [==--------------------------------]   6% eta: 29s
Batch submitting query [==--------------------------------]   7% eta: 29s
Batch submitting query [===-------------------------------]   9% eta: 29s
Batch submitting query [===-------------------------------]  10% eta: 31s
Batch submitting query [====------------------------------]  11% eta: 36s
Batch submitting query [====------------------------------]  13% eta: 34s
Batch submitting query [=====-----------------------------]  14% eta: 34s
Batch submitting query [=====-----------------------------]  16% eta: 33s
Batch submitting query [======----------------------------]  17% eta: 32s
Batch submitting query [======----------------------------]  19% eta: 32s
Batch submitting query [=======---------------------------]  20% eta: 31s
Batch submitting query [=======---------------------------]  21% eta: 30s
Batch submitting query [========--------------------------]  23% eta: 29s
Batch submitting query [========--------------------------]  24% eta: 29s
Batch submitting query [=========-------------------------]  26% eta: 28s
Batch submitting query [=========-------------------------]  27% eta: 27s
Batch submitting query [==========------------------------]  29% eta: 27s
Batch submitting query [==========------------------------]  30% eta: 27s
Batch submitting query [===========-----------------------]  31% eta: 27s
Batch submitting query [===========-----------------------]  33% eta: 27s
Batch submitting query [============----------------------]  34% eta: 26s
Batch submitting query [============----------------------]  36% eta: 26s
Batch submitting query [=============---------------------]  37% eta: 25s
Batch submitting query [=============---------------------]  39% eta: 24s
Batch submitting query [==============--------------------]  40% eta: 24s
Batch submitting query [==============--------------------]  41% eta: 23s
Batch submitting query [===============-------------------]  43% eta: 22s
Batch submitting query [===============-------------------]  44% eta: 22s
Batch submitting query [================------------------]  46% eta: 21s
Batch submitting query [================------------------]  47% eta: 20s
Batch submitting query [=================-----------------]  49% eta: 22s
Batch submitting query [=================-----------------]  50% eta: 22s
Batch submitting query [=================-----------------]  51% eta: 21s
Batch submitting query [==================----------------]  53% eta: 20s
Batch submitting query [==================----------------]  54% eta: 20s
Batch submitting query [===================---------------]  56% eta: 19s
Batch submitting query [===================---------------]  57% eta: 18s
Batch submitting query [====================--------------]  59% eta: 18s
Batch submitting query [====================--------------]  60% eta: 17s
Batch submitting query [=====================-------------]  61% eta: 17s
Batch submitting query [=====================-------------]  63% eta: 17s
Batch submitting query [======================------------]  64% eta: 16s
Batch submitting query [======================------------]  66% eta: 16s
Batch submitting query [=======================-----------]  67% eta: 15s
Batch submitting query [=======================-----------]  69% eta: 14s
Batch submitting query [========================----------]  70% eta: 14s
Batch submitting query [========================----------]  71% eta: 13s
Batch submitting query [=========================---------]  73% eta: 13s
Batch submitting query [=========================---------]  74% eta: 13s
Batch submitting query [==========================--------]  76% eta: 12s
Batch submitting query [==========================--------]  77% eta: 11s
Batch submitting query [===========================-------]  79% eta: 10s
Batch submitting query [===========================-------]  80% eta: 10s
Batch submitting query [============================------]  81% eta:  9s
Batch submitting query [============================------]  83% eta:  8s
Batch submitting query [=============================-----]  84% eta:  8s
Batch submitting query [=============================-----]  86% eta:  7s
Batch submitting query [==============================----]  87% eta:  6s
Batch submitting query [==============================----]  89% eta:  6s
Batch submitting query [===============================---]  90% eta:  5s
Batch submitting query [===============================---]  91% eta:  4s
Batch submitting query [================================--]  93% eta:  4s
Batch submitting query [================================--]  94% eta:  3s
Batch submitting query [=================================-]  96% eta:  2s
Batch submitting query [=================================-]  97% eta:  1s
Batch submitting query [==================================]  99% eta:  1s
Batch submitting query [==================================] 100% eta:  0s
                                                                         
# filter to remove genes without a gene symbol
gene.df <- gene.df %>% dplyr::filter(complete.cases(.))
vst.blind.annot <- dplyr::inner_join(gene.df, vst.blind,
                                     by = c("ensembl_gene_id" = "Gene")) %>%
  dplyr::select(-ensembl_gene_id)
colnames(vst.blind.annot)[1] <- "Gene"
# aggregate duplicate gene symbols to gene mean
vst.agg <- PrepExpressionDF(vst.blind.annot)

Read in recount2 PLIER model

recount.plier <- readRDS(file.path("data", "recount2_PLIER_data", 
                                   "recount_PLIER_model.RDS"))

Now filter the VST data to just the genes included in the recount2 model and prep it for use with various PLIER helper functions.

vst.filt <- vst.agg %>% 
  dplyr::filter(Gene %in% rownames(recount.plier$Z)) %>%
  tibble::column_to_rownames(var = "Gene")
Setting row names on a tibble is deprecated.
# save to file
vst.file <- file.path("data", "rtx", "VST_blind_filtered.RDS")
saveRDS(vst.filt, vst.file)
# let's remove the other VST data.frames or matrices and extraneous biomart 
# objects
rm(vst.agg, vst.blind, vst.blind.annot, vst.design, mart, count.matrix)
PCAPlotWrapper(exprs = vst.filt,
               plot.title = "VST filtered to genes in model")

PLIER

We’ll give PLIER row-normalized (z-scored) TPM data, as this is closest to the form we had the recount2 data in (RPKM) and, given this use case, the slight difference is unlikely to effect the results much.

# get the gene-level TPM
rtx.tpm <- gene.summary$abundance
# we'll need to convert to HGNC gene symbol
rtx.tpm <- tibble::rownames_to_column(data.frame(rtx.tpm), var = "Gene")
rtx.tpm.annot <- dplyr::inner_join(gene.df, rtx.tpm,
                                    by = c("ensembl_gene_id" = "Gene")) %>%
  dplyr::select(-ensembl_gene_id)
colnames(rtx.tpm.annot) <- c("Gene", colnames(log.count))
# Aggregate duplicate gene identifiers to mean
rtx.agg <- PrepExpressionDF(rtx.tpm.annot)
# remove first row without identifier & write to file
rtx.agg <- rtx.agg %>%
  dplyr::filter(Gene != "")
readr::write_tsv(rtx.agg, file.path("data", "rtx", "tpm_aggregated.pcl"))
# get in expression matrix form
rtx.exprs <- as.matrix(rtx.agg %>% tibble::column_to_rownames(var = "Gene"))
Setting row names on a tibble is deprecated.
# remove intermediates
rm(rtx.tpm.annot, rtx.tpm, rtx.agg)
# remove genes that are all zero
remove.index <- which(apply(rtx.exprs, 1, function(x) all(x == 0)))
rtx.exprs <- rtx.exprs[-remove.index, ]

Dataset-specific model

Training a PLIER model on this dataset

rtx.plier <- PLIERNewData(exprs.mat = as.matrix(rtx.exprs))
Loading required package: PLIER
Loading required package: RColorBrewer
Loading required package: gplots

Attaching package: ‘gplots’

The following object is masked from ‘package:stats’:

    lowess

Loading required package: pheatmap
Loading required package: glmnet
Loading required package: Matrix
Loading required package: foreach
Loaded glmnet 2.0-13

Loading required package: knitr
Loading required package: rsvd
Loading required package: qvalue
Removing 1 pathways with too few genesComputing SVD
Done
[1] 58.36176
[1] "L2 is set to 58.361764073198"
[1] "L1 is set to 29.180882036599"
errorY (SVD based:best possible) = 0.1835
iter1 errorY= 0.9724, Bdiff= 5546, Bkappa=63.6
iter2 errorY= 0.4744, Bdiff= 0.6175, Bkappa=40.06
iter3 errorY= 0.3814, Bdiff= 0.09271, Bkappa=32.25
iter4 errorY= 0.3606, Bdiff= 0.03585, Bkappa=28.31
iter5 errorY= 0.3526, Bdiff= 0.01795, Bkappa=26.55
iter6 errorY= 0.3493, Bdiff= 0.009761, Bkappa=25.69
iter7 errorY= 0.347, Bdiff= 0.006178, Bkappa=25.2
iter8 errorY= 0.3447, Bdiff= 0.004487, Bkappa=25.13
iter9 errorY= 0.3425, Bdiff= 0.003575, Bkappa=24.3
iter10 errorY= 0.3405, Bdiff= 0.002988, Bkappa=24.48
iter11 errorY= 0.3388, Bdiff= 0.002519, Bkappa=24.44
iter12 errorY= 0.3374, Bdiff= 0.002119, Bkappa=22.51
iter13 errorY= 0.3363, Bdiff= 0.001784, Bkappa=22.17
iter14 errorY= 0.3354, Bdiff= 0.00151, Bkappa=24.51
iter15 errorY= 0.3347, Bdiff= 0.001287, Bkappa=23.86
iter16 errorY= 0.3341, Bdiff= 0.001118, Bkappa=23.51
iter17 errorY= 0.3335, Bdiff= 0.0009953, Bkappa=20.35
iter18 errorY= 0.3331, Bdiff= 0.0009098, Bkappa=19.44
iter19 errorY= 0.3327, Bdiff= 0.0008494, Bkappa=19.55
Updating L3, current fraction= 0, target=0.7
L3 is set to 0.01172 in 8 iterations
iter20 errorY= 0.3301, prior information ratio= 0.03, Bdiff= 0.0009455, Bkappa=19.41;pos. col. U=17
iter21 errorY= 0.3292, prior information ratio= 0.03, Bdiff= 0.0008496, Bkappa=19.37;pos. col. U=16
iter22 errorY= 0.3286, prior information ratio= 0.05, Bdiff= 0.0007274, Bkappa=19.29;pos. col. U=14
iter23 errorY= 0.3282, prior information ratio= 0.05, Bdiff= 0.0006296, Bkappa=20.19;pos. col. U=14
iter24 errorY= 0.3279, prior information ratio= 0.05, Bdiff= 0.0005488, Bkappa=20.44;pos. col. U=14
iter25 errorY= 0.3276, prior information ratio= 0.04, Bdiff= 0.0004819, Bkappa=20.63;pos. col. U=15
iter26 errorY= 0.3274, prior information ratio= 0.05, Bdiff= 0.0004247, Bkappa=20.81;pos. col. U=15
iter27 errorY= 0.3272, prior information ratio= 0.05, Bdiff= 0.0003731, Bkappa=20.99;pos. col. U=15
iter28 errorY= 0.327, prior information ratio= 0.04, Bdiff= 0.0003264, Bkappa=21.13;pos. col. U=16
iter29 errorY= 0.3268, prior information ratio= 0.04, Bdiff= 0.0002838, Bkappa=21.27;pos. col. U=16
iter30 errorY= 0.3267, prior information ratio= 0.04, Bdiff= 0.0002474, Bkappa=21.43;pos. col. U=16
iter31 errorY= 0.3265, prior information ratio= 0.05, Bdiff= 0.0002154, Bkappa=21.91;pos. col. U=16
iter32 errorY= 0.3264, prior information ratio= 0.04, Bdiff= 0.0001876, Bkappa=21.97;pos. col. U=17
iter33 errorY= 0.3263, prior information ratio= 0.04, Bdiff= 0.0001639, Bkappa=21.96;pos. col. U=17
iter34 errorY= 0.3262, prior information ratio= 0.04, Bdiff= 0.0001442, Bkappa=21.89;pos. col. U=17
iter35 errorY= 0.3261, prior information ratio= 0.04, Bdiff= 0.0001276, Bkappa=21.76;pos. col. U=17
iter36 errorY= 0.326, prior information ratio= 0.04, Bdiff= 0.0001132, Bkappa=21.57;pos. col. U=17
iter37 errorY= 0.326, prior information ratio= 0.04, Bdiff= 0.0001006, Bkappa=21.32;pos. col. U=17
iter38 errorY= 0.3259, prior information ratio= 0.04, Bdiff= 8.93e-05, Bkappa=21.02;pos. col. U=17
iter39 errorY= 0.3258, prior information ratio= 0.04, Bdiff= 7.94e-05, Bkappa=20.76;pos. col. U=17
Updating L3, current fraction= 0.7391, target=0.7
L3 not changed
iter40 errorY= 0.3258, prior information ratio= 0.04, Bdiff= 7.111e-05, Bkappa=20.54;pos. col. U=17
iter41 errorY= 0.3257, prior information ratio= 0.04, Bdiff= 6.371e-05, Bkappa=20.32;pos. col. U=17
iter42 errorY= 0.3256, prior information ratio= 0.04, Bdiff= 5.733e-05, Bkappa=20.1;pos. col. U=17
iter43 errorY= 0.3256, prior information ratio= 0.04, Bdiff= 5.18e-05, Bkappa=19.88;pos. col. U=17
iter44 errorY= 0.3255, prior information ratio= 0.04, Bdiff= 4.707e-05, Bkappa=19.66;pos. col. U=17
iter45 errorY= 0.3255, prior information ratio= 0.04, Bdiff= 4.307e-05, Bkappa=19.48;pos. col. U=17
iter46 errorY= 0.3254, prior information ratio= 0.04, Bdiff= 3.973e-05, Bkappa=19.31;pos. col. U=17
iter47 errorY= 0.3254, prior information ratio= 0.04, Bdiff= 3.69e-05, Bkappa=19.14;pos. col. U=17
iter48 errorY= 0.3253, prior information ratio= 0.04, Bdiff= 3.456e-05, Bkappa=18.98;pos. col. U=17
iter49 errorY= 0.3253, prior information ratio= 0.04, Bdiff= 3.255e-05, Bkappa=18.82;pos. col. U=17
iter50 errorY= 0.3252, prior information ratio= 0.04, Bdiff= 3.086e-05, Bkappa=18.5;pos. col. U=17
iter51 errorY= 0.3252, prior information ratio= 0.04, Bdiff= 2.947e-05, Bkappa=18.47;pos. col. U=17
iter52 errorY= 0.3251, prior information ratio= 0.04, Bdiff= 2.84e-05, Bkappa=18.43;pos. col. U=17
iter53 errorY= 0.3251, prior information ratio= 0.04, Bdiff= 2.762e-05, Bkappa=18.39;pos. col. U=17
iter54 errorY= 0.325, prior information ratio= 0.04, Bdiff= 2.704e-05, Bkappa=18.35;pos. col. U=17
iter55 errorY= 0.325, prior information ratio= 0.04, Bdiff= 2.667e-05, Bkappa=18.3;pos. col. U=17
iter56 errorY= 0.3249, prior information ratio= 0.04, Bdiff= 2.647e-05, Bkappa=18.26;pos. col. U=17
iter57 errorY= 0.3249, prior information ratio= 0.04, Bdiff= 2.642e-05, Bkappa=18.21;pos. col. U=17
iter58 errorY= 0.3249, prior information ratio= 0.04, Bdiff= 2.649e-05, Bkappa=18.17;pos. col. U=17
iter59 errorY= 0.3248, prior information ratio= 0.04, Bdiff= 2.671e-05, Bkappa=18.29;pos. col. U=17
Updating L3, current fraction= 0.7391, target=0.7
L3 not changed
iter60 errorY= 0.3248, prior information ratio= 0.04, Bdiff= 2.709e-05, Bkappa=18.26;pos. col. U=17
iter61 errorY= 0.3247, prior information ratio= 0.04, Bdiff= 2.763e-05, Bkappa=18.44;pos. col. U=17
iter62 errorY= 0.3247, prior information ratio= 0.04, Bdiff= 2.811e-05, Bkappa=18.43;pos. col. U=17
iter63 errorY= 0.3247, prior information ratio= 0.04, Bdiff= 2.852e-05, Bkappa=18.43;pos. col. U=17
iter64 errorY= 0.3246, prior information ratio= 0.04, Bdiff= 2.89e-05, Bkappa=18.42;pos. col. U=17
iter65 errorY= 0.3246, prior information ratio= 0.04, Bdiff= 2.914e-05, Bkappa=18.42;pos. col. U=16
iter66 errorY= 0.3245, prior information ratio= 0.04, Bdiff= 2.942e-05, Bkappa=18.42;pos. col. U=17
iter67 errorY= 0.3245, prior information ratio= 0.04, Bdiff= 2.96e-05, Bkappa=18.41;pos. col. U=17
iter68 errorY= 0.3245, prior information ratio= 0.04, Bdiff= 2.955e-05, Bkappa=18.41;pos. col. U=17
iter69 errorY= 0.3244, prior information ratio= 0.04, Bdiff= 2.934e-05, Bkappa=18.4;pos. col. U=17
iter70 errorY= 0.3244, prior information ratio= 0.04, Bdiff= 2.887e-05, Bkappa=18.39;pos. col. U=17
iter71 errorY= 0.3243, prior information ratio= 0.04, Bdiff= 2.825e-05, Bkappa=18.39;pos. col. U=17
iter72 errorY= 0.3243, prior information ratio= 0.04, Bdiff= 2.749e-05, Bkappa=18.38;pos. col. U=17
iter73 errorY= 0.3243, prior information ratio= 0.04, Bdiff= 2.634e-05, Bkappa=18.37;pos. col. U=17
iter74 errorY= 0.3242, prior information ratio= 0.04, Bdiff= 2.51e-05, Bkappa=18.36;pos. col. U=17
iter75 errorY= 0.3242, prior information ratio= 0.04, Bdiff= 2.378e-05, Bkappa=18.35;pos. col. U=17
iter76 errorY= 0.3242, prior information ratio= 0.04, Bdiff= 2.254e-05, Bkappa=18.37;pos. col. U=17
iter77 errorY= 0.3241, prior information ratio= 0.04, Bdiff= 2.139e-05, Bkappa=18.39;pos. col. U=17
iter78 errorY= 0.3241, prior information ratio= 0.04, Bdiff= 2.029e-05, Bkappa=18.4;pos. col. U=17
iter79 errorY= 0.3241, prior information ratio= 0.04, Bdiff= 1.922e-05, Bkappa=18.42;pos. col. U=17
Updating L3, current fraction= 0.7391, target=0.7
L3 not changed
iter80 errorY= 0.3241, prior information ratio= 0.04, Bdiff= 1.824e-05, Bkappa=18.44;pos. col. U=17
iter81 errorY= 0.324, prior information ratio= 0.04, Bdiff= 1.73e-05, Bkappa=18.46;pos. col. U=17
iter82 errorY= 0.324, prior information ratio= 0.04, Bdiff= 1.643e-05, Bkappa=18.48;pos. col. U=17
iter83 errorY= 0.324, prior information ratio= 0.04, Bdiff= 1.566e-05, Bkappa=18.5;pos. col. U=17
iter84 errorY= 0.324, prior information ratio= 0.04, Bdiff= 1.5e-05, Bkappa=18.53;pos. col. U=17
iter85 errorY= 0.324, prior information ratio= 0.04, Bdiff= 1.44e-05, Bkappa=18.3;pos. col. U=17
iter86 errorY= 0.324, prior information ratio= 0.04, Bdiff= 1.387e-05, Bkappa=18.32;pos. col. U=17
iter87 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.339e-05, Bkappa=18.34;pos. col. U=17
iter88 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.296e-05, Bkappa=18.37;pos. col. U=17
iter89 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.258e-05, Bkappa=18.39;pos. col. U=17
iter90 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.224e-05, Bkappa=18.41;pos. col. U=17
iter91 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.192e-05, Bkappa=18.44;pos. col. U=17
iter92 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.162e-05, Bkappa=18.46;pos. col. U=17
iter93 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.133e-05, Bkappa=18.51;pos. col. U=17
iter94 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.106e-05, Bkappa=18.58;pos. col. U=17
iter95 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.079e-05, Bkappa=18.65;pos. col. U=17
iter96 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.048e-05, Bkappa=18.72;pos. col. U=17
iter97 errorY= 0.3239, prior information ratio= 0.04, Bdiff= 1.019e-05, Bkappa=18.78;pos. col. U=17
iter98 errorY= 0.3238, prior information ratio= 0.04, Bdiff= 9.922e-06, Bkappa=18.85;pos. col. U=17
converged at  iteration 98
There are 15  LVs with AUC>0.70
saveRDS(rtx.plier, file.path("data", "rtx", "RTX_PLIER_model.RDS"))
PLIER::plotU(rtx.plier, auc.cutoff = 0.75, fontsize_row = 7,
             fontsize_col = 10)

There’s no neutrophil signature with AUC > 0.75. That’s interesting because this is a signal that we would expect in this whole blood data.

pdf(file.path(plot.dir, "RTX_model_U_plot.pdf"))
PLIER::plotU(rtx.plier, auc.cutoff = 0.75, fontsize_row = 7,
             fontsize_col = 10)
dev.off()
null device 
          1 
PCAPlotWrapper(exprs = rtx.plier$B, 
               plot.title = "Dataset-specific PLIER B, All LVs")

recount2 model

recount.b <- GetNewDataB(exprs.mat = as.matrix(rtx.exprs),
                         plier.model = recount.plier)
saveRDS(recount.b, file.path("data", "rtx", "RTX_recount2_B.RDS"))
PCAPlotWrapper(exprs = recount.b, 
               plot.title = "recount2 PLIER B, All LVs")

Final plotting

We’ll plot the following three plots, as these are the expected into any kind of supervised machine learning model (predicting response):

  • VST expression data (only genes that overlap with recount2 PLIER model)
  • Dataset-specific PLIER B, all LVs
  • recount2 PLIER B, all LVs
exprs.plot <- PCAPlotWrapper(exprs = vst.filt,
                             plot.title = "VST filtered to genes in model")
rtx.plot <- PCAPlotWrapper(exprs = rtx.plier$B, 
                           plot.title = "Dataset-specific PLIER B, All LVs")
recount.plot <- PCAPlotWrapper(exprs = recount.b, 
                               plot.title = "recount2 PLIER B, All LVs")
pdf(file.path(plot.dir, "RTX_expected_ML_input_PCA.pdf"), height = 14, 
    width = 7)
cowplot::plot_grid(exprs.plot, rtx.plot, recount.plot, align = "h", ncol = 1)
dev.off()
null device 
          1 
LS0tCnRpdGxlOiAiRXhwbG9yZSB0aGUgUlRYIGRhdGEiCm91dHB1dDogICAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKKipKLiBUYXJvbmkgMjAxOCoqCgojIyBGdW5jdGlvbnMgYW5kIGRpcmVjdG9yeSBzZXQgdXAKCmBgYHtyfQojIG1hZ3JpdHRyIHBpcGUKYCU+JWAgPC0gZHBseXI6OmAlPiVgCnNvdXJjZShmaWxlLnBhdGgoInV0aWwiLCAicGxpZXJfdXRpbC5SIikpCnNvdXJjZShmaWxlLnBhdGgoInV0aWwiLCAidGVzdF9MVl9kaWZmZXJlbmNlcy5SIikpCmBgYAoKYGBge3J9CiMgcGxvdCBhbmQgcmVzdWx0IGRpcmVjdG9yeSBzZXR1cCBmb3IgdGhpcyBub3RlYm9vawpwbG90LmRpciA8LSBmaWxlLnBhdGgoInBsb3RzIiwgIjI0IikKZGlyLmNyZWF0ZShwbG90LmRpciwgcmVjdXJzaXZlID0gVFJVRSwgc2hvd1dhcm5pbmdzID0gRkFMU0UpCnJlc3VsdHMuZGlyIDwtIGZpbGUucGF0aCgicmVzdWx0cyIsICIyNCIpCmRpci5jcmVhdGUocmVzdWx0cy5kaXIsIHJlY3Vyc2l2ZSA9IFRSVUUsIHNob3dXYXJuaW5ncyA9IEZBTFNFKQpgYGAKCiMjIFJlYWQgaW4gZGF0YQoKU3BlY2lmaWNhbGx5LCB3ZSdsbCBsb29rIGF0IFJOQS1zZXEgZGF0YSB0aGF0J3MgYmVlbiBwcm9jZXNzZWQgdmFyaW91cyB3YXlzIAooZS5nLiwgdGFraW5nIGludG8gYWNjb3VudCBleHBlcmltZW50YWwgZGVzaWduIG9yIG5vdCwgZXRjLikuCgojIyMgQ292YXJpYXRlIGluZm9ybWF0aW9uCgpgYGB7cn0KY292YXJpYXRlLmRmIDwtIHJlYWRyOjpyZWFkX3RzdihmaWxlLnBhdGgoImRhdGEiLCAicnR4IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSVFhfZnVsbF9jb3ZhcmlhdGVzLnRzdiIpKQpgYGAKCiMjIyBDb3VudHMKCmBgYHtyfQojIHR4aW1wb3J0IGdlbmUtbGV2ZWwgZGF0YSAtLSBpbmNsdWRlcyBjb3VudHMsIFRQTQpnZW5lLnN1bW1hcnkgPC0gcmVhZFJEUyhmaWxlLnBhdGgoImRhdGEiLCAicnR4IiwgInR4aW1wb3J0LlJEUyIpKQojIGV4dHJhY3QgY291bnQgbWF0cml4IC0tIHdlIHVzZWQgYGNvdW50c0Zyb21BYnVuZGFuY2UgPSAibm8iYCB0byBnZW5lcmF0ZSB0aGlzCmNvdW50Lm1hdHJpeCA8LSBnZW5lLnN1bW1hcnkkY291bnRzCiMgbG9nMiB0cmFuc2Zvcm0gcGx1cyBzb21lIGNvbnN0YW50LCBoZXJlIDEsIHRvIGFjY291bnQgZm9yIHplcm9zCmxvZy5jb3VudCA8LSBsb2cyKGNvdW50Lm1hdHJpeCArIDEpCmBgYAoKIyMjIFZTVCAtIGJsaW5kIHRvIGV4cGVyaW1lbnRhbCBkZXNpZ24KCmBgYHtyfQp2c3QuYmxpbmQgPC0gcmVhZHI6OnJlYWRfdHN2KGZpbGUucGF0aCgiZGF0YSIsICJydHgiLCAiVlNUX2JsaW5kLnBjbCIpKQpgYGAKCiMjIyBWU1QgLSBiYXRjaCwgdGltZXBvaW50LCByZXNwb25kZXIgc3RhdHVzCgpOb3RlIHRoYXQgdGhlIGV4cGVyaW1lbnRhbCBkZXNpZ24gd2UgZ2F2ZSB0aGUgYERFU2VxMjo6dnN0YCBmdW5jdGlvbiBtYXkgCnVsdGltYXRlbHkgbm90IGJlIHRoZSBvbmUgd2UnZCBsaWtlIHRvIHVzZS4KCmBgYHtyfQp2c3QuZGVzaWduIDwtIHJlYWRyOjpyZWFkX3RzdihmaWxlLnBhdGgoImRhdGEiLCAicnR4IiwgIlZTVF9kZXNpZ24ucGNsIikpCmBgYAoKIyMgUENBIG9uIGZ1bGwgZXhwcmVzc2lvbiBtYXRyaXgKCmBgYHtyfQpQQ0FQbG90V3JhcHBlciA8LSBmdW5jdGlvbihleHBycywgcGxvdC50aXRsZSkgewogICMgVGhpcyBpcyBvbmx5IGludGVuZGVkIHRvIGJlIHVzZWQgaW4gdGhpcyBnbG9iYWwgZW52aXJvbm1lbnQgd2hlcmUgd2UgaGF2ZQogICMgY292YXJpYXRlLmRmIGFuZCB0aGUgbWFncml0dHIgcGlwZSBhbHJlYWR5CiAgIyB0YWtlcyB0aGUgcml0dXhpbWFiIGV4cHJlc3Npb24gZGF0YSAoZXhwcnMpIHdoZXJlIHJvd3MgYXJlIGdlbmVzIGFuZCBjb2x1bW5zIAogICMgYXJlIHNhbXBsZXMgYW5kIG1ha2VzIGEgcGxvdCBvZiBQQzEtMiB3aXRoIHRoZSB0aXRsZSBzdXBwbGllZCBhcyBwbG90LnRpdGxlCiAgIyBhcmd1bWVudAogIAogICMgUENBCiAgcGMucmVzdWx0cyA8LSBwcmNvbXAodChleHBycykpCiAgY3VtLnZhci5leHAgPC0gY3Vtc3VtKHBjLnJlc3VsdHMkc2Rldl4yIC8gc3VtKHBjLnJlc3VsdHMkc2Rldl4yKSkKICAjIFBDMS0yIGluIGZvcm0gc3VpdGFibGUgZm9yIGdncGxvdDIKICBwYy5kZiA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKHJvd25hbWVzKHBjLnJlc3VsdHMkeCksIHBjLnJlc3VsdHMkeFssIDE6Ml0pKQogIGNvbG5hbWVzKHBjLmRmKVsxXSA8LSAiU2FtcGxlIgogIAogICMgY2hlY2sgdGhhdCB0aGUgYmFyY29kZXMgYXJlIGluIGFncmVlbWVudAogIGJhcmNvZGUuY2hlY2sgPC0gYWxsKGNvdmFyaWF0ZS5kZiRiYXJjb2RlID09IHN1YnN0cihwYy5kZltbMV1dLCBzdGFydCA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gNikpCiAgaWYgKCFiYXJjb2RlLmNoZWNrKSB7CiAgICBzdG9wKCJTb21ldGhpbmcgd2VudCB3cm9uZywgdGhlIHNhbXBsZSBiYXJjb2RlcyBhcmUgbm90IGluIHRoZSBzYW1lIG9yZGVyISIpCiAgfQogIAogICMgbm93IHRoYXQgd2UndmUgZW5zdXJlZCB0aGF0IHRoZSBiYXJjb2RlcyBhcmUgaW4gdGhlIHNhbWUgb3JkZXIsIHdlJ2xsIAogICMgYWRkIGluIHRoZSBiYXRjaCBpbmZvcm1hdGlvbgogIHBjLmRmJEJhdGNoIDwtIGNvdmFyaWF0ZS5kZiRwcm9jYmF0Y2gKICAKICAjIHBsb3QhCiAgcGMuZGYgJT4lIAogICAgZHBseXI6Om11dGF0ZShQQzEgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihQQzEpKSwKICAgICAgICAgICAgICAgICAgUEMyID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoUEMyKSkpICU+JQogICAgZ2dwbG90Mjo6Z2dwbG90KGdncGxvdDI6OmFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IEJhdGNoLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBCYXRjaCkpICsKICAgIGdncGxvdDI6Omdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMC43NSkgKwogICAgZ2dwbG90Mjo6bGFicyh4ID0gcGFzdGUoIlBDMSAoY3VtLiB2YXIuIGV4cC4gPSIsIHJvdW5kKGN1bS52YXIuZXhwWzFdLCAzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKSIpLCAKICAgICAgICAgICAgICAgICAgeSA9ICBwYXN0ZSgiUEMyIChjdW0uIHZhci4gZXhwLiA9Iiwgcm91bmQoY3VtLnZhci5leHBbMl0sIDMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICIpIiksCiAgICAgICAgICAgICAgICAgIHRpdGxlID0gcGxvdC50aXRsZSkgKwogICAgZ2dwbG90Mjo6dGhlbWVfYncoKSArCiAgICBnZ3Bsb3QyOjp0aGVtZSh0ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpICsKICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDAwMDAwIiwgIiM5Njk2OTYiKSkKICAKfQpgYGAKCmBgYHtyfQojIHRoZSBjb3VudCBtYXRyaXggaXRzZWxmIGRvZXMgbm90IGhhdmUgY29sdW1uIG5hbWVzIGJlY2F1c2Ugb2YgdGhlIHdheSBpdCB3YXMKIyBwcm9jZXNzZWQKY29sbmFtZXMobG9nLmNvdW50KSA8LSBjb2xuYW1lcyh2c3QuYmxpbmQpWzI6bmNvbCh2c3QuYmxpbmQpXQpQQ0FQbG90V3JhcHBlcihleHBycyA9IGxvZy5jb3VudCwgcGxvdC50aXRsZSA9ICJsb2cyKGNvdW50cyArIDEpIikKYGBgCgpgYGB7cn0KUENBUGxvdFdyYXBwZXIoZXhwcnMgPSBhcy5tYXRyaXgodnN0LmJsaW5kWywgMjpuY29sKHZzdC5ibGluZCldKSwKICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9ICJWU1QgKGJsaW5kKSIpCmBgYAoKYGBge3J9ClBDQVBsb3RXcmFwcGVyKGV4cHJzID0gYXMubWF0cml4KHZzdC5kZXNpZ25bLCAyOm5jb2wodnN0LmRlc2lnbildKSwKICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9ICJWU1QiKQpgYGAKCiMjIEdlbmUgaWRlbnRpZmllciBjb252ZXJzaW9uCgpBbGwgb2YgdGhlIGdlbmUgZXhwcmVzc2lvbiBkYXRhIGZyb20gdGhlIFJUWCBkYXRhIHNldCB1c2VzIEVuc2VtYmwgZ2VuZSBJRHMuClBMSUVSLCBvbiB0aGUgb3RoZXIgaGFuZCwgdXNlcyBnZW5lIHN5bWJvbHMuClNvIHdlJ2xsIG5lZWQgdG8gZG8gY29udmVyc2lvbi4KTGV0J3MgY29udGludWUgd2l0aCB2YXJpYW5jZSBzdGFiaWxpemluZyB0cmFuc2Zvcm1lZCBkYXRhIGJsaW5kZWQgdG8gCmV4cGVyaW1lbnRhbCBkZXNpZ24uCgpgYGB7cn0KbWFydCA8LSBiaW9tYVJ0Ojp1c2VEYXRhc2V0KCJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpb21hUnQ6OnVzZU1hcnQoImVuc2VtYmwiKSkKZ2VuZS5kZiA8LSBiaW9tYVJ0OjpnZXRCTShmaWx0ZXJzID0gImVuc2VtYmxfZ2VuZV9pZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXR0cmlidXRlcyA9IGMoImVuc2VtYmxfZ2VuZV9pZCIsICJoZ25jX3N5bWJvbCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IHZzdC5ibGluZCRHZW5lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBtYXJ0ID0gbWFydCkKIyBmaWx0ZXIgdG8gcmVtb3ZlIGdlbmVzIHdpdGhvdXQgYSBnZW5lIHN5bWJvbApnZW5lLmRmIDwtIGdlbmUuZGYgJT4lIGRwbHlyOjpmaWx0ZXIoY29tcGxldGUuY2FzZXMoLikpCmBgYAoKYGBge3J9CnZzdC5ibGluZC5hbm5vdCA8LSBkcGx5cjo6aW5uZXJfam9pbihnZW5lLmRmLCB2c3QuYmxpbmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoImVuc2VtYmxfZ2VuZV9pZCIgPSAiR2VuZSIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1lbnNlbWJsX2dlbmVfaWQpCmNvbG5hbWVzKHZzdC5ibGluZC5hbm5vdClbMV0gPC0gIkdlbmUiCgojIGFnZ3JlZ2F0ZSBkdXBsaWNhdGUgZ2VuZSBzeW1ib2xzIHRvIGdlbmUgbWVhbgp2c3QuYWdnIDwtIFByZXBFeHByZXNzaW9uREYodnN0LmJsaW5kLmFubm90KQpgYGAKCiMjIFJlYWQgaW4gcmVjb3VudDIgUExJRVIgbW9kZWwKCmBgYHtyfQpyZWNvdW50LnBsaWVyIDwtIHJlYWRSRFMoZmlsZS5wYXRoKCJkYXRhIiwgInJlY291bnQyX1BMSUVSX2RhdGEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmVjb3VudF9QTElFUl9tb2RlbC5SRFMiKSkKYGBgCgpOb3cgZmlsdGVyIHRoZSBWU1QgZGF0YSB0byBqdXN0IHRoZSBnZW5lcyBpbmNsdWRlZCBpbiB0aGUgcmVjb3VudDIgbW9kZWwgYW5kCnByZXAgaXQgZm9yIHVzZSB3aXRoIHZhcmlvdXMgUExJRVIgaGVscGVyIGZ1bmN0aW9ucy4KCmBgYHtyfQp2c3QuZmlsdCA8LSB2c3QuYWdnICU+JSAKICBkcGx5cjo6ZmlsdGVyKEdlbmUgJWluJSByb3duYW1lcyhyZWNvdW50LnBsaWVyJFopKSAlPiUKICB0aWJibGU6OmNvbHVtbl90b19yb3duYW1lcyh2YXIgPSAiR2VuZSIpCiMgc2F2ZSB0byBmaWxlCnZzdC5maWxlIDwtIGZpbGUucGF0aCgiZGF0YSIsICJydHgiLCAiVlNUX2JsaW5kX2ZpbHRlcmVkLlJEUyIpCnNhdmVSRFModnN0LmZpbHQsIHZzdC5maWxlKQpgYGAKCmBgYHtyfQojIGxldCdzIHJlbW92ZSB0aGUgb3RoZXIgVlNUIGRhdGEuZnJhbWVzIG9yIG1hdHJpY2VzIGFuZCBleHRyYW5lb3VzIGJpb21hcnQgCiMgb2JqZWN0cwpybSh2c3QuYWdnLCB2c3QuYmxpbmQsIHZzdC5ibGluZC5hbm5vdCwgdnN0LmRlc2lnbiwgbWFydCwgY291bnQubWF0cml4KQpgYGAKCmBgYHtyfQpQQ0FQbG90V3JhcHBlcihleHBycyA9IHZzdC5maWx0LAogICAgICAgICAgICAgICBwbG90LnRpdGxlID0gIlZTVCBmaWx0ZXJlZCB0byBnZW5lcyBpbiBtb2RlbCIpCmBgYAoKIyMgUExJRVIKCldlJ2xsIGdpdmUgUExJRVIgcm93LW5vcm1hbGl6ZWQgKHotc2NvcmVkKSBUUE0gZGF0YSwgYXMgdGhpcyBpcyBjbG9zZXN0IHRvIHRoZQpmb3JtIHdlIGhhZCB0aGUgcmVjb3VudDIgZGF0YSBpbiAoUlBLTSkgYW5kLCBnaXZlbiB0aGlzIHVzZSBjYXNlLCB0aGUgc2xpZ2h0IApkaWZmZXJlbmNlIGlzIHVubGlrZWx5IHRvIGVmZmVjdCB0aGUgcmVzdWx0cyBtdWNoLgoKYGBge3J9CiMgZ2V0IHRoZSBnZW5lLWxldmVsIFRQTQpydHgudHBtIDwtIGdlbmUuc3VtbWFyeSRhYnVuZGFuY2UKCiMgd2UnbGwgbmVlZCB0byBjb252ZXJ0IHRvIEhHTkMgZ2VuZSBzeW1ib2wKcnR4LnRwbSA8LSB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbihkYXRhLmZyYW1lKHJ0eC50cG0pLCB2YXIgPSAiR2VuZSIpCnJ0eC50cG0uYW5ub3QgPC0gZHBseXI6OmlubmVyX2pvaW4oZ2VuZS5kZiwgcnR4LnRwbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJlbnNlbWJsX2dlbmVfaWQiID0gIkdlbmUiKSkgJT4lCiAgZHBseXI6OnNlbGVjdCgtZW5zZW1ibF9nZW5lX2lkKQpjb2xuYW1lcyhydHgudHBtLmFubm90KSA8LSBjKCJHZW5lIiwgY29sbmFtZXMobG9nLmNvdW50KSkKCiMgQWdncmVnYXRlIGR1cGxpY2F0ZSBnZW5lIGlkZW50aWZpZXJzIHRvIG1lYW4KcnR4LmFnZyA8LSBQcmVwRXhwcmVzc2lvbkRGKHJ0eC50cG0uYW5ub3QpCgojIHJlbW92ZSBmaXJzdCByb3cgd2l0aG91dCBpZGVudGlmaWVyICYgd3JpdGUgdG8gZmlsZQpydHguYWdnIDwtIHJ0eC5hZ2cgJT4lCiAgZHBseXI6OmZpbHRlcihHZW5lICE9ICIiKQpyZWFkcjo6d3JpdGVfdHN2KHJ0eC5hZ2csIGZpbGUucGF0aCgiZGF0YSIsICJydHgiLCAidHBtX2FnZ3JlZ2F0ZWQucGNsIikpCgojIGdldCBpbiBleHByZXNzaW9uIG1hdHJpeCBmb3JtCnJ0eC5leHBycyA8LSBhcy5tYXRyaXgocnR4LmFnZyAlPiUgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXModmFyID0gIkdlbmUiKSkKYGBgCgpgYGB7cn0KIyByZW1vdmUgaW50ZXJtZWRpYXRlcwpybShydHgudHBtLmFubm90LCBydHgudHBtLCBydHguYWdnKQpgYGAKCmBgYHtyfQojIHJlbW92ZSBnZW5lcyB0aGF0IGFyZSBhbGwgemVybwpyZW1vdmUuaW5kZXggPC0gd2hpY2goYXBwbHkocnR4LmV4cHJzLCAxLCBmdW5jdGlvbih4KSBhbGwoeCA9PSAwKSkpCnJ0eC5leHBycyA8LSBydHguZXhwcnNbLXJlbW92ZS5pbmRleCwgXQpgYGAKCiMjIyBEYXRhc2V0LXNwZWNpZmljIG1vZGVsCgpUcmFpbmluZyBhIFBMSUVSIG1vZGVsIG9uIHRoaXMgZGF0YXNldAoKYGBge3J9CnJ0eC5wbGllciA8LSBQTElFUk5ld0RhdGEoZXhwcnMubWF0ID0gYXMubWF0cml4KHJ0eC5leHBycykpCnNhdmVSRFMocnR4LnBsaWVyLCBmaWxlLnBhdGgoImRhdGEiLCAicnR4IiwgIlJUWF9QTElFUl9tb2RlbC5SRFMiKSkKYGBgCgpgYGB7cn0KUExJRVI6OnBsb3RVKHJ0eC5wbGllciwgYXVjLmN1dG9mZiA9IDAuNzUsIGZvbnRzaXplX3JvdyA9IDcsCiAgICAgICAgICAgICBmb250c2l6ZV9jb2wgPSAxMCkKYGBgCgpUaGVyZSdzIG5vIG5ldXRyb3BoaWwgc2lnbmF0dXJlIHdpdGggYEFVQyA+IDAuNzVgLgpUaGF0J3MgaW50ZXJlc3RpbmcgYmVjYXVzZSB0aGlzIGlzIGEgc2lnbmFsIHRoYXQgd2Ugd291bGQgZXhwZWN0IGluIHRoaXMKd2hvbGUgYmxvb2QgZGF0YS4KCmBgYHtyfQpwZGYoZmlsZS5wYXRoKHBsb3QuZGlyLCAiUlRYX21vZGVsX1VfcGxvdC5wZGYiKSkKUExJRVI6OnBsb3RVKHJ0eC5wbGllciwgYXVjLmN1dG9mZiA9IDAuNzUsIGZvbnRzaXplX3JvdyA9IDcsCiAgICAgICAgICAgICBmb250c2l6ZV9jb2wgPSAxMCkKZGV2Lm9mZigpCmBgYAoKYGBge3J9ClBDQVBsb3RXcmFwcGVyKGV4cHJzID0gcnR4LnBsaWVyJEIsIAogICAgICAgICAgICAgICBwbG90LnRpdGxlID0gIkRhdGFzZXQtc3BlY2lmaWMgUExJRVIgQiwgQWxsIExWcyIpCmBgYAoKIyMjIHJlY291bnQyIG1vZGVsCgpgYGB7cn0KcmVjb3VudC5iIDwtIEdldE5ld0RhdGFCKGV4cHJzLm1hdCA9IGFzLm1hdHJpeChydHguZXhwcnMpLAogICAgICAgICAgICAgICAgICAgICAgICAgcGxpZXIubW9kZWwgPSByZWNvdW50LnBsaWVyKQpzYXZlUkRTKHJlY291bnQuYiwgZmlsZS5wYXRoKCJkYXRhIiwgInJ0eCIsICJSVFhfcmVjb3VudDJfQi5SRFMiKSkKYGBgCgpgYGB7cn0KUENBUGxvdFdyYXBwZXIoZXhwcnMgPSByZWNvdW50LmIsIAogICAgICAgICAgICAgICBwbG90LnRpdGxlID0gInJlY291bnQyIFBMSUVSIEIsIEFsbCBMVnMiKQpgYGAKCgojIyBGaW5hbCBwbG90dGluZwoKV2UnbGwgcGxvdCB0aGUgZm9sbG93aW5nIHRocmVlIHBsb3RzLCBhcyB0aGVzZSBhcmUgdGhlIGV4cGVjdGVkIGludG8gYW55IGtpbmQKb2Ygc3VwZXJ2aXNlZCBtYWNoaW5lIGxlYXJuaW5nIG1vZGVsIChwcmVkaWN0aW5nIHJlc3BvbnNlKToKCiogVlNUIGV4cHJlc3Npb24gZGF0YSAob25seSBnZW5lcyB0aGF0IG92ZXJsYXAgd2l0aCByZWNvdW50MiBQTElFUiBtb2RlbCkKKiBEYXRhc2V0LXNwZWNpZmljIFBMSUVSIEIsIGFsbCBMVnMKKiByZWNvdW50MiBQTElFUiBCLCBhbGwgTFZzCgpgYGB7cn0KZXhwcnMucGxvdCA8LSBQQ0FQbG90V3JhcHBlcihleHBycyA9IHZzdC5maWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSAiVlNUIGZpbHRlcmVkIHRvIGdlbmVzIGluIG1vZGVsIikKcnR4LnBsb3QgPC0gUENBUGxvdFdyYXBwZXIoZXhwcnMgPSBydHgucGxpZXIkQiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSAiRGF0YXNldC1zcGVjaWZpYyBQTElFUiBCLCBBbGwgTFZzIikKcmVjb3VudC5wbG90IDwtIFBDQVBsb3RXcmFwcGVyKGV4cHJzID0gcmVjb3VudC5iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSAicmVjb3VudDIgUExJRVIgQiwgQWxsIExWcyIpCmBgYAoKYGBge3J9CnBkZihmaWxlLnBhdGgocGxvdC5kaXIsICJSVFhfZXhwZWN0ZWRfTUxfaW5wdXRfUENBLnBkZiIpLCBoZWlnaHQgPSAxNCwgCiAgICB3aWR0aCA9IDcpCmNvd3Bsb3Q6OnBsb3RfZ3JpZChleHBycy5wbG90LCBydHgucGxvdCwgcmVjb3VudC5wbG90LCBhbGlnbiA9ICJoIiwgbmNvbCA9IDEpCmRldi5vZmYoKQpgYGAKCg==