scatter = {
const svg = d3.create("svg")
.attr("width", 450)
.attr("height", 450)
.attr("viewBox", [0, 0, 450, 450])
.attr("style", `max-width: 100%; height: auto; overflow: visible; margin-top: 30px; margin-left:${0.5*(Math.max(width-450,0))}; margin-right:${0.5*(Math.max(width-450))};`)
const gradient = DOM.uid();
const svgGrad = svg.append("linearGradient")
.attr("id", gradient.id)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 400)
.attr("y1", 450)
.attr("x2", 0)
.attr("y2", 0)
svgGrad.append("stop")
.attr("offset","0%")
.attr("stop-color","rgb(190, 255, 189)")
svgGrad.append("stop")
.attr("offset","50%")
.attr("stop-color","white")
svgGrad.append("stop")
.attr("offset","100%")
.attr("stop-color","rgb(255, 189, 244)")
svg.append("rect")
.attr("x",50)
.attr("y",0)
.attr("width",400)
.attr("height",400)
.attr("fill",gradient)
let sortedUse = [...topicData].sort((a, b) => d3.ascending(a.useful, b.useful))
let sortedEnj = [...topicData].sort((a, b) => d3.ascending(a.enjoyed, b.enjoyed))
const xScale = d3.scaleLinear(
[Math.min( Math.floor((+sortedUse[0].useful - 2.5) / 5) * 5 , Math.floor((+sortedEnj[0].enjoyed - 2.5) / 5) * 5 ),
Math.ceil((+sortedUse[topicData.length-1].useful + 2.5) / 5) * 5],
[50,450])
const yScale = d3.scaleLinear(
[Math.min( Math.floor((+sortedUse[0].useful - 2.5) / 5) * 5 , Math.floor((+sortedEnj[0].enjoyed - 2.5) / 5) * 5 ),
Math.max(Math.ceil((+sortedUse[topicData.length-1].useful + 2.5) / 5) * 5, Math.ceil((+sortedEnj[topicData.length-1].enjoyed + 2.5) / 5) * 5)],
[400,0])
svg.append("g") // the axis will be contained in an SVG group element
.attr("id","yAxis")
.call(d3.axisLeft(yScale)
.ticks(5)
.tickFormat(d3.format("d"))
.tickSizeOuter(0)
)
.attr("transform","translate(50,0)")
.attr("color","rgb(200, 0, 180)")
.style("font-family","Teko, sans-serif")
.style("font-weight","300")
.style("font-size",16)
svg.append("g")
.attr("transform", `translate(0,400)`) // translate x-axis to bottom of chart
.attr("id","xAxis")
.call(d3.axisBottom(xScale)
.ticks(5)
.tickFormat(d3.format("d"))
.tickSizeOuter(0)
)
.attr("color","rgb(30, 156, 60)")
.style("font-family","Teko, sans-serif")
.style("font-weight","300")
.style("font-size",16)
const xAxisLabel = svg.append("text")
.attr("x", 450)
.attr("y", 440)
.text("% who said: USEFUL")
.style("text-anchor","end")
.attr("fill", "rgb(0, 156, 18)")
.style("font-family","Yanone Kaffeesatz, sans-serif")
.style("font-size",20);
const yAxisLabel = svg.append("text")
.attr("x", 0)
.attr("y", 40)
.text("% who said: ENJOYABLE")
.style("text-anchor","end")
.attr("transform","translate(-20,0), rotate(-90)")
.attr("fill", "rgb(200, 0, 180)")
.style("font-family","Yanone Kaffeesatz, sans-serif")
.style("font-size",20);
svg.selectAll(".bubble")
.data(topicData)
.join("circle")
.attr("class", "bubble")
.attr("cx", d => xScale(d.useful))
.attr("cy", d => yScale(d.enjoyed))
.attr("r", 25)
.attr("stroke", (d,i) => colors11[i])
.attr("fill", (d,i) => colors11[i])
.attr("fill-opacity", 0.25)
svg.selectAll(".bubbleLabel")
.data(topicData) // bind each element of the data array to one SVG circle
.join("text")
.attr("class", "bubbleLabel")
.attr("x", d => xScale(d.useful))
.attr("y", d => yScale(d.enjoyed))
.style("text-anchor","middle")
.style("font-weight","700")
.attr("fill", (d,i) => colors11[i])
.text(d => d.topic.indexOf("Functions")>=0
? d.topic.split("Functions - ")[1].substr(0,4)
: d.topic.substr(0,4))
.style("font-family","Yanone Kaffeesatz, sans-serif")
return svg.node()
}