Occasionally CATMAID users add the soma tag multiple times in error. We can find such neurons and generate CATMAID URLs to inspect them.
First load main packages
library(elmr) cl=try(catmaid_login()) catmaid_available=inherits(cl, "catmaid_connection") library(knitr) # only run if catmaid available # and cache so only run once per day opts_chunk$set(eval=inherits(cl, "catmaid_connection"),cache.extra=Sys.Date()) library(dplyr) rgl::setupKnitr()
First let's fetch information about all the labels (aka tags) applied to nodes in the current project.
label_stats=catmaid_get_label_stats()
Now let's restrict to cases where there are multiple soma tags per skeleton
# select soma labels soma_labels = label_stats %>% filter(labelName == 'soma') %>% group_by(skeletonID) # select skeleton ids for neurons with multiple cell bodies multiple_soma = soma_labels %>% count(skeletonID) %>% filter(n > 1) %>% arrange(desc(n)) multiple_soma_info = soma_labels %>% filter(skeletonID %in% multiple_soma$skeletonID) multiple_soma_info = soma_labels %>% filter(skeletonID%in% multiple_soma$skeletonID)
# wrapper for tree node details node_details <- function(tnid) { res=catmaid_get_treenodes_detail(tnid) ul=catmaid_get_user_list() res$login=ul$login[match(res$user_id, ul$id)] # we expect these to be capitalised elsewhere cn=colnames(res) cn[cn%in%c("x","y","z")]=toupper(cn[cn%in%c("x","y","z")]) colnames(res) <- cn res[c("X","Y","Z","radius","login")] } # note that we need to transpose the results of vnode_xyz to get X,Y,Z columns multiple_soma_info <- cbind(as.data.frame(multiple_soma_info), node_details(multiple_soma_info$treenodeID))
Now let's calculate the distance from the neuropil surface
multiple_soma_info$d=pointsinside(xyzmatrix(multiple_soma_info), FAFB.surf, rval = 'distance') multiple_soma_info %>% arrange(skeletonID, d) %>% group_by(skeletonID) %>% mutate(rank=row_number()) -> multiple_soma_info kable(multiple_soma_info)
This lets us see that in some cases there are two soma tags outside the neuropil (negative d) and close together - these are probably duplicates - whereas in other cases it is likely that points were added in error. We can also plot the points colouring them by their rank order (most external first).
# make a colour palette with as many entries as the maximum number of soma # tags in a neuron pal=rainbow(max(multiple_soma_info$rank)) multiple_soma_info %>% with(expr = spheres3d(X,Y,Z, col=pal[rank], rad=2000)) plot3d(FAFB) par3d(zoom=.6)
Now we can use this information to construct an url for each node.
multiple_soma_info %>% rowwise() %>% mutate(url = open_fafb( cbind(X, Y, Z), active_skeleton_id = skeletonID, active_node_id = treenodeID, open = FALSE )) -> multiple_soma_info
It might be useful to know who 'owns' each neuron. I think the simplest way to assign this is by the user who has traced most nodes for each skeleton (since there may be different users responsible for each soma).
get_top_user <- function(x, ...) { ul=catmaid_get_user_list(...) # save time by checking unique skids only ddx=unique(x) gtu_one <- function(x, ...) { t <- try({ res=catmaid_get_contributor_stats(x, ...) w=which.max(res$node_contributors$n) ul$login[match(res$node_contributors$id[w], ul$id)] }) if(inherits(t, 'try-error')) NA_character_ else t } topus <- sapply(ddx, gtu_one) topus[match(x, ddx)] }
Let's make a google sheet with all those urls that we can then review manually:
library(googlesheets) # helper function to upload via temp file # since writing cells via API is very slow gs_upload_tf <- function(x, ...) { tf=tempfile(fileext = '.tsv') on.exit(unlink(tf)) write.table(x, file=tf, sep="\t", row.names = FALSE) gs_upload(tf, ...) } multiple_soma_info %>% arrange(skeletonID, d) %>% group_by(skeletonID) %>% mutate(user=get_top_user(skeletonID)) %>% gs_upload_tf(sheet_title = 'multi_soma_neurons')
As an alternative we can divide that up with one worksheet per user.
library(googlesheets) gs <- googlesheets::gs_new("multi_soma_neurons_by_user") gs_add_sheet <- function(x, gs, ...) { gs_ws_new(row_extent = nrow(x)+1, col_extent = ncol(x), ss = gs, ..., input=x, col_names=T) } multiple_soma_info %>% arrange(skeletonID, d) %>% mutate(user=factor(get_top_user(skeletonID))) -> msi2 for(u in levels(msi2$user)) { gs_add_sheet(subset(msi2, user==u), gs, ws_title=u) cat(".") }
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.