load libraries————————————

1. Load and Subset Normal CD4 T Cells

Layers(All_samples_Merged@assays$RNA)
[1] "data"   "counts"

2. Run FindAllMarkers on RNA Assay

# Set assay to RNA
DefaultAssay(All_samples_Merged) <- "RNA"

# Check if RNA assay has normalized data
if (!"data" %in% slotNames(All_samples_Merged[["RNA"]]) || 
    ncol(GetAssayData(All_samples_Merged[["RNA"]], slot = "data")) == 0) {
  
  message("RNA assay does not contain normalized data. Running NormalizeData...")
  All_samples_Merged <- NormalizeData(
    All_samples_Merged,
    assay = "RNA",
    normalization.method = "LogNormalize",
    scale.factor = 10000
  )
  
} else {
  message("RNA assay already contains normalized data. Skipping normalization.")
}
Performing log-normalization
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Idents(All_samples_Merged) <- "seurat_clusters"

# Find markers for all clusters
all_markers <- FindAllMarkers(
    All_samples_Merged,
    logfc.threshold = 0.2,
    test.use = "wilcox",
    min.pct = 0.1,
    min.diff.pct = 0.2,
    only.pos = TRUE,
    max.cells.per.ident = 50,
    assay = "RNA"
)

# Save markers
write.csv(all_markers, "AllMarkers_clusters-17-09-2025-part2-nbi-parameters.csv", row.names = FALSE)

cat("Full marker list saved to AllMarkers_clusters-17-09-2025-part2-nbi-parameters.csv\n")
Full marker list saved to AllMarkers_clusters-17-09-2025-part2-nbi-parameters.csv

3. Top 25 and Top 5 markers per cluster


# Top 25 markers per cluster
all_markers %>%
    group_by(cluster) %>%
    top_n(-25, p_val_adj) %>% 
    # In case of tied p-values, further select the top 25 genes by fold-change
    top_n(25, avg_log2FC) -> 
  top25
head(top25)

write.csv(top25, "Top25Markers_clusters-part2-nbi.csv", row.names = FALSE)

cat("Top 25 marker list saved to Top25Markers_clusters-part2-nbi.csv\n")
Top 25 marker list saved to Top25Markers_clusters-part2-nbi.csv
# Top 5 markers per cluster
all_markers %>%
    group_by(cluster) %>%
    top_n(-5, p_val_adj) %>% 
    # In case of tied p-values, further select the top 25 genes by fold-change
    top_n(5, avg_log2FC) -> 
  top5
head(top5)

write.csv(top25, "Top5Markers_clusters-part2-nbi.csv", row.names = FALSE)

cat("Top 5 marker list saved to Top5Markers_clusters-part2-nbi.csv\n")
Top 5 marker list saved to Top5Markers_clusters-part2-nbi.csv

3. Visualize Markers


DefaultAssay(All_samples_Merged) <- "RNA"

# Unique genes from top5
all_genes <- top5$gene

# 1️⃣ Check overlap with RNA assay
valid_genes <- intersect(unique(all_genes), rownames(All_samples_Merged[["RNA"]]))
invalid_genes <- setdiff(unique(all_genes), rownames(All_samples_Merged[["RNA"]]))

cat("Valid genes:", length(valid_genes), "\n")
Valid genes: 67 
cat("Missing genes:", invalid_genes, "\n\n")
Missing genes:  
# 2️⃣ Check duplicates in top5 list
gene_counts <- table(all_genes)
duplicate_genes <- names(gene_counts[gene_counts > 1])

if(length(duplicate_genes) > 0){
  cat("Genes appearing more than once in top5 list:\n")
  print(duplicate_genes)
} else {
  cat("No duplicates found in top5 list.\n")
}
Genes appearing more than once in top5 list:
[1] "EGFL6"       "RPS4Y1"      "TRAV38-2DV8"
# Scale only the top5 marker genes
All_samples_Merged <- ScaleData(All_samples_Merged, features = unique(top5$gene))

  |                                                                                                            
  |                                                                                                      |   0%
  |                                                                                                            
  |======================================================================================================| 100%
 # DotPlot for top 5 markers
DotPlot(All_samples_Merged, features = unique(top5$gene), cols =
c("grey", "firebrick"), dot.scale = 8, assay = "RNA") + RotatedAxis()

LS0tCnRpdGxlOiAiU8OpemFyeSBTeW5kcm9tZSBTaW5nbGUtQ2VsbCBSTkEtU2VxIE1hcmtlciBBbmFseXNpcy0xNS0wOS0yMDI1LVBhcnQyIgphdXRob3I6IE5hc2lyIE1haG1vb2QgQWJiYXNpCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogICNybWRmb3JtYXRzOjpyZWFkdGhlZG93bgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQotLS0KCgoKIyMgbG9hZCBsaWJyYXJpZXMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CgpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShtb25vY2xlMykKbGlicmFyeShTZXVyYXRXcmFwcGVycykKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoU0NwdWJyKQoKc2V0LnNlZWQoMTIzNCkKYGBgCgoKIyAxLiBMb2FkIGFuZCBTdWJzZXQgTm9ybWFsIENENCBUIENlbGxzCmBgYHtyIGxvYWRTZXVyYXR9CgpBbGxfc2FtcGxlc19NZXJnZWQgPC0gcmVhZFJEUygiLi4vLi4vMC1TZXVyYXRfUkRTX09CSkVDVF9GSU5BTC9TZXVyYXRfb2JqZWN0X0ZpbmFsX2NoYW5nZXMvQWxsX3NhbXBsZXNfTWVyZ2VkX3dpdGhfU1RDQVRfQW5ub3RhdGlvbl9maW5hbC01LTA5LTIwMjUucmRzIikKCgpMYXllcnMoQWxsX3NhbXBsZXNfTWVyZ2VkQGFzc2F5cyRSTkEpCgpgYGAKCiMgMi4gUnVuIEZpbmRBbGxNYXJrZXJzIG9uIFJOQSBBc3NheQpgYGB7cn0KIyBTZXQgYXNzYXkgdG8gUk5BCkRlZmF1bHRBc3NheShBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJSTkEiCgojIENoZWNrIGlmIFJOQSBhc3NheSBoYXMgbm9ybWFsaXplZCBkYXRhCmlmICghImRhdGEiICVpbiUgc2xvdE5hbWVzKEFsbF9zYW1wbGVzX01lcmdlZFtbIlJOQSJdXSkgfHwgCiAgICBuY29sKEdldEFzc2F5RGF0YShBbGxfc2FtcGxlc19NZXJnZWRbWyJSTkEiXV0sIHNsb3QgPSAiZGF0YSIpKSA9PSAwKSB7CiAgCiAgbWVzc2FnZSgiUk5BIGFzc2F5IGRvZXMgbm90IGNvbnRhaW4gbm9ybWFsaXplZCBkYXRhLiBSdW5uaW5nIE5vcm1hbGl6ZURhdGEuLi4iKQogIEFsbF9zYW1wbGVzX01lcmdlZCA8LSBOb3JtYWxpemVEYXRhKAogICAgQWxsX3NhbXBsZXNfTWVyZ2VkLAogICAgYXNzYXkgPSAiUk5BIiwKICAgIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsCiAgICBzY2FsZS5mYWN0b3IgPSAxMDAwMAogICkKICAKfSBlbHNlIHsKICBtZXNzYWdlKCJSTkEgYXNzYXkgYWxyZWFkeSBjb250YWlucyBub3JtYWxpemVkIGRhdGEuIFNraXBwaW5nIG5vcm1hbGl6YXRpb24uIikKfQoKCgpJZGVudHMoQWxsX3NhbXBsZXNfTWVyZ2VkKSA8LSAic2V1cmF0X2NsdXN0ZXJzIgoKIyBGaW5kIG1hcmtlcnMgZm9yIGFsbCBjbHVzdGVycwphbGxfbWFya2VycyA8LSBGaW5kQWxsTWFya2VycygKICAgIEFsbF9zYW1wbGVzX01lcmdlZCwKICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMiwKICAgIHRlc3QudXNlID0gIndpbGNveCIsCiAgICBtaW4ucGN0ID0gMC4xLAogICAgbWluLmRpZmYucGN0ID0gMC4yLAogICAgb25seS5wb3MgPSBUUlVFLAogICAgbWF4LmNlbGxzLnBlci5pZGVudCA9IDUwLAogICAgYXNzYXkgPSAiUk5BIgopCgojIFNhdmUgbWFya2Vycwp3cml0ZS5jc3YoYWxsX21hcmtlcnMsICJBbGxNYXJrZXJzX2NsdXN0ZXJzLTE3LTA5LTIwMjUtcGFydDItbmJpLXBhcmFtZXRlcnMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgpjYXQoIkZ1bGwgbWFya2VyIGxpc3Qgc2F2ZWQgdG8gQWxsTWFya2Vyc19jbHVzdGVycy0xNy0wOS0yMDI1LXBhcnQyLW5iaS1wYXJhbWV0ZXJzLmNzdlxuIikKCmBgYAoKIyAzLiBUb3AgMjUgYW5kIFRvcCA1IG1hcmtlcnMgcGVyIGNsdXN0ZXIKYGBge3J9CgojIFRvcCAyNSBtYXJrZXJzIHBlciBjbHVzdGVyCmFsbF9tYXJrZXJzICU+JQogICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lCiAgICB0b3BfbigtMjUsIHBfdmFsX2FkaikgJT4lIAogICAgIyBJbiBjYXNlIG9mIHRpZWQgcC12YWx1ZXMsIGZ1cnRoZXIgc2VsZWN0IHRoZSB0b3AgMjUgZ2VuZXMgYnkgZm9sZC1jaGFuZ2UKICAgIHRvcF9uKDI1LCBhdmdfbG9nMkZDKSAtPiAKICB0b3AyNQpoZWFkKHRvcDI1KQoKd3JpdGUuY3N2KHRvcDI1LCAiVG9wMjVNYXJrZXJzX2NsdXN0ZXJzLXBhcnQyLW5iaS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCmNhdCgiVG9wIDI1IG1hcmtlciBsaXN0IHNhdmVkIHRvIFRvcDI1TWFya2Vyc19jbHVzdGVycy1wYXJ0Mi1uYmkuY3N2XG4iKQoKIyBUb3AgNSBtYXJrZXJzIHBlciBjbHVzdGVyCmFsbF9tYXJrZXJzICU+JQogICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lCiAgICB0b3BfbigtNSwgcF92YWxfYWRqKSAlPiUgCiAgICAjIEluIGNhc2Ugb2YgdGllZCBwLXZhbHVlcywgZnVydGhlciBzZWxlY3QgdGhlIHRvcCAyNSBnZW5lcyBieSBmb2xkLWNoYW5nZQogICAgdG9wX24oNSwgYXZnX2xvZzJGQykgLT4gCiAgdG9wNQpoZWFkKHRvcDUpCgp3cml0ZS5jc3YodG9wMjUsICJUb3A1TWFya2Vyc19jbHVzdGVycy1wYXJ0Mi1uYmkuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgpjYXQoIlRvcCA1IG1hcmtlciBsaXN0IHNhdmVkIHRvIFRvcDVNYXJrZXJzX2NsdXN0ZXJzLXBhcnQyLW5iaS5jc3ZcbiIpCgpgYGAKCiMgMy4gVmlzdWFsaXplIE1hcmtlcnMKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPSAxOH0KCkRlZmF1bHRBc3NheShBbGxfc2FtcGxlc19NZXJnZWQpIDwtICJSTkEiCgojIFVuaXF1ZSBnZW5lcyBmcm9tIHRvcDUKYWxsX2dlbmVzIDwtIHRvcDUkZ2VuZQoKIyAx77iP4oOjIENoZWNrIG92ZXJsYXAgd2l0aCBSTkEgYXNzYXkKdmFsaWRfZ2VuZXMgPC0gaW50ZXJzZWN0KHVuaXF1ZShhbGxfZ2VuZXMpLCByb3duYW1lcyhBbGxfc2FtcGxlc19NZXJnZWRbWyJSTkEiXV0pKQppbnZhbGlkX2dlbmVzIDwtIHNldGRpZmYodW5pcXVlKGFsbF9nZW5lcyksIHJvd25hbWVzKEFsbF9zYW1wbGVzX01lcmdlZFtbIlJOQSJdXSkpCgpjYXQoIlZhbGlkIGdlbmVzOiIsIGxlbmd0aCh2YWxpZF9nZW5lcyksICJcbiIpCmNhdCgiTWlzc2luZyBnZW5lczoiLCBpbnZhbGlkX2dlbmVzLCAiXG5cbiIpCgojIDLvuI/ig6MgQ2hlY2sgZHVwbGljYXRlcyBpbiB0b3A1IGxpc3QKZ2VuZV9jb3VudHMgPC0gdGFibGUoYWxsX2dlbmVzKQpkdXBsaWNhdGVfZ2VuZXMgPC0gbmFtZXMoZ2VuZV9jb3VudHNbZ2VuZV9jb3VudHMgPiAxXSkKCmlmKGxlbmd0aChkdXBsaWNhdGVfZ2VuZXMpID4gMCl7CiAgY2F0KCJHZW5lcyBhcHBlYXJpbmcgbW9yZSB0aGFuIG9uY2UgaW4gdG9wNSBsaXN0OlxuIikKICBwcmludChkdXBsaWNhdGVfZ2VuZXMpCn0gZWxzZSB7CiAgY2F0KCJObyBkdXBsaWNhdGVzIGZvdW5kIGluIHRvcDUgbGlzdC5cbiIpCn0KIyBTY2FsZSBvbmx5IHRoZSB0b3A1IG1hcmtlciBnZW5lcwpBbGxfc2FtcGxlc19NZXJnZWQgPC0gU2NhbGVEYXRhKEFsbF9zYW1wbGVzX01lcmdlZCwgZmVhdHVyZXMgPSB1bmlxdWUodG9wNSRnZW5lKSkKCgoKICMgRG90UGxvdCBmb3IgdG9wIDUgbWFya2VycwpEb3RQbG90KEFsbF9zYW1wbGVzX01lcmdlZCwgZmVhdHVyZXMgPSB1bmlxdWUodG9wNSRnZW5lKSwgY29scyA9CmMoImdyZXkiLCAiZmlyZWJyaWNrIiksIGRvdC5zY2FsZSA9IDgsIGFzc2F5ID0gIlJOQSIpICsgUm90YXRlZEF4aXMoKQoKYGBgCgoKCg==