How to use the natverse suite of neuroanatomy tools (written in R) to access and analyse data from the largest connectomics project to date, the 'hemibrain' project from HHMI Janelia's Fly EM.
2. What can we do with
hemibrain data? A partial
(~35%) connectome but
the largest to date, with
morphologies
21,662 ~full neurons
4,495 cut neurons
67,475 unassigned fragments
9.5M presynapses
64M postsynapses
~35% connectivity completion
3. What can we do with
hemibrain data? A partial
(~35%) connectome but
the largest to date, with
morphologies
4. We can interact with it via
neuPrint, a database and
analysis ecosystem for
connectomics with a web
interface and API access
5. Further, we can use the
natverse! Specifically, we
can use its package
neuprintr to access
neuPrint's API endpoints
11. And now you are in! To
access the neuPrint API
programmatically you will
need to use your token. Go
to account
12. And you will see this page.
You token will be a long
string of numbers, symbols
and letters. This token is
only an example
asBatEsiOIJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFsZXhhbmRlci5zaGFrZWVsLmJhdGVzQGdtYWlsLmN
vbSIsImxldmVsIjoicmVhZHdyaXRlIiwiaW1hZ2UtdXJsIjoiaHR0cHM7Ly9saDQuZ29vZ2xldXNlcmNvbnRlbnQuY2
9tLy1QeFVrTFZtbHdmcy9BQUFBQUFBQUFBDD9BQUFBQUFBQUFBQS9BQ0hpM3JleFZMeEI4Nl9FT1asb0dyMn
V0QjJBcFJSZlBRL21vL3Bob3RvLapwZz9zej01MCIsImV4cCI6MTczMjc1MjU2HH0.jhh1nMDBPl5A1HYKcszXM51
8NZeAhZG9jKy3hzVOWEU
13. You can build custom
queries in the web browser
to find neurons and their
connectivity.
14. These queries send a
message to a Neo4j
database, asking ito return
the right data, using a
cypher.
15. By clicking the 'I' button
you can view the cypher
that has been sent to this
database..
16. By clicking the 'I' button
you can view the cypher
that has been sent to this
database.
https://neo4j.com/develop
er/cypher-query-language/
18. MATCH (m:`hemibrain_Meta`) WITH m.superLevelRois AS rois MATCH (neuron :`hemibrain_Neuron`) WHERE
(neuron.`LH(R)`= true) AND (neuron.`AL(R)`= true) RETURN neuron.bodyId AS bodyid, neuron.instance AS
bodyname, neuron.type AS bodytype, neuron.status AS neuronStatus, neuron.roiInfo AS roiInfo, neuron.size
AS size, neuron.pre AS npre, neuron.post AS npost, rois ORDER BY neuron.bodyId
19. Now we know
neuPrint, let's look to
the natverse and its
package neuprintr
http://natverse.org/
20. The
natverse is
a suite of R
tools for
getting and
analysing
neuron
data. It can
be used to
look at
synaptic
neuron
data, and
can pull
from both
CATMAID
and neuPrint
The R
package
neuprintr
has been
developed
to interact
with
neuPrint. It
can use the
available
API
endpoints
and also
send custom
cyphers
21. In order to
use the
natverse,
you will
need the
latest
versions of R
and R
Studio.
Details on
prerequisites
and
detailed
installation
here:
http://natver
se.org/nat/a
rticles/Install
ation.html
Can interact
with other
languages.
For
example,
the python
library
navis works
similarly
(https://gith
ub.com/schl
egelp/navis)
22. Install the natverse and neuprintr
install.packages(c("usethis", "devtools"))
usethis::browse_github_pat()
usethis::edit_r_environ() # Optionally connect to your github account,
# in order to avoid API rate limits
# then paste your your personal access token to your Renviron file
# I.e. by adding adding the following line, followed by a blank line:
# GITHUB_PAT= your_personal_access_token_here
.rs.restartR()
devtools::install_github("natverse/natverse") # install all packages of
# the natverse with one line
library(natverse) # load all packages of the natverse
devtools::install_github("natverse/neuprintr") # or install/update just
# neuprintr
library(neuprintr)
23. Get to grips with the
natverse by
exploring our
tutorials
http://natverse.org/
https://github.com/natverse/nat.examples
24. Get to grips with
neuprintr with our
vignettes and
example
http://natverse.org/neuprintr/articles/hemib
rain_opns.html
https://github.com/natverse/nat.examples
25. The anatomy of a neuprintr function
neuprint_get_neuron_names <- function(bodyids, dataset = NULL, all_segments =
FALSE, conn = NULL, ...) {
all_segments.json = ifelse(all_segments,"Segment", "Neuron")
cypher = sprintf("WITH %s AS bodyIds UNWIND bodyIds AS bodyId MATCH (n:`%s`)
WHERE n.bodyId=bodyId RETURN n.instance AS name",
id2json(bodyids),
all_segments.json)
nc = neuprint_fetch_custom(cypher=cypher, conn = conn, dataset = dataset, ...)
d = unlist(lapply(nc$data,nullToNA))
names(d) = bodyids
d
}
It is a great idea to wrap your queries in a function. This will make
your code cleaner and more reusable. you should just be able to
edit this example without worrying about the details.
26. The anatomy of a neuprintr function
neuprint_get_neuron_names <- function(bodyids, dataset = NULL, all_segments =
FALSE, conn = NULL, ...) {
all_segments.json = ifelse(all_segments,"Segment", "Neuron")
cypher = sprintf("WITH %s AS bodyIds UNWIND bodyIds AS bodyId MATCH (n:`%s`)
WHERE n.bodyId=bodyId RETURN n.instance AS name",
id2json(bodyids),
all_segments.json)
nc = neuprint_fetch_custom(cypher=cypher, conn = conn, dataset = dataset, ...)
d = unlist(lapply(nc$data,nullToNA))
names(d) = bodyids
d
}
In order to make a query, you need to specify which neuPrint
server you want to talk to, and dataset. Usually you will not need to
do anything as this will be handled by a one time user setting to
specify their preferred server, dataset and authentication token.
27. The anatomy of a neuprintr function
neuprint_get_neuron_names <- function(bodyids, dataset = NULL, all_segments =
FALSE, conn = NULL, ...) {
all_segments.json = ifelse(all_segments,"Segment", "Neuron")
cypher = sprintf("WITH %s AS bodyIds UNWIND bodyIds AS bodyId MATCH (n:`%s`)
WHERE n.bodyId=bodyId RETURN n.instance AS name",
id2json(bodyids),
all_segments.json)
nc = neuprint_fetch_custom(cypher=cypher, conn = conn, dataset = dataset, ...)
d = unlist(lapply(nc$data,nullToNA))
names(d) = bodyids
d
}
Internally neuprint_fetch_custom, which will look after the dataset
argument, and then go on to call the low level neuprint_fetch,
which will ensure that the connection object is valid. It sends a
POST request to the neuPrint server, and gives us its response.
28. The anatomy of a neuprintr function
neuprint_get_neuron_names <- function(bodyids, dataset = NULL, all_segments =
FALSE, conn = NULL, ...) {
all_segments.json = ifelse(all_segments,"Segment", "Neuron")
cypher = sprintf("WITH %s AS bodyIds UNWIND bodyIds AS bodyId MATCH (n:`%s`)
WHERE n.bodyId=bodyId RETURN n.instance AS name",
id2json(bodyids),
all_segments.json)
nc = neuprint_fetch_custom(cypher=cypher, conn = conn, dataset = dataset, ...)
d = unlist(lapply(nc$data,nullToNA))
names(d) = bodyids
d
}
This function takes one or more bodyids as input and returns the
name of the neurons. Bodyids typically come in as either character
vector or numeric format. The internal function id2json() will look
after formatting them appropriately for the query
29. The anatomy of a neuprintr function
neuprint_get_neuron_names <- function(bodyids, dataset = NULL, all_segments =
FALSE, conn = NULL, ...) {
all_segments.json = ifelse(all_segments,"Segment", "Neuron")
cypher = sprintf("WITH %s AS bodyIds UNWIND bodyIds AS bodyId MATCH (n:`%s`)
WHERE n.bodyId=bodyId RETURN n.instance AS name",
id2json(bodyids),
all_segments.json)
nc = neuprint_fetch_custom(cypher=cypher, conn = conn, dataset = dataset, ...)
d = unlist(lapply(nc$data,nullToNA))
names(d) = bodyids
d
}
Many functions that operate on neurons will have an argument
(all_segments) controlling whether they operate only for larger
objects (Neuron) or also on fragments (Segment). Restricting
queries to Neuron can result in big speed-ups.
30. The anatomy of a neuprintr function
neuprint_get_neuron_names <- function(bodyids, dataset = NULL, all_segments =
FALSE, conn = NULL, ...) {
all_segments.json = ifelse(all_segments,"Segment", "Neuron")
cypher = sprintf("WITH %s AS bodyIds UNWIND bodyIds AS bodyId MATCH (n:`%s`)
WHERE n.bodyId=bodyId RETURN n.instance AS name",
id2json(bodyids),
all_segments.json)
nc = neuprint_fetch_custom(cypher=cypher, conn = conn, dataset = dataset, ...)
d = unlist(lapply(nc$data,nullToNA))
names(d) = bodyids
d
}
In this function, cypher is the actual query written in the
Cypher query language. As you can see this step uses the sprintf
function to interpolate variables into a string.
31. The anatomy of a neuprintr function
neuprint_get_neuron_names <- function(bodyids, dataset = NULL, all_segments =
FALSE, conn = NULL, ...) {
all_segments.json = ifelse(all_segments,"Segment", "Neuron")
cypher = sprintf("WITH %s AS bodyIds UNWIND bodyIds AS bodyId MATCH (n:`%s`)
WHERE n.bodyId=bodyId RETURN n.instance AS name",
id2json(bodyids),
all_segments.json)
nc = neuprint_fetch_custom(cypher=cypher, conn = conn, dataset = dataset, ...)
d = unlist(lapply(nc$data,nullToNA))
names(d) = bodyids
d
}
The results that come back from neuprint_fetch_custom are
typically in a big list object. For simple results, you can just unlist this
to make a vector. A function nullToNA is first applied in order to
ensure that missing values come back as NA.
32. Let's now go through
an example that
looks at olfactory
projection neurons
http://natverse.org/neuprintr/articles/hemib
rain_opns.html
33. Connect to neuPrint via R
install.packages(c("usethis", "devtools"))
usethis::browse_github_pat()
usethis::edit_r_environ() # Optionally connect to your github account,
# in order to avoid API rate limits
# then paste your your personal access token to your Renviron file
# I.e. by adding adding the following line, followed by a blank line:
# GITHUB_PAT= your_personal_access_token_here
.rs.restartR()
devtools::install_github("natverse/natverse") # install all packages of
# the natverse with one line
library(natverse) # load all packages of the natverse
devtools::install_github("natverse/neuprintr") # or install/update just
# neuprintr
library(neuprintr)
34. Connect to neuPrint
## example explicitly specifying connection options
conn = neuprint_login(server= "neuprint.janelia.org", token=
"asBatEsiOIJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFsZXhhbmRlci5za
GFrZWVsLmJhdGVzQGdtYWlsLmNvbSIsImxldmVsIjoicmVhZHdyaXRlIiwiaW1hZ2UtdXJsIj
oiaHR0cHM7Ly9saDQuZ35vZ2xldXNlcmNvbnRlbnQuY29tLy1QeFVrTFZtbHdmcy9BQUFBQUF
BQUFBDD9BQUFBQUFBQUFBQS9BQ0hpM3JleFZMeEI4Nl9FT1asb0dyMnV0QjJBcFJSZlBRL21v
L3Bob3RvLapwZz9zej01MCIsImV4cCI6MTczMjc1MjM2HH0.jhh1nMDBPl5A1HYKcszXM518NZ
eAhZG9jKy3hzVOWEU")# this is a non-functional example token
## examples assuming that neuprint_* environment variables/options are set
conn = neuprint_login()
35. Set up some defaults in your R environ
Usethis::edit_r_environ() # use this to edit your environment file directly
## Add these lines to your file:
neuprint_server = "https://neuprint.janelia.org"
neuprint_token =
"asBatEsiOIJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFsZXhhbmRlci5zaGFrZWVsLmJhdG
VzQGdtYWlsLmNvbSIsImxldmVsIjoicmVhZHdyaXRlIiwiaW1hZ2UtdXJsIjoiaHR0cHM7Ly9saDQ
uZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1QeFVrTFZtbHdmcy9BQUFBQUFBQUFBDD9BQUFBQUF
BQUFBQS9BQ0hpM3JleFZMeEI4Nl9FT1asb0dyMnV0QjJBcFJSZlBRL21vL3Bob3RvLapwZz9zej0
1MCIsImV4cCI6MTczMjc1MjU2HH0.jhh1nMDBPl5A1HYKcszXM518NZeAhZG9jKy3hzVOWEU"
neuprint_dataset = "hemibrain:v1.0"
# Leave a space at the end of the file
# Restart R
.rs.restartR()
36. You may want to change your default
dataset in the future, for now hemibrain
Usethis::edit_r_environ() # use this to edit your environment file directly
## Add these lines to your file:
neuprint_server = "https://neuprint.janelia.org"
neuprint_token =
"asBatEsiOIJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFsZXhhbmRlci5zaGFrZWVsLmJhdG
VzQGdtYWlsLmNvbSIsImxldmVsIjoicmVhZHdyaXRlIiwiaW1hZ2UtdXJsIjoiaHR0cHM7Ly9saDQ
uZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1QeFVrTFZtbHdmcy9BQUFBQUFBQUFBDD9BQUFBQUF
BQUFBQS9BQ0hpM3JleFZMeEI4Nl9FT1asb0dyMnV0QjJBcFJSZlBRL21vL3Bob3RvLapwZz9zej0
1MCIsImV4cCI6MTczMjc1MjU2HH0.jhh1nMDBPl5A1HYKcszXM518NZeAhZG9jKy3hzVOWEU"
neuprint_dataset = "hemibrain:v1.0"
# Leave a space at the end of the file
# Restart R
.rs.restartR()
37. Let's check you are logged in
## See whether this simple function works for you:
available.datasets = neuprint_datasets()
available.datasets
38. Great – now install some other packages
we will use in the following examples
# install
if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager")
if(!require('ComplexHeatmap')) BiocManager::install("ComplexHeatmap")
if(!require('ggnetwork')) install.packages("ggnetwork")
if(!require('network')) install.packages("network")
# load
library(natverse)
library(neuprintr)
library(dendroextras)
library(ComplexHeatmap)
library(ggnetwork)
library(network)
39. And let's not make ugly things. Let's set up
some nice colours
## some nice colors!! Inspired by LaCroixColoR
lacroix = c("#C70E7B", "#FC6882", "#007BC3", "#54BCD1", "#EF7C12", "#F4B95A",
"#009F3F", "#8FDA04", "#AF6125", "#F4E3C7", "#B25D91", "#EFC7E6",
"#EF7C12", "#F4B95A", "#C23A4B", "#FBBB48", "#EFEF46", "#31D64D",
"#132157","#EE4244", "#D72000", "#1BB6AF")
names(lacroix) = c("purple", "pink",
"blue", "cyan",
"darkorange", "paleorange",
"darkgreen", "green",
"brown", "palebrown",
"mauve", "lightpink",
"orange", "midorange",
"darkred", "darkyellow",
"yellow", "palegreen",
"navy","cerise",
"red", "marine")
41. Get information on olfactory projection
neurons in the hemibrain data
### Let's find some in our HemiBrain data:
opn.info = neuprint_search(".*mPN1.*")
opn.info[!is.na(opn.info$type),"type"] = opn.info[!is.na(opn.info$type),"name"]
rownames(opn.info) = opn.info$bodyid
#### Add AL glomerulus information from the name
name.split = strsplit(opn.info$name,split=c("(|_"))
gloms = sapply(name.split, function(x) tryCatch(x[[2]], error = function(e) ""))
opn.info$glomerulus = gloms
opn.info = subset(opn.info, glomerulus!="")
#### so there seem to be
print(length(gloms))
#### OPNs and and
print(length(unique(gloms)))
#### OPNs with unique glomerulus innervations
View(opn.info)
42. Use the bodyIds we have found to read a
neuron skeleton from neuPrint
## Let's quickly read one neuron, and have a look at it!
opn = neuprint_read_neuron(opn.info$bodyid[1])
### visualise:
nopen3d()
plot3d(opn, WithConnectors = TRUE, col = lacroix[["brown"]], lwd = 2)
43. Use the bodyIds we have found to read
neuron skeletons from neuPrint
## Now that we have all of the bodyIds, we can read these neurons from neuPrint:
opns = neuprint_read_neurons(opn.info$bodyid)
nopen3d()
plot3d(opns, col = sample(lacroix,length(opns), replace = TRUE), lwd = 2)
44. What information can we fetch
separately?
### Why is this function so slow?
### Because it fetches fragmented neuron skeletons assigned to the same neuron
### Stitched them into one neuron, grabs all the neuron's synapses
### and tries to work out where the soma is. If you want to move faster
### You can grab bits separately and quickly:
?neuprint_read_neuron_simple
?neuprint_get_synapses
?neuprint_assign_connectors
?neuprint_locate_soma
?neuprint_get_neuron_names
?neuprint_get_meta
### Try:
neuprint_get_meta(c(818983130, 1796818119))
45. Fetch bodyIds by brain region
### The regions of interest available are:
rois = sort(neuprint_ROIs())
rois
## We don't we try fetching all of the neurons in a glomerulus of the antennal lobe?
ca.info = neuprint_find_neurons(
input_ROIs = "CA(R)",
output_ROIs = NULL,
all_segments = FALSE # if true, fragments smaller than 'neurons' are returned as well
)
## So how many neurons is that?
print(nrow(ca.info))
## A lot! But what about that pesky load of Kenyon cells
ca.info = subset(ca.info, !is.na(bodyname) & neuronStatus == "Traced")
ca.info = ca.info[!grepl("KC",ca.info$bodyname),]
## So how many neurons is that?
print(nrow(ca.info))
47. Let's get an mesh3d object for the
antennal lobe (AL)
## Let's get some neuropil volume data from neuPrint!
### First, we gotta see what is available:
rois
# Read in the AL mesh!
al.mesh = neuprint_ROI_mesh(roi = "AL(R)")
nopen3d()# set view
plot3d(al.mesh, add = TRUE, alpha = 0.1, col = lacroix[["orange"]])
48. Let's get an mesh3d object for the main
olfactory neuropils
# And get the other main olfactory neuropils
ca.mesh = neuprint_ROI_mesh(roi = "CA(R)")
lh.mesh = neuprint_ROI_mesh(roi = "LH(R)")
malt.mesh = neuprint_ROI_mesh(roi = "mALT(R)")
plot3d(ca.mesh, add = TRUE, alpha = 0.3, col = lacroix[["pink"]])
plot3d(lh.mesh, add = TRUE, alpha = 0.3, col = lacroix[["green"]])
plot3d(malt.mesh, add = TRUE, alpha = 0.9, col = "grey30")
# save images as .png
rgl.snapshot(filename = "images/hemibrain_olfactory_neuropils.png", fmt ="png")
49.
50. Plot meshes and neurons together
# And get the other main olfactory neuropils
nopen3d()
plot3d(al.mesh, add = TRUE, alpha = 0.5, col = "grey")
plot3d(ca.mesh, add = TRUE, alpha = 0.5, col = "grey")
plot3d(lh.mesh, add = TRUE, alpha = 0.5, col = "grey")
plot3d(opns, col = sample(lacroix,length(opns), replace = TRUE), lwd = 2)
52. And now the really exciting bit! How do
these neurons connect to each other?
## We are looking at connectivity between OPNs.
### We can get an adjaceny matrix between all of these OPNs
opn.adj = neuprint_get_adjacency_matrix(bodyids = opn.info$bodyid)
rownames(opn.adj.comp) = colnames(opn.adj.comp) = opn.info$glomerulus
opn.adj.comp = t(apply(t(opn.adj.comp), 2, function(x) tapply(x,
colnames(opn.adj.comp), sum, na.rm = TRUE)))
opn.adj.comp = apply(opn.adj.comp, 2, function(x) tapply(x, rownames(opn.adj.comp),
sum, na.rm = TRUE))
Heatmap(opn.adj.comp, col = my_palette)
53. And now the really exciting bit! How do
these neurons connect to each other?
54. Other ways to look at connectivity
## What about OPN connectivity to neurons not in this set of OPNs?
### First, is there a common partner to all OPNs?
common = neuprint_common_connectivity(opn.info$bodyid, prepost = "PRE")
### could use 'post' for downstream
dim(common)
### What about the food hub PNs?
### The glomerulus DM1 is interesting, because it is involved in an axo-axonic
### 'food odour' related community in the lateral horn (Bates & Schlegel et al. 2020)
DM1.opn.info = subset(opn.info, grepl("DM1|DM3|DM4|VM3|VA4",name))
DM1.common = neuprint_common_connectivity(DM1.opn.info$bodyid, prepost = "PRE")
dim(DM1.common)
DM1.common.meta = neuprint_get_meta(colnames(DM1.common)) # what are they?
View(DM1.common.meta) # Huhh, local neurons, the APL and some LH stuff
55. Other ways to look at connectivity
## We can also get all of the neurons in the database that connect to the
### query neurons, either upstream or downstream of them
DM1.opn.connected = neuprint_connection_table(DM1.opn.info$bodyid, prepost = "POST")
### In which brain region are these partners?
table(DM1.opn.connected$roi)
56. Other ways to look at connectivity
## Let's have a look at what the strongest downstream partners look like
DM1.opn.connected.strong = subset(DM1.opn.connected,weight>100, prepost = "POST")
DM1.targets = neuprint_read_neurons(DM1.opn.connected.strong$partner)
nopen3d()
plot3d(DM1.targets, lwd = 2, col = sample(lacroix,length(DM1.targets),replace=TRUE))
View(DM1.targets[,])
57. Other ways to look at connectivity
## So there are three lateral horn neuron targets of the axon there
### c("359214479", "359891881", "511616870"), found using nat::find.neuron
### Let's move forward with those
lhns = c(359214479, 359891881, 511616870)
lhn.cols = c(lacroix[["marine"]],lacroix[["blue"]],lacroix[["green"]])
names(lhn.cols) = DM1.targets[lhns,"type"]
lh.targets = DM1.targets[lhns]
clear3d()
plot3d(lh.targets, lwd = 2, col = c(lacroix[["marine"]],
lacroix[["blue"]],
lacroix[["green"]]))
plot3d(subset(opns,grepl("DM1",name)),lwd=2,col=lacroix[["orange"]])
58. Let's make a network graph to see how
different OPNs can reach these LHNs
### Which other OPNs impinge on it?, vwhatever path?
shortest.paths = data.frame()
for(lhn in lhns){
for(b in opn.info$bodyid){ # PN -> LHN only
sp = neuprint_get_shortest_paths(body_pre = b, body_post = lhn, weightT = 10)
dupe = ifelse( is.na(which(duplicated(sp$to))[1]),nrow(sp),which(duplicated(sp$to))[1])
shortest = sp[1:dupe,]
if(nrow(shortest)>0 & nrow(shortest)<5 ){
shortest$order.to = paste(1:nrow(shortest), nrow(shortest), sep = "/")
shortest$order.from = paste(1:nrow(shortest)-1, nrow(shortest), sep = "/")
shortest[1,"order.from"] = opn.info[as.character(b),"glomerulus"]
shortest[nrow(shortest),"order.to"] = DM1.targets[lhn,"type"]
shortest.paths = rbind(shortest.paths, shortest)
}
}
}
59. Let's make a network graph to see how
different OPNs can reach these LHNs
paths = aggregate(list(weight = shortest.paths$weight), list(order.from =
shortest.paths$order.from, order.to = shortest.paths$order.to), sum)
n = network(paths, matrix.type = "edgelist", ignore.eval = FALSE, layout =
"fruchtermanreingold", names.eval = "weight", directed = TRUE)
n = ggnetwork(n, cell.jitter = 0.75, arrow.gap = 0.01)
# Set colours
orders = unique(c(paths$order.to,paths$order.from))
order.cols = rep("grey30",length(orders))
names(order.cols) = orders
gloms = unique(opn.info$glomerulus)
opn.cols = rep(lacroix[["orange"]],length(gloms))
names(opn.cols) = gloms
opn.cols =
c(opn.cols,lhn.cols,order.cols[!names(order.cols)%in%c(names(lhn.cols),names(opn.cols))])
60. Let's make a network graph to see how
different OPNs can reach these LHNs
# Plot
ggplot(n, aes(x = x, y = y, xend = xend, yend = yend)) +
geom_edges(aes(color = vertex.names),
curvature = 0.05,
arrow = arrow(length = unit(6, "pt"),
type = "closed")) +
geom_nodes(aes(color = vertex.names, size = 6)) +
geom_edgetext(aes(label = weight, color = vertex.names), fill = NA) +
geom_nodelabel_repel(aes(color = vertex.names, label = vertex.names),
fontface = "bold", box.padding = unit(1, "lines")) +
scale_color_manual(values = opn.cols) +
scale_fill_manual(values = opn.cols) +
theme_blank() +
guides(color = FALSE, shape = FALSE, fill = FALSE, size = FALSE, linetype = FALSE) + ylab("") +
xlab("")
61. Let's make a network graph to see how
different OPNs can reach these LHNs
62. That's it for now! If something is
broken or you want to suggest
a new feature, contact us
preferably by making an issue
on GitHub
https://github.com/natverse/neuprintr/issues