Public
Edited
Nov 6, 2022
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
doit = color_nodes()
Insert cell
async function color_nodes() {
let job_id = job_list.length;
job_list.forEach((_, i) => (job_list[i] = false));
job_list.push(true);
d3.select(comment).text("");
d3.select(greedy_animation)
.selectAll("g.node")
.select("ellipse")
.attr("fill", "white");
let colored_nodes = d3.range(G.nodes.length).map((n) => ({
idx: n,
neighbors: neighbors(G, n)
}));

// The order of the nodes can make a difference.
// colored_nodes = d3.sort(colored_nodes, (n) => n.neighbors.length);

let current_color = 1;
let cnt = 0;
for (
let i = 0;
i < colored_nodes.length && cnt < colored_nodes.length && job_list[job_id];
i++
) {
d3.select(comment).text(`Setting color ${current_color}.`);
await Promises.delay(200);
let node1 = colored_nodes[i];
if (test(node1, current_color)) {
node1.color = current_color;
cnt++;
d3.select(greedy_animation)
.select(`g#node${node1.idx + 1}`)
.select("ellipse")
.attr("fill", d3.schemeCategory10[current_color]);
for (let j = i + 1; j < colored_nodes.length && job_list[job_id]; j++) {
await Promises.delay(100);
let node2 = colored_nodes[j];
if (test(node2, current_color)) {
node2.color = current_color;
cnt++;
d3.select(greedy_animation)
.select(`g#node${node2.idx + 1}`)
.select("ellipse")
.attr("fill", d3.schemeCategory10[current_color]);
}
}
current_color++;
}
}
d3.select(comment).text(`Graph successfully ${current_color - 1}-colored!`);

function test(node, c) {
return (
!node.color &&
node.neighbors.every(function (k) {
let neighbor = colored_nodes.filter((node) => node.idx == k)[0];
return !neighbor.color || neighbor.color != c;
})
);
}
}
Insert cell
G = {
again;
if (type == "Graph") {
return random_graph(15, 0.2);
} else {
return random_tree(0.6);
}
}
Insert cell
function neighbors(G, node) {
let nodes = G.edges
.filter((e) => e.source == node || e.target == node)
.map((e) => [e.source, e.target])
.flat()
.filter((n) => n != node);
return nodes;
}
Insert cell
function random_graph(n, p) {
let edges = d3
.range(n)
.map((i) =>
d3
.range(i + 1, n)
.map((j) =>
d3.randomUniform(0, 1)() < p ? { source: i, target: j } : []
)
)
.flat(2);

return { nodes: d3.range(n), edges };
}
Insert cell
function random_tree(p) {
let cnt = 0;
let root = { id: cnt++, depth: 0, children: [] };
let stack = [root];

let edges = [];

while (stack.length > 0 && cnt < 10000) {
let node = stack.pop();
let depth = node.depth;
for (let i = 0; i < 3; i++) {
if (d3.randomUniform(0, 1)() < p ** node.depth) {
let child = { id: cnt++, depth: node.depth + 1, children: [] };
node.children.push(child);
stack.push(child);
edges.push({ source: node.id, target: child.id });
}
}
}
return { nodes: d3.range(cnt), edges };
}
Insert cell
job_list = []
Insert cell
dot`graph{rankdir="LR"; ${random_graph(5, 0.5)
.edges.map((e) => `${e.source}--${e.target}`)
.join(";")}}`
Insert cell
dot`graph{rankdir="LR"; node[shape=point]; ${random_graph(7, 0.5)
.edges.map((e) => `${e.source}--${e.target}`)
.join(";")}}`
Insert cell
dot`graph{${rg}}`
Insert cell
rg = random_graph(10, 0.4)
.edges.map((e) => `${e.source}--${e.target}`)
.join(";")
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