function SlopeChart(data, {
x = ([x]) => x,
y = ([, y]) => y,
z = () => 1,
defined,
curve = d3.curveLinear,
marginTop = 20,
marginRight = 30,
marginBottom = 20,
marginLeft = 30,
inset,
insetTop = inset === undefined ? 20 : inset,
insetBottom = inset === undefined ? 0 : inset,
labelPadding = 3,
labelSeparation = 10,
width = 640,
height = 400,
xDomain,
xRange = [marginLeft, width - marginRight],
xPadding = 0.5,
yType = d3.scaleLinear,
yDomain,
yRange = [height - marginBottom - insetBottom, marginTop + insetTop],
yFormat,
zDomain,
color = "currentColor",
stroke = color,
strokeLinecap,
strokeLinejoin,
strokeWidth,
strokeOpacity,
mixBlendMode,
halo = "#fff",
haloWidth = 4,
} = {}) {
const X = d3.map(data, x);
const Y = d3.map(data, y);
const Z = d3.map(data, z);
if (defined === undefined) defined = (d, i) => !isNaN(Y[i]);
const D = d3.map(data, defined);
if (xDomain === undefined) xDomain = X;
if (yDomain === undefined) yDomain = d3.extent(Y);
if (zDomain === undefined) zDomain = Z;
xDomain = new d3.InternSet(xDomain);
zDomain = new d3.InternSet(zDomain);
const I = d3.range(X.length).filter(i => xDomain.has(X[i]) && zDomain.has(Z[i]));
const xScale = d3.scalePoint(xDomain, xRange).padding(xPadding);
const yScale = yType(yDomain, yRange);
const colorScale = d3.scaleSequential(d3.interpolateRdBu)
.domain([-50,50])
.clamp(true);
const xAxis = d3.axisTop(xScale).tickSizeOuter(0);
yFormat = yScale.tickFormat(100, yFormat);
const line = d3.line()
.defined(i => D[i])
.curve(curve)
.x(i => xScale(X[i]))
.y(i => yScale(Y[i]));
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;")
.attr("font-family", "sans-serif")
.attr("font-size", 10);
svg.append("g")
.attr("transform", `translate(0,${marginTop})`)
.call(xAxis)
.call(g => g.select(".domain").remove());
svg.append("g")
.attr("fill", "none")
.attr("stroke", stroke)
.attr("stroke-linecap", strokeLinecap)
.attr("stroke-linejoin", strokeLinejoin)
.attr("stroke-width", strokeWidth)
.attr("stroke-opacity", strokeOpacity)
.selectAll("path")
.data(d3.group(I, i => Z[i]))
.join("path")
.style("mix-blend-mode", mixBlendMode)
.attr("d", ([, I]) => line(I))
.attr("stroke", ([, I]) => colorScale( Y[I[1]]-Y[I[0]] ))
return svg.node();
}