<commit_before>// JS
const d3 = require('d3');
const Datamap = require('datamaps');

// CSS
require('./world_map.css');

function worldMapChart(slice, payload) {
  const container = slice.container;
  const div = d3.select(slice.selector);

  container.css('height', slice.height());
  div.selectAll('*').remove();
  const fd = slice.formData;
  // Ignore XXX's to get better normalization
  let data = payload.data.filter(d => (d.country && d.country !== 'XXX'));

  const ext = d3.extent(data, function (d) {
    return d.m1;
  });
  const extRadius = d3.extent(data, function (d) {
    return d.m2;
  });
  const radiusScale = d3.scale.linear()
    .domain([extRadius[0], extRadius[1]])
    .range([1, fd.max_bubble_size]);

  const colorScale = d3.scale.linear()
    .domain([ext[0], ext[1]])
    .range(['#FFF', 'black']);

  data = data.map(d => Object.assign({}, d, {
    radius: radiusScale(d.m2),
    fillColor: colorScale(d.m1),
  }));

  const mapData = {};
  data.forEach((d) => {
    mapData[d.country] = d;
  });

  const formatter = d3.format('.3s');

  container.show();

  const map = new Datamap({
    element: slice.container.get(0),
    data,
    fills: {
      defaultFill: '#ddd',
    },
    geographyConfig: {
      popupOnHover: true,
      highlightOnHover: true,
      borderWidth: 1,
      borderColor: '#fff',
      highlightBorderColor: '#fff',
      highlightFillColor: '#005a63',
      highlightBorderWidth: 1,
      popupTemplate: (geo, d) => (
        `<div class="hoverinfo"><strong>${d.name}</strong><br>${formatter(d.m1)}</div>`
      ),
    },
    bubblesConfig: {
      borderWidth: 1,
      borderOpacity: 1,
      borderColor: '#005a63',
      popupOnHover: true,
      radius: null,
      popupTemplate: (geo, d) => (
        `<div class="hoverinfo"><strong>${d.name}</strong><br>${formatter(d.m2)}</div>`
      ),
      fillOpacity: 0.5,
      animate: true,
      highlightOnHover: true,
      highlightFillColor: '#005a63',
      highlightBorderColor: 'black',
      highlightBorderWidth: 2,
      highlightBorderOpacity: 1,
      highlightFillOpacity: 0.85,
      exitDelay: 100,
      key: JSON.stringify,
    },
  });

  map.updateChoropleth(mapData);

  if (fd.show_bubbles) {
    map.bubbles(data);
    div.selectAll('circle.datamaps-bubble').style('fill', '#005a63');
  }
}

module.exports = worldMapChart;<commit_msg>[SIP-5] Refactor World Map (#5719)<commit_after>import d3 from 'd3';
import PropTypes from 'prop-types';
import Datamap from 'datamaps';
import './world_map.css';

const propTypes = {
  data: PropTypes.arrayOf(PropTypes.shape({
    country: PropTypes.string,
    latitude: PropTypes.number,
    longitude: PropTypes.number,
    name: PropTypes.string,
    m1: PropTypes.number,
    m2: PropTypes.number,
  })),
  height: PropTypes.number,
  maxBubbleSize: PropTypes.number,
  showBubbles: PropTypes.bool,
};

const formatter = d3.format('.3s');

function WorldMap(element, props) {
  PropTypes.checkPropTypes(propTypes, props, 'prop', 'WorldMap');

  const {
    data,
    height,
    maxBubbleSize,
    showBubbles,
  } = props;

  const div = d3.select(element);

  const container = element;
  container.style.height = `${height}px`;
  div.selectAll('*').remove();

  // Ignore XXX's to get better normalization
  const filteredData = data.filter(d => (d.country && d.country !== 'XXX'));

  const ext = d3.extent(filteredData, d => d.m1);
  const extRadius = d3.extent(filteredData, d => d.m2);
  const radiusScale = d3.scale.linear()
    .domain([extRadius[0], extRadius[1]])
    .range([1, maxBubbleSize]);

  const colorScale = d3.scale.linear()
    .domain([ext[0], ext[1]])
    .range(['#FFF', 'black']);

  const processedData = filteredData.map(d => ({
    ...d,
    radius: radiusScale(d.m2),
    fillColor: colorScale(d.m1),
  }));

  const mapData = {};
  processedData.forEach((d) => {
    mapData[d.country] = d;
  });

  const map = new Datamap({
    element,
    data: processedData,
    fills: {
      defaultFill: '#ddd',
    },
    geographyConfig: {
      popupOnHover: true,
      highlightOnHover: true,
      borderWidth: 1,
      borderColor: '#fff',
      highlightBorderColor: '#fff',
      highlightFillColor: '#005a63',
      highlightBorderWidth: 1,
      popupTemplate: (geo, d) => (
        `<div class="hoverinfo"><strong>${d.name}</strong><br>${formatter(d.m1)}</div>`
      ),
    },
    bubblesConfig: {
      borderWidth: 1,
      borderOpacity: 1,
      borderColor: '#005a63',
      popupOnHover: true,
      radius: null,
      popupTemplate: (geo, d) => (
        `<div class="hoverinfo"><strong>${d.name}</strong><br>${formatter(d.m2)}</div>`
      ),
      fillOpacity: 0.5,
      animate: true,
      highlightOnHover: true,
      highlightFillColor: '#005a63',
      highlightBorderColor: 'black',
      highlightBorderWidth: 2,
      highlightBorderOpacity: 1,
      highlightFillOpacity: 0.85,
      exitDelay: 100,
      key: JSON.stringify,
    },
  });

  map.updateChoropleth(mapData);

  if (showBubbles) {
    map.bubbles(processedData);
    div.selectAll('circle.datamaps-bubble').style('fill', '#005a63');
  }
}

WorldMap.propTypes = propTypes;

function adaptor(slice, payload) {
  const { selector, formData } = slice;
  const {
    max_bubble_size: maxBubbleSize,
    show_bubbles: showBubbles,
  } = formData;
  const element = document.querySelector(selector);

  return WorldMap(element, {
    data: payload.data,
    height: slice.height(),
    maxBubbleSize: parseInt(maxBubbleSize, 10),
    showBubbles,
  });
}

export default adaptor;
{'fraction_non_alphanumeric': 0.16340456096247083, 'fraction_numerical': 0.021188723289639073, 'mean_word_length': 3.1754122938530736, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 35, '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': '5758252', 'n_tokens_mistral': 1993, 'n_tokens_neox': 1906, 'n_words': 372}