<commit_before>import Component from './Component';
import Globals from '../../Globals';
import ParallelLineset from '../components/ParallelLineset';
import {
    map,
    scaleLinear,
    scalePoint,
    axisLeft,
    axisBottom,
    Axis,
    extent,
    select,
    drag,
    event,
    brushY
} from 'd3';

class ParallelCoordinates extends Component {

    /**
     * An Array of dimensions extracted from the data of parallel coordinates
     * @private
     * @memberof ParallelCoordinates
     */
    private _dimensions: string[] = [];

    /**
     * A scale of dimensions. Determine dimension-position of parallel coordinates
     * @private
     * @memberof ParallelCoordinates
     */
    private _dimensionScale: any;

    /**
     * Parallel y-axes divided by dimension
     * @private
     * @memberof ParallelCoordinates
     */
    private _yAxes: { [dimension: string]: any } = {};

    /**
     * Type of parallel y-axes extracted from the data.
     * (number, string) -> ('linear', 'categorical')
     * @private
     * @memberof ParallelCoordinates
     */
    private yAxesType: { [dimension: string]: string } = {};

    /**
     * A set of no-value line
     * @private
     * @type {NoValueLineset}
     * @memberof ParallelCoordinates
     */
    private noValueLine: NoValueLineset;

    private dragEventPositions: any;
    private brushedExtent: any;

    constructor() {
        super();
    }

    public render() {
        let width = this.config.get('width');

        this.initializeParallelCoordinates(width);
    }

    public update(data: [any]) {
        let propertyKey = this.config.get('propertyKey'),
            height = this.config.get('height'),
            width = this.config.get('width');

        let missingDimensions: boolean = false;

        // extract dimensions of each data and check if data with missing dimensions exists
        data.map((d, i) => {
            let dimensions = Object.keys(d).filter((dimension) => dimension != propertyKey);
            if (dimensions.length != this._dimensions.length) {
                if (i != 0 && !missingDimensions) {
                    missingDimensions = true;
                }
                if (dimensions.length > this._dimensions.length) {
                    this._dimensions = dimensions;
                }
            }
        });

        // optimize to avoid looping by getting one of valid data
        let validData = data.find(this.getValidData, this);

        this.updateYaxesType(validData);
        this.updateDomainOfDimensions();
        this.updateYaxesByDimensions(data, height);

        this.initializeEvent(); // TODO separate event to each component

        let thisInstance = this;    // To use instance method in selection event

        if (missingDimensions) {
            this.noValueLine = {
                axis: axisBottom(this._dimensionScale).tickFormat((d) => ''),
                height: height * 1.1
            };

            this.svg.append('g')
                .attr('class', 'novalue-axis')
                .attr('transform', 'translate(0,' + this.noValueLine.height + ')')
                .call(thisInstance.noValueLine.axis);

            this.svg.append('text')
                .attr('class', 'xaxis-title')
                .attr('x', width + 10)
                .attr('y', height + 105)
                .text('No Value');
        }

        let dimensionEntries = this.svg.selectAll('.dimension')
                                    .data(this._dimensions)
                                    .enter()
                                    .append('g')
                                    .attr('class', 'dimension')
                                    .attr('transform', (d) => 'translate(' + this._dimensionScale(d) + ')')
                                    .each(function(d) {
                                        select(this)
                                            .call(drag()
                                                .on('start', (dimension) => thisInstance.startDrag(d))
                                                .on('drag', (dimension) => thisInstance.dragging(d))
                                                .on('end', (dimension) => thisInstance.endDrag(d, this))
                                            );
                                    });

        dimensionEntries.append('g')
                    .attr('class', 'axis')
                    .attr('transform', 'translate( 0, 0 )')
                    .each(function(d) {
                        select(this)
                            .call(thisInstance._yAxes[d]);
                    });

        dimensionEntries.append('text')
                .attr('class', 'yaxis-title')
                .style('text-anchor', 'middle')
                .style('cursor', 'move')
                .attr('y', -9)<commit_msg>Align no-value axis and text<commit_after>import Component from './Component';
import Globals from '../../Globals';
import ParallelLineset from '../components/ParallelLineset';
import {
    map,
    scaleLinear,
    scalePoint,
    axisLeft,
    axisBottom,
    Axis,
    extent,
    select,
    drag,
    event,
    brushY
} from 'd3';

class ParallelCoordinates extends Component {

    /**
     * An Array of dimensions extracted from the data of parallel coordinates
     * @private
     * @memberof ParallelCoordinates
     */
    private _dimensions: string[] = [];

    /**
     * A scale of dimensions. Determine dimension-position of parallel coordinates
     * @private
     * @memberof ParallelCoordinates
     */
    private _dimensionScale: any;

    /**
     * Parallel y-axes divided by dimension
     * @private
     * @memberof ParallelCoordinates
     */
    private _yAxes: { [dimension: string]: any } = {};

    /**
     * Type of parallel y-axes extracted from the data.
     * (number, string) -> ('linear', 'categorical')
     * @private
     * @memberof ParallelCoordinates
     */
    private yAxesType: { [dimension: string]: string } = {};

    /**
     * A set of no-value line
     * @private
     * @type {NoValueLineset}
     * @memberof ParallelCoordinates
     */
    private noValueLine: NoValueLineset;

    private dragEventPositions: any;
    private brushedExtent: any;

    constructor() {
        super();
    }

    public render() {
        let width = this.config.get('width');

        this.initializeParallelCoordinates(width);
    }

    public update(data: [any]) {
        let propertyKey = this.config.get('propertyKey'),
            height = this.config.get('height'),
            width = this.config.get('width');

        let missingDimensions: boolean = false;

        // extract dimensions of each data and check if data with missing dimensions exists
        data.map((d, i) => {
            let dimensions = Object.keys(d).filter((dimension) => dimension != propertyKey);
            if (dimensions.length != this._dimensions.length) {
                if (i != 0 && !missingDimensions) {
                    missingDimensions = true;
                }
                if (dimensions.length > this._dimensions.length) {
                    this._dimensions = dimensions;
                }
            }
        });

        // optimize to avoid looping by getting one of valid data
        let validData = data.find(this.getValidData, this);

        this.updateYaxesType(validData);
        this.updateDomainOfDimensions();
        this.updateYaxesByDimensions(data, height);

        this.initializeEvent(); // TODO separate event to each component

        let thisInstance = this;    // To use instance method in selection event

        if (missingDimensions) {
            this.noValueLine = {
                axis: axisBottom(this._dimensionScale).tickFormat((d) => ''),
                height: height * 1.2
            };

            this.svg.append('g')
                .attr('class', 'novalue-axis')
                .attr('transform', 'translate(0,' + this.noValueLine.height + ')')
                .call(thisInstance.noValueLine.axis);

            this.svg.append('text')
                .attr('class', 'xaxis-title')
                .attr('x', width + 10)
                .attr('y', height * 1.21)
                .text('No Value');
        }

        let dimensionEntries = this.svg.selectAll('.dimension')
                                    .data(this._dimensions)
                                    .enter()
                                    .append('g')
                                    .attr('class', 'dimension')
                                    .attr('transform', (d) => 'translate(' + this._dimensionScale(d) + ')')
                                    .each(function(d) {
                                        select(this)
                                            .call(drag()
                                                .on('start', (dimension) => thisInstance.startDrag(d))
                                                .on('drag', (dimension) => thisInstance.dragging(d))
                                                .on('end', (dimension) => thisInstance.endDrag(d, this))
                                            );
                                    });

        dimensionEntries.append('g')
                    .attr('class', 'axis')
                    .attr('transform', 'translate( 0, 0 )')
                    .each(function(d) {
                        select(this)
                            .call(thisInstance._yAxes[d]);
                    });

        dimensionEntries.append('text')
                .attr('class', 'yaxis-title')
                .style('text-anchor', 'middle')
                .style('cursor', 'move')
                .attr('y', -9)
{'fraction_non_alphanumeric': 0.11919441019317714, 'fraction_numerical': 0.0026715988491574187, 'mean_word_length': 1.4596916856204194, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 36, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3508174', 'n_tokens_mistral': 2518, 'n_tokens_neox': 2361, 'n_words': 553}