private renderParallelCoordinates()

in ts/webui/src/components/trial-detail/Para.tsx [174:274]


    private renderParallelCoordinates(): void {
        const { searchSpace } = this.props;
        const percent = parseFloat(this.state.selectedPercent);
        const { primaryMetricKey, chosenDimensions } = this.state;

        const inferredSearchSpace = TRIALS.inferredSearchSpace(searchSpace);
        const inferredMetricSpace = TRIALS.inferredMetricSpace();
        let convertedTrials = this.getTrialsAsObjectList(inferredSearchSpace, inferredMetricSpace);

        const dimensions: [string, any][] = [];
        let colorDim: string | undefined = undefined,
            colorScale: any = undefined;
        // treat every axis as numeric to fit for brush
        for (const [k, v] of inferredSearchSpace.axes) {
            dimensions.push([
                k,
                {
                    type: 'number',
                    yscale: this.convertToD3Scale(v)
                }
            ]);
        }
        for (const [k, v] of inferredMetricSpace.axes) {
            const scale = this.convertToD3Scale(v);
            if (k === primaryMetricKey && scale !== undefined && scale.interpolate) {
                // set color for primary metrics
                // `colorScale` is used to produce a color range, while `scale` is to produce a pixel range
                colorScale = this.convertToD3Scale(v, false);
                convertedTrials.sort((a, b) => (EXPERIMENT.optimizeMode === 'minimize' ? a[k] - b[k] : b[k] - a[k]));
                // filter top trials
                if (percent != 1) {
                    const keptTrialNum = Math.max(Math.ceil(convertedTrials.length * percent), 1);
                    convertedTrials = convertedTrials.slice(0, keptTrialNum);
                    const domain = d3.extent(convertedTrials, item => item[k]);
                    scale.domain([domain[0], domain[1]]);
                    colorScale.domain([domain[0], domain[1]]);
                    if (colorScale !== undefined) {
                        colorScale.domain(domain);
                    }
                }
                // reverse the converted trials to show the top ones upfront
                convertedTrials.reverse();
                const assignColors = (scale: any): void => {
                    scale.range([0, 1]); // fake a range to perform invert
                    const [scaleMin, scaleMax] = scale.domain();
                    const pivot = scale.invert(0.5);
                    scale
                        .domain([scaleMin, pivot, scaleMax])
                        .range(['#90EE90', '#FFC400', '#CA0000'])
                        .interpolate(d3.interpolateHsl);
                };
                assignColors(colorScale);
                colorDim = k;
            }
            dimensions.push([
                k,
                {
                    type: 'number',
                    yscale: scale
                }
            ]);
        }

        if (convertedTrials.length === 0 || dimensions.length <= 1) {
            return;
        }

        const firstRun = this.pcs === undefined;
        if (firstRun) {
            this.pcs = ParCoords()(this.paraRef.current);
        }
        this.pcs
            .data(convertedTrials)
            .dimensions(
                dimensions
                    .filter(([d, _]) => chosenDimensions.length === 0 || chosenDimensions.includes(d))
                    .reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1] }), {})
            );
        if (firstRun) {
            this.pcs
                .margin(this.innerChartMargins)
                .alphaOnBrushed(0.2)
                .smoothness(0.1)
                .brushMode('1D-axes')
                .reorderable()
                .interactive();
        }
        if (colorScale !== undefined) {
            this.pcs.color(d => (colorScale as any)(d[colorDim as any]));
        }
        this.pcs.render();
        if (firstRun) {
            this.setState({ noChart: false });
        }

        // set new available dims
        this.setState({
            availableDimensions: dimensions.map(e => e[0]),
            chosenDimensions: chosenDimensions.length === 0 ? dimensions.map(e => e[0]) : chosenDimensions
        });
    }