Published
Edited
Apr 21, 2020
1 star
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);

const rect = svg.selectAll("g")
.data(series)
.join("g")
.attr("fill", ({key}) => color(key))
.selectAll("rect")
.data(d => d)
.join("rect")
.attr("x", d => x(d.data.time))
.attr("y", height - margin.bottom)
.attr("width", x.bandwidth() - 1)
.attr("height", 0)

function transitionStacked() {
rect.transition()
.duration(500)
.delay((d, i) => i * 20)
.attr("y", d => y(d[1]))
.attr("height", d => y(d[0]) - y(d[1]))
}
const l = lineLength(line(nodeCounts));
svg.append("path")
.attr("fill", "none")
.attr("stroke", "#424242")
.attr("stroke-width", 1.5)
.attr("stroke-dasharray", `0,${l}`)
.attr("d", line(nodeCounts))
.transition()
.duration(1000)
.ease(d3.easeLinear)
.attr("stroke-dasharray", `${l},${l}`);

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

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

function update() {
transitionStacked();
}

return Object.assign(svg.node(), {update});
}
Insert cell
chart.update()
Insert cell
data= Object.assign(d3.csvParse(await FileAttachment("d3@10.csv").text()));


Insert cell
nodeCounts = {
var i = 0;
var nodeCounts = [];
for(i = 0; i < data.length; i++){
data[i]["time"] = +data[i]["time"];
data[i]["value"] = +data[i]["value"];
if(data[i]["category"] == "NodeCount"){
nodeCounts.push({time: data[i]["time"], count: data[i]["value"]});
}
}
return nodeCounts;
}

Insert cell
function lineLength(path) {
return d3.create("svg:path").attr("d", path).node().getTotalLength();
}
Insert cell
line = d3.line()
.curve(d3.curveBasis)
.x(d => x(d.time) + x.bandwidth() / 2)
.y(d => y2(d.count))
Insert cell
colors = new Map([
["Failures", "#F59D3D"],
["PodCount", "#5B8DB8"]
])
Insert cell
series = d3.stack()
.keys(Array.from(colors.keys()))
.value((group, key) => group.get(key).value)
.order(d3.stackOrderReverse)
(Array.from(d3.rollup(data, ([d]) => d, d => d.time, d => d.category).values()))
.map(s => (s.forEach(d => d.data = d.data.get(s.key)), s))
Insert cell
x = d3.scaleBand()
.domain(data.map(d => d.time))
.rangeRound([margin.left, width - margin.right])
Insert cell
maxPodCount = d3.max(series, d => d3.max(d, d => d[1]))
Insert cell
y = d3.scaleLinear()
.domain([0, d3.max(series, d => d3.max(d, d => d[1]))]).nice()
.range([height - margin.bottom, margin.top])
Insert cell
y2 = d3.scaleLinear()
.domain([0, d3.max(nodeCounts, d=> d.count)]).range([height - margin.bottom, margin.top])
Insert cell
color = d3.scaleOrdinal()
.domain(Array.from(colors.keys()))
.range(Array.from(colors.values()))
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickSizeOuter(0).tickFormat(() => ""))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y)
.tickFormat(x => x))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.attr("color", "#4C769B")
.text("Pod Count"))
Insert cell
y2Axis = g => g
.attr("transform", `translate(${width - margin.right},0)`)
.call(d3.axisRight(y2)
.tickFormat(x => x))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", -60)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text("Node Count"))
Insert cell
formatRevenue = x => (+(x / 1e9).toFixed(2) >= 1)
? `${(x / 1e9).toFixed(2)}B`
: `${(x / 1e6).toFixed(0)}M`
Insert cell
height = 500
Insert cell
margin = ({top: 20, right: 30, bottom: 30, left: 30})
Insert cell
d3 = require("d3@5", "d3-array@2")
Insert cell
import {swatches} from "@d3/color-legend"
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