<commit_before>// libraries
import React, { Component } from 'react'
import PropTypes from 'prop-types'

import { ResponsiveContainer, ComposedChart, Area, Line, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ReferenceLine } from 'recharts'
import moment from 'moment'

// utils

// components
import BasicTooltip from './basic-tooltip'

// logic

export const colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']

function sharedStart (array) {
  let A = array.concat().sort()
  let a1 = A[0]
  let a2 = A[A.length - 1]
  let L = a1.length
  let i = 0
  while (i < L && a1.charAt(i) === a2.charAt(i)) { i++ }
  return a1.substring(0, i)
}

const alphabeticalFacetSorter = (a, b) => a.name.localeCompare(b.name)

function getGraphData (graph, controls) {
  const { results, keys, timeGroup } = graph
  const { percentages, compareWith, compareWithPercentageLine, prediction } = controls

  const graphData = results.map(oldRow => {
    const time = oldRow.time
    const row = Object.assign({}, oldRow, { time: moment(time).valueOf() })

    if (percentages || (compareWith)) {
      let total = 0
      for (const key of keys) {
        total += parseFloat(row[key] || 0)
      }
      if (percentages) {
        for (const key of keys) {
          row[key + '__%'] = total !== 0 ? (parseFloat(row[key]) / total * 100) : 0
        }
      }

      if (compareWith) {
        let compareWithTotal = 0
        for (const key of keys) {
          compareWithTotal += parseFloat(row['compareWith::' + key] || 0)
        }

        if (percentages) {
          for (const key of keys) {
            row['compareWith::' + key + '__%'] = compareWithTotal !== 0 ? (parseFloat(row['compareWith::' + key]) / compareWithTotal * 100) : 0
          }
        }

        if (compareWithPercentageLine && compareWithTotal !== 0) {
          let totalToCompareWith = compareWithTotal

          if (prediction) {
            if (moment().startOf(timeGroup === 'week' ? 'isoWeek' : timeGroup).format('YYYY-MM-DD') === time) {
              const fullTime = moment().endOf(timeGroup === 'week' ? 'isoWeek' : timeGroup).unix() - moment().startOf(timeGroup === 'week' ? 'isoWeek' : timeGroup).unix()
              const elapsedTime = moment().unix() - moment().startOf(timeGroup === 'week' ? 'isoWeek' : timeGroup).unix()

              totalToCompareWith = totalToCompareWith * elapsedTime / fullTime
            }
          }

          row['compareWith:percentageLine'] = (total - totalToCompareWith) / totalToCompareWith * 100
        }
      }
    }
    return row
  })

  return graphData
}

export class Graph extends Component {
  static propTypes = {
    graph: PropTypes.object,

    controls: PropTypes.shape({
      type: PropTypes.oneOf(['area', 'bar', 'line']).isRequired,
      sort: PropTypes.oneOf(['123', 'abc']).isRequired,
      cumulative: PropTypes.bool,
      percentages: PropTypes.bool,
      labels: PropTypes.bool,
      compareWith: PropTypes.number,
      compareWithPercentageLine: PropTypes.bool,
      prediction: PropTypes.bool
    }).isRequired
  }

  static defaultProps = {
    tooltip: BasicTooltip
  }

  constructor (props) {
    super(props)

    this.state = {
      visibility: {},
      graphData: getGraphData(props.graph, props.controls)
    }
  }

  componentWillReceiveProps (nextProps) {
    if (this.props.graph !== nextProps.graph || this.props.controls !== nextProps.controls) {
      this.setState({
        graphData: getGraphData(nextProps.graph, nextProps.controls)
      })
    }
  }

  handleClick = (o) => {
    const { dataKey } = o
    const { visibility } = this.state

    const key = dataKey.replace(/__hidden$/, '')

    this.setState({
      visibility: { ...visibility, [key]: typeof visibility[key] === 'undefined' ? false : !visibility[key] }
    })
  }

  timeFormatter (time) {
    return moment(time).format('MMM DD')
  }

  yearFormatter (time) {
    return moment(time).format('YYYY')
  }

  quarterFormatter (time) {
    return 'Q' + moment(time).format('Q YYYY')
  }

  shortQuarterFormatter (time) {
    return 'Q' + moment(time).format('Q\'YY')
  }

  monthFormatter (time) {
    return moment(time).format(moment(time).month() === 0 ? 'YYYY' : 'MMMM')
  }

  shortMonthFormatter (time) {
    return moment(time).format(moment(time).month() === 0 ? 'YYYY' : 'MMM')
  }

  getTicks () {
    // const { data, timeGroup } = this.props
    const { graph: { timeGroup } } = this.props
    const { graphData: data } = this.state

    let ticks = []

    if (data.length === 0) {
      return ticks
    }

    const timeStart = data[0].time
    const timeEnd = data[data.length - 1].time

    const day = 86000 * 1000

    let unit = 'month'

    if (timeGroup === 'month' || timeGroup === 'year' || timeGroup === 'quarter') {
      unit = timeGroup
    } else if (timeEnd - timeStart < 32 * day && timeGroup !== 'week') {
      unit = 'day'
    } else if (timeEnd - timeStart < 365 * day) {
      unit = 'week'
    }

    let time = moment(timeStart).startOf(unit)
    if (time >= timeStart) {
      ticks.push(time.valueOf())
    }
    while (time < timeEnd) {
      time = time.add(1, unit)
      if (time <= timeEnd) {
        ticks.push(time.valueOf())
      }<commit_msg>align week dots with mondays<commit_after>// libraries
import React, { Component } from 'react'
import PropTypes from 'prop-types'

import { ResponsiveContainer, ComposedChart, Area, Line, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ReferenceLine } from 'recharts'
import moment from 'moment'

// utils

// components
import BasicTooltip from './basic-tooltip'

// logic

export const colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']

function sharedStart (array) {
  let A = array.concat().sort()
  let a1 = A[0]
  let a2 = A[A.length - 1]
  let L = a1.length
  let i = 0
  while (i < L && a1.charAt(i) === a2.charAt(i)) { i++ }
  return a1.substring(0, i)
}

const alphabeticalFacetSorter = (a, b) => a.name.localeCompare(b.name)

function getGraphData (graph, controls) {
  const { results, keys, timeGroup } = graph
  const { percentages, compareWith, compareWithPercentageLine, prediction } = controls

  const graphData = results.map(oldRow => {
    const time = oldRow.time
    const row = Object.assign({}, oldRow, { time: moment(time).valueOf() })

    if (percentages || (compareWith)) {
      let total = 0
      for (const key of keys) {
        total += parseFloat(row[key] || 0)
      }
      if (percentages) {
        for (const key of keys) {
          row[key + '__%'] = total !== 0 ? (parseFloat(row[key]) / total * 100) : 0
        }
      }

      if (compareWith) {
        let compareWithTotal = 0
        for (const key of keys) {
          compareWithTotal += parseFloat(row['compareWith::' + key] || 0)
        }

        if (percentages) {
          for (const key of keys) {
            row['compareWith::' + key + '__%'] = compareWithTotal !== 0 ? (parseFloat(row['compareWith::' + key]) / compareWithTotal * 100) : 0
          }
        }

        if (compareWithPercentageLine && compareWithTotal !== 0) {
          let totalToCompareWith = compareWithTotal

          if (prediction) {
            if (moment().startOf(timeGroup === 'week' ? 'isoWeek' : timeGroup).format('YYYY-MM-DD') === time) {
              const fullTime = moment().endOf(timeGroup === 'week' ? 'isoWeek' : timeGroup).unix() - moment().startOf(timeGroup === 'week' ? 'isoWeek' : timeGroup).unix()
              const elapsedTime = moment().unix() - moment().startOf(timeGroup === 'week' ? 'isoWeek' : timeGroup).unix()

              totalToCompareWith = totalToCompareWith * elapsedTime / fullTime
            }
          }

          row['compareWith:percentageLine'] = (total - totalToCompareWith) / totalToCompareWith * 100
        }
      }
    }
    return row
  })

  return graphData
}

export class Graph extends Component {
  static propTypes = {
    graph: PropTypes.object,

    controls: PropTypes.shape({
      type: PropTypes.oneOf(['area', 'bar', 'line']).isRequired,
      sort: PropTypes.oneOf(['123', 'abc']).isRequired,
      cumulative: PropTypes.bool,
      percentages: PropTypes.bool,
      labels: PropTypes.bool,
      compareWith: PropTypes.number,
      compareWithPercentageLine: PropTypes.bool,
      prediction: PropTypes.bool
    }).isRequired
  }

  static defaultProps = {
    tooltip: BasicTooltip
  }

  constructor (props) {
    super(props)

    this.state = {
      visibility: {},
      graphData: getGraphData(props.graph, props.controls)
    }
  }

  componentWillReceiveProps (nextProps) {
    if (this.props.graph !== nextProps.graph || this.props.controls !== nextProps.controls) {
      this.setState({
        graphData: getGraphData(nextProps.graph, nextProps.controls)
      })
    }
  }

  handleClick = (o) => {
    const { dataKey } = o
    const { visibility } = this.state

    const key = dataKey.replace(/__hidden$/, '')

    this.setState({
      visibility: { ...visibility, [key]: typeof visibility[key] === 'undefined' ? false : !visibility[key] }
    })
  }

  timeFormatter (time) {
    return moment(time).format('MMM DD')
  }

  yearFormatter (time) {
    return moment(time).format('YYYY')
  }

  quarterFormatter (time) {
    return 'Q' + moment(time).format('Q YYYY')
  }

  shortQuarterFormatter (time) {
    return 'Q' + moment(time).format('Q\'YY')
  }

  monthFormatter (time) {
    return moment(time).format(moment(time).month() === 0 ? 'YYYY' : 'MMMM')
  }

  shortMonthFormatter (time) {
    return moment(time).format(moment(time).month() === 0 ? 'YYYY' : 'MMM')
  }

  getTicks () {
    // const { data, timeGroup } = this.props
    const { graph: { timeGroup } } = this.props
    const { graphData: data } = this.state

    let ticks = []

    if (data.length === 0) {
      return ticks
    }

    const timeStart = data[0].time
    const timeEnd = data[data.length - 1].time

    const day = 86000 * 1000

    let unit = 'month'

    if (timeGroup === 'month' || timeGroup === 'year' || timeGroup === 'quarter') {
      unit = timeGroup === 'week' ? 'isoWeek' : timeGroup
    } else if (timeEnd - timeStart < 32 * day && timeGroup !== 'week') {
      unit = 'day'
    } else if (timeEnd - timeStart < 365 * day) {
      unit = 'isoWeek'
    }

    let time = moment(timeStart).startOf(unit)
    if (time >= timeStart) {
      ticks.push(time.valueOf())
    }
    while (time < timeEnd) {
      time = time.add(1, unit)
      if (time <= timeEnd) {
        ticks.push(time.valueOf())
      }
{'fraction_non_alphanumeric': 0.1525678340061966, 'fraction_numerical': 0.01577316683879448, 'mean_word_length': 2.694762400277489, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 11, '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': '2971374', 'n_tokens_mistral': 3538, 'n_tokens_neox': 3378, 'n_words': 803}