Published
Edited
Sep 19, 2020
3 forks
3 stars
Insert cell
Insert cell
{
const target = html`<div class='tableauPlaceholder' id='viz1600473864106' style='position: relative'><noscript><a href='#'><img alt=' ' src='https:&#47;&#47;public.tableau.com&#47;static&#47;images&#47;Ne&#47;Network_Visualizations&#47;HashtagsNetwork&#47;1_rss.png' style='border: none' /></a></noscript><object class='tableauViz' style='display:none;'><param name='host_url' value='https%3A%2F%2Fpublic.tableau.com%2F' /> <param name='embed_code_version' value='3' /> <param name='site_root' value='' /><param name='name' value='Network_Visualizations&#47;HashtagsNetwork' /><param name='tabs' value='no' /><param name='toolbar' value='yes' /><param name='static_image' value='https:&#47;&#47;public.tableau.com&#47;static&#47;images&#47;Ne&#47;Network_Visualizations&#47;HashtagsNetwork&#47;1.png' /> <param name='animate_transition' value='yes' /><param name='display_static_image' value='yes' /><param name='display_spinner' value='yes' /><param name='display_overlay' value='yes' /><param name='display_count' value='yes' /><param name='language' value='en' /></object></div>`;
yield target;

var divElement = document.getElementById('viz1600473864106');
var vizElement = divElement.getElementsByTagName('object')[0];
if (divElement.offsetWidth > 800) {
vizElement.style.width = '100%';
vizElement.style.height = divElement.offsetWidth * 0.75 + 'px';
} else if (divElement.offsetWidth > 500) {
vizElement.style.width = '100%';
vizElement.style.height = divElement.offsetWidth * 0.75 + 'px';
} else {
vizElement.style.width = '100%';
vizElement.style.height = '777px';
}
var scriptElement = document.createElement('script');
scriptElement.src = 'https://public.tableau.com/javascripts/api/viz_v1.js';
vizElement.parentNode.insertBefore(scriptElement, vizElement);
}
Insert cell
md`## D3 Version`
Insert cell
viewof selectedTweets = navio(tweets)
Insert cell
{
// const nodes = network.nodes.map(d => ({ ...d })),
// links = network.links.map(l => ({
// source: l.source.id,
// target: l.target.id,
// value: l.value
// }));

const nodes = network.nodes,
links = network.links;

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

const lines = svg
.selectAll("line")
.data(links)
.join("line")
.style("stroke", "#333")
.style("stroke-opacity", l => {
console.log(l, opacity(l.value));
return opacity(l.value);
});

// const circles = svg
// .selectAll("circle")
// .data(nodes)
// .join("circle")
// .attr("r", 3);

const text = svg
.selectAll("text")
.data(nodes)
.join("text")
.attr("fill", "#333")
.style("font-size", d => size(d.value) + "pt")
.style("fill", d => color(d.cluster))
.text(d => d.id);

const ticked = () => {
lines
.attr("x1", l => l.source.x)
.attr("y1", l => l.source.y)
.attr("x2", l => l.target.x)
.attr("y2", l => l.target.y);
// circles.attr("cx", d => d.x).attr("cy", d => d.y);

text.attr("x", d => d.x).attr("y", d => d.y);
};

const simulation = d3
.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-20))
.force("center", d3.forceCenter(width / 2, height / 2))
// .force("x", d3.forceX(width / 2))
.force("link", d3.forceLink(links).id(d => d.id))
.force("boundary", forceBoundary(3, 3, width, height))
.on("tick", ticked);

text.call(drag(simulation));

invalidation.then(() => simulation.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
color = d3.scaleOrdinal(d3.schemeCategory10)
Insert cell
opacity = d3
.scaleLinear()
.domain(d3.extent(network.links, d => d.value))
.range([0.1, 1])
Insert cell
size = d3
.scaleLinear()
.domain(d3.extent(network.nodes, d => d.value))
.range([4, 18])
Insert cell
opacity.domain()
Insert cell
height = 400
Insert cell
network = {
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 links = [];
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));
links.push({ source: s, target: t, value: v });
}

const network = { nodes: Array.from(dNodes.values()), links };
netClustering.cluster(network.nodes, network.links);
// return dNodes;
return network;
}
Insert cell
network.nodes
Insert cell
network.links
.map((l, i) => [{ ...l.source, link: i }, { ...l.target, link: i }])
.flat()
Insert cell
style = html`<style>svg#graph text {
font-family: sans-serif;
text-anchor: middle;
cursor: pointer;
} `
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.json").json()
Insert cell
d3 = require("d3@6")
Insert cell
import { navio } from "@john-guerra/navio"
Insert cell
forceBoundary = require("d3-force-boundary")
Insert cell
netClustering = require("netclustering")
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