SeqoutGeneNames()
converts gene IDs to names using genevintage.
SeqoutCorrectNames() repairs gene symbols that Excel
changed into dates. Both accept the result of
SeqoutMatrix() or a numeric matrix with genes on rows. They
preserve expression values and row order, keep feature metadata aligned,
and record the original labels and conversion status.
Install seqout and its genevintage dependency from Saket Lab’s r-universe:
install.packages("seqout", repos = c(
"https://saketlab.r-universe.dev", "https://cloud.r-project.org"
))The full-data commands below download GEO files and annotation tables
on first use. The evaluated examples use small, unaltered excerpts
bundled with seqout, so they also run offline. Their source URLs and
extraction details are in extdata/gene-names/README.md
inside the installed package.
GSE52529,
the Monocle myoblast differentiation study, became public on 23 March
2014. Its single-cell file has 47,192 gene rows and 372 cells, with the
original versioned Ensembl IDs such as ENSG00000000003.10.
The values are FPKM, not raw counts. Select
GSE52529_fpkm_matrix.txt.gz; the separate
truseq file contains bulk measurements.
old <- SeqoutListCounts("GSE52529") |>
SeqoutMatrix(sample = "GSE52529_fpkm_matrix.txt.gz")
dim(old$X)
head(rownames(old$X))
# automatic selection; decision recorded below
automatic <- old |> SeqoutGeneNames()
automatic$gene_annotation[[1]]$annotationAutomatic release selection is a ranked estimate: filtered gene sets can fit several references, adjacent releases can share identical gene sets, and versioned IDs do not uniquely identify the annotation used. For this file the detector selects GENCODE 17 on GRCh37, matching the sample’s processing record. You do not need to supply the release or assembly. All 47,192 deposited IDs, including their version suffixes, match that reference exactly.
head(SeqoutGeneReport(automatic))
stopifnot(
identical(unname(old$X), unname(automatic$X)),
identical(rownames(automatic$X), rownames(automatic$var))
)Ranking releases needs no annotation download. It uses the complete original ID vector, bundled separately from the expression excerpt, because ranking only the displayed genes would change the evidence.
id_file <- gzfile(file.path(example_dir, "GSE52529-gene-ids.txt.gz"))
old_ids <- readLines(id_file)
close(id_file)
head(genevintage::detect_release(old_ids), 3)
#> species source release assembly feasible dist n_index
#> 1 homo_sapiens gencode 17 37 TRUE 0.2023 57232
#> 2 homo_sapiens gencode 18 37 TRUE 0.2078 57396
#> 3 homo_sapiens gencode 19 37 TRUE 0.2169 57773Update genevintage if your installation still ranks release 25 first for this file.
The first 12 genes and first three cells of the deposited file, converted with the matching GENCODE 17 excerpt:
old_excerpt <- as.matrix(read_example("GSE52529-excerpt.tsv.gz", row.names = 1))
gencode17 <- read_example("gencode17-excerpt.tsv.gz")
old_named <- SeqoutGeneNames(old_excerpt, mapping = gencode17)
SeqoutGeneReport(old_named)[, c("input", "name", "status")]
#> input name status
#> 1 ENSG00000000003.10 TSPAN6 mapped
#> 2 ENSG00000000005.5 TNMD mapped
#> 3 ENSG00000000419.8 DPM1 mapped
#> 4 ENSG00000000457.8 SCYL3 mapped
#> 5 ENSG00000000460.12 C1orf112 mapped
#> 6 ENSG00000000938.8 FGR mapped
#> 7 ENSG00000000971.11 CFH mapped
#> 8 ENSG00000001036.8 FUCA2 mapped
#> 9 ENSG00000001084.6 GCLC mapped
#> 10 ENSG00000001167.10 NFYA mapped
#> 11 ENSG00000001460.13 STPG1 mapped
#> 12 ENSG00000001461.12 NIPAL3 mapped
stopifnot(identical(as.vector(old_excerpt), as.vector(old_named)))Version suffixes are ignored for matching but retained in the audit.
For example, ENSG00000000003.10 becomes
TSPAN6. An ID without a name in the selected annotation
stays as its input ID. Duplicate symbols receive distinct row labels;
the audit’s name column preserves the unsuffixed symbol. No
rows are summed.
GSE101942
has Excel-damaged gene names. We verified that the original
GSE101942_IPSC_rawCounts.txt.gz has 56,637 rows (five of
them counting-summary rows) and six samples, with 1-Mar,
9-Sep, and 15-Sep among the row labels.
Select the raw-count file explicitly; the study also deposits differential expression result tables, which are not count matrices.
damaged <- SeqoutListCounts("GSE101942") |>
SeqoutMatrix(sample = "GSE101942_IPSC_rawCounts.txt.gz")
# explicit target, not automatic
repaired <- damaged |> SeqoutCorrectNames(species = "human", release = 116)
report <- SeqoutGeneReport(repaired)
report[report$status != "unchanged", c("input", "name", "status")]
stopifnot(identical(unname(damaged$X), unname(repaired$X)))Against Ensembl 116, 25 labels are corrected. 15-Sep
stays unresolved because this annotation has no matching candidate for
it.
The bundled excerpt contains all 26 damaged labels plus
TP53 as an unchanged control, with the original six sample
columns and their counts. The annotation excerpt spans the reference’s
complete month-related candidate vocabulary.
excel_excerpt <- as.matrix(read_example("GSE101942-excerpt.tsv.gz", row.names = 1))
human116 <- read_example("ensembl116-excel.tsv.gz")
excel_fixed <- SeqoutCorrectNames(excel_excerpt, mapping = human116, quiet = TRUE)
excel_report <- SeqoutGeneReport(excel_fixed)
excel_report[
excel_report$input %in% c("1-Mar", "9-Sep", "15-Sep", "TP53"),
c("input", "name", "status")
]
#> input name status
#> 2 1-Mar MARCHF1 corrected
#> 13 15-Sep 15-Sep unresolved
#> 26 9-Sep SEPTIN9 corrected
#> 27 TP53 TP53 unchanged
table(excel_report$status)
#>
#> corrected unchanged unresolved
#> 25 1 1
stopifnot(identical(as.vector(excel_excerpt), as.vector(excel_fixed)))The same damaged labels resolve differently against human Ensembl 95 and 116. This compares two reference vocabularies; it does not infer which release GSE101942 used.
human95 <- read_example("ensembl95-excel.tsv.gz")
excel_old <- SeqoutCorrectNames(excel_excerpt, mapping = human95, quiet = TRUE)
old_report <- SeqoutGeneReport(excel_old)
show <- excel_report$input %in% c("1-Mar", "9-Sep")
data.frame(
deposited = excel_report$input[show],
ensembl95 = old_report$name[show],
ensembl116 = excel_report$name[show]
)
#> deposited ensembl95 ensembl116
#> 1 1-Mar MARCH1 MARCHF1
#> 2 9-Sep SEPT9 SEPTIN91-Mar resolves to MARCH1 in Ensembl 95 and
MARCHF1 in 116; 9-Sep to SEPT9
and SEPTIN9. Names alone cannot tell seqout which species
or vintage to choose, so Excel correction requires either an annotation
table or both species and release. Ambiguous
dates are retained and marked ambiguous; tokens without
candidates are marked unresolved. genevintage cannot repair
some formats or losses of numeric precision. Review the report before
analysis, and correct only columns known to hold gene labels.
If the damaged symbols are in feature metadata, pass that column explicitly:
The original var$symbol column is retained. The repaired
labels become the row names of both X and var,
and each call appends its audit to gene_annotation. Save
the corrected seqout_matrix if you need to retain this
audit alongside a later Seurat or SingleCellExperiment conversion.