Skip to content

Commit 156fdce

Browse files
committed
Fix "inconsistent counts" issue
With this fix, the following counts are now correct: db_name <- install_IMGT_germline_db("202614-2", "Homo_sapiens", tcr.db=TRUE) all_counts <- list_germline_dbs(long.listing=TRUE) # long listing colSums(all_counts[[db_name]]) # V D J # 355 6 101 More generally speaking, this fix makes sure that the counts reported by list_germline_dbs()'s and list_c_region_dbs()'s long listings are consistent with the counts reported by their short listings.
1 parent 53bbc8e commit 156fdce

12 files changed

Lines changed: 535 additions & 378 deletions

‎R/clean_allele_set.R‎

Lines changed: 98 additions & 108 deletions
Large diffs are not rendered by default.

‎R/create_germline_db.R‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ list_loci_in_germline_fasta_dir <-
142142
### Create the three "region dbs": one V-, one D-, and one J-region db.
143143
.do_create_germline_db <- function(destdir, fasta_dir, loci,
144144
gapped=FALSE, with.intdata=FALSE,
145-
excluded_J_alleles=NULL,
145+
excluded_J_alleles=character(0),
146146
with.auxdata=FALSE, imgt.fasta=FALSE,
147147
disambiguate.allele.names=FALSE,
148148
verbose=FALSE)
@@ -158,7 +158,7 @@ list_loci_in_germline_fasta_dir <-
158158
verbose=verbose)
159159
J_fasta_files <- .collect_fasta_files(fasta_dir, "J", loci)
160160
create_J_region_db(J_fasta_files, destdir,
161-
excluded_J_alleles=excluded_J_alleles,
161+
excluded_alleles=excluded_J_alleles,
162162
with.auxdata=with.auxdata, imgt.fasta=imgt.fasta,
163163
disambiguate.allele.names=disambiguate.allele.names,
164164
verbose=verbose)
@@ -176,7 +176,7 @@ list_loci_in_germline_fasta_dir <-
176176
### and 'disambiguate.allele.names' arguments.
177177
create_germline_db <- function(destdir, fasta_dir, loci,
178178
gapped=FALSE, with.intdata=FALSE,
179-
excluded_J_alleles=NULL,
179+
excluded_J_alleles=character(0),
180180
with.auxdata=FALSE, imgt.fasta=FALSE,
181181
disambiguate.allele.names=FALSE,
182182
overwrite=FALSE, verbose=FALSE)

‎R/create_region_db.R‎

Lines changed: 284 additions & 180 deletions
Large diffs are not rendered by default.

‎R/file-utils.R‎

Lines changed: 20 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,26 @@ display_data_frame_in_browser <- function(df)
309309
}
310310

311311

312+
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
313+
### read_version_file()
314+
###
315+
316+
read_version_file <- function(dirpath)
317+
{
318+
stopifnot(isSingleNonWhiteString(dirpath), dir.exists(dirpath))
319+
version_path <- file.path(dirpath, "version")
320+
if (!file.exists(version_path))
321+
stop(wmsg("missing 'version' file in ", dirpath, "/"))
322+
version <- readLines(version_path)
323+
if (length(version) != 1L)
324+
stop(wmsg("file '", version_path, "' should contain exactly one line"))
325+
version <- trimws2(version)
326+
if (version == "")
327+
stop(wmsg("file '", version_path, "' contains only white spaces"))
328+
version
329+
}
330+
331+
312332
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
313333
### list_fasta_files()
314334
###
@@ -326,55 +346,6 @@ list_fasta_files <- function(path, pattern="\\.fasta$", full.names=TRUE,
326346
}
327347

328348

329-
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
330-
### copy_fasta_file()
331-
###
332-
333-
### By "repeated" alleles we mean alleles with identical sequences **and**
334-
### names. Note that:
335-
### - we keep alleles with identical sequences but different names;
336-
### - we also keep alleles with identical names but different sequences.
337-
### Note that the .drop_repeated_alleles() function in R/clean_allele_set.R
338-
### implements the same semantic.
339-
copy_fasta_file <- function(infasta, outfasta, excluded_alleles=NULL,
340-
drop.repeated.alleles=FALSE)
341-
{
342-
stopifnot(isSingleNonWhiteString(infasta),
343-
!dir.exists(infasta), file.exists(infasta),
344-
isSingleNonWhiteString(outfasta),
345-
!dir.exists(outfasta), !file.exists(outfasta),
346-
isTRUEorFALSE(drop.repeated.alleles))
347-
if (!is.null(excluded_alleles) || drop.repeated.alleles) {
348-
headers <- names(fasta.seqlengths(infasta))
349-
allele_names <- clean_imgt_fasta_headers(headers)
350-
drop_me <- logical(length(allele_names))
351-
if (!is.null(excluded_alleles)) {
352-
stopifnot(is.character(excluded_alleles))
353-
drop_me <- drop_me | (allele_names %in% excluded_alleles)
354-
}
355-
if (drop.repeated.alleles) {
356-
alleles <- readBStringSet(infasta)
357-
stopifnot(identical(names(alleles), headers))
358-
m1 <- match(alleles, alleles)
359-
m2 <- match(allele_names, allele_names)
360-
is_repeated <- selfmatchIntegerPairs(m1, m2) != seq_along(alleles)
361-
drop_me <- drop_me | is_repeated
362-
}
363-
drop_idx <- which(drop_me)
364-
if (length(drop_idx) != 0L) {
365-
lines <- readLines(infasta)
366-
record_starts <- grep("^>", lines)
367-
stopifnot(identical(lines[record_starts], paste0(">", headers)))
368-
record_ends <- c(tail(record_starts - 1L, n=-1L), length(lines))
369-
record_bounds <- IRanges(record_starts, record_ends)
370-
lines <- extractROWS(lines, record_bounds[-drop_idx])
371-
return(writeLines(lines, outfasta))
372-
}
373-
}
374-
stopifnot(file.copy(infasta, outfasta, overwrite=FALSE))
375-
}
376-
377-
378349
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
379350
### fasta_files_as_one_uncompressed_file()
380351
###

‎R/install_IMGT_germline_db.R‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ install_IMGT_germline_db <- function(release, organism="Homo sapiens",
109109
if (organism == "Homo_sapiens" && loci_prefix == "IG") {
110110
excluded_J_alleles <- .EXCLUDED_IMGT_HUMAN_J_ALLELES
111111
} else {
112-
excluded_J_alleles <- NULL
112+
excluded_J_alleles <- character(0)
113113
}
114114

115115
## Create and install germline db.

‎R/install_custom_germline_db.R‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ stop_on_existing_cached_germline_db <- function(db_name)
5454
### Not exported!
5555
install_germline_db <- function(install_dir, db_name, fasta_dir, loci,
5656
gapped=FALSE, with.intdata=FALSE,
57-
excluded_J_alleles=NULL,
57+
excluded_J_alleles=character(0),
5858
with.auxdata=FALSE, imgt.fasta=FALSE,
5959
disambiguate.allele.names=FALSE,
6060
if.exists=c("error", "overwrite", "no-op"),

‎R/utils.R‎

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,65 @@ check_seqlens <- function(seqlens, varname)
130130
}
131131

132132

133+
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
134+
### make_unique_allele_names()
135+
###
136+
137+
### Generates a pool of unique suffixes made of lowercase letters.
138+
.make_pool_of_suffixes <- function(min_pool_size)
139+
{
140+
max_pool_size <- (length(letters)**8 - 1) / (length(letters) - 1) - 1
141+
if (min_pool_size > max_pool_size)
142+
stop(wmsg("too many duplicated allele names"))
143+
ans <- character(0)
144+
for (i in 1:7) {
145+
ans <- c(ans, mkAllStrings(letters, i))
146+
if (length(ans) >= min_pool_size)
147+
return(ans)
148+
}
149+
## Should never happen because we checked for this condition earlier (see
150+
## above).
151+
stop(wmsg("too many duplicated allele names"))
152+
}
153+
154+
### Returns the suffixes in a named character vector parallel to 'x'.
155+
.make_disambiguation_suffixes <- function(x)
156+
{
157+
stopifnot(is.character(x))
158+
if (length(x) <= 1L) {
159+
suffixes <- character(length(x))
160+
} else {
161+
oo <- order(x)
162+
ordered_x <- x[oo]
163+
ir <- IRanges(1L, runLength(Rle(ordered_x)))
164+
pool_of_suffixes <- .make_pool_of_suffixes(max(width(ir)))
165+
suffixes <- extractList(pool_of_suffixes, ir) # CharacterList
166+
suffixes[lengths(suffixes) == 1L] <- ""
167+
rev_oo <- S4Vectors:::reverseIntegerInjection(oo, length(oo))
168+
suffixes <- unlist(suffixes, use.names=FALSE)[rev_oo]
169+
}
170+
setNames(suffixes, names(x))
171+
}
172+
173+
### Has its own tests in tests/testthat/test-utils.R!
174+
### We make the allele names unique by adding a disambiguation suffix to
175+
### them. Note that this is not guaranteed to make the allele names unique
176+
### because adding the suffixes can create clashes with some other allele
177+
### names that already looks like they have a disambiguation suffix.
178+
### So we check for that and raise an error if it happens.
179+
make_unique_allele_names <- function(allele_names, suffixes.only=FALSE)
180+
{
181+
stopifnot(isTRUEorFALSE(suffixes.only))
182+
suffixes <- .make_disambiguation_suffixes(allele_names)
183+
ans <- add_suffix(allele_names, suffixes)
184+
if (anyDuplicated(ans))
185+
stop(wmsg("Our allele name disambiguation scheme doesn't work for ",
186+
"your set of alleles, sorry. Please file an issue at ",
187+
"https://github.com/HyrienLab/igblastr/issues"))
188+
if (suffixes.only) suffixes else ans
189+
}
190+
191+
133192
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
134193
### interweave()
135194
###
@@ -168,26 +227,6 @@ align_vectors_by_names <- function(vectors)
168227
}
169228

170229

171-
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
172-
### read_version_file()
173-
###
174-
175-
read_version_file <- function(dirpath)
176-
{
177-
stopifnot(isSingleNonWhiteString(dirpath), dir.exists(dirpath))
178-
version_path <- file.path(dirpath, "version")
179-
if (!file.exists(version_path))
180-
stop(wmsg("missing 'version' file in ", dirpath, "/"))
181-
version <- readLines(version_path)
182-
if (length(version) != 1L)
183-
stop(wmsg("file '", version_path, "' should contain exactly one line"))
184-
version <- trimws2(version)
185-
if (version == "")
186-
stop(wmsg("file '", version_path, "' contains only white spaces"))
187-
version
188-
}
189-
190-
191230
### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
192231
### rows_with_same_key_are_identical()
193232
###

‎TODO‎

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,6 @@ o More testing of combine_germline_dbs(). Expand the examples in its man
77
o In addition to combine_germline_dbs(), we need combine_c_region_dbs()
88
to combine C-region dbs.
99

10-
o Fix the "inconsistent counts" issue:
11-
12-
db_name <- install_IMGT_germline_db("202614-2", "Homo_sapiens", tcr.db=TRUE)
13-
all_counts <- list_germline_dbs(long.listing=TRUE) # long listing
14-
colSums(all_counts[[db_name]])
15-
# V D J
16-
# 370 6 101
17-
18-
These counts are wrong and inconsistent with the counts reported
19-
by list_germline_dbs()'s short listing (V:355 D:6 J:101).
20-
See .finish_cleanup() in R/clean_allele_set.R why.
21-
2210
o Maybe replace 'without.intdata' and 'without.auxdata' arguments with
2311
'with.intdata' and 'with.auxdata'. With default of TRUE for 'with.intdata'
2412
and "auto" for 'with.auxdata' ("auto" meaning "include the computed auxdata

‎tests/testthat/test-clean_allele_set.R‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,47 @@ test_that(".drop_repeated_alleles()", {
2020
expect_identical(as.character(object), toupper(y[-c(5:7, 10L)]))
2121
})
2222

23+
test_that(".make_DORsummary()", {
24+
make_DORsummary <- igblastr:::.make_DORsummary
25+
26+
expected <- data.frame(allele_name="A", suffix="")
27+
expect_identical(make_DORsummary(c(A="ct")), expected)
28+
29+
x <- c(A="ct", A="ct")
30+
expected <- data.frame(allele_name=names(x), suffix=c("", NA))
31+
expect_identical(make_DORsummary(x), expected)
32+
expect_identical(make_DORsummary(BStringSet(x)), expected)
33+
expect_identical(make_DORsummary(DNAStringSet(x)), expected)
34+
35+
x <- c(A="ct", A="ct", A="ct")
36+
expected <- data.frame(allele_name=names(x), suffix=c("", NA, NA))
37+
expect_identical(make_DORsummary(x), expected)
38+
expect_identical(make_DORsummary(BStringSet(x)), expected)
39+
expect_identical(make_DORsummary(DNAStringSet(x)), expected)
40+
41+
x <- c(A="ct", B="", A="ct", A="ct", C="", D="ggg", C="")
42+
expected <- data.frame(allele_name=names(x),
43+
suffix=c("", "", NA, NA, "", "", NA))
44+
expect_identical(make_DORsummary(x), expected)
45+
expect_identical(make_DORsummary(BStringSet(x)), expected)
46+
expect_identical(make_DORsummary(DNAStringSet(x)), expected)
47+
48+
x <- c(A="tt", B="g", C="gg", B="", C="g", A="tt", D="t",
49+
B="ggg", B="", C="", B="g", C="gg", E="tt", B="tt")
50+
expected <- data.frame(allele_name=names(x),
51+
suffix=c("", "a", "a", "b", "b", NA, "",
52+
"c", NA, "c", NA, NA, "", "d"))
53+
expect_identical(
54+
make_DORsummary(x, disambiguate.allele.names=TRUE),
55+
expected)
56+
expect_identical(
57+
make_DORsummary(BStringSet(x), disambiguate.allele.names=TRUE),
58+
expected)
59+
expect_identical(
60+
make_DORsummary(DNAStringSet(x), disambiguate.allele.names=TRUE),
61+
expected)
62+
})
63+
2364
.check_object_mcols <- function(object)
2465
{
2566
object_mcols <- mcols(object)

‎tests/testthat/test-combine_germline_dbs.R‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ test_that("combine_germline_dbs()", {
4141
db_name2 <- "_OGRDB.mouse.PWD_PhJ.IGH+IGK+IGL.202410"
4242

4343
## Combine 'db_name1' and 'db_name2'.
44-
db_name12 <- "comb.OGRDB.human+mouse.IGH+IGK+IGL"
44+
db_name12 <- "comb.OGRDB.human+mouse.IGH+IGK+IGL"
4545
combine_germline_dbs(db_name12, db_name1, db_name2, "_Hs", "_Mm")
4646
.check_combined_germline_db(db_name12, db_name1, db_name2, "_Hs", "_Mm")
4747

4848
## Combine 'db_name2' and 'db_name1'.
49-
db_name21 <- "comb.OGRDB.mouse+human.IGH+IGK+IGL"
49+
db_name21 <- "comb.OGRDB.mouse+human.IGH+IGK+IGL"
5050
combine_germline_dbs(db_name21, db_name2, db_name1, "_Mm", "_Hs")
5151
.check_combined_germline_db(db_name21, db_name2, db_name1, "_Mm", "_Hs")
5252

@@ -93,5 +93,8 @@ test_that("combine_germline_dbs()", {
9393
expect_true(all(AIRR_df12$locus %in% c("IGK", "IGL")))
9494
expect_true(all(igblastr:::has_suffix(AIRR_df21$v_call, "_Hs")))
9595
expect_true(all(igblastr:::has_suffix(AIRR_df21$j_call, "_Hs")))
96+
97+
rm_germline_db(db_name12)
98+
rm_germline_db(db_name21)
9699
})
97100

0 commit comments

Comments
 (0)