diff --git a/src/main/java/org/cbioportal/service/impl/AlterationCountServiceImpl.java b/src/main/java/org/cbioportal/service/impl/AlterationCountServiceImpl.java index 8bc8d23f793..28f3d34611f 100644 --- a/src/main/java/org/cbioportal/service/impl/AlterationCountServiceImpl.java +++ b/src/main/java/org/cbioportal/service/impl/AlterationCountServiceImpl.java @@ -8,7 +8,6 @@ import org.cbioportal.model.AlterationType; import org.cbioportal.model.CopyNumberCountByGene; import org.cbioportal.model.Gistic; -import org.cbioportal.model.GisticToGene; import org.cbioportal.model.MolecularProfile; import org.cbioportal.model.MolecularProfileCaseIdentifier; import org.cbioportal.model.MutSig; @@ -21,6 +20,7 @@ import org.cbioportal.service.SignificantCopyNumberRegionService; import org.cbioportal.service.SignificantlyMutatedGeneService; import org.cbioportal.service.exception.StudyNotFoundException; +import org.cbioportal.service.util.AlterationCountServiceUtil; import org.cbioportal.service.util.AlterationEnrichmentUtil; import org.cbioportal.web.parameter.Projection; import org.springframework.beans.factory.annotation.Autowired; @@ -51,8 +51,6 @@ public class AlterationCountServiceImpl implements AlterationCountService { private final SignificantlyMutatedGeneService significantlyMutatedGeneService; private final StudyViewRepository studyViewRepository; private final SignificantCopyNumberRegionService significantCopyNumberRegionService; - - private static final String WHOLE_EXOME_SEQUENCING = "WES"; @Autowired @@ -265,19 +263,19 @@ public Pair, Long> getPatientCnaGeneCounts(List getMutatedGenes(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { - var alterationCountByGenes = populateAlterationCounts(combineAlterationCountsWithConflictingHugoSymbols( studyViewRepository.getMutatedGenes(studyViewFilterContext)), + var alterationCountByGenes = populateAlterationCounts(AlterationCountServiceUtil.combineAlterationCountsWithConflictingHugoSymbols( studyViewRepository.getMutatedGenes(studyViewFilterContext)), studyViewFilterContext, AlterationType.MUTATION_EXTENDED); return populateAlterationCountsWithMutSigQValue(alterationCountByGenes, studyViewFilterContext); } public List getCnaGenes(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { - var copyNumberAlterationCounts = populateAlterationCounts(combineCopyNumberCountsWithConflictingHugoSymbols(studyViewRepository.getCnaGenes(studyViewFilterContext)), studyViewFilterContext, AlterationType.COPY_NUMBER_ALTERATION); + var copyNumberAlterationCounts = populateAlterationCounts(AlterationCountServiceUtil.combineCopyNumberCountsWithConflictingHugoSymbols(studyViewRepository.getCnaGenes(studyViewFilterContext)), studyViewFilterContext, AlterationType.COPY_NUMBER_ALTERATION); return populateAlterationCountsWithCNASigQValue(copyNumberAlterationCounts, studyViewFilterContext); } @Override public List getStructuralVariantGenes(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { - var alterationCountByGenes = populateAlterationCounts(combineAlterationCountsWithConflictingHugoSymbols(studyViewRepository.getStructuralVariantGenes(studyViewFilterContext)), + var alterationCountByGenes = populateAlterationCounts(AlterationCountServiceUtil.combineAlterationCountsWithConflictingHugoSymbols(studyViewRepository.getStructuralVariantGenes(studyViewFilterContext)), studyViewFilterContext, AlterationType.STRUCTURAL_VARIANT); return populateAlterationCountsWithMutSigQValue(alterationCountByGenes, studyViewFilterContext); } @@ -297,7 +295,7 @@ private < T extends AlterationCountByGene> List populateAlterationCounts(@Non Set matchingGenePanelIds = matchingGenePanelIdsMap.get(hugoGeneSymbol) != null ? matchingGenePanelIdsMap.get(hugoGeneSymbol) : Collections.emptySet(); - int alterationTotalProfiledCount = computeTotalProfiledCount(hasGenePanelData(matchingGenePanelIds), + int alterationTotalProfiledCount = AlterationCountServiceUtil.computeTotalProfiledCount(AlterationCountServiceUtil.hasGenePanelData(matchingGenePanelIds), profiledCountsMap.getOrDefault(hugoGeneSymbol, 0), sampleProfileCountWithoutGenePanelData, totalProfiledCount); @@ -308,107 +306,24 @@ private < T extends AlterationCountByGene> List populateAlterationCounts(@Non }); return alterationCounts; } - - private int computeTotalProfiledCount(boolean hasGenePanelData, int alterationsProfiledCount, int sampleProfileCountWithoutGenePanelData, int totalProfiledCount) { - int profiledCount = hasGenePanelData ? alterationsProfiledCount + sampleProfileCountWithoutGenePanelData - : sampleProfileCountWithoutGenePanelData; - return profiledCount == 0 ? totalProfiledCount : profiledCount; - } private List populateAlterationCountsWithMutSigQValue(List alterationCountByGenes, StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { final var mutSigs = getMutSigs(studyViewFilterContext); // If MutSig is not empty update Mutated Genes - if (!mutSigs.isEmpty()) { - alterationCountByGenes.parallelStream() - .filter(alterationCount -> mutSigs.containsKey(alterationCount.getHugoGeneSymbol())) - .forEach(alterationCount -> - alterationCount.setqValue(mutSigs.get(alterationCount.getHugoGeneSymbol()).getqValue()) - ); - } - return alterationCountByGenes; + return AlterationCountServiceUtil.updateAlterationCountsWithMutSigQValue(alterationCountByGenes, mutSigs); } private List populateAlterationCountsWithCNASigQValue(List alterationCountByGenes, StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { final var gisticMap = getGisticMap(studyViewFilterContext); - if(!gisticMap.isEmpty()) { - alterationCountByGenes.parallelStream() - .filter(alterationCount -> gisticMap.containsKey(Pair.create(alterationCount.getHugoGeneSymbol(), alterationCount.getAlteration()))) - .forEach(alterationCount -> { - alterationCount.setqValue(gisticMap.get(Pair.create(alterationCount.getHugoGeneSymbol(), alterationCount.getAlteration())).getqValue()); - }); - } - return alterationCountByGenes; + return AlterationCountServiceUtil.updateAlterationCountsWithCNASigQValue(alterationCountByGenes, gisticMap); } private List getFirstMolecularProfileGroupedByStudy(StudyViewFilterContext studyViewFilterContext, AlterationType alterationType) { final var molecularProfiles = studyViewRepository.getFilteredMolecularProfilesByAlterationType(studyViewFilterContext, alterationType.toString()); - return molecularProfiles.stream() - .collect(Collectors.toMap( - MolecularProfile::getCancerStudyIdentifier, - Function.identity(), - (existing, replacement) -> existing // Keep the first occurrence - )) - .values() - .stream() - .toList(); - } - - /** - * Combines alteration counts by Hugo gene symbols. If multiple entries exist for the same - * gene symbol, their number of altered cases and total counts are summed up. Returns a - * list of unique AlterationCountByGene objects where each gene symbol is represented only once. - * - * This appears in the Data where Genes have similar Hugo Gene Symbols but different Entrez Ids - * - * @param alterationCounts List of AlterationCountByGene objects, potentially with duplicate gene symbols - * @return List of AlterationCountByGene objects with unique gene symbols and combined counts - */ - private List combineAlterationCountsWithConflictingHugoSymbols(@NonNull List alterationCounts) { - Map alterationCountByGeneMap = new HashMap<>(); - for (var alterationCount : alterationCounts) { - if (alterationCountByGeneMap.containsKey(alterationCount.getHugoGeneSymbol())){ - AlterationCountByGene toUpdate = alterationCountByGeneMap.get(alterationCount.getHugoGeneSymbol()); - toUpdate.setNumberOfAlteredCases(toUpdate.getNumberOfAlteredCases() + alterationCount.getNumberOfAlteredCases()); - toUpdate.setTotalCount(toUpdate.getTotalCount() + alterationCount.getTotalCount()); - } else { - alterationCountByGeneMap.put(alterationCount.getHugoGeneSymbol(), alterationCount); - } - } - return alterationCountByGeneMap.values().stream().toList(); - } - - /** - * Combines alteration counts by Hugo gene symbols. If multiple entries exist for the same - * gene symbol, their number of altered cases and total counts are summed up. Returns a - * list of unique AlterationCountByGene objects where each gene symbol is represented only once. - * - * This appears in the Data where Genes have similar Hugo Gene Symbols but different Entrez Ids. - * This is a special case to handle Copy Number Mutations where the Alteration type should be a part of the key - * - * @param alterationCounts List of CopyNumberCountByGene objects, potentially with duplicate gene symbols - * @return List of AlterationCountByGene objects with unique gene symbols and combined counts - */ - private List combineCopyNumberCountsWithConflictingHugoSymbols(@NonNull List alterationCounts) { - Map, CopyNumberCountByGene> alterationCountByGeneMap = new HashMap<>(); - for (var alterationCount : alterationCounts) { - var copyNumberKey = Pair.create(alterationCount.getHugoGeneSymbol(), alterationCount.getAlteration()); - if (alterationCountByGeneMap.containsKey(copyNumberKey)) { - AlterationCountByGene toUpdate = alterationCountByGeneMap.get(copyNumberKey); - toUpdate.setNumberOfAlteredCases(toUpdate.getNumberOfAlteredCases() + alterationCount.getNumberOfAlteredCases()); - toUpdate.setTotalCount(toUpdate.getTotalCount() + alterationCount.getTotalCount()); - } else { - alterationCountByGeneMap.put(copyNumberKey, alterationCount); - } - } - return alterationCountByGeneMap.values().stream().toList(); - } - - private boolean hasGenePanelData(@NonNull Set matchingGenePanelIds) { - return matchingGenePanelIds.contains(WHOLE_EXOME_SEQUENCING) - && matchingGenePanelIds.size() > 1 || !matchingGenePanelIds.contains(WHOLE_EXOME_SEQUENCING) && !matchingGenePanelIds.isEmpty(); - } + return AlterationCountServiceUtil.getFirstMolecularProfileGroupedByStudy(molecularProfiles); + } private Map getMutSigs(StudyViewFilterContext studyViewFilterContext) throws StudyNotFoundException { var distinctStudyIds = studyViewRepository.getFilteredStudyIds(studyViewFilterContext); @@ -440,16 +355,7 @@ private Map, Gistic> getGisticMap(StudyViewFilterContext s null, null, null); - for(Gistic gistic : gisticList) { - var amp = (gistic.getAmp()) ? 2 : -2; - for (GisticToGene gene : gistic.getGenes()) { - var key = Pair.create(gene.getHugoGeneSymbol(), amp); - Gistic currentGistic = gisticMap.get(key); - if (currentGistic == null || gistic.getqValue().compareTo(currentGistic.getqValue()) < 0) { - gisticMap.put(key, gistic); - } - } - } + AlterationCountServiceUtil.setupGisticMap(gisticList, gisticMap); } return gisticMap; } @@ -487,26 +393,7 @@ private Pair, Long> getAlterationGeneCou Long studyProfiledCasesCount = includeFrequencyFunction.apply(studyMolecularProfileCaseIdentifiers, studyAlterationCountByGenes); profiledCasesCount.updateAndGet(v -> v + studyProfiledCasesCount); } - studyAlterationCountByGenes.forEach(datum -> { - String key = datum.getUniqueEventKey(); - if (totalResult.containsKey(key)) { - S alterationCountByGene = totalResult.get(key); - alterationCountByGene.setTotalCount(alterationCountByGene.getTotalCount() + datum.getTotalCount()); - alterationCountByGene.setNumberOfAlteredCases(alterationCountByGene.getNumberOfAlteredCases() + datum.getNumberOfAlteredCases()); - alterationCountByGene.setNumberOfProfiledCases(alterationCountByGene.getNumberOfProfiledCases() + datum.getNumberOfProfiledCases()); - Set matchingGenePanelIds = new HashSet<>(); - if (!alterationCountByGene.getMatchingGenePanelIds().isEmpty()) { - matchingGenePanelIds.addAll(alterationCountByGene.getMatchingGenePanelIds()); - } - if (!datum.getMatchingGenePanelIds().isEmpty()) { - matchingGenePanelIds.addAll(datum.getMatchingGenePanelIds()); - } - alterationCountByGene.setMatchingGenePanelIds(matchingGenePanelIds); - totalResult.put(key, alterationCountByGene); - } else { - totalResult.put(key, datum); - } - }); + AlterationCountServiceUtil.setupAlterationGeneCountsMap(studyAlterationCountByGenes, totalResult); }); alterationCountByGenes = new ArrayList<>(totalResult.values()); } diff --git a/src/main/java/org/cbioportal/service/impl/StudyViewColumnarServiceImpl.java b/src/main/java/org/cbioportal/service/impl/StudyViewColumnarServiceImpl.java index d30b77dcc4f..47c7fb87a2f 100644 --- a/src/main/java/org/cbioportal/service/impl/StudyViewColumnarServiceImpl.java +++ b/src/main/java/org/cbioportal/service/impl/StudyViewColumnarServiceImpl.java @@ -255,14 +255,7 @@ public List getMutationCountsByGeneSpecific(StudyViewFilte List genomicDataCountItemList = new ArrayList<>(); for (GenomicDataFilter genomicDataFilter : genomicDataFilters) { Map counts = studyViewRepository.getMutationCounts(createContext(studyViewFilter), genomicDataFilter); - List genomicDataCountList = new ArrayList<>(); - if (counts.getOrDefault("mutatedCount", 0) > 0) - genomicDataCountList.add(new GenomicDataCount("Mutated", "MUTATED", counts.get("mutatedCount"), counts.get("mutatedCount"))); - if (counts.getOrDefault("notMutatedCount", 0) > 0) - genomicDataCountList.add(new GenomicDataCount("Not Mutated", "NOT_MUTATED", counts.get("notMutatedCount"), counts.get("notMutatedCount"))); - if (counts.getOrDefault("notProfiledCount", 0) > 0) - genomicDataCountList.add(new GenomicDataCount("Not Profiled", "NOT_PROFILED", counts.get("notProfiledCount"), counts.get("notProfiledCount"))); - genomicDataCountItemList.add(new GenomicDataCountItem(genomicDataFilter.getHugoGeneSymbol(), "mutations", genomicDataCountList)); + genomicDataCountItemList.add(StudyViewColumnarServiceUtil.createGenomicDataCountItemFromMutationCounts(genomicDataFilter, counts)); } return genomicDataCountItemList; } diff --git a/src/main/java/org/cbioportal/service/util/AlterationCountServiceUtil.java b/src/main/java/org/cbioportal/service/util/AlterationCountServiceUtil.java new file mode 100644 index 00000000000..9f565e216fc --- /dev/null +++ b/src/main/java/org/cbioportal/service/util/AlterationCountServiceUtil.java @@ -0,0 +1,168 @@ +package org.cbioportal.service.util; + +import org.apache.commons.math3.util.Pair; +import org.cbioportal.model.AlterationCountBase; +import org.cbioportal.model.AlterationCountByGene; +import org.cbioportal.model.CopyNumberCountByGene; +import org.cbioportal.model.Gistic; +import org.cbioportal.model.GisticToGene; +import org.cbioportal.model.MolecularProfile; +import org.cbioportal.model.MutSig; +import org.springframework.lang.NonNull; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class AlterationCountServiceUtil { + + private AlterationCountServiceUtil() {} + + private static final String WHOLE_EXOME_SEQUENCING = "WES"; + + public static int computeTotalProfiledCount(boolean hasGenePanelData, int alterationsProfiledCount, int sampleProfileCountWithoutGenePanelData, int totalProfiledCount) { + int profiledCount = hasGenePanelData ? alterationsProfiledCount + sampleProfileCountWithoutGenePanelData + : sampleProfileCountWithoutGenePanelData; + return profiledCount == 0 ? totalProfiledCount : profiledCount; + } + + public static List updateAlterationCountsWithMutSigQValue( + List alterationCountByGenes, + Map mutSigs) { + + if (!mutSigs.isEmpty()) { + alterationCountByGenes.parallelStream() + .filter(alterationCount -> mutSigs.containsKey(alterationCount.getHugoGeneSymbol())) + .forEach(alterationCount -> + alterationCount.setqValue(mutSigs.get(alterationCount.getHugoGeneSymbol()).getqValue()) + ); + } + return alterationCountByGenes; + } + + public static List updateAlterationCountsWithCNASigQValue( + List alterationCountByGenes, + Map, Gistic> gisticMap) { + + if (!gisticMap.isEmpty()) { + alterationCountByGenes.parallelStream() + .filter(alterationCount -> gisticMap.containsKey(Pair.create(alterationCount.getHugoGeneSymbol(), alterationCount.getAlteration()))) + .forEach(alterationCount -> + alterationCount.setqValue(gisticMap.get(Pair.create(alterationCount.getHugoGeneSymbol(), alterationCount.getAlteration())).getqValue()) + ); + } + return alterationCountByGenes; + } + + public static List getFirstMolecularProfileGroupedByStudy(List molecularProfiles) { + return molecularProfiles.stream() + .collect(Collectors.toMap( + MolecularProfile::getCancerStudyIdentifier, + Function.identity(), + (existing, replacement) -> existing // Keep the first occurrence + )) + .values() + .stream() + .toList(); + } + + /** + * Combines alteration counts by Hugo gene symbols. If multiple entries exist for the same + * gene symbol, their number of altered cases and total counts are summed up. Returns a + * list of unique AlterationCountByGene objects where each gene symbol is represented only once. + * + * This appears in the Data where Genes have similar Hugo Gene Symbols but different Entrez Ids + * + * @param alterationCounts List of AlterationCountByGene objects, potentially with duplicate gene symbols + * @return List of AlterationCountByGene objects with unique gene symbols and combined counts + */ + public static List combineAlterationCountsWithConflictingHugoSymbols(List alterationCounts) { + Map alterationCountByGeneMap = new HashMap<>(); + for (var alterationCount : alterationCounts) { + if (alterationCountByGeneMap.containsKey(alterationCount.getHugoGeneSymbol())){ + AlterationCountByGene toUpdate = alterationCountByGeneMap.get(alterationCount.getHugoGeneSymbol()); + toUpdate.setNumberOfAlteredCases(toUpdate.getNumberOfAlteredCases() + alterationCount.getNumberOfAlteredCases()); + toUpdate.setTotalCount(toUpdate.getTotalCount() + alterationCount.getTotalCount()); + } else { + alterationCountByGeneMap.put(alterationCount.getHugoGeneSymbol(), alterationCount); + } + } + return alterationCountByGeneMap.values().stream().toList(); + } + + /** + * Combines alteration counts by Hugo gene symbols. If multiple entries exist for the same + * gene symbol, their number of altered cases and total counts are summed up. Returns a + * list of unique AlterationCountByGene objects where each gene symbol is represented only once. + * + * This appears in the Data where Genes have similar Hugo Gene Symbols but different Entrez Ids. + * This is a special case to handle Copy Number Mutations where the Alteration type should be a part of the key + * + * @param alterationCounts List of CopyNumberCountByGene objects, potentially with duplicate gene symbols + * @return List of AlterationCountByGene objects with unique gene symbols and combined counts + */ + public static List combineCopyNumberCountsWithConflictingHugoSymbols(List alterationCounts) { + Map, CopyNumberCountByGene> alterationCountByGeneMap = new HashMap<>(); + for (var alterationCount : alterationCounts) { + var copyNumberKey = Pair.create(alterationCount.getHugoGeneSymbol(), alterationCount.getAlteration()); + if (alterationCountByGeneMap.containsKey(copyNumberKey)) { + CopyNumberCountByGene toUpdate = alterationCountByGeneMap.get(copyNumberKey); + toUpdate.setNumberOfAlteredCases(toUpdate.getNumberOfAlteredCases() + alterationCount.getNumberOfAlteredCases()); + toUpdate.setTotalCount(toUpdate.getTotalCount() + alterationCount.getTotalCount()); + } else { + alterationCountByGeneMap.put(copyNumberKey, alterationCount); + } + } + return alterationCountByGeneMap.values().stream().toList(); + } + + public static boolean hasGenePanelData(@NonNull Set matchingGenePanelIds) { + return matchingGenePanelIds.contains(WHOLE_EXOME_SEQUENCING) + && matchingGenePanelIds.size() > 1 || !matchingGenePanelIds.contains(WHOLE_EXOME_SEQUENCING) && !matchingGenePanelIds.isEmpty(); + } + + public static void setupGisticMap(List gisticList, Map, Gistic> gisticMap) { + for (Gistic gistic : gisticList) { + var amp = gistic.getAmp().booleanValue() ? 2 : -2; + for (GisticToGene gene : gistic.getGenes()) { + var key = Pair.create(gene.getHugoGeneSymbol(), amp); + Gistic currentGistic = gisticMap.get(key); + if (currentGistic == null || gistic.getqValue().compareTo(currentGistic.getqValue()) < 0) { + gisticMap.put(key, gistic); + } + } + } + } + + public static void setupAlterationGeneCountsMap( + List studyAlterationCountByGenes, + Map totalResult) { + + studyAlterationCountByGenes.forEach(datum -> { + String key = datum.getUniqueEventKey(); + if (totalResult.containsKey(key)) { + S alterationCountByGene = totalResult.get(key); + alterationCountByGene.setTotalCount(alterationCountByGene.getTotalCount() + datum.getTotalCount()); + alterationCountByGene.setNumberOfAlteredCases(alterationCountByGene.getNumberOfAlteredCases() + datum.getNumberOfAlteredCases()); + alterationCountByGene.setNumberOfProfiledCases(alterationCountByGene.getNumberOfProfiledCases() + datum.getNumberOfProfiledCases()); + Set matchingGenePanelIds = new HashSet<>(); + if (!alterationCountByGene.getMatchingGenePanelIds().isEmpty()) { + matchingGenePanelIds.addAll(alterationCountByGene.getMatchingGenePanelIds()); + } + if (!datum.getMatchingGenePanelIds().isEmpty()) { + matchingGenePanelIds.addAll(datum.getMatchingGenePanelIds()); + } + alterationCountByGene.setMatchingGenePanelIds(matchingGenePanelIds); + totalResult.put(key, alterationCountByGene); + } else { + totalResult.put(key, datum); + } + }); + } + + +} \ No newline at end of file diff --git a/src/main/java/org/cbioportal/service/util/StudyViewColumnarServiceUtil.java b/src/main/java/org/cbioportal/service/util/StudyViewColumnarServiceUtil.java index 3a4bcc7c34a..981dbb80cf2 100644 --- a/src/main/java/org/cbioportal/service/util/StudyViewColumnarServiceUtil.java +++ b/src/main/java/org/cbioportal/service/util/StudyViewColumnarServiceUtil.java @@ -5,6 +5,8 @@ import org.cbioportal.model.ClinicalDataCount; import org.cbioportal.model.ClinicalDataCountItem; import org.cbioportal.model.GenomicDataCount; +import org.cbioportal.model.GenomicDataCountItem; +import org.cbioportal.web.parameter.GenomicDataFilter; import java.util.ArrayList; import java.util.Collection; @@ -15,6 +17,10 @@ public class StudyViewColumnarServiceUtil { private StudyViewColumnarServiceUtil() {} + + public static final String MUTATED_COUNT = "mutatedCount"; + public static final String NOT_MUTATED_COUNT = "notMutatedCount"; + public static final String NOT_PROFILED_COUNT = "notProfiledCount"; public static List mergeClinicalDataCounts( List items @@ -154,6 +160,17 @@ public static List normalizeDataCounts(List(normalizedDataCounts); } + + public static GenomicDataCountItem createGenomicDataCountItemFromMutationCounts(GenomicDataFilter genomicDataFilter, Map counts) { + List genomicDataCountList = new ArrayList<>(); + if (counts.getOrDefault(MUTATED_COUNT, 0) > 0) + genomicDataCountList.add(new GenomicDataCount("Mutated", "MUTATED", counts.get(MUTATED_COUNT), counts.get(MUTATED_COUNT))); + if (counts.getOrDefault(NOT_MUTATED_COUNT, 0) > 0) + genomicDataCountList.add(new GenomicDataCount("Not Mutated", "NOT_MUTATED", counts.get(NOT_MUTATED_COUNT), counts.get(NOT_MUTATED_COUNT))); + if (counts.getOrDefault(NOT_PROFILED_COUNT, 0) > 0) + genomicDataCountList.add(new GenomicDataCount("Not Profiled", "NOT_PROFILED", counts.get(NOT_PROFILED_COUNT), counts.get(NOT_PROFILED_COUNT))); + return new GenomicDataCountItem(genomicDataFilter.getHugoGeneSymbol(), "mutations", genomicDataCountList); + } } \ No newline at end of file diff --git a/src/test/java/org/cbioportal/service/util/AlterationCountServiceUtilTest.java b/src/test/java/org/cbioportal/service/util/AlterationCountServiceUtilTest.java new file mode 100644 index 00000000000..31f09303271 --- /dev/null +++ b/src/test/java/org/cbioportal/service/util/AlterationCountServiceUtilTest.java @@ -0,0 +1,418 @@ +package org.cbioportal.service.util; + +import org.apache.commons.math3.util.Pair; +import org.cbioportal.model.AlterationCountByGene; +import org.cbioportal.model.AlterationCountByStructuralVariant; +import org.cbioportal.model.CopyNumberCountByGene; +import org.cbioportal.model.Gistic; +import org.cbioportal.model.GisticToGene; +import org.cbioportal.model.MolecularProfile; +import org.cbioportal.model.MutSig; +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.*; + +public class AlterationCountServiceUtilTest { + + @Test + public void testComputeTotalProfiledCount() { + // Test with gene panel data + boolean hasGenePanelData = true; + int alterationsProfiledCount = 5; + int sampleProfileCountWithoutGenePanelData = 10; + int totalProfiledCount = 20; + + int result = AlterationCountServiceUtil.computeTotalProfiledCount( + hasGenePanelData, alterationsProfiledCount, sampleProfileCountWithoutGenePanelData, totalProfiledCount + ); + assertEquals(15, result); + + // Test without gene panel data + hasGenePanelData = false; + result = AlterationCountServiceUtil.computeTotalProfiledCount( + hasGenePanelData, alterationsProfiledCount, sampleProfileCountWithoutGenePanelData, totalProfiledCount + ); + assertEquals(10, result); + + // Test with zero profiled count + hasGenePanelData = true; + alterationsProfiledCount = 0; + sampleProfileCountWithoutGenePanelData = 0; + result = AlterationCountServiceUtil.computeTotalProfiledCount( + hasGenePanelData, alterationsProfiledCount, sampleProfileCountWithoutGenePanelData, totalProfiledCount + ); + assertEquals(20, result); + } + + + @Test + public void testUpdateAlterationCountsWithMutSigQValue() { + AlterationCountByGene count1 = new AlterationCountByGene(); + count1.setHugoGeneSymbol("hugo1"); + + AlterationCountByGene count2 = new AlterationCountByGene(); + count2.setHugoGeneSymbol("hugo2"); + + List counts = Arrays.asList(count1, count2); + + MutSig mutSig1 = new MutSig(); + mutSig1.setHugoGeneSymbol("hugo1"); + mutSig1.setqValue(BigDecimal.valueOf(0.01)); + + Map mutSigs = new HashMap<>(); + mutSigs.put("hugo1", mutSig1); + + List result = AlterationCountServiceUtil.updateAlterationCountsWithMutSigQValue(counts, mutSigs); + + assertEquals(BigDecimal.valueOf(0.01), result.get(0).getqValue()); + assertEquals(null, result.get(1).getqValue()); + } + + + @Test + public void testUpdateAlterationCountsWithCNASigQValue() { + CopyNumberCountByGene count1 = new CopyNumberCountByGene(); + count1.setHugoGeneSymbol("hugo1"); + count1.setAlteration(2); + + CopyNumberCountByGene count2 = new CopyNumberCountByGene(); + count2.setHugoGeneSymbol("hugo2"); + count2.setAlteration(-2); + + List counts = Arrays.asList(count1, count2); + + Gistic gistic1 = new Gistic(); + gistic1.setqValue(BigDecimal.valueOf(0.01)); + + Map, Gistic> gisticMap = new HashMap<>(); + gisticMap.put(Pair.create("hugo1", 2), gistic1); + + List result = AlterationCountServiceUtil.updateAlterationCountsWithCNASigQValue(counts, gisticMap); + + assertEquals(BigDecimal.valueOf(0.01), result.get(0).getqValue()); + assertEquals(null, result.get(1).getqValue()); + } + + + @Test + public void testGetFirstMolecularProfileGroupedByStudy() { + MolecularProfile profile1 = new MolecularProfile(); + profile1.setCancerStudyIdentifier("study1"); + profile1.setMolecularProfileId(1); + + MolecularProfile profile2 = new MolecularProfile(); + profile2.setCancerStudyIdentifier("study1"); + profile2.setMolecularProfileId(2); + + MolecularProfile profile3 = new MolecularProfile(); + profile3.setCancerStudyIdentifier("study2"); + profile3.setMolecularProfileId(3); + + List profiles = Arrays.asList(profile1, profile2, profile3); + + List result = AlterationCountServiceUtil.getFirstMolecularProfileGroupedByStudy(profiles); + + assertEquals(2, result.size()); + + MolecularProfile resultProfile1 = result.stream() + .filter(profile -> profile.getCancerStudyIdentifier().equals("study1")) + .findFirst() + .orElse(null); + assertEquals(Integer.valueOf(1), resultProfile1.getMolecularProfileId()); + + MolecularProfile resultProfile2 = result.stream() + .filter(profile -> profile.getCancerStudyIdentifier().equals("study2")) + .findFirst() + .orElse(null); + assertEquals(Integer.valueOf(3), resultProfile2.getMolecularProfileId()); + } + + + @Test + public void testCombineAlterationCountsWithConflictingHugoSymbols() { + AlterationCountByGene count1 = new AlterationCountByGene(); + count1.setHugoGeneSymbol("hugo1"); + count1.setNumberOfAlteredCases(5); + count1.setTotalCount(10); + + AlterationCountByGene count2 = new AlterationCountByGene(); + count2.setHugoGeneSymbol("hugo1"); + count2.setNumberOfAlteredCases(3); + count2.setTotalCount(6); + + AlterationCountByGene count3 = new AlterationCountByGene(); + count3.setHugoGeneSymbol("hugo2"); + count3.setNumberOfAlteredCases(2); + count3.setTotalCount(4); + + List counts = Arrays.asList(count1, count2, count3); + + List combinedCounts = AlterationCountServiceUtil.combineAlterationCountsWithConflictingHugoSymbols(counts); + + assertEquals(2, combinedCounts.size()); + + AlterationCountByGene combinedCount1 = combinedCounts.stream() + .filter(count -> count.getHugoGeneSymbol().equals("hugo1")) + .findFirst() + .orElse(null); + assertEquals(8, combinedCount1.getNumberOfAlteredCases().intValue()); + assertEquals(16, combinedCount1.getTotalCount().intValue()); + + AlterationCountByGene combinedCount2 = combinedCounts.stream() + .filter(count -> count.getHugoGeneSymbol().equals("hugo2")) + .findFirst() + .orElse(null); + assertEquals(2, combinedCount2.getNumberOfAlteredCases().intValue()); + assertEquals(4, combinedCount2.getTotalCount().intValue()); + } + + + @Test + public void testCombineCopyNumberCountsWithConflictingHugoSymbols() { + CopyNumberCountByGene count1 = new CopyNumberCountByGene(); + count1.setHugoGeneSymbol("hugo1"); + count1.setAlteration(1); + count1.setNumberOfAlteredCases(5); + count1.setTotalCount(10); + + CopyNumberCountByGene count2 = new CopyNumberCountByGene(); + count2.setHugoGeneSymbol("hugo1"); + count2.setAlteration(1); + count2.setNumberOfAlteredCases(3); + count2.setTotalCount(6); + + CopyNumberCountByGene count3 = new CopyNumberCountByGene(); + count3.setHugoGeneSymbol("hugo2"); + count3.setAlteration(2); + count3.setNumberOfAlteredCases(2); + count3.setTotalCount(4); + + List counts = Arrays.asList(count1, count2, count3); + + List result = AlterationCountServiceUtil.combineCopyNumberCountsWithConflictingHugoSymbols(counts); + + assertEquals(2, result.size()); + + CopyNumberCountByGene combinedCount1 = result.stream().filter(c -> c.getHugoGeneSymbol().equals("hugo1")).findFirst().orElse(null); + assertEquals(8, combinedCount1.getNumberOfAlteredCases().intValue()); + assertEquals(16, combinedCount1.getTotalCount().intValue()); + + CopyNumberCountByGene combinedCount2 = result.stream().filter(c -> c.getHugoGeneSymbol().equals("hugo2")).findFirst().orElse(null); + assertEquals(2, combinedCount2.getNumberOfAlteredCases().intValue()); + assertEquals(4, combinedCount2.getTotalCount().intValue()); + } + + + @Test + public void testHasGenePanelData() { + // Test with Whole Exome Sequencing and other panels + Set genePanelIds1 = Set.of("WES", "panel1"); + assertTrue(AlterationCountServiceUtil.hasGenePanelData(genePanelIds1)); + + // Test with only Whole Exome Sequencing + Set genePanelIds2 = Set.of("WES"); + assertFalse(AlterationCountServiceUtil.hasGenePanelData(genePanelIds2)); + + // Test with other panels + Set genePanelIds3 = Set.of("panel1", "panel2"); + assertTrue(AlterationCountServiceUtil.hasGenePanelData(genePanelIds3)); + + // Test with empty set + Set genePanelIds4 = Set.of(); + assertFalse(AlterationCountServiceUtil.hasGenePanelData(genePanelIds4)); + } + + + @Test + public void testSetupGisticMap() { + // Single Gistic with amplification + Gistic gistic1 = new Gistic(); + gistic1.setAmp(true); + gistic1.setqValue(BigDecimal.valueOf(0.01)); + GisticToGene gene1 = new GisticToGene(); + gene1.setHugoGeneSymbol("hugo1"); + gistic1.setGenes(List.of(gene1)); + + // Single Gistic without amplification + Gistic gistic2 = new Gistic(); + gistic2.setAmp(false); + gistic2.setqValue(BigDecimal.valueOf(0.02)); + GisticToGene gene2 = new GisticToGene(); + gene2.setHugoGeneSymbol("hugo2"); + gistic2.setGenes(List.of(gene2)); + + // Multiple Gistics for the same gene with different qValues + Gistic gistic3 = new Gistic(); + gistic3.setAmp(true); + gistic3.setqValue(BigDecimal.valueOf(0.03)); + GisticToGene gene3 = new GisticToGene(); + gene3.setHugoGeneSymbol("hugo1"); + gistic3.setGenes(List.of(gene3)); + + List gisticList = List.of(gistic1, gistic2, gistic3); + Map, Gistic> gisticMap = new HashMap<>(); + + AlterationCountServiceUtil.setupGisticMap(gisticList, gisticMap); + + assertEquals(2, gisticMap.size()); + assertTrue(gisticMap.containsKey(Pair.create("hugo1", 2))); + assertTrue(gisticMap.containsKey(Pair.create("hugo2", -2))); + assertEquals(gistic1, gisticMap.get(Pair.create("hugo1", 2))); // gistic1 should be chosen over gistic3 due to lower qValue + assertEquals(gistic2, gisticMap.get(Pair.create("hugo2", -2))); + } + + + @Test + public void testSetupAlterationGeneCountsMapWithAlterationCountByGene() { + AlterationCountByGene datum1 = new AlterationCountByGene(); + datum1.setHugoGeneSymbol("hugo1"); + datum1.setTotalCount(1); + datum1.setNumberOfAlteredCases(1); + datum1.setNumberOfProfiledCases(1); + datum1.setMatchingGenePanelIds(new HashSet<>(Arrays.asList("panel1"))); + + AlterationCountByGene datum2 = new AlterationCountByGene(); + datum2.setHugoGeneSymbol("hugo1"); + datum2.setTotalCount(2); + datum2.setNumberOfAlteredCases(2); + datum2.setNumberOfProfiledCases(2); + datum2.setMatchingGenePanelIds(new HashSet<>(Arrays.asList("panel2"))); + + AlterationCountByGene datum3 = new AlterationCountByGene(); + datum3.setHugoGeneSymbol("hugo2"); + datum3.setTotalCount(3); + datum3.setNumberOfAlteredCases(3); + datum3.setNumberOfProfiledCases(3); + datum3.setMatchingGenePanelIds(new HashSet<>(Arrays.asList("panel3"))); + + List studyAlterationCountByGenes = Arrays.asList(datum1, datum2, datum3); + Map totalResult = new HashMap<>(); + + AlterationCountServiceUtil.setupAlterationGeneCountsMap(studyAlterationCountByGenes, totalResult); + + assertEquals(2, totalResult.size()); + assertTrue(totalResult.containsKey("hugo1")); + assertTrue(totalResult.containsKey("hugo2")); + + AlterationCountByGene result1 = totalResult.get("hugo1"); + assertEquals(3L, (long) result1.getTotalCount()); + assertEquals(3L, (long) result1.getNumberOfAlteredCases()); + assertEquals(3L, (long) result1.getNumberOfProfiledCases()); + assertTrue(result1.getMatchingGenePanelIds().contains("panel1")); + assertTrue(result1.getMatchingGenePanelIds().contains("panel2")); + + AlterationCountByGene result2 = totalResult.get("hugo2"); + assertEquals(3L, (long) result2.getTotalCount()); + assertEquals(3L, (long) result2.getNumberOfAlteredCases()); + assertEquals(3L, (long) result2.getNumberOfProfiledCases()); + assertTrue(result2.getMatchingGenePanelIds().contains("panel3")); + } + + @Test + public void testSetupAlterationGeneCountsMapWithAlterationCountByStructuralVariant() { + AlterationCountByStructuralVariant datum1 = new AlterationCountByStructuralVariant(); + datum1.setGene1HugoGeneSymbol("hugo1"); + datum1.setGene2HugoGeneSymbol("hugo2"); + datum1.setTotalCount(1); + datum1.setNumberOfAlteredCases(1); + datum1.setNumberOfProfiledCases(1); + datum1.setMatchingGenePanelIds(new HashSet<>(Arrays.asList("panel1"))); + + AlterationCountByStructuralVariant datum2 = new AlterationCountByStructuralVariant(); + datum2.setGene1HugoGeneSymbol("hugo1"); + datum2.setGene2HugoGeneSymbol("hugo2"); + datum2.setTotalCount(2); + datum2.setNumberOfAlteredCases(2); + datum2.setNumberOfProfiledCases(2); + datum2.setMatchingGenePanelIds(new HashSet<>(Arrays.asList("panel2"))); + + AlterationCountByStructuralVariant datum3 = new AlterationCountByStructuralVariant(); + datum3.setGene1HugoGeneSymbol("hugo3"); + datum3.setGene2HugoGeneSymbol("hugo4"); + datum3.setTotalCount(3); + datum3.setNumberOfAlteredCases(3); + datum3.setNumberOfProfiledCases(3); + datum3.setMatchingGenePanelIds(new HashSet<>(Arrays.asList("panel3"))); + + List studyAlterationCountByGenes = Arrays.asList(datum1, datum2, datum3); + Map totalResult = new HashMap<>(); + + AlterationCountServiceUtil.setupAlterationGeneCountsMap(studyAlterationCountByGenes, totalResult); + + assertEquals(2, totalResult.size()); + assertTrue(totalResult.containsKey("hugo1::hugo2")); + assertTrue(totalResult.containsKey("hugo3::hugo4")); + + AlterationCountByStructuralVariant result1 = totalResult.get("hugo1::hugo2"); + assertEquals(3L, (long) result1.getTotalCount()); + assertEquals(3L, (long) result1.getNumberOfAlteredCases()); + assertEquals(3L, (long) result1.getNumberOfProfiledCases()); + assertTrue(result1.getMatchingGenePanelIds().contains("panel1")); + assertTrue(result1.getMatchingGenePanelIds().contains("panel2")); + + AlterationCountByStructuralVariant result2 = totalResult.get("hugo3::hugo4"); + assertEquals(3L, (long) result2.getTotalCount()); + assertEquals(3L, (long) result2.getNumberOfAlteredCases()); + assertEquals(3L, (long) result2.getNumberOfProfiledCases()); + assertTrue(result2.getMatchingGenePanelIds().contains("panel3")); + } + + @Test + public void testSetupAlterationGeneCountsMapWithCopyNumberCountByGene() { + CopyNumberCountByGene datum1 = new CopyNumberCountByGene(); + datum1.setEntrezGeneId(1); + datum1.setAlteration(2); + datum1.setTotalCount(1); + datum1.setNumberOfAlteredCases(1); + datum1.setNumberOfProfiledCases(1); + datum1.setMatchingGenePanelIds(new HashSet<>(Arrays.asList("panel1"))); + + CopyNumberCountByGene datum2 = new CopyNumberCountByGene(); + datum2.setEntrezGeneId(1); + datum2.setAlteration(2); + datum2.setTotalCount(2); + datum2.setNumberOfAlteredCases(2); + datum2.setNumberOfProfiledCases(2); + datum2.setMatchingGenePanelIds(new HashSet<>(Arrays.asList("panel2"))); + + CopyNumberCountByGene datum3 = new CopyNumberCountByGene(); + datum3.setEntrezGeneId(2); + datum3.setAlteration(-2); + datum3.setTotalCount(3); + datum3.setNumberOfAlteredCases(3); + datum3.setNumberOfProfiledCases(3); + datum3.setMatchingGenePanelIds(new HashSet<>(Arrays.asList("panel3"))); + + List studyAlterationCountByGenes = Arrays.asList(datum1, datum2, datum3); + Map totalResult = new HashMap<>(); + + AlterationCountServiceUtil.setupAlterationGeneCountsMap(studyAlterationCountByGenes, totalResult); + + assertEquals(2, totalResult.size()); + assertTrue(totalResult.containsKey("12")); + assertTrue(totalResult.containsKey("2-2")); + + CopyNumberCountByGene result1 = totalResult.get("12"); + assertEquals(3L, (long) result1.getTotalCount()); + assertEquals(3L, (long) result1.getNumberOfAlteredCases()); + assertEquals(3L, (long) result1.getNumberOfProfiledCases()); + assertTrue(result1.getMatchingGenePanelIds().contains("panel1")); + assertTrue(result1.getMatchingGenePanelIds().contains("panel2")); + + CopyNumberCountByGene result2 = totalResult.get("2-2"); + assertEquals(3L, (long) result2.getTotalCount()); + assertEquals(3L, (long) result2.getNumberOfAlteredCases()); + assertEquals(3L, (long) result2.getNumberOfProfiledCases()); + assertTrue(result2.getMatchingGenePanelIds().contains("panel3")); + } + + +} \ No newline at end of file diff --git a/src/test/java/org/cbioportal/service/util/StudyViewColumnarServiceUtilTest.java b/src/test/java/org/cbioportal/service/util/StudyViewColumnarServiceUtilTest.java index 58308717c01..0c9687d6e59 100644 --- a/src/test/java/org/cbioportal/service/util/StudyViewColumnarServiceUtilTest.java +++ b/src/test/java/org/cbioportal/service/util/StudyViewColumnarServiceUtilTest.java @@ -5,12 +5,15 @@ import org.cbioportal.model.ClinicalDataCount; import org.cbioportal.model.ClinicalDataCountItem; import org.cbioportal.model.GenomicDataCount; +import org.cbioportal.model.GenomicDataCountItem; +import org.cbioportal.web.parameter.GenomicDataFilter; import org.junit.Assert; import org.junit.Test; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Optional; import static org.junit.Assert.*; @@ -263,6 +266,81 @@ public void testNormalizeDataCounts() { .orElse(null); assertEquals(9, falseCount.getCount().intValue()); } + + + @Test + public void testCreateGenomicDataCountItemFromMutationCounts() { + GenomicDataFilter genomicDataFilter = new GenomicDataFilter(); + genomicDataFilter.setHugoGeneSymbol("hugo1"); + + Map counts1 = Map.of( + "mutatedCount", 5, + "notMutatedCount", 10, + "notProfiledCount", 15 + ); + + GenomicDataCountItem item1 = StudyViewColumnarServiceUtil.createGenomicDataCountItemFromMutationCounts(genomicDataFilter, counts1); + + assertEquals("hugo1", item1.getHugoGeneSymbol()); + assertEquals("mutations", item1.getProfileType()); + + assertEquals(3, item1.getCounts().size()); + + GenomicDataCount mutatedCount1 = item1.getCounts().stream() + .filter(count -> count.getValue().equals("MUTATED")) + .findFirst() + .orElse(null); + assertNotNull(mutatedCount1); + assertEquals(5, mutatedCount1.getCount().intValue()); + + GenomicDataCount notMutatedCount1 = item1.getCounts().stream() + .filter(count -> count.getValue().equals("NOT_MUTATED")) + .findFirst() + .orElse(null); + assertNotNull(notMutatedCount1); + assertEquals(10, notMutatedCount1.getCount().intValue()); + + GenomicDataCount notProfiledCount1 = item1.getCounts().stream() + .filter(count -> count.getValue().equals("NOT_PROFILED")) + .findFirst() + .orElse(null); + assertNotNull(notProfiledCount1); + assertEquals(15, notProfiledCount1.getCount().intValue()); + + // Test case where a count equals 0 + Map counts2 = Map.of( + "mutatedCount", 5, + "notMutatedCount", 0, + "notProfiledCount", 5 + ); + + GenomicDataCountItem item2 = StudyViewColumnarServiceUtil.createGenomicDataCountItemFromMutationCounts(genomicDataFilter, counts2); + + assertEquals("hugo1", item2.getHugoGeneSymbol()); + assertEquals("mutations", item2.getProfileType()); + + assertEquals(2, item2.getCounts().size()); + + GenomicDataCount mutatedCount2 = item2.getCounts().stream() + .filter(count -> count.getValue().equals("MUTATED")) + .findFirst() + .orElse(null); + assertNotNull(mutatedCount2); + assertEquals(5, mutatedCount2.getCount().intValue()); + + GenomicDataCount notMutatedCount2 = item2.getCounts().stream() + .filter(count -> count.getValue().equals("NOT_MUTATED")) + .findFirst() + .orElse(null); + assertNull(notMutatedCount2); + + GenomicDataCount notProfiledCount2 = item2.getCounts().stream() + .filter(count -> count.getValue().equals("NOT_PROFILED")) + .findFirst() + .orElse(null); + assertNotNull(notProfiledCount2); + assertEquals(5, notProfiledCount2.getCount().intValue()); + } } \ No newline at end of file