<commit_before>import _ from 'lodash'
import d3 from 'd3'

import formatUtil from 'util/format'

function _sortValue (s, sortCol) {
  // jshint validthis: true
  var options = this._options

  var val = (sortCol === null)
    ? options.seriesName(s)
    : options.value(_.find(options.values(s), d => options.column(d) === sortCol))

  return val
}

var DEFAULTS = {
  cellSize: 16,
  column: _.property('indicator.short_name'),
  sourceColumn: _.property('short_name'),
  fontSize: 12,
  format: formatUtil.general,
  headerText: _.property('short_name'),
  headers: [],
  onClick: null,
  onColumnHeadOver: null,
  onColumnHeadOut: null,
  onMouseMove: null,
  onMouseOut: null,
  onRowClick: null,
  seriesName: _.property('name'),
  sortValue: _sortValue,
  values: _.property('values'),
  value: _.property('value'),
  sortDirection: 1
}

function TableChart () {}

_.extend(TableChart.prototype, {
  defaults: DEFAULTS,
  sortCol: null,

  initialize: function (el, data, options) {
    options = this._options = _.defaults({}, options, DEFAULTS)

    var svg = this._svg = d3.select(el)
        .append('svg')
        .attr('class', 'heatmap sortable')

    var g = svg.append('g').attr('class', 'margin')

    g.append('g').attr('class', 'z axis')
    g.append('g').attr('class', 'y axis')
    g.append('g').attr('class', 'x axis')
    g.append('g').attr('class', 'data')
    g.append('g').attr('class', 'source-footer')
    g.append('g').attr('class', 'legend')

    this.update(data)
  },

  update: function (data, options) {
    options = _.extend(this._options, options)
    var margin = options.margin

    var self = this
    var parentLocationMap = options.parentLocationMap

    var w = 3 * Math.max(options.headers.length * options.cellSize, 0)
    var h = Math.max(data.length * options.cellSize, 0)
    var z = 160 //  extra margin space needed to add the "z" (parent) axis"

    // hacky way to sclae the view box.. this shoudl be done by taking into
    // account the user's screen size... needs some time to get 100% right.. //
    var viewBoxHeightScale = 1 + (options.headers.length - 8) / 10
    if (viewBoxHeightScale < 1) {
      viewBoxHeightScale = 1
    }
    var viewBox = '0 0 ' + (w + margin.left + margin.right) + ' ' + ((h * viewBoxHeightScale) + margin.top + margin.bottom)

    var svg = this._svg
      .attr({
        'viewBox': viewBox,
        'width': (w + margin.left + margin.right),
        'height': (h + margin.top + margin.bottom)
      })
      .datum(data)

    var xScale = d3.scale.ordinal()
        .domain(_.map(options.headers, options.headerText))
        .rangeBands([0, w], 0.1)

    var x = _.flow(options.column, xScale)
    var sourceFlow = _.flow(options.sourceColumn, xScale)

    // if there is a sortCol set, order the data that way. //
    if (this.sortCol) {
      let sortValue = _.partial(options.sortValue.bind(this), _, this.sortCol)
      var domain = _(data).sortBy(sortValue, this).map(options.seriesName).value()
    } else {
      // if not, show default.  This also applies to the third click of a header
      domain = options.defaultSortOrder
      this.sortDirection = 1
    }

    if (this.sortDirection === -1) {
      domain = domain.reverse()
    }
<commit_msg>when a variable has missing data, make sure the yScale domain represents all yAxis values<commit_after>import _ from 'lodash'
import d3 from 'd3'

import formatUtil from 'util/format'

function _sortValue (s, sortCol) {
  // jshint validthis: true
  var options = this._options

  var val = (sortCol === null)
    ? options.seriesName(s)
    : options.value(_.find(options.values(s), d => options.column(d) === sortCol))

  return val
}

var DEFAULTS = {
  cellSize: 16,
  column: _.property('indicator.short_name'),
  sourceColumn: _.property('short_name'),
  fontSize: 12,
  format: formatUtil.general,
  headerText: _.property('short_name'),
  headers: [],
  onClick: null,
  onColumnHeadOver: null,
  onColumnHeadOut: null,
  onMouseMove: null,
  onMouseOut: null,
  onRowClick: null,
  seriesName: _.property('name'),
  sortValue: _sortValue,
  values: _.property('values'),
  value: _.property('value'),
  sortDirection: 1
}

function TableChart () {}

_.extend(TableChart.prototype, {
  defaults: DEFAULTS,
  sortCol: null,

  initialize: function (el, data, options) {
    options = this._options = _.defaults({}, options, DEFAULTS)

    var svg = this._svg = d3.select(el)
        .append('svg')
        .attr('class', 'heatmap sortable')

    var g = svg.append('g').attr('class', 'margin')

    g.append('g').attr('class', 'z axis')
    g.append('g').attr('class', 'y axis')
    g.append('g').attr('class', 'x axis')
    g.append('g').attr('class', 'data')
    g.append('g').attr('class', 'source-footer')
    g.append('g').attr('class', 'legend')

    this.update(data)
  },

  update: function (data, options) {
    options = _.extend(this._options, options)
    var margin = options.margin

    var self = this
    var parentLocationMap = options.parentLocationMap
    var w = 3 * Math.max(options.headers.length * options.cellSize, 0)
    var h = Math.max(options.defaultSortOrder.length * options.cellSize, 0)
    var z = 160 //  extra margin space needed to add the "z" (parent) axis"

    // hacky way to sclae the view box.. this shoudl be done by taking into
    // account the user's screen size... needs some time to get 100% right.. //
    var viewBoxHeightScale = 1 + (options.headers.length - 8) / 10
    if (viewBoxHeightScale < 1) {
      viewBoxHeightScale = 1
    }
    var viewBox = '0 0 ' + (w + margin.left + margin.right) + ' ' + ((h * viewBoxHeightScale) + margin.top + margin.bottom)
    var svg = this._svg
      .attr({
        'viewBox': viewBox,
        'width': (w + margin.left + margin.right),
        'height': (h + margin.top + margin.bottom)
      })
      .datum(data)

    var xScale = d3.scale.ordinal()
        .domain(_.map(options.headers, options.headerText))
        .rangeBands([0, w], 0.1)

    var x = _.flow(options.column, xScale)
    var sourceFlow = _.flow(options.sourceColumn, xScale)

    // if there is a sortCol set, order the data that way. //
    if (this.sortCol) {
      let sortValue = _.partial(options.sortValue.bind(this), _, this.sortCol)
      var domain = _(data).sortBy(sortValue, this).map(options.seriesName).value()
    } else {
      // if not, show default.  This also applies to the third click of a header
      domain = options.defaultSortOrder
      this.sortDirection = 1
    }

    if (this.sortDirection === -1) {
      domain = domain.reverse()
    }

    // For empty data points i need to add the x axis domain items explicitly //
    // otherwise the domain will be less ( and different the ) the yScale //
    // see trello : https://trello.com/c/bCwyqSWs/277-display-bug-when-creating-table-chart //
    if (domain.length < options.defaultSortOrder.length) {
      var diff = options.defaultSortOrder.filter(function (x) {
        return domain.indexOf(x) < 0
      })
      domain = domain.concat(diff)
    }

{'fraction_non_alphanumeric': 0.14591605218377765, 'fraction_numerical': 0.00935904707884288, 'mean_word_length': 2.978003384094755, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4007594', 'n_tokens_mistral': 2346, 'n_tokens_neox': 2265, 'n_words': 610}