chart = {
const svg = d3.select(DOM.svg(width, height));
const boxWidth = 50;
const jitterWidth = 50;
const groups = svg.selectAll("g")
.data(data)
.join("g")
.attr("transform", d => `translate(${x(d.key)}, 0)`)
.attr("class", d => d.key);
groups
.selectAll("vertLine")
.data(d => [d.value.range])
.join("line")
.attr("class", "vertLine")
.attr("stroke", "#C0C0C0")
.attr('stroke-width','1px')
.style("width", 40)
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", range => y(range[0]))
.attr("y2", range => y(range[1]));
groups
.selectAll("points")
.data(d => d.value)
.join("circle")
.attr("cx", d => 0 - jitterWidth/2 + Math.random() * jitterWidth)
.attr("cy", d => y(d.value))
.attr("r", 2)
.style("fill", "#af5f68")
.attr("fill-opacity", 0.8);
groups
.selectAll("box")
.data(d => [d])
.join("rect")
.attr("class", "box")
.attr("x", -boxWidth/2)
.attr("y", d => y(d.value.quartiles[2]))
.attr("height", d => y(d.value.quartiles[0])-y(d.value.quartiles[2]))
.attr("width", boxWidth)
.attr("stroke", "#808080")
.style("fill", "rgb(255, 255, 255)")
.style("fill-opacity", 0.7);
groups
.selectAll("horizontalLine")
.data(d => [d.value.range[0], d.value.quartiles[1], d.value.range[1]])
.join("line")
.attr("class", "horizontalLine")
.attr("stroke", "#808080")
.attr('stroke-width','1px')
.style("width", 40)
.attr("x1", -boxWidth/2)
.attr("x2", +boxWidth/2)
.attr("y1", d => y(d))
.attr("y2", d => y(d));
svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
return svg.node();
}