---
title: "Drug Repurposing with CONCERTDR"
author:
  - name: Hengxin Pan
    affiliation: Walter and Eliza Hall Institute of Medical Research
    email: pan.h@wehi.edu.au
date: "`r Sys.Date()`"
output:
  BiocStyle::html_document:
    toc: true
    toc_depth: 3
    toc_float: true
    number_sections: true
vignette: >
  %\VignetteIndexEntry{Drug Repurposing with CONCERTDR}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment  = "#>",
  message  = FALSE,
  warning  = FALSE
)
```

# 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/`.

```{r load}
library(CONCERTDR)
```

# 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.

```{r load-data}
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")
```

## 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.

```{r view-signature}
signature <- read.delim(sig_file)
cat("Up-regulated genes:  ", sum(signature$log2FC > 0), "\n")
cat("Down-regulated genes:", sum(signature$log2FC < 0), "\n")
head(signature[order(-abs(signature$log2FC)), ], 10)
```

## 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.

```{r view-siginfo}
siginfo <- read.delim(sig_info_file, stringsAsFactors = FALSE)
cat("Total signatures:", nrow(siginfo), "\n")
table(Type = siginfo$pert_type, Cell = siginfo$cell_iname)
```

# Use Case 1 — Finding Repurposing Compounds

## 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.

```{r filter-compounds}
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")
table(cp_siginfo$cell_iname)
```

## 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.

```{r subset-reference-cp}
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")
```

## Score the AML signature against compounds

```{r score-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)
```

## 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.

```{r top-compounds}
xsum_cp <- results_cp$results$xsum
top_cp  <- head(xsum_cp[order(xsum_cp$Score), ], 20)
top_cp[, c("compound", "Score", "pValue", "pAdjValue")]
```

```{r plot-compound-scores, fig.width=8, fig.height=4}
plot(results_cp, method = "xsum", plot_type = "scores", top_n = 20)
```

```{r plot-compound-volcano, fig.width=6, fig.height=4}
plot(results_cp, method = "xsum", plot_type = "volcano")
```

## 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.

```{r annotate-compounds}
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)
```

```{r drug-context-summary}
# 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)
```

## 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.

```{r extract-zscores-cp}
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")
```

```{r heatmap-compounds, fig.width=14, fig.height=10}
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')")
}
```

### 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.

```{r heatmap-compounds-split, fig.width=16, fig.height=10}
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
  )
}
```

# 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.

## Filter to gene perturbation signatures

```{r filter-gene-perts}
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")
table(Type = ge_siginfo$pert_type, Cell = ge_siginfo$cell_iname)
```

## Build gene perturbation reference matrix

```{r subset-reference-ge}
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")
```

## Score the AML signature against gene perturbations

```{r score-gene-perts}
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)
```

## 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.

```{r top-gene-hits}
xsum_ge <- results_ge$results$xsum
top_ge  <- head(xsum_ge[order(xsum_ge$Score), ], 20)
top_ge[, c("compound", "Score", "pValue", "pAdjValue")]
```

```{r plot-gene-scores, fig.width=8, fig.height=4}
plot(results_ge, method = "xsum", plot_type = "scores", top_n = 20)
```

## Annotate gene perturbation hits

```{r annotate-gene-perts}
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)
```

## Barcode heatmap for top gene perturbations

```{r extract-zscores-ge}
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
)
```

```{r heatmap-gene-perts, fig.width=14, fig.height=10}
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
  )
}
```

### Split-direction heatmap for gene perturbations

```{r heatmap-gene-perts-split, fig.width=16, fig.height=10}
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
  )
}
```

# Comparing the Two Use Cases

```{r compare-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")
cat("Score range — gene perturbations:",
    round(range(top10_ge$Score), 3), "\n")
```

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.

# Comparison to Similar Packages

CONCERTDR overlaps with
[`signatureSearch`](https://bioconductor.org/packages/signatureSearch) and
[`cmapR`](https://bioconductor.org/packages/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.

# 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:

```{r full-cmap-setup, eval=FALSE}
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
```

# Session Info

```{r session-info}
sessionInfo()
```
