<commit_before>import * as React from "react";
import * as _ from 'lodash';
import wordwrap from 'word-wrap';
import { ThreeBounce } from 'better-react-spinkit';
import { CancerStudy } from 'shared/api/generated/CBioPortalAPI';
import { ChartTooltipItem } from '@types/chart.js';

import Chart from 'chart.js';

export interface IBarGraphProps {
    data:CancerStudy[];
};

interface ICancerTypeStudy {
    caseCount:number;
    shortName:string;
    studies: CancerStudy[];
};

interface ICounterObj {
    [name:string]: ICancerTypeStudy;
};

export default class BarGraph extends React.Component<IBarGraphProps, {colors: string[]}> {

    constructor() {
        super();
    }

    chartTarget:HTMLCanvasElement;

    shouldComponentUpdate() {
        return false;
    }

    getShortName(cancerStudiesObj:ICounterObj) {
        const aliases:{[id:string]:string} = {
            'Ovarian': 'Ovary', 'Cervical': 'Cervix', 'Uterine': 'Uterus',
            'Melanoma': 'Skin', 'CCLE':'Mixed', 'Thymoma(TCGA)': 'Thymus', 'Uveal': 'Eye',
            'Testicular': 'Testicle', 'Colorectal': 'Colon'
        };
        return _.mapValues(cancerStudiesObj, (cancerStudy) => {
            const shortName = cancerStudy.shortName.split(" ")[0];
            return {
                ...cancerStudy,
                shortName: aliases[shortName] ? aliases[shortName] : shortName
            };
        });
    }

    condenseCancerTypes(x:ICancerTypeStudy, y:ICancerTypeStudy[], shortName:string) {
        const studies = [..._.flattenDeep(_.map(y, 'studies')), ...x.studies]
        return {
            caseCount: y.reduce((a, b) => a + b.caseCount, x.caseCount),
            shortName,
            studies
        };
    }

    lightenDarkenColor(col:string, amt:number) {
        const num = parseInt(col,16);

        let r = (num >> 16) + amt;

        if (r > 255) r = 255;
        else if  (r < 0) r = 0;

        let b = ((num >> 8) & 0x00FF) + amt;

        if (b > 255) b = 255;
        else if  (b < 0) b = 0;

        let g = (num & 0x0000FF) + amt;

        if (g > 255) g = 255;
        else if (g < 0) g = 0;

        return "#" + (g | (b << 8) | (r << 16)).toString(16);
    }

    reduceDataArray(data:CancerStudy[]) {
        return _.reduce(data, (counterObj:ICounterObj, study) => {
            const { cancerTypeId, allSampleCount, shortName } = study;
            if (counterObj[cancerTypeId]) {
                counterObj[cancerTypeId].caseCount += allSampleCount;
                counterObj[cancerTypeId].studies.push(study);
            } else {
                counterObj[cancerTypeId] = {
                    caseCount: allSampleCount,
                    shortName,
                    studies: [study]
                };
            }
            return counterObj;
        }, {} as any);
    }

    formatTooltipString(label: string) {
        return wordwrap(label, {width: 30}).split(/\r?\n/).map(_label => _label.trim());
    }

    componentDidMount() {

        let cancerTypeStudiesObj = this.reduceDataArray(this.props.data);

        cancerTypeStudiesObj = this.getShortName(cancerTypeStudiesObj);

        const {luad, lusc, sclc, nsclc, plmeso, paac, paad, panet, esca, escc,
            hnsc, acyc, head_neck, thpa, thyroid, mnet, nbl, acc, difg, gbm, mbl,
            cll, aml, all, es, mm, soft_tissue, ccrcc, prcc, chrcc, nccrcc } = cancerTypeStudiesObj;

        cancerTypeStudiesObj.luad = this.condenseCancerTypes(luad, [lusc, sclc, nsclc, plmeso], 'Lung');
        cancerTypeStudiesObj.paac = this.condenseCancerTypes(paac, [paad, panet], 'Pancreas');
        cancerTypeStudiesObj.esca = this.condenseCancerTypes(esca, [escc], 'Esophagus');
        cancerTypeStudiesObj.hnsc = this.condenseCancerTypes(hnsc, [acyc, head_neck], 'Head/Neck');
        cancerTypeStudiesObj.thpa = this.condenseCancerTypes(thpa, [thyroid], 'Thyroid');
        cancerTypeStudiesObj.difg = this.condenseCancerTypes(difg, [gbm, mbl], 'Brain');
        cancerTypeStudiesObj.cll = this.condenseCancerTypes(cll, [aml, all, soft_tissue, es, mm], 'Blood/Bone');
        cancerTypeStudiesObj.ccrcc = this.condenseCancerTypes(ccrcc, [prcc, chrcc, nccrcc], 'Kidney');
        cancerTypeStudiesObj.mnet = this.condenseCancerTypes(mnet, [nbl, acc], 'Adrenal Gland');

        cancerTypeStudiesObj = _.omit(cancerTypeStudiesObj, 'lusc', 'sclc', 'nsclc', 'plmeso',
            'paad', 'panet', 'escc', 'acyc', 'head_neck', 'gbm', 'mbl', 'aml',
            'all', 'soft_tissue', 'es', 'mm', 'prcc', 'chrcc', 'nbl', 'acc', 'nccrcc',
            'thyroid', 'mixed');

        const cancerTypeStudiesArray =  Object.keys(cancerTypeStudiesObj).map((cancerType) => (
            { type: cancerType,
                ...cancerTypeStudiesObj[cancerType] }
        ))
            .sort((a, b) => b.caseCount - a.caseCount)
            .slice(0, 20);

        const datasets = _.flattenDeep(cancerTypeStudiesArray.map((cancerStudySet, i) => (
            cancerStudySet.studies.sort((a: CancerStudy, b:CancerStudy) => b.allSampleCount - a.allSampleCount).map((cancerStudy: CancerStudy, j: number) => {
                const {name, studyId, allSampleCount} = cancerStudy;
                const max = cancerStudySet.studies.length;
                const colors = ['1E36BF', '128C47', 'BF2231', '7D1FBF', 'BF7D15'];
                const color = this.lightenDarkenColor(colors[i%5], (j + 1)/max * 120);
                return {
                    borderColor: '#F1F6FE',
                    backgroundColor: color,
                    borderWidth: 1,
                    label: name,
                    total: cancerStudySet.caseCount,<commit_msg>Implement Chartjs.<commit_after>import * as React from "react";
import * as _ from 'lodash';
import wordwrap from 'word-wrap';
import { ThreeBounce } from 'better-react-spinkit';
import { CancerStudy } from 'shared/api/generated/CBioPortalAPI';
import { ChartTooltipItem } from '@types/chart.js';

import Chart from 'chart.js';

export interface IBarGraphProps {
    data:CancerStudy[];
};

interface ICancerTypeStudy {
    caseCount:number;
    shortName:string;
    studies: CancerStudy[];
};

interface ICounterObj {
    [name:string]: ICancerTypeStudy;
};

export default class BarGraph extends React.Component<IBarGraphProps, {colors: string[]}> {

    constructor() {
        super();
    }

    chartTarget:HTMLCanvasElement;

    shouldComponentUpdate() {
        return false;
    }

    getShortName(cancerStudiesObj:ICounterObj) {
        const aliases:{[id:string]:string} = {
            'Ovarian': 'Ovary', 'Cervical': 'Cervix', 'Uterine': 'Uterus',
            'Melanoma': 'Skin', 'CCLE':'Mixed', 'Thymoma(TCGA)': 'Thymus', 'Uveal': 'Eye',
            'Testicular': 'Testicle', 'Colorectal': 'Colon'
        };
        return _.mapValues(cancerStudiesObj, (cancerStudy) => {
            const shortName = cancerStudy.shortName.split(" ")[0];
            return {
                ...cancerStudy,
                shortName: aliases[shortName] ? aliases[shortName] : shortName
            };
        });
    }

    condenseCancerTypes(x:ICancerTypeStudy, y:ICancerTypeStudy[], shortName:string) {
        let xStudy = x ? x : {studies:[], caseCount: 0};
        const yStudies = _.without(y, null, undefined);
        if (yStudies.length === 0) {
            if (_.isEmpty(xStudy)) return false;
            return {
                caseCount: x.caseCount,
                shortName,
                studies: x.studies
            };
        }
        const studies = [..._.flattenDeep(_.map(yStudies, 'studies')), ...xStudy.studies]
        return {
            caseCount: yStudies.reduce((a, b) => a + b!.caseCount, xStudy.caseCount),
            shortName,
            studies
        };
    }

    lightenDarkenColor(col:string, amt:number) {
        const num = parseInt(col,16);

        let r = (num >> 16) + amt;

        if (r > 255) r = 255;
        else if  (r < 0) r = 0;

        let b = ((num >> 8) & 0x00FF) + amt;

        if (b > 255) b = 255;
        else if  (b < 0) b = 0;

        let g = (num & 0x0000FF) + amt;

        if (g > 255) g = 255;
        else if (g < 0) g = 0;

        return "#" + (g | (b << 8) | (r << 16)).toString(16);
    }

    reduceDataArray(data:CancerStudy[]) {
        return _.reduce(data, (counterObj:ICounterObj, study) => {
            const { cancerTypeId, allSampleCount, shortName } = study;
            if (counterObj[cancerTypeId]) {
                counterObj[cancerTypeId].caseCount += allSampleCount;
                counterObj[cancerTypeId].studies.push(study);
            } else {
                counterObj[cancerTypeId] = {
                    caseCount: allSampleCount,
                    shortName,
                    studies: [study]
                };
            }
            return counterObj;
        }, {} as any);
    }

    formatTooltipString(label: string) {
        return wordwrap(label, {width: 30}).split(/\r?\n/).map(_label => _label.trim());
    }

    componentDidMount() {

        let cancerTypeStudiesObj = this.reduceDataArray(this.props.data);

        cancerTypeStudiesObj = this.getShortName(cancerTypeStudiesObj);

        const {luad, lusc, sclc, nsclc, plmeso, paac, paad, panet, esca, escc,
            hnsc, acyc, head_neck, thpa, thyroid, mnet, nbl, acc, difg, gbm, mbl,
            cll, aml, all, es, mm, soft_tissue, ccrcc, prcc, chrcc, nccrcc } = cancerTypeStudiesObj;

        cancerTypeStudiesObj.luad = this.condenseCancerTypes(luad, [lusc, sclc, nsclc, plmeso], 'Lung');
        cancerTypeStudiesObj.paac = this.condenseCancerTypes(paac, [paad, panet], 'Pancreas');
        cancerTypeStudiesObj.esca = this.condenseCancerTypes(esca, [escc], 'Esophagus');
        cancerTypeStudiesObj.hnsc = this.condenseCancerTypes(hnsc, [acyc, head_neck], 'Head/Neck');
        cancerTypeStudiesObj.thpa = this.condenseCancerTypes(thpa, [thyroid], 'Thyroid');
        cancerTypeStudiesObj.difg = this.condenseCancerTypes(difg, [gbm, mbl], 'Brain');
        cancerTypeStudiesObj.cll = this.condenseCancerTypes(cll, [aml, all, soft_tissue, es, mm], 'Blood/Bone');
        cancerTypeStudiesObj.ccrcc = this.condenseCancerTypes(ccrcc, [prcc, chrcc, nccrcc], 'Kidney');
        cancerTypeStudiesObj.mnet = this.condenseCancerTypes(mnet, [nbl, acc], 'Adrenal Gland');

        cancerTypeStudiesObj = _.omitBy(_.omit(cancerTypeStudiesObj, 'lusc', 'sclc', 'nsclc', 'plmeso',
            'paad', 'panet', 'escc', 'acyc', 'head_neck', 'gbm', 'mbl', 'aml',
            'all', 'soft_tissue', 'es', 'mm', 'prcc', 'chrcc', 'nbl', 'acc', 'nccrcc',
            'thyroid', 'mixed'), value => value === false);

        const cancerTypeStudiesArray =  Object.keys(cancerTypeStudiesObj).map((cancerType) => (
            { type: cancerType,
                ...cancerTypeStudiesObj[cancerType] }
        ))
            .sort((a, b) => b.caseCount - a.caseCount)
            .slice(0, 20);

        const datasets = _.flattenDeep(cancerTypeStudiesArray.map((cancerStudySet, i) => (
            cancerStudySet.studies.sort((a: CancerStudy, b:CancerStudy) => b.allSampleCount - a.allSampleCount).map((cancerStudy: CancerStudy, j: number) => {
                const {name, studyId, allSampleCount} = cancerStudy;
                const max = cancerStudySet.studies.length;
                const colors = ['1E36BF', '128C47', 'BF2231', '7D1FBF', 'BF7D15'];
                const color = this.lightenDarkenColor(colors[i%5], (j + 1)/max * 120);
                return {
                    borderColor: '#F1F6FE',
                    backgroundColor: color,
                    borderWidth: 1,
                    label: name,
                    total: cancerStudySet.caseCount,
{'fraction_non_alphanumeric': 0.14106181072069762, 'fraction_numerical': 0.01265281696161409, 'mean_word_length': 2.396631823461092, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 38, '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': '664105', 'n_tokens_mistral': 4051, 'n_tokens_neox': 3707, 'n_words': 768}