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 [ ]: