Intro

Occasionally CATMAID users add the soma tag multiple times in error. We can find such neurons and generate CATMAID URLs to inspect them.

Setup

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()

Finding neurons with multiple somata

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)

XYZ position of the nodes we picked

# 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)
labelID labelName skeletonID treenodeID X Y Z radius login d rank
2773 soma 466765 10749295 336742 174855.0 161800 2402 managanc -7429.0000 1
2773 soma 466765 13022802 460268 103898.0 72040 -1 managanc 2544.1406 2
2773 soma 466765 293342 381102 149900.0 152080 -1 kknieriem 24269.3320 3
2773 soma 613965 10811439 487905 175115.0 190520 -1 wangf -3698.2480 1
2773 soma 613965 10811436 487322 175056.0 192360 -1 wangf -3428.5791 2
2773 soma 1027307 16649796 698691 261635.0 238880 -1 moranc -13119.6709 1
2773 soma 1027307 16649841 699130 261855.0 238360 4032 moranc -12446.8721 2
2773 soma 1056097 20321783 281805 281658.0 258720 -1 laughlandc -4587.3750 1
2773 soma 1056097 20136161 394996 176846.0 212520 3669 laughlandc -1374.8125 2
2773 soma 1540941 6010163 512703 294493.0 61720 2151 sharifin -2549.5781 1
2773 soma 1540941 16210433 441726 143097.0 81920 -1 batesa 16043.2812 2
2773 soma 1540941 16239938 459239 127355.0 81480 -1 robertsr 21358.0020 3
2773 soma 1605598 6102525 384290 139398.0 214840 1525 sharifin -11975.2314 1
2773 soma 1605598 8179141 467151 95598.4 103240 -1 lif 8600.1953 2
2773 soma 1605598 8151796 447091 113224.0 84560 -1 lif 8876.5410 3
2773 soma 1642465 9623166 342664 168612.0 120200 1722 robertsr -14362.3428 1
2773 soma 1642465 28739998 450907 116758.0 97640 -1 batesa 22795.0801 2
2773 soma 1852252 6618555 440338 231236.0 20160 1937 robertsr -2853.0312 1
2773 soma 1852252 6618575 439935 239097.0 21320 -1 robertsr -1474.8457 2
2773 soma 1855766 8178156 489228 174409.0 203040 1622 johnsonj -8780.4160 1
2773 soma 1855766 8585855 448561 113383.0 140000 -1 hsuj 17916.1641 2
2773 soma 1934952 2917709 484432 177420.0 210120 -1 wangf -12677.8135 1
2773 soma 1934952 8110036 484542 177079.0 208560 1832 wangf -11270.5156 2
2773 soma 2062703 7144275 403712 133268.0 202200 3371 batesa 2127.0625 1
2773 soma 2062703 7123901 442762 107221.0 129160 -1 batesa 26619.5645 2
2773 soma 2101395 7137710 322096 157457.0 163240 2237 lovef -6371.2500 1
2773 soma 2101395 7136507 355420 155440.0 148680 -1 lovef 5343.5625 2
2773 soma 2129474 22514175 322019 141825.0 173440 2381 batesa -1621.0938 1
2773 soma 2129474 19450031 340828 160142.0 173960 -1 batesa 7504.9590 2
2773 soma 2160773 14782661 509939 134319.0 41440 1909 taggl -598.7500 1
2773 soma 2160773 7277401 444186 89414.3 117480 -1 batesa 6818.6914 2
2773 soma 2161608 8717157 511123 109328.0 61480 2058 polskyj -8285.8906 1
2773 soma 2161608 8707654 484659 215526.0 120720 -1 polskyj 6136.4297 2
2773 soma 2198365 29993651 318971 182995.0 121240 2560 batesa -19948.7188 1
2773 soma 2198365 26906088 363872 156040.0 185920 -1 robertsr 18776.7891 2
2773 soma 2204528 7432577 385430 156578.0 214520 2760 batesa -7079.2310 1
2773 soma 2204528 7413904 361093 126280.0 167200 -1 batesa 15790.7637 2
2773 soma 2231264 7488013 330256 197047.0 151920 2740 batesa -4598.7812 1
2773 soma 2231264 7487331 347130 140521.0 164520 -1 batesa 16680.8125 2
2773 soma 2326256 8030385 572422 176479.0 204000 1749 sheridana -21168.9746 1
2773 soma 2326256 8040970 533214 197314.0 103160 -1 sheridana 7834.7188 2
2773 soma 2401906 16683373 327508 153617.0 165480 1883 lovef 509.3125 1
2773 soma 2401906 17949640 368728 144732.0 164560 -1 batesa 26381.6152 2
2773 soma 2548003 22250853 313451 152361.0 202120 2179 batesa -10895.2412 1
2773 soma 2548003 22230829 366377 130550.0 186600 -1 batesa 9497.2344 2
2773 soma 2779162 9414489 587182 134258.0 166880 2109 patrickc -8669.4375 1
2773 soma 2779162 9612310 515207 254093.0 91480 -1 patrickc -5991.4873 2
2773 soma 2923716 9384954 478410 174824.0 26600 2616 batesa -4091.1797 1
2773 soma 2923716 9438813 466796 136453.0 60320 -1 batesa 17201.1250 2
2773 soma 2931963 7731560 361109 155587.0 215520 2354 remyt -7505.5625 1
2773 soma 2931963 7732808 416265 145298.0 189720 -1 remyt 13019.6709 2
2773 soma 2931963 9423168 456240 99657.7 113760 -1 batesa 14787.6484 3
2773 soma 3029868 9808645 474070 136610.0 193320 3331 batesa -5318.4395 1
2773 soma 3029868 9809942 466970 85107.6 108640 -1 batesa -730.8359 2
2773 soma 3077625 23404895 477461 155207.0 198080 2276 pleijzierm -7881.7729 1
2773 soma 3077625 10917142 461411 133096.0 129160 -1 wangf 35392.1289 2
2773 soma 3079200 12068879 471522 90509.0 74400 1746 johnsonj -6013.1094 1
2773 soma 3079200 12060591 499220 148929.0 95040 -1 johnsonj 4420.6953 2
2773 soma 3080040 12908093 482779 81287.7 107720 1073 johnsonj -4230.2808 1
2773 soma 3080040 21122631 413512 147741.0 139120 -1 hsuj 36068.4961 2
2773 soma 3084758 12083905 345171 119567.0 143600 1743 johnsonj -5366.8501 1
2773 soma 3084758 12440744 430031 108623.0 110560 -1 schlegelp 17371.4375 2
2773 soma 3094186 10036307 467657 162724.0 204080 4752 batesa -11695.4053 1
2773 soma 3094186 10057107 404685 135986.0 188720 -1 batesa 10052.7031 2
2773 soma 3106997 13589617 513563 144817.0 165880 1597 masoodpanahn -1645.4375 1
2773 soma 3106997 13588952 519345 161710.0 160000 1745 masoodpanahn 1982.2188 2
2773 soma 3412165 16094172 315855 141941.0 157080 2159 lovef -11373.8125 1
2773 soma 3412165 23454784 346041 158150.0 173760 -1 robertsr 11844.1924 2
2773 soma 3469191 27492877 416827 259187.0 210040 2675 robertsr -5352.7188 1
2773 soma 3469191 28918683 412102 143137.0 180120 -1 robertsr 18714.5508 2
2773 soma 3629167 12137382 323231 142267.0 168040 2358 batesa -789.4375 1
2773 soma 3629167 12108600 331027 125550.0 176520 -1 robertsr 128.7500 2
2773 soma 3629167 12136851 336103 157833.0 169800 -1 batesa 5703.6719 3
2773 soma 3760679 12597831 417712 251763.0 84520 3202 kimh -1294.7812 1
2773 soma 3760679 13247764 434381 300183.0 113040 -1 kimh 2806.6250 2
2773 soma 3760683 12606187 422910 248073.0 83880 2818 kimh 294.8438 1
2773 soma 3760683 13307424 418320 266366.0 99200 -1 kimh 4705.9404 2
2773 soma 3788747 22226759 323620 201034.0 140600 1868 batesa -5425.6826 1
2773 soma 3788747 22225899 361852 147749.0 146520 -1 batesa 6962.9829 2
2773 soma 4176905 17815382 320876 156809.0 157840 2396 batesa -9116.2812 1
2773 soma 4176905 14238606 342919 135546.0 196000 -1 batesa 2899.3750 2
2773 soma 4191753 22370278 410632 254281.0 231520 2031 batesa -22302.3398 1
2773 soma 4191753 14335618 361600 272246.0 178760 -1 robertsr 4301.9297 2
2773 soma 4954843 23831400 329603 156281.0 166200 1805 batesa 1531.3125 1
2773 soma 4954843 16318243 331711 136008.0 170600 -1 batesa 6382.0312 2
2773 soma 4954843 16318241 331881 136229.0 170880 -1 batesa 6640.5625 3
2773 soma 4954843 10465252 372760 146655.0 169080 -1 batesa 29559.2148 4
2773 soma 5131480 17629748 335100 130682.0 138120 1712 hsuj -13602.0625 1
2773 soma 5131480 17629657 339471 137515.0 140200 -1 hsuj -7849.1250 2
2773 soma 5438142 26460593 478847 140342.0 172920 2506 yangt -6082.7041 1
2773 soma 5438142 26409624 508323 102348.0 75600 -1 yangt -447.5977 2
2773 soma 5446277 25159517 527434 115694.0 50600 2681 yangt -10508.1562 1
2773 soma 5446277 24558720 526023 110209.0 75800 -1 yangt 3976.6094 2
2773 soma 5448327 24192661 314749 140679.0 153000 2419 batesa -14154.8750 1
2773 soma 5448327 23126888 331659 136901.0 166120 -1 batesa 5459.5625 2
2773 soma 5532289 24776089 358237 163489.0 201160 2736 robertsr 2760.1719 1
2773 soma 5532289 19982453 389731 127560.0 167840 -1 robertsr 19078.2363 2
2773 soma 5730797 19689412 431335 177193.0 41880 2208 otton -10350.8125 1
2773 soma 5730797 19353457 479322 108289.0 73520 -1 otton 10811.3125 2
2773 soma 5955066 24195090 437997 301954.0 81400 3427 dreherm -16392.7812 1
2773 soma 5955066 28039979 421019 151521.0 99720 -1 dreherm 19665.5703 2
2773 soma 5961458 29473160 566747 307408.0 41280 1864 edmondsona -6941.0859 1
2773 soma 5961458 23148282 491352 109364.0 90600 -1 edmondsona 16929.3984 2
2773 soma 5997156 27618860 714910 210833.0 73680 2268 fairbanksk -5586.2188 1
2773 soma 5997156 27618915 714927 210832.0 73960 -1 fairbanksk -5458.0625 2
2773 soma 7427653 24248396 498789 108149.0 161080 -1 fairbanksk -12819.6875 1
2773 soma 7427653 24248778 499200 108344.0 160000 2108 fairbanksk -12047.8438 2
2773 soma 9008431 29960293 637624 249846.0 22080 2877 theissm -10949.9492 1
2773 soma 9008431 29944037 696317 153565.0 161600 -1 theissm 9450.1875 2

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)]
}

Google sheet

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(".")
}