<commit_before>// This module contains the main code to render Fava's charts.
//
// The charts heavily use d3 libraries.

import { extent, max, merge, min } from "d3-array";
import { axisLeft, axisBottom } from "d3-axis";
import { hierarchy, partition, treemap } from "d3-hierarchy";
import {
  scaleBand,
  scaleLinear,
  scaleOrdinal,
  scalePoint,
  scaleSqrt,
  scaleUtc,
} from "d3-scale";
import { event, select } from "d3-selection";
import { arc, line } from "d3-shape";
import { schemeSet3, schemeCategory10 } from "d3-scale-chromatic";
import { Delaunay } from "d3-delaunay";
import "d3-transition";

import e from "./events";
import { formatCurrency, formatCurrencyShort, dateFormat } from "./format";
import setTimeFilter from "./filters";
import { $, $$ } from "./helpers";
import router from "./router";

// The color scales for the charts.
//
// The scales for treemap and sunburst charts will be initialised with all
// accounts on page init and currencies with all commodities.
const scales = {
  treemap: scaleOrdinal(schemeSet3),
  sunburst: scaleOrdinal(schemeCategory10),
  currencies: scaleOrdinal(schemeCategory10),
  scatterplot: scaleOrdinal(schemeCategory10),
};

let container;
let tooltip;

function addInternalNodesAsLeaves(node) {
  node.children.forEach(o => {
    addInternalNodesAsLeaves(o);
  });
  if (node.children && node.children.length) {
    const copy = Object.assign({}, node);
    copy.children = null;
    copy.dummy = true;
    node.children.push(copy);
    node.balance = {}; // eslint-disable-line no-param-reassign
  }
}

// Turn the elements in the selection (assuming they have a .account attribute)
// into links to the account page.
function makeAccountLink(selection) {
  selection.on("click", d => {
    window.location = window.favaAPI.accountURL.replace(
      "REPLACEME",
      d.data.account
    );
    event.stopPropagation();
  });
}

// Add a tooltip to the given selection.
function addTooltip(selection, tooltipText) {
  selection
    .on("mouseenter", d => {
      tooltip.style("opacity", 1).html(tooltipText(d));
    })
    .on("mousemove", () => {
      tooltip
        .style("left", `${event.pageX}px`)
        .style("top", `${event.pageY - 15}px`);
    })
    .on("mouseleave", () => {
      tooltip.style("opacity", 0);
    });
}

// Set the chart legend to the given domain.
function setLegend(domain, colorScale) {
  domain.sort();
  const legend = select("#chart-legend")
    .selectAll("span.legend")
    .data(domain)
    .enter()
    .append("span")
    .attr("class", "legend");

  legend
    .append("span")
    .attr("class", "color")
    .style("background", d => colorScale(d));

  legend
    .append("span")
    .attr("class", "name")
    .html(d => d);
}

// Obtain the current value of a <select> and update the list of options.
function setSelect(selector, values) {
  const selectElement = $(selector);
  const { value } = selectElement;
  selectElement.innerHTML = "";
  values.forEach(currency => {
    const opt = document.createElement("option");
    opt.value = currency;
    opt.text = currency;
    if (value === currency) {
      opt.selected = true;
    }
    selectElement.add(opt);
  });
  return values.includes(value) ? value : values[0];
}

// The base class for all charts.
//
// Provides the following methods:
//
// - setHeight(num): set the height of the chart, accounting for margins.
// - setWidth(num): set the width of the chart, accounting for margins.
// - set(property, value): set the given property of the chart class to value.
//
// Charts should implement the following methods:
//
//  - constructor(svg): Initialise the chart, prepare for drawing it to the
//    given <svg> (which is a d3-selection).
//  - draw(data): Draw the chart for the given data.
//  - update(): Update the chart (after resize, toggling, etc)
class BaseChart {
  constructor() {
    this.selections = {};
    this.margin = {
      top: 10,
      right: 10,
      bottom: 30,
      left: 40,
    };
  }

  setHeight(d) {
    this.height = d - this.margin.top - this.margin.bottom;
    return this;
  }

  setWidth(d) {
    this.width = d - this.margin.left - this.margin.right;
    return this;
  }

  set(property, value) {
    this[property] = value;
    return this;
  }
}

class TreeMapChart extends BaseChart {
  constructor(svg) {
    super();
    this.svg = svg;
    this.treemap = treemap();

    this.canvas = svg.classed("treemap", true);
  }

  draw(data) {
    this.root = data;
    this.treemap(this.root);
<commit_msg>fix #891 set paddingInner for treemap<commit_after>// This module contains the main code to render Fava's charts.
//
// The charts heavily use d3 libraries.

import { extent, max, merge, min } from "d3-array";
import { axisLeft, axisBottom } from "d3-axis";
import { hierarchy, partition, treemap } from "d3-hierarchy";
import {
  scaleBand,
  scaleLinear,
  scaleOrdinal,
  scalePoint,
  scaleSqrt,
  scaleUtc,
} from "d3-scale";
import { event, select } from "d3-selection";
import { arc, line } from "d3-shape";
import { schemeSet3, schemeCategory10 } from "d3-scale-chromatic";
import { Delaunay } from "d3-delaunay";
import "d3-transition";

import e from "./events";
import { formatCurrency, formatCurrencyShort, dateFormat } from "./format";
import setTimeFilter from "./filters";
import { $, $$ } from "./helpers";
import router from "./router";

// The color scales for the charts.
//
// The scales for treemap and sunburst charts will be initialised with all
// accounts on page init and currencies with all commodities.
const scales = {
  treemap: scaleOrdinal(schemeSet3),
  sunburst: scaleOrdinal(schemeCategory10),
  currencies: scaleOrdinal(schemeCategory10),
  scatterplot: scaleOrdinal(schemeCategory10),
};

let container;
let tooltip;

function addInternalNodesAsLeaves(node) {
  node.children.forEach(o => {
    addInternalNodesAsLeaves(o);
  });
  if (node.children && node.children.length) {
    const copy = Object.assign({}, node);
    copy.children = null;
    copy.dummy = true;
    node.children.push(copy);
    node.balance = {}; // eslint-disable-line no-param-reassign
  }
}

// Turn the elements in the selection (assuming they have a .account attribute)
// into links to the account page.
function makeAccountLink(selection) {
  selection.on("click", d => {
    window.location = window.favaAPI.accountURL.replace(
      "REPLACEME",
      d.data.account
    );
    event.stopPropagation();
  });
}

// Add a tooltip to the given selection.
function addTooltip(selection, tooltipText) {
  selection
    .on("mouseenter", d => {
      tooltip.style("opacity", 1).html(tooltipText(d));
    })
    .on("mousemove", () => {
      tooltip
        .style("left", `${event.pageX}px`)
        .style("top", `${event.pageY - 15}px`);
    })
    .on("mouseleave", () => {
      tooltip.style("opacity", 0);
    });
}

// Set the chart legend to the given domain.
function setLegend(domain, colorScale) {
  domain.sort();
  const legend = select("#chart-legend")
    .selectAll("span.legend")
    .data(domain)
    .enter()
    .append("span")
    .attr("class", "legend");

  legend
    .append("span")
    .attr("class", "color")
    .style("background", d => colorScale(d));

  legend
    .append("span")
    .attr("class", "name")
    .html(d => d);
}

// Obtain the current value of a <select> and update the list of options.
function setSelect(selector, values) {
  const selectElement = $(selector);
  const { value } = selectElement;
  selectElement.innerHTML = "";
  values.forEach(currency => {
    const opt = document.createElement("option");
    opt.value = currency;
    opt.text = currency;
    if (value === currency) {
      opt.selected = true;
    }
    selectElement.add(opt);
  });
  return values.includes(value) ? value : values[0];
}

// The base class for all charts.
//
// Provides the following methods:
//
// - setHeight(num): set the height of the chart, accounting for margins.
// - setWidth(num): set the width of the chart, accounting for margins.
// - set(property, value): set the given property of the chart class to value.
//
// Charts should implement the following methods:
//
//  - constructor(svg): Initialise the chart, prepare for drawing it to the
//    given <svg> (which is a d3-selection).
//  - draw(data): Draw the chart for the given data.
//  - update(): Update the chart (after resize, toggling, etc)
class BaseChart {
  constructor() {
    this.selections = {};
    this.margin = {
      top: 10,
      right: 10,
      bottom: 30,
      left: 40,
    };
  }

  setHeight(d) {
    this.height = d - this.margin.top - this.margin.bottom;
    return this;
  }

  setWidth(d) {
    this.width = d - this.margin.left - this.margin.right;
    return this;
  }

  set(property, value) {
    this[property] = value;
    return this;
  }
}

class TreeMapChart extends BaseChart {
  constructor(svg) {
    super();
    this.svg = svg;
    this.treemap = treemap();
    this.treemap.paddingInner(2);

    this.canvas = svg.classed("treemap", true);
  }

  draw(data) {
    this.root = data;
    this.treemap(this.root);

{'fraction_non_alphanumeric': 0.14470794905577514, 'fraction_numerical': 0.007905138339920948, 'mean_word_length': 3.1612608497030608, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 23, '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': '5264353', 'n_tokens_mistral': 2935, 'n_tokens_neox': 2872, 'n_words': 812}