From e054d5554457ac7d10358c54b952dc1df3e64e68 Mon Sep 17 00:00:00 2001 From: Romain Franconville Date: Tue, 14 Jan 2020 11:15:13 -0500 Subject: [PATCH 1/8] Switch to neuprint_read_neuron_simple --- R/neurons.R | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/R/neurons.R b/R/neurons.R index bd4798b7..2084640d 100644 --- a/R/neurons.R +++ b/R/neurons.R @@ -61,21 +61,7 @@ neuprint_read_neuron <- function(bodyid, nat = TRUE, drvid = FALSE, flow.central n = drvid::read.neuron.dvid(bodyid) d = n$d }else{ - cypher = sprintf("MATCH (:`%s` {bodyId:%s})-[:Contains]->(:Skeleton)-[:Contains]->(root :SkelNode) WHERE NOT (root)<-[:LinksTo]-() RETURN root.rowNumber AS rowId, root.location.x AS x, root.location.y AS y, root.location.z AS z, root.radius AS radius, -1 AS link ORDER BY root.rowNumber UNION match (:`%s` {bodyId:%s})-[:Contains]->(:Skeleton)-[:Contains]->(s :SkelNode)<-[:LinksTo]-(ss :SkelNode) RETURN s.rowNumber AS rowId, s.location.x AS x, s.location.y AS y, s.location.z AS z, s.radius AS radius, ss.rowNumber AS link ORDER BY s.rowNumber", - paste0(dp, all_segments_json), - as.numeric(bodyid), - paste0(dp, all_segments_json), - as.numeric(bodyid)) - nc = neuprint_fetch_custom(cypher=cypher, conn = conn, ...) - if(!length(nc$data)){ - warning("bodyid ", bodyid, " could not be read from ", unlist(getenvoroption("server"))) - return(NULL) - } - d = data.frame(do.call(rbind,nc$data)) - d = as.data.frame(t(apply(d,1,function(r) unlist(r)))) - colnames(d) = c("PointNo","X","Y","Z","W","Parent") - d$Label = 0 - n = nat::as.neuron(d) + n = neuprint_read_neuron_simple(as.numeric(bodyid),dataset=dataset,conn = conn,heal = F,...) } if(heal|flow.centrality){ n = heal_skeleton(x = n) From 2cabf78d6b0dfd1249755c7e7645167768b773dd Mon Sep 17 00:00:00 2001 From: Romain Franconville Date: Tue, 14 Jan 2020 11:48:32 -0500 Subject: [PATCH 2/8] Small fix to avoid returning results from ROIs that start with the same letters --- R/connectivity.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/connectivity.R b/R/connectivity.R index 38a941e4..4641368b 100644 --- a/R/connectivity.R +++ b/R/connectivity.R @@ -218,7 +218,7 @@ extract_connectivity_df <- function(rois, json){ for(roi in rois){ d <- data.frame(0,0) colnames(d) <- paste0(roi,c(".pre",".post")) - b <- a[startsWith(names(a),roi)] + b <- a[startsWith(names(a),paste0(roi,"."))] d[names(b)] <- b values <- cbind(values,d) } From 6c0cc53978d9f2f82c8e71b10b2d8f97276a73fa Mon Sep 17 00:00:00 2001 From: Romain Franconville Date: Wed, 15 Jan 2020 11:28:11 -0500 Subject: [PATCH 3/8] Fixed common_connectivity. Also got faster because we're only looping through the actual common connections --- R/connectivity.R | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/R/connectivity.R b/R/connectivity.R index 38a941e4..347db309 100644 --- a/R/connectivity.R +++ b/R/connectivity.R @@ -135,20 +135,20 @@ neuprint_common_connectivity <- function(bodyids, statuses = NULL, all_segments)) class(Payload) = "json" com.conn = neuprint_fetch(path = 'api/npexplorer/commonconnectivity', body = Payload, conn = conn, ...) - m = matrix(0,nrow = length(bodyids),ncol = length(com.conn$data[[1]][[1]])) - rownames(m) = paste0(bodyids,"_weight") - connected = c() - for(i in 1:length(com.conn$data[[1]][[1]])){ - s = com.conn$data[[1]][[1]][[i]] - find = match(names(s),rownames(m)) - add = find[!is.na(find)] - m[add,i] = unlist(s)[!is.na(find)] - connected = c(connected,ifelse(is.null(s$input),s$output,s$input)) + partnerType <- ifelse(prepost=="PRE","output","input") + partnerNames <- sapply(com.conn$data[[1]][[1]],function(d) d[[partnerType]]) + partnerCount <- table(partnerNames) + commonPartners <- names(partnerCount[partnerCount == length(bodyids)]) + m <- matrix(0,nrow = length(bodyids),ncol = length(commonPartners)) + rownames(m) <- paste0(bodyids,"_weight") + colnames(m) <- commonPartners + comData <- com.conn$data[[1]][[1]][which(partnerNames %in% commonPartners)] + for(i in 1:length(comData)){ + s <- comData[[i]] + rName <- names(s)[names(s) %in% rownames(m)] + m[rName,as.character(s[[partnerType]])] <- s[[rName]] } - m = t(apply(m,1,as.numeric)) - colnames(m) = connected - rownames(m) = bodyids - m = m[,apply(m,2,function(x) sum(x==0)==0)] + rownames(m) <- bodyids m } From a657ffb880f0fd23cc6e0507240ca30ac52d4fe9 Mon Sep 17 00:00:00 2001 From: Romain Franconville Date: Wed, 15 Jan 2020 11:32:35 -0500 Subject: [PATCH 4/8] Small fix (in case they are no common partners) --- R/connectivity.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/connectivity.R b/R/connectivity.R index 347db309..e8547a46 100644 --- a/R/connectivity.R +++ b/R/connectivity.R @@ -143,8 +143,8 @@ neuprint_common_connectivity <- function(bodyids, statuses = NULL, rownames(m) <- paste0(bodyids,"_weight") colnames(m) <- commonPartners comData <- com.conn$data[[1]][[1]][which(partnerNames %in% commonPartners)] - for(i in 1:length(comData)){ - s <- comData[[i]] + + for(s in comData){ rName <- names(s)[names(s) %in% rownames(m)] m[rName,as.character(s[[partnerType]])] <- s[[rName]] } From 8840489534d7515ec19daf4fc9a9bcac145161a9 Mon Sep 17 00:00:00 2001 From: Romain Franconville Date: Wed, 15 Jan 2020 17:10:17 -0500 Subject: [PATCH 5/8] Prototype functions for paths and shortest paths running appropriate queries --- R/connectivity.R | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/R/connectivity.R b/R/connectivity.R index 38a941e4..d30ef6e5 100644 --- a/R/connectivity.R +++ b/R/connectivity.R @@ -208,6 +208,101 @@ neuprint_simple_connectivity <- function(bodyids, d } +#' @title Get a list of paths of length n between 2 neurons +#' +#' @description Get all of the paths in the database that connect the +#' query neurons with at least weightT synapses at each step +#' @param body_pre the bodyid of the neuron at the start of the path +#' @param body_post the bodyid of the neuron at the end of the path +#' @param n the length of the path. If n is a vector, paths of length n[1] to n[2] are considered +#' @param weightT weight threshold +#' @param dataset optional, a dataset you want to query. If NULL, the default +#' specified by your R environ file is used. See \code{neuprint_login} for +#' details. +#' @param all_segments if TRUE, all bodies are considered, if FALSE, only 'Neurons', i.e. bodies with a status roughly traced status. +#' @param conn optional, a neuprintr connection object, which also specifies the +#' neuPrint server see \code{\link{neuprint_login}}. If NULL, your defaults +#' set in your R.profile or R.environ are used. +#' @param ... methods passed to \code{neuprint_login} +#' @return +#' @seealso \code{\link{neuprint_common_connectivity}}, +#' \code{\link{neuprint_get_adjacency_matrix}} +#' @export +#' @rdname neuprint_get_paths +neuprint_get_paths <- function(body_pre,body_post,n,weightT=5,dataset = NULL, conn = NULL,all_segments=FALSE, ...){ + + if (length(n)==1){ + n <- c(n,n) + } + dataset <- check_dataset(dataset) + conn <- neuprint_login(conn) + all_segments.json <- ifelse(all_segments,"Segment","Neuron") + dp <- neuprint_dataset_prefix(dataset, conn=conn) + prefixed <- paste0(dp, all_segments.json) + + cypher <- sprintf(paste("call apoc.cypher.runTimeboxed('MATCH p = (src : `%s`{ bodyId: %s })-[ConnectsTo*%s..%s]->(dest:`%s`{ bodyId: %s })", + "WHERE ALL (x in relationships(p) WHERE x.weight >= %s)", + "RETURN length(p) AS `length(path)`,[n in nodes(p) | [n.bodyId, n.type]] AS path,[x in relationships(p) | x.weight] AS weights', {},5000)", + "YIELD value return value.`length(path)` as `length(path)`, value.path as path, value.weights AS weights" + ), + prefixed, + as.numeric(body_pre), + n[1]-1, + n[2], + prefixed, + as.numeric(body_post), + weightT + ) + nc <- neuprint_fetch_custom(cypher=cypher, conn = conn) + + +} + +#' @title Get a list of paths of length n between 2 neurons +#' +#' @description Get all of the paths in the database that connect the +#' query neurons with at least weightT synapses at each step +#' @param body_pre the bodyid of the neuron at the start of the path +#' @param body_post the bodyid of the neuron at the end of the path +#' @param n the length of the path. If n is a vector, paths of length n[1] to n[2] are considered +#' @param weightT weight threshold +#' @param dataset optional, a dataset you want to query. If NULL, the default +#' specified by your R environ file is used. See \code{neuprint_login} for +#' details. +#' @param all_segments if TRUE, all bodies are considered, if FALSE, only 'Neurons', i.e. bodies with a status roughly traced status. +#' @param conn optional, a neuprintr connection object, which also specifies the +#' neuPrint server see \code{\link{neuprint_login}}. If NULL, your defaults +#' set in your R.profile or R.environ are used. +#' @param ... methods passed to \code{neuprint_login} +#' @return +#' @seealso \code{\link{neuprint_common_connectivity}}, +#' \code{\link{neuprint_get_adjacency_matrix}} +#' @export +#' @rdname neuprint_get_shortest_paths +neuprint_get_shortest_paths <- function(body_pre,body_post,weightT=5,dataset = NULL, conn = NULL,all_segments=FALSE, ...){ + + dataset <- check_dataset(dataset) + conn <- neuprint_login(conn) + all_segments.json <- ifelse(all_segments,"Segment","Neuron") + dp <- neuprint_dataset_prefix(dataset, conn=conn) + prefixed <- paste0(dp, all_segments.json) + + cypher <- sprintf(paste("call apoc.cypher.runTimeboxed('MATCH p = allShortestPaths((src : `%s`{ bodyId: %s })-[ConnectsTo*]->(dest:`%s`{ bodyId: %s }))", + "WHERE ALL (x in relationships(p) WHERE x.weight >= %s)", + "RETURN length(p) AS `length(path)`,[n in nodes(p) | [n.bodyId, n.type]] AS path,[x in relationships(p) | x.weight] AS weights', {},5000)", + "YIELD value return value.`length(path)` as `length(path)`, value.path as path, value.weights AS weights" + ), + prefixed, + as.numeric(body_pre), + prefixed, + as.numeric(body_post), + weightT + ) + nc <- neuprint_fetch_custom(cypher=cypher, conn = conn) + + +} + # hidden, caution, does not deal with left/right neuropils extract_connectivity_df <- function(rois, json){ if(is.null(json)){ From db4d18529b49d4eb863d3763f3d9e558767fb7a4 Mon Sep 17 00:00:00 2001 From: Romain Franconville Date: Wed, 15 Jan 2020 17:10:17 -0500 Subject: [PATCH 6/8] Prototype functions for paths and shortest paths running appropriate queries --- R/connectivity.R | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/R/connectivity.R b/R/connectivity.R index 0d6491f8..d027935e 100644 --- a/R/connectivity.R +++ b/R/connectivity.R @@ -208,6 +208,101 @@ neuprint_simple_connectivity <- function(bodyids, d } +#' @title Get a list of paths of length n between 2 neurons +#' +#' @description Get all of the paths in the database that connect the +#' query neurons with at least weightT synapses at each step +#' @param body_pre the bodyid of the neuron at the start of the path +#' @param body_post the bodyid of the neuron at the end of the path +#' @param n the length of the path. If n is a vector, paths of length n[1] to n[2] are considered +#' @param weightT weight threshold +#' @param dataset optional, a dataset you want to query. If NULL, the default +#' specified by your R environ file is used. See \code{neuprint_login} for +#' details. +#' @param all_segments if TRUE, all bodies are considered, if FALSE, only 'Neurons', i.e. bodies with a status roughly traced status. +#' @param conn optional, a neuprintr connection object, which also specifies the +#' neuPrint server see \code{\link{neuprint_login}}. If NULL, your defaults +#' set in your R.profile or R.environ are used. +#' @param ... methods passed to \code{neuprint_login} +#' @return +#' @seealso \code{\link{neuprint_common_connectivity}}, +#' \code{\link{neuprint_get_adjacency_matrix}} +#' @export +#' @rdname neuprint_get_paths +neuprint_get_paths <- function(body_pre,body_post,n,weightT=5,dataset = NULL, conn = NULL,all_segments=FALSE, ...){ + + if (length(n)==1){ + n <- c(n,n) + } + dataset <- check_dataset(dataset) + conn <- neuprint_login(conn) + all_segments.json <- ifelse(all_segments,"Segment","Neuron") + dp <- neuprint_dataset_prefix(dataset, conn=conn) + prefixed <- paste0(dp, all_segments.json) + + cypher <- sprintf(paste("call apoc.cypher.runTimeboxed('MATCH p = (src : `%s`{ bodyId: %s })-[ConnectsTo*%s..%s]->(dest:`%s`{ bodyId: %s })", + "WHERE ALL (x in relationships(p) WHERE x.weight >= %s)", + "RETURN length(p) AS `length(path)`,[n in nodes(p) | [n.bodyId, n.type]] AS path,[x in relationships(p) | x.weight] AS weights', {},5000)", + "YIELD value return value.`length(path)` as `length(path)`, value.path as path, value.weights AS weights" + ), + prefixed, + as.numeric(body_pre), + n[1]-1, + n[2], + prefixed, + as.numeric(body_post), + weightT + ) + nc <- neuprint_fetch_custom(cypher=cypher, conn = conn) + + +} + +#' @title Get a list of paths of length n between 2 neurons +#' +#' @description Get all of the paths in the database that connect the +#' query neurons with at least weightT synapses at each step +#' @param body_pre the bodyid of the neuron at the start of the path +#' @param body_post the bodyid of the neuron at the end of the path +#' @param n the length of the path. If n is a vector, paths of length n[1] to n[2] are considered +#' @param weightT weight threshold +#' @param dataset optional, a dataset you want to query. If NULL, the default +#' specified by your R environ file is used. See \code{neuprint_login} for +#' details. +#' @param all_segments if TRUE, all bodies are considered, if FALSE, only 'Neurons', i.e. bodies with a status roughly traced status. +#' @param conn optional, a neuprintr connection object, which also specifies the +#' neuPrint server see \code{\link{neuprint_login}}. If NULL, your defaults +#' set in your R.profile or R.environ are used. +#' @param ... methods passed to \code{neuprint_login} +#' @return +#' @seealso \code{\link{neuprint_common_connectivity}}, +#' \code{\link{neuprint_get_adjacency_matrix}} +#' @export +#' @rdname neuprint_get_shortest_paths +neuprint_get_shortest_paths <- function(body_pre,body_post,weightT=5,dataset = NULL, conn = NULL,all_segments=FALSE, ...){ + + dataset <- check_dataset(dataset) + conn <- neuprint_login(conn) + all_segments.json <- ifelse(all_segments,"Segment","Neuron") + dp <- neuprint_dataset_prefix(dataset, conn=conn) + prefixed <- paste0(dp, all_segments.json) + + cypher <- sprintf(paste("call apoc.cypher.runTimeboxed('MATCH p = allShortestPaths((src : `%s`{ bodyId: %s })-[ConnectsTo*]->(dest:`%s`{ bodyId: %s }))", + "WHERE ALL (x in relationships(p) WHERE x.weight >= %s)", + "RETURN length(p) AS `length(path)`,[n in nodes(p) | [n.bodyId, n.type]] AS path,[x in relationships(p) | x.weight] AS weights', {},5000)", + "YIELD value return value.`length(path)` as `length(path)`, value.path as path, value.weights AS weights" + ), + prefixed, + as.numeric(body_pre), + prefixed, + as.numeric(body_post), + weightT + ) + nc <- neuprint_fetch_custom(cypher=cypher, conn = conn) + + +} + # hidden, caution, does not deal with left/right neuropils extract_connectivity_df <- function(rois, json){ if(is.null(json)){ From 14c0ee734011352b76172eeff4ceca0b06b153a0 Mon Sep 17 00:00:00 2001 From: Romain Franconville Date: Thu, 16 Jan 2020 11:17:21 -0500 Subject: [PATCH 7/8] Output a data frame with columns to,from,weight,name.to,name.from. --- R/connectivity.R | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/R/connectivity.R b/R/connectivity.R index d027935e..f07bb349 100644 --- a/R/connectivity.R +++ b/R/connectivity.R @@ -254,7 +254,15 @@ neuprint_get_paths <- function(body_pre,body_post,n,weightT=5,dataset = NULL, co weightT ) nc <- neuprint_fetch_custom(cypher=cypher, conn = conn) - + connTable <- dplyr::bind_rows(lapply(nc$data, function(d){ + l <- d[[1]] + dplyr::bind_rows(lapply(1:l, function(i){ + data.frame(from=as.character(d[[2]][[i]][[1]]), + to=as.character(d[[2]][[i+1]][[1]]), + weight=d[[3]][[i]], + name.from=d[[2]][[i]][[2]],name.to=d[[2]][[i+1]][[2]],stringsAsFactors = FALSE) + })) + })) } @@ -299,7 +307,15 @@ neuprint_get_shortest_paths <- function(body_pre,body_post,weightT=5,dataset = N weightT ) nc <- neuprint_fetch_custom(cypher=cypher, conn = conn) - + connTable <- dplyr::bind_rows(lapply(nc$data, function(d){ + l <- d[[1]] + dplyr::bind_rows(lapply(1:l, function(i){ + data.frame(from=as.character(d[[2]][[i]][[1]]), + to=as.character(d[[2]][[i+1]][[1]]), + weight=d[[3]][[i]], + name.from=d[[2]][[i]][[2]],name.to=d[[2]][[i+1]][[2]],stringsAsFactors = FALSE) + })) + })) } From f4529ad4c7527c490635367cdcda2f013208f2d0 Mon Sep 17 00:00:00 2001 From: Romain Franconville Date: Thu, 16 Jan 2020 14:08:14 -0500 Subject: [PATCH 8/8] Addind a `roi` argument to parse paths only in a ROI of set of ROIs --- R/connectivity.R | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/R/connectivity.R b/R/connectivity.R index 20aabbbc..a8f80da3 100644 --- a/R/connectivity.R +++ b/R/connectivity.R @@ -223,25 +223,32 @@ neuprint_simple_connectivity <- function(bodyids, #' @param conn optional, a neuprintr connection object, which also specifies the #' neuPrint server see \code{\link{neuprint_login}}. If NULL, your defaults #' set in your R.profile or R.environ are used. +#' @param roi Limit the search to connections happening within a certain ROI or set of ROIs (NULL by default) #' @param ... methods passed to \code{neuprint_login} #' @return #' @seealso \code{\link{neuprint_common_connectivity}}, #' \code{\link{neuprint_get_adjacency_matrix}} #' @export #' @rdname neuprint_get_paths -neuprint_get_paths <- function(body_pre,body_post,n,weightT=5,dataset = NULL, conn = NULL,all_segments=FALSE, ...){ +neuprint_get_paths <- function(body_pre,body_post,n,weightT=5,roi=NULL,dataset = NULL, conn = NULL,all_segments=FALSE, ...){ if (length(n)==1){ n <- c(n,n) } dataset <- check_dataset(dataset) conn <- neuprint_login(conn) + + if(!is.null(roi)){ + roicheck = neuprint_check_roi(rois=roi, dataset = dataset, conn = conn, ...) + roi <- paste("AND (" ,paste0("exists(apoc.convert.fromJsonMap(x.roiInfo).`",roi,"`)",collapse=" OR "),")") + } + all_segments.json <- ifelse(all_segments,"Segment","Neuron") dp <- neuprint_dataset_prefix(dataset, conn=conn) prefixed <- paste0(dp, all_segments.json) cypher <- sprintf(paste("call apoc.cypher.runTimeboxed('MATCH p = (src : `%s`{ bodyId: %s })-[ConnectsTo*%s..%s]->(dest:`%s`{ bodyId: %s })", - "WHERE ALL (x in relationships(p) WHERE x.weight >= %s)", + "WHERE ALL (x in relationships(p) WHERE x.weight >= %s %s)", "RETURN length(p) AS `length(path)`,[n in nodes(p) | [n.bodyId, n.type]] AS path,[x in relationships(p) | x.weight] AS weights', {},5000)", "YIELD value return value.`length(path)` as `length(path)`, value.path as path, value.weights AS weights" ), @@ -251,7 +258,8 @@ neuprint_get_paths <- function(body_pre,body_post,n,weightT=5,dataset = NULL, co n[2], prefixed, as.numeric(body_post), - weightT + weightT, + ifelse(is.null(roi),"",roi) ) nc <- neuprint_fetch_custom(cypher=cypher, conn = conn) @@ -266,17 +274,17 @@ neuprint_get_paths <- function(body_pre,body_post,n,weightT=5,dataset = NULL, co })) } -#' @title Get a list of paths of length n between 2 neurons +#' @title Get a list of the shortest paths between 2 neurons #' -#' @description Get all of the paths in the database that connect the +#' @description Get all of the shortest paths in the database that connect the #' query neurons with at least weightT synapses at each step #' @param body_pre the bodyid of the neuron at the start of the path #' @param body_post the bodyid of the neuron at the end of the path -#' @param n the length of the path. If n is a vector, paths of length n[1] to n[2] are considered #' @param weightT weight threshold #' @param dataset optional, a dataset you want to query. If NULL, the default #' specified by your R environ file is used. See \code{neuprint_login} for #' details. +#' @param roi Limit the search to connections happening within a certain ROI or set of ROIs (NULL by default) #' @param all_segments if TRUE, all bodies are considered, if FALSE, only 'Neurons', i.e. bodies with a status roughly traced status. #' @param conn optional, a neuprintr connection object, which also specifies the #' neuPrint server see \code{\link{neuprint_login}}. If NULL, your defaults @@ -287,7 +295,7 @@ neuprint_get_paths <- function(body_pre,body_post,n,weightT=5,dataset = NULL, co #' \code{\link{neuprint_get_adjacency_matrix}} #' @export #' @rdname neuprint_get_shortest_paths -neuprint_get_shortest_paths <- function(body_pre,body_post,weightT=5,dataset = NULL, conn = NULL,all_segments=FALSE, ...){ +neuprint_get_shortest_paths <- function(body_pre,body_post,weightT=5,roi=NULL,dataset = NULL, conn = NULL,all_segments=FALSE, ...){ dataset <- check_dataset(dataset) conn <- neuprint_login(conn) @@ -295,17 +303,22 @@ neuprint_get_shortest_paths <- function(body_pre,body_post,weightT=5,dataset = N dp <- neuprint_dataset_prefix(dataset, conn=conn) prefixed <- paste0(dp, all_segments.json) + if(!is.null(roi)){ + roicheck = neuprint_check_roi(rois=roi, dataset = dataset, conn = conn, ...) + roi <- paste("AND (" ,paste0("exists(apoc.convert.fromJsonMap(x.roiInfo).`",roi,"`)",collapse=" OR "),")") + } + cypher <- sprintf(paste("call apoc.cypher.runTimeboxed('MATCH p = allShortestPaths((src : `%s`{ bodyId: %s })-[ConnectsTo*]->(dest:`%s`{ bodyId: %s }))", - "WHERE ALL (x in relationships(p) WHERE x.weight >= %s)", + "WHERE ALL (x in relationships(p) WHERE x.weight >= %s %s)", "RETURN length(p) AS `length(path)`,[n in nodes(p) | [n.bodyId, n.type]] AS path,[x in relationships(p) | x.weight] AS weights', {},5000)", - "YIELD value return value.`length(path)` as `length(path)`, value.path as path, value.weights AS weights" - ), - prefixed, - as.numeric(body_pre), - prefixed, - as.numeric(body_post), - weightT - ) + "YIELD value return value.`length(path)` as `length(path)`, value.path as path, value.weights AS weights"), + prefixed, + as.numeric(body_pre), + prefixed, + as.numeric(body_post), + weightT, + ifelse(is.null(roi),"",roi) + ) nc <- neuprint_fetch_custom(cypher=cypher, conn = conn) connTable <- dplyr::bind_rows(lapply(nc$data, function(d){