Published
Edited
Mar 7, 2020
Importers
1 star
Insert cell
Insert cell
Insert cell
html`
<style>

svg.semanticsubstrate {
font: 10px sans-serif;
}

svg.semanticsubstrate .label {
fill: #999;
font-size: 22px;
font-weight: bold;
text-anchor: end;
}

svg.semanticsubstrate .links line {
fill: none;
stroke: #999;
stroke-opacity: 0.6;
}

svg.semanticsubstrate .nodes circle {
fill: #d62333;
stroke: #fff;
stroke-width: 1px;
}

</style>
`
Insert cell
chart = {
var nodeRadius = 4;

var linkWidth = d3.scaleLinear().range([1.5, 2 * nodeRadius]);

var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
};

var width = 960 - margin.left - margin.right;
var height = 500 - margin.top - margin.bottom;

var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);

var xAxis = d3.axisBottom().scale(x);
var yAxis = d3.axisLeft().scale(y);

var svgDOM = d3.select(DOM.svg(960, 500))
.attr('class', 'semanticsubstrate')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom);

var svg = svgDOM.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

var graph = data;
var idToNode = {};

graph.nodes.forEach(function (n) {
n.degree = 0;
idToNode[n.id] = n;
});

graph.links.forEach(function (e) {
e.source = idToNode[e.source];
e.target = idToNode[e.target];
e.source.degree++;
e.target.degree++;
});

x.domain([0, d3.max(graph.nodes, function (d) { return d.chapters.length; })]);
y.domain([0, d3.max(graph.nodes, function (d) { return d.degree; })]);

linkWidth.domain(d3.extent(graph.links, function (d) { return d.chapters.length; }));

svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis)
.append('text')
.attr('class', 'label')
.attr('x', width)
.attr('y', -6)
.text('Number of appearances');

svg.append('g')
.attr('class', 'y axis')
.call(yAxis)
.append('text')
.attr('class', 'label')
.attr('y', 6)
.attr('dy', '.71em')
.attr('transform', 'rotate(-90)')
.text('Number of interactions');

svg.selectAll('.tick line, .axis path')
.attr('stroke', '#999');

svg.selectAll('.tick text')
.attr('fill', '#777');

var link = svg.append('g')
.attr('class', 'links')
.selectAll('line')
.data(graph.links)
.enter().append('line')
.attr('x1', function (d) { return x(d.source.chapters.length); })
.attr('x2', function (d) { return x(d.target.chapters.length); })
.attr('y1', function (d) { return y(d.source.degree); })
.attr('y2', function (d) { return y(d.target.degree); })
.attr('stroke-width', function (d) { return linkWidth(d.chapters.length); })
.on('mouseover', function (d) {
link.style('stroke', null);
d3.select(this).style('stroke', '#d62333');
node.style('fill', function (node_d) {
return node_d === d.source || node_d === d.target ? 'black' : null;
});
})
.on('mouseout', function (d) {
link.style('stroke', null);
node.style('fill', null);
});

var node = svg.append('g')
.attr('class', 'nodes')
.selectAll('circle')
.data(graph.nodes)
.enter().append('circle')
.attr('cx', function (d) {
return (d.degree == 0 ? (Math.random() - 0.5) * nodeRadius : 0) + x(d.chapters.length);
})
.attr('cy', function (d) {
return (d.degree == 0 ? (Math.random() - 0.5) * nodeRadius : 0) + y(d.degree);
})
.attr('r', nodeRadius)
.on('mouseover', function (d) {
node.style('fill', null);
d3.select(this).style('fill', 'black');
var nodesToHighlight = graph.links.map(function (e) { return e.source === d ? e.target : e.target === d ? e.source : 0})
.filter(function (d) { return d; });
node.filter(function (d) { return nodesToHighlight.indexOf(d) >= 0; })
.style('fill', '#555');
link.style('stroke', function (link_d) {
return link_d.source === d || link_d.target === d ? '#d62333' : null;
});
})
.on('mouseout', function (d) {
node.style('fill', null);
link.style('stroke', null);
});

node.append('title').text(function (d) { return d.name; });
return svgDOM.node();
}
Insert cell
data = d3.json("https://gist.githubusercontent.com/cbuie/f0a833e4ecaa7b26bbd0186061eb366c/raw/55ab7d54ae1a876bca4cbf4f4fe33ca5b361f2ca/miserablesAppearance")
Insert cell
d3 = require("https://d3js.org/d3.v5.min.js")
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