Spaces:
Running
Running
window.highlightColor = '#bf0bbf' | |
window.makeSliders = function(metrics, sets, c, selectSet, drawRow, onRender){ | |
var width = 180 | |
var height = 30 | |
var color = '#000' | |
var xScale = d3.scaleLinear().range([0, width]).domain([0, 1]) | |
.clamp(1) | |
var sliderSel = c.svg.appendMany('g', metrics) | |
.translate((d, i) => [-c.margin.left -10 , 130*i + 30]) | |
.on('click', function(d){ | |
d.target = xScale.invert(d3.mouse(this)[0]) | |
render() | |
}) | |
.classed('slider', true) | |
.st({cursor: 'pointer'}) | |
var textSel = sliderSel.append('text.slider-label-container') | |
.at({y: -20, fontWeight: 500, textAnchor: 'middle', x: 180/2}) | |
sliderSel.append('rect') | |
.at({width, height, y: -height/2, fill: 'rgba(0,0,0,0)'}) | |
sliderSel.append('path').at({ | |
d: `M 0 -.5 H ${width}`, | |
stroke: color, | |
strokeWidth: 1 | |
}) | |
var leftPathSel = sliderSel.append('path').at({ | |
d: `M 0 -.5 H ${width}`, | |
stroke: color, | |
strokeWidth: 3 | |
}) | |
var drag = d3.drag() | |
.on('drag', function(d){ | |
var x = d3.mouse(this)[0] | |
d.target = xScale.invert(x) | |
render() | |
}) | |
var circleSel = sliderSel.append('circle').call(drag) | |
.at({r: 7, stroke: '#000'}) | |
var exSel = c.svg.append('g').translate([-c.margin.left -10, 400]) | |
.st({fontSize: 13}) | |
var curY = 0 | |
exSel.append('g') | |
.append('text').text('The selected set is...') | |
var selectedSetG = exSel.append('g.selected').translate([-10, curY += 15]) | |
.datum(sets[0]) | |
.call(drawRow) | |
selectedSetG.select('.no-stroke').classed('selected', 1) | |
curY += 25 | |
var exMetrics = exSel.appendMany('g', metrics) | |
.translate(() => curY +=22, 1) | |
.append('text').html(d => '10% small, 10% more than target') | |
curY += 10 | |
var exMeanDiff = exSel.append('text').translate(() => curY +=22, 1) | |
.at({textAnchor: 'end', x: 190}) | |
var exMaxDiff = exSel.append('text').translate(() => curY +=22, 1) | |
.at({textAnchor: 'end', x: 190}) | |
// Make histogram data | |
sliderSel.each(function(metric){ | |
var countKey = metric.key + '_count' | |
sets.forEach(set => { | |
var v = d3.sum(set, d => d[metric.field] == metric.key) | |
set[countKey] = v / set.length | |
}) | |
var byCountKey = d3.nestBy(sets, d => d[countKey]) | |
d3.range(.1, 1, .1).forEach(i => { | |
if (byCountKey.some(d => d.key*100 == Math.round(i*100))) return | |
var rv = [] | |
rv.key = i | |
byCountKey.push(rv) | |
}) | |
byCountKey.forEach(d => { | |
d.metric = metric | |
d.key = +d.key | |
}) | |
var countSel = d3.select(this).append('g.histogram').lower() | |
.translate(30, 1) | |
.appendMany('g', byCountKey) | |
.translate(d => xScale.clamp(0)(d.key - .05), 0) | |
xScale.clamp(1) | |
countSel.append('text') | |
// .text(d => '10') | |
.at({fontSize: 11, opacity: .7, y: -8, textAnchor: 'middle', x: 9.5}) | |
.text(d => d.key*100) | |
countSel.append('path') | |
.at({d: 'M 9.5 -18 V -30', stroke: '#ccc'}) | |
countSel | |
.appendMany('rect.histogram-set', d => d) | |
.at({width: 16, height: 4, x: 1.5, y: (d, i) => i*6}) | |
// .on('mouseover', selectSet) | |
}) | |
var histogramSetSel = sliderSel.selectAll('rect.histogram-set') | |
.st({cursor: 'default'}) | |
var axisSel = sliderSel.selectAll('.histogram text') | |
var pinkSel = sliderSel.append('g') | |
.at({r: 4, fill: highlightColor}) | |
.st({pointerEvents: 'none', opacity:0}) | |
pinkSel.append('path').at({stroke: highlightColor, d: 'M .5 0 V 15'}) | |
pinkSel.append('text').at({y: 30, textAnchor: 'middle'}) | |
pinkSel.append('text.score').at({y: 50, textAnchor: 'middle'}) | |
function render(){ | |
circleSel.at({cx: d => xScale(d.target)}) | |
// circleSel.at({cx: d => xScale(d.target)}) | |
textSel.text(d => (d.str + ' Target: ').replace('s ', ' ') + pctFmt(d.target)) | |
axisSel | |
.classed('selected', false) | |
// .text(function(d){ | |
// var str = Math.round(100*Math.abs(d.key - d.metric.target)) | |
// if (d.some(e => e.selected)){ | |
// d3.select(this).classed('selected', 1) | |
// // str = str + '%' | |
// } | |
// return str | |
// }) | |
leftPathSel.at({d: d => `M 0 -.5 H ${xScale(d.target)}`}) | |
metrics.forEach(d => { | |
d.scoreScale = d3.scaleLinear() | |
.domain([-.1, d.target, 1.1]) | |
.range([0, 1, 0]) | |
}) | |
histogramSetSel.st({fill: d => d === sets.selected ? highlightColor: '#bbb'}) | |
if (onRender) onRender() | |
var shapes = sets.selected | |
var metricVals = metrics.map(m => { | |
return d3.sum(shapes, (d, i) => shapes[i][m.field] == m.key)/shapes.length | |
}) | |
pinkSel.translate((d, i) => xScale(metricVals[i]), 0) | |
pinkSel.select('text').text((d, i) => pctFmt(metricVals[i])) | |
pinkSel.select('.score').text((d, i) => 'Difference: ' + Math.round(shapes.score[i]*100)) | |
selectedSetG.html('') | |
.datum(sets.selected) | |
.call(drawRow) | |
selectedSetG.select('.no-stroke').classed('selected', 1) | |
exMetrics | |
.html((d, i) => { | |
var target = d.target | |
var actual = sets.selected[d.key + '_count'] | |
var diff = sets.selected.score[i] | |
var str = d.str.replace('ls', 'l').replace('ns', 'n').toLowerCase() | |
return ` | |
${pctFmt(actual)} | |
${str}, | |
${pctFmt(diff)} | |
${actual < target ? 'less' : 'more'} than target | |
` | |
}) | |
.at({textAnchor: 'end', x: 190}) | |
exMeanDiff | |
.text('Mean Difference: ' + d3.format('.2%')(sets.selected['Utilitarian']/100)) | |
exMaxDiff | |
.text('Max Difference: ' + measures[1].ppFn(sets.selected['score']).replace('%', '.00%')) | |
} | |
return {render} | |
} | |
// window.initColumns('#columns-height', metrics1, measures) | |
// window.initColumns('#columns-height-disagree', metrics2, measures2) | |