<commit_before>import lazyLoadMathJax from '../utils/LazyLoader/mathjax';
import React, {Component} from 'react';
// /build/withPolyfill for IE11 support - https://github.com/maslianok/react-resize-detector/issues/144
import ResizeDetector from 'react-resize-detector/build/withPolyfill';
import {
    equals,
    filter,
    has,
    includes,
    isNil,
    mergeDeepRight,
    omit,
    type,
} from 'ramda';
import PropTypes from 'prop-types';
import {graphPropTypes, graphDefaultProps} from '../components/Graph.react';
/* global Plotly:true */

/**
 * `autosize: true` causes Plotly.js to conform to the parent element size.
 * This is necessary for `dcc.Graph` call to `Plotly.Plots.resize(target)` to do something.
 *
 * Users can override this value for specific use-cases by explicitly passing `autoresize: true`
 * if `responsive` is not set to True.
 */
const RESPONSIVE_LAYOUT = {
    autosize: true,
    height: undefined,
    width: undefined,
};

const AUTO_LAYOUT = {};

const UNRESPONSIVE_LAYOUT = {
    autosize: false,
};

/**
 * `responsive: true` causes Plotly.js to resize the graph on `window.resize`.
 * This is necessary for `dcc.Graph` call to `Plotly.Plots.resize(target)` to do something.
 *
 * Users can override this value for specific use-cases by explicitly passing `responsive: false`
 * if `responsive` is not set to True.
 */
const RESPONSIVE_CONFIG = {
    responsive: true,
};

const AUTO_CONFIG = {};

const UNRESPONSIVE_CONFIG = {
    responsive: false,
};

const filterEventData = (gd, eventData, event) => {
    let filteredEventData;
    if (includes(event, ['click', 'hover', 'selected'])) {
        const points = [];

        if (isNil(eventData)) {
            return null;
        }

        /*
         * remove `data`, `layout`, `xaxis`, etc
         * objects from the event data since they're so big
         * and cause JSON stringify ciricular structure errors.
         *
         * also, pull down the `customdata` point from the data array
         * into the event object
         */
        const data = gd.data;

        for (let i = 0; i < eventData.points.length; i++) {
            const fullPoint = eventData.points[i];
            const pointData = filter(function (o) {
                return !includes(type(o), ['Object', 'Array']);
            }, fullPoint);

            // permit a bounding box to pass through, if present
            if (has('bbox', fullPoint)) {
                pointData.bbox = fullPoint.bbox;
            }

            if (
                has('curveNumber', fullPoint) &&
                has('pointNumber', fullPoint) &&
                has('customdata', data[pointData.curveNumber])
            ) {
                pointData.customdata =
                    data[pointData.curveNumber].customdata[
                        fullPoint.pointNumber
                    ];
            }

            // specific to histogram. see https://github.com/plotly/plotly.js/pull/2113/
            if (has('pointNumbers', fullPoint)) {
                pointData.pointNumbers = fullPoint.pointNumbers;
            }

            points[i] = pointData;
        }
        filteredEventData = {points};
    } else if (event === 'relayout' || event === 'restyle') {
        /*
         * relayout shouldn't include any big objects
         * it will usually just contain the ranges of the axes like
         * "xaxis.range[0]": 0.7715822247381828,
         * "xaxis.range[1]": 3.0095292008680063`
         */
        filteredEventData = eventData;
    }
    if (has('range', eventData)) {
        filteredEventData.range = eventData.range;
    }
    if (has('lassoPoints', eventData)) {
        filteredEventData.lassoPoints = eventData.lassoPoints;
    }
    return filteredEventData;
};

/**
 * Graph can be used to render any plotly.js-powered data visualization.
 *
 * You can define callbacks based on user interaction with Graphs such as
 * hovering, clicking or selecting
 */
class PlotlyGraph extends Component {
    constructor(props) {
        super(props);
        this.gd = React.createRef();
        this._hasPlotted = false;
        this._prevGd = null;

        this.bindEvents = this.bindEvents.bind(this);
        this.getConfig = this.getConfig.bind(this);
        this.getConfigOverride = this.getConfigOverride.bind(this);
        this.getLayout = this.getLayout.bind(this);
        this.getLayoutOverride = this.getLayoutOverride.bind(this);
        this.graphResize = this.graphResize.bind(this);
        this.isResponsive = this.isResponsive.bind(this);

        this.state = {override: {}, originals: {}};
    }

    plot(props) {
        let {figure, config} = props;
        const {animate, animation_options, responsive, mathjax} = props;

        const gd = this.gd.current;
        figure = props._dashprivate_transformFigure(figure, gd);
        config = props._dashprivate_transformConfig(config, gd);

        const configClone = this.getConfig(config, responsive);
        // add typesetMath | not exposed to the dash API
        configClone.typesetMath = mathjax;

        const figureClone = {
            data: figure.data,
            layout: this.getLayout(figure.layout, responsive),
            frames: figure.frames,
            config: configClone,
        };

        if (
            animate &&
            this._hasPlotted &&
            figure.data.length === gd.data.length
        ) {
            // in case we've have figure frames,
            // we need to recreate frames before animation
            if (figure.frames) {
                return Plotly.deleteFrames(gd)
                    .then(() => Plotly.addFrames(gd, figure.frames))
                    .then(() =>
                        Plotly.animate(gd, figureClone, animation_options)
                    );
            }
            return Plotly.animate(gd, figureClone, animation_options);
        }

        gd.classList.add('dash-graph--pending');

        return lazyLoadMathJax(mathjax)
            .then(() => Plotly.react(gd, figureClone))
            .then(() => {
                const gd = this.gd.current;

                // double-check gd hasn't been unmounted
                if (!gd) {
                    return;
                }

                gd.classList.remove('dash-graph--pending');

                // in case we've made a new DOM element, transfer events
                if (this._hasPlotted && gd !== this._prevGd) {
                    if (this._prevGd && this._prevGd.removeAllListeners) {
                        this._prevGd.removeAllListeners();
                        Plotly.purge(this._prevGd);
                    }
                    this._hasPlotted = false;
                }

                if (!this._hasPlotted) {
                    this.bindEvents();
                    this.graphResize(true);
                    this._hasPlotted = true;
                    this._prevGd = gd;
                }
            });
    }<commit_msg>pass current gd to Plotly.react<commit_after>import lazyLoadMathJax from '../utils/LazyLoader/mathjax';
import React, {Component} from 'react';
// /build/withPolyfill for IE11 support - https://github.com/maslianok/react-resize-detector/issues/144
import ResizeDetector from 'react-resize-detector/build/withPolyfill';
import {
    equals,
    filter,
    has,
    includes,
    isNil,
    mergeDeepRight,
    omit,
    type,
} from 'ramda';
import PropTypes from 'prop-types';
import {graphPropTypes, graphDefaultProps} from '../components/Graph.react';
/* global Plotly:true */

/**
 * `autosize: true` causes Plotly.js to conform to the parent element size.
 * This is necessary for `dcc.Graph` call to `Plotly.Plots.resize(target)` to do something.
 *
 * Users can override this value for specific use-cases by explicitly passing `autoresize: true`
 * if `responsive` is not set to True.
 */
const RESPONSIVE_LAYOUT = {
    autosize: true,
    height: undefined,
    width: undefined,
};

const AUTO_LAYOUT = {};

const UNRESPONSIVE_LAYOUT = {
    autosize: false,
};

/**
 * `responsive: true` causes Plotly.js to resize the graph on `window.resize`.
 * This is necessary for `dcc.Graph` call to `Plotly.Plots.resize(target)` to do something.
 *
 * Users can override this value for specific use-cases by explicitly passing `responsive: false`
 * if `responsive` is not set to True.
 */
const RESPONSIVE_CONFIG = {
    responsive: true,
};

const AUTO_CONFIG = {};

const UNRESPONSIVE_CONFIG = {
    responsive: false,
};

const filterEventData = (gd, eventData, event) => {
    let filteredEventData;
    if (includes(event, ['click', 'hover', 'selected'])) {
        const points = [];

        if (isNil(eventData)) {
            return null;
        }

        /*
         * remove `data`, `layout`, `xaxis`, etc
         * objects from the event data since they're so big
         * and cause JSON stringify ciricular structure errors.
         *
         * also, pull down the `customdata` point from the data array
         * into the event object
         */
        const data = gd.data;

        for (let i = 0; i < eventData.points.length; i++) {
            const fullPoint = eventData.points[i];
            const pointData = filter(function (o) {
                return !includes(type(o), ['Object', 'Array']);
            }, fullPoint);

            // permit a bounding box to pass through, if present
            if (has('bbox', fullPoint)) {
                pointData.bbox = fullPoint.bbox;
            }

            if (
                has('curveNumber', fullPoint) &&
                has('pointNumber', fullPoint) &&
                has('customdata', data[pointData.curveNumber])
            ) {
                pointData.customdata =
                    data[pointData.curveNumber].customdata[
                        fullPoint.pointNumber
                    ];
            }

            // specific to histogram. see https://github.com/plotly/plotly.js/pull/2113/
            if (has('pointNumbers', fullPoint)) {
                pointData.pointNumbers = fullPoint.pointNumbers;
            }

            points[i] = pointData;
        }
        filteredEventData = {points};
    } else if (event === 'relayout' || event === 'restyle') {
        /*
         * relayout shouldn't include any big objects
         * it will usually just contain the ranges of the axes like
         * "xaxis.range[0]": 0.7715822247381828,
         * "xaxis.range[1]": 3.0095292008680063`
         */
        filteredEventData = eventData;
    }
    if (has('range', eventData)) {
        filteredEventData.range = eventData.range;
    }
    if (has('lassoPoints', eventData)) {
        filteredEventData.lassoPoints = eventData.lassoPoints;
    }
    return filteredEventData;
};

/**
 * Graph can be used to render any plotly.js-powered data visualization.
 *
 * You can define callbacks based on user interaction with Graphs such as
 * hovering, clicking or selecting
 */
class PlotlyGraph extends Component {
    constructor(props) {
        super(props);
        this.gd = React.createRef();
        this._hasPlotted = false;
        this._prevGd = null;

        this.bindEvents = this.bindEvents.bind(this);
        this.getConfig = this.getConfig.bind(this);
        this.getConfigOverride = this.getConfigOverride.bind(this);
        this.getLayout = this.getLayout.bind(this);
        this.getLayoutOverride = this.getLayoutOverride.bind(this);
        this.graphResize = this.graphResize.bind(this);
        this.isResponsive = this.isResponsive.bind(this);

        this.state = {override: {}, originals: {}};
    }

    plot(props) {
        let {figure, config} = props;
        const {animate, animation_options, responsive, mathjax} = props;

        const gd = this.gd.current;
        figure = props._dashprivate_transformFigure(figure, gd);
        config = props._dashprivate_transformConfig(config, gd);

        const configClone = this.getConfig(config, responsive);
        // add typesetMath | not exposed to the dash API
        configClone.typesetMath = mathjax;

        const figureClone = {
            data: figure.data,
            layout: this.getLayout(figure.layout, responsive),
            frames: figure.frames,
            config: configClone,
        };

        if (
            animate &&
            this._hasPlotted &&
            figure.data.length === gd.data.length
        ) {
            // in case we've have figure frames,
            // we need to recreate frames before animation
            if (figure.frames) {
                return Plotly.deleteFrames(gd)
                    .then(() => Plotly.addFrames(gd, figure.frames))
                    .then(() =>
                        Plotly.animate(gd, figureClone, animation_options)
                    );
            }
            return Plotly.animate(gd, figureClone, animation_options);
        }

        gd.classList.add('dash-graph--pending');

        return lazyLoadMathJax(mathjax)
            .then(() => Plotly.react(this.gd.current, figureClone))
            .then(() => {
                const gd = this.gd.current;

                // double-check gd hasn't been unmounted
                if (!gd) {
                    return;
                }

                gd.classList.remove('dash-graph--pending');

                // in case we've made a new DOM element, transfer events
                if (this._hasPlotted && gd !== this._prevGd) {
                    if (this._prevGd && this._prevGd.removeAllListeners) {
                        this._prevGd.removeAllListeners();
                        Plotly.purge(this._prevGd);
                    }
                    this._hasPlotted = false;
                }

                if (!this._hasPlotted) {
                    this.bindEvents();
                    this.graphResize(true);
                    this._hasPlotted = true;
                    this._prevGd = gd;
                }
            });
    }
{'fraction_non_alphanumeric': 0.1103631024851393, 'fraction_numerical': 0.006588841939411301, 'mean_word_length': 1.9007062733693394, 'pattern_counts': {'":': 4, '<': 5, '<?xml version=': 0, '>': 13, 'https://': 4, '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': '13218', 'n_tokens_mistral': 4013, 'n_tokens_neox': 3793, 'n_words': 968}