Published
Edited
May 21, 2021
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
n_steps = 300
Insert cell
experiments_parameters = ({
beta: [0.3, 0.3, 0.3],
gamma: [0.01],
theta: [0.001],
delta: [0.01],
initial_infected: [50],
initial_immune_perc: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
/**
* - S: susceptible; can be infected
* - I: infected; can infect others, recover, or die
* - R: recovered; immune, can become susceptible again
* - D: dead
*/
class Society {
constructor(input_data, desease_data = null) {
this.pop_data = input_data;
this.historical = [];
this.historical.push(this.make_historical_entry());
for (const node of this.pop_data.nodes) {
node.status = "S";
}
if (!desease_data) {
this.desease_transmission_rate = desease_values[0][0];
this.desease_recovery_rate = desease_values[1][0];
this.desease_susceptibility_rate = desease_values[2][0];
this.desease_death_rate = desease_values[3][0];
} else {
this.desease_transmission_rate = desease_data.beta;
this.desease_recovery_rate = desease_data.gamma;
this.desease_susceptibility_rate = desease_data.theta;
this.desease_death_rate = desease_data.delta;
}
}
// the percentage of immune people will take priority if both n_immune_initial and n_immune_initial_perc are specified
init(
n_infected_initial = 1,
n_immune_initial = 0,
n_immune_initial_perc = null
) {
this.pop_data.nodes = underscore.shuffle(this.pop_data.nodes);
if (n_immune_initial_perc)
n_immune_initial = n_immune_initial_perc * this.pop_data.nodes.length;
for (const i in this.pop_data.nodes) {
if (i < n_infected_initial) {
this.pop_data.nodes[i].status = "I";
} else if (i < n_infected_initial + n_immune_initial) {
this.pop_data.nodes[i].status = "R";
} else {
this.pop_data.nodes[i].status = "S";
}
}
}
data() {
return this.pop_data;
}
update() {
this.historical.push(this.make_historical_entry());
for (const node of this.pop_data.nodes) {
if (node.status == "S") {
for (const link of this.pop_data.links) {
// link has this node
if (link.source == node || link.target == node) {
const other = link.source == node ? link.target : link.source;
if (other.status == "I") {
// linked node can infect
if (Math.random() < this.desease_transmission_rate) {
node.status = "I";
}
}
}
}
} else if (node.status == "I") {
if (Math.random() < this.desease_recovery_rate) {
node.status = "R";
} else if (Math.random() < this.desease_death_rate) {
node.status = "D";
}
} else if (node.status == "R") {
if (Math.random() < this.desease_susceptibility_rate) {
node.status = "S";
}
}
}
}
make_historical_entry() {
return {
t: this.historical.length,
deaths: this.perc_deaths(),
infected: this.perc_infected()
};
}
count_susceptibles() {
return this.pop_data.nodes.reduce(
(acc, cur) => (cur.status == "S" ? acc + 1 : acc),
0
);
}
perc_infected() {
return (
this.pop_data.nodes.reduce(
(acc, cur) => (cur.status == "I" ? acc + 1 : acc),
0
) / this.pop_data.nodes.length
);
}

perc_deaths() {
return (
this.pop_data.nodes.reduce(
(acc, cur) => (cur.status == "D" ? acc + 1 : acc),
0
) / this.pop_data.nodes.length
);
}
}
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
map_color = function(status) {
if (status == 'S') return in_values[2][0];
if (status == 'I') return in_values[2][1];
if (status == 'R') return in_values[2][2];
if (status == 'D') return in_values[2][3];
}
Insert cell
society_example = new Society(initial_network)
Insert cell
init_btn = in_values[1][0]
Insert cell
initialize_example = {
init_btn;
society_example.init(in_values[0][0], in_values[0][1]);
}
Insert cell
step_btn = sim_values[0][0]
Insert cell
step_example = {
step_btn;
society_example.update();
}
Insert cell
function transform_data(list_of_edges) {
var nodes = [];
var links = list_of_edges.map(x => {
if (x.source == x.target) return null; // skip self-connections

// create nodes
if (!nodes.map(x => x.id).includes(x.source)) nodes.push({ id: x.source });
if (!nodes.map(x => x.id).includes(x.target)) nodes.push({ id: x.target });
return {
source: nodes.find(y => y.id == x.source),
target: nodes.find(y => y.id == x.target)
};
});
return { nodes: nodes, links: links };
}
Insert cell
input_net_csv = get_net(in_values[1][1])
Insert cell
// data from http://networkrepository.com/soc-dolphins.php
get_net = (key) => {
if (key == "test")
return [
{ source: 1, target: 2 },
{ source: 2, target: 3 },
{ source: 2, target: 4 },
{ source: 3, target: 4 },
{ source: 3, target: 5 },
{ source: 4, target: 6 },
{ source: 5, target: 7 }
];
if (key == "small")
return FileAttachment("ba_small@2.csv").csv({
typed: true
});
if (key == "big")
return FileAttachment("ba_big@2.csv").csv({
typed: true
});
}
Insert cell
initial_network = transform_data(input_net_csv)
Insert cell
height = 600
Insert cell
d3 = require("d3@6")
Insert cell
Inputs = require("@observablehq/inputs@0.7.21/dist/inputs.umd.min.js")
Insert cell
import { color } from "@jashkenas/inputs"
Insert cell
import { inputsGroup } from "@bumbeishvili/input-groups"
Insert cell
// https://stackoverflow.com/a/43053803/5599687
cartesian = (...a) =>
a.reduce((a, b) => a.flatMap((d) => b.map((e) => [d, e].flat())))
Insert cell
underscore = (await import("https://unpkg.com/underscore@1.10.1/modules/index-all.js"))
.default
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more