<commit_before>import * as React from 'react';
import SurvivalChart from "../resultsView/survival/SurvivalChart";
import LoadingIndicator from "shared/components/loadingIndicator/LoadingIndicator";
import {observer} from "mobx-react";
import GroupComparisonStore, {OverlapStrategy} from './GroupComparisonStore';
import {remoteData} from 'shared/api/remoteData';
import {MakeMobxView} from "../../shared/components/MobxView";
import {SURVIVAL_TOO_MANY_GROUPS_MSG} from "./GroupComparisonUtils";
import ErrorMessage from "../../shared/components/ErrorMessage";
import {blendColors} from "./OverlapUtils";
import OverlapExclusionIndicator from "./OverlapExclusionIndicator";
import _ from "lodash";

export interface ISurvivalProps {
    store: GroupComparisonStore
}

@observer
export default class Survival extends React.Component<ISurvivalProps, {}> {

    private overallSurvivalTitleText = 'Overall Survival Kaplan-Meier Estimate';
    private diseaseFreeSurvivalTitleText = 'Disease/Progression-free Kaplan-Meier Estimate';

    public readonly analysisGroupsComputations = remoteData({
        await: () => [
            this.props.store.patientsVennPartition,
            this.props.store.uidToGroup
        ],
        invoke: () => {
            const orderedActiveGroupUidSet = _.reduce(this.props.store._activeGroupsNotOverlapRemoved.result!, (acc, next, index) => {
                acc[next.uid] = index;
                return acc;
            }, {} as { [id: string]: number });
            const partition = this.props.store.patientsVennPartition.result!;

            // ascending sort partition bases on number of groups in each parition.
            // if they are equal then sort based on the give order of groups
            partition.sort((a, b) => {
                const aUids = Object.keys(a.key).filter(uid=>a.key[uid]);
                const bUids = Object.keys(b.key).filter(uid=>b.key[uid]);
                if (aUids.length !== bUids.length) {
                    return aUids.length - bUids.length;
                }
                const aCount = _.sumBy(aUids, uid=>orderedActiveGroupUidSet[uid])
                const bCount = _.sumBy(bUids, uid=>orderedActiveGroupUidSet[uid])
                return aCount - bCount;
            });
            const uidToGroup = this.props.store.uidToGroup.result!;
            const analysisGroups = [];
            const patientToAnalysisGroups:{[patientKey:string]:string[]} = {};
            for (const entry of partition) {
                const partitionGroupUids = Object.keys(entry.key).filter(uid=>entry.key[uid]);
                // sort by give order of groups
                partitionGroupUids.sort((a, b) => orderedActiveGroupUidSet[a] - orderedActiveGroupUidSet[b]);
                if (this.props.store.overlapStrategy === OverlapStrategy.EXCLUDE && partitionGroupUids.length > 1) {
                    // dont show the overlap curves if we're excluding overlapping cases
                } else {
                    const name = partitionGroupUids.map(uid=>uidToGroup[uid].nameWithOrdinal).join(", ");
                    const value = partitionGroupUids.join(",");
                    for (const patientKey of entry.value) {
                        patientToAnalysisGroups[patientKey] = [value];
                    }
                    analysisGroups.push({
                        name,
                        color: blendColors(partitionGroupUids.map(uid=>uidToGroup[uid].color)),
                        value,
                        legendText: name
                    });
                }
            }
            return Promise.resolve({
                analysisGroups,
                patientToAnalysisGroups
            });
        }
    });


    readonly tabUI = MakeMobxView({
        await:()=>{
            if (this.props.store._activeGroupsNotOverlapRemoved.isComplete &&
                this.props.store._activeGroupsNotOverlapRemoved.result.length > 10) {
                // dont bother loading data for and computing UI if its not valid situation for it
                return [this.props.store._activeGroupsNotOverlapRemoved];
            } else {<commit_msg>GC survival: Add only valid srivival curves<commit_after>import * as React from 'react';
import SurvivalChart from "../resultsView/survival/SurvivalChart";
import LoadingIndicator from "shared/components/loadingIndicator/LoadingIndicator";
import {observer} from "mobx-react";
import GroupComparisonStore, {OverlapStrategy} from './GroupComparisonStore';
import {remoteData} from 'shared/api/remoteData';
import {MakeMobxView} from "../../shared/components/MobxView";
import {SURVIVAL_TOO_MANY_GROUPS_MSG} from "./GroupComparisonUtils";
import ErrorMessage from "../../shared/components/ErrorMessage";
import {blendColors} from "./OverlapUtils";
import OverlapExclusionIndicator from "./OverlapExclusionIndicator";
import _ from "lodash";

export interface ISurvivalProps {
    store: GroupComparisonStore
}

@observer
export default class Survival extends React.Component<ISurvivalProps, {}> {

    private overallSurvivalTitleText = 'Overall Survival Kaplan-Meier Estimate';
    private diseaseFreeSurvivalTitleText = 'Disease/Progression-free Kaplan-Meier Estimate';

    public readonly analysisGroupsComputations = remoteData({
        await: () => [
            this.props.store.patientsVennPartition,
            this.props.store.uidToGroup
        ],
        invoke: () => {
            const orderedActiveGroupUidSet = _.reduce(this.props.store._activeGroupsNotOverlapRemoved.result!, (acc, next, index) => {
                acc[next.uid] = index;
                return acc;
            }, {} as { [id: string]: number });
            const partition = this.props.store.patientsVennPartition.result!;

            // ascending sort partition bases on number of groups in each parition.
            // if they are equal then sort based on the give order of groups
            partition.sort((a, b) => {
                const aUids = Object.keys(a.key).filter(uid=>a.key[uid]);
                const bUids = Object.keys(b.key).filter(uid=>b.key[uid]);
                if (aUids.length !== bUids.length) {
                    return aUids.length - bUids.length;
                }
                const aCount = _.sumBy(aUids, uid=>orderedActiveGroupUidSet[uid])
                const bCount = _.sumBy(bUids, uid=>orderedActiveGroupUidSet[uid])
                return aCount - bCount;
            });
            const uidToGroup = this.props.store.uidToGroup.result!;
            const analysisGroups = [];
            const patientToAnalysisGroups:{[patientKey:string]:string[]} = {};
            for (const entry of partition) {
                const partitionGroupUids = Object.keys(entry.key).filter(uid=>entry.key[uid]);
                // sort by give order of groups
                partitionGroupUids.sort((a, b) => orderedActiveGroupUidSet[a] - orderedActiveGroupUidSet[b]);
                if (this.props.store.overlapStrategy === OverlapStrategy.EXCLUDE && partitionGroupUids.length > 1) {
                    // dont show the overlap curves if we're excluding overlapping cases
                } else {
                    if (partitionGroupUids.length > 0) {
                        const name = partitionGroupUids.map(uid => uidToGroup[uid].nameWithOrdinal).join(", ");
                        const value = partitionGroupUids.join(",");
                        for (const patientKey of entry.value) {
                            patientToAnalysisGroups[patientKey] = [value];
                        }
                        analysisGroups.push({
                            name,
                            color: blendColors(partitionGroupUids.map(uid => uidToGroup[uid].color)),
                            value,
                            legendText: name
                        });
                    }
                }
            }
            return Promise.resolve({
                analysisGroups,
                patientToAnalysisGroups
            });
        }
    });


    readonly tabUI = MakeMobxView({
        await:()=>{
            if (this.props.store._activeGroupsNotOverlapRemoved.isComplete &&
                this.props.store._activeGroupsNotOverlapRemoved.result.length > 10) {
                // dont bother loading data for and computing UI if its not valid situation for it
                return [this.props.store._activeGroupsNotOverlapRemoved];
            } else {
{'fraction_non_alphanumeric': 0.10253090052972337, 'fraction_numerical': 0.000824014125956445, 'mean_word_length': 2.1029948867786707, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 36, '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': '2634621', 'n_tokens_mistral': 2228, 'n_tokens_neox': 2117, 'n_words': 485}