Published
Edited
Nov 26, 2020
2 forks
1 star
Insert cell
Insert cell
Insert cell
data = FileAttachment("countryIndices@2.json").json();
Insert cell
Insert cell
Insert cell
Insert cell
keys = Object.keys(selectedData[0]).slice(1); //Removes the first value -> name
Insert cell
Insert cell
Insert cell
keysm = keys.slice(0,5);
Insert cell
scatterPlotMatrixChart = {
const svg = d3.select(DOM.svg(width, width))
.attr("viewBox", `0 0 ${width} ${width}`)
.style("max-width", "100%")
.style("height", "auto");

svg.append("g")
.call(xAxis);

svg.append("g")
.call(yAxis);

const cell = svg.append("g")
.selectAll("g")
.data(d3.cross(d3.range(keysm.length), d3.range(keysm.length)))
.join("g")
.attr("transform", ([i, j]) => `translate(${i * size},${j * size})`); //here we move the scatter plot to the corresponding position on the matrix

//This rect is the border of each scatter plot
cell.append("rect")
.attr("fill", "none")
.attr("stroke", "#aaa")
.attr("x", padding / 2 + 0.5)
.attr("y", padding / 2 + 0.5)
.attr("width", size - padding)
.attr("height", size - padding);

//For each scatter plot we add the corresponding data
cell.each(function([i, j]) {
d3.select(this).selectAll("circle")
.data(selectedData.filter(d => d[keysm[i]] !== 'NA' && d[keysm[j]] !== 'NA'))
.join("circle")
.attr("cx", d => xm[i](d[keysm[i]]))
.attr("cy", d => ym[j](d[keysm[j]]));
});

const circle = cell.selectAll("circle")
.attr("r", 2)
.attr("fill-opacity", 0.7)
.attr("fill", "steelblue"); //d => d.waterFacilities > 90 ? 'purple':'steelblue');

svg.append("g")
.style("font", "bold 10px sans-serif")
.selectAll("text")
.data(keysm)
.join("text")
.attr("transform", (d, i) => `translate(${i * size},${i * size})`)
.attr("x", padding)
.attr("y", padding)
.attr("dy", ".71em")
.text(d => d);

return svg.node();
}
Insert cell
Insert cell
d3.range(keysm.length)
Insert cell
d3.cross(d3.range(keysm.length), d3.range(keysm.length));
Insert cell
xAxis = {
const axis = d3.axisBottom()
.ticks(5)
.tickSize(size * keysm.length);
return g => g.selectAll("g").data(xm).join("g")
.attr("transform", (d, i) => `translate(${i * size},0)`)
.each(function(d) { return d3.select(this).call(axis.scale(d)); })
.call(g => g.select(".domain").remove())
.call(g => g.selectAll(".tick line").attr("stroke", "#ddd"));
}
Insert cell
yAxis = {
const axis = d3.axisLeft()
.ticks(5)
.tickSize(-size * keysm.length);
return g => g.selectAll("g").data(ym).join("g")
.attr("transform", (d, i) => `translate(0,${i * size})`)
.each(function(d) { return d3.select(this).call(axis.scale(d)); })
.call(g => g.select(".domain").remove())
.call(g => g.selectAll(".tick line").attr("stroke", "#ddd"));
}
Insert cell
size = (width - (keysm.length + 1) * padding) / keysm.length + padding
Insert cell
padding = 10;
Insert cell
xm = keysm.map(c => d3.scaleLinear()
.domain(d3.extent(selectedData, d => d[c]!== 'NA' ? d[c] : NaN)).nice()
.rangeRound([padding / 2, size - padding / 2]))
Insert cell
ym = xm.map(x => x.copy().range([size - padding / 2, padding / 2]))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
legend({color: z, title: keyz});
Insert cell
parallelCoordsChart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);

svg.append("g")
.attr("fill", "none")
.attr("stroke-width", 1.5)
.attr("stroke-opacity", 0.4)
.selectAll("path")
.data(selectedData.slice().sort((a, b) => d3.ascending(a[keyz], b[keyz])))
.join("path")
.attr("stroke", d => z(d[keyz]))
.attr("stroke-width", d => widthScale(d['population']))
.attr("d", d => line(d3.cross(keys, [d], (key, d) => [key, d[key]])))
.append("title")
.text(d => d.name);

svg.append("g")
.selectAll("g")
.data(keys)
.join("g")
.attr("transform", d => `translate(0,${y(d)})`)
.each(function(d) { d3.select(this).call(d3.axisBottom(x.get(d))); })
.call(g => g.append("text")
.attr("x", margin.left)
.attr("y", -6)
.attr("text-anchor", "start")
.attr("fill", "currentColor")
.text(d => d))
.call(g => g.selectAll("text")
.clone(true).lower()
.attr("fill", "none")
.attr("stroke-width", 5)
.attr("stroke-linejoin", "round")
.attr("stroke", "white"));

return svg.node();
}
Insert cell
Insert cell
x = new Map(Array.from(keys, key => [key, d3.scaleLinear(d3.extent(selectedData, d => d[key]!== 'NA' ? d[key] : NaN ), [margin.left, width - margin.right])]));
Insert cell
Insert cell
d3.extent(selectedData, d => d["waterFacilities"])
Insert cell
d3.extent(selectedData, d =>d["waterFacilities"]!== 'NA' ? d["waterFacilities"] : NaN )
Insert cell
Insert cell
widthScale = d3.scaleLinear()
.domain(d3.extent(selectedData, d => d['population']!== 'NA' ? d['population'] : NaN ))
.range([1,4])
Insert cell
line = d3.line()
.defined(([, value]) => value !== 'NA')
.x(([key, value]) => x.get(key)(value))
.y(([key]) => y(key))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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