Skip to content

Instantly share code, notes, and snippets.

@OMHouston
Last active April 20, 2017 13:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OMHouston/ada82602ae73c9017cbd6495934faab8 to your computer and use it in GitHub Desktop.
Save OMHouston/ada82602ae73c9017cbd6495934faab8 to your computer and use it in GitHub Desktop.
Data-Driven Neural Network

This diagram uses d3-force to create a neural network that shows where information from classes of cells goes within a small subsection of the brainstem.

The locations displayed are the cochlear (inner ear) and the 3 cochlear nuclei (within the brainstem). Each node represents a cell-type and the known links between them. Other links may exist, but are not clearly documented.

The lonely looking marker in the base of the DCN represents cartwheel-cell to cartwheel-cell synapses.

{
"locations": [
{"name": "Cochlear", "id": 1},
{"name": "Dorsal Cochlear Nucleus", "id": 2},
{"name": "Anteroventral Cochlear Nucleus", "id": 3},
{"name": "Posteroventral Cochlear Nucleus", "id": 4}
],
"cells": [
{"id": "Inner Hair Cell", "location": 1},
{"id": "Outer Hair Cell", "location": 1},
{"id": "Type I SGN", "location": 1},
{"id": "Type II SGN", "location": 1},
{"id": "Pyramidal", "location": 2},
{"id": "Stellate", "location": 2},
{"id": "Cartwheel", "location": 2},
{"id": "Unipolar Brush", "location": 2},
{"id": "Golgi", "location": 2},
{"id": "Granule", "location": 2},
{"id": "Giant", "location": 2},
{"id": "Tuberculoventral", "location": 2},
{"id": "Spherical", "location": 3},
{"id": "Globular", "location": 3},
{"id": "T-Stellate", "location": 3},
{"id": "D-Stellate", "location": 3},
{"id": "Planar","location": 4},
{"id": "Octopus","location": 4},
{"id": "Radiate","location": 4}
],
"links": [
{"source": "Inner Hair Cell", "target": "Type I SGN", "type": "E"},
{"source": "Outer Hair Cell", "target": "Type II SGN", "type": "E"},
{"source": "Type I SGN", "target": "Pyramidal", "type": "E"},
{"source": "Type I SGN", "target": "Tuberculoventral", "type": "E"},
{"source": "Pyramidal", "target": "Stellate", "type": "E"},
{"source": "Granule", "target": "Cartwheel", "type": "E"},
{"source": "Stellate", "target": "Cartwheel", "type": "I"},
{"source": "Cartwheel", "target": "Cartwheel", "type": "I"},
{"source": "Granule", "target": "Unipolar Brush", "type": "E"},
{"source": "Unipolar Brush", "target": "Granule", "type": "E"},
{"source": "Cartwheel", "target": "Giant", "type": "I"},
{"source": "Type I SGN", "target": "Spherical", "type": "E"},
{"source": "Type I SGN", "target": "Globular", "type": "E"},
{"source": "Type I SGN", "target": "T-Stellate", "type": "E"},
{"source": "D-Stellate", "target": "T-Stellate", "type": "I"},
{"source": "Type I SGN", "target": "Planar", "type": "E"},
{"source": "Type I SGN", "target": "Radiate", "type": "E"},
{"source": "Type I SGN", "target": "Octopus", "type": "E"},
{"source": "T-Stellate", "target": "Pyramidal", "type": "I"},
{"source": "Cartwheel", "target": "Pyramidal", "type": "I"},
{"source": "Tuberculoventral", "target": "Pyramidal", "type": "I"},
{"source": "Tuberculoventral", "target": "T-Stellate", "type": "I"}
]
}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<style>
.links line {
stroke: #999;
stroke-opacity: 0.5;
}
.nodes circle {
stroke: #000;
stroke-width: 1px;
stroke-opacity:0.5;
}
.locations circle {
fill-opacity: 0.2;
stroke: #000;
stroke-width: 1px;
}
.nodes .node-mouseover {
cursor: pointer;
stroke: #000;
stroke-width: 1px;
}
.tooltip {
position:absolute;
font: 14px sans-serif;
background-color:#ccc;
border: solid 1px #aaa;
border-radius:3px;
padding:5px;
}
</style>
</head>
<body>
<div id="chart"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var width = 640,
height = 300;
var svg = d3.select("#chart")
.append("svg")
.attr("width", width)
.attr("height", height);
var color = d3.scaleOrdinal(d3.schemeCategory20);
var popup = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
d3.json("cncells.json", function(error, graph) {
if (error) throw error;
var xPoint = d3.scalePoint()
.domain(graph.locations.map(function(d) {return d.id}))
.range([100, width - 100]);
var locations = svg.append("g")
.attr("class", "locations")
.selectAll("circle")
.data(graph.locations)
.enter()
.append('circle')
.attr('cx', function(d) { return xPoint(d.id) })
.attr('cy', function(d) {
return d.id % 2 === 1 ? height/4 : height/2;
})
.attr('r', 60)
.attr('fill', function(d) { return color(d.id) })
.on("mouseover", loc("over"))
.on("mouseout",loc("out"));;
locations.append("title")
.text(function(d) { return d.name; });
svg.append("svg:defs").selectAll("marker")
.data(["end"])
.enter().append("svg:marker")
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 20)
.attr("refY", 0)
.attr("markerWidth", 3)
.attr("markerHeight", 3)
.attr("orient", "auto")
.attr("fill", "#999")
.attr("fill-opacity", 0.6)
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", 2)
.attr("marker-end", "url(#end)");
var nodes = svg.append("g")
.attr("class", "nodes")
.selectAll("circles")
.data(graph.cells)
.enter()
.append('circle')
.attr('r', 6)
.attr('fill', function(d,i) { return color(d.location); })
.on("mouseover", fade(.1,"over"))
.on("mouseout",fade(.5,"out"));
var position = d3.forceSimulation(nodes)
.force('x', d3.forceX((d) => xPoint(d.location)).strength(0.8))
.force('y', d3.forceY(function(d) {
return d.location % 2 === 1 ? height/4: height/2
}).strength(0.4))
.force("collide", d3.forceCollide(16));
position.nodes(graph.cells)
.on('tick', function() {
nodes
.attr('transform', (d) => {
return 'translate(' + (d.x) + ',' + (d.y) + ')';
});
});
var simulation = d3.forceSimulation(graph.links)
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody());
simulation
.nodes(graph.cells)
.on("tick", ticked);
simulation.force("link")
.links(graph.links)
.strength(0);
function ticked() {
link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; })
};
var linkedByIndex = {};
graph.links.forEach(function(d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
}
function fade(opacity,event) {
return function(d) {
if (event === "over") {
popup.transition()
.duration(100)
.style("opacity", .9);
popup.html("cell: " + d.id)
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY - 20) + "px");
d3.select(this).classed("node-mouseover", true);
} else
if (event === "out") {
popup.transition()
.duration(100)
.style("opacity", 0);
d3.select(this).classed("node-mouseover", false);
}
nodes.style("stroke-opacity", function(o) {
var thisOpacity = isConnected(d, o) ? 1 : opacity;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.style("stroke-opacity", function(o) {
return o.source === d || o.target === d ? 1 : opacity; });
if (event === "out") {
link.style("stroke-opacity", opacity);
nodes.style("fill-opacity", 1);
nodes.style("stroke-opacity", 0.5);
}
}
}
function loc(event) {
return function(d) {
if (event === "over") {
popup.transition()
.duration(100)
.style("opacity", .9);
popup.html("location: " + d.name)
.style("left", (d3.event.pageX + 20) + "px")
.style("top", (d3.event.pageY - 20) + "px");
d3.select(this).classed("node-mouseover", true);
} else
if (event === "out") {
popup.transition()
.duration(100)
.style("opacity", 0);
d3.select(this).classed("node-mouseover", false);
}
}
}
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment