function renderMessages(id, messages) { if (messages && messages.length > 0) { let errorDiv = document.createElement('div'); let style='padding: 10px; background-color: #ffe5e5;' style+='color: #d83f48; font-weight: bold;'; errorDiv.setAttribute('style', style); errorDiv.innerHTML = messages.join('<br/>'); document.getElementById(id).appendChild(errorDiv); } }; function validateChartConfig(chartConfig, aes, scales, measureStore) { let hasNoDataMsg = LABKEY.vis.GenericChartHelper.validateResponseHasData(measureStore, false); if (hasNoDataMsg != null) return {"success": false, "messages": [hasNoDataMsg]}; let measureNames = Object.keys(chartConfig.measures); for (let i = 0; i < measureNames.length; i++) { let measureProps = chartConfig.measures[measureNames[i]]; if (measureProps && measureProps.name && measureStore.records()[0][measureProps.name] == undefined){ let retVal=new Object(); retVal.success=false; retVal.messages=['The measure, ' + measureProps.label + ', is not available. It may have been renamed or removed.'] return retVal; } } let messages = []; let axisMeasureNames = ['x', 'xSub', 'y']; for (let i = 0; i < axisMeasureNames.length; i++) { if (measureNames.indexOf(axisMeasureNames[i]) > 0) { let validation = LABKEY.vis.GenericChartHelper.validateAxisMeasure( chartConfig.renderType, chartConfig, axisMeasureNames[i], aes, scales, measureStore.records()); if (validation.message != null) messages.push(validation.message); if (!validation.success) return {"success": false, "messages": messages}; } } return {"success": true, "messages": messages}; } function selectRowsCallback(renderConfig, measureStore) { let responseMetaData = measureStore.getResponseMetadata(); for (let f in measureStore) document.getElementById('debugCode').value+='\n '+f+' '+typeof(f); let record=measureStore.records()[1]; for (let f in record) document.getElementById('debugCode').value+='\n '+f+ ' ' +typeof(f); //try something stupid let participantField=document.getElementById('participantField').innerHTML; let participantCode=document.getElementById('participantCode').innerHTML; let visitField=document.getElementById('visitField').innerHTML; let visitCode=document.getElementById('visitCode').innerHTML; let selectedParticipantData=new Array(); let otherParticipantData=new Array(); let i=0; let maxValue=-1e30; while (i<measureStore.records().length){ let record=measureStore.records()[i]; //document.getElementById('debugCode').value+='\n '+record[participantField].value; let pMatch=record[participantField].value==participantCode; let vMatch=true; if (visitField in record) vMatch=record[visitField].value==visitCode; let sMatch=true; if ('SequenceNum' in record) sMatch=record['SequenceNum'].value<renderConfig.visitThreshold; if (pMatch && vMatch) { if (sMatch) selectedParticipantData.push(record); measureStore.records().splice(i,1); if (!sMatch) continue; if (record['value'].value>maxValue) maxValue=record['value'].value; continue; } record[participantField].value=renderConfig.labelOthers; if (!pMatch || sMatch) otherParticipantData.push(record); measureStore.records().splice(i,1); } document.getElementById('debugCode').value+='\nrecords: '+otherParticipantData.length; document.getElementById('debugCode').value+='\nownData: '+selectedParticipantData.length; document.getElementById('debugCode').value+='\nmaxValue: '+maxValue; for (let i=0;i<otherParticipantData.length;i++) measureStore.records().push(otherParticipantData[i]); for (let i=0;i<selectedParticipantData.length;i++) measureStore.records().push(selectedParticipantData[i]); // chartConfig is the saved information about the chart (labels, scales, etc.) let chartConfig = new Object(); chartConfig.renderType="line_plot"; let mX=new Object(); mX.displayFieldJsonType=""; mX.hidden=false; mX.fieldKey="percentile"; mX.label="Percentile"; mX.schemaName="study"; mX.type="float"; mX.normalizedType="float"; mX.measure=true; mX.name="percentile"; mX.queryName="SUVQuantiles"; mX.alias="percentile"; mX.shortCaption="Percentile"; mX.dimension=false; document.getElementById('debugCode').value+='\nplot: '+renderConfig.plot; if (renderConfig.plot=="time"){ mX.fieldKey="SequenceNum"; mX.label="Visit ID"; mX.name="SequenceNum"; mX.alias="Visit"; mX.shortCaption="Visit ID"; } let mY=new Object(); mY.displayFieldJsonType=""; mY.hidden=false; mY.fieldKey="value"; mY.label="SUV Value"; mY.schemaName="study"; mY.type="float"; mY.normalizedType="float"; mY.measure=true; mY.name="value"; mY.queryName="SUVQuantiles"; mY.alias="value"; mY.shortCaption="Value"; mY.dimension=false; let mS=new Object(); mS.displayFieldJsonType=""; mS.hidden=false; mS.fieldKey=participantField; mS.label="Participant ID"; mS.schemaName="study"; mS.type="string"; mS.normalizedType="string"; mS.measure=false; mS.name=participantField; mS.queryName="SUVQuantiles"; mS.alias=participantField; mS.shortCaption="Participant ID"; mS.dimension=true; chartConfig.measures=new Object(); chartConfig.measures.x=mX; chartConfig.measures.y=mY; chartConfig.measures.series=mS; chartConfig.measures.pointClickFn=null; chartConfig.scales=new Object(); chartConfig.scales.x=new Object(); chartConfig.scales.x.trans="linear"; chartConfig.scales.y=new Object(); chartConfig.scales.y.trans="linear"; chartConfig.scales.y.min=0; chartConfig.scales.y.max=renderConfig.max; if (renderConfig.max<0) chartConfig.scales.y.max=1.5*maxValue; chartConfig.labels=new Object(); chartConfig.labels.main=renderConfig.title; chartConfig.labels.subtitle=""; chartConfig.labels.x="Percentile"; chartConfig.labels.y="SUV Value"; chartConfig.width=null; chartConfig.height=null; chartConfig.pointType="outliers"; chartConfig.geomOptions=new Object(); chartConfig.geomOptions.label="SUVQuantiles"; chartConfig.geomOptions.subtitle=""; chartConfig.geomOptions.width=null; chartConfig.geomOptions.height=null; chartConfig.geomOptions.pointType="outliers"; chartConfig.geomOptions.pointFillColor="111111"; chartConfig.geomOptions.lineWidth=2; chartConfig.pointFillColor="111111"; chartConfig.lineWidth="3"; chartConfig.lineColor="000000"; chartConfig.boxFillColor="3366FF"; chartConfig.hideDataPoints=false; // chartConfig.colorPaletteScale="ColorDiscrete"; chartConfig.geomOptions.colorPaletteScale="Light"; chartConfig.chartLayout="single"; chartConfig.chartSubjectSelection="subjects"; chartConfig.displayIndividual=true; chartConfig.displayAggregate=false; chartConfig.errorBars="None"; chartConfig.pieInnerRadius=0; chartConfig.pieOuterRadius=80; chartConfig.showPiePercentages=true; chartConfig.pieHideWhenLessThanPercentage=5; chartConfig.piePercentagesColor="333333"; chartConfig.gradientPercentage=95; chartConfig.gradientColor="FFFFFF"; chartConfig.binThreshold=10000; chartConfig.binShapeGroup="hex"; chartConfig.binColorGroup="BlueWhite"; chartConfig.binSingleColor="000000"; chartConfig.showOutliers=true; chartConfig.binShape="hex"; chartConfig.labels.x="Percentile"; if (renderConfig.plot=="time"){ chartConfig.labels.x="Visit ID"; chartConfig.labels.y="SUV"+renderConfig.suv+"%"; } if (!chartConfig.hasOwnProperty('width') || chartConfig.width == null) chartConfig.width = 1000; if (!chartConfig.hasOwnProperty('height') || chartConfig.height == null) chartConfig.height = 600; if (renderConfig.hasOwnProperty('width')){ chartConfig.width=renderConfig.width; chartConfig.height=0.6*renderConfig.width; } let xAxisType = chartConfig.measures.x ? ( chartConfig.measures.x.normalizedType || chartConfig.measures.x.type) : null; let chartType = LABKEY.vis.GenericChartHelper.getChartType( chartConfig.renderType, xAxisType); let aes = LABKEY.vis.GenericChartHelper.generateAes( chartType, chartConfig.measures, responseMetaData.schemaName, responseMetaData.queryName); let valueConversionResponse = LABKEY.vis.GenericChartHelper.doValueConversion( chartConfig, aes, chartType, measureStore.records()); if (!Ext4.Object.isEmpty(valueConversionResponse.processed)) { Ext4.Object.merge(chartConfig.measures, valueConversionResponse.processed); aes = LABKEY.vis.GenericChartHelper.generateAes( chartType, chartConfig.measures, responseMetaData.schemaName, responseMetaData.queryName); } let data = measureStore.records(); if (chartType == 'scatter_plot' && data.length > chartConfig.geomOptions.binThreshold) { chartConfig.geomOptions.binned = true; } let scales = LABKEY.vis.GenericChartHelper.generateScales( chartType, chartConfig.measures, chartConfig.scales, aes, measureStore); let geom = LABKEY.vis.GenericChartHelper.generateGeom( chartType, chartConfig.geomOptions); document.getElementById('debugCode').value+='\n geom color '+geom.color; let labels = LABKEY.vis.GenericChartHelper.generateLabels( chartConfig.labels); if (chartType == 'bar_chart' || chartType == 'pie_chart') { let dimName = null, subDimName = null; measureName = null, aggType = 'COUNT'; if (chartConfig.measures.x) { dimName = chartConfig.measures.x.converted ? chartConfig.measures.x.convertedName : chartConfig.measures.x.name; } if (chartConfig.measures.xSub) { subDimName = chartConfig.measures.xSub.converted ? chartConfig.measures.xSub.convertedName : chartConfig.measures.xSub.name; } if (chartConfig.measures.y) { measureName = chartConfig.measures.y.converted ? chartConfig.measures.y.convertedName : chartConfig.measures.y.name; if (Ext4.isDefined(chartConfig.measures.y.aggregate)) { aggType = chartConfig.measures.y.aggregate; } else if (measureName != null) { aggType = 'SUM'; } } data = LABKEY.vis.getAggregateData(data, dimName, subDimName, measureName, aggType, '[Blank]', false); } let plotConfig = LABKEY.vis.GenericChartHelper.generatePlotConfig( renderConfig.chartId,chartConfig, labels, aes, scales, geom, data); document.getElementById('debugCode').value+='\n plotConfig layers: '+plotConfig.layers.length; for (let i=0;i<plotConfig.layers.length;i++){ let l=plotConfig.layers[i]; document.getElementById('debugCode').value+='\n color: '+l.aes.pathColor; if (l.data===null) continue; document.getElementById('debugCode').value+='\n data: '+l.data.length; } let validation = validateChartConfig(chartConfig, aes, scales, measureStore); renderMessages(renderConfig.chartId, validation.messages); if (!validation.success) return; let plot; if (chartType == 'pie_chart') { new LABKEY.vis.PieChart(plotConfig); } else { plot = new LABKEY.vis.Plot(plotConfig); plot.render(); } } function plotAll() { let participantField=document.getElementById('participantField').innerHTML; let visitField=document.getElementById('visitField').innerHTML; document.getElementById('debugCode').value+='\n'+participantField; let organs=["3","4","5"]; for (let i=0;i < organs.length; i++){ let renderConfig=new Object(); //all additional configuration stuff goes in here renderConfig.chartId='SUVall_organ'+organs[i]; renderConfig.width=500; renderConfig.participantCode=document.getElementById("participantCode").innerHTML; renderConfig.visitCode=document.getElementById("visitCode").innerHTML; renderConfig.labelOthers='other visits/participants'; renderConfig.plot="percentile"; renderConfig.max=10; renderConfig.title="SUV cumulative distribution"; // When all the dependencies are loaded we then load the data via the MeasureStore selectRows API. // The queryConfig object stores all the information needed to make a selectRows request let queryConfig = new Object; queryConfig.schemaName="study"; queryConfig.queryName="SUVQuantiles"; queryConfig.viewName=null; queryConfig.dataRegionName="Dataset"; queryConfig.queryLabel="SUVQuantiles"; queryConfig.parameters= new Object(); queryConfig.requiredVersion=13.2; queryConfig.maxRows=-1; queryConfig.sort="lsid"; queryConfig.method="POST"; queryConfig.columns=["percentile","value",participantField,visitField]; queryConfig.filterArray=new Array(); //queryConfig.filterArray.push({ // "name":"patientCode", // "value":renderConfig.participantCode, // "type":"eq"}); //queryConfig.filterArray.push({ // "name":"visitCode", // "value":renderConfig.visitCode, // "type":"eq"}); queryConfig.filterArray.push({ "name":"organ", "value":organs[i], "type":"eq"}); if (queryConfig.filterArray && queryConfig.filterArray.length > 0) { let filters = []; for (let i = 0; i < queryConfig.filterArray.length; i++) { let f = queryConfig.filterArray[i]; filters.push(LABKEY.Filter.create( f.name, f.value, LABKEY.Filter.getFilterTypeForURLSuffix(f.type))); } queryConfig.filterArray = filters; } queryConfig.success = function(data){ selectRowsCallback(renderConfig,data);}; queryConfig.containerPath = LABKEY.ActionURL.getContainer(); LABKEY.Query.MeasureStore.selectRows(queryConfig); } }; function plotParticipant() { let participantField=document.getElementById('participantField').innerHTML; let participantCode=document.getElementById('participantCode').innerHTML; let visitField=document.getElementById('visitField').innerHTML; let visitCode=document.getElementById('visitCode').innerHTML; let visitValue=parseInt(visitCode.split('_')[1])+1; document.getElementById('debugCode').value+='\n'+visitValue; let organs=["3","4","5"]; for (let i=0;i < organs.length; i++){ let renderConfig=new Object(); //all additional configuration stuff goes in here renderConfig.chartId='SUVparticipant_organ'+organs[i]; renderConfig.width=500; renderConfig.participantCode=document.getElementById("participantCode").innerHTML; renderConfig.visitCode=document.getElementById("visitCode").innerHTML; renderConfig.labelOthers='other visits'; renderConfig.plot="percentile"; renderConfig.max=10; renderConfig.title="SUV cumulative distribution"; renderConfig.visitThreshold=visitValue; // When all the dependencies are loaded we then load the data via the MeasureStore selectRows API. // The queryConfig object stores all the information needed to make a selectRows request let queryConfig = new Object; queryConfig.schemaName="study"; queryConfig.queryName="SUVQuantiles"; queryConfig.viewName=null; queryConfig.dataRegionName="Dataset"; queryConfig.queryLabel="SUVQuantiles"; queryConfig.parameters= new Object(); queryConfig.requiredVersion=13.2; queryConfig.maxRows=-1; queryConfig.sort="lsid"; queryConfig.method="POST"; queryConfig.columns=["SequenceNum","percentile","value",participantField,visitField]; queryConfig.filterArray=new Array(); queryConfig.filterArray.push({ "name":"patientCode", "value":renderConfig.participantCode, "type":"eq"}); //queryConfig.filterArray.push({ // "name":"visitCode", // "value":renderConfig.visitCode, // "type":"eq"}); queryConfig.filterArray.push({ "name":"organ", "value":organs[i], "type":"eq"}); if (queryConfig.filterArray && queryConfig.filterArray.length > 0) { let filters = []; for (let i = 0; i < queryConfig.filterArray.length; i++) { let f = queryConfig.filterArray[i]; filters.push(LABKEY.Filter.create( f.name, f.value, LABKEY.Filter.getFilterTypeForURLSuffix(f.type))); } queryConfig.filterArray = filters; } queryConfig.success = function(data){ selectRowsCallback(renderConfig,data);}; queryConfig.containerPath=LABKEY.ActionURL.getContainer(); LABKEY.Query.MeasureStore.selectRows(queryConfig); } }; function plotTime() { let participantField=document.getElementById('participantField').innerHTML; let participantCode=document.getElementById('participantCode').innerHTML; let visitField=document.getElementById('visitField').innerHTML; let visitCode=document.getElementById('visitCode').innerHTML; let visitValue=parseInt(visitCode.split('_')[1])+1; document.getElementById('debugCode').value+='\n'+visitValue; let organs=["3","4","5"]; for (let i=0;i < organs.length; i++){ let renderConfig=new Object(); //all additional configuration stuff goes in here renderConfig.chartId='SUVparticipant_organ'+organs[i]; renderConfig.width=500; renderConfig.participantCode=document.getElementById("participantCode").innerHTML; renderConfig.visitCode=document.getElementById("visitCode").innerHTML; renderConfig.labelOthers='others'; renderConfig.suv=95; renderConfig.plot="time"; if (organs[i]=="4") renderConfig.suv=70; renderConfig.max=-1; renderConfig.visitThreshold=visitValue; renderConfig.title="Quantitative inflamation time-curve"; // When all the dependencies are loaded we then load the data via the MeasureStore selectRows API. // The queryConfig object stores all the information needed to make a selectRows request let queryConfig = new Object; queryConfig.schemaName="study"; queryConfig.queryName="SUVQuantiles"; queryConfig.viewName=null; queryConfig.dataRegionName="Dataset"; queryConfig.queryLabel="SUVQuantiles"; queryConfig.parameters= new Object(); queryConfig.requiredVersion=13.2; queryConfig.maxRows=-1; queryConfig.sort="lsid"; queryConfig.method="POST"; queryConfig.columns=["SequenceNum","value",participantField]; queryConfig.filterArray=new Array(); //queryConfig.filterArray.push({ // "name":"patientCode", // "value":renderConfig.participantCode, // "type":"eq"}); queryConfig.filterArray.push({ "name":"percentile", "value":renderConfig.suv, "type":"eq"}); queryConfig.filterArray.push({ "name":"organ", "value":organs[i], "type":"eq"}); if (queryConfig.filterArray && queryConfig.filterArray.length > 0) { let filters = []; for (let i = 0; i < queryConfig.filterArray.length; i++) { let f = queryConfig.filterArray[i]; filters.push(LABKEY.Filter.create( f.name, f.value, LABKEY.Filter.getFilterTypeForURLSuffix(f.type))); } queryConfig.filterArray = filters; } queryConfig.success = function(data){ selectRowsCallback(renderConfig,data);}; queryConfig.containerPath = LABKEY.ActionURL.getContainer(); LABKEY.Query.MeasureStore.selectRows(queryConfig); } };