diff --git a/src/pages/groupComparison/MultipleCategoryBarPlot.tsx b/src/pages/groupComparison/MultipleCategoryBarPlot.tsx index ec6fa6e8dc8..4badab7bef4 100644 --- a/src/pages/groupComparison/MultipleCategoryBarPlot.tsx +++ b/src/pages/groupComparison/MultipleCategoryBarPlot.tsx @@ -58,6 +58,16 @@ export interface IMultipleCategoryBarPlotProps { svgRef?: (svgContainer: SVGElement | null) => void; pValue: number | null; qValue: number | null; + sortOption?: string; +} +export interface TotalSumItem { + majorCategory: string; + sum: number; + minorCategory: { + name: string; + count: number; + percentage: number; + }[]; } export interface IMultipleCategoryBarPlotData { @@ -274,6 +284,7 @@ export default class MultipleCategoryBarPlot extends React.Component< } else if (this.props.plotData) { data = this.props.plotData; } + return data; } @@ -424,12 +435,56 @@ export default class MultipleCategoryBarPlot extends React.Component< } @computed get labels() { + if (this.props.sortOption == 'sortByCount') { + _.forEach(this.data, item => { + item.counts.sort((a, b) => + a.majorCategory.localeCompare(b.majorCategory) + ); + }); + const totalSumArray: TotalSumItem[] = []; + _.forEach(this.data, item => { + _.forEach(item.counts, countItem => { + const existingItem = _.find( + totalSumArray, + sumItem => + sumItem.majorCategory === countItem.majorCategory + ); + if (existingItem) { + existingItem.sum += countItem.count; + existingItem.minorCategory.push({ + name: item.minorCategory, + count: countItem.count, + percentage: countItem.percentage, + }); + } else { + totalSumArray.push({ + majorCategory: countItem.majorCategory, + sum: countItem.count, + minorCategory: [ + { + name: item.minorCategory, + count: countItem.count, + percentage: countItem.percentage, + }, + ], + }); + } + }); + }); + + totalSumArray.sort((a, b) => b.sum - a.sum); + + const sortedLabels = totalSumArray.map(item => item.majorCategory); + return sortedLabels; + } + if (this.data.length > 0) { - return sortDataByCategory( + const CategorizedData = sortDataByCategory( this.data[0].counts.map(c => c.majorCategory), x => x, this.majorCategoryOrder ); + return CategorizedData; } else { return []; } @@ -739,7 +794,8 @@ export default class MultipleCategoryBarPlot extends React.Component< this.categoryCoord, !!this.props.horizontalBars, !!this.props.stacked, - !!this.props.percentage + !!this.props.percentage, + this.props.sortOption || 'sortByAlphabet' ); return barSpecs.map(spec => ( { categoryCoord, false, false, - false + false, + 'sortByAlphabet' ), [] ); @@ -267,7 +268,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - false + false, + 'sortByAlphabet' ), [ { @@ -341,7 +343,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - true + true, + 'sortByAlphabet' ), [ { @@ -415,7 +418,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - false + false, + 'sortByAlphabet' ), [ { @@ -489,7 +493,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - true + true, + 'sortByAlphabet' ), [ { @@ -563,7 +568,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - false + false, + 'sortByAlphabet' ), [ { @@ -637,7 +643,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - true + true, + 'sortByAlphabet' ), [ { @@ -711,7 +718,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - false + false, + 'sortByAlphabet' ), [ { @@ -785,7 +793,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - true + true, + 'sortByAlphabet' ), [ { @@ -861,7 +870,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - false + false, + 'sortByAlphabet' ), [ { @@ -940,7 +950,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - true + true, + 'sortByAlphabet' ), [ { @@ -1019,7 +1030,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - false + false, + 'sortByAlphabet' ), [ { @@ -1098,7 +1110,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - true + true, + 'sortByAlphabet' ), [ { @@ -1177,7 +1190,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - false + false, + 'sortByAlphabet' ), [ { @@ -1256,7 +1270,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - true + true, + 'sortByAlphabet' ), [ { @@ -1335,7 +1350,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - false + false, + 'sortByAlphabet' ), [ { @@ -1414,7 +1430,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - true + true, + 'sortByAlphabet' ), [ { @@ -1494,7 +1511,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - false + false, + 'sortByAlphabet' ), [ { @@ -1568,7 +1586,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - true + true, + 'sortByAlphabet' ), [ { @@ -1642,7 +1661,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - false + false, + 'sortByAlphabet' ), [ { @@ -1716,7 +1736,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - true + true, + 'sortByAlphabet' ), [ { @@ -1790,7 +1811,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - false + false, + 'sortByAlphabet' ), [ { @@ -1864,7 +1886,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - true + true, + 'sortByAlphabet' ), [ { @@ -1938,7 +1961,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - false + false, + 'sortByAlphabet' ), [ { @@ -2012,7 +2036,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, false, false, - true + true, + 'sortByAlphabet' ), [ { @@ -2088,7 +2113,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - false + false, + 'sortByAlphabet' ), [ { @@ -2167,7 +2193,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, true, - true + true, + 'sortByAlphabet' ), [ { @@ -2246,7 +2273,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - false + false, + 'sortByAlphabet' ), [ { @@ -2325,7 +2353,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, true, - true + true, + 'sortByAlphabet' ), [ { @@ -2404,7 +2433,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - false + false, + 'sortByAlphabet' ), [ { @@ -2483,7 +2513,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, true, - true + true, + 'sortByAlphabet' ), [ { @@ -2562,7 +2593,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, false, - false + false, + 'sortByAlphabet' ), [ { @@ -2641,7 +2673,8 @@ describe('MultipleCategoryBarPlotUtils', () => { categoryCoord, true, true, - true + true, + 'sortByAlphabet' ), [ { diff --git a/src/shared/components/plots/MultipleCategoryBarPlotUtils.ts b/src/shared/components/plots/MultipleCategoryBarPlotUtils.ts index cd41f0325a0..93ad619a89a 100644 --- a/src/shared/components/plots/MultipleCategoryBarPlotUtils.ts +++ b/src/shared/components/plots/MultipleCategoryBarPlotUtils.ts @@ -1,6 +1,10 @@ import { IStringAxisData } from './PlotsTabUtils'; import _ from 'lodash'; -import { IMultipleCategoryBarPlotData } from '../../../pages/groupComparison/MultipleCategoryBarPlot'; +import { + IMultipleCategoryBarPlotData, + TotalSumItem, +} from '../../../pages/groupComparison/MultipleCategoryBarPlot'; +import { marginLeft } from 'pages/patientView/trialMatch/style/trialMatch.module.scss'; export function makePlotData( horzData: IStringAxisData['data'], @@ -107,7 +111,8 @@ export function makeBarSpecs( categoryCoord: (categoryIndex: number) => number, horizontalBars: boolean, stacked: boolean, - percentage: boolean + percentage: boolean, + sortOption?: string ): { fill: string; data: { @@ -117,24 +122,94 @@ export function makeBarSpecs( minorCategory: string; count: number; percentage: number; - }[]; // one data per major category, in correct order - either specified, or alphabetical + }[]; }[] { - // one bar spec per minor category, in correct order - either specified, or alphabetical data = sortDataByCategory(data, d => d.minorCategory, minorCategoryOrder); - // reverse the order of stacked or horizontal bars + if ((!horizontalBars && stacked) || (horizontalBars && !stacked)) { data = _.reverse(data); } + data.forEach(item => { + item.counts.sort((a, b) => + a.majorCategory.localeCompare(b.majorCategory) + ); + }); + + const totalSumArray: TotalSumItem[] = []; + data.forEach(item => { + item.counts.forEach(countItem => { + const existingItem = totalSumArray.find( + sumItem => sumItem.majorCategory === countItem.majorCategory + ); + if (existingItem) { + existingItem.sum += countItem.count; + existingItem.minorCategory.push({ + name: item.minorCategory, + count: countItem.count, + percentage: countItem.percentage, + }); + } else { + totalSumArray.push({ + majorCategory: countItem.majorCategory, + sum: countItem.count, + minorCategory: [ + { + name: item.minorCategory, + count: countItem.count, + percentage: countItem.percentage, + }, + ], + }); + } + }); + }); + + totalSumArray.sort((a, b) => b.sum - a.sum); + return data.map(({ minorCategory, counts }) => { const fill = getColor(minorCategory); - const sortedCounts = sortDataByCategory( - counts, - d => d.majorCategory, - majorCategoryOrder - ); + + let categorizedCounts; + if (sortOption == 'sortByCount') { + const minorCategoryArrays: { + [key: string]: { + majorCategory: string; + count: number; + percentage: number; + }[]; + } = {}; + data.forEach(item => { + // Extract the minorCategory from the current item + if (!minorCategoryArrays[item.minorCategory]) { + minorCategoryArrays[item.minorCategory] = []; + } + + // Find corresponding items in totalSumArray and add them to the array + totalSumArray.forEach(totalItem => { + totalItem.minorCategory.forEach(minorItem => { + if (minorItem.name === item.minorCategory) { + minorCategoryArrays[item.minorCategory].push({ + majorCategory: totalItem.majorCategory, + count: minorItem.count, + percentage: minorItem.percentage, + }); + } + }); + }); + }); + + categorizedCounts = minorCategoryArrays[minorCategory]; + } else { + categorizedCounts = sortDataByCategory( + counts, + d => d.majorCategory, + majorCategoryOrder + ); + } + return { fill, - data: sortedCounts.map((obj, index) => ({ + data: categorizedCounts.map((obj, index) => ({ x: categoryCoord(index), y: percentage ? obj.percentage : obj.count, majorCategory: obj.majorCategory, diff --git a/src/shared/components/plots/PlotsTab.tsx b/src/shared/components/plots/PlotsTab.tsx index 814df5b16f7..dac31c4b9c4 100644 --- a/src/shared/components/plots/PlotsTab.tsx +++ b/src/shared/components/plots/PlotsTab.tsx @@ -261,6 +261,10 @@ export type ColoringMenuSelection = { entrezGeneId?: number; }; }; +interface OptionType { + value: string; + label: string; +} export interface IPlotsTabProps { filteredSamplesByDetailedCancerType: MobxPromise<{ @@ -439,8 +443,9 @@ export default class PlotsTab extends React.Component { private scrollPane: HTMLDivElement; private dummyScrollPane: HTMLDivElement; private scrollingDummyPane = false; - @observable plotElementWidth = 0; + @observable plotElementWidth = 0; + @observable sortOption: string = 'sortByAlphabet'; @observable boxPlotSortByMedian = false; @observable.ref searchCaseInput: string; @observable.ref searchMutationInput: string; @@ -848,6 +853,8 @@ export default class PlotsTab extends React.Component { this.horzSelection = this.initAxisMenuSelection(false); this.vertSelection = this.initAxisMenuSelection(true); this.coloringMenuSelection = this.initColoringMenuSelection(); + this.sortOption = 'sortByAlphabet'; + this.handleChangeSortOption = this.handleChangeSortOption.bind(this); this.searchCaseInput = ''; this.searchMutationInput = ''; @@ -1488,7 +1495,16 @@ export default class PlotsTab extends React.Component { selectedCategories: [], }); } - + handleChangeSortOption(selectedOption: OptionType) { + if (selectedOption) { + console.log(selectedOption, 'thisisselectedoptions'); + console.log(this.sortOption, 'thisSOrtts'); + this.sortOption = selectedOption.value; + // this.setState({ sortOption: selectedOption.value }); + } else { + // Handle case when selectedOption is null (if needed) + } + } private initColoringMenuSelection(): ColoringMenuSelection { const self = this; return observable({ @@ -4448,6 +4464,32 @@ export default class PlotsTab extends React.Component { )} + {this.isStacked && (this.plotType.result==3) && ( +
+ +
+ +
+
+ )} {showRegression && (