1 Overview

CONCERTDR provides a complete pipeline for drug repurposing using the Connectivity Map (CMap) L1000 database. The core idea is signature matching: given a disease differential-expression signature (a ranked list of up- and down-regulated genes), CONCERTDR scores every perturbation in CMap and returns those whose transcriptional effect most strongly reverses the disease pattern.

This vignette demonstrates two complementary use cases using a bundled AML-relevant example dataset (163 genes × 496 signatures):

  • Use case 1 — Find repurposing compounds: score small-molecule (trt_cp) perturbations against an AML disease signature to identify candidate drugs.
  • Use case 2 — Find target genes: score gene overexpression (trt_oe) and CRISPR knockout (trt_xpr) perturbations against the same signature to nominate therapeutic gene targets.

All code in this vignette runs without any external downloads using the data bundled in inst/extdata/.

library(CONCERTDR)

2 Bundled Example Data

The package ships with a real CMap subset in inst/extdata/:

File Description
example_signature.txt Manually curated AML/BCR-ABL-themed demonstration query
example_reference_df.csv 163 genes × 496 CMap signatures (Level 5 z-scores)
example_siginfo.txt Metadata for the 496 signatures
example_geneinfo.txt CMap annotations for the 163 genes
example_compoundinfo.txt CMap compound, mechanism-of-action, and target annotations

The four CMap-derived files can be regenerated from the LINCS2020 source files with inst/scripts/make_example_data.R. The script records the source URLs, selection manifest, extraction procedure, and rounding used for the compact example. example_signature.txt is not a CMap measurement: it is a deterministic, manually curated query used to exercise both reversal-scoring directions. Its values should not be interpreted as estimates from a patient cohort or as biological validation of the example rankings.

sig_file  <- system.file("extdata", "example_signature.txt",
                          package = "CONCERTDR")
ref_file  <- system.file("extdata", "example_reference_df.csv",
                          package = "CONCERTDR")
sig_info_file  <- system.file("extdata", "example_siginfo.txt",
                               package = "CONCERTDR")
comp_info_file <- system.file("extdata", "example_compoundinfo.txt",
                               package = "CONCERTDR")

# Load the reference matrix
reference_df <- read.csv(ref_file, row.names = 1, check.names = FALSE)
reference_df$gene_symbol <- rownames(reference_df)

cat("Reference matrix:", nrow(reference_df), "genes ×",
    ncol(reference_df) - 1, "signatures\n")
#> Reference matrix: 163 genes × 496 signatures

2.1 The disease signature

The example signature is an AML/BCR-ABL-themed set of genes with illustrative positive and negative weights. It demonstrates the reversal criterion: a perturbation that suppresses the positively weighted genes and activates the negatively weighted genes receives a negative connectivity score.

signature <- read.delim(sig_file)
cat("Up-regulated genes:  ", sum(signature$log2FC > 0), "\n")
#> Up-regulated genes:   30
cat("Down-regulated genes:", sum(signature$log2FC < 0), "\n")
#> Down-regulated genes: 27
head(signature[order(-abs(signature$log2FC)), ], 10)
#>      Gene log2FC
#> 1     MYC    3.0
#> 2    TP53   -3.0
#> 3    MYCN    2.9
#> 4     RB1   -2.9
#> 5   CCND1    2.8
#> 6  CDKN1A   -2.8
#> 7   CCND2    2.7
#> 8  CDKN1B   -2.7
#> 9    CDK2    2.6
#> 10 CDKN2A   -2.6

2.2 The siginfo metadata

The bundled siginfo covers both small-molecule (trt_cp) and gene perturbation (trt_oe, trt_xpr) signatures in four well-represented CMap cell lines.

siginfo <- read.delim(sig_info_file, stringsAsFactors = FALSE)
cat("Total signatures:", nrow(siginfo), "\n")
#> Total signatures: 496
table(Type = siginfo$pert_type, Cell = siginfo$cell_iname)
#>          Cell
#> Type      A375 A549 HEPG2 PC3
#>   trt_cp   106  109    65 116
#>   trt_oe    23   26     0  12
#>   trt_xpr   10   20     0   9

3 Use Case 1 — Finding Repurposing Compounds

3.1 Filter to compound signatures

We first subset the siginfo to trt_cp only, then build a reference matrix containing just those signatures. This keeps the scoring fast and the results interpretable.

cp_siginfo <- subset_siginfo_beta(
  siginfo_file = sig_info_file,
  interactive  = FALSE,
  filters      = list(pert_type = "trt_cp"),
  verbose      = FALSE,
  show_preview = FALSE
)
cat("Compound signatures:", nrow(cp_siginfo), "\n")
#> Compound signatures: 396
table(cp_siginfo$cell_iname)
#> 
#>  A375  A549 HEPG2   PC3 
#>   106   109    65   116

3.2 Build compound reference matrix

Rather than re-reading from GCTX (which would require the full CMap download), we subset the in-memory reference matrix to keep only the compound signatures identified above.

cp_sig_ids <- cp_siginfo$sig_id
cp_ref     <- reference_df[, c("gene_symbol",
                                intersect(cp_sig_ids, colnames(reference_df))),
                            drop = FALSE]
cat("Compound reference:", nrow(cp_ref), "genes ×",
    ncol(cp_ref) - 1, "signatures\n")
#> Compound reference: 163 genes × 396 signatures

3.3 Score the AML signature against compounds

results_cp <- process_signature_with_df(
  signature_file = sig_file,
  reference_df   = cp_ref,
  methods        = c("xsum", "ks"),
  topN           = 30,
  permutations   = 100,
  save_files     = FALSE
)
print(results_cp)
#> CMap Signature Matching Results
#> ===============================
#> 
#> Signature file: /tmp/RtmpCrCoRF/Rinsta847b17da37fd/CONCERTDR/extdata/example_signature.txt
#> Analysis completed: 2026-09-08 17:08:19
#> Time taken: 0.10 minutes
#> 
#> Methods used:
#>   - xsum: 396 results
#>   - ks: 396 results
#> 
#> Gene coverage:
#>   Up-regulated: 30/30 genes (100.0%)
#>   Down-regulated: 27/27 genes (100.0%)
#> 
#> Top compounds across all methods:
#>   1. PBIOA018_HEPG2_24H:O07 (method: xsum, score: 43.8400, p-value: 0.0400)
#>   2. PCLB003_HEPG2_24H:BRD-A52530684-003-01-7:10 (method: xsum, score: 35.0200, p-value: 0.0400)
#>   3. REP.B003_A375_24H:P02 (method: xsum, score: 28.3500, p-value: 0.0100)
#>   4. CPC011_A549_24H:BRD-K82109576-065-20-2:10 (method: xsum, score: 26.8100, p-value: 0.0100)
#>   5. CRCGN004_PC3_24H:BRD-K74793820-001-01-2:10 (method: xsum, score: 23.8800, p-value: 0.0000)
#> 
#> Use the following to explore the results:
#>   - $results: List of result data frames for each method
#>   - $summary: Summary of top hits across all methods
#>   - $gene_data: Original signature gene data
#>   - $settings: Analysis settings and metadata
#>   - $common_genes: Genes found in the reference data
#> 
#> Example: result_obj$results$ks to view KS score results

3.4 Inspect top compound hits

A negative score means the drug reverses the disease signature — the standard criterion for a candidate repurposing hit. BCR-ABL inhibitors such as imatinib and dasatinib should rank near the top against this AML signature.

xsum_cp <- results_cp$results$xsum
top_cp  <- head(xsum_cp[order(xsum_cp$Score), ], 20)
top_cp[, c("compound", "Score", "pValue", "pAdjValue")]
#>                                                                              compound
#> CPC005_A375_24H:BRD-K81418486:10                     CPC005_A375_24H:BRD-K81418486:10
#> REP.A015_PC3_24H:P14                                             REP.A015_PC3_24H:P14
#> ERG021_PC3_24H:BRD-K02130563:10                       ERG021_PC3_24H:BRD-K02130563:10
#> CPC005_A375_6H:BRD-A18419789-001-01-4:10     CPC005_A375_6H:BRD-A18419789-001-01-4:10
#> PBIOA013_PC3_24H:C21                                             PBIOA013_PC3_24H:C21
#> PBIOA022_A375_24H:H15                                           PBIOA022_A375_24H:H15
#> ASG002_PC3_24H:D10                                                 ASG002_PC3_24H:D10
#> PBIOA015_A549_24H:O19                                           PBIOA015_A549_24H:O19
#> BRAF001_A375_24H:BRD-K81418486-001-15-2:10 BRAF001_A375_24H:BRD-K81418486-001-15-2:10
#> REP.A015_PC3_24H:P16                                             REP.A015_PC3_24H:P16
#> REP.A015_PC3_24H:P15                                             REP.A015_PC3_24H:P15
#> ASG003_A549_24H:P01                                               ASG003_A549_24H:P01
#> LKCP001_A549_24H:D22                                             LKCP001_A549_24H:D22
#> REP.A015_PC3_24H:P17                                             REP.A015_PC3_24H:P17
#> PBIOA022_HEPG2_24H:H13                                         PBIOA022_HEPG2_24H:H13
#> CPC011_A375_6H:BRD-K37798499-001-13-2:10     CPC011_A375_6H:BRD-K37798499-001-13-2:10
#> PBIOA013_A375_24H:O07                                           PBIOA013_A375_24H:O07
#> LKCP001_A549_24H:D23                                             LKCP001_A549_24H:D23
#> PBIOA013_PC3_24H:G18                                             PBIOA013_PC3_24H:G18
#> PBIOA022_HEPG2_24H:H15                                         PBIOA022_HEPG2_24H:H15
#>                                             Score pValue  pAdjValue
#> CPC005_A375_24H:BRD-K81418486:10           -77.30   0.00 0.00000000
#> REP.A015_PC3_24H:P14                       -71.50   0.00 0.00000000
#> ERG021_PC3_24H:BRD-K02130563:10            -69.80   0.00 0.00000000
#> CPC005_A375_6H:BRD-A18419789-001-01-4:10   -69.02   0.00 0.00000000
#> PBIOA013_PC3_24H:C21                       -63.64   0.00 0.00000000
#> PBIOA022_A375_24H:H15                      -63.57   0.01 0.04771084
#> ASG002_PC3_24H:D10                         -59.24   0.00 0.00000000
#> PBIOA015_A549_24H:O19                      -58.41   0.00 0.00000000
#> BRAF001_A375_24H:BRD-K81418486-001-15-2:10 -56.56   0.01 0.04771084
#> REP.A015_PC3_24H:P16                       -55.30   0.01 0.04771084
#> REP.A015_PC3_24H:P15                       -55.03   0.01 0.04771084
#> ASG003_A549_24H:P01                        -52.93   0.00 0.00000000
#> LKCP001_A549_24H:D22                       -52.88   0.03 0.09504000
#> REP.A015_PC3_24H:P17                       -52.80   0.01 0.04771084
#> PBIOA022_HEPG2_24H:H13                     -52.70   0.00 0.00000000
#> CPC011_A375_6H:BRD-K37798499-001-13-2:10   -49.79   0.00 0.00000000
#> PBIOA013_A375_24H:O07                      -49.68   0.02 0.07689320
#> LKCP001_A549_24H:D23                       -49.61   0.00 0.00000000
#> PBIOA013_PC3_24H:G18                       -48.93   0.00 0.00000000
#> PBIOA022_HEPG2_24H:H15                     -47.80   0.02 0.07689320
plot(results_cp, method = "xsum", plot_type = "scores", top_n = 20)

plot(results_cp, method = "xsum", plot_type = "volcano")

3.5 Annotate compound hits

annotate_drug_results() joins the scoring output with siginfo and compoundinfo to add drug names, mechanism of action, targets, and clinical phase.

compinfo <- read.delim(comp_info_file, stringsAsFactors = FALSE)

views_cp <- annotate_drug_results(
  results_df     = xsum_cp,
  sig_info_file  = cp_siginfo,
  comp_info_file = compinfo,
  write_outputs  = FALSE,
  verbose        = FALSE
)

# Drug-level summary: one row per compound, best score across all contexts
head(views_cp$wetlab_drug_view[,
  c("perturbation_name", "Score", "effect_direction", "moa", "target")
], 15)
#>    perturbation_name  Score
#> 37        vorinostat -77.30
#> 30        romidepsin -71.50
#> 11      panobinostat -69.80
#> 3          etoposide -69.02
#> 41        bortezomib -63.64
#> 16       midostaurin -58.41
#> 20         etoposide -49.79
#> 35        entinostat -47.20
#> 42       doxorubicin -43.82
#> 17        pacritinib -43.51
#> 32        cytarabine -42.64
#> 45         bosutinib -41.44
#> 18        cytarabine -39.82
#> 28      methotrexate -37.58
#> 25       palbociclib -34.51
#>                                         effect_direction
#> 37                    Reversal (potentially therapeutic)
#> 30                    Reversal (potentially therapeutic)
#> 11                    Reversal (potentially therapeutic)
#> 3                     Reversal (potentially therapeutic)
#> 41 Mimic/Aggravating; Reversal (potentially therapeutic)
#> 16                    Reversal (potentially therapeutic)
#> 20                    Reversal (potentially therapeutic)
#> 35 Mimic/Aggravating; Reversal (potentially therapeutic)
#> 42 Mimic/Aggravating; Reversal (potentially therapeutic)
#> 17 Mimic/Aggravating; Reversal (potentially therapeutic)
#> 32                    Reversal (potentially therapeutic)
#> 45 Mimic/Aggravating; Reversal (potentially therapeutic)
#> 18                    Reversal (potentially therapeutic)
#> 28                    Reversal (potentially therapeutic)
#> 25                    Reversal (potentially therapeutic)
#>                                   moa target
#> 37                     HDAC inhibitor  HDAC6
#> 30                     HDAC inhibitor  HDAC1
#> 11                     HDAC inhibitor  HDAC1
#> 3             Topoisomerase inhibitor  TOP2A
#> 41               Proteasome inhibitor  PSMB1
#> 16                      KIT inhibitor   FLT3
#> 20            Topoisomerase inhibitor  TOP2A
#> 35                     HDAC inhibitor  HDAC1
#> 42            Topoisomerase inhibitor  TOP2A
#> 17                      JAK inhibitor   FLT3
#> 32 Ribonucleotide reductase inhibitor  POLA1
#> 45                      Src inhibitor   ABL1
#> 18 Ribonucleotide reductase inhibitor  POLA1
#> 28  Dihydrofolate reductase inhibitor   DHFR
#> 25                      CDK inhibitor   CDK4
# How many cell-line contexts did each top drug appear in?
head(views_cp$drug_context_summary[,
  c("perturbation_name", "best_score", "n_contexts", "n_cell_lines", "moa_status")
], 10)
#>     perturbation_name best_score n_contexts n_cell_lines moa_status
#> 297        vorinostat     -77.30         16            4      Known
#> 50       panobinostat     -69.80         16            4      Known
#> 344        bortezomib     -63.64         16            4      Known
#> 93        midostaurin     -58.41         16            4      Known
#> 261        entinostat     -47.20         16            4      Known
#> 301         nilotinib     -30.04         16            4      Known
#> 164         dasatinib     -26.34         16            4      Known
#> 279        decitabine     -17.38         16            4      Known
#> 143        buparlisib     -22.97         15            4      Known
#> 333        navitoclax     -21.13         15            4      Known

3.6 Barcode heatmap for top compounds

The barcode heatmap shows the z-score profile of the top-scoring perturbations across the signature genes. Genes are arranged left-to-right as down-regulated → up-regulated in the disease; a drug that reverses the signature appears as warm colours on the left and cool colours on the right.

z_cp <- extract_signature_zscores(
  results_df      = views_cp$tech_view_all,
  signature_file  = sig_file,
  reference_df    = cp_ref,
  max_genes       = 50,           # top-50 up-regulated + top-50 down-regulated
  split_direction = TRUE,
  max_perts       = 50,
  verbose         = FALSE
)
cat("Heatmap matrix:", nrow(z_cp$z_plot), "perturbations ×",
    ncol(z_cp$z_plot), "genes\n")
#> Heatmap matrix: 50 perturbations × 57 genes
if (requireNamespace("ComplexHeatmap", quietly = TRUE) &&
    requireNamespace("circlize",       quietly = TRUE)) {
  plot_signature_direction_tile_barcode(
    precomputed         = z_cp,
    cluster_rows        = TRUE,
    show_row_dendrogram = TRUE,
    cluster_cols        = FALSE,
    verbose             = FALSE
  )
} else {
  message("Install ComplexHeatmap and circlize for heatmap rendering:\n",
          "  BiocManager::install('ComplexHeatmap')\n",
          "  install.packages('circlize')")
}

3.6.1 Split-direction heatmap

Setting split_direction = TRUE divides the plot into two panels: genes with positive log2FC (up-regulated in the disease) on the left, and genes with negative log2FC (down-regulated) on the right. Both panels share the same perturbation row order, determined by hierarchical clustering of the full gene matrix, so patterns on each side can be compared directly.

if (requireNamespace("ComplexHeatmap", quietly = TRUE) &&
    requireNamespace("circlize",       quietly = TRUE)) {
  plot_signature_direction_tile_barcode(
    precomputed         = z_cp,
    split_direction     = TRUE,   # up-regulated panel (left) | down-regulated panel (right)
    gap_width           = 6,      # mm gap between the two panels
    cluster_rows        = TRUE,
    show_row_dendrogram = TRUE,
    cluster_cols        = FALSE,
    verbose             = FALSE
  )
}

4 Use Case 2 — Finding Therapeutic Gene Targets

Gene overexpression and CRISPR knockout perturbations in CMap can identify which genes, when modulated, produce a transcriptional effect similar to a beneficial drug. This nominates candidate therapeutic targets independently of any existing compound library.

4.1 Filter to gene perturbation signatures

ge_siginfo <- subset_siginfo_beta(
  siginfo_file = sig_info_file,
  interactive  = FALSE,
  filters      = list(pert_type = c("trt_oe", "trt_xpr")),
  verbose      = FALSE,
  show_preview = FALSE
)
cat("Gene perturbation signatures:", nrow(ge_siginfo), "\n")
#> Gene perturbation signatures: 100
table(Type = ge_siginfo$pert_type, Cell = ge_siginfo$cell_iname)
#>          Cell
#> Type      A375 A549 PC3
#>   trt_oe    23   26  12
#>   trt_xpr   10   20   9

4.2 Build gene perturbation reference matrix

ge_sig_ids <- ge_siginfo$sig_id
ge_ref     <- reference_df[, c("gene_symbol",
                                intersect(ge_sig_ids, colnames(reference_df))),
                            drop = FALSE]
cat("Gene perturbation reference:", nrow(ge_ref), "genes ×",
    ncol(ge_ref) - 1, "signatures\n")
#> Gene perturbation reference: 163 genes × 100 signatures

4.3 Score the AML signature against gene perturbations

results_ge <- process_signature_with_df(
  signature_file = sig_file,
  reference_df   = ge_ref,
  methods        = c("xsum", "ks"),
  topN           = 50,
  permutations   = 100,
  save_files     = FALSE
)
print(results_ge)
#> CMap Signature Matching Results
#> ===============================
#> 
#> Signature file: /tmp/RtmpCrCoRF/Rinsta847b17da37fd/CONCERTDR/extdata/example_signature.txt
#> Analysis completed: 2026-09-08 17:08:33
#> Time taken: 0.03 minutes
#> 
#> Methods used:
#>   - xsum: 100 results
#>   - ks: 100 results
#> 
#> Gene coverage:
#>   Up-regulated: 30/30 genes (100.0%)
#>   Down-regulated: 27/27 genes (100.0%)
#> 
#> Top compounds across all methods:
#>   1. TA.OE012_A549_96H:BRDN0000553495:-666 (method: xsum, score: 21.5200, p-value: 0.0600)
#>   2. TA.OE014_A549_96H:BRDN0000553488:-666 (method: xsum, score: 18.8300, p-value: 0.0000)
#>   3. TA.OE002_A375_72H:CCSBBROAD304_00526:-666 (method: xsum, score: 16.9500, p-value: 0.0000)
#>   4. XPRJJ001_A375_96H:BRDN0001057046:-666 (method: xsum, score: 16.2300, p-value: 0.0400)
#>   5. TA.OE002_A375_72H:BRDN0000464822:-666 (method: xsum, score: 13.9300, p-value: 0.0400)
#> 
#> Use the following to explore the results:
#>   - $results: List of result data frames for each method
#>   - $summary: Summary of top hits across all methods
#>   - $gene_data: Original signature gene data
#>   - $settings: Analysis settings and metadata
#>   - $common_genes: Genes found in the reference data
#> 
#> Example: result_obj$results$ks to view KS score results

4.4 Inspect top gene perturbation hits

Negative-scoring gene perturbations are those whose expression effect reverses the AML signature. An overexpression hit (trt_oe) suggests that activating that gene is therapeutic; a knockout hit (trt_xpr) suggests that silencing it is therapeutic.

xsum_ge <- results_ge$results$xsum
top_ge  <- head(xsum_ge[order(xsum_ge$Score), ], 20)
top_ge[, c("compound", "Score", "pValue", "pAdjValue")]
#>                                                                            compound
#> XPR016_PC3.311B_96H:J12                                     XPR016_PC3.311B_96H:J12
#> TA.OE003_PC3_72H:BRDN0000464908:-666           TA.OE003_PC3_72H:BRDN0000464908:-666
#> XPR008_PC3.311B_96H:G11                                     XPR008_PC3.311B_96H:G11
#> XPR016_A375.311_96H:J12                                     XPR016_A375.311_96H:J12
#> XPR033_A549.311_96H:C10                                     XPR033_A549.311_96H:C10
#> XPR026_A375.311_96H:L06                                     XPR026_A375.311_96H:L06
#> XPR025_PC3.311B_96H:L11                                     XPR025_PC3.311B_96H:L11
#> TA.OE003_A375_72H:CCSBBROAD304_00282:-666 TA.OE003_A375_72H:CCSBBROAD304_00282:-666
#> TA.OE007_A549_96H:BRDN0000464992:-666         TA.OE007_A549_96H:BRDN0000464992:-666
#> TA.OE002_A375_72H:BRDN0000465013:-666         TA.OE002_A375_72H:BRDN0000465013:-666
#> XPR025_A549.311_96H:L11                                     XPR025_A549.311_96H:L11
#> TA.OE007_A549_96H:CCSBBROAD304_00282:-666 TA.OE007_A549_96H:CCSBBROAD304_00282:-666
#> OEC001_A375_96H:CCSBBROAD304_01093:-666     OEC001_A375_96H:CCSBBROAD304_01093:-666
#> OEB001_A375_96H:BRDN0000399136:-666             OEB001_A375_96H:BRDN0000399136:-666
#> TA.OE012_A549_96H:BRDN0000561657:-666         TA.OE012_A549_96H:BRDN0000561657:-666
#> TA.OE002_PC3_72H:CCSBBROAD304_06179:-666   TA.OE002_PC3_72H:CCSBBROAD304_06179:-666
#> TA.OE007_A549_96H:BRDN0000465013:-666         TA.OE007_A549_96H:BRDN0000465013:-666
#> XPR042_A549.311_96H:K24                                     XPR042_A549.311_96H:K24
#> XPR026_A549.311_96H:L06                                     XPR026_A549.311_96H:L06
#> XPR008_PC3.311B_96H:O23                                     XPR008_PC3.311B_96H:O23
#>                                            Score pValue pAdjValue
#> XPR016_PC3.311B_96H:J12                   -30.52   0.00 0.0000000
#> TA.OE003_PC3_72H:BRDN0000464908:-666      -29.90   0.00 0.0000000
#> XPR008_PC3.311B_96H:G11                   -22.50   0.04 0.3076923
#> XPR016_A375.311_96H:J12                   -22.02   0.02 0.2500000
#> XPR033_A549.311_96H:C10                   -19.11   0.04 0.3076923
#> XPR026_A375.311_96H:L06                   -19.01   0.00 0.0000000
#> XPR025_PC3.311B_96H:L11                   -18.29   0.00 0.0000000
#> TA.OE003_A375_72H:CCSBBROAD304_00282:-666 -17.41   0.19 0.5714286
#> TA.OE007_A549_96H:BRDN0000464992:-666     -14.63   0.02 0.2500000
#> TA.OE002_A375_72H:BRDN0000465013:-666     -13.59   0.18 0.5714286
#> XPR025_A549.311_96H:L11                   -13.36   0.07 0.4375000
#> TA.OE007_A549_96H:CCSBBROAD304_00282:-666 -13.28   0.38 0.6666667
#> OEC001_A375_96H:CCSBBROAD304_01093:-666   -11.67   0.26 0.5777778
#> OEB001_A375_96H:BRDN0000399136:-666       -10.81   0.22 0.5714286
#> TA.OE012_A549_96H:BRDN0000561657:-666     -10.19   0.23 0.5714286
#> TA.OE002_PC3_72H:CCSBBROAD304_06179:-666   -9.81   0.16 0.5714286
#> TA.OE007_A549_96H:BRDN0000465013:-666      -9.57   0.10 0.4761905
#> XPR042_A549.311_96H:K24                    -8.39   0.12 0.4800000
#> XPR026_A549.311_96H:L06                    -8.26   0.18 0.5714286
#> XPR008_PC3.311B_96H:O23                    -8.06   0.27 0.5869565
plot(results_ge, method = "xsum", plot_type = "scores", top_n = 20)

4.5 Annotate gene perturbation hits

views_ge <- annotate_drug_results(
  results_df     = xsum_ge,
  sig_info_file  = ge_siginfo,
  comp_info_file = compinfo,   # compinfo may not cover gene perts; that is expected
  write_outputs  = FALSE,
  verbose        = FALSE
)

# Gene-focused view: perturbation name, mode (OE vs XPR), score
head(views_ge$wetlab_gene_view[,
  c("perturbation_name", "mode", "Score", "effect_direction", "cell_line")
], 15)
#>    perturbation_name mode  Score                   effect_direction cell_line
#> 71              CDK4  XPR -30.52 Reversal (potentially therapeutic)  PC3.311B
#> 13              TP53   OE -29.90 Reversal (potentially therapeutic)       PC3
#> 59              AKT1  XPR -22.50 Reversal (potentially therapeutic)  PC3.311B
#> 70              CDK4  XPR -22.02 Reversal (potentially therapeutic)  A375.311
#> 72              CDK4  XPR -19.11 Reversal (potentially therapeutic)  A549.311
#> 64              MTOR  XPR -19.01 Reversal (potentially therapeutic)  A375.311
#> 68              CDK4  XPR -18.29 Reversal (potentially therapeutic)  PC3.311B
#> 89            CDKN1A   OE -17.41 Reversal (potentially therapeutic)      A375
#> 17              AKT1   OE -14.63 Reversal (potentially therapeutic)      A549
#> 20              AKT1   OE -13.59 Reversal (potentially therapeutic)      A375
#> 67              CDK4  XPR -13.36 Reversal (potentially therapeutic)  A549.311
#> 90            CDKN1A   OE -13.28 Reversal (potentially therapeutic)      A549
#> 93            NFKBIA   OE -11.67 Reversal (potentially therapeutic)      A375
#> 2              GATA2   OE -10.81 Reversal (potentially therapeutic)      A375
#> 47              PTEN   OE -10.19 Reversal (potentially therapeutic)      A549

4.6 Barcode heatmap for top gene perturbations

z_ge <- extract_signature_zscores(
  results_df      = views_ge$tech_view_all,
  signature_file  = sig_file,
  reference_df    = ge_ref,
  max_genes       = 50,
  split_direction = TRUE,
  max_perts       = 50,
  verbose         = FALSE
)
if (requireNamespace("ComplexHeatmap", quietly = TRUE) &&
    requireNamespace("circlize",       quietly = TRUE)) {
  plot_signature_direction_tile_barcode(
    precomputed         = z_ge,
    cluster_rows        = TRUE,
    show_row_dendrogram = TRUE,
    cluster_cols        = FALSE,
    verbose             = FALSE
  )
}

4.6.1 Split-direction heatmap for gene perturbations

if (requireNamespace("ComplexHeatmap", quietly = TRUE) &&
    requireNamespace("circlize",       quietly = TRUE)) {
  plot_signature_direction_tile_barcode(
    precomputed     = z_ge,
    split_direction = TRUE,
    gap_width       = 6,
    cluster_rows    = TRUE,
    cluster_cols    = FALSE,
    verbose         = FALSE
  )
}

5 Comparing the Two Use Cases

# Top 10 compounds vs top 10 gene perturbations by XSum score
top10_cp <- head(xsum_cp[order(xsum_cp$Score), "Score", drop = FALSE], 10)
top10_ge <- head(xsum_ge[order(xsum_ge$Score), "Score", drop = FALSE], 10)

cat("Score range — compounds:         ",
    round(range(top10_cp$Score), 3), "\n")
#> Score range — compounds:          -77.3 -55.3
cat("Score range — gene perturbations:",
    round(range(top10_ge$Score), 3), "\n")
#> Score range — gene perturbations: -30.52 -13.59

The two use cases are complementary: compound hits suggest drugs that could be repositioned immediately, while gene perturbation hits suggest mechanistic targets that could guide future drug discovery or combination strategies.

6 Comparison to Similar Packages

CONCERTDR overlaps with signatureSearch and cmapR, but the packages operate at different levels of the workflow:

Package Primary scope When it is a good fit
CONCERTDR An opinionated end-to-end drug-repurposing workflow: filter CMap contexts, extract reference profiles, run KS/GSEA/XCos/XSum/Zhang matching, annotate hits, and create wet-lab-oriented tables and heatmaps. When the goal is to move from a disease signature and CMap files to ranked, annotated drug or gene-perturbation candidates with a compact API.
signatureSearch A broader gene-expression-signature search and functional-enrichment framework, with preprocessed CMap/LINCS reference resources supplied through signatureSearchData and ExperimentHub. When scalable searches against packaged reference databases, custom databases, or downstream functional enrichment are central to the analysis.
cmapR General infrastructure for parsing, manipulating, and writing CMap formats such as GCT/GCTX matrices and gene-set collections. When low-level CMap data access and format manipulation are needed without an opinionated repurposing and result-annotation pipeline.

The packages can also be complementary. For example, cmapR can prepare or inspect CMap objects before a CONCERTDR analysis, while signatureSearch is a useful alternative when its database abstractions and functional-enrichment tools are preferred.

7 Running with Full CMap Data

For a real analysis, replace the bundled reference_df with a matrix built from the full CMap GCTX. Set file paths once at the top of your script:

data_dir <- "/path/to/cmap_data"

options(
  CONCERTDR.data_dir          = data_dir,
  CONCERTDR.gctx_file         = file.path(data_dir, "level5_beta_trt_cp_n720216x12328.gctx"),
  CONCERTDR.siginfo_file      = file.path(data_dir, "siginfo_beta.txt"),
  CONCERTDR.geneinfo_file     = file.path(data_dir, "geneinfo_beta.txt"),
  CONCERTDR.compoundinfo_file = file.path(data_dir, "compoundinfo_beta.txt")
)

# Step 1: filter siginfo
cp_siginfo <- subset_siginfo_beta(
  getOption("CONCERTDR.siginfo_file"),
  interactive = FALSE,
  filters = list(
    pert_type  = "trt_cp",
    pert_itime = c("6 h", "24 h"),
    cell_iname = c("K562", "HL60", "THP1", "JURKAT", "U937", "NB4")
  )
)

# Step 2: build reference matrix from GCTX
reference_df <- extract_cmap_data_from_siginfo(
  siginfo_file  = cp_siginfo,
  geneinfo_file = getOption("CONCERTDR.geneinfo_file"),
  gctx_file     = getOption("CONCERTDR.gctx_file"),
  filter_quality = FALSE,
  landmark       = TRUE
)

# Steps 3–7: identical to the vignette above — just replace cp_ref with
# reference_df and use larger topN / permutations for real-scale analysis:
#   topN = 400, permutations = 1000

8 Session Info

sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 LTS
#> 
#> Matrix products: default
#> BLAS:   /home/biocbuild/bbs-3.24-bioc/R/lib/libRblas.so 
#> LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0  LAPACK version 3.12.0
#> 
#> locale:
#>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>  [3] LC_TIME=en_GB              LC_COLLATE=C              
#>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#> 
#> time zone: America/New_York
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] CONCERTDR_0.99.2 BiocStyle_2.41.0
#> 
#> loaded via a namespace (and not attached):
#>  [1] sass_0.4.10           generics_0.1.4        shape_1.4.6.1        
#>  [4] digest_0.6.39         magrittr_2.0.5        evaluate_1.0.5       
#>  [7] grid_4.6.1            RColorBrewer_1.1-3    bookdown_0.48        
#> [10] iterators_1.0.14      circlize_0.4.18       fastmap_1.2.0        
#> [13] foreach_1.5.2         doParallel_1.0.17     jsonlite_2.0.0       
#> [16] GlobalOptions_0.1.4   tinytex_0.60          BiocManager_1.30.27  
#> [19] ComplexHeatmap_2.29.0 scales_1.4.0          codetools_0.2-20     
#> [22] jquerylib_0.1.4       cli_3.6.6             crayon_1.5.3         
#> [25] rlang_1.3.0           withr_3.0.3           cachem_1.1.0         
#> [28] yaml_2.3.12           otel_0.2.0            tools_4.6.1          
#> [31] parallel_4.6.1        dplyr_1.2.1           colorspace_2.1-3     
#> [34] Rhdf5lib_2.1.0        ggplot2_4.0.3         BiocGenerics_0.59.12 
#> [37] GetoptLong_1.1.1      vctrs_0.7.3           R6_2.6.1             
#> [40] png_0.1-9             stats4_4.6.1          matrixStats_1.5.0    
#> [43] lifecycle_1.0.5       rhdf5_2.57.12         magick_2.9.1         
#> [46] S4Vectors_0.51.9      IRanges_2.47.5        clue_0.3-68          
#> [49] cluster_2.1.8.3       pkgconfig_2.0.3       pillar_1.11.1        
#> [52] bslib_0.12.0          gtable_0.3.6          data.table_1.18.6.1  
#> [55] glue_1.8.1            Rcpp_1.1.2            xfun_0.60            
#> [58] tibble_3.3.1          tidyselect_1.2.1      knitr_1.52           
#> [61] dichromat_2.0-1       rhdf5filters_1.25.4   rjson_0.2.23         
#> [64] farver_2.1.2          htmltools_0.5.9       rmarkdown_2.32       
#> [67] labeling_0.4.3        Cairo_1.7-0           compiler_4.6.1       
#> [70] S7_0.2.2