<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import map from 'lodash.map';
import reduce from 'lodash.reduce';
import forEach from 'lodash.foreach';
import pluck from 'lodash.pluck';
import filter from 'lodash.filter';
import min from 'lodash.min';
import max from 'lodash.max';
import isNumber from 'lodash.isnumber';
import L from 'leaflet';
import { MapLayer } from 'react-leaflet';
import simpleheat from 'simpleheat';

export type LngLat = {
  lng: number;
  lat: number;
}

export type Point = {
  x: number;
  y: number;
}

export type Bounds = {
  contains: (latLng: LngLat) => boolean;
}

export type Map = {
  layerPointToLatLng: (lngLat: Point) => LngLat;
  latLngToLayerPoint: (lngLat: LngLat) => Point;
  on: (event: string, handler: () => void) => void;
  getBounds: () => Bounds;
  getPanes: () => Panes;
  invalidateSize: () => void;
  options: Object;
}

export type Panes = {
  overlayPane: Pane;
}

export type Pane = {
  appendChild: (element: Object) => void;
}

export type LeafletZoomEvent = {
  zoom: number;
  center: Object;
}

function isValidLatLngArray(arr: Array<number>): boolean {
  return filter(arr, isValid).length === arr.length;
}

function isInvalidLatLngArray(arr: Array<number>): boolean {
  return !isValidLatLngArray(arr);
}

function isInvalid(num: number): boolean {
  return !isNumber(num) && !num;
}

function isValid(num: number): boolean {
  return !isInvalid(num);
}

function shouldIgnoreLocation(loc: LngLat): boolean {
  return isInvalid(loc.lng) || isInvalid(loc.lat);
}

export default class HeatmapLayer extends MapLayer {
  static propTypes = {
    points: React.PropTypes.array.isRequired,
    longitudeExtractor: React.PropTypes.func.isRequired,
    latitudeExtractor: React.PropTypes.func.isRequired,
    intensityExtractor: React.PropTypes.func.isRequired,
    fitBoundsOnLoad: React.PropTypes.bool,
    fitBoundsOnUpdate: React.PropTypes.bool,
    onStatsUpdate: React.PropTypes.func,
    /* props controlling heatmap generation */
    max: React.PropTypes.number,
    radius: React.PropTypes.number,
    maxZoom: React.PropTypes.number,
    minOpacity: React.PropTypes.number,
    blur: React.PropTypes.number,
    gradient: React.PropTypes.object
  };

  componentDidMount(): void {
    this.leafletElement = ReactDOM.findDOMNode(this.refs.container);
    this.props.map.getPanes().overlayPane.appendChild(this.leafletElement);
    this._heatmap = simpleheat(this.leafletElement);

    if (this.props.fitBoundsOnLoad) {
      this.fitBounds();
    }

    this.attachEvents();
    this.updateHeatmapProps(this.getHeatmapProps());
    this.reset();
  }

  getMax(props) {
    return props.max || 3.0;
  }

  getRadius(props) {
    return props.radius || 30;
  }

  getMaxZoom(props) {
    return props.radius || 18;
  }

  getMinOpacity(props) {
    return props.minOpacity || 0.01;
  }

  getBlur(props) {
    return props.blur || 15;
  }

  getHeatmapProps() {
    return {<commit_msg>Fix getMaxZoom to use props.maxZoom  <commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import map from 'lodash.map';
import reduce from 'lodash.reduce';
import forEach from 'lodash.foreach';
import pluck from 'lodash.pluck';
import filter from 'lodash.filter';
import min from 'lodash.min';
import max from 'lodash.max';
import isNumber from 'lodash.isnumber';
import L from 'leaflet';
import { MapLayer } from 'react-leaflet';
import simpleheat from 'simpleheat';

export type LngLat = {
  lng: number;
  lat: number;
}

export type Point = {
  x: number;
  y: number;
}

export type Bounds = {
  contains: (latLng: LngLat) => boolean;
}

export type Map = {
  layerPointToLatLng: (lngLat: Point) => LngLat;
  latLngToLayerPoint: (lngLat: LngLat) => Point;
  on: (event: string, handler: () => void) => void;
  getBounds: () => Bounds;
  getPanes: () => Panes;
  invalidateSize: () => void;
  options: Object;
}

export type Panes = {
  overlayPane: Pane;
}

export type Pane = {
  appendChild: (element: Object) => void;
}

export type LeafletZoomEvent = {
  zoom: number;
  center: Object;
}

function isValidLatLngArray(arr: Array<number>): boolean {
  return filter(arr, isValid).length === arr.length;
}

function isInvalidLatLngArray(arr: Array<number>): boolean {
  return !isValidLatLngArray(arr);
}

function isInvalid(num: number): boolean {
  return !isNumber(num) && !num;
}

function isValid(num: number): boolean {
  return !isInvalid(num);
}

function shouldIgnoreLocation(loc: LngLat): boolean {
  return isInvalid(loc.lng) || isInvalid(loc.lat);
}

export default class HeatmapLayer extends MapLayer {
  static propTypes = {
    points: React.PropTypes.array.isRequired,
    longitudeExtractor: React.PropTypes.func.isRequired,
    latitudeExtractor: React.PropTypes.func.isRequired,
    intensityExtractor: React.PropTypes.func.isRequired,
    fitBoundsOnLoad: React.PropTypes.bool,
    fitBoundsOnUpdate: React.PropTypes.bool,
    onStatsUpdate: React.PropTypes.func,
    /* props controlling heatmap generation */
    max: React.PropTypes.number,
    radius: React.PropTypes.number,
    maxZoom: React.PropTypes.number,
    minOpacity: React.PropTypes.number,
    blur: React.PropTypes.number,
    gradient: React.PropTypes.object
  };

  componentDidMount(): void {
    this.leafletElement = ReactDOM.findDOMNode(this.refs.container);
    this.props.map.getPanes().overlayPane.appendChild(this.leafletElement);
    this._heatmap = simpleheat(this.leafletElement);

    if (this.props.fitBoundsOnLoad) {
      this.fitBounds();
    }

    this.attachEvents();
    this.updateHeatmapProps(this.getHeatmapProps());
    this.reset();
  }

  getMax(props) {
    return props.max || 3.0;
  }

  getRadius(props) {
    return props.radius || 30;
  }

  getMaxZoom(props) {
    return props.maxZoom || 18;
  }

  getMinOpacity(props) {
    return props.minOpacity || 0.01;
  }

  getBlur(props) {
    return props.blur || 15;
  }

  getHeatmapProps() {
    return {
{'fraction_non_alphanumeric': 0.1278622764499415, 'fraction_numerical': 0.0036770850743774027, 'mean_word_length': 4.079796264855688, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 25, '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': '3582156', 'n_tokens_mistral': 2060, 'n_tokens_neox': 1985, 'n_words': 453}