diff --git a/model/src/main/java/org/cbioportal/model/GenericAssayBinaryEnrichment.java b/model/src/main/java/org/cbioportal/model/GenericAssayBinaryEnrichment.java new file mode 100644 index 00000000000..f7ccbc7c3b5 --- /dev/null +++ b/model/src/main/java/org/cbioportal/model/GenericAssayBinaryEnrichment.java @@ -0,0 +1,19 @@ +package org.cbioportal.model; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.List; + +public class GenericAssayBinaryEnrichment extends GenericAssayEnrichment { + @NotNull + private List counts; + + public List getCounts() { + return counts; + } + + public void setCounts(List counts) { + this.counts = counts; + } + +} diff --git a/model/src/main/java/org/cbioportal/model/GenericAssayCategoricalEnrichment.java b/model/src/main/java/org/cbioportal/model/GenericAssayCategoricalEnrichment.java new file mode 100644 index 00000000000..2fdb661cf38 --- /dev/null +++ b/model/src/main/java/org/cbioportal/model/GenericAssayCategoricalEnrichment.java @@ -0,0 +1,18 @@ +package org.cbioportal.model; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; + +public class GenericAssayCategoricalEnrichment extends GenericAssayEnrichment { + @NotNull + private BigDecimal qValue; + + public BigDecimal getqValue() { + return qValue; + } + + public void setqValue(BigDecimal qValue) { + this.qValue = qValue; + } + +} diff --git a/model/src/main/java/org/cbioportal/model/GenericAssayCountSummary.java b/model/src/main/java/org/cbioportal/model/GenericAssayCountSummary.java new file mode 100644 index 00000000000..2f24ed760ba --- /dev/null +++ b/model/src/main/java/org/cbioportal/model/GenericAssayCountSummary.java @@ -0,0 +1,38 @@ +package org.cbioportal.model; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +public class GenericAssayCountSummary implements Serializable { + + @NotNull + private String name; + @NotNull + private Integer count; + @NotNull + private Integer totalCount; + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getTotalCount() { + return totalCount; + } + + public void setTotalCount(Integer totalCount) { + this.totalCount = totalCount; + } +} diff --git a/model/src/main/java/org/cbioportal/model/GenericAssayEnrichment.java b/model/src/main/java/org/cbioportal/model/GenericAssayEnrichment.java index 8278694f9be..02491c2221b 100644 --- a/model/src/main/java/org/cbioportal/model/GenericAssayEnrichment.java +++ b/model/src/main/java/org/cbioportal/model/GenericAssayEnrichment.java @@ -1,6 +1,7 @@ package org.cbioportal.model; import java.io.Serializable; +import java.math.BigDecimal; import java.util.HashMap; import javax.validation.constraints.NotNull; @@ -11,6 +12,8 @@ public class GenericAssayEnrichment extends ExpressionEnrichment implements Seri private String stableId; @NotNull private String name; + @NotNull + private BigDecimal qValue; @NotNull private HashMap genericEntityMetaProperties; @@ -37,5 +40,16 @@ public HashMap getGenericEntityMetaProperties() { public void setGenericEntityMetaProperties(HashMap genericEntityMetaProperties) { this.genericEntityMetaProperties = genericEntityMetaProperties; } - + + public BigDecimal getqValue() { + return qValue; + } + + public void setqValue(BigDecimal qValue) { + this.qValue = qValue; + } + + public static int compare(GenericAssayEnrichment c1, GenericAssayEnrichment c2) { + return c1.getpValue().compareTo(c2.getpValue()); + } } diff --git a/service/src/main/java/org/cbioportal/service/ExpressionEnrichmentService.java b/service/src/main/java/org/cbioportal/service/ExpressionEnrichmentService.java index ae602d46b35..d3c2a444bd8 100644 --- a/service/src/main/java/org/cbioportal/service/ExpressionEnrichmentService.java +++ b/service/src/main/java/org/cbioportal/service/ExpressionEnrichmentService.java @@ -7,6 +7,8 @@ import org.cbioportal.model.GenericAssayEnrichment; import org.cbioportal.model.GenomicEnrichment; import org.cbioportal.model.MolecularProfileCaseIdentifier; +import org.cbioportal.model.GenericAssayBinaryEnrichment; +import org.cbioportal.model.GenericAssayCategoricalEnrichment; import org.cbioportal.service.exception.MolecularProfileNotFoundException; public interface ExpressionEnrichmentService { @@ -15,8 +17,18 @@ List getGenomicEnrichments(String molecularProfileId, Map> molecularProfileCaseSets, EnrichmentType enrichmentType) throws MolecularProfileNotFoundException; - List getGenericAssayEnrichments(String molecularProfileId, + List getGenericAssayNumericalEnrichments(String molecularProfileId, Map> molecularProfileCaseSets, EnrichmentType enrichmentType) throws MolecularProfileNotFoundException; + List getGenericAssayBinaryEnrichments( + String molecularProfileId, + Map> molecularProfileCaseSets, + EnrichmentType enrichmentType) + throws MolecularProfileNotFoundException; + + List getGenericAssayCategoricalEnrichments(String molecularProfileId, + Map> molecularProfileCaseSets, + EnrichmentType enrichmentType) + throws MolecularProfileNotFoundException; } diff --git a/service/src/main/java/org/cbioportal/service/impl/ExpressionEnrichmentServiceImpl.java b/service/src/main/java/org/cbioportal/service/impl/ExpressionEnrichmentServiceImpl.java index fb8fe8ef62a..45eb9ae478e 100644 --- a/service/src/main/java/org/cbioportal/service/impl/ExpressionEnrichmentServiceImpl.java +++ b/service/src/main/java/org/cbioportal/service/impl/ExpressionEnrichmentServiceImpl.java @@ -1,20 +1,23 @@ package org.cbioportal.service.impl; +import java.math.BigDecimal; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.lang3.BooleanUtils; +import org.cbioportal.model.MolecularProfile.MolecularAlterationType; +import org.cbioportal.model.meta.GenericAssayMeta; import org.cbioportal.model.EnrichmentType; -import org.cbioportal.model.Gene; -import org.cbioportal.model.GeneMolecularAlteration; -import org.cbioportal.model.GenericAssayEnrichment; +import org.cbioportal.model.GenericAssayBinaryEnrichment; +import org.cbioportal.model.GenericAssayCategoricalEnrichment; import org.cbioportal.model.GenericAssayMolecularAlteration; -import org.cbioportal.model.GenomicEnrichment; -import org.cbioportal.model.MolecularProfile; -import org.cbioportal.model.MolecularProfile.MolecularAlterationType; import org.cbioportal.model.MolecularProfileCaseIdentifier; +import org.cbioportal.model.MolecularProfile; import org.cbioportal.model.Sample; -import org.cbioportal.model.meta.GenericAssayMeta; +import org.cbioportal.model.GenericAssayEnrichment; +import org.cbioportal.model.GenomicEnrichment; +import org.cbioportal.model.Gene; +import org.cbioportal.model.GeneMolecularAlteration; import org.cbioportal.persistence.MolecularDataRepository; import org.cbioportal.service.ExpressionEnrichmentService; import org.cbioportal.service.GeneService; @@ -23,6 +26,7 @@ import org.cbioportal.service.SampleService; import org.cbioportal.service.exception.MolecularProfileNotFoundException; import org.cbioportal.service.util.ExpressionEnrichmentUtil; +import org.cbioportal.service.util.FisherExactTestCalculator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -42,68 +46,56 @@ public class ExpressionEnrichmentServiceImpl implements ExpressionEnrichmentServ private GenericAssayService genericAssayService; @Autowired private SampleService sampleService; - + @Autowired + private FisherExactTestCalculator fisherExactTestCalculator = new FisherExactTestCalculator(); @Override // transaction needs to be setup here in order to return Iterable from // molecularDataService in fetchCoExpressions @Transactional(readOnly = true) public List getGenomicEnrichments(String molecularProfileId, - Map> molecularProfileCaseSets, EnrichmentType enrichmentType) - throws MolecularProfileNotFoundException { - + Map> molecularProfileCaseSets, EnrichmentType enrichmentType) + throws MolecularProfileNotFoundException { MolecularProfile molecularProfile = molecularProfileService.getMolecularProfile(molecularProfileId); - List validGenomicMolecularAlterationTypes = Arrays.asList( - MolecularAlterationType.MICRO_RNA_EXPRESSION, MolecularAlterationType.MRNA_EXPRESSION, - MolecularAlterationType.MRNA_EXPRESSION_NORMALS, MolecularAlterationType.RNA_EXPRESSION, - MolecularAlterationType.METHYLATION, MolecularAlterationType.METHYLATION_BINARY, - MolecularAlterationType.PHOSPHORYLATION, MolecularAlterationType.PROTEIN_LEVEL, - MolecularAlterationType.PROTEIN_ARRAY_PROTEIN_LEVEL, - MolecularAlterationType.PROTEIN_ARRAY_PHOSPHORYLATION); - + MolecularAlterationType.MICRO_RNA_EXPRESSION, MolecularAlterationType.MRNA_EXPRESSION, + MolecularAlterationType.MRNA_EXPRESSION_NORMALS, MolecularAlterationType.RNA_EXPRESSION, + MolecularAlterationType.METHYLATION, MolecularAlterationType.METHYLATION_BINARY, + MolecularAlterationType.PHOSPHORYLATION, MolecularAlterationType.PROTEIN_LEVEL, + MolecularAlterationType.PROTEIN_ARRAY_PROTEIN_LEVEL, + MolecularAlterationType.PROTEIN_ARRAY_PHOSPHORYLATION); validateMolecularProfile(molecularProfile, validGenomicMolecularAlterationTypes); - Iterable maItr = molecularDataRepository - .getGeneMolecularAlterationsIterableFast(molecularProfile.getStableId()); - + .getGeneMolecularAlterationsIterableFast(molecularProfile.getStableId()); List expressionEnrichments = expressionEnrichmentUtil.getEnrichments(molecularProfile, - molecularProfileCaseSets, enrichmentType, maItr); - + molecularProfileCaseSets, enrichmentType, maItr); List entrezGeneIds = expressionEnrichments.stream().map(GenomicEnrichment::getEntrezGeneId) - .collect(Collectors.toList()); - + .collect(Collectors.toList()); Map> geneMapByEntrezId = geneService - .fetchGenes(entrezGeneIds.stream().map(Object::toString).collect(Collectors.toList()), "ENTREZ_GENE_ID", - "SUMMARY") - .stream().collect(Collectors.groupingBy(Gene::getEntrezGeneId)); - + .fetchGenes(entrezGeneIds.stream().map(Object::toString).collect(Collectors.toList()), "ENTREZ_GENE_ID", + "SUMMARY") + .stream().collect(Collectors.groupingBy(Gene::getEntrezGeneId)); return expressionEnrichments.stream() - // filter Enrichments having no gene reference object(this - // happens when multiple - // entrez ids map to same hugo gene symbol) - .filter(expressionEnrichment -> geneMapByEntrezId.containsKey(expressionEnrichment.getEntrezGeneId())) - .map(expressionEnrichment -> { - Gene gene = geneMapByEntrezId.get(expressionEnrichment.getEntrezGeneId()).get(0); - expressionEnrichment.setHugoGeneSymbol(gene.getHugoGeneSymbol()); - return expressionEnrichment; - }).collect(Collectors.toList()); + // filter Enrichments having no gene reference object(this + // happens when multiple + // entrez ids map to same hugo gene symbol) + .filter(expressionEnrichment -> geneMapByEntrezId.containsKey(expressionEnrichment.getEntrezGeneId())) + .map(expressionEnrichment -> { + Gene gene = geneMapByEntrezId.get(expressionEnrichment.getEntrezGeneId()).get(0); + expressionEnrichment.setHugoGeneSymbol(gene.getHugoGeneSymbol()); + return expressionEnrichment; + }).collect(Collectors.toList()); } - @Override // transaction needs to be setup here in order to return Iterable from // molecularDataRepository in getGenericAssayMolecularAlterationsIterable @Transactional(readOnly = true) - public List getGenericAssayEnrichments(String molecularProfileId, - Map> molecularProfileCaseSets, EnrichmentType enrichmentType) - throws MolecularProfileNotFoundException { - + public List getGenericAssayNumericalEnrichments(String molecularProfileId, + Map> molecularProfileCaseSets, EnrichmentType enrichmentType) + throws MolecularProfileNotFoundException { MolecularProfile molecularProfile = molecularProfileService.getMolecularProfile(molecularProfileId); - validateMolecularProfile(molecularProfile, Arrays.asList(MolecularAlterationType.GENERIC_ASSAY)); - Iterable maItr = molecularDataRepository - .getGenericAssayMolecularAlterationsIterable(molecularProfile.getStableId(), null, "SUMMARY"); - + .getGenericAssayMolecularAlterationsIterable(molecularProfile.getStableId(), null, "SUMMARY"); Map> filteredMolecularProfileCaseSets; if (BooleanUtils.isTrue(molecularProfile.getPatientLevel())) { // Build sampleIdToPatientIdMap to quick find if a sample has shared patientId with other samples @@ -125,31 +117,159 @@ public List getGenericAssayEnrichments(String molecularP filteredMolecularProfileCaseSets.put(pair.getKey(), identifierListUniqueByPatientId); } } else { - filteredMolecularProfileCaseSets = molecularProfileCaseSets; + filteredMolecularProfileCaseSets = molecularProfileCaseSets; } List genericAssayEnrichments = expressionEnrichmentUtil.getEnrichments(molecularProfile, - filteredMolecularProfileCaseSets, enrichmentType, maItr); + filteredMolecularProfileCaseSets, enrichmentType, maItr); List getGenericAssayStableIds = genericAssayEnrichments.stream() - .map(GenericAssayEnrichment::getStableId).collect(Collectors.toList()); + .map(GenericAssayEnrichment::getStableId).collect(Collectors.toList()); Map genericAssayMetaByStableId = genericAssayService - .getGenericAssayMetaByStableIdsAndMolecularIds(getGenericAssayStableIds, - getGenericAssayStableIds.stream().map(stableId -> molecularProfileId) - .collect(Collectors.toList()), - "SUMMARY") - .stream().collect(Collectors.toMap(GenericAssayMeta::getStableId, Function.identity())); + .getGenericAssayMetaByStableIdsAndMolecularIds(getGenericAssayStableIds, + getGenericAssayStableIds.stream().map(stableId -> molecularProfileId) + .collect(Collectors.toList()), + "SUMMARY") + .stream().collect(Collectors.toMap(GenericAssayMeta::getStableId, Function.identity())); return genericAssayEnrichments.stream().map(enrichmentDatum -> { enrichmentDatum.setGenericEntityMetaProperties( - genericAssayMetaByStableId.get(enrichmentDatum.getStableId()).getGenericEntityMetaProperties()); + genericAssayMetaByStableId.get(enrichmentDatum.getStableId()).getGenericEntityMetaProperties()); return enrichmentDatum; }).collect(Collectors.toList()); } + @Override + @Transactional(readOnly = true) + public List getGenericAssayBinaryEnrichments( + String molecularProfileId, + Map> molecularProfileCaseSets, EnrichmentType enrichmentType) + throws MolecularProfileNotFoundException { + + // Validate and fetch molecular profile + MolecularProfile molecularProfile = getAndValidateMolecularProfile(molecularProfileId, "BINARY"); + + // Get the molecular alterations for the provided profile + Iterable maItr = molecularDataRepository + .getGenericAssayMolecularAlterationsIterable(molecularProfile.getStableId(), null, "SUMMARY"); + + // Filter the case sets based on molecular profile + Map> filteredMolecularProfileCaseSets = filterMolecularProfileCaseSets(molecularProfile, molecularProfileCaseSets); + + // Obtain binary enrichments from the utility + List genericAssayBinaryEnrichments = expressionEnrichmentUtil.getGenericAssayBinaryEnrichments(molecularProfile, + filteredMolecularProfileCaseSets, enrichmentType, maItr); + + // Calculate q-values for enrichments + calcQValues(genericAssayBinaryEnrichments); + + // Extract stable IDs from binary enrichments + List getGenericAssayStableIds = genericAssayBinaryEnrichments.stream() + .map(GenericAssayEnrichment::getStableId).collect(Collectors.toList()); + + // Fetch metadata of generic assays by their stable IDs + Map genericAssayMetaByStableId = getGenericAssayMetaByStableId(getGenericAssayStableIds, molecularProfileId); + + // Assign meta properties to each enrichment + return genericAssayBinaryEnrichments.stream().map(enrichmentDatum -> { + enrichmentDatum.setGenericEntityMetaProperties( + genericAssayMetaByStableId.get(enrichmentDatum.getStableId()).getGenericEntityMetaProperties()); + return enrichmentDatum; + }).collect(Collectors.toList()); + } + + @Override + @Transactional(readOnly = true) + public List getGenericAssayCategoricalEnrichments(String molecularProfileId, + Map> molecularProfileCaseSets, EnrichmentType enrichmentType) + throws MolecularProfileNotFoundException { + + MolecularProfile molecularProfile = getAndValidateMolecularProfile(molecularProfileId, "CATEGORICAL"); + + Iterable maItr = molecularDataRepository + .getGenericAssayMolecularAlterationsIterable(molecularProfile.getStableId(), null, "SUMMARY"); + + Map> filteredMolecularProfileCaseSets = filterMolecularProfileCaseSets(molecularProfile, molecularProfileCaseSets); + + List genericAssayCategoricalEnrichments = expressionEnrichmentUtil.getGenericAssayCategoricalEnrichments(molecularProfile, + filteredMolecularProfileCaseSets, enrichmentType, maItr); + + calcQValues(genericAssayCategoricalEnrichments); + + List getGenericAssayStableIds = genericAssayCategoricalEnrichments.stream() + .map(GenericAssayEnrichment::getStableId).collect(Collectors.toList()); + Map genericAssayMetaByStableId = getGenericAssayMetaByStableId(getGenericAssayStableIds, molecularProfileId); + + return genericAssayCategoricalEnrichments.stream().map(enrichmentDatum -> { + enrichmentDatum.setGenericEntityMetaProperties( + genericAssayMetaByStableId.get(enrichmentDatum.getStableId()).getGenericEntityMetaProperties()); + return enrichmentDatum; + }).collect(Collectors.toList()); + } + + private MolecularProfile getAndValidateMolecularProfile(String molecularProfileId, String dataType) throws MolecularProfileNotFoundException { + MolecularProfile molecularProfile = molecularProfileService.getMolecularProfile(molecularProfileId); + validateMolecularProfile(molecularProfile, Arrays.asList(MolecularProfile.MolecularAlterationType.GENERIC_ASSAY), dataType); + return molecularProfile; + } private void validateMolecularProfile(MolecularProfile molecularProfile, - List validMolecularAlterationTypes) throws MolecularProfileNotFoundException { + List validMolecularAlterationTypes, + String dataType) throws MolecularProfileNotFoundException { if (!validMolecularAlterationTypes.contains(molecularProfile.getMolecularAlterationType())) { + // Check alteration type throw new MolecularProfileNotFoundException(molecularProfile.getStableId()); } + // Check datatype for binary or categorical + if(molecularProfile.getMolecularAlterationType().equals(MolecularProfile.MolecularAlterationType.GENERIC_ASSAY) && + !molecularProfile.getDatatype().equals(dataType)) + throw new MolecularProfileNotFoundException(molecularProfile.getStableId()); + } + + private Map> filterMolecularProfileCaseSets(MolecularProfile molecularProfile, Map> molecularProfileCaseSets) { + if (BooleanUtils.isTrue(molecularProfile.getPatientLevel())) { + // If patient level, filter duplicates by patient id + // For now we only support sample level for samples + List sampleIds = molecularProfileCaseSets.values().stream().flatMap(Collection::stream).map(MolecularProfileCaseIdentifier::getCaseId).collect(Collectors.toList()); + List studyIds = Collections.nCopies(sampleIds.size(), molecularProfile.getCancerStudyIdentifier()); + List samples = sampleService.fetchSamples(studyIds, sampleIds, "ID"); + Map sampleIdToPatientIdMap = samples.stream().collect(Collectors.toMap(Sample::getStableId, Sample::getPatientId)); + + Map> filteredMolecularProfileCaseSets = new HashMap<>(); + for (Map.Entry> pair : molecularProfileCaseSets.entrySet()) { + Set patientSet = new HashSet(); + List identifierListUniqueByPatientId = new ArrayList<>(); + for (MolecularProfileCaseIdentifier caseIdentifier : pair.getValue()) { + if (!patientSet.contains(sampleIdToPatientIdMap.get(caseIdentifier.getCaseId()))) { + identifierListUniqueByPatientId.add(caseIdentifier); + patientSet.add(sampleIdToPatientIdMap.get(caseIdentifier.getCaseId())); + } + } + filteredMolecularProfileCaseSets.put(pair.getKey(), identifierListUniqueByPatientId); + } + return filteredMolecularProfileCaseSets; + } else { + return molecularProfileCaseSets; + } + } + + private Map getGenericAssayMetaByStableId(List stableIds, String molecularProfileId) { + return genericAssayService.getGenericAssayMetaByStableIdsAndMolecularIds(stableIds, stableIds.stream().map(sid -> molecularProfileId) + .collect(Collectors.toList()), "SUMMARY").stream() + .collect(Collectors.toMap(GenericAssayMeta::getStableId, Function.identity())); } + private void calcQValues(List enrichments) { + // Sort enrichments by pValue + Collections.sort(enrichments, GenericAssayEnrichment::compare); + BigDecimal[] pValues = enrichments.stream().map(T::getpValue).toArray(BigDecimal[]::new); + BigDecimal[] qValues = fisherExactTestCalculator.calcqValue(pValues); + // Assign q-values to enrichments + for (int i = 0; i < enrichments.size(); i++) { + enrichments.get(i).setqValue(qValues[i]); + } + } + private void validateMolecularProfile(MolecularProfile molecularProfile, + List validMolecularAlterationTypes) throws MolecularProfileNotFoundException { + if (!validMolecularAlterationTypes.contains(molecularProfile.getMolecularAlterationType())) { + throw new MolecularProfileNotFoundException(molecularProfile.getStableId()); + } + } } diff --git a/service/src/main/java/org/cbioportal/service/util/ExpressionEnrichmentUtil.java b/service/src/main/java/org/cbioportal/service/util/ExpressionEnrichmentUtil.java index a147e0065fc..79c4ace75a7 100644 --- a/service/src/main/java/org/cbioportal/service/util/ExpressionEnrichmentUtil.java +++ b/service/src/main/java/org/cbioportal/service/util/ExpressionEnrichmentUtil.java @@ -3,29 +3,36 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; +import java.util.HashMap; import java.util.Map; +import java.util.Set; +import java.util.List; import java.util.Map.Entry; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; -import org.apache.commons.lang3.math.NumberUtils; -import org.apache.commons.math3.stat.StatUtils; -import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; -import org.apache.commons.math3.stat.inference.OneWayAnova; -import org.apache.commons.math3.stat.inference.TestUtils; import org.cbioportal.model.EnrichmentType; import org.cbioportal.model.ExpressionEnrichment; import org.cbioportal.model.GenericAssayEnrichment; +import org.cbioportal.model.GenericAssayBinaryEnrichment; +import org.cbioportal.model.GenericAssayCategoricalEnrichment; import org.cbioportal.model.GenericAssayMolecularAlteration; import org.cbioportal.model.GenomicEnrichment; import org.cbioportal.model.GroupStatistics; +import org.cbioportal.model.GenericAssayCountSummary; import org.cbioportal.model.MolecularAlteration; import org.cbioportal.model.MolecularProfile; import org.cbioportal.model.MolecularProfileCaseIdentifier; import org.cbioportal.model.MolecularProfileSamples; import org.cbioportal.model.Sample; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.commons.math3.stat.StatUtils; +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; +import org.apache.commons.math3.stat.inference.ChiSquareTest; +import org.apache.commons.math3.stat.inference.OneWayAnova; +import org.apache.commons.math3.stat.inference.TestUtils; import org.cbioportal.persistence.MolecularDataRepository; import org.cbioportal.service.SampleService; import org.springframework.beans.factory.annotation.Autowired; @@ -34,199 +41,368 @@ @Component public class ExpressionEnrichmentUtil { - @Autowired - private SampleService sampleService; - @Autowired - private MolecularDataRepository molecularDataRepository; - - private static final double LOG2 = Math.log(2); - private static final String RNA_SEQ = "rna_seq"; - - public List getEnrichments( - MolecularProfile molecularProfile, - Map> molecularProfileCaseSets, EnrichmentType enrichmentType, - Iterable maItr) { - List expressionEnrichments = new ArrayList<>(); - - Map> groupIndicesMap = getGroupIndicesMap(molecularProfileCaseSets, enrichmentType, - molecularProfile); - for (MolecularAlteration ma : maItr) { - - List groupsStatistics = new ArrayList(); - // used for p-value calculation - List groupedValues = new ArrayList(); - - for (Entry> group : groupIndicesMap.entrySet()) { - - // get expression values to all the indices in the group - List molecularDataValues = group.getValue().stream() - .map(sampleIndex -> ma.getSplitValues()[sampleIndex]) - .filter(a -> NumberUtils.isNumber(a)) - .collect(Collectors.toList()); - - // ignore group if there are less than 2 values - if (molecularDataValues.size() < 2) { - continue; - } - - double[] values = getAlterationValues(molecularDataValues, molecularProfile.getStableId()); - - GroupStatistics groupStatistics = new GroupStatistics(); - double alteredMean = StatUtils.mean(values); - double alteredStandardDeviation = calculateStandardDeviation(values); - - // ignore if mean or standard deviation are not numbers - if (Double.isNaN(alteredMean) || Double.isNaN(alteredStandardDeviation)) { - continue; - } - - groupedValues.add(values); - groupStatistics.setName(group.getKey()); - groupStatistics.setMeanExpression(BigDecimal.valueOf(alteredMean)); - groupStatistics.setStandardDeviation(BigDecimal.valueOf(alteredStandardDeviation)); - groupsStatistics.add(groupStatistics); - } - - // calculate p-value and add enrichment if atleast 2 groups have data - if (groupsStatistics.size() > 1) { - double pValue = calculatePValue(groupedValues); - if (Double.isNaN(pValue)) { - continue; - } - S expressionEnrichment = null; - if (ma instanceof GenericAssayMolecularAlteration) { - GenericAssayEnrichment genericAssayEnrichment = new GenericAssayEnrichment(); - genericAssayEnrichment.setStableId(ma.getStableId()); - expressionEnrichment = (S) genericAssayEnrichment; - } else { - GenomicEnrichment genomicEnrichment = new GenomicEnrichment(); - genomicEnrichment.setEntrezGeneId(Integer.valueOf(ma.getStableId())); - expressionEnrichment = (S) genomicEnrichment; - } - expressionEnrichment.setpValue(BigDecimal.valueOf(pValue)); - expressionEnrichment.setGroupsStatistics(groupsStatistics); - expressionEnrichments.add(expressionEnrichment); - } - } - return expressionEnrichments; - } - - private double[] getAlterationValues(List molecularDataValues, String molecularProfileId) { - - if (molecularProfileId.contains(RNA_SEQ)) { - return molecularDataValues.stream().mapToDouble(d -> { - double datum = Double.parseDouble(d); - // reset to 0 if there are any negative values and then do log1p - return Math.log1p(datum < 0 ? 0 : datum) / LOG2; - }).toArray(); - } else { - return molecularDataValues.stream().mapToDouble(g -> Double.parseDouble(g)).toArray(); - } - } - - private double calculatePValue(List alteredValues) { - - if (alteredValues.size() == 2) { - return TestUtils.tTest(alteredValues.get(0), alteredValues.get(1)); - } else { - // calculate Anova statisitcs if there are more than 2 groups - OneWayAnova oneWayAnova = new OneWayAnova(); - return oneWayAnova.anovaPValue(alteredValues); - } - } - - private double calculateStandardDeviation(double[] values) { - - DescriptiveStatistics descriptiveStatistics = new DescriptiveStatistics(); - for (double value : values) { - descriptiveStatistics.addValue(value); - } - return descriptiveStatistics.getStandardDeviation(); - } - - /** - * - * This method maps valid samples in molecularProfileCaseSets to indices in - * genetic_alteration.VALUES column. Recall this column of the - * genetic_alteration table is a comma separated list of scalar values. Each - * value in this list is associated with a sample at the same position found in - * the genetic_profile_samples.ORDERED_SAMPLE_LIST column. - * - * @param molecularProfileCaseSets - * @param enrichmentType - * @param molecularProfile - * @return - */ - private Map> getGroupIndicesMap( - Map> molecularProfileCaseSets, EnrichmentType enrichmentType, - MolecularProfile molecularProfile) { - - MolecularProfileSamples commaSeparatedSampleIdsOfMolecularProfile = molecularDataRepository - .getCommaSeparatedSampleIdsOfMolecularProfile(molecularProfile.getStableId()); - - List internalSampleIds = Arrays.stream(commaSeparatedSampleIdsOfMolecularProfile.getSplitSampleIds()) - .mapToInt(Integer::parseInt).boxed().collect(Collectors.toList()); - - Map internalSampleIdToIndexMap = IntStream.range(0, internalSampleIds.size()).boxed() - .collect(Collectors.toMap(internalSampleIds::get, Function.identity())); - - Map> selectedCaseIdToInternalIdsMap = getCaseIdToInternalIdsMap(molecularProfileCaseSets, - enrichmentType, molecularProfile); - - // this block map caseIds(sampleIds or patientids) to sampleIndices which - // represents the position fount in the - // genetic_profile_samples.ORDERED_SAMPLE_LIST column - Map> groupIndicesMap = molecularProfileCaseSets.entrySet().stream() - .collect(Collectors.toMap(entity -> entity.getKey(), entity -> { - List sampleIndices = new ArrayList<>(); - entity.getValue().forEach(molecularProfileCaseIdentifier -> { - // consider only valid samples - if (selectedCaseIdToInternalIdsMap.containsKey(molecularProfileCaseIdentifier.getCaseId())) { - List sampleInternalIds = selectedCaseIdToInternalIdsMap - .get(molecularProfileCaseIdentifier.getCaseId()); - - // only consider samples which are profiled for the give molecular profile id - sampleInternalIds.forEach(sampleInternalId -> { - if (internalSampleIdToIndexMap.containsKey(sampleInternalId)) { - sampleIndices.add(internalSampleIdToIndexMap.get(sampleInternalId)); - } - }); - } - }); - return sampleIndices; - })); - return groupIndicesMap; - } - - private Map> getCaseIdToInternalIdsMap( - Map> molecularProfileCaseSets, EnrichmentType enrichmentType, - MolecularProfile molecularProfile) { - - if (enrichmentType.equals(EnrichmentType.PATIENT)) { - List patientIds = molecularProfileCaseSets.values().stream() - .flatMap(molecularProfileCaseSet -> molecularProfileCaseSet.stream() - .map(MolecularProfileCaseIdentifier::getCaseId)) - .collect(Collectors.toList()); - - List samples = sampleService - .getAllSamplesOfPatientsInStudy(molecularProfile.getCancerStudyIdentifier(), patientIds, "SUMMARY"); - - return samples.stream().collect(Collectors.groupingBy(Sample::getPatientStableId, - Collectors.mapping(Sample::getInternalId, Collectors.toList()))); - } else { - List sampleIds = new ArrayList<>(); - List studyIds = new ArrayList<>(); - - molecularProfileCaseSets.values().forEach(molecularProfileCaseIdentifiers -> { - molecularProfileCaseIdentifiers.forEach(molecularProfileCaseIdentifier -> { - sampleIds.add(molecularProfileCaseIdentifier.getCaseId()); - studyIds.add(molecularProfile.getCancerStudyIdentifier()); - }); - }); - List samples = sampleService.fetchSamples(studyIds, sampleIds, "ID"); - - return samples.stream() - .collect(Collectors.toMap(Sample::getStableId, x -> Arrays.asList(x.getInternalId()))); - } - } -} + @Autowired + private SampleService sampleService; + @Autowired + private MolecularDataRepository molecularDataRepository; + + private static final double LOG2 = Math.log(2); + private static final String RNA_SEQ = "rna_seq"; + private static final String POS = "true"; + private static final String NEG = "false"; + private static final String ALTERED = "1"; + private static final String UNALTERED = "0"; + public List getEnrichments( + MolecularProfile molecularProfile, + Map> molecularProfileCaseSets, EnrichmentType enrichmentType, + Iterable maItr) { + List expressionEnrichments = new ArrayList<>(); + + Map> groupIndicesMap = getGroupIndicesMap(molecularProfileCaseSets, enrichmentType, + molecularProfile); + for (MolecularAlteration ma : maItr) { + List groupsStatistics = new ArrayList(); + // used for p-value calculation + List groupedValues = new ArrayList(); + + for (Entry> group : groupIndicesMap.entrySet()) { + + // get expression values to all the indices in the group + List molecularDataValues = group.getValue().stream() + .map(sampleIndex -> ma.getSplitValues()[sampleIndex]) + .filter(a -> NumberUtils.isNumber(a)) + .collect(Collectors.toList()); + + // ignore group if there are less than 2 values + if (molecularDataValues.size() < 2) { + continue; + } + + double[] values = getAlterationValues(molecularDataValues, molecularProfile.getStableId()); + + GroupStatistics groupStatistics = new GroupStatistics(); + double alteredMean = StatUtils.mean(values); + double alteredStandardDeviation = calculateStandardDeviation(values); + + // ignore if mean or standard deviation are not numbers + if (Double.isNaN(alteredMean) || Double.isNaN(alteredStandardDeviation)) { + continue; + } + + groupedValues.add(values); + groupStatistics.setName(group.getKey()); + groupStatistics.setMeanExpression(BigDecimal.valueOf(alteredMean)); + groupStatistics.setStandardDeviation(BigDecimal.valueOf(alteredStandardDeviation)); + groupsStatistics.add(groupStatistics); + } + + // calculate p-value and add enrichment if atleast 2 groups have data + if (groupsStatistics.size() > 1) { + double pValue = calculatePValue(groupedValues); + if (Double.isNaN(pValue)) { + continue; + } + S expressionEnrichment = null; + if (ma instanceof GenericAssayMolecularAlteration) { + GenericAssayEnrichment genericAssayEnrichment = new GenericAssayEnrichment(); + genericAssayEnrichment.setStableId(ma.getStableId()); + expressionEnrichment = (S) genericAssayEnrichment; + } else { + GenomicEnrichment genomicEnrichment = new GenomicEnrichment(); + genomicEnrichment.setEntrezGeneId(Integer.valueOf(ma.getStableId())); + expressionEnrichment = (S) genomicEnrichment; + } + expressionEnrichment.setpValue(BigDecimal.valueOf(pValue)); + expressionEnrichment.setGroupsStatistics(groupsStatistics); + expressionEnrichments.add(expressionEnrichment); + } + } + return expressionEnrichments; + } + + public List getGenericAssayCategoricalEnrichments( + MolecularProfile molecularProfile, + Map> molecularProfileCaseSets, EnrichmentType enrichmentType, + Iterable maItr) { + + List expressionEnrichments = new ArrayList<>(); + Map> groupCategoryStatistics = new HashMap<>(); + Map> groupIndicesMap = getGroupIndicesMap(molecularProfileCaseSets, enrichmentType, + molecularProfile); + + for (MolecularAlteration ma : maItr) { + List groupsStatistics = new ArrayList(); + for (Entry> group : groupIndicesMap.entrySet()) { + // Get the corresponding split values for the group + List groupValues = group.getValue().stream() + .map(sampleIndex -> ma.getSplitValues()[sampleIndex]) + .collect(Collectors.toList()); + // Group and count the split values + Map groupedSplitValues = groupValues.stream() + .collect(Collectors.toMap(Function.identity(), v -> 1, Integer::sum)); + + // ignore group if there are less than 2 values + if (groupValues.size() < 2) { + continue; + } + + GroupStatistics groupStatistics = new GroupStatistics(); + groupStatistics.setName(group.getKey()); + groupsStatistics.add(groupStatistics); + groupCategoryStatistics.put(group.getKey(), groupedSplitValues); + } + + // calculate p-value and add enrichment if atleast 2 groups have data + + if (groupsStatistics.size() > 1) { + long[][] array = getCategoricalValues(groupCategoryStatistics); + double pValue; + if(array[0].length <= 1) { + pValue = 1; + } else { + ChiSquareTest chiSquareTest = new ChiSquareTest(); + pValue = chiSquareTest.chiSquareTest(array); + } + + // set p-value to 1 when the cases in all groups are altered + if (Double.isNaN(pValue)) { + pValue = 1; + } + + S expressionEnrichment = null; + GenericAssayCategoricalEnrichment genericAssayCategoricalEnrichment = new GenericAssayCategoricalEnrichment(); + genericAssayCategoricalEnrichment.setStableId(ma.getStableId()); + expressionEnrichment = (S) genericAssayCategoricalEnrichment; + + expressionEnrichment.setpValue(BigDecimal.valueOf(pValue)); + expressionEnrichment.setGroupsStatistics(groupsStatistics); + expressionEnrichments.add(expressionEnrichment); + } + } + return expressionEnrichments; + } + + public List getGenericAssayBinaryEnrichments( + MolecularProfile molecularProfile, + Map> molecularProfileCaseSets, EnrichmentType enrichmentType, + Iterable maItr) { + List expressionEnrichments = new ArrayList<>(); + + Map> groupIndicesMap = getGroupIndicesMap(molecularProfileCaseSets, enrichmentType, + molecularProfile); + + for (MolecularAlteration ma : maItr) { + List genericAssayCountSummaries = new ArrayList<>(); + List groupsStatistics = new ArrayList(); + // used for p-value calculation + List groupedValues = new ArrayList(); + + for (Entry> group : groupIndicesMap.entrySet()) { + GenericAssayCountSummary genericAssayCountSummary = new GenericAssayCountSummary(); + genericAssayCountSummary.setName(group.getKey()); + + // get expression values to all the indices in the group, filter NA and map binary values + List molecularDataValues = group.getValue().stream() + .map(sampleIndex -> ma.getSplitValues()[sampleIndex]) + .filter(StringUtils::isNotEmpty) + .map(a -> a.equals(POS) ? ALTERED : UNALTERED) + .collect(Collectors.toList()); + + // ignore group if there are less than 2 values + if (molecularDataValues.size() < 2) { + continue; + } + genericAssayCountSummary.setTotalCount(molecularDataValues.size()); + + double[] values = getAlterationValues(molecularDataValues, molecularProfile.getStableId()); + genericAssayCountSummary.setCount((int) Arrays.stream(values) + .filter(num -> num == 1) + .count()); + GroupStatistics groupStatistics = new GroupStatistics(); + double alteredMean = StatUtils.mean(values); + double alteredStandardDeviation = calculateStandardDeviation(values); + + // ignore if mean or standard deviation are not numbers + if (Double.isNaN(alteredMean) || Double.isNaN(alteredStandardDeviation)) { + continue; + } + + groupedValues.add(values); + groupStatistics.setName(group.getKey()); + groupStatistics.setMeanExpression(BigDecimal.valueOf(alteredMean)); + groupStatistics.setStandardDeviation(BigDecimal.valueOf(alteredStandardDeviation)); + groupsStatistics.add(groupStatistics); + genericAssayCountSummaries.add(genericAssayCountSummary); + } + + // calculate p-value and add enrichment if atleast 2 groups have data + if (groupsStatistics.size() > 1) { + + double pValue = calculatePValue(groupedValues); + if (Double.isNaN(pValue)) { + continue; + } + S expressionEnrichment = null; + GenericAssayBinaryEnrichment genericAssayBinaryEnrichment = new GenericAssayBinaryEnrichment(); + genericAssayBinaryEnrichment.setStableId(ma.getStableId()); + genericAssayBinaryEnrichment.setCounts(genericAssayCountSummaries); + expressionEnrichment = (S) genericAssayBinaryEnrichment; + + expressionEnrichment.setpValue(BigDecimal.valueOf(pValue)); + expressionEnrichment.setGroupsStatistics(groupsStatistics); + expressionEnrichments.add(expressionEnrichment); + } + } + return expressionEnrichments; + } + + private double[] getAlterationValues(List molecularDataValues, String molecularProfileId) { + + if (molecularProfileId.contains(RNA_SEQ)) { + return molecularDataValues.stream().mapToDouble(d -> { + double datum = Double.parseDouble(d); + // reset to 0 if there are any negative values and then do log1p + return Math.log1p(datum < 0 ? 0 : datum) / LOG2; + }).toArray(); + } else { + return molecularDataValues.stream().mapToDouble(g -> Double.parseDouble(g)).toArray(); + } + } + + private long[][] getCategoricalValues(Map> groupCategoryStatistics) { + // Determine the number of rows and columns + int numRows = groupCategoryStatistics.size(); + Set allCategories = groupCategoryStatistics.values().stream() + .flatMap(innerMap -> innerMap.keySet().stream()) + .collect(Collectors.toSet()); + int numCols = allCategories.size(); + + // Create the 2-dimensional long array + long[][] array = new long[numRows][numCols]; + + // Iterate over the outer map (group -> categories) + List groupKeys = new ArrayList<>(groupCategoryStatistics.keySet()); + for (int row = 0; row < numRows; row++) { + String groupKey = groupKeys.get(row); + Map innerMap = groupCategoryStatistics.get(groupKey); + + // Iterate over all categories + List categoryKeys = new ArrayList<>(allCategories); + for (int col = 0; col < numCols; col++) { + String categoryKey = categoryKeys.get(col); + + // Get the count from the inner map, or set as zero if the category doesn't exist + int count = innerMap.getOrDefault(categoryKey, 0); + array[row][col] = count; + } + } + return array; + } + + private double calculatePValue(List alteredValues) { + + if (alteredValues.size() == 2) { + return TestUtils.tTest(alteredValues.get(0), alteredValues.get(1)); + } else { + // calculate Anova statisitcs if there are more than 2 groups + OneWayAnova oneWayAnova = new OneWayAnova(); + return oneWayAnova.anovaPValue(alteredValues); + } + } + + private double calculateStandardDeviation(double[] values) { + + DescriptiveStatistics descriptiveStatistics = new DescriptiveStatistics(); + for (double value : values) { + descriptiveStatistics.addValue(value); + } + return descriptiveStatistics.getStandardDeviation(); + } + + /** + * + * This method maps valid samples in molecularProfileCaseSets to indices in + * genetic_alteration.VALUES column. Recall this column of the + * genetic_alteration table is a comma separated list of scalar values. Each + * value in this list is associated with a sample at the same position found in + * the genetic_profile_samples.ORDERED_SAMPLE_LIST column. + * + * @param molecularProfileCaseSets + * @param enrichmentType + * @param molecularProfile + * @return + */ + private Map> getGroupIndicesMap( + Map> molecularProfileCaseSets, EnrichmentType enrichmentType, + MolecularProfile molecularProfile) { + + MolecularProfileSamples commaSeparatedSampleIdsOfMolecularProfile = molecularDataRepository + .getCommaSeparatedSampleIdsOfMolecularProfile(molecularProfile.getStableId()); + + List internalSampleIds = Arrays.stream(commaSeparatedSampleIdsOfMolecularProfile.getSplitSampleIds()) + .mapToInt(Integer::parseInt).boxed().collect(Collectors.toList()); + + Map internalSampleIdToIndexMap = IntStream.range(0, internalSampleIds.size()).boxed() + .collect(Collectors.toMap(internalSampleIds::get, Function.identity())); + + Map> selectedCaseIdToInternalIdsMap = getCaseIdToInternalIdsMap(molecularProfileCaseSets, + enrichmentType, molecularProfile); + + // this block map caseIds(sampleIds or patientids) to sampleIndices which + // represents the position fount in the + // genetic_profile_samples.ORDERED_SAMPLE_LIST column + Map> groupIndicesMap = molecularProfileCaseSets.entrySet().stream() + .collect(Collectors.toMap(entity -> entity.getKey(), entity -> { + List sampleIndices = new ArrayList<>(); + entity.getValue().forEach(molecularProfileCaseIdentifier -> { + // consider only valid samples + if (selectedCaseIdToInternalIdsMap.containsKey(molecularProfileCaseIdentifier.getCaseId())) { + List sampleInternalIds = selectedCaseIdToInternalIdsMap + .get(molecularProfileCaseIdentifier.getCaseId()); + + // only consider samples which are profiled for the give molecular profile id + sampleInternalIds.forEach(sampleInternalId -> { + if (internalSampleIdToIndexMap.containsKey(sampleInternalId)) { + sampleIndices.add(internalSampleIdToIndexMap.get(sampleInternalId)); + } + }); + } + }); + return sampleIndices; + })); + return groupIndicesMap; + } + + private Map> getCaseIdToInternalIdsMap( + Map> molecularProfileCaseSets, EnrichmentType enrichmentType, + MolecularProfile molecularProfile) { + + if (enrichmentType.equals(EnrichmentType.PATIENT)) { + List patientIds = molecularProfileCaseSets.values().stream() + .flatMap(molecularProfileCaseSet -> molecularProfileCaseSet.stream() + .map(MolecularProfileCaseIdentifier::getCaseId)) + .collect(Collectors.toList()); + + List samples = sampleService + .getAllSamplesOfPatientsInStudy(molecularProfile.getCancerStudyIdentifier(), patientIds, "SUMMARY"); + + return samples.stream().collect(Collectors.groupingBy(Sample::getPatientStableId, + Collectors.mapping(Sample::getInternalId, Collectors.toList()))); + } else { + List sampleIds = new ArrayList<>(); + List studyIds = new ArrayList<>(); + + molecularProfileCaseSets.values().forEach(molecularProfileCaseIdentifiers -> { + molecularProfileCaseIdentifiers.forEach(molecularProfileCaseIdentifier -> { + sampleIds.add(molecularProfileCaseIdentifier.getCaseId()); + studyIds.add(molecularProfile.getCancerStudyIdentifier()); + }); + }); + List samples = sampleService.fetchSamples(studyIds, sampleIds, "ID"); + + return samples.stream() + .collect(Collectors.toMap(Sample::getStableId, x -> Arrays.asList(x.getInternalId()))); + } + } + +} \ No newline at end of file diff --git a/service/src/main/java/org/cbioportal/service/util/FisherExactTestCalculator.java b/service/src/main/java/org/cbioportal/service/util/FisherExactTestCalculator.java index ed94cad2b5b..150fb370178 100644 --- a/service/src/main/java/org/cbioportal/service/util/FisherExactTestCalculator.java +++ b/service/src/main/java/org/cbioportal/service/util/FisherExactTestCalculator.java @@ -2,6 +2,8 @@ import org.springframework.stereotype.Component; +import java.math.BigDecimal; + @Component public class FisherExactTestCalculator { @@ -40,9 +42,9 @@ public double getCumulativePValue(int a, int b, int c, int d) { } return p; } - + public double getTwoTailedPValue(int a, int b, int c, int d) { - + int min, i; int n = a + b + c + d; double p = 0; @@ -60,10 +62,10 @@ public double getTwoTailedPValue(int a, int b, int c, int d) { // frequencies, of obtaining exactly the frequencies observed and any configuration more extreme. // By "more extreme," we mean any configuration (given observed marginals) with a smaller probability of // occurrence in the same direction (one-tailed) or in both directions (two-tailed). - + int initialA = a, initialB = b, initialC = c, initialD = d; p += baseP; - + min = (c < b) ? c : b; for (i = 0; i < min; i++) { double tempP = getPValue(++a, --b, --c, ++d, f); @@ -77,7 +79,7 @@ public double getTwoTailedPValue(int a, int b, int c, int d) { b = initialB; c = initialC; d = initialD; - + min = (a < d) ? a : d; for (i = 0; i < min; i++) { double pTemp = getPValue(--a, ++b, ++c, --d, f); @@ -87,4 +89,36 @@ public double getTwoTailedPValue(int a, int b, int c, int d) { } return p; } + public BigDecimal[] calcqValue(BigDecimal[] pValuesInIncreasingOrder) { + BigDecimal cachedElement = BigDecimal.valueOf(0.0); + int dataLength = pValuesInIncreasingOrder.length; + BigDecimal[] reversedQValues = new BigDecimal[dataLength]; + + reverseValues(dataLength, pValuesInIncreasingOrder); + + for (int i = 0; i < dataLength; i++) { + if (i > 0) { + BigDecimal calculatedValue = cachedElement.min( + (pValuesInIncreasingOrder[i].multiply(new BigDecimal(dataLength))).divide(new BigDecimal(dataLength - i), BigDecimal.ROUND_HALF_UP) + ); + cachedElement = calculatedValue; + reversedQValues[i] = calculatedValue; + } else { + cachedElement = pValuesInIncreasingOrder[i]; + reversedQValues[i] = pValuesInIncreasingOrder[i]; + } + } + + reverseValues(dataLength, reversedQValues); + + return reversedQValues; + } + + private void reverseValues(int dataLength, BigDecimal[] reversedQValues) { + for (int i = 0; i < dataLength / 2; i++) { + BigDecimal temp = reversedQValues[i]; + reversedQValues[i] = reversedQValues[dataLength - i - 1]; + reversedQValues[dataLength - i - 1] = temp; + } + } } diff --git a/service/src/test/java/org/cbioportal/service/impl/ExpressionEnrichmentServiceImplTest.java b/service/src/test/java/org/cbioportal/service/impl/ExpressionEnrichmentServiceImplTest.java index e4d1da579cf..a777176e26a 100644 --- a/service/src/test/java/org/cbioportal/service/impl/ExpressionEnrichmentServiceImplTest.java +++ b/service/src/test/java/org/cbioportal/service/impl/ExpressionEnrichmentServiceImplTest.java @@ -207,7 +207,7 @@ public void getGenomicEnrichments() throws Exception { } @Test - public void getGenericAssayEnrichments() throws Exception { + public void getGenericAssayNumericalEnrichments() throws Exception { geneMolecularProfile.setMolecularAlterationType(MolecularProfile.MolecularAlterationType.GENERIC_ASSAY); List molecularDataList = new ArrayList(); @@ -229,7 +229,7 @@ public void getGenericAssayEnrichments() throws Exception { .thenReturn(Arrays.asList(new GenericAssayMeta(HUGO_GENE_SYMBOL_1), new GenericAssayMeta(HUGO_GENE_SYMBOL_2))); - List result = enrichmentServiceImpl.getGenericAssayEnrichments(MOLECULAR_PROFILE_ID, + List result = enrichmentServiceImpl.getGenericAssayNumericalEnrichments(MOLECULAR_PROFILE_ID, molecularProfileCaseSets, EnrichmentType.SAMPLE); Assert.assertEquals(2, result.size()); @@ -301,7 +301,7 @@ public void getGenericAssayPatientLevelEnrichments() throws Exception { Mockito.when(sampleService.fetchSamples(Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID, STUDY_ID, STUDY_ID), Arrays.asList(SAMPLE_ID3, SAMPLE_ID4, SAMPLE_ID5, SAMPLE_ID1, SAMPLE_ID2), "ID")).thenReturn(samples); - List result = enrichmentServiceImpl.getGenericAssayEnrichments(MOLECULAR_PROFILE_ID, molecularProfilePatientLevelCaseSets, EnrichmentType.SAMPLE); + List result = enrichmentServiceImpl.getGenericAssayNumericalEnrichments(MOLECULAR_PROFILE_ID, molecularProfilePatientLevelCaseSets, EnrichmentType.SAMPLE); Assert.assertEquals(2, result.size()); GenericAssayEnrichment genericAssayEnrichment = result.get(0); diff --git a/service/src/test/java/org/cbioportal/service/impl/GenericAssayEnrichmentServiceImplTest.java b/service/src/test/java/org/cbioportal/service/impl/GenericAssayEnrichmentServiceImplTest.java new file mode 100644 index 00000000000..017a5ab005f --- /dev/null +++ b/service/src/test/java/org/cbioportal/service/impl/GenericAssayEnrichmentServiceImplTest.java @@ -0,0 +1,272 @@ +package org.cbioportal.service.impl; + +import org.cbioportal.model.meta.GenericAssayMeta; +import org.cbioportal.model.EnrichmentType; +import org.cbioportal.model.MolecularProfileCaseIdentifier; +import org.cbioportal.model.MolecularProfile; +import org.cbioportal.model.MolecularProfileSamples; +import org.cbioportal.model.CancerStudy; +import org.cbioportal.model.ReferenceGenome; +import org.cbioportal.model.Sample; +import org.cbioportal.model.GenericAssayMolecularAlteration; +import org.cbioportal.model.GenericAssayBinaryEnrichment; +import org.cbioportal.model.GenericAssayCategoricalEnrichment; +import org.cbioportal.model.GroupStatistics; + +import org.cbioportal.persistence.MolecularDataRepository; +import org.cbioportal.service.GenericAssayService; +import org.cbioportal.service.MolecularProfileService; +import org.cbioportal.service.SampleService; +import org.cbioportal.service.exception.MolecularProfileNotFoundException; +import org.cbioportal.service.util.ExpressionEnrichmentUtil; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; + +import java.math.BigDecimal; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + + +@RunWith(MockitoJUnitRunner.class) +public class GenericAssayEnrichmentServiceImplTest extends BaseServiceImplTest{ + @InjectMocks + private ExpressionEnrichmentServiceImpl expressionEnrichmentServiceImpl; + @Mock + private SampleService sampleService; + @Mock + private MolecularProfileService molecularProfileService; + @Mock + private MolecularDataRepository molecularDataRepository; + + @Mock + private GenericAssayService genericAssayService; + + @Spy + @InjectMocks + private ExpressionEnrichmentUtil expressionEnrichmentUtil; + + CancerStudy cancerStudy = new CancerStudy(); + MolecularProfile geneMolecularProfile = new MolecularProfile(); + MolecularProfileSamples molecularProfileSamples = new MolecularProfileSamples(); + List samples = new ArrayList<>(); + Map> molecularProfileCaseSets = new HashMap<>(); + Map> molecularProfilePatientLevelCaseSets = new HashMap<>(); + // patient level only data + public static final String SAMPLE_ID5 = "sample_id5"; + + + @Before + public void setup() throws MolecularProfileNotFoundException { + cancerStudy.setReferenceGenome(ReferenceGenome.HOMO_SAPIENS_DEFAULT_GENOME_NAME); + cancerStudy.setCancerStudyIdentifier(STUDY_ID); + + geneMolecularProfile.setCancerStudyIdentifier(STUDY_ID); + geneMolecularProfile.setStableId(MOLECULAR_PROFILE_ID); + + geneMolecularProfile.setCancerStudy(cancerStudy); + + molecularProfileSamples.setMolecularProfileId(MOLECULAR_PROFILE_ID); + molecularProfileSamples.setCommaSeparatedSampleIds("1,2,3,4"); + + Sample sample1 = new Sample(); + sample1.setStableId(SAMPLE_ID1); + sample1.setInternalId(1); + sample1.setCancerStudyIdentifier(STUDY_ID); + sample1.setPatientId(1); + samples.add(sample1); + Sample sample2 = new Sample(); + sample2.setStableId(SAMPLE_ID2); + sample2.setInternalId(2); + sample2.setCancerStudyIdentifier(STUDY_ID); + sample2.setPatientId(2); + samples.add(sample2); + Sample sample3 = new Sample(); + sample3.setStableId(SAMPLE_ID3); + sample3.setInternalId(3); + sample3.setCancerStudyIdentifier(STUDY_ID); + sample3.setPatientId(3); + samples.add(sample3); + Sample sample4 = new Sample(); + sample4.setStableId(SAMPLE_ID4); + sample4.setInternalId(4); + sample4.setCancerStudyIdentifier(STUDY_ID); + sample4.setPatientId(4); + samples.add(sample4); + + List alteredSampleIdentifieres = new ArrayList<>(); + List unalteredSampleIdentifieres = new ArrayList<>(); + List unalteredPatientLevelSampleIdentifieres = new ArrayList<>(); + + MolecularProfileCaseIdentifier caseIdentifier1 = new MolecularProfileCaseIdentifier(); + caseIdentifier1.setMolecularProfileId(MOLECULAR_PROFILE_ID); + caseIdentifier1.setCaseId(SAMPLE_ID1); + alteredSampleIdentifieres.add(caseIdentifier1); + + MolecularProfileCaseIdentifier caseIdentifier2 = new MolecularProfileCaseIdentifier(); + caseIdentifier2.setMolecularProfileId(MOLECULAR_PROFILE_ID); + caseIdentifier2.setCaseId(SAMPLE_ID2); + alteredSampleIdentifieres.add(caseIdentifier2); + + MolecularProfileCaseIdentifier caseIdentifier3 = new MolecularProfileCaseIdentifier(); + caseIdentifier3.setMolecularProfileId(MOLECULAR_PROFILE_ID); + caseIdentifier3.setCaseId(SAMPLE_ID3); + unalteredSampleIdentifieres.add(caseIdentifier3); + unalteredPatientLevelSampleIdentifieres.add(caseIdentifier3); + + MolecularProfileCaseIdentifier caseIdentifier4 = new MolecularProfileCaseIdentifier(); + caseIdentifier4.setMolecularProfileId(MOLECULAR_PROFILE_ID); + caseIdentifier4.setCaseId(SAMPLE_ID4); + unalteredSampleIdentifieres.add(caseIdentifier4); + unalteredPatientLevelSampleIdentifieres.add(caseIdentifier4); + + // patient level only data + MolecularProfileCaseIdentifier caseIdentifier5 = new MolecularProfileCaseIdentifier(); + caseIdentifier5.setMolecularProfileId(MOLECULAR_PROFILE_ID); + caseIdentifier5.setCaseId(SAMPLE_ID5); + unalteredPatientLevelSampleIdentifieres.add(caseIdentifier5); + + molecularProfileCaseSets.put("altered samples", alteredSampleIdentifieres); + molecularProfileCaseSets.put("unaltered samples", unalteredSampleIdentifieres); + molecularProfilePatientLevelCaseSets.put("altered samples", alteredSampleIdentifieres); + molecularProfilePatientLevelCaseSets.put("unaltered samples", unalteredPatientLevelSampleIdentifieres); + + Mockito.when(molecularProfileService.getMolecularProfile(MOLECULAR_PROFILE_ID)) + .thenReturn(geneMolecularProfile); + + Mockito.when(molecularDataRepository.getCommaSeparatedSampleIdsOfMolecularProfile(MOLECULAR_PROFILE_ID)) + .thenReturn(molecularProfileSamples); + + Mockito.when(sampleService.fetchSamples(Arrays.asList(STUDY_ID, STUDY_ID, STUDY_ID, STUDY_ID), + Arrays.asList(SAMPLE_ID3, SAMPLE_ID4, SAMPLE_ID1, SAMPLE_ID2), "ID")).thenReturn(samples); + } + + @Test + public void getGenericAssayBinaryEnrichments() throws Exception { + geneMolecularProfile.setMolecularAlterationType(MolecularProfile.MolecularAlterationType.GENERIC_ASSAY); + geneMolecularProfile.setDatatype("BINARY"); + List molecularDataList = new ArrayList(); + GenericAssayMolecularAlteration genericAssayMolecularAlteration1 = new GenericAssayMolecularAlteration(); + genericAssayMolecularAlteration1.setGenericAssayStableId(HUGO_GENE_SYMBOL_1); + + // here are 2 groups + genericAssayMolecularAlteration1.setValues("true,true,true,false"); + molecularDataList.add(genericAssayMolecularAlteration1); + + GenericAssayMolecularAlteration genericAssayMolecularAlteration2 = new GenericAssayMolecularAlteration(); + genericAssayMolecularAlteration2.setGenericAssayStableId(HUGO_GENE_SYMBOL_2); + genericAssayMolecularAlteration2.setValues("true,false,false,true"); + molecularDataList.add(genericAssayMolecularAlteration2); + Mockito.when(molecularDataRepository.getGenericAssayMolecularAlterationsIterable(MOLECULAR_PROFILE_ID, null, + "SUMMARY")).thenReturn(molecularDataList); + + Mockito.when(genericAssayService.getGenericAssayMetaByStableIdsAndMolecularIds( + Arrays.asList(HUGO_GENE_SYMBOL_1, HUGO_GENE_SYMBOL_2), + Arrays.asList(MOLECULAR_PROFILE_ID, MOLECULAR_PROFILE_ID), "SUMMARY")) + .thenReturn(Arrays.asList(new GenericAssayMeta(HUGO_GENE_SYMBOL_1), + new GenericAssayMeta(HUGO_GENE_SYMBOL_2))); + + List result = expressionEnrichmentServiceImpl.getGenericAssayBinaryEnrichments(MOLECULAR_PROFILE_ID, + molecularProfileCaseSets, EnrichmentType.SAMPLE); + + Assert.assertEquals(2, result.size()); + GenericAssayBinaryEnrichment genericAssayBinaryEnrichment = result.get(0); + Assert.assertEquals(HUGO_GENE_SYMBOL_1, genericAssayBinaryEnrichment.getStableId()); + Assert.assertEquals(2, genericAssayBinaryEnrichment.getGroupsStatistics().size()); + + GroupStatistics unalteredGroupStats = genericAssayBinaryEnrichment.getGroupsStatistics().get(0); + Assert.assertEquals("unaltered samples", unalteredGroupStats.getName()); + Assert.assertEquals(new BigDecimal("0.5"), unalteredGroupStats.getMeanExpression()); + Assert.assertEquals(new BigDecimal("0.7071067811865476"), unalteredGroupStats.getStandardDeviation()); + + GroupStatistics alteredGroupStats = genericAssayBinaryEnrichment.getGroupsStatistics().get(1); + Assert.assertEquals("altered samples", alteredGroupStats.getName()); + Assert.assertEquals(new BigDecimal("1.0"), alteredGroupStats.getMeanExpression()); + Assert.assertEquals(new BigDecimal("0.0"), alteredGroupStats.getStandardDeviation()); + + Assert.assertEquals(new BigDecimal("0.49999999999999983"), genericAssayBinaryEnrichment.getpValue()); + Assert.assertEquals(new BigDecimal("0.99999999999999966"), genericAssayBinaryEnrichment.getqValue()); + + genericAssayBinaryEnrichment = result.get(1); + Assert.assertEquals(HUGO_GENE_SYMBOL_2, genericAssayBinaryEnrichment.getStableId()); + Assert.assertEquals(2, genericAssayBinaryEnrichment.getGroupsStatistics().size()); + + unalteredGroupStats = genericAssayBinaryEnrichment.getGroupsStatistics().get(0); + Assert.assertEquals("unaltered samples", unalteredGroupStats.getName()); + Assert.assertEquals(new BigDecimal("0.5"), unalteredGroupStats.getMeanExpression()); + Assert.assertEquals(new BigDecimal("0.7071067811865476"), unalteredGroupStats.getStandardDeviation()); + + alteredGroupStats = genericAssayBinaryEnrichment.getGroupsStatistics().get(1); + Assert.assertEquals("altered samples", alteredGroupStats.getName()); + Assert.assertEquals(new BigDecimal("0.5"), alteredGroupStats.getMeanExpression()); + Assert.assertEquals(new BigDecimal("0.7071067811865476"), alteredGroupStats.getStandardDeviation()); + + Assert.assertEquals(new BigDecimal("1.0"), genericAssayBinaryEnrichment.getpValue()); + Assert.assertEquals(new BigDecimal("1.0"), genericAssayBinaryEnrichment.getqValue()); + } + + + @Test + public void getGenericAssayCategoricalEnrichments() throws MolecularProfileNotFoundException { + geneMolecularProfile.setMolecularAlterationType(MolecularProfile.MolecularAlterationType.GENERIC_ASSAY); + geneMolecularProfile.setDatatype("CATEGORICAL"); + List molecularDataList = new ArrayList(); + GenericAssayMolecularAlteration genericAssayMolecularAlteration1 = new GenericAssayMolecularAlteration(); + genericAssayMolecularAlteration1.setGenericAssayStableId(HUGO_GENE_SYMBOL_1); + genericAssayMolecularAlteration1.setValues("category1,category1,category2,category2"); + molecularDataList.add(genericAssayMolecularAlteration1); + + GenericAssayMolecularAlteration genericAssayMolecularAlteration2 = new GenericAssayMolecularAlteration(); + genericAssayMolecularAlteration2.setGenericAssayStableId(HUGO_GENE_SYMBOL_2); + genericAssayMolecularAlteration2.setValues("category2,category2,category1,category1"); + molecularDataList.add(genericAssayMolecularAlteration2); + Mockito.when(molecularDataRepository.getGenericAssayMolecularAlterationsIterable(MOLECULAR_PROFILE_ID, null, + "SUMMARY")).thenReturn(molecularDataList); + + Mockito.when(genericAssayService.getGenericAssayMetaByStableIdsAndMolecularIds( + Arrays.asList(HUGO_GENE_SYMBOL_1, HUGO_GENE_SYMBOL_2), + Arrays.asList(MOLECULAR_PROFILE_ID, MOLECULAR_PROFILE_ID), "SUMMARY")) + .thenReturn(Arrays.asList(new GenericAssayMeta(HUGO_GENE_SYMBOL_1), + new GenericAssayMeta(HUGO_GENE_SYMBOL_2))); + + List result = expressionEnrichmentServiceImpl.getGenericAssayCategoricalEnrichments(MOLECULAR_PROFILE_ID, + molecularProfileCaseSets, EnrichmentType.SAMPLE); + + Assert.assertEquals(2, result.size()); + GenericAssayCategoricalEnrichment genericAssayCategoricalEnrichment = result.get(0); + Assert.assertEquals(HUGO_GENE_SYMBOL_1, genericAssayCategoricalEnrichment.getStableId()); + Assert.assertEquals(2, genericAssayCategoricalEnrichment.getGroupsStatistics().size()); + + GroupStatistics unalteredGroupStats = genericAssayCategoricalEnrichment.getGroupsStatistics().get(0); + Assert.assertEquals("unaltered samples", unalteredGroupStats.getName()); + + GroupStatistics alteredGroupStats = genericAssayCategoricalEnrichment.getGroupsStatistics().get(1); + Assert.assertEquals("altered samples", alteredGroupStats.getName()); + + Assert.assertEquals(new BigDecimal("0.04550026389635764"), genericAssayCategoricalEnrichment.getpValue()); + Assert.assertEquals(new BigDecimal("0.04550026389635764"), genericAssayCategoricalEnrichment.getqValue()); + + genericAssayCategoricalEnrichment = result.get(1); + Assert.assertEquals(HUGO_GENE_SYMBOL_2, genericAssayCategoricalEnrichment.getStableId()); + Assert.assertEquals(2, genericAssayCategoricalEnrichment.getGroupsStatistics().size()); + + unalteredGroupStats = genericAssayCategoricalEnrichment.getGroupsStatistics().get(0); + Assert.assertEquals("unaltered samples", unalteredGroupStats.getName()); + + alteredGroupStats = genericAssayCategoricalEnrichment.getGroupsStatistics().get(1); + Assert.assertEquals("altered samples", alteredGroupStats.getName()); + + Assert.assertEquals(new BigDecimal("0.04550026389635764"), genericAssayCategoricalEnrichment.getpValue()); + Assert.assertEquals(new BigDecimal("0.04550026389635764"), genericAssayCategoricalEnrichment.getqValue()); + } + +} diff --git a/web/src/main/java/org/cbioportal/web/ExpressionEnrichmentController.java b/web/src/main/java/org/cbioportal/web/ExpressionEnrichmentController.java index 0252463e558..4072480eb13 100644 --- a/web/src/main/java/org/cbioportal/web/ExpressionEnrichmentController.java +++ b/web/src/main/java/org/cbioportal/web/ExpressionEnrichmentController.java @@ -95,7 +95,7 @@ private List fetchExpressionEnrichments(Enri } if (isRequestForGenericAssayEnrichments) { - return (List) expressionEnrichmentService.getGenericAssayEnrichments( + return (List) expressionEnrichmentService.getGenericAssayNumericalEnrichments( molecularProfileIds.iterator().next(), groupCaseIdentifierSet, enrichmentType); } diff --git a/web/src/main/java/org/cbioportal/web/GenericAssayEnrichmentController.java b/web/src/main/java/org/cbioportal/web/GenericAssayEnrichmentController.java new file mode 100644 index 00000000000..294c580582e --- /dev/null +++ b/web/src/main/java/org/cbioportal/web/GenericAssayEnrichmentController.java @@ -0,0 +1,116 @@ +package org.cbioportal.web; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.cbioportal.model.EnrichmentType; +import org.cbioportal.model.GenericAssayBinaryEnrichment; +import org.cbioportal.model.GenericAssayCategoricalEnrichment; +import org.cbioportal.model.MolecularProfileCaseIdentifier; +import org.cbioportal.service.ExpressionEnrichmentService; +import org.cbioportal.service.exception.MolecularProfileNotFoundException; +import org.cbioportal.web.config.annotation.InternalApi; +import org.cbioportal.web.parameter.MolecularProfileCasesGroupFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestAttribute; +import springfox.documentation.annotations.ApiIgnore; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@InternalApi +@RestController +@Validated +@Api(tags = "Generic Assay Enrichment Data", description = " ") +public class GenericAssayEnrichmentController { + @Autowired + private ExpressionEnrichmentService expressionEnrichmentService; + + @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.utils.security.AccessLevel).READ)") + @RequestMapping(value = "/generic-assay-categorical-enrichments/fetch", + method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation("Fetch generic assay categorical data enrichments in a molecular profile") + public ResponseEntity> fetchGenericAssayCategoricalDataEnrichmentInMultipleMolecularProfiles( + @ApiIgnore + @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, + @ApiParam("Type of the enrichment e.g. SAMPLE or PATIENT") + @RequestParam(defaultValue = "SAMPLE") EnrichmentType enrichmentType, + @ApiParam(required = true, value = "List of groups containing sample and molecular profile identifiers") + @Valid @RequestBody(required = false) List groups, + @ApiIgnore + @Valid @RequestAttribute(required = false, value = "interceptedMolecularProfileCasesGroupFilters") List interceptedMolecularProfileCasesGroupFilters) + throws MolecularProfileNotFoundException, UnsupportedOperationException { + + return new ResponseEntity<>(fetchExpressionEnrichments(enrichmentType, interceptedMolecularProfileCasesGroupFilters), + HttpStatus.OK); + } + + @PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection', T(org.cbioportal.utils.security.AccessLevel).READ)") + @RequestMapping(value = "/generic-assay-binary-enrichments/fetch", + method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation("Fetch generic assay binary data enrichments in a molecular profile") + public ResponseEntity> fetchGenericAssayBinaryDataEnrichmentInMultipleMolecularProfiles( + @ApiIgnore + @RequestAttribute(required = false, value = "involvedCancerStudies") Collection involvedCancerStudies, + @ApiParam("Type of the enrichment e.g. SAMPLE or PATIENT") + @RequestParam(defaultValue = "SAMPLE") EnrichmentType enrichmentType, + @ApiParam(required = true, value = "List of groups containing sample and molecular profile identifiers") + @Valid @RequestBody(required = false) List groups, + @ApiIgnore + @Valid @RequestAttribute(required = false, value = "interceptedMolecularProfileCasesGroupFilters") List interceptedMolecularProfileCasesGroupFilters) + throws MolecularProfileNotFoundException, UnsupportedOperationException { + + Map> groupCaseIdentifierSet = interceptedMolecularProfileCasesGroupFilters + .stream().collect(Collectors.toMap(MolecularProfileCasesGroupFilter::getName, + MolecularProfileCasesGroupFilter::getMolecularProfileCaseIdentifiers)); + + Set molecularProfileIds = groupCaseIdentifierSet.values().stream() + .flatMap(molecularProfileCaseSet -> molecularProfileCaseSet.stream() + .map(MolecularProfileCaseIdentifier::getMolecularProfileId)) + .collect(Collectors.toSet()); + + if (molecularProfileIds.size() > 1) { + throw new UnsupportedOperationException("Multi-study enrichments is not yet implemented"); + } + + return new ResponseEntity<>( + expressionEnrichmentService.getGenericAssayBinaryEnrichments( + molecularProfileIds.iterator().next(), groupCaseIdentifierSet, enrichmentType), + HttpStatus.OK); + } + + private List fetchExpressionEnrichments(EnrichmentType enrichmentType, + List interceptedMolecularProfileCasesGroupFilters + ) throws MolecularProfileNotFoundException { + Map> groupCaseIdentifierSet = interceptedMolecularProfileCasesGroupFilters + .stream().collect(Collectors.toMap(MolecularProfileCasesGroupFilter::getName, + MolecularProfileCasesGroupFilter::getMolecularProfileCaseIdentifiers)); + + Set molecularProfileIds = groupCaseIdentifierSet.values().stream() + .flatMap(molecularProfileCaseSet -> molecularProfileCaseSet.stream() + .map(MolecularProfileCaseIdentifier::getMolecularProfileId)) + .collect(Collectors.toSet()); + + if (molecularProfileIds.size() > 1) { + throw new UnsupportedOperationException("Multi-study expression enrichments is not yet implemented"); + } + return expressionEnrichmentService.getGenericAssayCategoricalEnrichments( + molecularProfileIds.iterator().next(), groupCaseIdentifierSet, enrichmentType); + } +} diff --git a/web/src/main/java/org/cbioportal/web/util/InvolvedCancerStudyExtractorInterceptor.java b/web/src/main/java/org/cbioportal/web/util/InvolvedCancerStudyExtractorInterceptor.java index f56a51727b0..91720ee1f81 100644 --- a/web/src/main/java/org/cbioportal/web/util/InvolvedCancerStudyExtractorInterceptor.java +++ b/web/src/main/java/org/cbioportal/web/util/InvolvedCancerStudyExtractorInterceptor.java @@ -102,6 +102,8 @@ public class InvolvedCancerStudyExtractorInterceptor extends HandlerInterceptorA public static final String TREATMENTS_PATIENT_PATH = "/treatments/patient"; public static final String TREATMENTS_SAMPLE_PATH = "/treatments/sample"; public static final String GENERIC_ASSAY_ENRICHMENT_FETCH_PATH = "/generic-assay-enrichments/fetch"; + public static final String GENERIC_ASSAY_CATEGORICAL_ENRICHMENT_FETCH_PATH = "/generic-assay-categorical-enrichments/fetch"; + public static final String GENERIC_ASSAY_BINARY_ENRICHMENT_FETCH_PATH = "/generic-assay-binary-enrichments/fetch"; public static final String CLINICAL_EVENT_TYPE_COUNT_FETCH_PATH = "/clinical-event-type-counts/fetch"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { @@ -151,7 +153,9 @@ public class InvolvedCancerStudyExtractorInterceptor extends HandlerInterceptorA } else if (requestPathInfo.equals(MUTATION_ENRICHMENT_FETCH_PATH) || requestPathInfo.equals(COPY_NUMBER_ENRICHMENT_FETCH_PATH) || requestPathInfo.equals(EXPRESSION_ENRICHMENT_FETCH_PATH) || - requestPathInfo.equals(GENERIC_ASSAY_ENRICHMENT_FETCH_PATH)) { + requestPathInfo.equals(GENERIC_ASSAY_ENRICHMENT_FETCH_PATH) || + requestPathInfo.equals(GENERIC_ASSAY_CATEGORICAL_ENRICHMENT_FETCH_PATH) || + requestPathInfo.equals(GENERIC_ASSAY_BINARY_ENRICHMENT_FETCH_PATH)) { return extractAttributesFromMolecularProfileCasesGroups(request); } else if (requestPathInfo.equals(ALTERATION_ENRICHMENT_FETCH_PATH)) { return extractAttributesFromMolecularProfileCasesGroupsAndAlterationTypes(request); diff --git a/web/src/test/java/org/cbioportal/web/ExpressionEnrichmentControllerTest.java b/web/src/test/java/org/cbioportal/web/ExpressionEnrichmentControllerTest.java index 868b46cfa06..0abe4a9e3ca 100644 --- a/web/src/test/java/org/cbioportal/web/ExpressionEnrichmentControllerTest.java +++ b/web/src/test/java/org/cbioportal/web/ExpressionEnrichmentControllerTest.java @@ -186,7 +186,7 @@ public void fetchGenericAssayEnrichments() throws Exception { genericAssayEnrichment2.setpValue(TEST_P_VALUE_2); genericAssayEnrichments.add(genericAssayEnrichment2); - Mockito.when(expressionEnrichmentService.getGenericAssayEnrichments(Mockito.anyString(), Mockito.anyMap(), + Mockito.when(expressionEnrichmentService.getGenericAssayNumericalEnrichments(Mockito.anyString(), Mockito.anyMap(), Mockito.any(EnrichmentType.class))).thenReturn(genericAssayEnrichments); mockMvc.perform(MockMvcRequestBuilders.post("/generic-assay-enrichments/fetch")