Public
Edited
Mar 13, 2024
Importers
Insert cell
Insert cell
Insert cell
data = FileAttachment("data2-4.json").json()
Insert cell
nodes = data.map((d) => {
return { data: { id: d.file } };
})
Insert cell
edges = {
const edges = [];
data.forEach((node) => {
node.info.links.forEach((link) => {
if (nodes.find((n) => link == n.data.id))
edges.push({
data: { source: node.file, target: link, id: node.file + "--" + link }
});
});
});
return edges;
}
Insert cell
Insert cell
edges.map((edge) => [edge.data.source, edge.data.target])
Insert cell
Insert cell
Insert cell
Insert cell
splitgraph = FileAttachment("SplitGraph.json").json()
Insert cell
Insert cell
Insert cell
SplitGraph = {
const G = new jsnx.Graph();
const storeTopNode = [];
data.forEach((node) => {
G.addNode(node.file);
});
data.forEach((node) => {
G.addNode(node.file);
node.info.links.forEach((link) => {
if (G.nodes().find((n) => link == n)) G.addEdge(node.file, link);
});
});

const funcEdgeBC = (G) =>
Object.entries(
jsnx.edgeBetweennessCentrality(G, { normalized: false })._values
)
.map(([edge, centrality]) => ({
edge: edge.toString(), // Convert tuple to string for consistency
centrality,
startNode: edge.toString().split(",")[0], // we only need this info for the first node -> optimisation
startNodeDegree: G.degree(edge.toString().split(",")[0]),
endNode: edge.toString().split(",")[1],
endNodeDegree: G.degree(edge.toString().split(",")[1])
}))
.sort((a, b) => b.centrality - a.centrality);

let currentG = funcEdgeBC(G);
// could use a some() function to be sure, but as the graph is sorted at everystep, the top node is pretty close to the condition
console.log(currentG[0]);
let lim = 0;
while (
StartFunc &&
currentG[0].centrality > 1 &&
currentG[0].startNodeDegree > 1 &&
currentG[0].endNodeDegree > 1 &&
lim < (limLimit || Infinity)
) {
console.log(currentG[0]);
console.log(lim);
storeTopNode.push(currentG[0]);
G.removeEdge(currentG[0].startNode, currentG[0].endNode); // remove the higest BC edge
currentG = funcEdgeBC(G); // recalculate the BD egdes
lim++;
}
console.log("---");
let findEdge = currentG.find(
(edge) =>
edge.centrality > 1 && edge.startNodeDegree > 1 && edge.endNodeDegree > 1
);

while (StartFunc && findEdge && lim < (limLimit || Infinity)) {
console.log(findEdge);
console.log(lim);
storeTopNode.push(findEdge);
G.removeEdge(findEdge.startNode, findEdge.endNode); // remove the node found BC edge
currentG = funcEdgeBC(G); // recalculate the BD egdes
lim++;
findEdge = currentG.find(
(edge) =>
edge.centrality > 1 &&
edge.startNodeDegree > 1 &&
edge.endNodeDegree > 1
);
}

return { edgeBC: funcEdgeBC(G), TopNodes: storeTopNode };
}
Insert cell
Insert cell
communitiesOrigin = {
const edges = splitgraph.edgeBC;
let communities = [];
let comNum = 0;

edges.forEach((edge) => {
const a = edge.startNode,
b = edge.endNode;
let comFound = communities.find((com) =>
com.children.find((child) => child.name == a || child.name == b)
);
if (comFound) {
if (!comFound.children.find((child) => child.name == a))
comFound.children.push({ name: a });
if (!comFound.children.find((child) => child.name == b))
comFound.children.push({ name: b });
} else {
const newCom = {
name: "C-" + comNum,
children: [{ name: a }, { name: b }]
};
communities.push(newCom);
comNum++;
}
});

return communities.map((com) => d3.hierarchy(com)); // all height = 1
}
Insert cell
Insert cell
hierarchies = {
let communities = communitiesOrigin;
const comEx = [];
const links = splitgraph.TopNodes; // should be topEdges
let i = 0;
let r = 0;
links.reverse().forEach((link) => {
//if (false || i < 150) {
// for debuging

// Finding Communities
let a = link.startNode,
b = link.endNode;
let comA = communities.find((com) =>
com.find((node) => node.data.name == a)
);
let comB = communities.find((com) =>
com.find((node) => node.data.name == b)
);

console.table(">>>", a, b, comA, comB);

// Merginig if coms are different
if (comA != comB) {
let heightA = comA.find((node) => node.depth == 0).height;
let heightB = comB.find((node) => node.depth == 0).height;
if (heightB != heightA) {
if (heightB > heightA) {
const comTemp = comB,
temp = b,
heightTemp = heightB;
comB = comA;
comA = comTemp;
b = a;
a = temp;
heightB = heightA;
heightA = heightTemp;
}

console.table("->>", a, b, comA, comB, heightA, heightB);

comA = d3.hierarchy(comA); // recompute the hierarchy
comA.each((d) => (d.data = { ...d.data.data, children: d.children })); // fixes the glitch

comB = d3.hierarchy(comB); // recompute the hierarchy
comB.each((d) => (d.data = { ...d.data.data, children: d.children })); // fixes the glitch

console.table("-->", a, b, comA, comB, heightA, heightB);

// comA is heigher than comB
// we have to merge at heightB + 1
// we need to find the sub tree of comA that contains the node a

const nodeA = comA.find((node) => node.data.name == a);
console.log("nodeA = ", nodeA);
console.log("nodeA.a = ", nodeA.ancestors());
const ancestorA = nodeA
.ancestors()
.find((ancestor) => ancestor.height == heightB + 1);
console.log("an = ", ancestorA);
comB.parent = ancestorA;
ancestorA.children.push(comB);
comA = d3.hierarchy(comA); // recompute the hierarchy
comA.each((d) => (d.data = { ...d.data.data, children: d.children })); // fixes the glitch
//comEx.push(comB)
communities = communities.filter((com) => com != comB);
//comB = null
} else {
// we need to add a common new ancestor to both communities
let comC = d3.hierarchy({ name: "C-" + heightA + "-" + r });
comC.children = [comA, comB];
comC = d3.hierarchy(comC);
comC.each((d) => (d.data = { ...d.data.data, children: d.children })); // fixes the glitch
communities.push(comC);

communities = communities.filter((com) => com != comA && com != comB);
//communities = communities.filter((com) => com != comB);
//comA = null;
//comB = null;
r++;
console.log("===", comC);
}
}
console.table(communities.length);
// i++;
//}
});

return communities.sort((a, b) => b.height - a.height);
}
Insert cell
hierarchies.map((h) => h.leaves().length)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// https://stackoverflow.com/questions/46076767/storing-editing-and-retrieving-the-d3-hierarchy-in-a-mongodb-keeping-realtime
addNewNodeToParent = (parent, node, index) => {
var newNode = d3.hierarchy({
name: node.name,
children: node.children
});

// added some properties to Node like parent, depth, id
newNode.depth = parent.depth + 1;
newNode.height = parent.height - 1;
newNode.parent = parent;
newNode.id = this.i;

//If no child array, create an empty array
if (!parent.children) {
parent.children = [];
parent.data.children = [];
}

//Push it to parent.children array
parent.children.splice(index, 0, newNode);
parent.data.children.splice(index, 0, newNode.data);

//Update tree
this.update(parent);
}
Insert cell
https://manual.cytoscape.org/en/stable/Navigation_and_Layout.html
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