In [1]:
    
library('curl')
library('R.matlab')
library('gdata')
    
    
In [2]:
    
# Set up URLs for data download..
download_urls <- c('http://neuro.rzg.mpg.de/download/Helmstaedter_et_al_Nature_2013_skeletons_contacts_matrices.mat',
                   'https://media.nature.com/original/nature-assets/nature/journal/v500/n7461/extref/nature12346-s3.zip')
    
In [3]:
    
# Set up Folder name insides 'natverse_examples'..
dataset_name <- 'natverse_mouseconnectome'
    
In [4]:
    
download_filename <- basename(download_urls)
if (is.null(getOption(dataset_name))){
    message("Setting options")
    options(natverse_examples=rappdirs::user_data_dir('R/natverse_examples'))
  }
    
    
In [5]:
    
dataset_path <- file.path(getOption('natverse_examples'),dataset_name)
message("Dataset path:", dataset_path)
    
    
In [6]:
    
if (!dir.exists(dataset_path)){
    message("Creating folder: ", basename(dataset_path))
    dir.create(dataset_path, recursive = TRUE, showWarnings = FALSE)
  }
    
In [7]:
    
downloaded_dataset <- ''
if(length(download_urls))
    message("Downloading files to: ", dataset_path)
for (download_fileidx in 1:length(download_urls)){
        localfile <- file.path(dataset_path, download_filename[download_fileidx])
        downloaded_dataset[download_fileidx] <- localfile
        if(file.exists(localfile)) next
        message("Processing URL: ", download_urls[download_fileidx], " (file ", download_fileidx, "/", length(download_urls), ")")
        curl::curl_download(download_urls[download_fileidx], localfile, quiet=FALSE)
      }
message("Downloads done")
    
    
In [8]:
    
message(paste(c("Dataset downloaded at: ", downloaded_dataset), collapse="\n"))
    
    
In [9]:
    
raw_data <- R.matlab::readMat(downloaded_dataset[1])
    
In [10]:
    
names(raw_data)
    
    
In [11]:
    
skeleton_metadata <- raw_data[2:8]
saveRDS(skeleton_metadata, file=file.path(dataset_path,'skeleton_metadata.rds'))
    
In [12]:
    
skall <- raw_data$kn.e2006.ALLSKELETONS.FINAL2012
    
In [13]:
    
rownames(skall[[1]][[1]])
    
    
In [14]:
    
#' Parse a single skeleton object cleaning up the rather messy structure that comes out of readMat
parse.moritz.skel<-function(x, simple_fields_only=TRUE){
  # delist
  x=x[[1]]
  stopifnot(inherits(x,'array'))
  
  vars=rownames(x)
  stopifnot(all(c('nodes','edges') %in% vars))
  
  #simplevars=intersect(c('nodes','edges', 'edgeSel'), vars)
  simplevars=intersect(c('nodes','edges'), vars)
  r=sapply(simplevars, function(v) x[v,,][[1]], simplify=FALSE)
  
  othervars=setdiff(vars, simplevars)
  process_var<-function(y){
    if(inherits(y,'list')) y=y[[1]]
    if(inherits(y,'array')) apply(y, 1, unlist) else {
      if(is.numeric(y)) drop(y) else y
    }
  }
  if(simple_fields_only)
    structure(r, class=c('skel','list'))
  else {
    r2=sapply(othervars, function(v) process_var(x[v,,]), simplify = FALSE)
    structure(c(r, r2), class=c('skel','list'))
  }
}
    
In [15]:
    
# Convert all the neurons to intermediate skeleton format (here just a neuronlist in 'nat')
skallp=nat::nlapply(skall, parse.moritz.skel, .progress='text')
# give the neurons names
names(skallp)=sprintf("sk%04d", seq_along(skallp))
    
    
    
In [16]:
    
skallp_unique <- skallp
    
In [17]:
    
attr(skallp_unique,'df')=data.frame(
  row.names=names(skallp_unique),
  skid=seq.int(skallp_unique),
  cellid=skeleton_metadata$kn.e2006.ALLSKELETONS.FINAL2012.cellIDs[1,],
  typeid=skeleton_metadata$kn.e2006.ALLSKELETONS.FINAL2012.globalTypeIDs.REDOMAR2013[1,],
  cellid.soma=skeleton_metadata$kn.e2006.ALLSKELETONS.FINAL2012.cellIDs.pure.forSomata[1,]
  )
    
In [18]:
    
head(attr(skallp_unique,'df'))
    
    
In [19]:
    
attr(skallp_unique,'df')$nedges=sapply(skallp_unique,function(x) nrow(x$edges))
    
In [20]:
    
message("Number of unique cells(neurons): ", length(unique(attr(skallp_unique,'df')$cellid)))
    
    
In [21]:
    
message("Number of tracings: ", length(skallp_unique))
    
    
In [22]:
    
sk.uniq_temp=skallp_unique[by(attr(skallp_unique,'df'),attr(skallp_unique,'df')$cellid,function(x) x$skid[which.max(x$nedges)])]
    
In [23]:
    
message("Number of tracings used: ", length(sk.uniq_temp))
    
    
In [24]:
    
message("Reading SI 4 spreadsheet sheet 3 ...")
utils::unzip(downloaded_dataset[2],exdir = file.path(dataset_path, sub('\\.zip$', '', basename(downloaded_dataset[2]))))
SI4.s3=gdata::read.xls(file.path(dataset_path, sub('\\.zip$', '', basename(downloaded_dataset[2])),'Helmstaedter_et_al_SUPPLinformation4.xlsx'), sheet=3)
message("Reading done")
    
    
In [25]:
    
head(SI4.s3)
    
    
In [26]:
    
saveRDS(SI4.s3,file=file.path(dataset_path,"SI4.s3.rds"))
    
In [27]:
    
# assign sorted typed id as used in the paper
attr(sk.uniq_temp,'df')$stypeid=0
attr(sk.uniq_temp,'df')$stypeid[match(SI4.s3$cell.ID.in.skeleton.db,attr(sk.uniq_temp,'df')$cellid)]=SI4.s3$sorted.type.ID..as.in.Type.Mx.
    
In [28]:
    
# Make classes for 
# 1:12 ganglion
# 13:57 amacrine
# 58:71 bipolar
df=attr(sk.uniq_temp,'df')
df$class=''
df<-within(df,class[stypeid%in%1:12]<-'ganglion')
df<-within(df,class[stypeid%in%13:57]<-'amacrine')
# narow 13-24
# wide: 25, 28, 30–32, 37, 39, 41, 47, 53 and 57
# medium: types 26, 27, 29, 33-36, 38, 40, 42–46, 48–52 and 54-57
# typo for that last 57?
df<-within(df,class[stypeid%in%58:71]<-'bipolar')
# I assume that these must be Muller glial cells
df<-within(df,class[stypeid%in%77]<-'glial')
df$class=factor(df$class)
df$subclass=''
df$subclass[df$stypeid%in%13:24]='narrow field'
df$subclass[df$stypeid%in%c(25, 28, 30:32, 37, 39, 41, 47, 53, 57)]='wide field'
df$subclass[df$stypeid%in%c(26, 27, 29, 33:36, 38, 40, 42:46, 48:52,54:57)]='medium field'
df$subclass=factor(df$subclass)
df$ntype=''
df$ntype[df$stypeid%in%c(33,51)]='starburst amacrine'
attr(sk.uniq_temp,'df')=df
    
In [29]:
    
saveRDS(sk.uniq_temp, file=file.path(dataset_path,'sk.uniq.rds'))
    
In [30]:
    
file.path(dataset_path,'sk.uniq.rds')
    
    
In [ ]:
    
    
In [33]:
    
load('/Users/sri/Documents/R/dev/nat.examples/03-helmstaedter2013/sk.uniq.rda')
    
In [34]:
    
str(sk.uniq[[1]])
    
    
In [35]:
    
str(sk.uniq_temp[[1]])
    
    
In [36]:
    
head(attr(sk.uniq_temp,'df'))
    
    
In [37]:
    
head(attr(sk.uniq,'df'))
    
    
In [38]:
    
all.equal(attr(sk.uniq,'df'),attr(sk.uniq_temp,'df'))
    
    
In [39]:
    
all.equal(sk.uniq,sk.uniq_temp, check.attributes = F)
    
    
In [ ]:
    
    
In [40]:
    
#install.packages("/Users/sri/Documents/R/dev/nat",repos = NULL, 
#type = "source",force=T)
    
In [41]:
    
library(nat)
    
    
In [42]:
    
#' Convert Helmstaedter's matlab skel format into nat::neuron objects
#' 
#' @description skel objects are my direct R translation of the matlab data
#'   provided by Briggman, Helmstaedter and Denk.
#' @param x A skel format neuron to convert
#' @param ... arguments passed to as.neuron
#' @return An object of class \code{neuron}
#' @seealso \code{\link{as.neuron}}
as.neuron.skel<-function(x, ...) {
  as.neuron(as.ngraph(x), ...)
}
    
In [43]:
    
#' Convert Helmstaedter's matlab skel format into nat::ngraph objects
#' 
#' @details \code{ngraph} objects are thin wrappers for \code{igraph::graph} 
#'   objects.
#'   
#'   This function always removes self edges (i.e. when a node is connected to 
#'   itself), which seem to be used as a placeholder in the Helmstaedter dataset
#'   when there are no valid edges.
#'   
#'   Isolated nodes are also removed by default (i.e. the nodes that are not
#'   connected by any edges.)
#' @param remove.isolated Whether or not to remove isolated nodes from the graph
#'   (see Details).
#' @inheritParams as.neuron.skel
#' @seealso \code{\link[nat]{ngraph}}, \code{\link{as.neuron.skel}}
as.ngraph.skel<-function(x, remove.isolated=TRUE, ...) {
  self_edges=x$edges[,1]==x$edges[,2]
  if(sum(self_edges)>0){
    if(sum(self_edges)==nrow(x$edges)){
      # there are only self edges - make a dummy empty edge matrix
      x$edges=matrix(nrow=0, ncol=2)
    } else {
      x$edges[!self_edges, , drop=FALSE]
    }
  }
  ng=ngraph(x$edges, vertexnames = seq_len(nrow(x$nodes)), xyz=x$nodes, ...)
  if(remove.isolated){
    isolated_vertices=igraph::V(ng)[igraph::degree(ng)==0]
    g=igraph::delete.vertices(graph=ng,isolated_vertices)
    ng=as.ngraph(g)
  }
}
    
In [44]:
    
options(nat.progress="none")
    
In [45]:
    
options(warn=-1)
skn=nlapply(sk.uniq_temp, as.neuron, OmitFailures = T, Verbose = FALSE)
options(warn=0)
    
In [46]:
    
class(skn[[1]])
    
    
In [47]:
    
#options(nat.plotengine = 'plotly')
#getOption('nat.plotengine')
    
In [48]:
    
library(htmlwidgets)
library(plotly)
library(IRdisplay)
    
    
In [54]:
    
clearplotlyscene()
tempval <- plot3d(skn[1:5], plotengine ='plotly', soma = TRUE)
#tempval$plotlyscenehandle
    
In [55]:
    
htmlwidgets::saveWidget(plotly::as_widget(tempval$plotlyscenehandle), 'helmstaedter2013_01.html')
IRdisplay::display_html(paste0('<iframe src="','helmstaedter2013_01.html" width=100%, height=500> frameborder="0" </iframe>'))
    
    
In [60]:
    
clearplotlyscene()
tempval <- plot3d(skn,ntype=='starburst amacrine',col=stypeid, plotengine = 'plotly', soma = TRUE, alpha = 0.5)
#tempval$plotlyscenehandle
    
In [61]:
    
htmlwidgets::saveWidget(plotly::as_widget(tempval$plotlyscenehandle), 'helmstaedter2013_02.html')
IRdisplay::display_html(paste0('<iframe src="','helmstaedter2013_02.html" width=100%, height=500> frameborder="0" </iframe>'))
    
    
In [ ]:
    
    
In [62]:
    
sessionInfo()
    
    
In [ ]: