dotPlot = {
const xAccessorAA = d => d["AllAdults"]
const xAccessorLV = d => d["LikelyVoters"]
const xAccessorNV = d => d["NonVoters"]
const yAccessor = d => d["Race"]
let dimensions = {
width: width,
height: width * 0.334,
margin: {
top: 90,
right: 15,
bottom: 60,
left: 65,
},
}
dimensions.boundedWidth = dimensions.width - dimensions.margin.left - dimensions.margin.right
dimensions.boundedHeight = dimensions.height - dimensions.margin.top - dimensions.margin.bottom
const svg = d3.select(DOM.svg(dimensions.width, dimensions.height))
const bounds = svg.append("g")
.attr("transform", `translate(${dimensions.margin.left}, ${dimensions.margin.top})`)
const xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, xAccessorLV)])
.range([0, dimensions.boundedWidth])
.nice()
const yScale = d3.scaleBand()
.domain(dataset.map(yAccessor))
.range([0, dimensions.boundedHeight])
.paddingInner(0.5)
.paddingOuter(1.5)
// Draw data
const lineGenerator = d3.line()
const axisLinePath = d => lineGenerator( [ [xScale(d) + 0.5, 0], [xScale(d) + 0.5, dimensions.boundedHeight]])
const dotsLinePathNVAA = d => lineGenerator([ [xScale(xAccessorNV(d)), 0], [xScale(xAccessorAA(d)), 0] ])
const dotsLinePathAALV = d => lineGenerator([ [xScale(xAccessorAA(d)), 0], [xScale(xAccessorLV(d)), 0] ])
const dotsGroup = bounds.append("g")
.attr("class", "dots")
const dots = dotsGroup.selectAll("g")
.data(dataset)
.enter().append("g")
.attr("class", "dot")
.attr("transform", d => `translate(0, ${(yScale(yAccessor(d)) + (yScale.bandwidth() / 2))})`)
dots.append("path")
.attr("class", "dots-line-NVAA")
.attr("d", dotsLinePathNVAA)
dots.append("path")
.attr("class", "dots-line-AALV")
.attr("d", dotsLinePathAALV)
const nonVoterCircles = dots.append("circle")
.attr("class", "non-voters")
.attr("r", radiusCircles)
.attr("cx", d => xScale(xAccessorNV(d)))
const likelyVoterCircles = dots.append("circle")
.attr("class", "likely-voters")
.attr("r", radiusCircles)
.attr("cx", d => xScale(xAccessorLV(d)))
const allAdultCircles = dots.append("circle")
.attr("class", "all-adults")
.attr("r", radiusAdults)
.attr("cx", d => xScale(xAccessorAA(d)))
// Make axes
const xAxisGenerator = d3.axisTop()
.scale(xScale)
.tickFormat(d3.format(".0%"))
.ticks(5)
const yAxisGenerator = d3.axisLeft()
.scale(yScale)
.tickSize(0)
const xAxis = bounds.append("g")
.attr("class", "x-axis")
.call(xAxisGenerator)
const yAxis = bounds.append("g")
.attr("class", "y-axis")
.attr("transform", "tranlate(-20, 0)")
.call(yAxisGenerator)
.select(".domain")
.attr("opacity", 0)
// gridlines
const gridLines = bounds.append("g")
.attr("class", "grid-lines")
gridLines.selectAll("path")
.data(xScale.ticks())
.enter().append("path")
.attr("class", "grid-line")
.attr("d", axisLinePath)
// legend
const legendLabels = [
{"label": "Non Voters", class: "non-voters"},
{"label": "All Adults", class: "all-adults"},
{"label": "Likely Voters", class: "likely-voters"},
]
const legendX = dimensions.boundedWidth / 2
const legendY = dimensions.margin.top / 2
const spaceBetween = dimensions.boundedWidth / 8
const titleOffset = -dimensions.boundedWidth / 2
const legend = svg.append("g")
.attr("transform", `translate(${legendX}, ${legendY})`)
legend.append("g")
.attr("class", "title")
.append("text")
.attr("x", titleOffset + dimensions.margin.left)
.attr("y", -20)
.text("Voters do not reflect California's racial diversity")
legend.selectAll("circle")
.data(legendLabels)
.enter().append("circle")
.attr("cx", (d, i) => spaceBetween * i + 180)
.attr("cy", 5)
.attr("r", 4)
.attr("class", d => d.class)
legend.append("g")
.selectAll("text")
.data(legendLabels)
.enter().append("text")
.attr("x", (d, i) => spaceBetween * i + 190)
.attr("y", 10)
.text(d => d.label)
return svg.node()
}