Public
Edited
May 23, 2023
Insert cell
Insert cell
Insert cell
{
const height = 300;
const maxRadius = 20;
const margin = 100;
const width = 600; // Replace with the desired width of the SVG element

const xScale = d3
.scaleBand()
.domain(dataset.map((d) => d.mip))
.range([margin, width - margin]);

const yScale = d3
.scaleBand()
.domain(dataset.map((d) => d.mip))
.range([Math.PI, -Math.PI / 4]);

const radiusScale = d3
// .scaleSqrt()
.scaleLinear()
.domain([0, d3.max(newdata, (d) => d.val)])
.range([0, 1]);

const colorScale = d3
.scaleOrdinal()
.domain([...new Set(newdata.map((d) => d.kind))])
.range(colors);

console.log(colorScale.domain());

const svg = d3
.create("svg")
.attr("viewBox", [0, -height / 2, width, 1.5 * height]);

const simulation = d3
.forceSimulation(newdata)
.force(
"x",
d3
.forceX()
.x((d, i) => xScale(d.mip) + i * 10 + Math.random())
.strength(100)
)
.force(
"y",
d3
.forceY()
.y(height / 2)
.strength(0.1)
)
.force(
"collision",
d3
.forceCollide()
.radius((d) => maxRadius * radiusScale(d.val) ** 0.95 + 5)
.strength(1)
)
.force("charge", d3.forceManyBody().strength(-30).distanceMax(40))
.stop();

svg
.selectAll("circle")
.data(newdata)
.join("circle")
.attr("r", (d) => maxRadius * radiusScale(d.val) ** 0.6)
.attr("cx", (d, i) => xScale(d.mip) + i * Math.random())
.attr(
"cy",
(d, i) =>
0.1 * height +
(Math.sin(yScale(d.mip)) * height) / 2 +
(i + 1) * Math.random()
)
.attr("fill", (d) => colorScale(d.kind))
.attr("fill-opacity", 0.4)
.attr("stroke", (d) => colorScale(d.kind));

const circles = svg.selectAll("circle");

simulation.alpha(1).restart();

function adjustCollisions() {
const padding = 2;

circles.each((currentData, i, nodes) => {
const currentCircle = nodes[i];
const x1 =
+currentCircle.getAttribute("cx") + Math.random() * Math.random();
const y1 =
+currentCircle.getAttribute("cy") + Math.random() * Math.random();
const r1 = +currentCircle.getAttribute("r") + Math.random();

for (let j = 0; j < i; j++) {
const prevCircle = nodes[j];
const x2 = +prevCircle.getAttribute("cx");
const y2 = +prevCircle.getAttribute("cy");
const r2 = +prevCircle.getAttribute("r");

const dx = x1 - x2;
const dy = y1 - y2;
const distance = Math.sqrt(dx * dx + dy * dy);
const minDistance = r1 + r2 + padding;

if (distance < minDistance) {
const moveX = (dx / distance) * (minDistance - distance);
const moveY = (dy / distance) * (minDistance - distance);

currentCircle.setAttribute("cx", x1 + moveX);
currentCircle.setAttribute("cy", y1 + moveY);
}
}
});
simulation.tick();
}

setInterval(adjustCollisions, 1000 / 3);

return svg.node();
}
Insert cell
<!DOCTYPE html>
<html>
<head>
<title>Colored Words Example</title>
<style>
.color1 {
color: #000546;
}

.color2 {
color: #f2b30d;
}

.color3 {
color: #a40e4C;
}

.color4 {
color: #0e0f0f;
}

.color5 {
color: #22bfb7;
}
</style>
</head>
<body>
<h1>Colored Words Example</h1>
<p>
Here are the words in different colors:
</p>
<p>
<span class="color1">models</span>,
<span class="color2">experiments</span>,
<span class="color3">institutions</span>,
<span class="color4">countries</span>,
<span class="color5">forcings</span>.
</p>
</body>
</html>
Insert cell
Insert cell
Insert cell
newdata = {
var nd = [];
dataset.forEach((d) => {
Object.entries(d).forEach((e) => {
if (e[0] != "mip") {
nd.push({ mip: d.mip, kind: e[0], val: e[1] });
}
});
});
console.log(nd);
return nd;
}
Insert cell
Insert cell
d3 = require("d3")
Insert cell
// {
// const height = 300;
// const maxRadius = 10;
// const margin = 100;
// const width = 600; // Replace with the desired width of the SVG element

// const xScale = d3
// .scaleBand()
// .domain(dataset.map((d) => d.mip))
// .range([margin, width - margin]);

// const radiusScale = d3
// .scaleSqrt()
// .domain([
// 0,
// // d3.max(dataset.map((d) => d3.max(Object.values(d).map((e) => +e || 0))))
// d3.max(newdata.map((d) => d.val))
// ])
// .range([0, maxRadius]);

// const colorScale = d3
// .scaleOrdinal()
// .domain(new Set(newdata.map((d) => d.kind)))
// .range(colors); //d3.schemeCategory10);

// const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

// const simulation = d3
// .forceSimulation(newdata)
// .force(
// "x",
// d3
// .forceX()
// .x((d, i) => i + xScale(d.mip))
// .strength(1)
// )
// .force(
// "y",
// d3
// .forceY()
// .y(height / 2)
// .strength(1)
// )
// .force(
// "collision",
// d3
// .forceCollide()
// .radius((d) => radiusScale(d.val) + 2)
// .strength(1)
// )

// .force(
// "charge",
// d3
// .forceManyBody()
// .strength(-3) // Repulsive force strength (adjust as needed)
// .distanceMax(400) // Maximum distance over which the force is applied (optional)
// )
// .stop();

// svg
// .selectAll("circle")
// .data(newdata)
// .join("circle")
// .attr("r", (d) => radiusScale(d.val))
// .attr("cx", (d, i) => xScale(d.mip) + i * Math.random())
// .attr("cy", (d) => height / 2 + 20 * Math.random())
// .attr("fill", (d) => colorScale(d.kind))
// .attr("fill-opacity", 0.4)
// .attr("stroke", (d) => colorScale(d.kind));

// var node = d3.selectAll("circle");
// const circles = svg.selectAll("circle");

// simulation.alpha(10).restart();

// simulation.on("tick", () => {
// node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
// });

// function adjustCollisions() {
// const padding = 2; // Adjust the padding between circles as needed

// circles.each((d, i, nodes) => {
// const currentCircle = nodes[i];
// const x1 = currentCircle.getAttribute("cx");
// const y1 = currentCircle.getAttribute("cy");
// const r1 = +currentCircle.getAttribute("r");

// for (let j = 0; j < i; j++) {
// const prevCircle = nodes[j];
// const x2 = prevCircle.getAttribute("cx");
// const y2 = prevCircle.getAttribute("cy");
// const r2 = +prevCircle.getAttribute("r");

// const dx = x1 - x2;
// const dy = y1 - y2;
// const distance = Math.sqrt(dx * dx + dy * dy);
// const minDistance = r1 + r2 + padding;

// if (distance < minDistance) {
// // Adjust positions of overlapping circles
// const moveX = (dx / distance) * (minDistance - distance);
// const moveY = (dy / distance) * (minDistance - distance);

// currentCircle.setAttribute("cx", +x1 + moveX);
// currentCircle.setAttribute("cy", +y1 + moveY);
// }
// }
// });
// // console.log("crash");
// }

// setInterval(() => {
// adjustCollisions();
// // simulation.tick();
// }, 1000 / 60);

// return svg.node();
// }
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