Skip to content

Commit 0b9b80f

Browse files
authored
Fix PhyDatToMatrix crash on zero-character phyDat (#261)
PhyDatToMatrix() crashed when given a phyDat with nr=0 (e.g. from a star tree) because matrix() could not reconcile empty data with non-empty dimnames. Add an early return for the nr=0 case, returning a 0-column matrix with correct row names. This also fixes AddUnconstrained() when passed such a phyDat, since it delegates to PhyDatToMatrix() internally.
1 parent 86eed2a commit 0b9b80f

File tree

4 files changed

+32
-1
lines changed

4 files changed

+32
-1
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: TreeTools
22
Title: Create, Modify and Analyse Phylogenetic Trees
3-
Version: 2.1.0.9007
3+
Version: 2.1.0.9008
44
Authors@R: c(
55
person("Martin R.", 'Smith', role = c("aut", "cre", "cph"),
66
email = "martin.smith@durham.ac.uk",

NEWS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# TreeTools 2.1.0.9008 (2026-03-17) #
2+
3+
- `PhyDatToMatrix()` no longer crashes on zero-character `phyDat` objects
4+
(e.g. from a star tree); returns a 0-column matrix with correct row names.
5+
- `AddUnconstrained()` handles zero-character `phyDat` input gracefully.
6+
17
# TreeTools 2.1.0.9007 (2026-03-13) #
28

39
- `duplicated.Splits()` uses hash-based O(n) de-duplication, replacing

R/parse_files.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,10 @@ PhyDatToMatrix <- function(dataset, ambigNA = FALSE, inappNA = ambigNA,
809809
}
810810

811811
at <- attributes(dataset)
812+
if (at[["nr"]] == 0L) {
813+
return(matrix(character(0), nrow = length(at[["names"]]), ncol = 0,
814+
dimnames = list(at[["names"]], NULL)))
815+
}
812816
allLevels <- as.character(at[["allLevels"]])
813817
if (inappNA) {
814818
allLevels[allLevels == "-"] <- NA_character_

tests/testthat/test-ImposeConstraint.R

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
test_that("AddUnconstrained() handles zero-character phyDat", {
2+
star <- ape::read.tree(text = "(a,b,c,d);")
3+
empty_pd <- MatrixToPhyDat(t(as.matrix(star)))
4+
5+
# PhyDatToMatrix returns a correctly-dimensioned 0-column matrix
6+
mat <- PhyDatToMatrix(empty_pd)
7+
expect_equal(dim(mat), c(4L, 0L))
8+
expect_equal(rownames(mat), c("a", "b", "c", "d"))
9+
10+
# AddUnconstrained returns 0-character phyDat with extra taxa
11+
result <- AddUnconstrained(empty_pd, c("e", "f", "g"))
12+
expect_s3_class(result, "phyDat")
13+
expect_equal(names(result), c("a", "b", "c", "d", "e", "f", "g"))
14+
expect_equal(attr(result, "nr"), 0L)
15+
16+
# asPhyDat = FALSE returns a 0-column matrix
17+
result_mat <- AddUnconstrained(empty_pd, c("e", "f", "g"), asPhyDat = FALSE)
18+
expect_equal(dim(result_mat), c(7L, 0L))
19+
expect_equal(rownames(result_mat), c("a", "b", "c", "d", "e", "f", "g"))
20+
})
21+
122
test_that("AddUnconstrained() works", {
223
tips <- letters[1:9]
324
constraint <- StringToPhyDat("0000?1111 000111111 0000??110", tips, FALSE)

0 commit comments

Comments
 (0)