Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Demo rfc80 poc violin plot #10863

Merged
merged 10 commits into from
Jul 2, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ public ClinicalViolinPlotData getClinicalViolinPlotData(
Double value = useLogScale ? ViolinPlotServiceImpl.logScale(Double.parseDouble(d.getAttrValue())) : Double.parseDouble(d.getAttrValue());
gaussians.add(new Gaussian(value, sigma));
}

row.setCurveData(
curvePoints.stream().map(p -> {
curvePoints.parallelStream().map(p -> {
BigDecimal sum = new BigDecimal(0);
for (Gaussian g : gaussians) {
sum = sum.add(BigDecimal.valueOf(g.value(p)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
import org.cbioportal.model.ClinicalData;
import org.cbioportal.model.ClinicalDataBin;
import org.cbioportal.model.ClinicalDataCountItem;
import org.cbioportal.model.CopyNumberCountByGene;
import org.cbioportal.model.ClinicalViolinPlotData;
import org.cbioportal.model.DensityPlotData;
import org.cbioportal.model.CopyNumberCountByGene;
import org.cbioportal.model.GenomicDataCount;
import org.cbioportal.model.Sample;
import org.cbioportal.service.ClinicalDataDensityPlotService;
import org.cbioportal.service.StudyViewColumnarService;
import org.cbioportal.service.ViolinPlotService;
import org.cbioportal.service.exception.StudyNotFoundException;
import org.cbioportal.web.columnar.util.NewStudyViewFilterUtil;
import org.cbioportal.web.config.annotation.InternalApi;
Expand Down Expand Up @@ -58,15 +60,18 @@ public class StudyViewColumnStoreController {
private final StudyViewColumnarService studyViewColumnarService;
private final ClinicalDataBinner clinicalDataBinner;
private final ClinicalDataDensityPlotService clinicalDataDensityPlotService;

private final ViolinPlotService violinPlotService;

@Autowired
public StudyViewColumnStoreController(StudyViewColumnarService studyViewColumnarService,
ClinicalDataBinner clinicalDataBinner,
ClinicalDataDensityPlotService clinicalDataDensityPlotService
ClinicalDataDensityPlotService clinicalDataDensityPlotService,
ViolinPlotService violinPlotService
) {
this.studyViewColumnarService = studyViewColumnarService;
this.clinicalDataBinner = clinicalDataBinner;
this.clinicalDataDensityPlotService = clinicalDataDensityPlotService;
this.violinPlotService = violinPlotService;
}


Expand Down Expand Up @@ -205,8 +210,8 @@ public ResponseEntity<List<ClinicalDataBin>> fetchClinicalDataBinCounts(
}

@PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection<CancerStudyId>', T(org.cbioportal.utils.security.AccessLevel).READ)")
@RequestMapping(value = "/column-store/clinical-data-density-plot/fetch", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = "/column-store/clinical-data-density-plot/fetch", consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(description = "Fetch clinical data density plot bins by study view filter")
@ApiResponse(responseCode = "200", description = "OK",
content = @Content(schema = @Schema(implementation = DensityPlotData.class)))
Expand Down Expand Up @@ -260,4 +265,64 @@ public ResponseEntity<DensityPlotData> fetchClinicalDataDensityPlot(

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

@PreAuthorize("hasPermission(#involvedCancerStudies, 'Collection<CancerStudyId>', T(org.cbioportal.utils.security.AccessLevel).READ)")
@PostMapping(value = "/column-store/clinical-data-violin-plots/fetch",
consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(description = "Fetch violin plot curves per categorical clinical data value, filtered by study view filter")
@ApiResponse(responseCode = "200", description = "OK",
content = @Content(schema = @Schema(implementation = ClinicalViolinPlotData.class)))
public ResponseEntity<ClinicalViolinPlotData> fetchClinicalDataViolinPlots(
@Parameter(required = true, description = "Clinical Attribute ID of the categorical attribute")
@RequestParam String categoricalAttributeId,
@Parameter(required = true, description = "Clinical Attribute ID of the numerical attribute")
@RequestParam String numericalAttributeId,
@Parameter(description = "Starting point of the violin plot axis, if different than smallest value")
@RequestParam(required = false) BigDecimal axisStart,
@Parameter(description = "Ending point of the violin plot axis, if different than largest value")
@RequestParam(required = false) BigDecimal axisEnd,
@Parameter(description = "Number of points in the curve")
@RequestParam(required = false, defaultValue = "100") BigDecimal numCurvePoints,
@Parameter(description="Use log scale for the numerical attribute")
@RequestParam(required = false, defaultValue = "false") Boolean logScale,
@Parameter(description="Sigma stepsize multiplier")
@RequestParam(required = false, defaultValue = "1") BigDecimal sigmaMultiplier,
@Parameter(hidden = true) // prevent reference to this attribute in the swagger-ui interface
@RequestAttribute(required = false, value = "involvedCancerStudies") Collection<String> involvedCancerStudies,
@Parameter(hidden = true) // 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,
@Parameter(required = true, description = "Study view filter")
@Valid @RequestBody(required = false) StudyViewFilter studyViewFilter) {

List<Sample> filteredSamples = studyViewColumnarService.getFilteredSamples(interceptedStudyViewFilter);

// get samples that are filtered without the numerical filter - this is violin plot data
if (interceptedStudyViewFilter.getClinicalDataFilters() != null) {
interceptedStudyViewFilter.getClinicalDataFilters().stream()
.filter(f->f.getAttributeId().equals(numericalAttributeId))
.findAny()
.ifPresent(f->interceptedStudyViewFilter.getClinicalDataFilters().remove(f));
}

// Filter out clinical data with empty attribute values due to Clickhouse migration
List<ClinicalData> sampleClinicalDataList = studyViewColumnarService.getSampleClinicalData(interceptedStudyViewFilter, List.of(numericalAttributeId, categoricalAttributeId))
.stream()
.filter(clinicalData -> !clinicalData.getAttrValue().isEmpty())
.toList();

// Only mutation count can use log scale
boolean useLogScale = logScale && numericalAttributeId.equals("MUTATION_COUNT");

ClinicalViolinPlotData result = violinPlotService.getClinicalViolinPlotData(
sampleClinicalDataList,
filteredSamples,
axisStart,
axisEnd,
numCurvePoints,
useLogScale,
sigmaMultiplier
);

return new ResponseEntity<>(result, HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
cancer_study_identifier as studyId
FROM clinical_data_derived
<where>
type = 'sample' AND
sample_unique_id IN (
<include refid="sampleUniqueIdsFromStudyViewFilter"/>
<if test="applyPatientIdFilters == true">
Expand Down
Loading