tests/testthat/test-msn.R

ucl <- function(x){
  unclass(x$graph)[-10]
}

set.seed(9005)

gend <- new("genind"
           , tab = structure(c(1L, 1L, 0L, 0L, 
                               1L, 1L, 2L, 2L,
                               0L, 1L, 1L, 0L, 
                               2L, 1L, 1L, 2L), 
              .Dim = c(4L, 4L), 
              .Dimnames = list(c("1", "2", "3", "4"), 
                               c("loc-1.1", "loc-1.2", "loc-2.1", "loc-2.2")))
           , loc.names = structure(c("loc-1", "loc-2"), .Names = c("loc-1", "loc-2"))
           , loc.fac = structure(c(1L, 1L, 2L, 2L), .Label = c("loc-1", "loc-2"), class = "factor")
           , loc.nall = structure(c(2L, 2L), .Names = c("loc-1", "loc-2"))
           , all.names = structure(list(`loc-1` = structure(c("3", "4"), .Names = c("1", "2"
           )), `loc-2` = structure(c("3", "4"), .Names = c("1", "2"))), .Names = c("loc-1",
                                                                              "loc-2"))
           , call = NULL
           , ind.names = structure(c("", "", "", ""), .Names = c("1", "2", "3", "4"))
           , pop = structure(1:4, .Label = c("1", "2", "3", "4"), class = "factor")
           , pop.names = structure(c("1", "2", "3", "4"))
           , ploidy = 2L
           , type = "codom"
           , other = NULL
)

gend_gc          <- as.genclone(gend)
gend_bruvo       <- bruvo.dist(gend, replen = c(1, 1))
gend_single      <- gend
pop(gend_single) <- rep("A", 4)

#' Identical population and color fields
#'
#' @param g1 graph 1
#' @param g2 graph 2
#'
#' @noRd
expect_identical_metadata <- function(g1, g2){
  eval(bquote(expect_identical(.(g1[-1]), .(g2[-1]))))
}

#' Vertex counts
#'
#' @param g a graph
#' @param n an integer equal to the number of vertices in the graph
#'
#' @noRd
expect_vcount <- function(g, n){
  eval(bquote(expect_equal(igraph::vcount(.(g$graph)), .(n))))
}

#' Edge counts
#'
#' @param g a graph
#' @param n an integer equal to the number of edges in the graph
#'
#' @noRd
expect_ecount <- function(g, n){
  eval(bquote(expect_equal(igraph::ecount(.(g$graph)), .(n))))
}

#' Identical attributes
#'
#' @param g1 graph 1
#' @param g2 graph 2
#' @param a  a character specifying which attribute to test
#'
#' @noRd
expect_identical_vertex_attr <- function(g1, g2, a){
  eval(bquote(expect_identical(igraph::vertex_attr(.(g1)$graph, .(a)), 
                               igraph::vertex_attr(.(g2)$graph, .(a))
  )
  ))
}

#' Identical attributes
#'
#' @param g1 graph 1
#' @param g2 graph 2
#' @param a  a character specifying which attribute to test
#'
#' @noRd
expect_identical_edge_attr <- function(g1, g2, a){
  eval(bquote(expect_identical(igraph::edge_attr(.(g1)$graph, .(a)), 
                               igraph::edge_attr(.(g2)$graph, .(a))
  )
  ))
}

#' Attribute names
#'
#' @param g a graph
#' @param a a character vector specifying all the named attributes
#'
#' @noRd
expect_vertex_attr <- function(g, a){
  eval(bquote(expect_equal(igraph::vertex_attr_names(.(g$graph)), .(a))))
}


#' Testing distance tables
#'
#' @param g a graph
#' @param d a tabulaton of the distances between nodes. For example, a graph
#'   with four nodes connected in a line would have 3:1, indicating that there
#'   are three pairs that can be reached with one step, two with two steps, and
#'   one pair needs three steps.
#'
#' @noRd
expect_distance_table <- function(g, d){
  eval(bquote(expect_equal(igraph::distance_table(.(g$graph))$res, .(d))))
}

bruv_no_ties  <- bruvo.msn(gend, replen = c(1,1), showplot = FALSE)
bruv_ties     <- bruvo.msn(gend, replen = c(1,1), showplot = FALSE, include.ties = TRUE)
pmsn_no_ties  <- poppr.msn(gend, distmat = gend_bruvo, showplot = FALSE)
pmsn_ties     <- poppr.msn(gend, distmat = gend_bruvo, showplot = FALSE, include.ties = TRUE)
sbruv_no_ties <- bruvo.msn(gend_single, replen = c(1,1), showplot = FALSE)
sbruv_ties    <- bruvo.msn(gend_single, replen = c(1,1), showplot = FALSE, include.ties = TRUE)
spmsn_no_ties <- poppr.msn(gend_single, distmat = gend_bruvo, showplot = FALSE)
spmsn_ties    <- poppr.msn(gend_single, distmat = gend_bruvo, showplot = FALSE, include.ties = TRUE)
pienames      <- c("name", "size", "shape", "pie", "pie.color", "color", "label")
nopienames    <- c("name", "size", "color", "label")

context("Input parameter tests")

test_that("{poppr,bruvo}.msn needs a genind object to work", {
  expect_error(poppr.msn(1:10), "must be a genind")
  expect_error(bruvo.msn(1:10), "must be a genind")
})


test_that("distance matrix must be valid", {
  expect_error(poppr.msn(gend, distmat = 1:10),
               "The distance matrix is neither a dist object nor a matrix.")
  expect_error(poppr.msn(gend, distmat = as.matrix(gend_bruvo)[-1, ]), 
               "The size of the distance matrix does not match the size of the data.")
})

context("Tied MSN edge tests")

test_that("bruvo.msn can properly account for tied edges", {
  # metadata are equal
  expect_identical_metadata(bruv_no_ties, bruv_ties)
  
  # There will be four tied edges, but only 3 untied.
  expect_ecount(bruv_no_ties, 3L)
  expect_ecount(bruv_ties, 4L)
  
  # vertex attributes come with pie
  expect_vertex_attr(bruv_no_ties, pienames)
  expect_vertex_attr(bruv_ties, pienames)
  
  # both graphs will have the same number of vertices
  expect_vcount(bruv_no_ties, 4L)
  expect_vcount(bruv_ties, 4L)
  
  # Adding a loop will shrink the distance between nodes 1 and 4
  expect_distance_table(bruv_no_ties, 3:1)
  expect_distance_table(bruv_ties, c(4, 2))
})

test_that("poppr.msn can properly account for tied edges", {
  # metadata are equal
  expect_identical_metadata(pmsn_no_ties, pmsn_ties)
  
  # There will be four tied edges, but only 3 untied.
  expect_ecount(pmsn_no_ties, 3L)
  expect_ecount(pmsn_ties, 4L)
  
  # vertex attributes come with pie
  expect_vertex_attr(pmsn_no_ties, pienames)
  expect_vertex_attr(pmsn_ties, pienames)
  
  # both graphs will have the same number of vertices
  expect_vcount(pmsn_no_ties, 4L)
  expect_vcount(pmsn_ties, 4L)
  
  # Adding a loop will shrink the distance between nodes 1 and 4
  expect_distance_table(pmsn_no_ties, 3:1)
  expect_distance_table(pmsn_ties, c(4, 2))
})

test_that("bruvo.msn can work with single populations", {
  # metadata are equal
  expect_identical_metadata(sbruv_no_ties, sbruv_ties)
  
  # There will be four tied edges, but only 3 untied.
  expect_ecount(sbruv_no_ties, 3L)
  expect_ecount(sbruv_ties, 4L)
  
  # both graphs will have the same number of vertices
  expect_vcount(sbruv_no_ties, 4L)
  expect_vcount(sbruv_ties, 4L)
  
  # vertex attributes don't come with pie :(
  expect_vertex_attr(sbruv_no_ties, nopienames)
  expect_vertex_attr(sbruv_ties, nopienames)
  
  # Adding a loop will shrink the distance between nodes 1 and 4
  expect_distance_table(sbruv_no_ties, 3:1)
  expect_distance_table(sbruv_ties, c(4, 2))
})

test_that("poppr.msn can work with single populations", {
  # metadata are equal
  expect_identical_metadata(spmsn_no_ties, spmsn_ties)
  
  # There will be four tied edges, but only 3 untied.
  expect_ecount(spmsn_no_ties, 3L)
  expect_ecount(spmsn_ties, 4L)
  
  # vertex attributes don't come with pie :(
  expect_vertex_attr(spmsn_no_ties, nopienames)
  expect_vertex_attr(spmsn_ties, nopienames)
  
  # both graphs will have the same number of vertices
  expect_vcount(spmsn_no_ties, 4L)
  expect_vcount(spmsn_ties, 4L)
  
  # Adding a loop will shrink the distance between nodes 1 and 4
  expect_distance_table(spmsn_no_ties, 3:1)
  expect_distance_table(spmsn_ties, c(4, 2))
})

context("plot_poppr_msn tests")

test_that("plot_poppr_msn needs a genind object up front", {
  skip_on_cran()
  expect_error(plot_poppr_msn(pmsn_ties, gend), "pmsn_ties is not a genind")
})

test_that("plot_poppr_msn for some reason needs the silly listgraph", {
  skip_on_cran()
  expect_error(plot_poppr_msn(gend, pmsn_ties$graph), "graph not compatible")
})


test_that("the user can label specific nodes (UX)", {
  skip_on_cran()
  # Note: this test can really only test that this feature doesn't cause the 
  # function to break
  x <- plot_poppr_msn(gend, pmsn_ties, nodescale = 40, inds = 4)
  expect_identical(ucl(x), ucl(pmsn_ties))
  x <- plot_poppr_msn(gend, pmsn_ties, nodescale = 40, inds = "4")
  expect_identical(ucl(x), ucl(pmsn_ties))
})

test_that("plot_poppr_msn can use layouts", {
  skip_on_cran()
  x <- plot_poppr_msn(gend, pmsn_ties, layfun = igraph::layout_as_tree)
  expect_identical(ucl(x), ucl(pmsn_ties))
})

test_that("plot_poppr_msn will label MLGs (UX)", {
  skip_on_cran()
  x <- plot_poppr_msn(gend, pmsn_ties, mlg = TRUE)
  expect_identical(ucl(x), ucl(pmsn_ties))
})

test_that("plot_poppr_msn will not take the quantiles for the legend (UX)", {
  skip_on_cran()
  x <- plot_poppr_msn(gend, pmsn_ties, quantiles = FALSE)
  expect_identical(ucl(x), ucl(pmsn_ties))
})

test_that("plot_poppr_msn can plot without legends (UX)", {
  skip_on_cran()
  x <- plot_poppr_msn(gend, pmsn_ties, pop.leg = FALSE, size.leg = FALSE, scale.leg = FALSE)
  expect_identical(ucl(x), ucl(pmsn_ties))
  x <- plot_poppr_msn(gend, pmsn_ties, pop.leg = TRUE, size.leg = FALSE, scale.leg = FALSE)
  expect_identical(ucl(x), ucl(pmsn_ties))
  x <- plot_poppr_msn(gend, pmsn_ties, pop.leg = FALSE, size.leg = TRUE, scale.leg = FALSE)
  expect_identical(ucl(x), ucl(pmsn_ties))
  x <- plot_poppr_msn(gend, pmsn_ties, pop.leg = TRUE, size.leg = TRUE, scale.leg = FALSE)
  expect_identical(ucl(x), ucl(pmsn_ties))
  x <- plot_poppr_msn(gend, pmsn_ties, pop.leg = FALSE, size.leg = FALSE, scale.leg = TRUE)
  expect_identical(ucl(x), ucl(pmsn_ties))
  x <- plot_poppr_msn(gend, pmsn_ties, pop.leg = TRUE, size.leg = FALSE, scale.leg = TRUE)
  expect_identical(ucl(x), ucl(pmsn_ties))
  x <- plot_poppr_msn(gend, pmsn_ties, pop.leg = FALSE, size.leg = TRUE, scale.leg = TRUE)
  expect_identical(ucl(x), ucl(pmsn_ties))
  x <- plot_poppr_msn(gend, pmsn_ties, pop.leg = TRUE, size.leg = TRUE, scale.leg = TRUE)
  expect_identical(ucl(x), ucl(pmsn_ties))
})

test_that("plot_poppr_msn throws a warning if the user tries nodebase", {
  skip_on_cran()
  expect_warning(plot_poppr_msn(gend, pmsn_ties, nodebase = 1.15), 
                 "Please use.+nodescale")
  expect_warning(plot_poppr_msn(gend, pmsn_ties, nodebase = 1), 
                 "reverting to nodebase = 1.15")
})

test_that("edges can be deleted", {
  skip_on_cran()
  graph_to_trim <- pmsn_ties
  graph_to_trim$graph <- igraph::set_edge_attr(pmsn_ties$graph, "weight", 4, 0.5)
  x <- plot_poppr_msn(gend, graph_to_trim, cutoff = 0.25)
  expect_ecount(graph_to_trim, 4L)
  expect_ecount(x, 3L)
  
  # warning if the cutoff is too low
  expect_warning(plot_poppr_msn(gend, pmsn_ties, cutoff = 0.01), 
                 "Cutoff value \\(0.01\\) is below the minimum observed")
})

context("MSN and collapsed MLG tests")

gmsnt <- bruvo.msn(gend, replen = c(1, 1), threshold = 0.15)

test_that("Minimum spanning networks also collapse MLGs", {
  skip_on_cran()
  gend        <- as.genclone(gend)
  gend_single <- as.genclone(gend_single)
  
  # Adding the filter for testing
  mlg.filter(gend, dist = bruvo.dist, replen = c(1, 1)) <- 0.15
  mll(gend) <- "original"
  
  expect_vcount(gmsnt, 2)

  pgmsnt <- poppr.msn(gend, distmat = gend_bruvo, threshold = 0.15)
  mll(gend) <- "contracted"
  gmsnot  <- bruvo.msn(gend, replen = c(1, 1)) # no threshold supplied
  gmsnone <- bruvo.msn(gend, replen = c(1, 1), threshold = 0.3)
  expect_vcount(gmsnone, 1)
  gmsnall  <- bruvo.msn(gend, replen = c(1, 1), threshold = 0)
  expect_vcount(gmsnall, 4)

  expect_identical_vertex_attr(gmsnt, pgmsnt, "pie")
  expect_identical_vertex_attr(gmsnot, pgmsnt, "pie")
  
  expect_identical_vertex_attr(gmsnt, pgmsnt, "name")
  expect_identical_vertex_attr(gmsnot, pgmsnt, "name")
  
  expect_identical_edge_attr(gmsnt, pgmsnt, "weight")
  expect_identical_edge_attr(gmsnot, pgmsnt, "weight")
  
  mll(gend) <- "original"
  gmsn   <- bruvo.msn(gend, replen = c(1, 1), showplot = FALSE)
  expect_vcount(gmsn, 4)
  pgmsn  <- poppr.msn(gend, distmat = gend_bruvo, showplot = FALSE)

  expect_identical_vertex_attr(gmsn, pgmsn, "pie")
  expect_identical_vertex_attr(gmsn, gmsnall, "pie")
  
  expect_identical_vertex_attr(gmsn, pgmsn, "name")
  expect_identical_vertex_attr(gmsn, gmsnall, "name")
  
  expect_identical_edge_attr(gmsn, pgmsn, "weight")
  expect_identical_edge_attr(gmsn, gmsnall, "weight")
  
})

test_that("Minimum spanning networks can collapse MLGs with single populations", {
  skip_on_cran()
  sgmsnt  <- bruvo.msn(gend_single, replen = c(1, 1), threshold = 0.15)
  psgmsnt <- poppr.msn(gend_single, distmat = gend_bruvo, threshold = 0.15)

  expect_identical_vertex_attr(sgmsnt, psgmsnt, "pie")
  expect_identical_vertex_attr(sgmsnt, psgmsnt, "name")
  expect_identical_edge_attr(sgmsnt, psgmsnt, "weight")
  
  sgmsn   <- bruvo.msn(gend_single, replen = c(1, 1), showplot = FALSE)
  psgmsn  <- poppr.msn(gend_single, distmat = gend_bruvo, showplot = FALSE)

  expect_identical_vertex_attr(sgmsn, psgmsn, "pie")
  expect_identical_vertex_attr(sgmsn, psgmsn, "name")
  expect_identical_edge_attr(sgmsn, psgmsn, "weight")

  expect_vcount(sgmsnt, 2)
  expect_vcount(sgmsn, 4)

  expect_output(plot_poppr_msn(gend, gmsnt, palette = "cm.colors"), NA)
  expect_output(plot_poppr_msn(gend_single, sgmsnt, palette = "cm.colors"), NA)
})


test_that("Filtered minimum spanning networks retain original names", {
  skip_on_cran()
  # setup ----------------------------------------------------
  grid_example <- matrix(c(1, 4,
                           1, 1,
                           5, 1,
                           9, 1,
                           9, 4), 
                         ncol = 2,
                         byrow = TRUE)
  rownames(grid_example) <- LETTERS[1:5]
  colnames(grid_example) <- c("x", "y")
  grid_new <- rbind(grid_example, 
                    new = c(5, NA), 
                    mut = c(5, 2)
                    )
  x <- as.genclone(df2genind(grid_new, ploidy = 1))
  indNames(x)
  ## [1] "A"   "B"   "C"   "D"   "E"   "new" "mut"
  
  raw_dist <- function(x){
    dist(genind2df(x, usepop = FALSE))
  }
  (xdis <- raw_dist(x))
  
  # normal ---------------------------------------------------
  set.seed(9001)
  g1 <- poppr.msn(x, xdis, include.ties = TRUE, 
                  vertex.label.color = "firebrick", vertex.label.font = 2)
  all_names <- igraph::V(g1$graph)$name
  ## [1] "A"   "B"   "C"   "D"   "E"   "new" "mut"
  
  # filtered ---------------------------------------------------
  set.seed(9001)
  g1.1 <- poppr.msn(x, xdis, threshold = 1, include.ties = TRUE, 
                  vertex.label.color = "firebrick", vertex.label.font = 2)
  cc_names <- igraph::V(g1.1$graph)$name
  ## [1] "A"   "B"   "C"   "D"   "E"   "new"
  expect_identical(cc_names, head(all_names, -1))
})

context("minimum spanning network subset populations")

data("partial_clone")
pc <- as.genclone(partial_clone)
bpc  <- bruvo.dist(pc, replen = rep(1, 10))
bmsn <- bruvo.msn(pc, replen = rep(1, 10), showplot = FALSE)
pmsn <- poppr.msn(pc, bpc, showplot = FALSE)

test_that("a warning is thrown if there are no populations to subset", {
  skip_on_cran()
  pc2 <- pc
  pop(pc2) <- NULL
  expect_warning(poppr.msn(pc2, dist(pc), showplot = FALSE, sublist = 1), 
                 "Subsetting not taking place")
  expect_warning(bruvo.msn(pc2, replen = rep(1, 10), showplot = FALSE, sublist = 1),
                 "Subsetting not taking place")
})

test_that("Minimum spanning networks can subset populations", {
  
  expect_identical(ucl(bmsn), ucl(pmsn))
  
  bmsn12 <- bruvo.msn(pc, replen = rep(1, 10), sublist = 1:2, showplot = FALSE)
  pmsn12 <- poppr.msn(pc, bpc, sublist = 1:2, showplot = FALSE)
  expect_identical(ucl(bmsn12), ucl(pmsn12))

  bmsn1 <- bruvo.msn(pc, replen = rep(1, 10), sublist = 1, showplot = FALSE)
  pmsn1 <- poppr.msn(pc, bpc, sublist = 1, showplot = FALSE)
  expect_identical(ucl(bmsn1), ucl(pmsn1))
  
})

context("custom MLLs and minimum spanning networks")

mll.custom(pc) <- LETTERS[mll(pc)]
mll.levels(pc)[mll.levels(pc) == "Q"] <- "M"
mll(pc) <- "custom"

test_that("msn works with custom MLLs", {
  skip_on_cran()
  expect_error(pcmsn <- bruvo.msn(pc, replen = rep(1, 10)), NA)
  expect_equivalent(sort(unique(igraph::V(pcmsn$graph)$label)), sort(mll.levels(pc)))
  expect_error(plot_poppr_msn(pc, pcmsn), NA)
  expect_error(plot_poppr_msn(pc, pcmsn, mlg = TRUE), NA)
})

context("Minimum spanning network aesthetics")

test_that("vectors can be used to color graphs", {
  skip_on_cran()
  data(Aeut)
  A.dist <- diss.dist(Aeut)
  
  # Graph it.
  A.msn <- poppr.msn(Aeut, A.dist, gadj=15, vertex.label=NA, showplot = FALSE)
  unpal <- c("black", "orange")
  fpal  <- function(x) unpal
  npal  <- setNames(unpal, c("Athena", "Mt. Vernon"))
  xpal  <- c(npal, JoMo = "awesome")
  # Using palette without names
  uname_pal  <- plot_poppr_msn(Aeut, A.msn, palette = unpal)$colors
  # Using palette with function
  fun_pal    <- plot_poppr_msn(Aeut, A.msn, palette = fpal)$colors
  # Using palette with names
  name_pal   <- plot_poppr_msn(Aeut, A.msn, palette = npal[2:1])$colors
  # Using palette with extra names
  xname_pal  <- plot_poppr_msn(Aeut, A.msn, palette = xpal)$colors
  
  expect_identical(uname_pal, npal)
  expect_identical(fun_pal, npal)
  expect_identical(name_pal, npal)
  expect_identical(xname_pal, npal)
})
grunwaldlab/poppr documentation built on March 18, 2024, 11:24 p.m.