diff --git a/NAMESPACE b/NAMESPACE index 7b15161..ce5c7c6 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,8 @@ # Generated by roxygen2: do not edit by hand +S3method(banc_add_synapses,default) +S3method(banc_add_synapses,neuron) +S3method(banc_add_synapses,neuronlist) S3method(banc_decapitate,"NULL") S3method(banc_decapitate,data.frame) S3method(banc_decapitate,hxsurf) @@ -21,6 +24,7 @@ S3method(geom_neuron,neuronlist) S3method(ggplot2_neuron_path,mesh3d) S3method(ggplot2_neuron_path,neuron) S3method(ggplot2_neuron_path,neuronlist) +export(banc_add_synapses) export(banc_all_synapses) export(banc_backbone_proofread) export(banc_brain_side_view) @@ -43,6 +47,7 @@ export(banc_neuron_comparison_plot) export(banc_nm2raw) export(banc_nuclei) export(banc_partner_summary) +export(banc_partners) export(banc_peripheral_nerves) export(banc_raw2nm) export(banc_read_l2dp) diff --git a/R/banc-table.R b/R/banc-table.R index cf963c3..8dd788a 100644 --- a/R/banc-table.R +++ b/R/banc-table.R @@ -120,7 +120,7 @@ banctable_set_token <- function(user, pwd, url = "https://cloud.seatable.io/"){ password = pwd, server_url = url) ac$auth() Sys.setenv(banctable_TOKEN = ac$token) - cat("banctable_TOKEN='", ac$token, "'\n", sep = "", append = TRUE, + cat("BANCTABLE_TOKEN='", ac$token, "'\n", sep = "", append = TRUE, file = path.expand("~/.Renviron")) return(invisible(NULL)) } diff --git a/R/ggplot2.R b/R/ggplot2.R index 7b69f66..1168ca1 100644 --- a/R/ggplot2.R +++ b/R/ggplot2.R @@ -528,6 +528,167 @@ geom_neuron.dotprops <- function(x = NULL, rotation_matrix = NULL, root = 3, col ...) } +#' @rdname geom_neuron +#' @method geom_neuron synapticneuron +#' @export +geom_neuron.synapticneuron <- function(x = NULL, + rotation_matrix = NULL, + root = 3, + cols = c("navy", "turquoise"), + stat = "identity", position = "identity", + na.rm = FALSE, + show.legend = NA, + inherit.aes = FALSE, + ...) { + if("splitneuron"%in%class(x)){ + geomneuron<-geom_neuron.splitneuron(x = x, + rotation_matrix = rotation_matrix, + root = root, + cols = cols, + stat = stat, + position = position, + na.rm = na.rm, + show.legend = show.legend, + inherit.aes = inherit.aes, + ...) + }else{ + geomneuron<-geom_neuron.neuron(x = x, + rotation_matrix = rotation_matrix, + root = root, + cols = cols, + stat = stat, + position = position, + na.rm = na.rm, + show.legend = show.legend, + inherit.aes = inherit.aes, + ...) + } + if(!is.null(x$connectors)){ + syns.in <- nat::xyzmatrix(subset(x$connectors, x$connectors$prepost==1)) + syns.out <- nat::xyzmatrix(subset(x$connectors, x$connectors$prepost==0)) + if(!is.null(rotation_matrix)){ + syns.in <- as.data.frame(t(rotation_matrix[,1:3] %*% t(syns.in))) + syns.in <- syns.in[,-4] + colnames(syns.in) <- c("X","Y","Z") + syns.out <- as.data.frame(t(rotation_matrix[,1:3] %*% t(syns.out))) + syns.out <- syns.out[,-4] + colnames(syns.out) <- c("X","Y","Z") + } + glist <- list( + ggplot2::geom_point(data = syns.in, + mapping = ggplot2::aes(x = .data$X, + y = .data$Y), + color = "#132157", + size = root/50, + alpha = 0.5), + ggplot2::geom_point(data = syns.out, + mapping = ggplot2::aes(x = .data$X, + y = .data$Y), + color = "#D72000", + size = root/50, + alpha = 0.5) + ) + c(geomneuron,glist) + }else{ + geomneuron + } +} + +#' @rdname geom_neuron +#' @method geom_neuron dotprops +#' @export +geom_neuron.splitneuron <- function(x = NULL, + rotation_matrix = NULL, + root = 3, + cols = c("navy", "turquoise"), + stat = "identity", position = "identity", + na.rm = FALSE, + show.legend = NA, + inherit.aes = FALSE, + ...) { + + # Get parts + if(root){ + x$tags$soma <- nat::rootpoints(x) + } + soma <- catmaid::soma(x) + if(!is.null(rotation_matrix)){ + soma <- as.data.frame(t(rotation_matrix[,1:3] %*% t(nat::xyzmatrix(soma)))) + soma <- soma[,-4] + colnames(soma) <- c("X","Y","Z") + } + dendrites.v = subset(rownames(x$d), x$d$Label == 3) + axon.v = subset(rownames(x$d), x$d$Label == 2) + p.d.v = subset(rownames(x$d), x$d$Label == 4) + p.n.v = subset(rownames(x$d), x$d$Label == 7) + null.v = subset(rownames(x$d), x$d$Label == 0 | is.na(x$d$Label)) + + # Get cable + dendrites = tryCatch(nat::prune_vertices(x, + verticestoprune = as.integer(c(axon.v,p.d.v, p.n.v, null.v))), + error = function(e) NULL) + axon = tryCatch(nat::prune_vertices(x, + verticestoprune = as.integer(c(dendrites.v, p.d.v, p.n.v, null.v))), + error = function(e) NULL) + p.d = tryCatch(nat::prune_vertices(x, verticestoprune = as.integer(c(axon.v, dendrites.v, p.n.v, null.v))), + error = function(e) NULL) + p.n = tryCatch(nat::prune_vertices(x, verticestoprune = as.integer(c(axon.v, dendrites.v, p.d.v, null.v))), + error = function(e) NULL) + nulls = tryCatch(nat::prune_vertices(x, verticestoprune = as.integer(c(axon.v, dendrites.v, p.d.v, p.n.v))), + error = function(e) NULL) + + # Make ggplot2 objects + g.dendrites <- ggplot2_neuron_path.neuron(dendrites, rotation_matrix = rotation_matrix) + g.axon <- ggplot2_neuron_path.neuron(axon, rotation_matrix = rotation_matrix) + g.p.d <- ggplot2_neuron_path.neuron(p.d, rotation_matrix = rotation_matrix) + g.p.n <- ggplot2_neuron_path.neuron(p.n, rotation_matrix = rotation_matrix) + g.nulls <- ggplot2_neuron_path.neuron(nulls, rotation_matrix = rotation_matrix) + + # Make geom objects + list( + ggplot2::geom_path(mapping = ggplot2::aes(x = .data$X, y = .data$Y, group = .data$group), + data = g.dendrites, col = "#54BCD1", + stat = stat, position = position, na.rm = na.rm, + show.legend = show.legend, inherit.aes = inherit.aes, alpha = 1), + ggplot2::geom_path(mapping = ggplot2::aes(x = .data$X, y = .data$Y, group = .data$group), + data = g.axon, col = "#EF7C12", + stat = stat, position = position, na.rm = na.rm, + show.legend = show.legend, inherit.aes = inherit.aes, alpha = 1), + ggplot2::geom_path(mapping = ggplot2::aes(x = .data$X, y = .data$Y, group = .data$group), + data = g.p.d, col = "#8FDA04", + stat = stat, position = position, na.rm = na.rm, + show.legend = show.legend, inherit.aes = inherit.aes, alpha = 1), + ggplot2::geom_path(mapping = ggplot2::aes(x = .data$X, y = .data$Y, group = .data$group), + data = g.p.n, col = "#C70E7B", + stat = stat, position = position, na.rm = na.rm, + show.legend = show.legend, inherit.aes = inherit.aes, alpha = 1), + ggplot2::geom_path(mapping = ggplot2::aes(x = .data$X, y = .data$Y, group = .data$group), + data = g.nulls, col = "#B3B3B3", + stat = stat, position = position, na.rm = na.rm, + show.legend = show.legend, inherit.aes = inherit.aes, alpha = 1), + ggplot2::geom_point(mapping = ggplot2::aes(x = .data$X, y = .data$Y), + data = soma, col = "black", + color = cols[1], alpha = 0.75, size = root) + ) +} + + + + + + + + + + + + + + + + + + #' Create a ggplot2 Visualisation of Neuron Objects #' #' @description diff --git a/R/l2.R b/R/l2.R index 15f1410..c318167 100644 --- a/R/l2.R +++ b/R/l2.R @@ -95,6 +95,8 @@ banc_read_l2skel <- function(id, OmitFailures=TRUE, dataset=NULL, ...) { #' obtained using `bancr::banc_nuclei()`. This data frame is assumed to have #' columns named `root_id` and `nucleus_position_nm`, where `nucleus_position_nm` #' specifies the 3D coordinates of the soma for each `root_id`. +#' @param estimate if \code{TRUE} and nucleus position is not in `banc_nuclei`, +#' then root is estimated as a leaf node furthest outside of the brain neuropil. #' @param ... Methods passed to \code{nat::nlapply}. #' #' @return The function returns the re-rooted `neuron` object. @@ -107,12 +109,12 @@ banc_read_l2skel <- function(id, OmitFailures=TRUE, dataset=NULL, ...) { #' } #' @export #' @rdname banc_reroot -banc_reroot <- function(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), ...) UseMethod("banc_reroot") +banc_reroot <- function(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), estimate = TRUE, ...) UseMethod("banc_reroot") #' @rdname banc_reroot #' @method banc_reroot neuron #' @export -banc_reroot.neuron <- function(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), ...){ +banc_reroot.neuron <- function(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), estimate = TRUE, ...){ if(is.null(id)){ id <- x$root_id } @@ -124,7 +126,7 @@ banc_reroot.neuron <- function(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), soma <- nat::xyzmatrix(df$nucleus_position_nm)[1,] x <- nat::reroot(x = x, point = c(soma)) x$tags$soma <- nat::rootpoints(x ) - }else{ # As best we can + }else if (estimate){ # As best we can warning(sprintf("no valid nucleus ID detecting for %s, estimating root point"),id) leaves <- nat::endpoints(x) npoints1 <- nat::xyzmatrix(x)[leaves,] @@ -142,6 +144,8 @@ banc_reroot.neuron <- function(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), nat::xyzmatrix(bancr::banc_neck_connective.surf)), k = 1) soma <-nat::xyzmatrix(npoints)[which.max(nearest$nn.dists),] x <- nat::reroot(x = x, point = c(soma)) + }else{ + warning(sprintf("no valid nucleus ID detecting for %s, no action taken"),id) } x } @@ -149,7 +153,7 @@ banc_reroot.neuron <- function(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), #' @rdname banc_reroot #' @method banc_reroot neuronlist #' @export -banc_reroot.neuronlist <- function(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), ...){ +banc_reroot.neuronlist <- function(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), estimate = TRUE, ...){ if(is.null(id)){ id <- names(x) } diff --git a/R/partners.R b/R/partners.R index a76df47..5f61605 100644 --- a/R/partners.R +++ b/R/partners.R @@ -28,6 +28,7 @@ #' slice_max(weight, n = 20) %>% #' banc_scene(open=TRUE) #' } +#' @rdname banc_partners banc_partner_summary <- function(rootids, partners = c("outputs", "inputs"), threshold = 0, @@ -87,6 +88,8 @@ banc_datastack_name <- memoise::memoise(function() { #' fpo=banc_partners(banc_latestid("720575941478275714"), partners='out') #' points3d(banc_raw2nm(fpo$pre_pt_position), col='red') #' } +#' @export +#' @rdname banc_partners banc_partners <- function(rootids, partners=c("input", "output"), ...) { partners=match.arg(partners) rootids=banc_ids(rootids) diff --git a/R/synapses.R b/R/synapses.R index f62ae9f..7ac86e5 100644 --- a/R/synapses.R +++ b/R/synapses.R @@ -127,3 +127,134 @@ banc_all_synapses <- function(path = "gs://zetta_lee_fly_cns_001_synapse/240623_ # path <- 'gs://zetta_lee_fly_cns_001_synapse/240529_run/240604_assignment/final_edgelist.df' # df <- googleCloudStorageR::gcs_get_object(path, parseFunction = function(x) read.csv(x, nrows = 1000)) # } + + +#' Add synapses to neuron objects +#' +#' This function family adds synaptic data to neuron objects or neuron lists. +#' It retrieves synaptic connections and attaches them to the neuron object(s). +#' +#' @param x A neuron object, neuronlist, or other object to add synapses to +#' @param id The root ID of the neuron. If NULL, it uses the ID from the neuron object +#' @param connectors A dataframe of synaptic connections. If NULL, it retrieves the data +#' @param size.threshold Minimum size threshold for synapses to include +#' @param remove.autapses Whether to remove autapses (self-connections) +#' @param ... Additional arguments passed to methods, \code{nat::nlapply} +#' +#' @return An object of the same type as `x`, with synapses added +#' +#' @export +banc_add_synapses <- function(x, ...) { + UseMethod("banc_add_synapses") +} + +#' @rdname banc_add_synapses +#' @export +banc_add_synapses.neuron <- function(x, + id = NULL, + connectors = NULL, + size.threshold = 5, + remove.autapses = TRUE, + ...){ + # Get valid root id + if(is.null(id)){ + id <- x$id + } + + # Get synaptic data + if(is.null(connectors)){ + connectors.in <- bancr:::banc_partners(id, partners = "input") + if(nrow(connectors.in)){ + connectors.in.xyz <- do.call(rbind,connectors.in$post_pt_position) + connectors.in.xyz <- as.data.frame(connectors.in.xyz) + colnames(connectors.in.xyz) <- c("X","Y","Z") + connectors.in <- cbind(connectors.in,connectors.in.xyz) + connectors.in <- connectors.in %>% + dplyr::rename(connector_id = id, + pre_id = pre_pt_root_id, + pre_svid = pre_pt_supervoxel_id, + post_id = post_pt_root_id, + post_svid = post_pt_supervoxel_id) %>% + dplyr::filter(size>size.threshold) %>% + dplyr::mutate(prepost = 1) %>% + dplyr::select(connector_id, pre_id, post_id, prepost, pre_svid, post_svid, size, X, Y, Z) + } + connectors.out <- bancr:::banc_partners(id, partners = "output") + if(nrow(connectors.out)){ + connectors.out.xyz <- do.call(rbind,connectors.out$pre_pt_position) + connectors.out.xyz <- as.data.frame(connectors.out.xyz) + colnames(connectors.out.xyz) <- c("X","Y","Z") + connectors.out <- cbind(connectors.out,connectors.out.xyz) + connectors.out <- connectors.out %>% + dplyr::rename(connector_id = id, + pre_id = pre_pt_root_id, + pre_svid = pre_pt_supervoxel_id, + post_id = post_pt_root_id, + post_svid = post_pt_supervoxel_id) %>% + dplyr::filter(size>size.threshold) %>% + dplyr::mutate(prepost = 0) %>% + dplyr::select(connector_id, pre_id, post_id, prepost, pre_svid, post_svid, size, X, Y, Z) + } + connectors <- rbind(connectors.in,connectors.out) + }else{ + connectors <- connectors %>% + dplyr::filter(post_id==id|pre_id==id) + } + if(remove.autapses) { + connectors=connectors[connectors$post_id!=connectors$pre_id,,drop=FALSE] + } + + # Attach synapses + if(nrow(connectors)){ + near <- nabor::knn(query = nat::xyzmatrix(connectors), + data = nat::xyzmatrix(x$d),k=1) + connectors$treenode_id <- x$d[near$nn.idx,"PointNo"] + x$connectors = as.data.frame(connectors, stringsAsFactors = FALSE) + } + x$connectors <- connectors + + # Change class to work with connectivity functions in other packages + class(x) <- union(c("synapticneuron"), class(x)) + + # Return + x +} + +#' @rdname banc_add_synapses +#' @export +banc_add_synapses.neuronlist <- function(x, + id = NULL, + connectors = NULL, + size.threshold = 5, + remove.autapses = TRUE, + ...) { + if(is.null(id)){ + is <- names(x) + } + nat::nlapply(x,banc_add_synapses.neuron, + id=id, + connectors=connectors, + size.threshold=size.threshold, + remove.autapses=remove.autapses) +} + +#' @rdname banc_add_synapses +#' @export +banc_add_synapses.default <- function(x, + id = NULL, + connectors = NULL, + size.threshold = 5, + remove.autapses = TRUE, + ...) { + stop("No method for class ", class(x)) +} + + + + + + + + + + diff --git a/R/urls.R b/R/urls.R index 52cb7eb..9cba020 100644 --- a/R/urls.R +++ b/R/urls.R @@ -22,7 +22,7 @@ banc_scene <- function(ids=NULL, open=FALSE) { url="https://spelunker.cave-explorer.org/#!middleauth+https://global.daf-apis.com/nglstate/api/v1/6283844278812672" url=sub("#!middleauth+", "?", url, fixed = T) parts=unlist(strsplit(url, "?", fixed = T)) - json=try(flywire_fetch(parts[2], token=banc_token(), return = 'text', cache = TRUE)) + json=try(fafbseg::flywire_fetch(parts[2], token=banc_token(), return = 'text', cache = TRUE)) if(inherits(json, 'try-error')) { badtoken=paste0("You have a token but it doesn't seem to be authorised for banc.\n", "Have you definitely used `banc_set_token()` to make a token for the banc dataset?") diff --git a/man/banc_add_synapses.Rd b/man/banc_add_synapses.Rd new file mode 100644 index 0000000..d4946a1 --- /dev/null +++ b/man/banc_add_synapses.Rd @@ -0,0 +1,58 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/synapses.R +\name{banc_add_synapses} +\alias{banc_add_synapses} +\alias{banc_add_synapses.neuron} +\alias{banc_add_synapses.neuronlist} +\alias{banc_add_synapses.default} +\title{Add synapses to neuron objects} +\usage{ +banc_add_synapses(x, ...) + +\method{banc_add_synapses}{neuron}( + x, + id = NULL, + connectors = NULL, + size.threshold = 5, + remove.autapses = TRUE, + ... +) + +\method{banc_add_synapses}{neuronlist}( + x, + ids = NULL, + connectors = NULL, + size.threshold = 5, + remove.autapses = TRUE, + ... +) + +\method{banc_add_synapses}{default}( + x, + ids = NULL, + connectors = NULL, + size.threshold = 5, + remove.autapses = TRUE, + ... +) +} +\arguments{ +\item{x}{A neuron object, neuronlist, or other object to add synapses to} + +\item{...}{Additional arguments passed to methods} + +\item{id}{The root ID of the neuron. If NULL, it uses the ID from the neuron object} + +\item{connectors}{A dataframe of synaptic connections. If NULL, it retrieves the data} + +\item{size.threshold}{Minimum size threshold for synapses to include} + +\item{remove.autapses}{Whether to remove autapses (self-connections)} +} +\value{ +An object of the same type as \code{x}, with synapses added +} +\description{ +This function family adds synaptic data to neuron objects or neuron lists. +It retrieves synaptic connections and attaches them to the neuron object(s). +} diff --git a/man/banc_partner_summary.Rd b/man/banc_partners.Rd similarity index 72% rename from man/banc_partner_summary.Rd rename to man/banc_partners.Rd index 7658c30..0a38586 100644 --- a/man/banc_partner_summary.Rd +++ b/man/banc_partners.Rd @@ -2,7 +2,6 @@ % Please edit documentation in R/partners.R \name{banc_partner_summary} \alias{banc_partner_summary} -\alias{banc_partners} \title{Summarise the connectivity of banc neurons} \usage{ banc_partner_summary( @@ -14,8 +13,6 @@ banc_partner_summary( datastack_name = NULL, ... ) - -banc_partners(rootids, partners = c("input", "output"), ...) } \arguments{ \item{rootids}{Character vector specifying one or more BANC rootids. As a @@ -43,8 +40,7 @@ sensible default is chosen.} a data.frame } \description{ -\code{banc_partners} returns details of each unitary synaptic -connection (including its xyz location). +Summarise the connectivity of banc neurons } \details{ note that the rootids you pass in must be up to date. See example. @@ -52,26 +48,18 @@ note that the rootids you pass in must be up to date. See example. \examples{ \dontrun{ # NB id must be up to date -sample_id=banc_latestid("720575941480769421") +sample_id=banc_latestid("720575941478275714") head(banc_partner_summary(sample_id)) head(banc_partner_summary(sample_id, partners='inputs')) # get the latest id for an outdate -banc_partner_summary(banc_latestid("720575941480769421")) +banc_partner_summary(banc_latestid("720575941478275714")) ## open banc/flywire scene containing top partners library(dplyr) -banc_partner_summary(banc_latestid("720575941480769421"), partners='inputs') \%>\% +banc_partner_summary(banc_latestid("720575941478275714"), partners='inputs') \%>\% slice_max(weight, n = 20) \%>\% banc_scene(open=TRUE) } -\dontrun{ -# plot input and output synapses of a neuron -nclear3d() -fpi=banc_partners(banc_latestid("648518346481082458"), partners='in') -points3d(banc_raw2nm(fpi$post_pt_position), col='cyan') -fpo=banc_partners(banc_latestid("648518346481082458"), partners='out') -points3d(banc_raw2nm(fpo$pre_pt_position), col='red') -} } \seealso{ \code{\link{flywire_partner_summary}}, \code{\link{banc_latestid}} diff --git a/man/banc_reroot.Rd b/man/banc_reroot.Rd index f5bd62d..b1a3f0f 100644 --- a/man/banc_reroot.Rd +++ b/man/banc_reroot.Rd @@ -6,11 +6,29 @@ \alias{banc_reroot.neuronlist} \title{Re-root BANC neuron skeleton at soma} \usage{ -banc_reroot(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), ...) +banc_reroot( + x, + id = NULL, + banc_nuclei = bancr::banc_nuclei(), + estimate = TRUE, + ... +) -\method{banc_reroot}{neuron}(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), ...) +\method{banc_reroot}{neuron}( + x, + id = NULL, + banc_nuclei = bancr::banc_nuclei(), + estimate = TRUE, + ... +) -\method{banc_reroot}{neuronlist}(x, id = NULL, banc_nuclei = bancr::banc_nuclei(), ...) +\method{banc_reroot}{neuronlist}( + x, + id = NULL, + banc_nuclei = bancr::banc_nuclei(), + estimate = TRUE, + ... +) } \arguments{ \item{x}{A \code{banc.neurite} object representing the neuron skeleton.} @@ -23,6 +41,9 @@ obtained using \code{bancr::banc_nuclei()}. This data frame is assumed to have columns named \code{root_id} and \code{nucleus_position_nm}, where \code{nucleus_position_nm} specifies the 3D coordinates of the soma for each \code{root_id}.} +\item{estimate}{if \code{TRUE} and nucleus position is not in \code{banc_nuclei}, +then root is estimated as a leaf node furthest outside of the brain neuropil.} + \item{...}{Methods passed to \code{nat::nlapply}.} } \value{