Public
Edited
Mar 6, 2024
1 fork
Insert cell
Insert cell
Insert cell
chart = {
var svg = d3.create("svg").attr("width", width).attr("height", height);

var force = d3
.forceSimulation(dataset.nodes)
.force("charge", d3.forceManyBody().strength(-10))
.force("link", d3.forceLink(dataset.edges))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("boundary", forceBoundary(3, 3, width, height));

var colors = d3.scaleOrdinal(d3.schemeCategory10);

//Create edges as lines
var edges = svg
.selectAll("line")
.data(dataset.edges)
.join("line")
.style("stroke", "#ccc")
.style("stroke-width", 1);

// Add a tooltip div. Here I define the general feature of the tooltip: stuff that do not depend on the data point.
// Its opacity is set to 0: we don't see it by default.

// A function that change this tooltip when the user hover a point.
// Its opacity is set to 1: we can now see it. Plus it set the text and position of tooltip depending on the datapoint (d)
const mouseover = function (event, d) {
tooltip.style("opacity", 1);
};

// A function that change this tooltip when the leaves a point: just need to set opacity to 0 again
const mouseleave = function (event, d) {
tooltip.transition().duration(200).style("opacity", 0);
};

//Create nodes as circles
var nodes = svg
.selectAll("circle")
.data(dataset.nodes)
.join("circle")
.attr("r", (d) => d.value / 4)
.style("fill", "#333")
.on("mouseover", tooltip_in)
.on("mousemove", tooltip_in)
.on("mouseout", tooltip_out)
.call(drag(force));
// Add a simple tooltip
// nodes
// .append("title")
// .style("font-size", "20pt")
// .text((d) => d.id);

//Every time the simulation "ticks", this will be called
force.on("tick", function () {
edges
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});

nodes
.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
});
});

invalidation.then(() => force.stop());

return svg.node();
}
Insert cell
drag = simulation => {
function dragstarted(event) {
if (!event.active) simulation.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}

function dragged(event) {
event.subject.fx = event.x;
event.subject.fy = event.y;
}

function dragended(event) {
if (!event.active) simulation.alphaTarget(0);
event.subject.fx = null;
event.subject.fy = null;
}

return d3
.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
Insert cell
// name a variable tooltip, and style it using css properties
tooltip = d3
.select("body")
.append("text")
.style("position", "absolute") // the absolute position is necessary so that we can manually define its position later
.style("visibility", "hidden") // hide it from default at the start so it only appears on hover
.style("background-color", "white")
.attr("class", "tooltip")
Insert cell
//name a tooltip_in function to call when the mouse hovers a node
tooltip_in = function (event, d) {
// pass event and d to this function so that it can access d for our data
return tooltip
.text("#" + d.id + ", value:" + d.value)
.style("visibility", "visible") // make the tooltip visible on hover
.style("top", event.y / 1.2 + "px")
.style("left", event.x / 1.2 + "px");
}
Insert cell
// name a tooltip_out function to call when the mouse stops hovering
tooltip_out = function () {
return tooltip
.transition()
.duration(200) // give the hide behavior a 50 milisecond delay so that it doesn't jump around as the network moves
.style("visibility", "hidden"); // hide the tooltip when the mouse stops hovering
}
Insert cell
selectedTweets = tweets
Insert cell
height = 400
Insert cell
dataset = {
const dLinks = new Map();

for (let t of selectedTweets) {
for (let i = 0; i < t.entities.hashtags.length; i += 1) {
for (let j = i + 1; j < t.entities.hashtags.length; j += 1) {
const key = getKey(
t.entities.hashtags[i].text,
t.entities.hashtags[j].text
);
if (!dLinks.has(key)) dLinks.set(key, 0);

dLinks.set(key, dLinks.get(key) + 1);
}
}
}

const dNodes = new Map();
let edges = [];
for (let [l, v] of dLinks) {
const [source, target] = l.split("~");

const s = findOrAdd(dNodes, source);
const t = findOrAdd(dNodes, target);

dNodes.set(source, ((s.value += 1), s));
dNodes.set(target, ((t.value += 1), t));
edges.push({ source: s, target: t, value: v });
}

const dataset = { nodes: Array.from(dNodes.values()), edges };
// netClustering.cluster(network.nodes, network.links);
// return dNodes;
return dataset;
}
Insert cell
findOrAdd = (dNodes, n) => {
if (!dNodes.has(n)) dNodes.set(n, { id: n, value: 0 });
return dNodes.get(n);
}
Insert cell
getKey = (a, b) => (a >= b ? `${a}~${b}` : `${b}~${a}`)
Insert cell
tweets = FileAttachment("duto_guerra_tweets@2.json").json()
Insert cell
forceBoundary = require("d3-force-boundary")
Insert cell
d3 = require("d3@6")
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