Skip to content

Commit

Permalink
Merge 8e0e7d9 into 5c346d8
Browse files Browse the repository at this point in the history
  • Loading branch information
jefferis committed Aug 14, 2020
2 parents 5c346d8 + 8e0e7d9 commit f3a0c11
Show file tree
Hide file tree
Showing 21 changed files with 297 additions and 159 deletions.
6 changes: 4 additions & 2 deletions DESCRIPTION
Expand Up @@ -47,7 +47,8 @@ Suggests:
MASS,
alphashape3d,
Morpho,
plotly
plotly,
readobj
License: GPL-3
LazyData: yes
Collate:
Expand Down Expand Up @@ -76,6 +77,7 @@ Collate:
'neuron-io-fiji.R'
'neuron-io-neuroml.R'
'neuron-io.R'
'neuron-mesh.R'
'neuron-plot.R'
'neuronlist.R'
'neuronlist_interactive_3d.R'
Expand All @@ -96,7 +98,7 @@ Collate:
'xformimage.R'
'xformpoints.R'
'zzz.R'
RoxygenNote: 7.1.0
RoxygenNote: 7.1.1
Encoding: UTF-8
VignetteBuilder: knitr
Language: en-GB
110 changes: 67 additions & 43 deletions R/neuron-io.R
@@ -1,49 +1,53 @@
#' Read a single neuron from a file
#'
#' @details This function will handle \code{neuron} and \code{dotprops} objects
#' saved in R .rds or .rda format by default. Additional file formats can be
#'
#' @details This function will handle \code{neuron} and \code{dotprops} objects
#' saved in R .rds or .rda format by default. Additional file formats can be
#' registered using \code{fileformats}.
#'
#' At the moment the following formats are supported using file readers
#'
#' At the moment the following formats are supported using file readers
#' already included with the nat package: \itemize{
#'
#' \item \bold{swc} See \code{\link{read.neuron.swc}}. SWC files can also
#' return an \code{\link{ngraph}} object containing the neuron structure in a
#' (permissive) general graph format that also contains the 3D positions for
#'
#' \item \bold{swc} See \code{\link{read.neuron.swc}}. SWC files can also
#' return an \code{\link{ngraph}} object containing the neuron structure in a
#' (permissive) general graph format that also contains the 3D positions for
#' each vertex.
#'
#'
#' \item \bold{neuroml} See \code{\link{read.neuron.neuroml}}
#'
#'
#' \item \bold{fijitraces} See \code{\link{read.neuron.fiji}}. The file format
#' used by the \href{http://fiji.sc/Simple_Neurite_Tracer}{Simple Neurite
#' used by the \href{http://fiji.sc/Simple_Neurite_Tracer}{Simple Neurite
#' Tracer} plugin of Fiji/ImageJ.
#'
#' \item \bold{hxlineset,hxskel} Two distinct fileformats used by Amira.
#' \code{hxlineset} is the generic one, \code{hxskel} is used by the
#'
#' \item \bold{hxlineset,hxskel} Two distinct fileformats used by Amira.
#' \code{hxlineset} is the generic one, \code{hxskel} is used by the
#' hxskeletonize extension of Schmitt and Evers (see refs).
#'
#' \item \bold{rda,rds} Native R cross-platform binary formats (see
#' \code{\link{load}, \link{readRDS}}). Note that RDS only contains a single
#'
#' \item \bold{rda,rds} Native R cross-platform binary formats (see
#' \code{\link{load}, \link{readRDS}}). Note that RDS only contains a single
#' unnamed neuron, whereas rda contains one or more named neurons.
#'
#'
#' \item \bold{obj,ply} 3D Mesh formats encoding surface models of neurons.
#' These depend on the suggested package \code{\link[Rvcg]{Rvcg}} (for 'ply'
#' format) and \code{\link[readobj]{readobj}} (for Wavefront 'obj' format).
#'
#' }
#' @export
#' @param f Path to file. This can be a URL, in which case the file is
#' @param f Path to file. This can be a URL, in which case the file is
#' downloaded to a temporary location before reading.
#' @param format The file format of the neuron. When \code{format=NULL}, the
#' default, \code{read.neuron} will infer the file format from the extension
#' @param format The file format of the neuron. When \code{format=NULL}, the
#' default, \code{read.neuron} will infer the file format from the extension
#' or file header (aka magic) using the \code{fileformats} registry.
#' @param class The class of the returned object - presently either
#' @param class The class of the returned object - presently either
#' \code{"neuron"} or \code{"ngraph"}
#' @param ... additional arguments passed to format-specific readers
#' @seealso \code{\link{write.neuron}}, \code{\link{read.neurons}},
#' \code{\link{fileformats}}
#' @references Schmitt, S. and Evers, J. F. and Duch, C. and Scholz, M. and
#' Obermayer, K. (2004). New methods for the computer-assisted 3-D
#' reconstruction of neurons from confocal image stacks. Neuroimage 4,
#' 1283--98.
#' @references Schmitt, S. and Evers, J. F. and Duch, C. and Scholz, M. and
#' Obermayer, K. (2004). New methods for the computer-assisted 3-D
#' reconstruction of neurons from confocal image stacks. Neuroimage 4,
#' 1283--98.
#' \href{http://dx.doi.org/10.1016/j.neuroimage.2004.06.047}{doi:10.1016/j.neuroimage.2004.06.047}
#'
#'
#' @examples
#' \dontrun{
#' # note that we override the default NeuronName field
Expand Down Expand Up @@ -98,7 +102,7 @@ read.neuron<-function(f, format=NULL, class=c("neuron", "ngraph"), ...){
#' Read one or more neurons from file to a neuronlist in memory
#'
#' @details This function will cope with the same set of file formats offered by
#' \code{read.neuron}.
#' \code{\link{read.neuron}}.
#'
#' If the \code{paths} argument specifies a (single) directory then all files
#' in that directory will be read unless an optional regex pattern is also
Expand Down Expand Up @@ -594,7 +598,7 @@ is.swc<-function(f, TrustSuffix=TRUE) {
all(sapply(first_line[c("X", "Y", "Z", "W")], is.numeric))
}

#' Write out a neuron in any of the file formats we know about
#' Write out a neuron skeleton or mesh in any of the file formats we know about
#'
#' If file is not specified the neuron's InputFileName field will be checked
#' (for a dotprops object it will be the \code{'file'} attribute). If this is
Expand All @@ -612,14 +616,17 @@ is.swc<-function(f, TrustSuffix=TRUE) {
#' \code{normalise.ids=NA} will normalise \code{PointNo} vertex ids only when
#' a vertex is connected (by the \code{Parent} field) to a vertex that had not
#' yet been defined. Many readers make the assumption that this is true. When
#' \code{normalise.ids=F} the vertex ids will not be touched.
#' \code{normalise.ids=FALSE} the vertex ids will not be touched.
#'
#' @param n A neuron
#' @param file Path to output file
#' @param dir Path to directory (this will replace dirname(file) if specified)
#' @param dir Path to directory (this will replace \code{dirname(file)} if
#' specified)
#' @param format Unique abbreviation of one of the registered file formats for
#' neurons including 'swc', 'hxlineset', 'hxskel', if no format can be extracted from
#' the filename and the ext parameter, then it defaults to 'swc'
#' neurons including 'swc', 'hxlineset', 'hxskel' (skeletons) and 'ply', 'obj'
#' (neuron meshes). If no format can be extracted from the filename or the
#' \code{ext} parameter, then it defaults to 'swc' for skeletons and 'ply' for
#' meshes.
#' @param ext Will replace the default extension for the filetype and should
#' include the period e.g. \code{ext='.amiramesh'} or \code{ext='_reg.swc'}.
#' The special value of ext=NA will prevent the extension from being changed
Expand All @@ -635,12 +642,14 @@ is.swc<-function(f, TrustSuffix=TRUE) {
#' # show the currently registered file formats that we can write
#' fileformats(class='neuron', write=TRUE)
#' \dontrun{
#' # write out "myneuron.swc" in SWC format
#' # write neuron to "myneuron.swc" in SWC format
#' write.neuron(Cell07PNs[[1]], file='myneuron.swc')
#' # write out "myneuron.swc" in SWC format, normalising the integer ids that
#' # label every node (this is required by some SWC readers e.g. Fiji)
#' # write in SWC format, normalising the integer ids that label every node
#' # (this is required by some SWC readers e.g. Fiji)
#' write.neuron(Cell07PNs[[1]], file='myneuron.swc', normalise.ids=TRUE)
#'
#' # write out "myneuron.swc" in SWC format withour the final extension
#' write.neuron(Cell07PNs[[1]], file='myneuron.swc')

#' # write out "myneuron.amiramesh" in Amira hxlineset format
#' write.neuron(Cell07PNs[[1]], format = 'hxlineset', file='myneuron.amiramesh')
#'
Expand Down Expand Up @@ -670,13 +679,18 @@ write.neuron<-function(n, file=NULL, dir=NULL, format=NULL, ext=NULL,
if(!(length(ext) && is.na(ext)))
file=tools::file_path_sans_ext(file)
}

if(!is.null(format)) {
# TODO - one day it should be possible to have one file format associated
# with different R classes
if(format=='obj') format='neuron.obj'
else if(format=='ply') format='neuron.ply'
}
fw=try(getformatwriter(format=format, file=file, ext=ext, class='neuron'), silent = T)
if(inherits(fw, 'try-error')) {
if(is.null(format)){
format='swc'
format <- if(inherits(n, 'mesh3d')) 'neuron.ply' else 'swc'
fw=getformatwriter(format=format, file=file, ext=ext, class='neuron')
warning('write.neuron: using default format="swc"')
warning('write.neuron: using default format="',format,'"')
} else {
# rethrow the error
stop(fw)
Expand Down Expand Up @@ -784,10 +798,19 @@ write.dotprops.swc<-function(x, file, ...) {
#' write.neurons(Cell07PNs, dir="testwn", format='swc')
#' # write some neurons in swc format for picky software
#' write.neurons(Cell07PNs, dir="testwn", format='swc', normalise.ids=TRUE)
#' # write some neurons in swc format and zip them up
#' write.neurons(Cell07PNs, dir="testwn.zip", format='swc')
#'
#' # write some neurons in Amira hxlineset format
#' write.neurons(Cell07PNs, dir="testwn", format='hxlineset')
#'
#' # write some neuron meshes in Stanford ply format (the default for meshes)
#' write.neurons(myneurons, dir="testwn")
#' # specify the format to avoid a warning. Write to a zip file.
#' write.neurons(myneurons, dir="testmeshes.zip", format='ply')
#' # Wavefront obj format
#' write.neurons(myneurons, dir="testwn", format='obj')
#'
#' # organise new files in directory hierarchy by glomerulus and Scored.By field
#' write.neurons(Cell07PNs,dir="testwn",
#' subdir=file.path(Glomerulus,Scored.By),format='hxlineset')
Expand Down Expand Up @@ -859,10 +882,11 @@ write.neurons<-function(nl, dir, format=NULL, subdir=NULL, INDICES=names(nl),
}
if(!file.exists(thisdir)) dir.create(thisdir, recursive=TRUE)
file=files[nn]
if(!isTRUE(nzchar(file)) && is.neuron(n) && is.null(n$InputFileName)){
if(!isTRUE(nchar(file)>0)){
# the filename was not specified explicitly and we can't figure it out
# from field inside the neuron, so set to name of object in neuronlist
file=nn
if(!is.neuron(n) || is.null(n$InputFileName))
file=nn
}
if(interactive())
pb$tick()
Expand Down
49 changes: 49 additions & 0 deletions R/neuron-mesh.R
@@ -0,0 +1,49 @@
# internal function
# read a mesh representing a neuron and return a mesh3d object
read.neuron.mesh <- function(x, ...) {
ext=tools::file_ext(x)

if(ext=="ply") {
if(!requireNamespace('Rvcg', quietly = TRUE))
stop("Please install suggested library Rvcg to read .ply files!")
Rvcg::vcgPlyRead(x, updateNormals=F, ...)
} else if(ext=="obj") {
if(!requireNamespace('readobj', quietly = TRUE))
stop("Please install suggested library readobj to read .obj files!")
res=readobj::read.obj(x, convert.rgl = TRUE)
if(length(res)>1)
warning("Only reading 1/",length(res)," objects in: ",x)
res[[1]]
} else {
stop("Unrecognised mesh file format!")
}
}

is.ply<-function(f=NULL, bytes=NULL) {
if(!is.null(bytes) && is.character(f) && length(f)>1)
stop("Can only check bytes for a single file")
tocheck=if(is.null(bytes)) f else bytes
generic_magic_check(tocheck, "ply")
}

write.neuron.ply <- function(x, file, binary=TRUE, ...) {
write.neuron.mesh(x, file=file, format="ply", binary=binary, ...)
}

write.neuron.obj <- function(x, file, ... ) {
write.neuron.mesh(x, file=file, format="obj", ...)
}

write.neuron.mesh <- function(x, file, format=c("ply", "obj"), ...) {
if(!requireNamespace('Rvcg', quietly = TRUE))
stop("Please install suggested library Rvcg to write .",format," files!")
if(!inherits(x, 'mesh3d')) {
x=tryCatch(as.mesh3d(x), error=function(e) stop("Unable to convert x to mesh3d object! Only neuron meshes can be written in ",format," format!"))
}
if(format=="ply")
Rvcg::vcgPlyWrite(x, filename=file, writeCol = F, writeNormals = F, ...)
else if(format=="obj")
Rvcg::vcgObjWrite(x, filename=file, writeNormals=F, ...)
else stop("Unknown format")

}

0 comments on commit f3a0c11

Please sign in to comment.