Published
Edited
Aug 14, 2021
1 star
Insert cell
Insert cell
lif_neuron_ei = (nSteps, alpha, beta, excRate, inhRate, constantDrive) => {
// Simulate a leaky integrate and fire neuron. Nothing very special here, except that
// we use stdlib to generate Poisson variables.
let spikeTimes = [];
let v = 0.0;
let exc, inh = 0.0;
let dv = 0.0;
let vs = [];
for(var i = 0; i < nSteps; i++) {
if(v == 1) {
v = 0;
}
[exc, inh] = [excRate > 0 ? stdlib.base.random.poisson(excRate) : 0,
inhRate > 0 ? stdlib.base.random.poisson(inhRate) : 0];
dv = -beta * v + alpha * (exc - inh) + constantDrive;
v += dv;
if(v > 1) { // Fixed threshold at 1.0
spikeTimes.push(i);
// Reset the neuron;
v = 1;
}
vs.push(v)
}
return [spikeTimes, vs];
}
Insert cell
md`Double-check that calling lif_neuron_ei gives something reasonable`
Insert cell
lif_neuron_ei(1000, alpha, beta, excRate, inhRate);
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
eiChart = {
let margin = {top: 0, bottom: 0, left: 120, right: 300, buffer: 50};
let x = d3.scaleLinear().domain([0, maxT]).range([margin.left, width - margin.right]);
let y = d3.scaleLinear().domain([2, -5]).range([margin.top + 30, height - margin.bottom]);
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const nRepeats = 1;
//let r, u = [];
let xAxis = svg.append("g")
.attr("transform", `translate(0,${height - 50})`)
.call(d3.axisBottom(x).ticks(10).tickSizeOuter(0))
svg
.append("g")
.append("text")
.attr("x", margin.left + (width - margin.left - margin.right) / 2)
.attr("y", height - 10)
.attr("font-size", "14px")
.attr("text-anchor", "middle")
.attr("fill", "black")
.text(() => {return "Time (ms)"})
svg
.append("g")
.append("text")
.attr("x", width - (margin.right - margin.buffer - 10)/2 - 10)
.attr("y", height - 10)
.attr("font-size", "14px")
.attr("text-anchor", "middle")
.attr("fill", "black")
.text(() => {return "Interval (ms)"})
svg
.append("text")
.attr("x", 0)
.attr("y", 18)
.attr("text-anchor", "center")
.attr("fill", "black")
.text(() => {return "Spike train"})
svg
.append("text")
.attr("x", 0)
.attr("y", y(0) + 5)
.attr("fill", "grey")
.text(() => {return "0 voltage"})
svg
.append("text")
.attr("x", 0)
.attr("y", y(1) + 5)
.attr("fill", "red")
.text(() => {return "Threshold"})

svg
.append("text")
.attr("x", width - (margin.right - margin.buffer - 10)/ 2 - 10)
.attr("y", height/2 - 60)
.attr("fill", "#69b3a2")
.attr("text-anchor", "middle")
.text(() => {return "Inter spike intervals"})
let [r, u] = lif_neuron_ei(maxT, alpha, beta, excRate, inhRate, constantDrive);
let g = svg.append("g")
.attr("stroke", "black")
.selectAll("g")
.data(r)
.join("g")
.attr("transform", d => `translate(${x(d)})`);

// Create ticks for raster plots
g.append("line")
.attr("y1", 0)
.attr("y2", 20);
// Create line for u(t)
let line = d3.line()
.x(d => x(d.x))
.y(d => y(d.y));
g = svg.append("path")
.datum([{x: 0, y: 0}, {x: maxT, y:0}])
.attr("stroke", "lightgrey")
.attr("d", line)
g = svg.append("path")
.datum([{x: 0, y: 1}, {x: maxT, y:1}])
.attr("stroke", "red")
.attr("d", line)
line = d3.line()
.x((d, i) => x(i))
.y((d, i) => y(d));
let lineData = line(u);
g = svg
.append("path")
.datum(u)
.attr("d", line)
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 1)
// Calculate the histogram of spike timing deltas
let deltas = [];
for(var i = 0; i < r.length - 1; i++) {
deltas.push(r[i+1] - r[i]);
}
x = d3.scaleLinear()
.domain([0, 100])
.range([width - margin.right + margin.buffer, width - 10]);
svg.append("g")
.attr("transform", "translate(0," + (height - 50) + ")")
.call(d3.axisBottom(x));

// set the parameters for the histogram
var histogram = d3.histogram()
.value((x) => x) // I need to give the vector of value
.domain(x.domain()) // then the domain of the graphic
.thresholds(x.ticks(70)); // then the numbers of bins

// And apply this function to data to get the bins
var bins = histogram(deltas);

// Y axis: scale and draw:
y = d3.scaleLinear()
.range([0, height / 2]);
y.domain([0, d3.max(bins, function(d) { return d.length; })]); // d3.hist has to be called before the Y axis obviously
//svg.append("g")
// .call(d3.axisLeft(y));

// append the bar rectangles to the svg element
svg.selectAll("rect")
.data(bins)
.enter()
.append("rect")
.attr("x", 1)
.attr("transform", function(d) { return "translate(" + x(d.x0) + "," + (height - 50 - y(d.length)) + ")"; })
.attr("width", function(d) { return x(d.x1) - x(d.x0) -1 ; })
.attr("height", function(d) { return y(d.length); })
.style("fill", "#69b3a2")
return svg.node();
}
Insert cell
chart = {
//const svg = d3.create("svg").attr("viewBox", [0, 0, width, 200]);
const svg = d3.create("g");
svg.append("g").
append("circle").
attr("cx", 0).
attr("cy", 0).
attr("r", 10).
attr("fill", "black");

svg.append("g").
append("circle").
attr("cx", 200).
attr("cy", 200).
attr("r", 10).
attr("fill", "black");
return svg.node();
}
Insert cell
eiChart2 = {
let margin = {top: 0, bottom: 0, left: 120, right: 300, buffer: 50};
let x = d3.scaleLinear().domain([0, maxT]).range([margin.left, width - margin.right]);
let y = d3.scaleLinear().domain([10, -10]).range([margin.top + 30, height - margin.bottom]);
let w = 200;
let h = 200;
const svg = d3.create("svg").attr("width", w).attr("height", h).attr("viewBox", [0, 0, w, h]);
const nRepeats = 1;

svg.append("g").
append("circle").
attr("cx", 0).
attr("cy", 0).
attr("r", 10).
attr("fill", "black");

svg
.append("g")
.append("text")
.attr("x", width - (margin.right - margin.buffer - 10)/2 - 10)
.attr("y", height - 10)
.attr("font-size", "14px")
.attr("text-anchor", "middle")
.attr("fill", "black")
.text(() => {return "Interval (ms)"})

svg
.append("text")
.attr("x", width - (margin.right - margin.buffer - 10)/ 2 - 10)
.attr("y", height/2 - 60)
.attr("fill", "#69b3a2")
.attr("text-anchor", "middle")
.text(() => {return "Inter spike intervals"})
let [r, u] = lif_neuron_ei(maxT, alpha, beta, excRate, inhRate);
// Calculate the histogram of spike timing deltas
let deltas = [];
for(var i = 0; i < r.length - 1; i++) {
deltas.push(r[i+1] - r[i]);
}
x = d3.scaleLinear()
.domain([0, 100])
.range([0, w]);
svg.append("g")
.attr("transform", "translate(0," + (h - 10) + ")")
.call(d3.axisBottom(x));

// set the parameters for the histogram
var histogram = d3.histogram()
.value((x) => x) // I need to give the vector of value
.domain(x.domain()) // then the domain of the graphic
.thresholds(x.ticks(70)); // then the numbers of bins

// And apply this function to data to get the bins
var bins = histogram(deltas);

// Y axis: scale and draw:
y = d3.scaleLinear()
.range([0, height / 2]);
y.domain([0, d3.max(bins, function(d) { return d.length; })]); // d3.hist has to be called before the Y axis obviously
//svg.append("g")
// .call(d3.axisLeft(y));

// append the bar rectangles to the svg element
svg.selectAll("rect")
.data(bins)
.enter()
.append("rect")
.attr("x", 1)
.attr("transform", function(d) { return "translate(" + x(d.x0) + "," + (height - 50 - y(d.length)) + ")"; })
.attr("width", function(d) { return x(d.x1) - x(d.x0) -1 ; })
.attr("height", function(d) { return y(d.length); })
.style("fill", "#69b3a2")

svg.attr("id", "histogram");
return svg;
}
Insert cell
eichart3 = {
const svg = d3.create("svg").attr("width", width).attr("height", height).attr("viewBox", [0, 0, width, height]);
//eiChart2.attr("attr("transform", "translate(0, 0)");
svg.node().append(eiChart2.node());
svg.select("#eiChart2").attr("transform", "translate(0, 0)");
return svg.node();
}

Insert cell
domnode = {
return d3.create("svg");
}
Insert cell
Insert cell
height = 400;
Insert cell
maxT = 1000;
Insert cell
stdlib =require("https://unpkg.com/@stdlib/stdlib@0.0.32/dist/stdlib-flat.min.js")
Insert cell
stdlib
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more