diff --git a/.Rbuildignore b/.Rbuildignore index c9361f7e..0ce310ee 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -15,3 +15,5 @@ travisbuildchildren.sh ^\.github$ ^depends.Rds$ ^codecov\.yml$ +^CODE_OF_CONDUCT\.md$ +^CRAN-SUBMISSION$ diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index ff3e797e..d5561cd9 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -1,15 +1,14 @@ -#on: push +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: - branches: - - main - - master + branches: [main, master] pull_request: - branches: - - main - - master + branches: [main, master] -name: R-CMD-check +name: R-CMD-check.yaml + +permissions: read-all jobs: R-CMD-check: @@ -21,71 +20,42 @@ jobs: fail-fast: false matrix: config: - #- {os: windows-latest, r: 'release', rglusenull: "true"} - - {os: macOS-latest, r: 'release', rglusenull: "true"} - - {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest", rglusenull: "true", codecov: "true"} - #- {os: ubuntu-20.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"} + - {os: macos-latest, r: 'release'} + - {os: windows-latest, r: 'release'} + - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} + - {os: ubuntu-latest, r: 'release', codecov: 'true'} + - {os: ubuntu-latest, r: 'oldrel-1'} env: - R_REMOTES_NO_ERRORS_FROM_WARNINGS: true - RSPM: ${{ matrix.config.rspm }} GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - RGL_USE_NULL: ${{ matrix.config.rglusenull }} + R_KEEP_PKG_SOURCE: yes + RGL_USE_NULL: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-pandoc@v2 - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} + http-user-agent: ${{ matrix.config.http-user-agent }} + use-public-rspm: true - - uses: r-lib/actions/setup-pandoc@v2 - - - name: Query dependencies - run: Rscript -e "install.packages('remotes')" -e "saveRDS(remotes::dev_package_deps(dependencies = TRUE), 'depends.Rds', version = 2)" - - - name: Cache R packages - if: runner.os != 'Windows' - uses: actions/cache@v1 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-r-${{ matrix.config.r }}-${{ hashFiles('depends.Rds') }} - restore-keys: ${{ runner.os }}-r-${{ matrix.config.r }}- - - - name: Install system dependencies - if: runner.os == 'Linux' - env: - RHUB_PLATFORM: linux-x86_64-ubuntu-gcc - run: | - Rscript -e "remotes::install_github('r-hub/sysreqs')" - sysreqs=$(Rscript -e "cat(sysreqs::sysreq_commands('DESCRIPTION'))") - sudo -s eval "$sysreqs" - - - name: Install Covr - run: Rscript -e "remotes::install_github('r-lib/covr')" + extra-packages: any::rcmdcheck, natverse/natcpp + needs: check - name: Build CMTK + if: ${{matrix.config.os != 'windows-latest'}} run: sh ./build-cmtk.sh env: + CC: clang + CXX: clang++ MAKEFLAGS: "-j2" - - name: Install dependencies - run: Rscript -e "library(remotes)" -e "update(readRDS('depends.Rds'))" -e "remotes::install_cran('rcmdcheck')" - - - name: Install manual dependencies - run: Rscript -e "remotes::install_github('natverse/natcpp')" - - - name: Check - run: Rscript -e "rcmdcheck::rcmdcheck(args = c('--no-manual', '--as-cran'), error_on = 'warning', check_dir = 'check')" - - - name: Upload check results - if: failure() - uses: actions/upload-artifact@v2 + - uses: r-lib/actions/check-r-package@v2 with: - name: ${{ runner.os }}-r${{ matrix.config.r }}-results - path: check - - - name: Test coverage - if: matrix.config.codecov - run: | - Rscript -e 'covr::codecov(token = "${{secrets.CODECOV_TOKEN}}")' + upload-snapshots: true + build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml new file mode 100644 index 00000000..0aef2381 --- /dev/null +++ b/.github/workflows/test-coverage.yaml @@ -0,0 +1,62 @@ +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples +# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +name: test-coverage.yaml + +permissions: read-all + +jobs: + test-coverage: + runs-on: ubuntu-latest + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + RGL_USE_NULL: true + + steps: + - uses: actions/checkout@v4 + + - uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + + - uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::covr, any::xml2 + needs: coverage + + - name: Test coverage + run: | + cov <- covr::package_coverage( + quiet = FALSE, + clean = FALSE, + install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") + ) + covr::to_cobertura(cov) + shell: Rscript {0} + + - uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }} + file: ./cobertura.xml + plugin: noop + disable_search: true + token: ${{ secrets.CODECOV_TOKEN }} + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package diff --git a/DESCRIPTION b/DESCRIPTION index ad6c02bf..ea0fc9c5 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -27,7 +27,7 @@ Depends: rgl (>= 0.98.1) Imports: nabor, - igraph (>= 0.7.1), + igraph (>= 1.0), methods, filehash (>= 2.3), digest, diff --git a/NAMESPACE b/NAMESPACE index fdc7683e..a48a203c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -114,6 +114,7 @@ S3method(ndigest,neuron) S3method(ndigest,neuronlistfh) S3method(nvertices,default) S3method(nvertices,dotprops) +S3method(nvertices,igraph) S3method(nvertices,neuron) S3method(nvertices,neuronlist) S3method(nvertices,shapelist3d) @@ -389,27 +390,26 @@ importFrom(digest,digest) importFrom(igraph,"V<-") importFrom(igraph,E) importFrom(igraph,V) -importFrom(igraph,add.edges) +importFrom(igraph,add_edges) importFrom(igraph,as.directed) importFrom(igraph,as.undirected) importFrom(igraph,as_edgelist) -importFrom(igraph,decompose.graph) +importFrom(igraph,bfs) +importFrom(igraph,decompose) importFrom(igraph,degree) importFrom(igraph,delete.vertices) +importFrom(igraph,dfs) importFrom(igraph,diameter) importFrom(igraph,distances) importFrom(igraph,get.diameter) -importFrom(igraph,get.shortest.paths) -importFrom(igraph,get.vertex.attribute) -importFrom(igraph,graph.bfs) -importFrom(igraph,graph.dfs) -importFrom(igraph,is.connected) -importFrom(igraph,is.directed) +importFrom(igraph,is_connected) +importFrom(igraph,is_directed) importFrom(igraph,make_empty_graph) importFrom(igraph,neighborhood) importFrom(igraph,set_edge_attr) -importFrom(igraph,shortest.paths) +importFrom(igraph,shortest_paths) importFrom(igraph,vcount) +importFrom(igraph,vertex_attr) importFrom(methods,is) importFrom(nabor,knn) importFrom(nat.utils,RunCmdForNewerInput) diff --git a/R/graph-nodes.R b/R/graph-nodes.R index 8778b3ab..b9d56cfc 100644 --- a/R/graph-nodes.R +++ b/R/graph-nodes.R @@ -13,7 +13,7 @@ #' available). Set to FALSE when this is not desired. #' @param exclude.isolated Do not count isolated vertices as root/end points #' (default) -#' @importFrom igraph V degree get.vertex.attribute +#' @importFrom igraph V degree vertex_attr #' @export #' @seealso \code{\link{rootpoints}}, \code{\link{ngraph}} #' @examples @@ -27,7 +27,7 @@ graph.nodes<-function(x, type=c('root','end','branch'), original.ids='name', exclude.isolated=TRUE){ type=match.arg(type) - if(type=='root' && !is.directed(x)) + if(type=='root' && !is_directed(x)) stop("Cannot establish root points for undirected graph") # root points are those without incoming edges @@ -42,7 +42,7 @@ graph.nodes<-function(x, type=c('root','end','branch'), original.ids='name', } if(is.character(original.ids)) - vertex_names=get.vertex.attribute(x, original.ids, index=vertex_idxs) + vertex_names=vertex_attr(x, original.ids, index=vertex_idxs) if(!is.character(original.ids) || is.null(vertex_names)) as.integer(vertex_idxs) else diff --git a/R/neuron.R b/R/neuron.R index 0caa709e..155f8c0f 100644 --- a/R/neuron.R +++ b/R/neuron.R @@ -67,7 +67,7 @@ #' #' # converting back and forth between neurons and graphs #' g=as.ngraph(Cell07PNs[[1]]) -#' gstem=igraph::induced.subgraph(g, 1:10) +#' gstem=igraph::induced_subgraph(g, 1:10) #' # this is fine #' plot(gstem) #' plot(as.neuron(gstem)) @@ -206,9 +206,9 @@ normalise_swc<-function(x, requiredColumns=c('PointNo','Label','X','Y','Z','W',' #' (NumPoints,StartPoint,BranchPoints,EndPoints,nTrees,NumSegs,SegList, #' [SubTrees]) NB SubTrees will only be present when nTrees>1. #' @export -#' @importFrom igraph V V<- vcount decompose.graph +#' @importFrom igraph V V<- vcount decompose #' @rdname neuron -#' @seealso \code{\link{graph.dfs}, \link{as.seglist}} +#' @seealso \code{\link{dfs}, \link{as.seglist}} as.neuron.ngraph<-function(x, vertexData=NULL, origin=NULL, Verbose=FALSE, ...){ # translate origin into raw vertex id if necessary if(length(origin)){ @@ -221,11 +221,11 @@ as.neuron.ngraph<-function(x, vertexData=NULL, origin=NULL, Verbose=FALSE, ...){ # save original vertex ids igraph::V(x)$vid=seq.int(igraph::vcount(x)) # check if we have multiple subgraphs - if(igraph::no.clusters(x)>1){ + if(igraph::count_components(x)>1){ if(!length(origin)){ # no origin specified, will pick the biggest subtree # decompose into list of subgraphs - gg=igraph::decompose.graph(x) + gg=igraph::decompose(x) # reorder by descending number of vertices gg=gg[order(sapply(gg,igraph::vcount), decreasing=TRUE)] subtrees=lapply(gg, as.seglist, Verbose=Verbose) @@ -233,15 +233,15 @@ as.neuron.ngraph<-function(x, vertexData=NULL, origin=NULL, Verbose=FALSE, ...){ masterg=gg[[1]] } else { # origin specified, subtree containing origin will be the master - cg=igraph::clusters(x) + cg=igraph::components(x) master_tree_num=cg$membership[origin] # make a master graph with the vertices from subgraph including origin - masterg=igraph::induced.subgraph(x, which(cg$membership==master_tree_num)) + masterg=igraph::induced_subgraph(x, which(cg$membership==master_tree_num)) # ... and then corresponding seglist sl=as.seglist(masterg, origin=origin) # now deal with remaining vertices - remainderg=igraph::induced.subgraph(x, which(cg$membership!=master_tree_num)) - gg=igraph::decompose.graph(remainderg) + remainderg=igraph::induced_subgraph(x, which(cg$membership!=master_tree_num)) + gg=igraph::decompose(remainderg) # reorder by descending number of vertices gg=gg[order(sapply(gg,igraph::vcount), decreasing=TRUE)] subtrees=c(list(sl),lapply(gg, as.seglist, Verbose=Verbose)) @@ -262,7 +262,7 @@ as.neuron.ngraph<-function(x, vertexData=NULL, origin=NULL, Verbose=FALSE, ...){ # sort out the vertex information # TODO refactor this into a separate function e.g. normalise.swc since # we need to do something similar in as.neuron.dataframe and seglist2swc etc - d=data.frame(PointNo=get.vertex.attribute(x,'name')) + d=data.frame(PointNo=vertex_attr(x,'name')) if(is.null(vertexData)){ # get vertex information from graph object xyz=xyzmatrix(x) @@ -290,7 +290,7 @@ as.neuron.ngraph<-function(x, vertexData=NULL, origin=NULL, Verbose=FALSE, ...){ d=seglist2swc(x=subtrees,d=d) d=normalise_swc(d) - n=list(d=d,NumPoints=igraph::vcount(masterg), + n=list(d=d,NumPoints=nvertices(masterg), StartPoint=StartPoint, BranchPoints=branchpoints(masterg, original.ids='vid'), EndPoints=endpoints(masterg, original.ids='vid'), @@ -776,7 +776,7 @@ smooth_segment_spline <- function(xyz, ...) { #' # now find the points downstream (distal) of that with respect to the root #' ng=as.ngraph(n) #' # use a depth first search -#' distal_points=igraph::graph.dfs(ng, root=n$AxonLHEP, unreachable=FALSE, +#' distal_points=igraph::dfs(ng, root=n$AxonLHEP, unreachable=FALSE, #' mode='out')$order #' distal_tree=subset(n, distal_points) #' plot(distal_tree, add=TRUE, col='red', lwd=2) @@ -945,7 +945,7 @@ simplify_neuron <- function(x, n=1, invert=FALSE, ...) { # there will be warnings because most branch points will not be reachable # from the selected leaf res=suppressWarnings( - igraph::get.shortest.paths(ng, from = farthest_leaf, + igraph::shortest_paths(ng, from = farthest_leaf, to = bps[bps_available], mode = "in", weights = NA)) pathlengths=sapply(res$vpath, length) @@ -973,7 +973,7 @@ simplify_neuron <- function(x, n=1, invert=FALSE, ...) { } leafpath <- function(ng, from, to) { - res=igraph::get.shortest.paths(ng,from = from,to = to,mode = "out", weights=NA) + res=igraph::shortest_paths(ng,from = from,to = to,mode = "out", weights=NA) as.integer(res$vpath[[1]]) } @@ -1169,7 +1169,7 @@ stitch_neurons_mst <- function(x, threshold = Inf, k=10L) { mod_graph <- igraph::add_edges(ng,edge_list,"weight"= weights) #Step 7: Find the minimum spanning tree of the new graph.. - mst <- igraph::minimum.spanning.tree(mod_graph) + mst <- igraph::mst(mod_graph) #Step 8: Find the new edges added by the mst.. new_edges <- igraph::difference(igraph::E(mst),igraph::E(masterng)) @@ -1208,7 +1208,7 @@ stitch_neurons_mst <- function(x, threshold = Inf, k=10L) { warning("The root node doesn't belong to the largest fragment") } - stitchedng=igraph::delete.vertices(stitchedng, verticestoprune) + stitchedng=igraph::delete_vertices(stitchedng, verticestoprune) #Step 11: Set the root of the stitched graph now.. stitchedneuron <- as.neuron(stitchedng, origin = master_root) @@ -1411,7 +1411,7 @@ distal_to <- function(x, node.idx=NULL, node.pointno=NULL, root.idx=NULL, g=as.directed.usingroot(gorig, root = root.idx) } - #Step3: For each node id, travese the graph from the given node using depth first search and return the visited + #Step3: For each node id, traverse the graph from the given node using depth first search and return the visited #nodes.. l=sapply(node.idx, dfs_traversal, g, simplify = FALSE) if(length(node.idx)==1) l[[1]] else l @@ -1419,7 +1419,8 @@ distal_to <- function(x, node.idx=NULL, node.pointno=NULL, root.idx=NULL, dfs_traversal <- function(x, g) { gdfs=igraph::dfs(g, root = x, unreachable = FALSE) - as.integer(gdfs$order)[!is.na(gdfs$order)] + # nb igraph 2.0 may change signalling for unreached nodes + as.integer(gdfs$order)[!(is.na(gdfs$order) | gdfs$order<1)] } diff --git a/R/ngraph.R b/R/ngraph.R index 0839d969..4e856d77 100644 --- a/R/ngraph.R +++ b/R/ngraph.R @@ -50,12 +50,12 @@ #' @param vertex.attributes,graph.attributes List of named attributes to be #' added to the graph. The elements of \code{vertex.attributes} must be #' vectors whose length is compatible with the number of elements in the -#' graph. See \code{\link[igraph]{set.vertex.attribute}} for details. +#' graph. See \code{\link[igraph]{set_vertex_attr}} for details. #' @return an \code{igraph} object with additional class \code{ngraph}, having a #' vertex for each entry in vertexnames, each vertex having a \code{label} #' attribute. All vertices are included whether connected or not. #' @family neuron -#' @seealso \code{\link{igraph}}, \code{\link[igraph]{set.vertex.attribute}}, +#' @seealso \code{\link{igraph}}, \code{\link[igraph]{set_vertex_attr}}, #' \code{\link{subset.neuron}} for example of graph-based manipulation of a #' neuron, \code{\link{plot3d.ngraph}} #' @export @@ -72,9 +72,9 @@ #' # find longest path across graph #' d=get.diameter(gw) #' # make a new neuron using the longest path -#' gw_spine=as.neuron(induced.subgraph(gw, d)) +#' gw_spine=as.neuron(induced_subgraph(gw, d)) #' # make a new neuron containing all nodes except those in longest path -#' gw_antispine=as.neuron(delete.vertices(gw, d)) +#' gw_antispine=as.neuron(delete_vertices(gw, d)) #' #' # note use of bounding box of original neuron to set plot axes #' plot(gw_spine, col='red', boundingbox=boundingbox(n)) @@ -110,10 +110,10 @@ ngraph<-function(el, vertexnames, xyz=NULL, diam=NULL, directed=TRUE, } if(!is.null(diam)) igraph::V(g)$diam=diam for(n in names(vertex.attributes)){ - g=igraph::set.vertex.attribute(g, name=n,value=vertex.attributes[[n]]) + g=igraph::set_vertex_attr(g, name=n,value=vertex.attributes[[n]]) } for(n in names(graph.attributes)){ - g=igraph::set.graph.attribute(g, name=n,value=graph.attributes[[n]]) + g=igraph::set_graph_attr(g, name=n,value=graph.attributes[[n]]) } class(g)=c("ngraph", class(g)) g @@ -159,10 +159,10 @@ as.ngraph.neuron<-function(x, directed=TRUE, method=c('swc','seglist'), ...){ #' @export as.ngraph.igraph<-function(x, directed=TRUE, root, mode=c('out','in'), ...){ if(inherits(x,'ngraph')) - if(igraph::is.directed(x)==directed) return(x) + if(igraph::is_directed(x)==directed) return(x) - if(igraph::is.directed(x) && !directed) x=as.undirected(x, ...) - else if(!igraph::is.directed(x) && directed) x=as.directed.usingroot(x, root, mode=mode, ...) + if(igraph::is_directed(x) && !directed) x=as.undirected(x, ...) + else if(!igraph::is_directed(x) && directed) x=as.directed.usingroot(x, root, mode=mode, ...) if(!inherits(x,'ngraph')){ class(x)=c("ngraph",class(x)) @@ -173,11 +173,11 @@ as.ngraph.igraph<-function(x, directed=TRUE, root, mode=c('out','in'), ...){ as.directed.usingroot<-function(g, root, mode=c('out','in')){ mode=match.arg(mode) # make a directed graph _keeping any attributes_ - if(!igraph::is.directed(g)) + if(!igraph::is_directed(g)) dg=igraph::as.directed(g, mode='arbitrary') else dg=g - dfs=igraph::graph.dfs(dg, root, unreachable=FALSE, dist=TRUE, mode='all') - el=igraph::get.edgelist(dg) + dfs=igraph::dfs(dg, root, unreachable=FALSE, dist=TRUE, mode='all') + el=igraph::as_edgelist(dg) connected_vertices=which(is.finite(dfs$order)) edges_to_check=which(el[,1]%in%connected_vertices) @@ -193,8 +193,8 @@ as.directed.usingroot<-function(g, root, mode=c('out','in')){ if(any(same_dist)) warning(sum(same_dist)," edges connect vertices that are the same distance from the root => cycles.") edges_to_flip <- edges_to_check[if(mode=='out') parent_further else parent_closer] - dg=igraph::delete.edges(dg,edges_to_flip) - dg=igraph::add.edges(dg,t(el[edges_to_flip,2:1])) + dg=igraph::delete_edges(dg,edges_to_flip) + dg=igraph::add_edges(dg,t(el[edges_to_flip,2:1])) dg } @@ -225,7 +225,7 @@ as.directed.usingroot<-function(g, root, mode=c('out','in')){ #' #' } #' @seealso \code{\link[igraph]{diameter}}, -#' \code{\link[igraph]{shortest.paths}}, \code{\link{prune_strahler}} for +#' \code{\link[igraph]{distances}}, \code{\link{prune_strahler}} for #' removing lower order branches from a neuron, \code{\link{prune}} for #' removing parts of a neuron by spatial criteria. #' @export @@ -247,7 +247,7 @@ as.directed.usingroot<-function(g, root, mode=c('out','in')){ #' plot3d(antispine, lwd=4, col='red') #' } #' -#' @importFrom igraph shortest.paths get.shortest.paths diameter get.diameter +#' @importFrom igraph distances shortest_paths diameter get.diameter #' delete.vertices #' @family neuron spine <- function(n, UseStartPoint=FALSE, SpatialWeights=TRUE, invert=FALSE, @@ -261,7 +261,7 @@ spine <- function(n, UseStartPoint=FALSE, SpatialWeights=TRUE, invert=FALSE, start <- if(UseStartPoint) n$StartPoint else n$EndPoints # Find distances for longest shortest paths from given start point(s) to # all end points - lps=shortest.paths(graph = ng, start, to = n$EndPoints, mode = 'all') + lps=distances(graph = ng, start, to = n$EndPoints, mode = 'all') if(rval=='length') return(max(lps)) if(!UseStartPoint && length(start)>1 && length(n$EndPoints)>1) { # we have a square distance matrix which is symmetric across @@ -273,7 +273,7 @@ spine <- function(n, UseStartPoint=FALSE, SpatialWeights=TRUE, invert=FALSE, wmi=arrayInd(which.max(lps), dim(lps)) from=start[wmi[1]] to=n$EndPoints[wmi[2]] - longestpath=get.shortest.paths(ng, from = from, to = to, mode = 'all')$vpath[[1]] + longestpath=shortest_paths(ng, from = from, to = to, mode = 'all')$vpath[[1]] if(rval=='ids') { if(invert) { @@ -308,7 +308,7 @@ spine <- function(n, UseStartPoint=FALSE, SpatialWeights=TRUE, invert=FALSE, #' @return \code{igraph} object containing only nodes of neuron keeping original #' labels (\code{x$d$PointNo} => \code{V(g)$label}) and vertex indices #' (\code{1:nrow(x$d)} => \code{V(g)$vid)}. -#' @importFrom igraph make_empty_graph add.edges E +#' @importFrom igraph make_empty_graph add_edges E #' @export #' @examples #' sg=segmentgraph(Cell07PNs[[1]]) @@ -344,9 +344,9 @@ segmentgraph<-function(x, weights=TRUE, segids=FALSE, exclude.isolated=FALSE, } if(weights){ weights=seglengths(x, all=TRUE) - g=add.edges(g, elred, weight=weights, segid=segids) + g=add_edges(g, elred, weight=weights, segid=segids) } else { - g=add.edges(g, elred, segid=segids) + g=add_edges(g, elred, segid=segids) } if(include.xyz){ @@ -357,7 +357,7 @@ segmentgraph<-function(x, weights=TRUE, segids=FALSE, exclude.isolated=FALSE, if(exclude.isolated){ # remove any points with no neighbours isolated_vertices=igraph::V(g)[igraph::degree(g)==0] - g=igraph::delete.vertices(graph=g,isolated_vertices) + g=igraph::delete_vertices(graph=g,isolated_vertices) } g } @@ -381,7 +381,7 @@ segmentgraph<-function(x, weights=TRUE, segids=FALSE, exclude.isolated=FALSE, #' @seealso \code{\link{prune_strahler}}, a \code{\link{segmentgraph}} (a form #' of \code{\link{ngraph}}) representation is used to calculate the Strahler #' order. -#' @importFrom igraph graph.bfs neighborhood V +#' @importFrom igraph bfs neighborhood V #' @return A list containing \itemize{ #' #' \item points Vector of integer Strahler orders for each point in the neuron @@ -400,7 +400,7 @@ strahler_order<-function(x){ return(list(points=rep(1L, nrow(x$d)), segments=rep(1L, length(x$SegList)))) - b=graph.bfs(s, root=roots, mode = 'out', unreachable=F, father=T) + b=bfs(s, root=roots, mode = 'out', unreachable=F, father=T) # find neighbours for each node n=neighborhood(s, 1, mode='out') @@ -533,15 +533,17 @@ prune_strahler<-function(x, orderstoprune=1:2, ...) { prune_vertices<-function(x, verticestoprune, invert=FALSE, ...) { g=as.ngraph(x) - # because igraph.vs sequences are atttached to a specific graph + # because igraph.vs sequences are attached to a specific graph if(inherits(verticestoprune, "igraph.vs")) verticestoprune=as.integer(verticestoprune) if(invert) { - nvertices=nrow(xyzmatrix(x)) + nvertices=igraph::vcount(g) verticestoprune=setdiff(seq_len(nvertices), verticestoprune) + } else { + verticestoprune=setdiff(verticestoprune, 0) } - dg=igraph::delete.vertices(g, verticestoprune) - # delete.vertices will return an igraph + dg=igraph::delete_vertices(g, verticestoprune) + # delete_vertices will return an igraph as.neuron(as.ngraph(dg), ...) } @@ -583,10 +585,10 @@ prune_edges_ng <- function(g, edges, invert=FALSE) { if(invert) edges=setdiff(igraph::E(g), edges) - dg=igraph::delete.edges(g, edges = edges) + dg=igraph::delete_edges(g, edges = edges) # remove unreferenced vertices - dg=igraph::delete.vertices(dg, which(igraph::degree(dg, mode='all')==0)) + dg=igraph::delete_vertices(dg, which(igraph::degree(dg, mode='all')==0)) } # Construct EdgeList matrix with start and end points from SegList diff --git a/R/seglist.R b/R/seglist.R index c1092855..a07bb33a 100644 --- a/R/seglist.R +++ b/R/seglist.R @@ -92,7 +92,7 @@ as.seglist.default<-function(x, ...) stop("Not yet implemented!") #' @return a \code{list} with one entry for each unbranched segment. #' @seealso \code{\link{ngraph},\link{igraph}} #' @export -#' @importFrom igraph is.directed is.connected graph.dfs degree +#' @importFrom igraph is_directed is_connected dfs degree #' @rdname seglist as.seglist.igraph<-function(x, origin=NULL, Verbose=FALSE, ...){ # Handle degenerate cases @@ -100,8 +100,8 @@ as.seglist.igraph<-function(x, origin=NULL, Verbose=FALSE, ...){ if(Verbose) warning("Empty graph! Seglist not defined") return(NULL) } - if(!is.connected(x)) stop("Graph is not fully connected!") - if(is.directed(x) && !igraph::is.dag(x)){ + if(!is_connected(x)) stop("Graph is not fully connected!") + if(is_directed(x) && !igraph::is_dag(x)){ stop("Graph has cycles!") } @@ -123,7 +123,7 @@ as.seglist.igraph<-function(x, origin=NULL, Verbose=FALSE, ...){ # Handle Origin if(is.null(origin)){ # no explicit origin specified, use raw vertex id of graph root - if(is.directed(x)) + if(is_directed(x)) origin=rootpoints(x, original.ids=FALSE) } else { # we've been given an origin but it may not be a raw vertex id for this @@ -140,7 +140,7 @@ as.seglist.igraph<-function(x, origin=NULL, Verbose=FALSE, ...){ } # Now do a depth first search to ensure that ordering is correct - dfs=graph.dfs(x, root=origin, father=TRUE, mode='all') + dfs=dfs(x, root=origin, father=TRUE, mode='all') # cache orders for speed: dfs$order[i] is slooooow in igraph>=1.0 orders=as.integer(dfs$order) ncount=degree(x) diff --git a/R/xform.R b/R/xform.R index 4a766445..e4b14a99 100644 --- a/R/xform.R +++ b/R/xform.R @@ -230,6 +230,13 @@ xform.neuronlist<-function(x, reg, subset=NULL, ..., OmitFailures=NA, } +#' @rdname nvertices +#' @export +nvertices.igraph <- function(x, ...) { + # as of igraph 2.0 this is numeric + as.integer(igraph::vcount(x)) +} + #' Mirror 3D object about a given axis, optionally using a warping registration #' #' @description mirroring with a warping registration can be used to account diff --git a/R/xyzmatrix.R b/R/xyzmatrix.R index 86b52308..a600c7d2 100644 --- a/R/xyzmatrix.R +++ b/R/xyzmatrix.R @@ -177,7 +177,7 @@ xyzmatrix.hxsurf<-function(x, ...) { #' @rdname xyzmatrix #' @export xyzmatrix.igraph<-function(x, ...){ - xyz=sapply(c("X","Y","Z"), function(c) igraph::get.vertex.attribute(x, c)) + xyz=sapply(c("X","Y","Z"), function(c) igraph::vertex_attr(x, c)) if(is.list(xyz) && all(sapply(xyz, is.null))) xyz = NULL xyz @@ -341,7 +341,7 @@ xyzmatrix2list <- function(x) { `xyzmatrix<-.igraph`<-function(x, value){ colnames(value)=c("X","Y","Z") for(col in colnames(value)){ - x=igraph::set.vertex.attribute(x, col, value=value[,col]) + x=igraph::set_vertex_attr(x, col, value=value[,col]) } x } diff --git a/README.md b/README.md index e6d403b4..7a491764 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![DOI](https://img.shields.io/badge/doi-10.5281%2Fzenodo.10171-blue.svg)](http://dx.doi.org/10.5281/zenodo.10171) [![Release Version](https://img.shields.io/github/release/natverse/nat.svg)](https://github.com/natverse/nat/releases/latest) [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/nat)](https://cran.r-project.org/package=nat) -[![Build status](https://github.com/natverse/nat/workflows/R-CMD-check/badge.svg)](https://github.com/natverse/nat/actions) +[![R-CMD-check](https://github.com/natverse/nat/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/natverse/nat/actions/workflows/R-CMD-check.yaml) [![Coverage Status](https://codecov.io/gh/natverse/nat/branch/master/graph/badge.svg)](https://app.codecov.io/gh/natverse/nat) [![Docs](https://img.shields.io/badge/docs-100%25-brightgreen.svg)](https://natverse.org//nat/reference/) [![Downloads](http://cranlogs.r-pkg.org/badges/nat?color=brightgreen)](https://www.r-pkg.org:443/pkg/nat) diff --git a/build-cmtk.sh b/build-cmtk.sh index 34cdb139..2e1e158c 100755 --- a/build-cmtk.sh +++ b/build-cmtk.sh @@ -3,8 +3,9 @@ set -e # check to see if cmtk install folder is empty if [ ! -d "$HOME/usr/local/bin" ]; then mkdir -p $HOME/src && cd $HOME/src - git clone --depth 50 https://github.com/jefferis/cmtk - cd cmtk/core && mkdir build && cd build && cmake .. && make DESTDIR=$HOME/ all install + git clone --depth 10 --branch natdev https://github.com/jefferis/cmtk + cd cmtk && git checkout natdev + cd core && mkdir build && cd build && cmake .. && make DESTDIR=$HOME/ all install else echo 'Using cached $HOME/usr/local directory.'; -fi \ No newline at end of file +fi diff --git a/man/neuron.Rd b/man/neuron.Rd index 4a13771f..7b6af9b9 100644 --- a/man/neuron.Rd +++ b/man/neuron.Rd @@ -160,7 +160,7 @@ hist(igraph::distances(ngw)) # converting back and forth between neurons and graphs g=as.ngraph(Cell07PNs[[1]]) -gstem=igraph::induced.subgraph(g, 1:10) +gstem=igraph::induced_subgraph(g, 1:10) # this is fine plot(gstem) plot(as.neuron(gstem)) @@ -178,7 +178,7 @@ plot(as.neuron(gstem2)) \seealso{ \code{\link{neuronlist}} -\code{\link{graph.dfs}, \link{as.seglist}} +\code{\link{dfs}, \link{as.seglist}} Other neuron: \code{\link{ngraph}()}, diff --git a/man/ngraph.Rd b/man/ngraph.Rd index 10baa693..be9772c4 100644 --- a/man/ngraph.Rd +++ b/man/ngraph.Rd @@ -45,7 +45,7 @@ when 4th column is assumed to be diameter)} \item{vertex.attributes, graph.attributes}{List of named attributes to be added to the graph. The elements of \code{vertex.attributes} must be vectors whose length is compatible with the number of elements in the -graph. See \code{\link[igraph]{set.vertex.attribute}} for details.} +graph. See \code{\link[igraph]{set_vertex_attr}} for details.} \item{x}{Object to convert (see method descriptions)} @@ -126,16 +126,16 @@ gw=as.ngraph(n, weights=TRUE) # find longest path across graph d=get.diameter(gw) # make a new neuron using the longest path -gw_spine=as.neuron(induced.subgraph(gw, d)) +gw_spine=as.neuron(induced_subgraph(gw, d)) # make a new neuron containing all nodes except those in longest path -gw_antispine=as.neuron(delete.vertices(gw, d)) +gw_antispine=as.neuron(delete_vertices(gw, d)) # note use of bounding box of original neuron to set plot axes plot(gw_spine, col='red', boundingbox=boundingbox(n)) plot(gw_antispine, col='blue', add=TRUE) } \seealso{ -\code{\link{igraph}}, \code{\link[igraph]{set.vertex.attribute}}, +\code{\link{igraph}}, \code{\link[igraph]{set_vertex_attr}}, \code{\link{subset.neuron}} for example of graph-based manipulation of a neuron, \code{\link{plot3d.ngraph}} diff --git a/man/nvertices.Rd b/man/nvertices.Rd index 8de405a7..136faf04 100644 --- a/man/nvertices.Rd +++ b/man/nvertices.Rd @@ -1,12 +1,15 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/xyzmatrix.R -\name{nvertices} +% Please edit documentation in R/xform.R, R/xyzmatrix.R +\name{nvertices.igraph} +\alias{nvertices.igraph} \alias{nvertices} \alias{nvertices.default} \alias{nvertices.neuronlist} \alias{nvertices.shapelist3d} \title{Find the number of vertices in an object (or each element of a neuronlist)} \usage{ +\method{nvertices}{igraph}(x, ...) + nvertices(x, ...) \method{nvertices}{default}(x, ...) diff --git a/man/spine.Rd b/man/spine.Rd index bb975bc9..b461bb59 100644 --- a/man/spine.Rd +++ b/man/spine.Rd @@ -69,7 +69,7 @@ plot3d(antispine, lwd=4, col='red') } \seealso{ \code{\link[igraph]{diameter}}, - \code{\link[igraph]{shortest.paths}}, \code{\link{prune_strahler}} for + \code{\link[igraph]{distances}}, \code{\link{prune_strahler}} for removing lower order branches from a neuron, \code{\link{prune}} for removing parts of a neuron by spatial criteria. diff --git a/man/subset.neuron.Rd b/man/subset.neuron.Rd index 15a498a5..3aac2c2e 100644 --- a/man/subset.neuron.Rd +++ b/man/subset.neuron.Rd @@ -69,7 +69,7 @@ points(t(xyzmatrix(n)[n$AxonLHEP, 1:2]), pch=19, cex=2.5) # now find the points downstream (distal) of that with respect to the root ng=as.ngraph(n) # use a depth first search -distal_points=igraph::graph.dfs(ng, root=n$AxonLHEP, unreachable=FALSE, +distal_points=igraph::dfs(ng, root=n$AxonLHEP, unreachable=FALSE, mode='out')$order distal_tree=subset(n, distal_points) plot(distal_tree, add=TRUE, col='red', lwd=2) diff --git a/tests/testthat/test-cmtk.R b/tests/testthat/test-cmtk.R index 922600d3..8dca925a 100644 --- a/tests/testthat/test-cmtk.R +++ b/tests/testthat/test-cmtk.R @@ -6,6 +6,9 @@ test_that("cmtk.bindir works when CMTK is in the path",{ # We're going to set up some fake directories to look like # different kinds of CMTK installation + # some spurious failures on windows actions + skip_on_os(os = 'windows') + td <- tempfile(pattern = 'nat-cmtk-test') makeexecfile <- function(p) { fullp <- file.path(td, p) diff --git a/tests/testthat/test-neuron.R b/tests/testthat/test-neuron.R index 519173ee..e42d6f21 100644 --- a/tests/testthat/test-neuron.R +++ b/tests/testthat/test-neuron.R @@ -273,7 +273,7 @@ test_that("we can subset a neuron", { test_that("we can subset a neuron with a vertex sequence", { n = Cell07PNs[[1]] - n_graph_dfs = igraph::graph.dfs(as.ngraph(n), root = 48, mode = "out", unreachable = FALSE) + n_graph_dfs = igraph::dfs(as.ngraph(n), root = 48, mode = "out", unreachable = FALSE) expect_is(n_subset <- subset(n, n_graph_dfs$order, invert = F), 'neuron') expect_is(n_subset <- subset(n, n_graph_dfs$order, invert = T), 'neuron') }) diff --git a/tests/testthat/test-ngraph.R b/tests/testthat/test-ngraph.R index 293c1ac7..1806e585 100644 --- a/tests/testthat/test-ngraph.R +++ b/tests/testthat/test-ngraph.R @@ -1,5 +1,5 @@ context("ngraph class") -library(igraph, warn.conflicts = FALSE) +suppressPackageStartupMessages(library(igraph, warn.conflicts = FALSE)) # make a very simple neuron # 1 2 3b 4 5 @@ -13,7 +13,7 @@ test_that("as.ngraph can convert swc data into an ngraph object",{ expect_is(g1,'ngraph') # check we keep ngraph class when modifying ngraph - expect_is(set.graph.attribute(g1,'origin',1),'ngraph') + expect_is(set_graph_attr(g1,'origin',1),'ngraph') # same neuron with PointNo 2 greater testd2=data.frame(PointNo=3:8,Label=2, @@ -144,13 +144,13 @@ test_that("setting of graph attributes",{ gatts=list(name='testneuron',nclass="PN") expect_is(testg <- as.ngraph(testd, graph.attributes = gatts, vertex.attributes=list(X=testd$X)), 'ngraph') - expect_equal(get.graph.attribute(testg, name = 'nclass'), gatts$nclass) - expect_equal(get.graph.attribute(testg, name = 'name'), gatts$name) + expect_equal(graph_attr(testg, name = 'nclass'), gatts$nclass) + expect_equal(graph_attr(testg, name = 'name'), gatts$name) # null attributes - expect_equal(get.graph.attribute(testg, name = 'rhubarb'), gatts$rhubarb) + expect_equal(graph_attr(testg, name = 'rhubarb'), gatts$rhubarb) # vertex attributes - expect_equal(get.vertex.attribute(testg, name = 'X'), testd$X) + expect_equal(vertex_attr(testg, name = 'X'), testd$X) if(igraph::igraph_version()>=numeric_version("1.3.5.9098")) expect_error(testg <- as.ngraph(testd, graph.attributes = gatts, vertex.attributes=list(X=testd$X[-1])))