_includes/fairness_visualization/visualization.js
// Create histogram for scores of items in a model.
Create histogram for scores of items in a model.
Create histogram for scores of items in a model .
function createHistogram(id, model, noThreshold, includeAnnotation, linked_model) {
  var width = HISTOGRAM_WIDTH;
  var height = HEIGHT;
  var bottom = height - 16;
  var items = copyItems(model.items);
  var numBuckets = 100 / HISTOGRAM_BUCKET_SIZE;
  var pedestalWidth = numBuckets * SIDE;
  var hx = (width - pedestalWidth) / 2;
    var scale = d3.scaleLinear().range([hx, hx + pedestalWidth]).
      domain([0, 100]);
  var scale2 = d3.scaleLinear().range([hx, hx + pedestalWidth]).
      domain([300, 800]);
  function histogramLayout(items, x, y, side, low, high, bucketSize, y_side_ratio) {
    var buckets = [];
    var maxNum = Math.floor((high - low) / bucketSize);
    items.forEach(function(item) {
      var bn = Math.floor((item.score - low) / bucketSize);
      bn = Math.max(0, Math.min(maxNum, bn));
      buckets[bn] = 1 + (buckets[bn] || 0);
      item.x = x + side * bn;
      item.y = y - side * y_side_ratio * buckets[bn];
      item.side = side;
      item.side_y = side * y_side_ratio;
    });
  }
  histogramLayout(items, hx, bottom, SIDE, 0, 100, HISTOGRAM_BUCKET_SIZE, Y_SIDE_RATIO);
  var svg = createIcons(id, items, width, height);
  var tx = width / 2;
  var topY = 60;
  var axis = d3.axisBottom(scale2);
  svg.append('g').attr('class', 'histogram-axis')
    .attr('transform', 'translate(0,-8)')
    .call(axis);
  d3.select('.domain').attr('stroke-width', 1);
  if (noThreshold) {
    return;
  }
  var cutoff = svg.append('rect').attr('x', tx - 2).attr('y', topY - 10).
      attr('width', 3).attr('height', height - topY);
  var thresholdLabel = svg.append('text').text('loan threshold: 550') 
      .attr('x', tx)
      .attr('y', 40)
      .attr('text-anchor', 'middle').attr('class', 'bold-label');
  if (includeAnnotation) {
    var annotationPad = 10;
    var annotationW = 200;
    var thresholdAnnotation = svg.append('rect')
        .attr('class', 'annotation group-unaware-annotation')
        .attr('x', tx - annotationW / 2)
        .attr('y', 30 - annotationPad)
        .attr('rx', 20)
        .attr('ry', 20)
        .attr('width', annotationW)
        .attr('height', 30);
   }
  function setThreshold(t, eventFromUser) {
    t = Math.max(0, Math.min(t, 100));
    if (eventFromUser) {
      t = HISTOGRAM_BUCKET_SIZE * Math.round(t / HISTOGRAM_BUCKET_SIZE);
    } else {
      tx = Math.round(scale(t));
      t = HISTOGRAM_BUCKET_SIZE * Math.round(t / HISTOGRAM_BUCKET_SIZE)
    }
    tx = Math.max(0, Math.min(width - 4, tx));
    var rounded = SIDE * Math.round(tx / SIDE);
    cutoff.attr('x', rounded);
    var labelX = Math.max(50, Math.min(rounded, width - 70));
    thresholdLabel.attr('x', labelX).text('loan threshold: ' + (t * 5 + 300));
    if (includeAnnotation) {
      thresholdAnnotation.attr('x', tx - annotationW / 2);
    }
    svg.selectAll('.icon').call(defineIcon);
  }
  var drag = d3.drag()
    .on('drag', function() {
      var oldTx = tx;
      tx += d3.event.dx;
      var t = scale.invert(tx);
      setThreshold(t, true);
      if (tx != oldTx) {
        model.classify(t);
        model.notifyListeners('histogram-drag');
      }
  });
  svg.call(drag);
  model.addListener(function(event) {
    for (var i = 0; i < items.length; i++) {
      items[i].predicted = items[i].score >= model.threshold ? 1 : 0;
    }
    if (!(typeof linked_model == "undefined") && event == 'histogram-drag') {
      translateThresh(model, linked_model, model.link_setting) 
    }
    setThreshold(model.threshold, event == 'histogram-drag');
  });
}
function createHistogram ( id , model , noThreshold , includeAnnotation , linked_model ) { var width = HISTOGRAM_WIDTH ; var height = HEIGHT ; var bottom = height - 16 ; var items = copyItems ( model . items ) ; var numBuckets = 100 / HISTOGRAM_BUCKET_SIZE ; var pedestalWidth = numBuckets * SIDE ; var hx = ( width - pedestalWidth ) / 2 ; var scale = d3 . scaleLinear ( ) . range ( [ hx , hx + pedestalWidth ] ) . domain ( [ 0 , 100 ] ) ; var scale2 = d3 . scaleLinear ( ) . range ( [ hx , hx + pedestalWidth ] ) . domain ( [ 300 , 800 ] ) ; function histogramLayout ( items , x , y , side , low , high , bucketSize , y_side_ratio ) { var buckets = [ ] ; var maxNum = Math . floor ( ( high - low ) / bucketSize ) ; items . forEach ( function ( item ) { var bn = Math . floor ( ( item . score - low ) / bucketSize ) ; bn = Math . max ( 0 , Math . min ( maxNum , bn ) ) ; buckets [ bn ] = 1 + ( buckets [ bn ] || 0 ) ; item . x = x + side * bn ; item . y = y - side * y_side_ratio * buckets [ bn ] ; item . side = side ; item . side_y = side * y_side_ratio ; } ) ; } histogramLayout ( items , hx , bottom , SIDE , 0 , 100 , HISTOGRAM_BUCKET_SIZE , Y_SIDE_RATIO ) ; var svg = createIcons ( id , items , width , height ) ; var tx = width / 2 ; var topY = 60 ; var axis = d3 . axisBottom ( scale2 ) ; svg . append ( 'g' ) . attr ( 'class' , 'histogram-axis' ) . attr ( 'transform' , 'translate(0,-8)' ) . call ( axis ) ; d3 . select ( '.domain' ) . attr ( 'stroke-width' , 1 ) ; if ( noThreshold ) { return ; } var cutoff = svg . append ( 'rect' ) . attr ( 'x' , tx - 2 ) . attr ( 'y' , topY - 10 ) . attr ( 'width' , 3 ) . attr ( 'height' , height - topY ) ; var thresholdLabel = svg . append ( 'text' ) . text ( 'loan threshold: 550' ) . attr ( 'x' , tx ) . attr ( 'y' , 40 ) . attr ( 'text-anchor' , 'middle' ) . attr ( 'class' , 'bold-label' ) ; if ( includeAnnotation ) { var annotationPad = 10 ; var annotationW = 200 ; var thresholdAnnotation = svg . append ( 'rect' ) . attr ( 'class' , 'annotation group-unaware-annotation' ) . attr ( 'x' , tx - annotationW / 2 ) . attr ( 'y' , 30 - annotationPad ) . attr ( 'rx' , 20 ) . attr ( 'ry' , 20 ) . attr ( 'width' , annotationW ) . attr ( 'height' , 30 ) ; } function setThreshold ( t , eventFromUser ) { t = Math . max ( 0 , Math . min ( t , 100 ) ) ; if ( eventFromUser ) { t = HISTOGRAM_BUCKET_SIZE * Math . round ( t / HISTOGRAM_BUCKET_SIZE ) ; } else { tx = Math . round ( scale ( t ) ) ; t = HISTOGRAM_BUCKET_SIZE * Math . round ( t / HISTOGRAM_BUCKET_SIZE ) } tx = Math . max ( 0 , Math . min ( width - 4 , tx ) ) ; var rounded = SIDE * Math . round ( tx / SIDE ) ; cutoff . attr ( 'x' , rounded ) ; var labelX = Math . max ( 50 , Math . min ( rounded , width - 70 ) ) ; thresholdLabel . attr ( 'x' , labelX ) . text ( 'loan threshold: ' + ( t * 5 + 300 ) ) ; if ( includeAnnotation ) { thresholdAnnotation . attr ( 'x' , tx - annotationW / 2 ) ; } svg . selectAll ( '.icon' ) . call ( defineIcon ) ; } var drag = d3 . drag ( ) . on ( 'drag' , function ( ) { var oldTx = tx ; tx += d3 . event . dx ; var t = scale . invert ( tx ) ; setThreshold ( t , true ) ; if ( tx != oldTx ) { model . classify ( t ) ; model . notifyListeners ( 'histogram-drag' ) ; } } ) ; svg . call ( drag ) ; model . addListener ( function ( event ) { for ( var i = 0 ; i < items . length ; i ++ ) { items [ i ] . predicted = items [ i ] . score >= model . threshold ? 1 : 0 ; } if ( ! ( typeof linked_model == "undefined" ) && event == 'histogram-drag' ) { translateThresh ( model , linked_model , model . link_setting ) } setThreshold ( model . threshold , event == 'histogram-drag' ) ; } ) ; }
Create histogram for scores of items in a model.
Create histogram for scores of items in a model .
// Create an internal copy. // Icons // Sliding threshold bar. // 50 * (500/100) + 300