Public
Edited
Dec 29
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const scale = 1.03;
const scaleWord = 1.2;
const sw = 0.4;
const so = 0.95;
const k = 2; // 2^k colors segments per curve

const myColor = blackWhite
? (d) => (darkMode ? "white" : "black")
: colorFunc(colorNumber, colorRotation, colorSeed, darkenFactor);

// Specify the chart’s dimensions.
const width = 1500;
const height = width;
const cx = width * 0.5; // adjust as needed to fit
const cy = height * 0.5; // adjust as needed to fit
const radius = Math.min(width, height) / 2 - 135;

// Create a radial cluster layout. The layout’s first dimension (x)
// is the angle, while the second (y) is the radius.
const tree = d3
.cluster()
.size([2 * Math.PI, radius])
.separation((a, b) => {
// Find shared ancestor at depth 2 and depth 3
const depth2Ancestor = a
.ancestors()
.find((ancestor) => ancestor.depth === 2);
const depth3Ancestor = a
.ancestors()
.find((ancestor) => ancestor.depth === 3);
const bDepth2Ancestor = b
.ancestors()
.find((ancestor) => ancestor.depth === 2);
const bDepth3Ancestor = b
.ancestors()
.find((ancestor) => ancestor.depth === 3);

// If both have a common ancestor at depth 3
if (depth3Ancestor && depth3Ancestor === bDepth3Ancestor) {
return 0.6; // Moderate separation for shared depth 3 ancestor
}
// If both have a common ancestor at depth 2
if (depth2Ancestor && depth2Ancestor === bDepth2Ancestor) {
return 0.7; // Larger separation for shared depth 2 ancestor
}

// Default separation for other cases
return 1;
});

// Sort the tree and apply the layout.
const root = tree(hierarchie);

root.leaves().forEach((leaf) => {
leaf.outgoing = [];
leaf.incoming = [];
const link = links.find((node) => node.file === leaf.data.name);
if (link) {
link.links.forEach((targetLink) => {
const targetNode = root.find((d) => d.data.name === targetLink.file);
if (targetNode) {
leaf.outgoing.push([leaf, targetNode]);
console.log(targetNode);
}
});
}
links.forEach((node) => {
node.links.forEach((link) => {
if (link.file === leaf.data.name) leaf.incoming.push([node, leaf]);
});
});
leaf.degree = leaf.incoming.length + leaf.outgoing.length;
});

console.log(root);

// Creates the SVG container.
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [-cx * scale, -cy * scale, width * scale, height * scale])
.attr("style", "width: 100%; height: auto; font: 10px sans-serif;");

if (darkMode)
svg
.append("rect")
.attr("x", -width / 2)
.attr("y", -height / 2)
.attr("width", width)
.attr("height", height)
.attr("fill", "black");

// Append links.
if (structure)
svg
.append("g")
.attr("fill", "none")
.attr("stroke", "#555")
.attr("stroke-opacity", 0.4)
.attr("stroke-width", 1.5)
.selectAll()
.data(root.links())
.join("path")
.attr(
"d",
d3
.linkRadial()
.angle((d) => d.x)
.radius((d) => d.y)
)
.attr("stroke", (d) =>
myColor(
d.target.ancestors().find((ancestor) => ancestor.depth == colorDepth)
)
);

// Append nodes.
svg
.append("g")
.selectAll()
.data(root.leaves())
.join("circle")
.attr(
"transform",
(d) => `rotate(${(d.x * 180) / Math.PI - 90}) translate(${d.y},0)`
)
.attr("fill", (d) => (d.children ? "#555" : "#999"))
.attr("r", (d) => 1 + 0.05 * d.degree)
.attr("fill", (d) => {
const col = myColor(
d.ancestors().find((ancestor) => ancestor.depth == colorDepth)
);
return d.children ? col : darkMode ? darken(col, 0.8) : lighten(col, 0);
// return d.children ? col : darkMode ? darken(col, 0.8) : lighten(col, 0.8);
});

// Append labels.
svg
.append("g")
.attr("stroke-linejoin", "round")
.attr("stroke-width", 3)
.selectAll()
.data(root.leaves())
.join("text")
.attr(
"transform",
(d) =>
`rotate(${(d.x * 180) / Math.PI - 90}) translate(${d.y},0) rotate(${
d.x >= Math.PI ? 180 : 0
})`
)
.attr("dy", "0.31em")
.attr("x", (d) =>
d.x < Math.PI === !d.children ? 6 * scaleWord : -6 * scaleWord
)
.attr("text-anchor", (d) =>
d.x < Math.PI === !d.children ? "start" : "end"
)
.attr("font-size", (d) => 9.5 + 0.05 * d.degree)
.attr("paint-order", "stroke")
.attr("stroke", darkMode ? "black" : "white")
.attr("fill", "currentColor")
.attr("fill", (d) => {
const col = myColor(
d.ancestors().find((ancestor) => ancestor.depth == colorDepth)
);
return darkMode ? lighten(col, 0.4) : col;
})
.text((d) =>
d.height == 0
? links.find((node) => node.file == d.data.name).title
: d.depth
);

if (edge)
svg
.append("g")
.attr("fill", "none")
.attr("stroke-width", sw)
.attr("stroke-opacity", so)
.selectAll("path")
.data(root.leaves().flatMap((leaf) => leaf.outgoing))
.join("path")
.style("mix-blend-mode", darkMode ? "normal" : "multiply")
.style("opacity", so)
.attr("d", ([i, o]) => line(i.path(o)))
.each(function (d) {
d.path = this;
})
.attr("stroke", (d) =>
lighten(
myColor(
d[1].ancestors().find((ancestor) => ancestor.depth == colorDepth)
),
LighenFactor
)
);

const g = svg.append("g");

const drawRingAround = (
level = 2,
radiusCat = 1000,
catRadius = 50,
fontSize = 10,
offAngle = 0,
withText = false,
withEdges = true,
cornerRadius = 5,
arrayName
) => {
let leaves = root.leaves();

let currentCategory = leaves[0]
.ancestors()
.find((ancestor) => ancestor.depth == level).data.name;
console.log(currentCategory);
let currentColor = myColor(
leaves[0].ancestors().find((ancestor) => ancestor.depth == colorDepth)
);
let currentFirstX = leaves[0].x;
let currentLastX = leaves[0].x;
let catArray = [];

for (let i = 1; i < leaves.length; i++) {
if (
leaves[i].ancestors().find((ancestor) => ancestor.depth == level).data
.name !== currentCategory
) {
catArray.push({
color: currentColor,
name: currentCategory,
start: currentFirstX,
end: currentLastX
});
currentColor = myColor(
leaves[i].ancestors().find((ancestor) => ancestor.depth == colorDepth)
);
currentCategory = leaves[i]
.ancestors()
.find((ancestor) => ancestor.depth == level).data.name;
currentFirstX = leaves[i].x;
}
currentLastX = leaves[i].x;
}

catArray.push({
color: currentColor,
name: currentCategory,
start: currentFirstX,
end: currentLastX
});

const catData = catArray.map((d, i) => {
return {
color: d.color,
text: withText ? arrayName[i] : "", //d.name,
startAngle: (d.start / Math.PI) * 180,
endAngle: (d.end / Math.PI) * 180
};
});

drawRing(g, {
fontSize: fontSize,
r: radiusCat,
innerR: catRadius,
opacity: 0,
padAngle: 0,
endsPadAngle: -offAngle,
opaque: false,
//radial: true,
cornerRadius: cornerRadius,
data: catData,
strokeWidth: withEdges ? undefined : 0
});
};

drawRingAround(2, 618, 150, 10, 0.8, false, true, undefined);
drawRingAround(2, 743, 30, 12, 0.8, true, false, undefined, paliCategories);
drawRingAround(3, 621, 125, 10, 0.5, false, true, 3);
drawRingAround(3, 725, 30, 8, 0.5, true, false, 3, categories);

return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
hierarchie = {
let communities = communitiesH;
const links = removed_edges;
let r = 0;

links.reverse().forEach((link) => {
// Finding Communities
let a = link[0],
b = link[1];
let comA = communities.find((com) =>
com.find((node) => node.data.name == a)
);
let comB = communities.find((com) =>
com.find((node) => node.data.name == b)
);
// 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;
}
// 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);
const ancestorA = nodeA
.ancestors()
.find((ancestor) => ancestor.height == heightB + 1);
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
communities = communities.filter((com) => com != comB);
} 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);
r++;
}
}
console.table(communities.length);
});
let comF = d3.hierarchy(communities[0]);
comF.each((d) => (d.data = { ...d.data.data, children: d.children })); // fixes the glitch
return comF;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
paliCategories = [
"Virtues and Spiritual Development",
"Meditation and Ethical Conduct",
"Liberation and Higher Realizations",
"Mental and Meditative Processes",
"Aggregates and Dependent Origination",
"Defilements and Stages of Enlightenment",
"Doctrinal Classifications and Cosmic Concepts",
"Insight Knowledge and Meditative Progress",
"Realms of Existence and Beings"
]
Insert cell
categories = [
"Powers",
"Enlightenment Factors",
"Mindfulness and Ethics",
"Path and Wisdom",
"Concentration and Meditation",
"Reflections and Virtues",
"Meditative Objects",
"Liberation States",
"Wisdom and Liberation",
"Mental Factors and Stream-entry",
"Bases of Power",
"Mental Processes",
"Happiness and Concentration",
"Dependent Origination and Kamma",
"Equanimity and Aggregates",
"Elements and Sense Bases",
"Defilements and Path Qualities",
"Cravings and Hindrances",
"Skillful Actions",
"Views and Rebirth",
"Defilements and Mental Corruptions",
"Beings and Samsaric Cycle",
"Knowledge and Insight",
"Liberation and Purification",
"Jhana and Mental Processes",
"Functions of Consciousness",
"Teachings and Practice",
"Non-returners and Realms",
"States of Existence",
"Lower Realms and Destinations"
]
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
<style>
body{
max-width: 1100px;
padding-left: 1em;
padding-right: 1em;
margin-left: auto;
margin-right: auto;}
img{
/*max-width: 1100px;
margin-left: auto;
margin-right: auto;}*/
max-width: 100%;

h1::after {
content: "";
display: block;
width: 100%;
height: 1px;
background-color: #ccc; /* Grey color for the horizontal rule */
margin: 0; /* Space above and below the rule */
}

h1, h2, h3, h4, h5, h6 {
max-width: none;
}

</style>
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