<commit_before>/**
 * Summarized stats for a data series or set of series. When
 * constructed with a data series, computes the sum, min, max, and
 * mean.
 *
 * The input format is assumed to be the JSON representation returned
 * by graphite-web.
 */
ds.models.data.Summation = function(initial_data) {
  "use strict"

  var self = limivorous.observable()
                       .property('sum', { init: 0 })
                       .property('min', { init: Number.MAX_VALUE })
                       .property('min_index')
                       .property('max', { init: Number.MIN_VALUE })
                       .property('max_index')
                       .property('mean', { init: 0 })
                       .property('median', { init: 0 })
                       .property('first', { init: 0 })
                       .property('last', { init: 0 })
                       .property('count', { init: 0 })
                       .build()
  Object.defineProperty(self, 'is_summation', {value: true})

  function if_defined(value, default_value) {
    return typeof(value) === 'undefined'
         ? default_value
         : value
  }

  /**
   * Initialize the summation
   */
  var datapoints = []

  if (initial_data && (initial_data instanceof Array) && (initial_data.length)) {
    /* This assumes that all input series have the same number of data points */
    var length = initial_data[0].datapoints.length
    var summed_datapoints = []
    for (var i = 0; i < length; i++) {
      var x = 0
      for (var n = 0; n < initial_data.length; n++) {
        /* ignore input series which are smaller than the first series */
        if(typeof(initial_data[n].datapoints[i]) !== 'undefined') {
          x += initial_data[n].datapoints[i][0]
        }
      }
      datapoints.push([x, initial_data[0].datapoints[i][1]])
    }
  } else if (initial_data && initial_data.datapoints) {
    datapoints = initial_data.datapoints
  }

  if (datapoints && datapoints.length) {
    /* add simple-statistics methods */
    var values = ss.mixin(datapoints.map(function(point) {
                            return point[0]
                          }))
    self.median = values.median()
    self.first = datapoints[0][0]
    self.count = datapoints.length
    if (self.first == null) {
      self.first = 0
    }
    var index = 0
    datapoints.forEach(function(point) {
      var value = point[0] || 0
      self.last = value
      self.sum = self.sum + value
      if (value > self.max) {
        self.max = value
        self.max_index = index
      }
      if (point[0] && (value < self.min)) {
        self.min = value
        self.min_index = index
      }
      index++
    })<commit_msg>Bugfix: don't leave uninitialized min & max in Summation if the sum is zero<commit_after>/**
 * Summarized stats for a data series or set of series. When
 * constructed with a data series, computes the sum, min, max, and
 * mean.
 *
 * The input format is assumed to be the JSON representation returned
 * by graphite-web.
 */
ds.models.data.Summation = function(initial_data) {
  "use strict"

  var self = limivorous.observable()
                       .property('sum', { init: 0 })
                       .property('min', { init: Number.MAX_VALUE })
                       .property('min_index')
                       .property('max', { init: Number.MIN_VALUE })
                       .property('max_index')
                       .property('mean', { init: 0 })
                       .property('median', { init: 0 })
                       .property('first', { init: 0 })
                       .property('last', { init: 0 })
                       .property('count', { init: 0 })
                       .build()
  Object.defineProperty(self, 'is_summation', {value: true})

  function if_defined(value, default_value) {
    return typeof(value) === 'undefined'
         ? default_value
         : value
  }

  /**
   * Initialize the summation
   */
  var datapoints = []

  if (initial_data && (initial_data instanceof Array) && (initial_data.length)) {
    /* This assumes that all input series have the same number of data points */
    var length = initial_data[0].datapoints.length
    var summed_datapoints = []
    for (var i = 0; i < length; i++) {
      var x = 0
      for (var n = 0; n < initial_data.length; n++) {
        /* ignore input series which are smaller than the first series */
        if(typeof(initial_data[n].datapoints[i]) !== 'undefined') {
          x += initial_data[n].datapoints[i][0]
        }
      }
      datapoints.push([x, initial_data[0].datapoints[i][1]])
    }
  } else if (initial_data && initial_data.datapoints) {
    datapoints = initial_data.datapoints
  }

  if (datapoints && datapoints.length) {
    /* add simple-statistics methods */
    var values = ss.mixin(datapoints.map(function(point) {
                            return point[0]
                          }))
    self.median = values.median()
    self.first = datapoints[0][0]
    self.count = datapoints.length
    if (self.first == null) {
      self.first = 0
    }
    var index = 0
    datapoints.forEach(function(point) {
      var value = point[0] || 0
      self.last = value
      self.sum = self.sum + value
      if (value > self.max) {
        self.max = value
        self.max_index = index
      }
      if (point[0] && (value < self.min)) {
        self.min = value
        self.min_index = index
      }
      index++
    })
    if (self.sum === 0) {
      self.min = 0
      self.max = 0
    }
{'fraction_non_alphanumeric': 0.12844202898550725, 'fraction_numerical': 0.008152173913043478, 'mean_word_length': 1.868051948051948, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, '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': '212786', 'n_tokens_mistral': 1717, 'n_tokens_neox': 1640, 'n_words': 423}