{
const height = 500;
const p_h = 50;
const width = 800;
const p_w = 100;
const svg = d3.select(DOM.svg(width, height));
const n_bins = 20;
const r = 3;
let x_data = input_to_data.filter(function(d) { return d['input'] == x_metric})[0]['data']
const x_max = d3.max(x_data)
const x_min = d3.min(x_data)
let y_data = input_to_data.filter(function(d) { return d['input'] == y_metric})[0]['data']
if (y_metric == "Number of stories") {
const new_x_data = []
const new_y_data = []
let x_interpolated = d3.interpolate(x_min, x_max)
const bin_bounds = d3.range(n_bins).map(b => [x_interpolated(b/n_bins), x_interpolated((b+1)/n_bins)])
for (let i=0; i<n_bins; i++) {
let this_bin = bin_bounds[i]
let this_bin_size = x_data.filter(function(d) {
return d >= this_bin[0] && d <= this_bin[1] }).length
let this_bin_point = d3.interpolate(this_bin[0], this_bin[1])(0.5)
d3.range(this_bin_size).map(p => new_x_data.push(this_bin_point))
d3.range(this_bin_size).map(p => new_y_data.push(r*p))
}
x_data = new_x_data;
y_data = new_y_data;
}
//combined data points
let combined_data = d3.range(n_points).map(j => [x_data[j], y_data[j]])
/////scales
//x-scale w/already calculated min and max
var x_scale = d3.scaleLinear()
.domain([x_min, x_max])
.range([p_w, width-p_w]);
//y-scale
const y_max = d3.max(y_data)
const y_min = d3.min(y_data)
var y_scale = d3.scaleLinear()
.domain([y_min, y_max])
.range([height-p_h, p_h]);
////////////axes
////y-axis
var y_axis = d3.axisLeft(y_scale)
.ticks(5);
svg.append('g')
.attr('class', 'y-axis')
.call(y_axis)
.attr('transform', 'translate(' + p_w + ',0)');
//add y-axis label
svg.append("text")
.attr("class", "axis-label")
.attr("transform", "rotate(-90)")
.attr("y", p_w-30)
.attr("x", 0 - (height / 2))
.text("Y: " + y_metric);
////x-axis
var x_axis = d3.axisBottom(x_scale)
.ticks(5);
svg.append('g')
.attr('class', 'x-axis')
.call(x_axis)
.attr('transform', 'translate(0,' + (height-p_h) +')');
//add y-axis label
svg.append("text")
.attr("class", "axis-label")
.attr("y", height - (p_h - 40))
.attr("x", width/2)
.text("X: " + x_metric);
//draw scatterplot points
svg.selectAll('circle')
.data(combined_data)
.join('circle')
.attr('class', 'point')
.attr('cx', (d) => x_scale(d[0]))
.attr('cy', (d) => y_scale(d[1]))
.attr('r', r)
.style('fill', "blue")
.style('opacity', 0.5);
svg.selectAll('.circle-stroke')
.data(combined_data)
.join('circle')
.attr('class', 'point')
.attr('cx', (d) => x_scale(d[0]))
.attr('cy', (d) => y_scale(d[1]))
.attr('r', r)
.style('fill', "none")
.style('stroke', 'purple');
///////////interactivity - tooltips on hover
//create tooltip
svg.append('rect') //questionable rectangle background because I don't understand observable
.attr('id', 'tooltip-background')
.attr('class', 'tooltip')
.attr('width', 80)
.attr('height', 20)
.style('fill', 'white')
.style('display', 'none')
.attr('rx', 5);
svg.append('text')
.attr('id', 'tooltip-text')
.attr('class', 'tooltip')
.style('display', 'none');
//set mouse events for the points
svg.selectAll('.point')
.on('mouseover', function() {
//make bigger
d3.select(this).attr('r', r*2);
//show tooltip
let d = d3.select(this).datum()
d3.selectAll('.tooltip')
.style('display', 'inline');
d3.select('#tooltip-text')
.attr('x', x_scale(d[0]) + r*2)
.attr('y', y_scale(d[1]) - r*2)
.attr('width', 100)
.text('Headline: XXXXX ' + x_metric + ': ' + d[0] + ' ' + y_metric + ': ' + d[1]);
d3.select('#tooltip-background')
.attr('x', x_scale(d[0]) + r)
.attr('y', y_scale(d[1]) - 20);
})
.on('mouseout', function() {
//reset radius
d3.select(this).attr('r', r);
//hide tooltip
d3.selectAll('.tooltip')
.style('display', 'none');
});
//draw median lines
//draw x-median every time
const x_median = x_scale(d3.quantile(x_data, 0.5))
svg.append('path')
.attr('d', d3.line()([[x_median, p_h], [x_median, (height-p_h)]]))
.attr('stroke', "black")
.style('fill', 'none')
.style('stroke-dasharray', '5,5');
//draw y-median if it represents a metric
if (y_metric != "Number of stories") {
const y_median = y_scale(d3.quantile(y_data, 0.5))
svg.append('path')
.attr('d', d3.line()([[p_w, y_median], [(width-p_w), y_median]]))
.attr('stroke', "black")
.style('fill', 'none')
.style('stroke-dasharray', '5,5');
}
return svg.node();
}