Two complementary approaches were used to derive MEK inhibitor resistance gene signatures. First, to identify genes associated with intrinsic resistance, baseline expression data from colorectal cancer cell lines in the Cancer Cell Line Encyclopedia (CCLE) were correlated with Selumetinib IC50 values using linear regression. Second, to identify genes associated with acquired resistance, differential expression analysis was performed using Gene Expression Omnibus dataset GSE126109, which includes five colorectal cancer cell lines and their matched Selumetinib-resistant derivatives generated by long-term drug exposure.

1. Load packages

Include all R and Bioconductor packages

library(conflicted)
library(kableExtra)
library(readr)
library(AnnotationDbi)
library(org.Hs.eg.db)
library(tidyverse)
library(writexl)
library(DESeq2)
conflicts_prefer(dplyr::filter)
conflicts_prefer(dplyr::select)
conflicts_prefer(dplyr::slice_head)

2. Working directory and input files

Set your preferred working directory and ensure that the required input files, CCLE_TPM.txt, GDSC1.txt, GSE126109_SAMPLES.txt, and GSE126109_COUNT_MATRIX.txt, are stored in this directory.

  setwd("L:/2026/WM7/R") # use your preferred directory

3. Read expression file from CCLE database

From the Cancer Cell Line Encyclopedia (CCLE) downloaded a file including gene expression values (TPM) for > 1000 cancer cell lines https://depmap.org/portal/data_page/?tab=allData&releasename=CCLE%202019&filename=CCLE_RNAseq_rsem_genes_tpm_20180929.txt.gz the final file was renamed to

We can use the read_tsv() function from the readr package to read the file and assign it to ccle_expr.

CCLE_EXPR <- read_tsv("CCLE_TPM.txt")
CCLE_EXPR |>
  select(1:8) |>
  slice_head(n = 20) 

Transfrom data: Select only colon cancer cell lines (LARGE_INTESTINE), log2-transform TPM adding a pseudocount of 1, adding gene symbol column, filter for genes with no expression in more than 20 cancer cell lines

COL_ind <- grep("LARGE_INTESTINE", names(CCLE_EXPR))
CCLE <- CCLE_EXPR |>
  select(all_of(COL_ind)) |>
  mutate(across(everything(), \(x) log2(x + 1))) |>
  rename_with(\(x) gsub("_LARGE_INTESTINE", "", x))
CCLE_ANNO <- CCLE |>
  mutate(
    ENSEMBL = gsub("\\..*", "", CCLE_EXPR$gene_id),
    .before = 1
  ) |>
  left_join(
    tibble(ENSEMBL = unique(gsub("\\..*", "", CCLE_EXPR$gene_id))) |>
      mutate(
        SYMBOL = AnnotationDbi::mapIds(
          org.Hs.eg.db,
          keys = ENSEMBL,
          column = "SYMBOL",
          keytype = "ENSEMBL",
          multiVals = "first"
        )
      ),
    by = "ENSEMBL"
  ) |>
  relocate(SYMBOL, .after = ENSEMBL)
CCLE_ANNO_FILT <- CCLE_ANNO |>
  mutate(n_low = rowSums(across(where(is.numeric), \(x) x < 0.001))) |>
  filter(!is.na(SYMBOL),n_low < 20) |>
  select(-n_low)

The final CCLE table will look like:

CCLE_ANNO_FILT |>
  select(ENSEMBL, SYMBOL, 3:8) |>
  slice_head(n = 20)

The final CCLE table will be formatted and saved as text file:

CCLEP <- CCLE_ANNO_FILT |>
  mutate(across(where(is.numeric),\(x) sprintf("%.4f", x)))
write_tsv(CCLEP,"CCLE_LOG2TPM1_CRC_FILT.txt")  

4. Read IC50 information from GDSC

The Genomics of Drug Sensitivity in Cancer (GDSC) database was used to obtain drug sensitivity data for cancer cell lines, which were saved in the file GDSC1.txt. For this analysis, the primary information used was the IC50 values (or log-transformed IC50; ln IC50) for the MEK inhibitor Selumetinib in colorectal cancer cell lines. The GDSC1 (legacy) release was used and remains available through the GDSC website or can be downloaded directly as an Excel file from GDSC1_fitted_dose_response.

GDSC<-read_tsv("GDSC1.txt")
GDSC<- GDSC |>
  mutate(CELL_LINE_NAME = toupper(gsub("-", "", CELL_LINE_NAME)))|>
  filter(TCGA_DESC=="COREAD",DRUG_NAME=="Selumetinib", DRUG_ID=="1062")
write_tsv(GDSC,"GDSC_CRC_SELUMETINIB_IC50.txt")
GDSC1<-GDSC |>
  column_to_rownames("CELL_LINE_NAME")

The final IC50 table from GDSC GDSC1

GDSC1

5. Get IC50 (ln IC50) values from matched cell lines from CCLE expression data

CL <- base::intersect(GDSC$CELL_LINE_NAME, names(CCLE_ANNO_FILT))
IC50<-GDSC1[CL,"LN_IC50"]
CCLEX <- CCLE_ANNO_FILT |>
  select(all_of(c("SYMBOL",CL)))
CCLEXU <- CCLEX |>
  distinct(SYMBOL, .keep_all = TRUE)

6. Define plotting function for linear regression

This section defines the plotting function plotlinreg(gene_name, IC50, expression), which generates a linear regression plot for a given gene. The Selumetinib ln(IC50) value is shown on the x-axis, and gene expression, expressed as log2(TPM + 1), is shown on the y-axis. The plot includes the fitted regression line with confidence intervals, together with Pearson’s correlation coefficient and the unadjusted p-value.

plotlinreg<-function (name,y,x) {
  plot_df <- tibble(
    IC50 = y,
    expr = x
  )
  di<-max(x)-min(x)
  fit1<-lm(IC50 ~ x,data=plot_df)
  s1 <- summary(fit1)
  p1 <- s1$coefficients[2,4]
  r21<-r2 <- s1$r.squared
  r1 <- sign(coef(fit1)[2]) * sqrt(r21)
   g <- ggplot(plot_df, aes(IC50, expr)) +
    geom_point() +
    geom_smooth(method = "lm") +
    labs(
      x = "Selumetinib ln(IC50)",
      y = paste0(name, " log2(TPM+1)")
    ) +
    theme_classic(base_size = 16) + 
    theme(
      plot.margin = margin(1.5,1.5,1.5,1.5, "cm"),
      axis.title.y = element_text(vjust = +4),
      axis.title.x = element_text(vjust = -2),
      axis.text.y=element_text(size=16),
      axis.text.x=element_text(size=16),
    ) +
    annotate("text", x=0.75*max(IC50), y=max(x)+0.2*di, label= paste0("R = ",round(r1, 3)), size=5) + 
    annotate("text", x=0.75*max(IC50), y=max(x)+0.1*di, label= paste0("p = ",signif(p1, 3)), size=5)
  ggsave(
    paste0(name, "_REG_PLOT.pdf"),
    g,
    width = 14,
    height = 12,
    units = "cm"
  )
}

7. Calculate correlation (linear regression) of gene expression with IC50 values

The expression object CCLEXU is split by gene symbol and processed using map_dfr() from the purrr package. For each gene, a linear regression model is fitted between gene expression and Selumetinib ln(IC50) values. Regression statistics, including slope (coefficient), Pearson’s correlation coefficient (R), coefficient of determination (R²), and p-value, were extracted and combined into a single results table RESULTS. Only genes meeting the predefined significance criteria (P < 0.01 and R² > 0.1) are retained. For genes with p < 0.002 a regresion plot is saved in pdf format using the defined plotting function plotlinreg(gene_name, IC50, expression).

RESULTS <- CCLEXU |>
  split(CCLEXU$SYMBOL) |>
  map_dfr(\(gene) {
    x <- unlist(gene[-1])
    fit <- lm(IC50 ~ x)
    s <- summary(fit)
    p <- s$coefficients[2,4]
    r2 <- s$r.squared
    r <- sign(coef(fit)[2]) * sqrt(r2)
    if (p < 0.002) {
      plotlinreg(gene$SYMBOL[1],IC50,x)
    }
    if (p < 0.01 && r2 > 0.1) {
      tibble(
        symbol = gene$SYMBOL[1],
        slope = coef(fit)[2],
        R = r,
        R2 = r2,
        P = p
      )
    } else {
      tibble()
    }
  })
RESULTS<-RESULTS |>
  arrange(desc(R))

The final RESULTS table:

RESULTS

Write results to text file and Excel file

write_tsv(RESULTS,"SELUMETINIB_CRC_RESISTANT_SENSITIVE_GENES.txt")  
write_xlsx(RESULTS,"SELUMETINIB_CRC_RESISTANT_SENSITIVE_GENES.xlsx") 

8. Determine acquired resistance from RNA sequencing data of resistant cell lines

Raw sequencing data for GSE126109 were downloaded from the Gene Expression Omnibus (GEO) as the archive GSE126109_RAW.tar (https://www.ncbi.nlm.nih.gov/geo/download/?acc=GSE126109&format=file). The following samples were included in the analysis: HCT116R, HCT116R_6244R, HKH2, HKH2_6244R, LoVo, LoVo_6244R, SW480, SW480_6244R, SW620, and SW620_6244R, representing five colorectal cancer cell lines and their corresponding Selumetinib (6244R)-resistant derivatives. For each sample, gene-level count tables were extracted from the archive and combined into a single count matrix (GSE126109_COUNT_MATRIX.txt). Sample annotations, including cell line and treatment status, were compiled into a corresponding sample information table (GSE126109_SAMPLES.txt).

SAMPLES<- read_tsv("GSE126109_SAMPLES.txt")
COUNTS<- read_tsv("GSE126109_COUNT_MATRIX.txt")

The sample information

SAMPLES

The final counts table

COUNTS |>
  select(1:8) |>
  slice_head(n = 20)

9. Perform differential gene expression analysis using DESeq2

As differences between cell lines are expected to be greater than those associated with acquired resistance, as indicated by the PCA analysis, differential expression analysis was performed using a paired design in DESeq2 design = ~ CELL + COND).

count_mat <- COUNTS |> column_to_rownames("gene") |> round()
sample_info <- SAMPLES |> select(-FILE)
dds <- DESeqDataSetFromMatrix(countData = count_mat,colData = sample_info,design= ~ CELL + COND)
dds$COND = relevel(dds$COND, "CTRL")
dds <- DESeq(dds)
res <- results(dds)
vsd <- vst(dds, blind=FALSE)
res_significant <- as.data.frame(res) |>
  filter(!is.na(padj), padj < 0.1, baseMean>10) |>
  arrange(desc(log2FoldChange))
res_sig_tbl <- res_significant |>  rownames_to_column("gene") |>  tibble::as_tibble()

The final significant results are stored in res_sig_tbl

res_sig_tbl |>
  select(gene, baseMean, log2FoldChange, padj) |>
  slice_head(n = 50)

Write results to a text file and an Excel file

write_tsv(res_sig_tbl,"SELUMETINIB_CRC_ACQUIRED_RESISTANCE_GENES.txt")  
write_xlsx(res_sig_tbl,"SELUMETINIB_CRC_ACQUIRED_RESISTANCE_GENES.xlsx")

10. Get a list of resistance and sensitivity gene signatures

Generate a list gene signatures for both acquired resistance (sensitivity) and intrinsic resistance (sensitivity) and save in GMT format as used for Gene Set Enrichment Analysis (GSEA).

L<-list()
L$acquired_up_genes <- pull(res_sig_tbl |> filter(log2FoldChange > 0.3) |> select(gene), gene)
L$acquired_down_genes <- pull(res_sig_tbl |> filter(log2FoldChange < -0.3) |> select(gene),gene)
L$IC50_positive_genes <- as.vector(pull(RESULTS |> filter(R > 0.3) |> select(symbol),symbol))
L$IC50_negative_genes <- as.vector(pull(RESULTS |> filter(R < -0.3) |> select(symbol),symbol))

write_gmt <- function(gene_sets, file) {
  con <- file(file, open = "wt")
  on.exit(close(con))
  for (set_name in names(gene_sets)) {
    genes <- unique(na.omit(gene_sets[[set_name]]))
    n_genes <- length(genes)
    line <- paste(c(set_name, n_genes, genes),collapse = "\t")
    writeLines(line, con)
  }
}
write_gmt(L, "MEKi_selumetinib_CRC_signatures.gmt")

11. MEKi resistance score

To assess the likelihood of a patient’s response to therapy, we defined two Selumetinib (MEK inhibitor, MEKi) resistance scores representing intrinsic and acquired resistance. Both scores were calculated using single-sample gene set enrichment analysis (ssGSEA) implemented in the GSVA package on bulk RNA sequencing data from the tumor. The intrinsic resistance score is defined as:

MEKi_score_intrinsic = ssGSEA(IC50-positive genes) − ssGSEA(IC50-negative genes), whereas the acquired resistance score is defined as:

MEKi_score_acquired = ssGSEA(acquired-upregulated genes) − ssGSEA(acquired-downregulated genes).

Higher scores indicate a gene expression profile associated with increased resistance to Selumetinib and, consequently, a lower likelihood of therapeutic response.