<commit_before>/**
* VIZABI MOUNTAINCHART
* This graph displays income distribution in the world
*
* Original code:
* Angie https://github.com/angieskazka
*
* Contributions:
* IncoCode https://github.com/IncoCode/
* Arthur https://github.com/arthurcamara1
*
* Developed in Gapminder Foundation, 2015
*/

import * as utils from 'base/utils';
import globals from 'base/globals';
import Component from 'base/component';
import { warn as iconWarn, question as iconQuestion } from 'base/iconset';

import Exporter from 'helpers/svgexport';
import axisSmart from 'helpers/d3.axisWithLabelPicker';
import MountainChartMath from './mountainchart-math';
import Selectlist from './mountainchart-selectlist';
import Probe from './mountainchart-probe';
import DynamicBackground from 'helpers/d3.dynamicBackground';

var THICKNESS_THRESHOLD = 0.001;

//MOUNTAIN CHART COMPONENT
var MountainChartComponent = Component.extend({

    /**
     * Initialize the component
     * Executed once before any template is rendered.
     * @param {Object} config The options passed to the component
     * @param {Object} context The component's parent
     */
    init: function (config, context) {

        var _this = this;
        this.name = "mountainchart";
        this.template = "mountainchart.html";

        //define expected models for this component
        this.model_expects = [
            { name: "time", type: "time" },
            { name: "entities", type: "entities" },
            { name: "marker", type: "model" },
            { name: "language", type: "language" }
        ];

        //attach event listeners to the model items
        this.model_binds = {
            "change:time:value": function (evt) {
                //console.log("MONT: " + evt);
                _this.updateTime();
                _this.redrawDataPoints();
                _this._selectlist.redraw();
                _this._probe.redraw();
                _this.updateDoubtOpacity();
            },
            "change:time:xScaleFactor": function () {
                _this.ready();
            },
            "change:time:xScaleShift": function () {
                _this.ready();
            },
            "change:time:tailCutX": function () {
                _this.ready();
            },
            "change:time:tailFade": function () {
                _this.ready();
            },
            "change:time:probeX": function () {
                _this.ready();
            },
            "change:time:xPoints": function () {
                _this.ready();
            },
            "change:time:xLogStops": function () {
                _this.updateSize();
            },
            "change:time:yMaxMethod": function () {
                _this._adjustMaxY({ force: true });
                _this.redrawDataPoints();
            },
            "change:time:record": function (evt) {
                if (_this.model.time.record) {
                    _this._export.open(this.element, this.name);
                } else {
                    _this._export.reset();
                }
            },
            "change:entities:highlight": function (evt) {
                if (!_this._readyOnce) return;
                _this.highlightEntities();
                _this.updateOpacity();
            },
            "change:entities:select": function (evt) {
                if (!_this._readyOnce) return;
                _this.selectEntities();
                _this._selectlist.redraw();
                _this.updateOpacity();
                _this.updateDoubtOpacity();
                _this.redrawDataPoints();
            },
            "change:entities:opacitySelectDim": function (evt) {
                _this.updateOpacity();
            },
            "change:entities:opacityRegular": function (evt) {
                _this.updateOpacity();
            },
            "change:marker": function (evt) {
                if (!_this._readyOnce) return;
                if (evt.indexOf("fakeMin") > -1 || evt.indexOf("fakeMax") > -1) {
                    _this.zoomToMaxMin();
                    _this.redrawDataPoints();
                    _this._probe.redraw();
                }
            },
            "change:marker:group": function (evt) {
                if (!_this._readyOnce) return;
                if (evt.indexOf("group:merge") > -1) return;
                _this.ready();
            },
            "change:marker:group:merge": function (evt) {
                if (!_this._readyOnce) return;
                _this.updateTime();
                _this.redrawDataPoints();
            },
            "change:marker:stack": function (evt) {
                if (!_this._readyOnce) return;
                _this.ready();
            },
            "change:marker:color:palette": function (evt) {
                if (!_this._readyOnce) return;
                _this.redrawDataPointsOnlyColors();
                _this._selectlist.redraw();
            },
        };

        this._super(config, context);

        this._math = new MountainChartMath(this);
        this._export = new Exporter(this);
        this._export
            .prefix("vzb-mc-")
            .deleteClasses(["vzb-mc-mountains-mergestacked", "vzb-mc-mountains-mergegrouped", "vzb-mc-mountains", "vzb-mc-year", "vzb-mc-mountains-labels", "vzb-mc-axis-labels"]);
        this._probe = new Probe(this);
        this._selectlist = new Selectlist(this);

        // define path generator
        this.area = d3.svg.area()
            .interpolate("basis")
            .x(function (d) {
                return _this.xScale(_this._math.rescale(d.x));
            })
            .y0(function (d) {
                return _this.yScale(d.y0);
            })
            .y1(function (d) {
                return _this.yScale(d.y0 + d.y);
            });

        //define d3 stack layout
        this.stack = d3.layout.stack()
            .order("reverse")
            .values(function (d) {
                return _this.cached[d.KEY()];
            })
            .out(function out(d, y0, y) {
                d.y0 = y0;
            });

        // init internal variables
        this.xScale = null;
        this.yScale = null;
        this.cScale = null;

        this.xAxis = axisSmart();


        this.rangeRatio = 1;
        this.rangeShift = 0;
        this.cached = {};
        this.mesh = [];
        this.yMax = 0;
    },

    domReady: function () {
        var _this = this;

        // reference elements
        this.element = d3.select(this.element);
        this.graph = this.element.select(".vzb-mc-graph");
        this.xAxisEl = this.graph.select(".vzb-mc-axis-x");
        this.xTitleEl = this.graph.select(".vzb-mc-axis-x-title");
        this.yTitleEl = this.graph.select(".vzb-mc-axis-y-title");
        this.infoEl = this.graph.select(".vzb-mc-axis-info");
        this.dataWarningEl = this.graph.select(".vzb-data-warning");

        this.yearEl = this.graph.select(".vzb-mc-year");
        this.year = new DynamicBackground(this.yearEl);

        this.mountainMergeStackedContainer = this.graph.select(".vzb-mc-mountains-mergestacked");
        this.mountainMergeGroupedContainer = this.graph.select(".vzb-mc-mountains-mergegrouped");
        this.mountainAtomicContainer = this.graph.select(".vzb-mc-mountains");
        this.mountainLabelContainer = this.graph.select(".vzb-mc-mountains-labels");
        this.tooltip = this.element.select(".vzb-mc-tooltip");
        this.eventAreaEl = this.element.select(".vzb-mc-eventarea");
        this.probeEl = this.element.select(".vzb-mc-probe");
        this.probeLineEl = this.probeEl.select("line");
        this.probeTextEl = this.probeEl.selectAll("text");

        this.element
            .onTap(function (d, i) {
                _this._interact()._mouseout(d, i);
            });
    },

    afterPreload: function () {
        var _this = this;

        var yearNow = _this.model.time.value.getFullYear();
        var yearEnd = _this.model.time.end.getFullYear();

        this._math.xScaleFactor = this.model.time.xScaleFactor;
        this._math.xScaleShift = this.model.time.xScaleShift;

        if (!this.precomputedShapes || !this.precomputedShapes[yearNow] || !this.precomputedShapes[yearEnd]) return;

        var yMax = this.precomputedShapes[this.model.time.yMaxMethod == "immediate" ? yearNow : yearEnd].yMax;
        var shape = this.precomputedShapes[yearNow].shape;

        if (!yMax || !shape || shape.length === 0) return;

        this.xScale = d3.scale.log().domain([this.model.marker.axis_x.min, this.model.marker.axis_x.max]);
        this.yScale = d3.scale.linear().domain([0, +yMax]);

        _this.updateSize(shape.length);
        _this.zoomToMaxMin();

        shape = shape.map(function (m, i) {return {x: _this.mesh[i], y0: 0, y: +m};})

        this.mountainAtomicContainer.selectAll(".vzb-mc-prerender")
            .data([0])
            .enter().append("path")
            .attr("class", "vzb-mc-prerender")
            .style("fill", "pink")
            .style("opacity", 0)
            .attr("d", _this.area(shape))
            .transition().duration(1000).ease("linear")
            .style("opacity", 1);
    },

    readyOnce: function () {

        this.eventAreaEl
            .on("mousemove", function () {
                if (_this.model.time.dragging) return;
                _this._probe.redraw({
                    level: _this.xScale.invert(d3.mouse(this)[0]),
                    full: true
                });
            })
            .on("mouseout", function () {
                if (_this.model.time.dragging) return;
                _this._probe.redraw();
            });

        var _this = this;
        this.on("resize", function () {
            //console.log("acting on resize");
            _this.updateSize();
            _this.updateTime(); // respawn is needed
            _this.redrawDataPoints();
            _this._selectlist.redraw();
            _this._probe.redraw();
        });

        this.KEY = this.model.entities.getDimension();
        this.TIMEDIM = this.model.time.getDimension();

        this.mountainAtomicContainer.select(".vzb-mc-prerender").remove();

        this.wScale = d3.scale.linear()
            .domain(this.parent.datawarning_content.doubtDomain)
            .range(this.parent.datawarning_content.doubtRange);
    },

    ready: function () {
        //console.log("ready")

        this._math.xScaleFactor = this.model.time.xScaleFactor;
        this._math.xScaleShift = this.model.time.xScaleShift;

        this.updateUIStrings();
        this.updateIndicators();
        this.updateEntities();
        this.updateSize();
        this.zoomToMaxMin();
        this._spawnMasks();
        this.updateTime();
        this._adjustMaxY({force: true});
        this.redrawDataPoints();
        this.redrawDataPointsOnlyColors();
        this.highlightEntities();
        this.selectEntities();
        this._selectlist.redraw();
        this.updateOpacity();
        this.updateDoubtOpacity();
        this._probe.redraw();
    },

    updateSize: function (meshLength) {

        var margin, infoElHeight;
        var padding = 2;

        var profiles = {
          small: {
            margin: { top: 10, right: 10, left: 10, bottom: 25 },
            infoElHeight: 16
          },
          medium: {
            margin: { top: 20, right: 20, left: 20, bottom: 30 },
            infoElHeight: 20
          },
          large: {
            margin: { top: 30, right: 30, left: 30, bottom: 35 },
            infoElHeight: 22
          }
        };

        var presentationProfileChanges = {
          small: {
            margin: { top: 10, right: 10, left: 10, bottom: 30 },
            infoElHeight: 16
          },
          medium: {
            margin: { top: 20, right: 20, left: 20, bottom: 50 },
            infoElHeight: 20
          },
          large: {
            margin: { top: 30, right: 30, left: 30, bottom: 50 },
            infoElHeight: 22
          }
        };

        this.activeProfile = this.getActiveProfile(profiles, presentationProfileChanges);
        margin = this.activeProfile.margin;
        infoElHeight = this.activeProfile.infoElHeight;

        //mesure width and height
        this.height = parseInt(this.element.style("height"), 10) - margin.top - margin.bottom;
        this.width = parseInt(this.element.style("width"), 10) - margin.left - margin.right;

        //graph group is shifted according to margins (while svg element is at 100 by 100%)
        this.graph.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var yearLabelOptions = {
            topOffset: this.getLayoutProfile()==="large"? margin.top * 2 : 0,
            xAlign: this.getLayoutProfile()==="large"? 'right' : 'center',
            yAlign: this.getLayoutProfile()==="large"? 'top' : 'center',
        };

        var yearLabelFontSize = this.getLayoutProfile()==="large"? this.width / 6 : Math.max(this.height / 4, this.width / 4);

        //year is centered and resized
        this.year
            .setConditions(yearLabelOptions)
            .resize(this.width, this.height, yearLabelFontSize);

        //update scales to the new range
        this.yScale.range([this.height, 0]);
        this.xScale.range([this.rangeShift, this.width * this.rangeRatio + this.rangeShift]);


        //need to know scale type of X to move on
        var scaleType = this._readyOnce ? this.model.marker.axis_x.scaleType : "log";

        //axis is updated
        this.xAxis.scale(this.xScale)
            .orient("bottom")
            .tickSize(6, 0)
            .tickSizeMinor(3, 0)
            .labelerOptions({
                scaleType: scaleType,
                toolMargin: margin,
                method: this.xAxis.METHOD_REPEATING,
                stops: this._readyOnce ? this.model.time.xLogStops : [1]
            });


        this.xAxisEl
            .attr("transform", "translate(0," + this.height + ")")
            .call(this.xAxis);

        this.xTitleEl.select("text")
            .attr("transform", "translate(" + this.width + "," + this.height + ")")
            .attr("dy", "-0.36em");

        this.yTitleEl.select("text")
            .attr("transform", "translate(0," + margin.top + ")")


        var warnBB = this.dataWarningEl.select("text").node().getBBox();
        this.dataWarningEl.select("svg")
            .attr("width", warnBB.height)
            .attr("height", warnBB.height)
            .attr("x", warnBB.height * .1)
            .attr("y", -warnBB.height * 1.0 + 1)

        this.dataWarningEl
            .attr("transform", "translate(" + (0) + "," + (margin.top + warnBB.height * 1.5) + ")")<commit_msg>reduce vertical padding between x axis & timeslider, hack axis labeler so that labels don't disappear<commit_after>/**
* VIZABI MOUNTAINCHART
* This graph displays income distribution in the world
*
* Original code:
* Angie https://github.com/angieskazka
*
* Contributions:
* IncoCode https://github.com/IncoCode/
* Arthur https://github.com/arthurcamara1
*
* Developed in Gapminder Foundation, 2015
*/

import * as utils from 'base/utils';
import globals from 'base/globals';
import Component from 'base/component';
import { warn as iconWarn, question as iconQuestion } from 'base/iconset';

import Exporter from 'helpers/svgexport';
import axisSmart from 'helpers/d3.axisWithLabelPicker';
import MountainChartMath from './mountainchart-math';
import Selectlist from './mountainchart-selectlist';
import Probe from './mountainchart-probe';
import DynamicBackground from 'helpers/d3.dynamicBackground';

var THICKNESS_THRESHOLD = 0.001;

//MOUNTAIN CHART COMPONENT
var MountainChartComponent = Component.extend({

    /**
     * Initialize the component
     * Executed once before any template is rendered.
     * @param {Object} config The options passed to the component
     * @param {Object} context The component's parent
     */
    init: function (config, context) {

        var _this = this;
        this.name = "mountainchart";
        this.template = "mountainchart.html";

        //define expected models for this component
        this.model_expects = [
            { name: "time", type: "time" },
            { name: "entities", type: "entities" },
            { name: "marker", type: "model" },
            { name: "language", type: "language" }
        ];

        //attach event listeners to the model items
        this.model_binds = {
            "change:time:value": function (evt) {
                //console.log("MONT: " + evt);
                _this.updateTime();
                _this.redrawDataPoints();
                _this._selectlist.redraw();
                _this._probe.redraw();
                _this.updateDoubtOpacity();
            },
            "change:time:xScaleFactor": function () {
                _this.ready();
            },
            "change:time:xScaleShift": function () {
                _this.ready();
            },
            "change:time:tailCutX": function () {
                _this.ready();
            },
            "change:time:tailFade": function () {
                _this.ready();
            },
            "change:time:probeX": function () {
                _this.ready();
            },
            "change:time:xPoints": function () {
                _this.ready();
            },
            "change:time:xLogStops": function () {
                _this.updateSize();
            },
            "change:time:yMaxMethod": function () {
                _this._adjustMaxY({ force: true });
                _this.redrawDataPoints();
            },
            "change:time:record": function (evt) {
                if (_this.model.time.record) {
                    _this._export.open(this.element, this.name);
                } else {
                    _this._export.reset();
                }
            },
            "change:entities:highlight": function (evt) {
                if (!_this._readyOnce) return;
                _this.highlightEntities();
                _this.updateOpacity();
            },
            "change:entities:select": function (evt) {
                if (!_this._readyOnce) return;
                _this.selectEntities();
                _this._selectlist.redraw();
                _this.updateOpacity();
                _this.updateDoubtOpacity();
                _this.redrawDataPoints();
            },
            "change:entities:opacitySelectDim": function (evt) {
                _this.updateOpacity();
            },
            "change:entities:opacityRegular": function (evt) {
                _this.updateOpacity();
            },
            "change:marker": function (evt) {
                if (!_this._readyOnce) return;
                if (evt.indexOf("fakeMin") > -1 || evt.indexOf("fakeMax") > -1) {
                    _this.zoomToMaxMin();
                    _this.redrawDataPoints();
                    _this._probe.redraw();
                }
            },
            "change:marker:group": function (evt) {
                if (!_this._readyOnce) return;
                if (evt.indexOf("group:merge") > -1) return;
                _this.ready();
            },
            "change:marker:group:merge": function (evt) {
                if (!_this._readyOnce) return;
                _this.updateTime();
                _this.redrawDataPoints();
            },
            "change:marker:stack": function (evt) {
                if (!_this._readyOnce) return;
                _this.ready();
            },
            "change:marker:color:palette": function (evt) {
                if (!_this._readyOnce) return;
                _this.redrawDataPointsOnlyColors();
                _this._selectlist.redraw();
            },
        };

        this._super(config, context);

        this._math = new MountainChartMath(this);
        this._export = new Exporter(this);
        this._export
            .prefix("vzb-mc-")
            .deleteClasses(["vzb-mc-mountains-mergestacked", "vzb-mc-mountains-mergegrouped", "vzb-mc-mountains", "vzb-mc-year", "vzb-mc-mountains-labels", "vzb-mc-axis-labels"]);
        this._probe = new Probe(this);
        this._selectlist = new Selectlist(this);

        // define path generator
        this.area = d3.svg.area()
            .interpolate("basis")
            .x(function (d) {
                return _this.xScale(_this._math.rescale(d.x));
            })
            .y0(function (d) {
                return _this.yScale(d.y0);
            })
            .y1(function (d) {
                return _this.yScale(d.y0 + d.y);
            });

        //define d3 stack layout
        this.stack = d3.layout.stack()
            .order("reverse")
            .values(function (d) {
                return _this.cached[d.KEY()];
            })
            .out(function out(d, y0, y) {
                d.y0 = y0;
            });

        // init internal variables
        this.xScale = null;
        this.yScale = null;
        this.cScale = null;

        this.xAxis = axisSmart();


        this.rangeRatio = 1;
        this.rangeShift = 0;
        this.cached = {};
        this.mesh = [];
        this.yMax = 0;
    },

    domReady: function () {
        var _this = this;

        // reference elements
        this.element = d3.select(this.element);
        this.graph = this.element.select(".vzb-mc-graph");
        this.xAxisEl = this.graph.select(".vzb-mc-axis-x");
        this.xTitleEl = this.graph.select(".vzb-mc-axis-x-title");
        this.yTitleEl = this.graph.select(".vzb-mc-axis-y-title");
        this.infoEl = this.graph.select(".vzb-mc-axis-info");
        this.dataWarningEl = this.graph.select(".vzb-data-warning");

        this.yearEl = this.graph.select(".vzb-mc-year");
        this.year = new DynamicBackground(this.yearEl);

        this.mountainMergeStackedContainer = this.graph.select(".vzb-mc-mountains-mergestacked");
        this.mountainMergeGroupedContainer = this.graph.select(".vzb-mc-mountains-mergegrouped");
        this.mountainAtomicContainer = this.graph.select(".vzb-mc-mountains");
        this.mountainLabelContainer = this.graph.select(".vzb-mc-mountains-labels");
        this.tooltip = this.element.select(".vzb-mc-tooltip");
        this.eventAreaEl = this.element.select(".vzb-mc-eventarea");
        this.probeEl = this.element.select(".vzb-mc-probe");
        this.probeLineEl = this.probeEl.select("line");
        this.probeTextEl = this.probeEl.selectAll("text");

        this.element
            .onTap(function (d, i) {
                _this._interact()._mouseout(d, i);
            });
    },

    afterPreload: function () {
        var _this = this;

        var yearNow = _this.model.time.value.getFullYear();
        var yearEnd = _this.model.time.end.getFullYear();

        this._math.xScaleFactor = this.model.time.xScaleFactor;
        this._math.xScaleShift = this.model.time.xScaleShift;

        if (!this.precomputedShapes || !this.precomputedShapes[yearNow] || !this.precomputedShapes[yearEnd]) return;

        var yMax = this.precomputedShapes[this.model.time.yMaxMethod == "immediate" ? yearNow : yearEnd].yMax;
        var shape = this.precomputedShapes[yearNow].shape;

        if (!yMax || !shape || shape.length === 0) return;

        this.xScale = d3.scale.log().domain([this.model.marker.axis_x.min, this.model.marker.axis_x.max]);
        this.yScale = d3.scale.linear().domain([0, +yMax]);

        _this.updateSize(shape.length);
        _this.zoomToMaxMin();

        shape = shape.map(function (m, i) {return {x: _this.mesh[i], y0: 0, y: +m};})

        this.mountainAtomicContainer.selectAll(".vzb-mc-prerender")
            .data([0])
            .enter().append("path")
            .attr("class", "vzb-mc-prerender")
            .style("fill", "pink")
            .style("opacity", 0)
            .attr("d", _this.area(shape))
            .transition().duration(1000).ease("linear")
            .style("opacity", 1);
    },

    readyOnce: function () {

        this.eventAreaEl
            .on("mousemove", function () {
                if (_this.model.time.dragging) return;
                _this._probe.redraw({
                    level: _this.xScale.invert(d3.mouse(this)[0]),
                    full: true
                });
            })
            .on("mouseout", function () {
                if (_this.model.time.dragging) return;
                _this._probe.redraw();
            });

        var _this = this;
        this.on("resize", function () {
            //console.log("acting on resize");
            _this.updateSize();
            _this.updateTime(); // respawn is needed
            _this.redrawDataPoints();
            _this._selectlist.redraw();
            _this._probe.redraw();
        });

        this.KEY = this.model.entities.getDimension();
        this.TIMEDIM = this.model.time.getDimension();

        this.mountainAtomicContainer.select(".vzb-mc-prerender").remove();

        this.wScale = d3.scale.linear()
            .domain(this.parent.datawarning_content.doubtDomain)
            .range(this.parent.datawarning_content.doubtRange);
    },

    ready: function () {
        //console.log("ready")

        this._math.xScaleFactor = this.model.time.xScaleFactor;
        this._math.xScaleShift = this.model.time.xScaleShift;

        this.updateUIStrings();
        this.updateIndicators();
        this.updateEntities();
        this.updateSize();
        this.zoomToMaxMin();
        this._spawnMasks();
        this.updateTime();
        this._adjustMaxY({force: true});
        this.redrawDataPoints();
        this.redrawDataPointsOnlyColors();
        this.highlightEntities();
        this.selectEntities();
        this._selectlist.redraw();
        this.updateOpacity();
        this.updateDoubtOpacity();
        this._probe.redraw();
    },

    updateSize: function (meshLength) {

        var margin, infoElHeight;
        var padding = 2;

        var profiles = {
          small: {
            margin: { top: 10, right: 10, left: 10, bottom: 18 },
            infoElHeight: 16
          },
          medium: {
            margin: { top: 20, right: 20, left: 20, bottom: 30 },
            infoElHeight: 20
          },
          large: {
            margin: { top: 30, right: 30, left: 30, bottom: 35 },
            infoElHeight: 22
          }
        };

        var presentationProfileChanges = {
          small: {
            margin: { top: 10, right: 10, left: 10, bottom: 30 },
            infoElHeight: 16
          },
          medium: {
            margin: { top: 20, right: 20, left: 20, bottom: 50 },
            infoElHeight: 20
          },
          large: {
            margin: { top: 30, right: 30, left: 30, bottom: 50 },
            infoElHeight: 22
          }
        };

        this.activeProfile = this.getActiveProfile(profiles, presentationProfileChanges);
        margin = this.activeProfile.margin;
        infoElHeight = this.activeProfile.infoElHeight;

        //mesure width and height
        this.height = parseInt(this.element.style("height"), 10) - margin.top - margin.bottom;
        this.width = parseInt(this.element.style("width"), 10) - margin.left - margin.right;

        //graph group is shifted according to margins (while svg element is at 100 by 100%)
        this.graph.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var yearLabelOptions = {
            topOffset: this.getLayoutProfile()==="large"? margin.top * 2 : 0,
            xAlign: this.getLayoutProfile()==="large"? 'right' : 'center',
            yAlign: this.getLayoutProfile()==="large"? 'top' : 'center',
        };

        var yearLabelFontSize = this.getLayoutProfile()==="large"? this.width / 6 : Math.max(this.height / 4, this.width / 4);

        //year is centered and resized
        this.year
            .setConditions(yearLabelOptions)
            .resize(this.width, this.height, yearLabelFontSize);

        //update scales to the new range
        this.yScale.range([this.height, 0]);
        this.xScale.range([this.rangeShift, this.width * this.rangeRatio + this.rangeShift]);


        //need to know scale type of X to move on
        var scaleType = this._readyOnce ? this.model.marker.axis_x.scaleType : "log";

        //axis is updated
        this.xAxis.scale(this.xScale)
            .orient("bottom")
            .tickSize(6, 0)
            .tickSizeMinor(3, 0)
            .labelerOptions({
                scaleType: scaleType,
                toolMargin: margin,
                pivotingLimit: margin.bottom * 1.5,
                method: this.xAxis.METHOD_REPEATING,
                stops: this._readyOnce ? this.model.time.xLogStops : [1]
            });


        this.xAxisEl
            .attr("transform", "translate(0," + this.height + ")")
            .call(this.xAxis);

        this.xTitleEl.select("text")
            .attr("transform", "translate(" + this.width + "," + this.height + ")")
            .attr("dy", "-0.36em");

        this.yTitleEl.select("text")
            .attr("transform", "translate(0," + margin.top + ")")


        var warnBB = this.dataWarningEl.select("text").node().getBBox();
        this.dataWarningEl.select("svg")
            .attr("width", warnBB.height)
            .attr("height", warnBB.height)
            .attr("x", warnBB.height * .1)
            .attr("y", -warnBB.height * 1.0 + 1)

        this.dataWarningEl
            .attr("transform", "translate(" + (0) + "," + (margin.top + warnBB.height * 1.5) + ")")
{'fraction_non_alphanumeric': 0.13905045313134046, 'fraction_numerical': 0.00940078452590288, 'mean_word_length': 1.8010039780261413, 'pattern_counts': {'":': 38, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2396947', 'n_tokens_mistral': 8839, 'n_tokens_neox': 8423, 'n_words': 1567}