Skip to content

Commit d7705b6

Browse files
committed
GAMA version 0.2.8
1 parent dee11a2 commit d7705b6

12 files changed

Lines changed: 151 additions & 48 deletions

CITATION.cff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
cff-version: 1.2.0
22
message: 'If you use GAMA in your research, please cite it as below.'
33
title: 'GAMA: Genomic Availability & Metadata Analysis Tool'
4-
version: 0.2.7
5-
date-released: 2026-04-23
4+
version: 0.2.8
5+
date-released: 2026-05-08
66
authors:
77
- family-names: Lewis
88
given-names: James

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: GAMA
22
Title: Genomic Availability & Metadata Analysis Tool
3-
Version: 0.2.7
3+
Version: 0.2.8
44
Authors@R:
55
person('James', 'Lewis',
66
email = 'James.Lewis-2022@outlook.com',

NEWS.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
# GAMA 0.2.8
2+
3+
## Reliability
4+
- Patched SRA modality subclass capitalisation so `other` and `unknown` are treated consistently as lower-case labels
5+
- Added clearer error messaging for invalid `class`, `subclass`, and `unit` argument parameters, including suggestion logic
6+
7+
## API changes
8+
- Removed the `classes` argument from `plot_sra_geo()`
9+
- `plot_sra_geo()` now uses a fixed GEO-oriented modality display set
10+
11+
## Documentation
12+
- Updated roxygen documentation and the GAMA user guide accordingly
13+
14+
## Testing
15+
- Tested canonical, normalised, fuzzy, and unmatched parameter inputs using real `query_species()` workflows
16+
17+
---
18+
119
# GAMA 0.2.7
220

321
## Reliability

R/Availability_Analysis.R

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ include_geo = FALSE) {
371371
#'
372372
#' Retrieves and structures assembly metadata for one or more species using the
373373
#' Assembly identifiers stored in the output of [query_species()]. Metadata are
374-
#' returned in a tidy tibble and optionally reduced to a single 'best' assembly
374+
#' returned in a tidy tibble and optionally reduced to a single best assembly
375375
#' per species.
376376
#'
377377
#' When `best = TRUE`, the best assembly is selected using structural-weighting
@@ -501,6 +501,7 @@ extract_assembly_metadata <- function(results, species = NULL, best = FALSE) {
501501
#' `SELEX`}
502502
#' \item{`chromatin`}{`3C-based`, `ChIA-PET`, `Hi-C`, `TCC`}
503503
#' \item{`other`}{`other`}
504+
#' \item{`unknown`}{`unknown`}
504505
#' }
505506
#'
506507
#' @param results A list returned by [query_species()], containing SRA IDs.
@@ -540,6 +541,13 @@ only_geo = FALSE) {
540541
if (length(missing) > 0L) .gama_warn('Requested species not found in `results`: ', paste(missing, collapse = ', '), '. Dropping.')
541542
species <- species[species %in% names(results)]
542543
}
544+
valid_class <- c(names(.ONTOLOGY), 'unknown')
545+
valid_subclass <- c(
546+
unique(unlist(lapply(.ONTOLOGY, names), use.names = FALSE)),
547+
'unknown'
548+
)
549+
class <- .gama_validate_choices(class, 'class', valid_class)
550+
subclass <- .gama_validate_choices(subclass, 'subclass', valid_subclass)
543551
if (!is.null(species) && !length(species)) {
544552
META <- tibble::tibble(
545553
species = character(),
@@ -617,9 +625,9 @@ only_geo = FALSE) {
617625
summarise_sra_skew <- function(x, species = NULL, unit = c('bioproject', 'biosample'), class = NULL) {
618626
x <- .gama_require_output(x, 'summarise_sra_availability')
619627
if (missing(unit)) unit <- 'bioproject'
620-
if (length(unit) != 1L) .gama_stop('`unit` must be a single value: \'bioproject\' or \'biosample\'.')
621-
unit <- match.arg(unit)
622-
if (!is.null(class) && length(class) != 1L) .gama_stop('`class` must be a single modality class (or NULL). Use one class per call.')
628+
unit <- .gama_validate_choices(unit, 'unit', c('bioproject', 'biosample'), multiple = FALSE, allow_null = FALSE)
629+
valid_class <- c(names(.ONTOLOGY), 'unknown')
630+
class <- .gama_validate_choices(class, 'class', valid_class, multiple = FALSE)
623631
prof <- .gama_require_cache(
624632
x,
625633
attr_name = 'sra_profile',

R/Core_Logic.R

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@
174174

175175
.classify_strategy <- function(term, ontology) {
176176
if (is.na(term) || !nzchar(term) || .is_unknown(term)) {
177-
return(list(class = 'unknown', subclass = 'Unknown'))
177+
return(list(class = 'unknown', subclass = 'unknown'))
178178
}
179179
for (class in names(ontology)) {
180180
for (subclass in names(ontology[[class]])) {
@@ -183,7 +183,7 @@
183183
}
184184
}
185185
}
186-
list(class = 'other', subclass = 'Other')
186+
list(class = 'other', subclass = 'other')
187187
}
188188

189189
.classify_strategy_fallback <- function(strategy_raw,
@@ -192,7 +192,7 @@ source_raw,
192192
selection_raw,
193193
title_raw = NA_character_) {
194194
if (!.is_unknown(strategy_raw) && !.is_unknown(strategy_norm) && !.is_other_strategy(strategy_norm)) {
195-
return(list(class = 'other', subclass = 'Other'))
195+
return(list(class = 'other', subclass = 'other'))
196196
}
197197
src <- .normalise_strategy(source_raw)
198198
sel <- .normalise_strategy(selection_raw)
@@ -211,7 +211,7 @@ title_raw = NA_character_) {
211211
return(list(class = 'transcriptomic', subclass = 'small-RNA'))
212212
}
213213
if (!is.na(ttl) && grepl('\\biso\\s*seq\\b|\\bisoseq\\b|\\bdirect rna\\b', ttl)) {
214-
return(list(class = 'transcriptomic', subclass = 'Long-read'))
214+
return(list(class = 'transcriptomic', subclass = 'long-read'))
215215
}
216216
return(list(class = 'transcriptomic', subclass = 'RNA-seq'))
217217
}
@@ -226,8 +226,8 @@ title_raw = NA_character_) {
226226
if (!is.na(ttl) && grepl('\\bfaire\\b', ttl)) return(list(class = 'epigenomic', subclass = 'FAIRE-seq'))
227227
if (!is.na(ttl) && grepl('\\bmnase\\b', ttl)) return(list(class = 'epigenomic', subclass = 'MNase-seq'))
228228
if (!is.na(ttl) && grepl('\\bchip\\b', ttl)) return(list(class = 'epigenomic', subclass = 'ChIP-seq'))
229-
if (!is.na(ttl) && grepl('\\bbisulfite\\b|\\bwgbs\\b|\\brrbs\\b|\\bmethyl\\b', ttl)) return(list(class = 'epigenomic', subclass = 'Bisulfite-seq'))
230-
return(list(class = 'epigenomic', subclass = 'Other'))
229+
if (!is.na(ttl) && grepl('\\bbisulfite\\b|\\bwgbs\\b|\\brrbs\\b|\\bmethyl\\b', ttl)) return(list(class = 'epigenomic', subclass = 'bisulfite-seq'))
230+
return(list(class = 'epigenomic', subclass = 'other'))
231231
}
232232
if (!is.na(ttl) && grepl('\\batac\\b|\\bdnase\\b|\\bfaire\\b|\\bmnase\\b|\\bchip\\b|\\bcut tag\\b|\\bcutandtag\\b|\\bcut run\\b|\\bcutandrun\\b', ttl)) {
233233
if (grepl('\\bcut tag\\b|\\bcutandtag\\b', ttl)) return(list(class = 'epigenomic', subclass = 'CUT&Tag'))
@@ -239,14 +239,14 @@ title_raw = NA_character_) {
239239
if (grepl('\\bchip\\b', ttl)) return(list(class = 'epigenomic', subclass = 'ChIP-seq'))
240240
}
241241
if (!is.na(ttl) && grepl('\\bbisulfite\\b|\\bwgbs\\b|\\brrbs\\b|\\bmethyl\\b', ttl)) {
242-
return(list(class = 'epigenomic', subclass = 'Bisulfite-seq'))
242+
return(list(class = 'epigenomic', subclass = 'bisulfite-seq'))
243243
}
244244
if (!is.na(src) && grepl('\\bchromatin\\b|\\bchromosome conformation\\b|\\bconformation\\b', src)) {
245245
if (!is.na(ttl) && grepl('\\bhi c\\b|\\bhic\\b', ttl)) return(list(class = 'chromatin', subclass = 'Hi-C'))
246246
if (!is.na(ttl) && grepl('\\bchia pet\\b', ttl)) return(list(class = 'chromatin', subclass = 'ChIA-PET'))
247247
if (!is.na(ttl) && grepl('\\btcc\\b', ttl)) return(list(class = 'chromatin', subclass = 'TCC'))
248248
if (!is.na(ttl) && grepl('\\b3c\\b|\\b4c\\b|\\b5c\\b|\\bcapture c\\b|\\bpromoter capture\\b|\\bhichip\\b|\\bplac\\b', ttl)) return(list(class = 'chromatin', subclass = '3C-based'))
249-
return(list(class = 'chromatin', subclass = 'Other'))
249+
return(list(class = 'chromatin', subclass = 'other'))
250250
}
251251
if (!is.na(ttl) && grepl('\\bhi c\\b|\\bhic\\b|\\bchia pet\\b|\\btcc\\b|\\b3c\\b|\\b4c\\b|\\b5c\\b|\\bcapture c\\b|\\bhichip\\b|\\bplac\\b|\\bpromoter capture\\b', ttl)) {
252252
if (grepl('\\bhi c\\b|\\bhic\\b', ttl)) return(list(class = 'chromatin', subclass = 'Hi-C'))
@@ -255,9 +255,9 @@ title_raw = NA_character_) {
255255
return(list(class = 'chromatin', subclass = '3C-based'))
256256
}
257257
if (.is_unknown(strategy_raw) || .is_unknown(strategy_norm) || .is_other_strategy(strategy_norm)) {
258-
return(list(class = 'unknown', subclass = 'Unknown'))
258+
return(list(class = 'unknown', subclass = 'unknown'))
259259
}
260-
list(class = 'other', subclass = 'Other')
260+
list(class = 'other', subclass = 'other')
261261
}
262262

263263
.ONTOLOGY <- list(
@@ -276,7 +276,7 @@ title_raw = NA_character_) {
276276
'genome sequencing',
277277
'genomic sequencing'
278278
),
279-
`Amplicon-seq` = c(
279+
`amplicon-seq` = c(
280280
'amplicon',
281281
'amplicon seq',
282282
'amplicon sequencing',
@@ -304,7 +304,7 @@ title_raw = NA_character_) {
304304
'genotyping by sequencing',
305305
'genotyping by seq'
306306
),
307-
`Targeted-Capture` = c(
307+
`targeted-capture` = c(
308308
'targeted capture',
309309
'targeted sequencing',
310310
'targeted seq',
@@ -320,7 +320,7 @@ title_raw = NA_character_) {
320320
'panel sequencing',
321321
'gene panel'
322322
),
323-
`Clone-based` = c(
323+
`clone-based` = c(
324324
'clone',
325325
'cloneend',
326326
'poolclone',
@@ -391,7 +391,7 @@ title_raw = NA_character_) {
391391
'sirna seq',
392392
'pirna seq'
393393
),
394-
`Long-read` = c(
394+
`long-read` = c(
395395
'iso seq',
396396
'isoseq',
397397
'direct rna seq',
@@ -402,7 +402,7 @@ title_raw = NA_character_) {
402402
)
403403
),
404404
epigenomic = list(
405-
`Bisulfite-seq` = c(
405+
`bisulfite-seq` = c(
406406
'bisulfite seq',
407407
'mbd seq',
408408
'medip seq',
@@ -524,7 +524,7 @@ title_raw = NA_character_) {
524524
)
525525
),
526526
other = list(
527-
`Other` = c(
527+
`other` = c(
528528
'custom',
529529
'custom sequencing',
530530
'custom protocol',
@@ -624,12 +624,12 @@ title_raw = NA_character_) {
624624
if (!is.null(rescue$class) && rescue$class %in% c('genomic', 'transcriptomic', 'epigenomic', 'chromatin')) {
625625
cls <- rescue
626626
} else if (.is_unknown(strategy_raw) || .is_unknown(strategy_norm) || .is_other_strategy(strategy_norm)) {
627-
cls <- list(class = 'unknown', subclass = 'Unknown')
627+
cls <- list(class = 'unknown', subclass = 'unknown')
628628
}
629629
}
630630
}
631631
if (cls$class == 'other' && (.is_unknown(strategy_raw) || .is_unknown(strategy_norm))) {
632-
cls <- list(class = 'unknown', subclass = 'Unknown')
632+
cls <- list(class = 'unknown', subclass = 'unknown')
633633
}
634634
sra_ids <- .extract_sra_ids(x)
635635
geo <- .extract_geo_accessions(x$expxml)

R/Helpers.R

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# HELPERS =====================================================================
22

3-
.GAMA_VERSION <- '0.2.7'
3+
.GAMA_VERSION <- '0.2.8'
44

55
# NCBI configuration
66

@@ -372,7 +372,93 @@ utils::globalVariables(c(
372372
stop(.gama_prefix(), paste0(..., collapse = ''), call. = call.)
373373
}
374374

375-
# Object identity and validation
375+
# Argument validation
376+
377+
.gama_choice_key <- function(x) {
378+
x <- trimws(as.character(x))
379+
x <- tolower(x)
380+
gsub('[^a-z0-9]+', '', x)
381+
}
382+
383+
.gama_format_values <- function(x) {
384+
paste0("'", x, "'", collapse = ', ')
385+
}
386+
387+
.gama_suggest_choice <- function(x, choices) {
388+
choices <- unique(as.character(choices))
389+
x_key <- .gama_choice_key(x)
390+
choice_keys <- .gama_choice_key(choices)
391+
normalised_match <- choices[choice_keys == x_key]
392+
if (length(normalised_match) == 1L) return(normalised_match)
393+
d <- as.integer(utils::adist(x_key, choice_keys))
394+
best <- min(d)
395+
if (best > 2L) return(NA_character_)
396+
fuzzy_match <- choices[d == best]
397+
if (length(fuzzy_match) == 1L) fuzzy_match else NA_character_
398+
}
399+
400+
.gama_format_suggestions <- function(invalid, suggestions, pairs = length(invalid) > 1L) {
401+
suggestions <- unname(suggestions)
402+
if (!isTRUE(pairs)) return(.gama_format_values(suggestions))
403+
paste0("'", invalid, "' -> '", suggestions, "'", collapse = '; ')
404+
}
405+
406+
.gama_validate_choices <- function(x, arg, choices, multiple = TRUE, allow_null = TRUE) {
407+
if (is.null(x)) {
408+
if (isTRUE(allow_null)) return(invisible(NULL))
409+
.gama_stop('`', arg, '` must be a single value.')
410+
}
411+
if (!is.character(x)) .gama_stop('`', arg, '` must be a character vector or NULL.')
412+
if (!multiple && length(x) != 1L) .gama_stop('`', arg, '` must be a single value or NULL.')
413+
if (any(is.na(x) | !nzchar(trimws(x)))) .gama_stop('`', arg, '` cannot contain missing or empty values.')
414+
choices <- unique(as.character(choices))
415+
invalid <- setdiff(unique(x), choices)
416+
if (!length(invalid)) return(x)
417+
suggestions <- vapply(
418+
invalid,
419+
.gama_suggest_choice,
420+
choices = choices,
421+
FUN.VALUE = character(1)
422+
)
423+
has_suggestion <- !is.na(suggestions) & nzchar(suggestions)
424+
if (all(has_suggestion)) {
425+
msg <- paste0(
426+
'Invalid `',
427+
arg,
428+
'` parameter',
429+
if (length(invalid) > 1L) 's' else '',
430+
': ',
431+
.gama_format_values(invalid),
432+
'. Did you mean ',
433+
.gama_format_suggestions(invalid, suggestions),
434+
'?'
435+
)
436+
.gama_stop(msg)
437+
}
438+
no_suggestion <- invalid[!has_suggestion]
439+
msg <- paste0(
440+
'Invalid `',
441+
arg,
442+
'` parameter',
443+
if (length(no_suggestion) > 1L) 's' else '',
444+
': ',
445+
.gama_format_values(no_suggestion),
446+
'. Accepted values are: ',
447+
.gama_format_values(choices),
448+
'.'
449+
)
450+
if (any(has_suggestion)) {
451+
msg <- paste0(
452+
msg,
453+
' Did you mean ',
454+
.gama_format_suggestions(invalid[has_suggestion], suggestions[has_suggestion], pairs = TRUE),
455+
'?'
456+
)
457+
}
458+
.gama_stop(msg)
459+
}
460+
461+
# Object validation
376462

377463
.set_gama_object <- function(x, object_name) {
378464
attr(x, 'gama_object') <- object_name

0 commit comments

Comments
 (0)