Skip to content

Commit

Permalink
resolve issue cBioPortal#5613 fixing mutated genes table shows incorr…
Browse files Browse the repository at this point in the history
…ect frequencies
  • Loading branch information
Kelsey Zhu authored and Hongxin Zhang committed Oct 2, 2019
1 parent fc04e5f commit 0e35e36
Show file tree
Hide file tree
Showing 12 changed files with 203 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ List<MutationCountByGene> getSampleCountByEntrezGeneIdsAndSampleIds(String molec
List<MutationCountByGene> getSampleCountInMultipleMolecularProfiles(List<String> molecularProfileIds,
List<String> sampleIds,
List<Integer> entrezGeneIds);

@Cacheable(cacheNames = "GeneralRepositoryCache", condition = "@cacheEnabledConfig.getEnabled()")
List<MutationCountByGene> getSampleCountInMultipleMolecularProfilesForFusions(List<String> molecularProfileIds,
List<String> sampleIds,
List<Integer> entrezGeneIds);

@Cacheable(cacheNames = "GeneralRepositoryCache", condition = "@cacheEnabledConfig.getEnabled()")
List<MutationCountByGene> getPatientCountInMultipleMolecularProfiles(List<String> molecularProfileIds,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ List<MutationCountByGene> getPatientCountInMultipleMolecularProfiles(List<String
List<String> patientIds,
List<Integer> entrezGeneIds,
Boolean snpOnly);

List<MutationCountByGene> getSampleCountInMultipleMolecularProfilesForFusions(List<String> molecularProfileIds,
List<String> sampleIds,
List<Integer> entrezGeneIds,
Boolean snpOnly);



MutationCountByPosition getMutationCountByPosition(Integer entrezGeneId, Integer proteinPosStart,
Integer proteinPosEnd);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ public List<MutationCountByGene> getSampleCountInMultipleMolecularProfiles(List<
return mutationMapper.getSampleCountInMultipleMolecularProfiles(molecularProfileIds, sampleIds, entrezGeneIds, null);
}

@Override
public List<MutationCountByGene> getSampleCountInMultipleMolecularProfilesForFusions(List<String> molecularProfileIds,
List<String> sampleIds, List<Integer> entrezGeneIds) {

return mutationMapper.getSampleCountInMultipleMolecularProfilesForFusions(molecularProfileIds,
sampleIds, entrezGeneIds, null);
}

@Override
public List<MutationCountByGene> getPatientCountInMultipleMolecularProfiles(List<String> molecularProfileIds,
List<String> patientIds,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,22 @@
COUNT(*) AS totalCount,
COUNT(DISTINCT(mutation.SAMPLE_ID)) AS numberOfAlteredCases
FROM mutation
INNER JOIN mutation_event ON mutation_event.MUTATION_EVENT_ID = mutation.MUTATION_EVENT_ID AND mutation_event.MUTATION_TYPE != 'Fusion'
INNER JOIN genetic_profile ON mutation.GENETIC_PROFILE_ID = genetic_profile.GENETIC_PROFILE_ID
INNER JOIN sample ON mutation.SAMPLE_ID = sample.INTERNAL_ID
INNER JOIN gene ON mutation.ENTREZ_GENE_ID = gene.ENTREZ_GENE_ID
<include refid="whereInMultipleMolecularProfiles"/>
GROUP BY mutation.ENTREZ_GENE_ID
</select>

<select id="getSampleCountInMultipleMolecularProfilesForFusions" resultType="org.cbioportal.model.MutationCountByGene">
SELECT
mutation.ENTREZ_GENE_ID AS entrezGeneId,
gene.HUGO_GENE_SYMBOL AS hugoGeneSymbol,
COUNT(*) AS totalCount,
COUNT(DISTINCT(mutation.SAMPLE_ID)) AS numberOfAlteredCases
FROM mutation
INNER JOIN mutation_event ON mutation_event.MUTATION_EVENT_ID = mutation.MUTATION_EVENT_ID AND mutation_event.MUTATION_TYPE = 'Fusion'
INNER JOIN genetic_profile ON mutation.GENETIC_PROFILE_ID = genetic_profile.GENETIC_PROFILE_ID
INNER JOIN sample ON mutation.SAMPLE_ID = sample.INTERNAL_ID
INNER JOIN gene ON mutation.ENTREZ_GENE_ID = gene.ENTREZ_GENE_ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ List<MutationCountByGene> getSampleCountInMultipleMolecularProfiles(List<String>
List<Integer> entrezGeneIds,
boolean includeFrequency);

List<MutationCountByGene> getSampleCountInMultipleMolecularProfilesForFusions(List<String> molecularProfileIds,
List<String> sampleIds,
List<Integer> entrezGeneId,
boolean includeFrequency);

List<MutationCountByGene> getPatientCountInMultipleMolecularProfiles(List<String> molecularProfileIds,
List<String> patientIds,
List<Integer> entrezGeneIds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,27 @@ public List<MutationCountByGene> getSampleCountInMultipleMolecularProfiles(List<
profiledSamplesCounter.calculate(molecularProfileIds, sampleIds, result);
}
}

return result;
}

@Override
public List<MutationCountByGene> getSampleCountInMultipleMolecularProfilesForFusions(List<String> molecularProfileIds,
List<String> sampleIds,
List<Integer> entrezGeneIds,
boolean includeFrequency) {
List<MutationCountByGene> result;
if (molecularProfileIds.isEmpty()) {
result = Collections.emptyList();
} else {
result = mutationRepository.getSampleCountInMultipleMolecularProfilesForFusions(
molecularProfileIds, sampleIds, entrezGeneIds);
if (includeFrequency) {
profiledSamplesCounter.calculate(molecularProfileIds, sampleIds, result);
}
}
return result;
}

@Override
public List<MutationCountByGene> getPatientCountInMultipleMolecularProfiles(List<String> molecularProfileIds,
List<String> patientIds,
Expand Down
37 changes: 37 additions & 0 deletions web/src/main/java/org/cbioportal/web/StudyViewController.java
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,43 @@ public ResponseEntity<List<MutationCountByGene>> fetchMutatedGenes(
return new ResponseEntity<>(result, HttpStatus.OK);
}

@PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection<CancerStudyId>', 'read')")
@RequestMapping(value = "/fusion-genes/fetch", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ApiOperation("Fetch fusion genes by study view filter")
public ResponseEntity<List<MutationCountByGene>> fetchFusionGenes(
@ApiParam(required = true, value = "Study view filter")
@Valid @RequestBody(required = false) StudyViewFilter studyViewFilter,
@ApiIgnore // prevent reference to this attribute in the swagger-ui interface
@RequestAttribute(required = false, value = "involvedCancerStudies") Collection<String> involvedCancerStudies,
@ApiIgnore // prevent reference to this attribute in the swagger-ui interface. this attribute is needed for the @PreAuthorize tag above.
@Valid @RequestAttribute(required = false, value = "interceptedStudyViewFilter") StudyViewFilter interceptedStudyViewFilter) throws StudyNotFoundException {
List<SampleIdentifier> filteredSampleIdentifiers = studyViewFilterApplier.apply(interceptedStudyViewFilter);
List<MutationCountByGene> result = new ArrayList<>();
if (!filteredSampleIdentifiers.isEmpty()) {
List<String> studyIds = new ArrayList<>();
List<String> sampleIds = new ArrayList<>();
studyViewFilterUtil.extractStudyAndSampleIds(filteredSampleIdentifiers, studyIds, sampleIds);
result = mutationService.getSampleCountInMultipleMolecularProfilesForFusions(molecularProfileService
.getFirstMutationProfileIds(studyIds, sampleIds), sampleIds, null, false);
result.sort((a, b) -> b.getNumberOfAlteredCases() - a.getNumberOfAlteredCases());
List<String> distinctStudyIds = studyIds.stream().distinct().collect(Collectors.toList());
if (distinctStudyIds.size() == 1 && !result.isEmpty()) {
Map<Integer, MutSig> mutSigMap = significantlyMutatedGeneService.getSignificantlyMutatedGenes(
distinctStudyIds.get(0), Projection.SUMMARY.name(), null, null, null, null).stream().collect(
Collectors.toMap(MutSig::getEntrezGeneId, Function.identity()));
result.forEach(r -> {
if (mutSigMap.containsKey(r.getEntrezGeneId())) {
r.setqValue(mutSigMap.get(r.getEntrezGeneId()).getqValue());
}
});
}
}

return new ResponseEntity<>(result, HttpStatus.OK);
}


@PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection<CancerStudyId>', 'read')")
@RequestMapping(value = "/cna-genes/fetch", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.cbioportal.web.parameter;

import java.io.Serializable;
import java.util.List;

public class FusionGeneFilter implements Serializable {

private List<Integer> entrezGeneIds;

public List<Integer> getEntrezGeneIds() {
return entrezGeneIds;
}

public void setEntrezGeneIds(List<Integer> entrezGeneIds) {
this.entrezGeneIds = entrezGeneIds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ public class StudyViewFilter implements Serializable {
private List<String> studyIds;
private List<ClinicalDataEqualityFilter> clinicalDataEqualityFilters;
private List<ClinicalDataIntervalFilter> clinicalDataIntervalFilters;
private List<MutationGeneFilter> mutatedGenes;
private List<CopyNumberGeneFilter> cnaGenes;
private Boolean withMutationData;
private Boolean withCNAData;
private RectangleBounds mutationCountVsCNASelection;
private List<MutationGeneFilter> mutatedGenes;
private List<FusionGeneFilter> fusionGenes;
private List<CopyNumberGeneFilter> cnaGenes;
private Boolean withMutationData;
private Boolean withCNAData;
private RectangleBounds mutationCountVsCNASelection;

@AssertTrue
private boolean isEitherSampleIdentifiersOrStudyIdsPresent() {
Expand Down Expand Up @@ -81,8 +82,14 @@ public List<MutationGeneFilter> getMutatedGenes() {
return mutatedGenes;
}

public void setMutatedGenes(List<MutationGeneFilter> mutatedGenes) {
this.mutatedGenes = mutatedGenes;
public void setMutatedGenes(List<MutationGeneFilter> mutatedGenes) { this.mutatedGenes = mutatedGenes; }

public List<FusionGeneFilter> getFusionGenes() {
return fusionGenes;
}

public void setFusionGenes(List<FusionGeneFilter> fusionGenes) {
this.fusionGenes = fusionGenes;
}

public List<CopyNumberGeneFilter> getCnaGenes() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public class InvolvedCancerStudyExtractorInterceptor extends HandlerInterceptorA
public static final String STUDY_VIEW_CNA_GENES = "/cna-genes/fetch";
public static final String STUDY_VIEW_FILTERED_SAMPLES = "/filtered-samples/fetch";
public static final String STUDY_VIEW_MUTATED_GENES = "/mutated-genes/fetch";
public static final String STUDY_VIEW_FUSION_GENES = "/fusion-genes/fetch";
public static final String STUDY_VIEW_SAMPLE_COUNTS = "/sample-counts/fetch";
public static final String CLINICAL_DATA_ENRICHMENT_FETCH_PATH = "/clinical-data-enrichments/fetch";
public static final String MUTATION_ENRICHMENT_FETCH_PATH = "/mutation-enrichments/fetch";
Expand Down Expand Up @@ -132,7 +133,7 @@ public class InvolvedCancerStudyExtractorInterceptor extends HandlerInterceptorA
} else if (requestPathInfo.equals(STUDY_VIEW_CLINICAL_DATA_COUNTS_PATH)) {
return extractAttributesFromClinicalDataCountFilter(wrappedRequest);
} else if (Arrays.asList(STUDY_VIEW_CLINICAL_DATA_DENSITY_PATH, STUDY_VIEW_CNA_GENES,
STUDY_VIEW_FILTERED_SAMPLES, STUDY_VIEW_MUTATED_GENES, STUDY_VIEW_SAMPLE_COUNTS)
STUDY_VIEW_FILTERED_SAMPLES, STUDY_VIEW_MUTATED_GENES, STUDY_VIEW_FUSION_GENES, STUDY_VIEW_SAMPLE_COUNTS)
.contains(requestPathInfo)) {
return extractAttributesFromStudyViewFilter(wrappedRequest);
} else if (requestPathInfo.equals(CLINICAL_DATA_ENRICHMENT_FETCH_PATH)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ public List<SampleIdentifier> apply(StudyViewFilter studyViewFilter, Boolean neg
sampleIdentifiers = filterCNAGenes(cnaGenes, sampleIdentifiers);
}

List<FusionGeneFilter> fusionGenes = studyViewFilter.getFusionGenes();
if (fusionGenes != null && !sampleIdentifiers.isEmpty()) {
sampleIdentifiers = filterFusionGenes(fusionGenes, sampleIdentifiers);
}

Boolean withMutationData = studyViewFilter.getWithMutationData();
if (withMutationData != null && !sampleIdentifiers.isEmpty()) {
sampleIdentifiers = filterByProfiled(sampleIdentifiers, withMutationData, molecularProfileService::getFirstMutationProfileIds);
Expand Down Expand Up @@ -178,9 +183,7 @@ private List<SampleIdentifier> filterMutatedGenes(List<MutationGeneFilter> mutat
List<String> sampleIds = new ArrayList<>();
studyViewFilterUtil.extractStudyAndSampleIds(sampleIdentifiers, studyIds, sampleIds);
List<Mutation> mutations = mutationService.getMutationsInMultipleMolecularProfiles(molecularProfileService
.getFirstMutationProfileIds(studyIds, sampleIds), sampleIds, molecularProfileGeneFilter.getEntrezGeneIds(),
Projection.ID.name(), null, null, null, null);

.getFirstMutationProfileIds(studyIds, sampleIds), sampleIds, molecularProfileGeneFilter.getEntrezGeneIds(), Projection.ID.name(), null, null, null, null);
sampleIdentifiers = mutations.stream().map(m -> {
SampleIdentifier sampleIdentifier = new SampleIdentifier();
sampleIdentifier.setSampleId(m.getSampleId());
Expand All @@ -192,6 +195,24 @@ private List<SampleIdentifier> filterMutatedGenes(List<MutationGeneFilter> mutat
return sampleIdentifiers;
}

private List<SampleIdentifier> filterFusionGenes(List<FusionGeneFilter> fusionGenes, List<SampleIdentifier> sampleIdentifiers) {
for (FusionGeneFilter molecularProfileGeneFilter : fusionGenes) {
List<String> studyIds = new ArrayList<>();
List<String> sampleIds = new ArrayList<>();
studyViewFilterUtil.extractStudyAndSampleIds(sampleIdentifiers, studyIds, sampleIds);
List<Mutation> fusions = mutationService.getMutationsInMultipleMolecularProfiles(molecularProfileService
.getFirstMutationProfileIds(studyIds, sampleIds), sampleIds, molecularProfileGeneFilter.getEntrezGeneIds(), Projection.ID.name(), null, null, null, null);
sampleIdentifiers = fusions.stream().map(m -> {
SampleIdentifier sampleIdentifier = new SampleIdentifier();
sampleIdentifier.setSampleId(m.getSampleId());
sampleIdentifier.setStudyId(m.getStudyId());
return sampleIdentifier;
}).distinct().collect(Collectors.toList());
}

return sampleIdentifiers;
}

private List<SampleIdentifier> filterCNAGenes(List<CopyNumberGeneFilter> cnaGenes, List<SampleIdentifier> sampleIdentifiers) {
for (CopyNumberGeneFilter copyNumberGeneFilter : cnaGenes) {

Expand Down
50 changes: 50 additions & 0 deletions web/src/test/java/org/cbioportal/web/StudyViewControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,56 @@ public void fetchMutatedGenes() throws Exception {
.andExpect(MockMvcResultMatchers.jsonPath("$[1].totalCount").value(3));
}

@Test
public void fetchFusionGenes() throws Exception {

MolecularProfile molecularProfile = new MolecularProfile();
molecularProfile.setCancerStudyIdentifier(TEST_STUDY_ID);
Mockito.when(molecularProfileService.getMolecularProfile(Mockito.anyString())).thenReturn(molecularProfile);

List<SampleIdentifier> filteredSampleIdentifiers = new ArrayList<>();
SampleIdentifier sampleIdentifier = new SampleIdentifier();
sampleIdentifier.setSampleId(TEST_SAMPLE_ID_1);
sampleIdentifier.setStudyId(TEST_STUDY_ID);
filteredSampleIdentifiers.add(sampleIdentifier);
Mockito.when(studyViewFilterApplier.apply(Mockito.anyObject())).thenReturn(filteredSampleIdentifiers);

List<MutationCountByGene> fusionCounts = new ArrayList<>();
MutationCountByGene fusionCount1 = new MutationCountByGene();
fusionCount1.setEntrezGeneId(TEST_ENTREZ_GENE_ID_1);
fusionCount1.setHugoGeneSymbol(TEST_HUGO_GENE_SYMBOL_1);
fusionCount1.setNumberOfAlteredCases(1);
fusionCount1.setTotalCount(1);
fusionCounts.add(fusionCount1);
MutationCountByGene fusionCount2 = new MutationCountByGene();
fusionCount2.setEntrezGeneId(TEST_ENTREZ_GENE_ID_2);
fusionCount2.setHugoGeneSymbol(TEST_HUGO_GENE_SYMBOL_2);
fusionCount2.setNumberOfAlteredCases(2);
fusionCount2.setTotalCount(2);
fusionCounts.add(fusionCount2);

Mockito.when(mutationService.getSampleCountInMultipleMolecularProfilesForFusions(Mockito.anyListOf(String.class),
Mockito.anyListOf(String.class), Mockito.anyListOf(Integer.class), Mockito.anyBoolean())).thenReturn(fusionCounts);

StudyViewFilter studyViewFilter = new StudyViewFilter();
studyViewFilter.setStudyIds(Arrays.asList(TEST_STUDY_ID));

mockMvc.perform(MockMvcRequestBuilders.post("/fusion-genes/fetch")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(studyViewFilter)))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.jsonPath("$[0].entrezGeneId").value(TEST_ENTREZ_GENE_ID_2))
.andExpect(MockMvcResultMatchers.jsonPath("$[0].hugoGeneSymbol").value(TEST_HUGO_GENE_SYMBOL_2))
.andExpect(MockMvcResultMatchers.jsonPath("$[0].numberOfAlteredCases").value(2))
.andExpect(MockMvcResultMatchers.jsonPath("$[0].totalCount").value(2))
.andExpect(MockMvcResultMatchers.jsonPath("$[1].entrezGeneId").value(TEST_ENTREZ_GENE_ID_1))
.andExpect(MockMvcResultMatchers.jsonPath("$[1].hugoGeneSymbol").value(TEST_HUGO_GENE_SYMBOL_1))
.andExpect(MockMvcResultMatchers.jsonPath("$[1].numberOfAlteredCases").value(1))
.andExpect(MockMvcResultMatchers.jsonPath("$[1].totalCount").value(1));
}

@Test
public void fetchCNAGenes() throws Exception {

Expand Down

0 comments on commit 0e35e36

Please sign in to comment.