Public
Edited
Jan 1, 2024
Insert cell
Insert cell
Insert cell
Insert cell
canvas = {
const context = DOM.context2d(width, height);
const numNodes = 4000, // Adjust this to get the desired number of nodes
// radiusFactor = 10,
mbStrength = -15,
centerX = width / 2,
centerY = height / 2,
strength = 0.1;
var nodes = d3.range(numNodes).map(function (i) {
return {
id: i,
r: 3 // Size of circles
};
});

// Define the forces
var forceRadial = d3
.forceRadial(
function (d) {
// Calculate the target radius more precisely to reduce the gap
// between the rings. Here, you could subtract a small value to
// pull nodes towards the center or adjust the multiplier for each ring.
// -50 controls the center cluster only
return radiusFactor * ((d.id % 4) + 1) + centerClusterGap;
},
centerX,
centerY
)
.strength(1);

var forceManybody = d3.forceManyBody().strength(mbStrength);

var forceCenter = d3.forceCenter(centerX, centerY);

var forceCollide = d3
.forceCollide(function (d) {
return d.r + 0.5;
})
.iterations(2)
.strength(strength);

// Create the simulation
var simulation = d3
.forceSimulation(nodes)
.velocityDecay(0.2)
.force("x", d3.forceX(centerX).strength(0.2))
.force("y", d3.forceY(centerY).strength(0.2))
.force("collide", forceCollide)
.force("center", forceCenter)
.force("n-body", forceManybody)
.force("radial", forceRadial)
.on("tick", ticked);
while (simulation.alpha() > 0.01) {
// You can adjust this threshold
simulation.tick();
}

// The tick function for the simulation
function ticked() {
context.clearRect(0, 0, width, height);
context.save();
// context.translate(centerX, centerY);

nodes.forEach(function (d, i) {
context.beginPath();
context.moveTo(d.x + d.r, d.y);
context.arc(d.x, d.y, d.r, 0, 2 * Math.PI);
context.fillStyle = getColor(d.id); // Function to color based on the id
context.fill();
});

context.restore();
}

// Function to get color based on the id
function getColor(id) {
const ring = id % 4;
if (ring === 0) return "#48EBCC";
if (ring === 1) return "#60968C";
if (ring === 2) return "#8D49EB";
if (ring === 3) return "#EB7549";
}

// Start the simulation
simulation.alpha(1).restart();
return context.canvas;
}
Insert cell
rScale = d3
.scaleQuantize()
.domain([280, 870]) // Define your input range
.range(["#48EBCC", "#60968C", "#8D49EB", "#EB7549"])
Insert cell
circlepacking = {
const context = DOM.context2d(width, height);
// Number of nodes
const numNodes = 4000;

// Generate a flat hierarchy for our nodes
const nodesData = { children: d3.range(numNodes).map(() => ({ r: 3 })) };

// Create a root node from the hierarchy and calculate the packing
const root = d3
.hierarchy(nodesData)
.sum((d) => d.r) // The size of the node will be determined by its radius
.sort((a, b) => b.value - a.value); // Sort the nodes based on value

const pack = d3.pack().size([width, height]).padding(1.5); // Padding between circles

pack(root);
console.log(d3.extent(root.leaves(), (d) => d.r));
// console.log(d3.extent(root.leaves(), (d) => d.y));
// Draw each node as a circle
root.leaves().forEach((leaf) => {
context.beginPath();
context.arc(leaf.x, leaf.y, leaf.r, 0, 2 * Math.PI);
context.fillStyle = rScale(leaf.x);
// context.fillStyle = getColor(leaf.data.r); // Function to color based on the radius
context.fill();
});

// Function to get color based on the radius
function getColor(radius) {
// Define your color scheme here based on the radius or other property
return "#48EBCC"; // Just as an example, returning a fixed color
}
return context.canvas;
}
Insert cell
height = 600
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