Published
Edited
May 5, 2020
Importers
8 stars
Insert cell
Insert cell
chart = {
const links = data.links.map(d => Object.create(d));
const nodes = data.nodes.map(d => Object.create(d));

const simulation = d3.forceSimulation(nodes)
.stop()
.force("link", d3.forceLink(links).id(d => d.id))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(0, 20))
.force('collide', d3.forceCollide(0).strength(-1));

const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height * 1.3]);
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "black");
const networks = svg.append('g').attr('transform', `translate(${width / 30}, ${width / 30})`)
.selectAll('g').data(simulation.nodes()).enter()
.append('g');
const circles = networks.append('circle')
.attr('r', d => 7 * Math.log(d.np + d.nnp))
.attr('fill', 'black')
.attr('stroke', 'white')
.attr('stroke-width', 2);
networks.each(function (d) {
tippy(this, {
content: "Overall, the genre " + d.genre + " is "
+ Math.ceil(d.np / (d.np + d.nnp) * 100)
+ "% netflix produced, and is "
+ Math.ceil(d.nnp / (d.np + d.nnp) * 100 - 1)
+ "% non-netflix produced",
theme: 'light',
followCursor: true
});
});
var num_per_square = 25;
var sq_size = width/170;
networks.each(function (d) {
var curr_node = data.nodes[d.index];
var nnp = curr_node.nnp
var np = curr_node.np
var num_rows_columns = (nnp + np) / num_per_square;
var rc = Math.ceil(Math.sqrt(num_rows_columns));
var shift = Math.ceil(rc / 2 * sq_size) + rc;
var np_squares = Math.ceil(np / num_per_square);
var id = 'np';
for(var i=0; i<rc; i++){
for(var j=0; j<rc; j++){
var id = 'np';
if(j == rc-1){
if(i+1 > (rc - np_squares)){
id = 'nnp';
}
}
d3.select(this)
.append('rect')
.attr('transform', `translate(${i*8 - shift} ${j*8 - shift})`)
.attr('width', width / 170)
.attr('height', width / 170)
.attr('fill', d => 'rgb(110, 110, 110)')
.attr('stroke', 'rgb(110, 110, 110)')
.attr('stroke-width', 1)
.attr('id', id);
}
}
})
svg.selectAll("rect[id='nnp']")
.attr('fill', 'red')
.attr('stroke', 'red');
const textWrapper = networks.append('g');
textWrapper.append('text')
.attr('text-anchor', 'middle')
.attr('font-size', `${width / 80}px`)
.attr('font-weight', 800)
.attr('fill', 'white')
.text(d => d.genre);
const updateNetworks = () => networks
.attr('transform', d => `translate(${d.x + width / 2} ${d.y + height / 2})`)
while(true) {
d3.range(3).forEach(i => simulation.tick());
updateNetworks();
yield svg.node();
}
}
Insert cell
// data = FileAttachment("miserables.json").json()
data = FileAttachment("genres.json").json()
Insert cell
height = 600
Insert cell
color = {
const scale = d3.scaleOrdinal(d3.schemeCategory10);
return d => scale(d.group);
}
Insert cell
drag = simulation => {
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
return d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
Insert cell
tippy = require('tippy.js')
Insert cell
d3 = require("d3@5")
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