From 5fb2db8aac5ec64a345fccd8d1592b9cc99ae308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guilhem=20Semp=C3=A9r=C3=A9?= Date: Wed, 26 Jun 2024 09:38:27 +0200 Subject: [PATCH] Simplified individual selection --- src/main/webapp/js/charts.js | 284 ++++++++++++++++++----------------- 1 file changed, 148 insertions(+), 136 deletions(-) diff --git a/src/main/webapp/js/charts.js b/src/main/webapp/js/charts.js index d64c82c5..6a256328 100644 --- a/src/main/webapp/js/charts.js +++ b/src/main/webapp/js/charts.js @@ -25,6 +25,7 @@ var currentChartType = null; let progressTimeoutId = null; var emptyResponseCountsByProcess = []; var cachedResults; +var callSetIds = [], additionalCallSetIds = []; const chartTypes = new Map([ ["density", { @@ -38,6 +39,25 @@ const chartTypes = new Map([ enableMarker: false, lineWidth: 2 }], + onLoad: function (){ + if ($("#plotGroupingSelectionMode").length == 1) + updateAvailableGroups(); + }, + buildCustomisation: function () { + if ($("input.showHideSeriesBox").length == 0) + return ""; + + let groupingOoptions = getGroupingOptions(); + if (groupingOoptions == "") + return ""; + + return ( '
' + + '
Individuals accounted for
' + + '
' + + '
' + + '... refine if you wish
' + + '
'); + } }], ["maf", { displayName: "MAF distribution", @@ -45,7 +65,6 @@ const chartTypes = new Map([ title: "MAF values for {{displayedVariantType}} variants on sequence {{displayedSequence}}", subtitle: "MAF values calculated in an interval of size {{intervalSize}} around each point (excluding missing and multi-allelic variants)", xAxisTitle: "Positions on selected sequence", - selectIndividuals: true, series: [ { name: "MAF * 100", @@ -59,6 +78,21 @@ const chartTypes = new Map([ return null; } }, + onLoad: function (){ + updateAvailableGroups(); + }, + buildCustomisation: function () { + let groupingOoptions = getGroupingOptions(); + if (groupingOoptions == "") + return ""; + + return ( '
' + + '
Individuals accounted for
' + + '
' + + '
' + + '... refine if you wish
' + + '
'); + } }], ["fst", { displayName: "Fst", @@ -81,56 +115,20 @@ const chartTypes = new Map([ return null; } }, - buildCustomisation: function (){ - return ('

with value ' - + '
Group FST by
' - + ''); + onLoad: function (){ + updateAvailableGroups(); }, - buildRequestPayload: function (payload){ - const groupOption = $("#plotGroupingSelectionMode").find(":selected").val(); - const selectedValues = $("#plotGroupingMetadataValues").val(); - if (selectedValues === null || selectedValues.length < 2) - return null; - - payload.additionalCallSetIds = []; // override default group selection - if (groupOption != "__") { - let selectedIndividuals = getSelectedIndividuals(); - - payload.callSetIds = []; // override default group selection - for (var i in selectedValues) { - var filters = {}; - if (i > 0) - payload.additionalCallSetIds.push([]); - var targetGroup = i == 0 ? payload.callSetIds : payload.additionalCallSetIds[i - 1]; - filters[groupOption] = [selectedValues[i]]; - $.ajax({ - url: filterIndividualMetadata + '/' + referenceset + "?projID=" + document.getElementById('project').options[document.getElementById('project').options.selectedIndex].dataset.id.split(idSep)[1], - type: "POST", - async: false, - contentType: "application/json;charset=utf-8", - headers: buildHeader(token, $('#assembly').val()), - data: JSON.stringify(filters), - success: function (callSetResponse) { - callSetResponse.forEach(function (callset) { - if (selectedIndividuals.length == 0 || selectedIndividuals.includes(callset.id)) - targetGroup.push(callset.id) - }); - } - }); - } - } - else - for (var i in selectedValues) - if (i == 0) - payload.callSetIds = getSelectedIndividuals([selectedValues[i]]); // override default group selection - else - payload.additionalCallSetIds.push(getSelectedIndividuals([selectedValues[i]])); - return payload; - }, - onLoad: function (){ - setFstGroupingOption(); + buildCustomisation: function () { + let groupingOoptions = getGroupingOptions(); + if (groupingOoptions == "") + return ""; + + return ( '

with value ' + + '
Group FST by
' + + '
' + + '
' + + '... values defining groups (2 or more)
' + + '
'); }, onDisplay: function (){ displayOrHideThreshold(document.getElementById("showFstThreshold").checked); @@ -142,7 +140,6 @@ const chartTypes = new Map([ title: "Tajima's D values for {{displayedVariantType}} variants on sequence {{displayedSequence}}", subtitle: "Tajima's D values calculated in an interval of size {{intervalSize}} around each point (excluding missing and multi-allelic variants)", xAxisTitle: "Positions on selected sequence", - selectIndividuals: true, series: [ { name: "Tajima's D", @@ -161,19 +158,82 @@ const chartTypes = new Map([ return null; } }, + onLoad: function (){ + updateAvailableGroups(); + }, + buildCustomisation: function () { + let groupingOoptions = getGroupingOptions(); + if (groupingOoptions == "") + return ""; + + return ( '
' + + '
Individuals accounted for
' + + '
' + + '
' + + '... refine if you wish
' + + '
'); + } }] ]); -function fstGroupsChanged() { - let groups = $("select#plotGroupingMetadataValues").val(); - if (groups == null || groups.length < 2) - $('#showChartButton').prop('disabled', true); - else if ($("#plotGroupingSelectionMode").find(":selected").val() == "__" && areGroupsOverlapping($("select#plotGroupingMetadataValues").val())) { - alert("Fst groups are overlapping, please change selection!"); - $('#showChartButton').prop('disabled', true); +function chartIndSelectionChanged() { + callSetIds = []; + additionalCallSetIds = []; + const groupOption = $("#plotGroupingSelectionMode").find(":selected").val(); + let selectedValues = $("select#plotGroupingMetadataValues").val(); + if (selectedValues == null) { + selectedValues = []; + $("input.showHideSeriesBox:checked").prop("checked", false); + } + let minRequiredGroups = currentChartType == "fst" ? 2 : (currentChartType == "density" && $("input.showHideSeriesBox:checked").length == 0 ? 0 : 1); + + if (selectedValues.length >= minRequiredGroups) { + $('#showChartButton').prop('disabled', false); + if (groupOption != "__") { + let selectedIndividuals = getSelectedIndividuals(); + for (var i in selectedValues) { + var filters = {}; + if (i > 0) + additionalCallSetIds.push([]); + var targetGroup = i == 0 ? callSetIds : additionalCallSetIds[i - 1]; + filters[groupOption] = [selectedValues[i]]; + $.ajax({ + url: filterIndividualMetadata + '/' + referenceset + "?projID=" + document.getElementById('project').options[document.getElementById('project').options.selectedIndex].dataset.id.split(idSep)[1], + type: "POST", + async: false, + contentType: "application/json;charset=utf-8", + headers: buildHeader(token, $('#assembly').val()), + data: JSON.stringify(filters), + success: function (callSetResponse) { + callSetResponse.forEach(function (callset) { + if (selectedIndividuals.length == 0 || selectedIndividuals.includes(callset.id)) + targetGroup.push(getProjectId() + idSep + callset.id) + }); + } + }); + } + } + else { + if (currentChartType == "fst" && areGroupsOverlapping(selectedValues)) { + alert("Fst groups are overlapping, please change selection!"); + $('#showChartButton').prop('disabled', true); + return; + } + + for (var i in selectedValues) + if (i == 0) + callSetIds = getSelectedIndividuals([selectedValues[i]], true); + else + additionalCallSetIds.push(getSelectedIndividuals([selectedValues[i]], true)); + } } else - $('#showChartButton').prop('disabled', false); + $('#showChartButton').prop('disabled', true); + + let allCallsetIDs = new Set(callSetIds); + for (let i = 0; additionalCallSetIds != null && i < additionalCallSetIds.length; i++) + additionalCallSetIds[i].forEach(cs => allCallsetIDs.add(cs)); + $('#indSelectionCount').text("(" + allCallsetIDs.size + " selected)"); } function initializeChartDisplay(){ @@ -241,7 +301,7 @@ function onManualIndividualSelection() { } function getGroupingOptions() { - let options = getGenotypeInvestigationMode() == 0 ? "" : ''; + let options = getGenotypeInvestigationMode() == 0 ? "" : ''; const fields = callSetMetadataFields.slice(); fields.sort(); fields.forEach(function (field){ @@ -282,10 +342,7 @@ function feedSequenceSelectAndLoadVariantTypeList(sequences, types) { $("#chartVariantTypeList").append(""); buildCustomisationDiv(chartInfo); - - if (chartInfo.onLoad !== undefined) - chartInfo.onLoad(); - + chartInfo.onLoad(); loadChart(); } @@ -305,7 +362,7 @@ function buildCustomisationDiv(chartInfo) { for (var key in jsonResult) { let fieldName = jsonResult[key]; if (i == 0) - vcfMetadataSelectionHTML += '

Additional series based on VCF genotype metadata:

'; + vcfMetadataSelectionHTML += '

Additional series based on VCF genotype metadata:

'; vcfMetadataSelectionHTML += '
'; i++; } @@ -320,8 +377,6 @@ function buildCustomisationDiv(chartInfo) { let customisationDivHTML = "
"; customisationDivHTML += '
'; customisationDivHTML += '

Customisation options

Number of intervals
(between 50 and 1000)'; - if (vcfMetadataSelectionHTML != "" || chartInfo.selectIndividuals) - customisationDivHTML += '
Individuals accounted for
'; customisationDivHTML += '
'; customisationDivHTML += '
'; @@ -332,20 +387,6 @@ function buildCustomisationDiv(chartInfo) { customisationDivHTML += '
' $("div#chartContainer div#additionalCharts").html(customisationDivHTML + "
"); - if (vcfMetadataSelectionHTML != "" || chartInfo.selectIndividuals) - showSelectedIndCount($('#plotIndividualSelectionMode'), $('#indSelectionCount')); -} - -function showSelectedIndCount(selectionObj, selectionLabelObj) { - var selectedOption = selectionObj.find("option:selected"), chooseMode = selectedOption.val() == "choose"; - if (chooseMode) - selectionLabelObj.text(""); - else if (selectedOption.val() == "") - selectionLabelObj.text(" (" + indOpt.length + " selected)"); - else { - var selectedIndCount = Object.keys(getSelectedIndividuals(selectedOption.val() == "allGroups" ? null : [parseInt(selectedOption.val())])).length; - selectionLabelObj.text(" (" + (selectedIndCount == 0 ? indOpt.length : selectedIndCount) + " selected)"); - } } function displayOrAbort() { @@ -370,8 +411,7 @@ function getIntervalCountFromLocalStorage() { function applyChartType() { cachedResults = {}; - var typeSelect = document.getElementById("chartTypeList"); - currentChartType = typeSelect.options[typeSelect.selectedIndex].value; + currentChartType = $("#chartTypeList").val(); const chartInfo = chartTypes.get(currentChartType); if (chartInfo.enableCondition !== undefined){ @@ -400,65 +440,30 @@ function applyChartType() { } function buildDataPayLoad(displayedSequence, displayedVariantType) { - const chartInfo = chartTypes.get(currentChartType); - - let plotIndividuals = null; - if (chartInfo.selectIndividuals) { - switch ($('#plotIndividualSelectionMode').val()) { - case "choose": - plotIndividuals = $('#plotIndividualSelectionMode').parent().parent().find("select.individualSelector").val(); - break; - case "allGroups": - plotIndividuals = getSelectedIndividuals(); - break; - case "": - plotIndividuals = []; - break; - default: - plotIndividuals = getSelectedIndividuals([parseInt($('#plotIndividualSelectionMode').val())]); - break; - } - } - let activeGroups = $(".genotypeInvestigationDiv").length; let query = { "variantSetId": $('#project :selected').data("id"), - "callSetIds": getSelectedIndividuals(activeGroups !== 0 ? [1] : null, true), "discriminate": getDiscriminateArray(), "displayedSequence": displayedSequence, "displayedVariantType": displayedVariantType != "" ? displayedVariantType : null, "displayedRangeMin": localmin, "displayedRangeMax": localmax, "displayedRangeIntervalCount": displayedRangeIntervalCount, - "plotIndividuals": plotIndividuals, + "callSetIds": callSetIds.length > 0 ? callSetIds : indOpt.map(ind => getProjectId() + idSep + ind), + "additionalCallSetIds": additionalCallSetIds, "start": $('#minposition').val() === "" ? -1 : parseInt($('#minposition').val()), "end": $('#maxposition').val() === "" ? -1 : parseInt($('#maxposition').val()) }; - -// let genotypes = []; -// let mostsameratio = []; -// let minmaf = []; -// let maxmaf = []; -// let minmissingdata = []; -// let maxmissingdata = []; -// let minhez = []; -// let maxhez = []; - let callsetids = []; - var annotationFieldThresholds = []; + + query.annotationFieldThresholds = []; for (let i = 0; i < activeGroups; i++) { var threshold = {}; $(`#vcfFieldFilterGroup${i + 1} input`).each(function() { if (parseInt($(this).val()) > 0) threshold[this.id.substring(0, this.id.lastIndexOf("_"))] = $(this).val(); }); - if (i !== 0) - callsetids.push(getSelectedIndividuals([i + 1], true)); - annotationFieldThresholds.push(threshold); + query.annotationFieldThresholds.push(threshold); } - - query["annotationFieldThresholds"] = annotationFieldThresholds; - query["additionalCallSetIds"] = callsetids; - return query; } @@ -515,9 +520,8 @@ function displayChart(minPos, maxPos) { var displayedSequence = $("select#chartSequenceList").val(); var displayedVariantType = $("select#chartVariantTypeList").val(); var dataPayLoad = buildDataPayLoad(displayedSequence, displayedVariantType); - if (chartInfo.buildRequestPayload !== undefined) - dataPayLoad = chartInfo.buildRequestPayload(dataPayLoad); - if (dataPayLoad === null) return; + if (dataPayLoad === null) + return; calculateObjectHash(dataPayLoad) .then(hash => { @@ -712,7 +716,7 @@ function displayResult(chartInfo, jsonResult, displayedVariantType, displayedSeq $("div#chartContainer div#additionalCharts").toggle(!isNaN(intervalSize)); if (!isNaN(intervalSize)) - $('.showHideSeriesBox').change(); + $('input.showHideSeriesBox:checked').change(); if (chartInfo.onDisplay !== undefined) chartInfo.onDisplay(); @@ -726,8 +730,7 @@ function addMetadataSeries(minPos, maxPos, fieldName, colorIndex) { var displayedVariantType = $("select#chartVariantTypeList").val(); var dataPayLoad = buildDataPayLoad(displayedSequence, displayedVariantType); dataPayLoad["vcfField"] = fieldName; - dataPayLoad["plotIndividuals"] = $('#plotIndividualSelectionMode').val() == "choose" ? $('#plotIndividualSelectionMode').parent().parent().find("select.individualSelector").val() : ($('#plotIndividualSelectionMode').val() == "allGroups" ? getSelectedIndividuals() : ($('#plotIndividualSelectionMode').val() == "" ? [] : getSelectedIndividuals([parseInt($('#plotIndividualSelectionMode').val())]))) - + $.ajax({ url: 'rest/gigwa/vcfFieldPlotData/' + encodeURIComponent($('#project :selected').data("id")), type: "POST", @@ -885,6 +888,12 @@ function checkChartLoadingProgress() { function displayOrHideSeries(fieldName, isChecked, colorIndex) { if (chart === null) return; + + if (isChecked && $("select#plotGroupingMetadataValues").val() == null) { + alert("You must select some individuals to show this series"); + $("input#chartVCFSeries_" + fieldName).prop("checked", false); + return; + } $('.showHideSeriesBox').prop('disabled', true); if (isChecked) { @@ -947,11 +956,10 @@ function setFstThreshold(){ } } -function setFstGroupingOption() { +function updateAvailableGroups() { const option = $("#plotGroupingSelectionMode").find(":selected").val(); let fieldValues = new Set(); let selectedIndividuals = getSelectedIndividuals(); - $("#plotMetadata").css("display", "block"); const groupSelect = $("select#plotGroupingMetadataValues"); if (option != "__") $.ajax({ @@ -961,9 +969,12 @@ function setFstGroupingOption() { contentType: "application/json;charset=utf-8", headers: buildHeader(token, $('#assembly').val()), success: function (metaDataValues) { - metaDataValues[option].forEach(function (mdVal) { - fieldValues.add(mdVal); - }); + $("#chartGroupSelectionDesc").css("visibility", selectedIndividuals.length == 0 || selectedIndividuals.length == indOpt.length ? "hidden" : "visible"); + + if (Object.keys(metaDataValues).length > 0) + metaDataValues[option].forEach(function (mdVal) { + fieldValues.add(mdVal); + }); let selectOptions = ""; let orderedValues = Array.from(fieldValues.values()); @@ -976,12 +987,13 @@ function setFstGroupingOption() { } }); else { + $("#chartGroupSelectionDesc").css("visibility", "hidden"); let selectOptions = ""; for (var i=1; i<=getGenotypeInvestigationMode(); i++) selectOptions += ''; - groupSelect.html(selectOptions); + $("select#plotGroupingMetadataValues").html(selectOptions); if (!areGroupsOverlapping(groupSelect.val())) - groupSelect.find('option').prop('selected', true); + $("select#plotGroupingMetadataValues").find('option').prop('selected', true); groupSelect.change(); } }