crfReview.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. function renderMessages(id, messages) {
  2. if (messages && messages.length > 0) {
  3. let errorDiv = document.createElement('div');
  4. let style='padding: 10px; background-color: #ffe5e5;'
  5. style+='color: #d83f48; font-weight: bold;';
  6. errorDiv.setAttribute('style', style);
  7. errorDiv.innerHTML = messages.join('<br/>');
  8. document.getElementById(id).appendChild(errorDiv);
  9. }
  10. };
  11. function validateChartConfig(chartConfig, aes, scales, measureStore) {
  12. let hasNoDataMsg = LABKEY.vis.GenericChartHelper.validateResponseHasData(measureStore, false);
  13. if (hasNoDataMsg != null)
  14. return {"success": false, "messages": [hasNoDataMsg]};
  15. let measureNames = Object.keys(chartConfig.measures);
  16. for (let i = 0; i < measureNames.length; i++) {
  17. let measureProps = chartConfig.measures[measureNames[i]];
  18. if (measureProps &&
  19. measureProps.name &&
  20. measureStore.records()[0][measureProps.name] == undefined){
  21. let retVal=new Object();
  22. retVal.success=false;
  23. retVal.messages=['The measure, ' +
  24. measureProps.label +
  25. ', is not available. It may have been renamed or removed.']
  26. return retVal;
  27. }
  28. }
  29. let messages = [];
  30. let axisMeasureNames = ['x', 'xSub', 'y'];
  31. for (let i = 0; i < axisMeasureNames.length; i++) {
  32. if (measureNames.indexOf(axisMeasureNames[i]) > 0) {
  33. let validation = LABKEY.vis.GenericChartHelper.validateAxisMeasure(
  34. chartConfig.renderType, chartConfig, axisMeasureNames[i],
  35. aes, scales, measureStore.records());
  36. if (validation.message != null)
  37. messages.push(validation.message);
  38. if (!validation.success)
  39. return {"success": false, "messages": messages};
  40. }
  41. }
  42. return {"success": true, "messages": messages};
  43. }
  44. function selectRowsCallback(renderConfig, measureStore) {
  45. let responseMetaData = measureStore.getResponseMetadata();
  46. for (let f in measureStore)
  47. document.getElementById('debugCode').value+='\n '+f+' '+typeof(f);
  48. let record=measureStore.records()[1];
  49. for (let f in record)
  50. document.getElementById('debugCode').value+='\n '+f+ ' ' +typeof(f);
  51. //try something stupid
  52. let participantField=document.getElementById('participantField').innerHTML;
  53. let participantCode=document.getElementById('participantCode').innerHTML;
  54. let visitField=document.getElementById('visitField').innerHTML;
  55. let visitCode=document.getElementById('visitCode').innerHTML;
  56. let selectedParticipantData=new Array();
  57. let otherParticipantData=new Array();
  58. let i=0;
  59. let maxValue=-1e30;
  60. while (i<measureStore.records().length){
  61. let record=measureStore.records()[i];
  62. //document.getElementById('debugCode').value+='\n '+record[participantField].value;
  63. let pMatch=record[participantField].value==participantCode;
  64. let vMatch=true;
  65. if (visitField in record)
  66. vMatch=record[visitField].value==visitCode;
  67. let sMatch=true;
  68. if ('SequenceNum' in record)
  69. sMatch=record['SequenceNum'].value<renderConfig.visitThreshold;
  70. if (pMatch && vMatch) {
  71. if (sMatch)
  72. selectedParticipantData.push(record);
  73. measureStore.records().splice(i,1);
  74. if (!sMatch)
  75. continue;
  76. if (record['value'].value>maxValue)
  77. maxValue=record['value'].value;
  78. continue;
  79. }
  80. record[participantField].value=renderConfig.labelOthers;
  81. if (!pMatch || sMatch) otherParticipantData.push(record);
  82. measureStore.records().splice(i,1);
  83. }
  84. document.getElementById('debugCode').value+='\nrecords: '+otherParticipantData.length;
  85. document.getElementById('debugCode').value+='\nownData: '+selectedParticipantData.length;
  86. document.getElementById('debugCode').value+='\nmaxValue: '+maxValue;
  87. for (let i=0;i<otherParticipantData.length;i++)
  88. measureStore.records().push(otherParticipantData[i]);
  89. for (let i=0;i<selectedParticipantData.length;i++)
  90. measureStore.records().push(selectedParticipantData[i]);
  91. // chartConfig is the saved information about the chart (labels, scales, etc.)
  92. let chartConfig = new Object();
  93. chartConfig.renderType="line_plot";
  94. let mX=new Object();
  95. mX.displayFieldJsonType="";
  96. mX.hidden=false;
  97. mX.fieldKey="percentile";
  98. mX.label="Percentile";
  99. mX.schemaName="study";
  100. mX.type="float";
  101. mX.normalizedType="float";
  102. mX.measure=true;
  103. mX.name="percentile";
  104. mX.queryName="SUVQuantiles";
  105. mX.alias="percentile";
  106. mX.shortCaption="Percentile";
  107. mX.dimension=false;
  108. document.getElementById('debugCode').value+='\nplot: '+renderConfig.plot;
  109. if (renderConfig.plot=="time"){
  110. mX.fieldKey="SequenceNum";
  111. mX.label="Visit ID";
  112. mX.name="SequenceNum";
  113. mX.alias="Visit";
  114. mX.shortCaption="Visit ID";
  115. }
  116. let mY=new Object();
  117. mY.displayFieldJsonType="";
  118. mY.hidden=false;
  119. mY.fieldKey="value";
  120. mY.label="SUV Value";
  121. mY.schemaName="study";
  122. mY.type="float";
  123. mY.normalizedType="float";
  124. mY.measure=true;
  125. mY.name="value";
  126. mY.queryName="SUVQuantiles";
  127. mY.alias="value";
  128. mY.shortCaption="Value";
  129. mY.dimension=false;
  130. let mS=new Object();
  131. mS.displayFieldJsonType="";
  132. mS.hidden=false;
  133. mS.fieldKey=participantField;
  134. mS.label="Participant ID";
  135. mS.schemaName="study";
  136. mS.type="string";
  137. mS.normalizedType="string";
  138. mS.measure=false;
  139. mS.name=participantField;
  140. mS.queryName="SUVQuantiles";
  141. mS.alias=participantField;
  142. mS.shortCaption="Participant ID";
  143. mS.dimension=true;
  144. chartConfig.measures=new Object();
  145. chartConfig.measures.x=mX;
  146. chartConfig.measures.y=mY;
  147. chartConfig.measures.series=mS;
  148. chartConfig.measures.pointClickFn=null;
  149. chartConfig.scales=new Object();
  150. chartConfig.scales.x=new Object();
  151. chartConfig.scales.x.trans="linear";
  152. chartConfig.scales.y=new Object();
  153. chartConfig.scales.y.trans="linear";
  154. chartConfig.scales.y.min=0;
  155. chartConfig.scales.y.max=renderConfig.max;
  156. if (renderConfig.max<0)
  157. chartConfig.scales.y.max=1.5*maxValue;
  158. chartConfig.labels=new Object();
  159. chartConfig.labels.main=renderConfig.title;
  160. chartConfig.labels.subtitle="";
  161. chartConfig.labels.x="Percentile";
  162. chartConfig.labels.y="SUV Value";
  163. chartConfig.width=null;
  164. chartConfig.height=null;
  165. chartConfig.pointType="outliers";
  166. chartConfig.geomOptions=new Object();
  167. chartConfig.geomOptions.label="SUVQuantiles";
  168. chartConfig.geomOptions.subtitle="";
  169. chartConfig.geomOptions.width=null;
  170. chartConfig.geomOptions.height=null;
  171. chartConfig.geomOptions.pointType="outliers";
  172. chartConfig.geomOptions.pointFillColor="111111";
  173. chartConfig.geomOptions.lineWidth=2;
  174. chartConfig.pointFillColor="111111";
  175. chartConfig.lineWidth="3";
  176. chartConfig.lineColor="000000";
  177. chartConfig.boxFillColor="3366FF";
  178. chartConfig.hideDataPoints=false;
  179. // chartConfig.colorPaletteScale="ColorDiscrete";
  180. chartConfig.geomOptions.colorPaletteScale="Light";
  181. chartConfig.chartLayout="single";
  182. chartConfig.chartSubjectSelection="subjects";
  183. chartConfig.displayIndividual=true;
  184. chartConfig.displayAggregate=false;
  185. chartConfig.errorBars="None";
  186. chartConfig.pieInnerRadius=0;
  187. chartConfig.pieOuterRadius=80;
  188. chartConfig.showPiePercentages=true;
  189. chartConfig.pieHideWhenLessThanPercentage=5;
  190. chartConfig.piePercentagesColor="333333";
  191. chartConfig.gradientPercentage=95;
  192. chartConfig.gradientColor="FFFFFF";
  193. chartConfig.binThreshold=10000;
  194. chartConfig.binShapeGroup="hex";
  195. chartConfig.binColorGroup="BlueWhite";
  196. chartConfig.binSingleColor="000000";
  197. chartConfig.showOutliers=true;
  198. chartConfig.binShape="hex";
  199. chartConfig.labels.x="Percentile";
  200. if (renderConfig.plot=="time"){
  201. chartConfig.labels.x="Visit ID";
  202. chartConfig.labels.y="SUV"+renderConfig.suv+"%";
  203. }
  204. if (!chartConfig.hasOwnProperty('width') ||
  205. chartConfig.width == null)
  206. chartConfig.width = 1000;
  207. if (!chartConfig.hasOwnProperty('height') ||
  208. chartConfig.height == null)
  209. chartConfig.height = 600;
  210. if (renderConfig.hasOwnProperty('width')){
  211. chartConfig.width=renderConfig.width;
  212. chartConfig.height=0.6*renderConfig.width;
  213. }
  214. let xAxisType = chartConfig.measures.x ? (
  215. chartConfig.measures.x.normalizedType ||
  216. chartConfig.measures.x.type) : null;
  217. let chartType = LABKEY.vis.GenericChartHelper.getChartType(
  218. chartConfig.renderType, xAxisType);
  219. let aes = LABKEY.vis.GenericChartHelper.generateAes(
  220. chartType, chartConfig.measures,
  221. responseMetaData.schemaName, responseMetaData.queryName);
  222. let valueConversionResponse =
  223. LABKEY.vis.GenericChartHelper.doValueConversion(
  224. chartConfig, aes, chartType, measureStore.records());
  225. if (!Ext4.Object.isEmpty(valueConversionResponse.processed)) {
  226. Ext4.Object.merge(chartConfig.measures,
  227. valueConversionResponse.processed);
  228. aes = LABKEY.vis.GenericChartHelper.generateAes(
  229. chartType, chartConfig.measures,
  230. responseMetaData.schemaName, responseMetaData.queryName);
  231. }
  232. let data = measureStore.records();
  233. if (chartType == 'scatter_plot' &&
  234. data.length > chartConfig.geomOptions.binThreshold) {
  235. chartConfig.geomOptions.binned = true;
  236. }
  237. let scales = LABKEY.vis.GenericChartHelper.generateScales(
  238. chartType, chartConfig.measures, chartConfig.scales,
  239. aes, measureStore);
  240. let geom = LABKEY.vis.GenericChartHelper.generateGeom(
  241. chartType, chartConfig.geomOptions);
  242. document.getElementById('debugCode').value+='\n geom color '+geom.color;
  243. let labels = LABKEY.vis.GenericChartHelper.generateLabels(
  244. chartConfig.labels);
  245. if (chartType == 'bar_chart' || chartType == 'pie_chart') {
  246. let dimName = null, subDimName = null; measureName = null,
  247. aggType = 'COUNT';
  248. if (chartConfig.measures.x) {
  249. dimName = chartConfig.measures.x.converted ?
  250. chartConfig.measures.x.convertedName :
  251. chartConfig.measures.x.name;
  252. }
  253. if (chartConfig.measures.xSub) {
  254. subDimName = chartConfig.measures.xSub.converted ?
  255. chartConfig.measures.xSub.convertedName :
  256. chartConfig.measures.xSub.name;
  257. }
  258. if (chartConfig.measures.y) {
  259. measureName = chartConfig.measures.y.converted ?
  260. chartConfig.measures.y.convertedName :
  261. chartConfig.measures.y.name;
  262. if (Ext4.isDefined(chartConfig.measures.y.aggregate)) {
  263. aggType = chartConfig.measures.y.aggregate;
  264. }
  265. else if (measureName != null) {
  266. aggType = 'SUM';
  267. }
  268. }
  269. data = LABKEY.vis.getAggregateData(data, dimName, subDimName,
  270. measureName, aggType, '[Blank]', false);
  271. }
  272. let plotConfig = LABKEY.vis.GenericChartHelper.generatePlotConfig(
  273. renderConfig.chartId,chartConfig, labels, aes, scales, geom, data);
  274. document.getElementById('debugCode').value+='\n plotConfig layers: '+plotConfig.layers.length;
  275. for (let i=0;i<plotConfig.layers.length;i++){
  276. let l=plotConfig.layers[i];
  277. document.getElementById('debugCode').value+='\n color: '+l.aes.pathColor;
  278. if (l.data===null)
  279. continue;
  280. document.getElementById('debugCode').value+='\n data: '+l.data.length;
  281. }
  282. let validation = validateChartConfig(chartConfig, aes, scales, measureStore);
  283. renderMessages(renderConfig.chartId, validation.messages);
  284. if (!validation.success)
  285. return;
  286. let plot;
  287. if (chartType == 'pie_chart') {
  288. new LABKEY.vis.PieChart(plotConfig);
  289. }
  290. else {
  291. plot = new LABKEY.vis.Plot(plotConfig);
  292. plot.render();
  293. }
  294. }
  295. function plotAll() {
  296. let participantField=document.getElementById('participantField').innerHTML;
  297. let visitField=document.getElementById('visitField').innerHTML;
  298. document.getElementById('debugCode').value+='\n'+participantField;
  299. let organs=["3","4","5"];
  300. for (let i=0;i < organs.length; i++){
  301. let renderConfig=new Object();
  302. //all additional configuration stuff goes in here
  303. renderConfig.chartId='SUVall_organ'+organs[i];
  304. renderConfig.width=500;
  305. renderConfig.participantCode=document.getElementById("participantCode").innerHTML;
  306. renderConfig.visitCode=document.getElementById("visitCode").innerHTML;
  307. renderConfig.labelOthers='other visits/participants';
  308. renderConfig.plot="percentile";
  309. renderConfig.max=10;
  310. renderConfig.title="SUV cumulative distribution";
  311. // When all the dependencies are loaded we then load the data via the MeasureStore selectRows API.
  312. // The queryConfig object stores all the information needed to make a selectRows request
  313. let queryConfig = new Object;
  314. queryConfig.schemaName="study";
  315. queryConfig.queryName="SUVQuantiles";
  316. queryConfig.viewName=null;
  317. queryConfig.dataRegionName="Dataset";
  318. queryConfig.queryLabel="SUVQuantiles";
  319. queryConfig.parameters= new Object();
  320. queryConfig.requiredVersion=13.2;
  321. queryConfig.maxRows=-1;
  322. queryConfig.sort="lsid";
  323. queryConfig.method="POST";
  324. queryConfig.columns=["percentile","value",participantField,visitField];
  325. queryConfig.filterArray=new Array();
  326. //queryConfig.filterArray.push({
  327. // "name":"patientCode",
  328. // "value":renderConfig.participantCode,
  329. // "type":"eq"});
  330. //queryConfig.filterArray.push({
  331. // "name":"visitCode",
  332. // "value":renderConfig.visitCode,
  333. // "type":"eq"});
  334. queryConfig.filterArray.push({
  335. "name":"organ",
  336. "value":organs[i],
  337. "type":"eq"});
  338. if (queryConfig.filterArray &&
  339. queryConfig.filterArray.length > 0) {
  340. let filters = [];
  341. for (let i = 0; i < queryConfig.filterArray.length; i++) {
  342. let f = queryConfig.filterArray[i];
  343. filters.push(LABKEY.Filter.create(
  344. f.name, f.value,
  345. LABKEY.Filter.getFilterTypeForURLSuffix(f.type)));
  346. }
  347. queryConfig.filterArray = filters;
  348. }
  349. queryConfig.success = function(data){
  350. selectRowsCallback(renderConfig,data);};
  351. queryConfig.containerPath = LABKEY.ActionURL.getContainer();
  352. LABKEY.Query.MeasureStore.selectRows(queryConfig);
  353. }
  354. };
  355. function plotParticipant() {
  356. let participantField=document.getElementById('participantField').innerHTML;
  357. let participantCode=document.getElementById('participantCode').innerHTML;
  358. let visitField=document.getElementById('visitField').innerHTML;
  359. let visitCode=document.getElementById('visitCode').innerHTML;
  360. let visitValue=parseInt(visitCode.split('_')[1])+1;
  361. document.getElementById('debugCode').value+='\n'+visitValue;
  362. let organs=["3","4","5"];
  363. for (let i=0;i < organs.length; i++){
  364. let renderConfig=new Object();
  365. //all additional configuration stuff goes in here
  366. renderConfig.chartId='SUVparticipant_organ'+organs[i];
  367. renderConfig.width=500;
  368. renderConfig.participantCode=document.getElementById("participantCode").innerHTML;
  369. renderConfig.visitCode=document.getElementById("visitCode").innerHTML;
  370. renderConfig.labelOthers='other visits';
  371. renderConfig.plot="percentile";
  372. renderConfig.max=10;
  373. renderConfig.title="SUV cumulative distribution";
  374. renderConfig.visitThreshold=visitValue;
  375. // When all the dependencies are loaded we then load the data via the MeasureStore selectRows API.
  376. // The queryConfig object stores all the information needed to make a selectRows request
  377. let queryConfig = new Object;
  378. queryConfig.schemaName="study";
  379. queryConfig.queryName="SUVQuantiles";
  380. queryConfig.viewName=null;
  381. queryConfig.dataRegionName="Dataset";
  382. queryConfig.queryLabel="SUVQuantiles";
  383. queryConfig.parameters= new Object();
  384. queryConfig.requiredVersion=13.2;
  385. queryConfig.maxRows=-1;
  386. queryConfig.sort="lsid";
  387. queryConfig.method="POST";
  388. queryConfig.columns=["SequenceNum","percentile","value",participantField,visitField];
  389. queryConfig.filterArray=new Array();
  390. queryConfig.filterArray.push({
  391. "name":"patientCode",
  392. "value":renderConfig.participantCode,
  393. "type":"eq"});
  394. //queryConfig.filterArray.push({
  395. // "name":"visitCode",
  396. // "value":renderConfig.visitCode,
  397. // "type":"eq"});
  398. queryConfig.filterArray.push({
  399. "name":"organ",
  400. "value":organs[i],
  401. "type":"eq"});
  402. if (queryConfig.filterArray &&
  403. queryConfig.filterArray.length > 0) {
  404. let filters = [];
  405. for (let i = 0; i < queryConfig.filterArray.length; i++) {
  406. let f = queryConfig.filterArray[i];
  407. filters.push(LABKEY.Filter.create(
  408. f.name, f.value,
  409. LABKEY.Filter.getFilterTypeForURLSuffix(f.type)));
  410. }
  411. queryConfig.filterArray = filters;
  412. }
  413. queryConfig.success = function(data){
  414. selectRowsCallback(renderConfig,data);};
  415. queryConfig.containerPath=LABKEY.ActionURL.getContainer();
  416. LABKEY.Query.MeasureStore.selectRows(queryConfig);
  417. }
  418. };
  419. function plotTime() {
  420. let participantField=document.getElementById('participantField').innerHTML;
  421. let participantCode=document.getElementById('participantCode').innerHTML;
  422. let visitField=document.getElementById('visitField').innerHTML;
  423. let visitCode=document.getElementById('visitCode').innerHTML;
  424. let visitValue=parseInt(visitCode.split('_')[1])+1;
  425. document.getElementById('debugCode').value+='\n'+visitValue;
  426. let organs=["3","4","5"];
  427. for (let i=0;i < organs.length; i++){
  428. let renderConfig=new Object();
  429. //all additional configuration stuff goes in here
  430. renderConfig.chartId='SUVparticipant_organ'+organs[i];
  431. renderConfig.width=500;
  432. renderConfig.participantCode=document.getElementById("participantCode").innerHTML;
  433. renderConfig.visitCode=document.getElementById("visitCode").innerHTML;
  434. renderConfig.labelOthers='others';
  435. renderConfig.suv=95;
  436. renderConfig.plot="time";
  437. if (organs[i]=="4")
  438. renderConfig.suv=70;
  439. renderConfig.max=-1;
  440. renderConfig.visitThreshold=visitValue;
  441. renderConfig.title="Quantitative inflamation time-curve";
  442. // When all the dependencies are loaded we then load the data via the MeasureStore selectRows API.
  443. // The queryConfig object stores all the information needed to make a selectRows request
  444. let queryConfig = new Object;
  445. queryConfig.schemaName="study";
  446. queryConfig.queryName="SUVQuantiles";
  447. queryConfig.viewName=null;
  448. queryConfig.dataRegionName="Dataset";
  449. queryConfig.queryLabel="SUVQuantiles";
  450. queryConfig.parameters= new Object();
  451. queryConfig.requiredVersion=13.2;
  452. queryConfig.maxRows=-1;
  453. queryConfig.sort="lsid";
  454. queryConfig.method="POST";
  455. queryConfig.columns=["SequenceNum","value",participantField];
  456. queryConfig.filterArray=new Array();
  457. //queryConfig.filterArray.push({
  458. // "name":"patientCode",
  459. // "value":renderConfig.participantCode,
  460. // "type":"eq"});
  461. queryConfig.filterArray.push({
  462. "name":"percentile",
  463. "value":renderConfig.suv,
  464. "type":"eq"});
  465. queryConfig.filterArray.push({
  466. "name":"organ",
  467. "value":organs[i],
  468. "type":"eq"});
  469. if (queryConfig.filterArray &&
  470. queryConfig.filterArray.length > 0) {
  471. let filters = [];
  472. for (let i = 0; i < queryConfig.filterArray.length; i++) {
  473. let f = queryConfig.filterArray[i];
  474. filters.push(LABKEY.Filter.create(
  475. f.name, f.value,
  476. LABKEY.Filter.getFilterTypeForURLSuffix(f.type)));
  477. }
  478. queryConfig.filterArray = filters;
  479. }
  480. queryConfig.success = function(data){
  481. selectRowsCallback(renderConfig,data);};
  482. queryConfig.containerPath = LABKEY.ActionURL.getContainer();
  483. LABKEY.Query.MeasureStore.selectRows(queryConfig);
  484. }
  485. };