crfReviewSection.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. //loadFile is in fileManager.js
  2. var crfReviewSection={};
  3. crfReviewSection.set=
  4. function(parentClass){
  5. if ("parent" in this)
  6. return;
  7. this.parent=parentClass;
  8. }
  9. crfReviewSection.generateErrorMessage=
  10. function (id,listName,msg){
  11. this.parent.print('generateErrorMessage:');
  12. let eid=listName+"_errorMsg";
  13. let el=config.document.getElementById(eid);
  14. if (el===null){
  15. el=config.document.createElement("p");
  16. config.document.getElementById(id).appendChild(el);
  17. }
  18. el.innerHTML=msg;
  19. }
  20. crfReviewSection.clearErrorMessage=
  21. function(listName){
  22. let eid=listName+"_errorMsg";
  23. let el=config.document.getElementById(eid);
  24. if (el===null) return;
  25. el.remove();
  26. }
  27. crfReviewSection.generateSection=
  28. function(listName,id,callback){
  29. let that=this;
  30. let action=function(){that.fcontinue(listName,id,callback);};
  31. LABKEY.requiresScript(["crfTecant/fileManager.js"],action);
  32. }
  33. crfReviewSection.fcontinue=
  34. function(listName,id,callback){
  35. //callback should be generateReviewSectionCB and it takes no arguments
  36. this.parent.print("generateReviewSection");
  37. let config=this.parent.config;
  38. //need base path
  39. config.loadFileConfig=new Object();
  40. config.loadFileConfig.cb=callback;
  41. config.loadFileConfig.id=id;
  42. config.loadFileConfig.url=fileManager.getBasePath()+'/@files/reportSetup/'+listName+'.json';
  43. fileManager.loadFile();
  44. //load file and continue in the next function
  45. }
  46. crfReviewSection.getParticipantCode=
  47. function(pid){
  48. let filters=[LABKEY.Filter.create("crfRef",this.parent.getCRFref())];
  49. let config=this.parent.config;
  50. let mfId=config.formConfig.form['masterQuery'];
  51. let queryName=config.formConfig.queryMap[mfId];
  52. let that=this;
  53. pid.afterId=function(id){that.setParticipantCode(id);};
  54. pid.participantField=config.formConfig.studyData["SubjectColumnName"];
  55. let cb=function(data){that.afterRegistration(pid,data);}
  56. //untested
  57. this.parent.selectRows('lists',queryName,filters,cb,this.parent.getContainer('data'));
  58. }
  59. crfReviewSection.visitCodeFromVisitId=
  60. function(visitId){
  61. if (visitId<0) return "NONE";
  62. let project=this.parent.getContainer('data');
  63. this.parent.print('visitCodeFromVisitId: '+project.search('retro'));
  64. if (project.search('retro')>-1)
  65. visitId-=1;
  66. return 'VISIT_'+visitId.toString();
  67. }
  68. crfReviewSection.replaceSlash=
  69. function(x){
  70. return x.replace(/\//,'_');
  71. }
  72. crfReviewSection.setParticipantCode=
  73. function(pid){
  74. let fName='[setParticipantCode]';
  75. let rows=pid.registration.rows;
  76. let config=this.parent.config;
  77. //pick from study
  78. let participantField=config.formConfig.studyData["SubjectColumnName"];
  79. if (rows.length==1){
  80. this.parent.print(fName+': '+rows[0][participantField]+'/'+rows[0].visitId);
  81. let visitCode=this.visitCodeFromVisitId(rows[0].visitId);
  82. this.parent.print('setParticipantCode: '+pid.participantId+'/'+visitCode);
  83. pid.participantCode=this.replaceSlash(pid.participantId);
  84. pid.visitCode=visitCode;
  85. }
  86. this.generateReviewSection2(pid);
  87. }
  88. crfReviewSection.CB=
  89. function(){
  90. let config=this.parent.config;
  91. let listName=config.loadFileConfig.listName;
  92. let id=config.loadFileConfig.id;
  93. this.parent.clearErrorMessage(listName);
  94. let pid=new Object();
  95. pid.participantCode="NONE";
  96. pid.visitCode="NONE";
  97. this.getParticipantCode(pid);
  98. this.parent.print('Get participant code sent');
  99. //involves database search, continue after callback
  100. }
  101. crfReviewSection.getValueFromElement=
  102. function(id,defaultValue){
  103. let config=this.parent.config;
  104. let e=config.document.getElementById(id);
  105. if (e!=null){
  106. defaultValue=e.innerHTML;
  107. }
  108. return defaultValue;
  109. }
  110. crfReviewSection.pickParticipantCodeFromPage=
  111. function(){
  112. let pid=new Object();
  113. pid.participantCode=this.getValueFromElement("participantCode","NIX-LJU-D2002-IRAE-A000");
  114. pid.visitCode=this.getValueFromElement("visitCode","VISIT_1");
  115. this.generateReviewSection2(pid);
  116. }
  117. crfReviewSection.patternReplace=
  118. function(src,replacements,values){
  119. for (rep in replacements){
  120. let txt1=src.replace(new RegExp(rep),values[replacements[rep]]);
  121. src=txt1;
  122. }
  123. return src;
  124. }
  125. crfReviewSection.plotImage=
  126. function(cell,k,row,rowVariable,obj,pid){
  127. let config=this.parent.config;
  128. let baseDir=this.patternReplace(obj.imageDir,obj.replacements,pid);
  129. this.parent.print('Base dir: '+pid.basePath);
  130. pid[obj.variable]=obj.values[k];
  131. cell.id=pid[obj.variable]+"_"+rowVariable+pid[rowVariable];
  132. let img=null;
  133. let imgId=cell.id+'_img_';
  134. img=config.document.getElementById(imgId);
  135. if (img===null){
  136. img=config.document.createElement('img');
  137. img.id=imgId;
  138. cell.appendChild(img);
  139. }
  140. let imgSrc=patternReplace(obj.file,obj.replacements,pid);
  141. this.parent.print('Image: '+imgSrc);
  142. let imagePath=pid.basePath+'/'+baseDir+'/'+imgSrc;
  143. img.src=imagePath;
  144. img.width="300";
  145. }
  146. crfReviewSection.showReport=
  147. function(cell,k,row,rowVariable,obj,pid){
  148. cell.width="300px";
  149. cell.id='report_'+obj.values[k]+"_"+rowVariable+pid[rowVariable];
  150. let reportConfig=new Object();
  151. reportConfig.partName="Report";
  152. reportConfig.renderTo=cell.id;
  153. //reportConfig.showFrame=false;
  154. //reportConfig.width="300";
  155. reportConfig.frame="none";
  156. reportConfig.partConfig=new Object();
  157. reportConfig.partConfig.width="300";
  158. reportConfig.partConfig.title="R Report";
  159. reportConfig.partConfig.reportName=obj.values[k];
  160. for (f in obj.parameters){
  161. reportConfig.partConfig[f]=pid[f];
  162. }
  163. reportConfig.partConfig.showSection="myscatterplot";
  164. let reportWebPartRenderer = new LABKEY.WebPart(reportConfig);
  165. this.parent.print('Render to: '+reportConfig.renderTo);
  166. reportWebPartRenderer.render();
  167. }
  168. crfReviewSection.showProbability=
  169. function(cell,k,row,rowSetup,j,obj,pid){
  170. this.parent.print('showProbability: '+rowSetup);
  171. let rowVariable=rowSetup.variable;
  172. cell.id='prob_'+obj.values[k]+"_"+rowVariable+pid[rowVariable];
  173. let probDensity=new Object();
  174. probDensity.mean=rowSetup.mean[j];
  175. probDensity.sigma=rowSetup.sigma[j];
  176. this.parent.print('showProbability: mean '+probDensity.mean+' sigma '+probDensity.sigma);
  177. probDensity.func=obj.values[k];
  178. probDensity.organCode=pid.organCode;
  179. pid[obj.variable]=rowSetup[obj.variable][j];
  180. probDensity.percentile=pid.percentile;
  181. let selectRows=new Object();
  182. selectRows.queryName=obj.queryName;
  183. selectRows.schemaName="study";
  184. selectRows.filterArray=[];
  185. selectRows.containerPath=getContainer('data');
  186. for (let f in obj.filters){
  187. selectRows.filterArray.push(
  188. LABKEY.Filter.create(f,pid[obj.filters[f]]));
  189. this.parent.print('Filter ['+f+']: '+pid[obj.filters[f]]);
  190. }
  191. selectRows.success=function(data){
  192. this.drawProbability(data,cell,obj,pid,probDensity);}
  193. LABKEY.Query.selectRows(selectRows);
  194. }
  195. crfReviewSection.erf=
  196. function(x){
  197. let fx=[0,0.02,0.04,0.06,0.08,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,
  198. 1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2,
  199. 2.1,2.2,2.3,2.4,2.5,3,3.5];
  200. let fy=[0,0.222702589,0.328626759,0.428392355,0.520499878,
  201. 0.603856091,0.677801194,0.742100965,0.796908212,
  202. 0.842700793,0.880205070,0.910313978,0.934007945,
  203. 0.952285120,0.966105146,0.976348383,
  204. 0.983790459,0.989090502,0.992790429,0.995322265,
  205. 0.997020533,0.998137154,0.998856823,0.999311486,
  206. 0.999593048,0.999977910,0.999999257];
  207. let n=32;
  208. let i0=n-1;
  209. for (let i=1;i<n;i++){
  210. if (Math.abs(x)>fx[i]) continue;
  211. i0=i-1;
  212. break;
  213. }
  214. let fval=1;
  215. if (i0<n-1){
  216. //interpolate
  217. let y1=fy[i0+1];
  218. let y0=fy[i0];
  219. let x1=fx[i0+1];
  220. let x0=fx[i0];
  221. fval=y0+(y1-y0)/(x1-x0)*(Math.abs(x)-x0);
  222. }
  223. this.parent.print('Erf: '+fval);
  224. if (x<0) return -fval;
  225. return fval;
  226. }
  227. crfReviewSection.setLine=
  228. function(fbox,name,value,fontSize){
  229. let fpId=fbox.id+name;
  230. let fp=config.document.getElementById(fpId);
  231. if (fp===null){
  232. fp=config.document.createElement("p");
  233. fp.id=fpId;
  234. fbox.appendChild(fp);
  235. }
  236. fp.classList.add("center");
  237. fp.style.textAlign="center";
  238. fp.style.fontSize=fontSize;
  239. fp.innerText=value;
  240. }
  241. crfReviewSection.drawProbability=
  242. function(data,cell,obj,pid,probDensity){
  243. this.parent.print('drawProbability');
  244. if (data.rows.length!=1){
  245. this.parent.print("drawProbability row length mismatch: "+data.rows.length);
  246. return;
  247. }
  248. //possible mismatch; I assume the dataset will have a field called value
  249. let val=data.rows[0].value;
  250. let prob=0;
  251. let fz=-100;
  252. if (probDensity.func=="gaus"){
  253. fz=(val-probDensity.mean)/probDensity.sigma/Math.sqrt(2);
  254. prob=0.5+0.5*erf(fz);
  255. }
  256. let color="red";
  257. let fzx=fz*Math.sqrt(2);
  258. this.parent.print('drawProbability '+fzx);
  259. for (let i=1;i<obj.intervals.n;i++){
  260. if (fzx>obj.intervals.zlimits[i]) continue;
  261. color=obj.intervals.colors[i-1];
  262. break;
  263. }
  264. let fboxId=cell.id+'_fbox_';
  265. let fbox=config.document.getElementById(fboxId);
  266. if (fbox===null){
  267. fbox=config.document.createElement("div");
  268. fbox.id=fboxId;
  269. cell.appendChild(fbox);
  270. }
  271. fbox.style.backgroundColor=color;
  272. fbox.style.width="180px";
  273. fbox.style.height="180px";
  274. this.parent.print('organCode '+probDensity.organCode);
  275. let organName="Lung";
  276. if (probDensity.organCode==4){
  277. organName="Thyroid";
  278. }
  279. if (probDensity.organCode==5){
  280. organName="Bowel";
  281. }
  282. this.setLine(fbox,'_fp4_',organName,"16px");
  283. this.setLine(fbox,'_fp_',val.toPrecision(3),"25px");
  284. this.setLine(fbox,'_fp1_',"SUV("+probDensity.percentile+"%)","16px");
  285. this.setLine(fbox,'_fp2_',fzx.toPrecision(3),"25px");
  286. this.setLine(fbox,'_fp3_',"z-value","16px");
  287. }
  288. crfReviewSection.generateReviewSection2=
  289. function(pid){
  290. let config=this.parent.config;
  291. let listName=config.loadFileConfig.listName;
  292. let id=config.loadFileConfig.id;
  293. this.parent.print('generateReviewSection2: '+pid.participantCode+'/'+
  294. pid.visitCode);
  295. if (pid.participantCode=="NONE" || pid.visitCode=="NONE"){
  296. this.generateErrorMessage(id,listName,
  297. "ParticipantId/visitId not set");
  298. return;
  299. }
  300. this.parent.print('JSON: '+config.loadFileConfig.json);
  301. let json=config.loadFileConfig.json;
  302. let nrows=json.rows.values.length;
  303. let ncol=json.columns.length;
  304. pid.basePath=fileManager.getBasePath()+"/@files";
  305. let el=config.document.getElementById(id);
  306. let tableId=id+'_Table';
  307. let table=config.document.getElementById(tableId);
  308. if (table==null){
  309. table=config.document.createElement('table');
  310. table.id=tableId;
  311. el.appendChild(table);
  312. }
  313. table.style.tableLayout="fixed";
  314. table.style.columnWidth="300px";
  315. for (let i=0;i<nrows;i++){
  316. pid[json.rows.variable]=json.rows.values[i];
  317. //let organ=organs[i];
  318. let row=null;
  319. if (i<table.rows.length)
  320. row=table.rows[i];
  321. else
  322. row=table.insertRow();
  323. let ic=0;
  324. for (let j=0;j<ncol;j++){
  325. let obj=json.columns[j];
  326. let nv=obj.values.length;
  327. for (let k=0;k<nv;k++){
  328. let cell=null;
  329. if (ic<row.cells.length)
  330. cell=row.cells[ic];
  331. else
  332. cell=row.insertCell();
  333. if (obj.display=="image")
  334. this.plotImage(cell,k,row,json.rows.variable,obj,pid);
  335. if (obj.display=="report")
  336. this.showReport(cell,k,row,json.rows.variable,obj,pid);
  337. if (obj.display=="probability"){
  338. this.showProbability(cell,k,row,json.rows,i,obj,pid);
  339. }
  340. ic++;
  341. }
  342. }
  343. }
  344. }
  345. ///>>>>>>>>>>>>>>end of reviewSection(REPORT)
  346. crfReviewSection.afterRegistration=
  347. function(data,fc){
  348. let fName='[afterRegistration/'+data.queryName+']';
  349. this.parent.print(fName+": rows:"+data.rows.length);
  350. fc.registration=data;
  351. let registrationData=fc.registration;
  352. this.parent.clearErr();
  353. if (registrationData.rows.length!=1){
  354. let msg=fName+": ERROR: Found "+registrationData.rows.length;
  355. msg+=" registration entries for crfrefid "+this.parent.getCRFref();
  356. this.parent.print(msg);
  357. fc.afterId(fc);
  358. return;
  359. }
  360. this.parent.print(fName+'registration participant field: '+fc.participantField);
  361. fc.participantId=registrationData.rows[0][fc.participantField];
  362. //could be a lookup field (particularly for studies)
  363. this.parent.print('ID: '+fc.participantId);
  364. let fields=registrationData.metaData.fields;
  365. let field="NONE";
  366. for (f in fields){
  367. if (fields[f]["name"]==fc.participantField)
  368. field=fields[f];
  369. }
  370. if ("lookup" in field){
  371. let pid=fc.participantId;
  372. this.parent.print("Using lookup for participantId: "+pid);
  373. let lookup=field["lookup"];
  374. this.parent.print("Lookup: ["+lookup.schemaName+','+lookup.queryName+']');
  375. //load lookup
  376. let that=this;
  377. let cb=function(data){that.afterRegistrationLookup(data,lookup.displayColumn,fc)};
  378. let filters=[LABKEY.Filter.create(lookup.keyColumn,pid)];
  379. this.parent.selectRows(lookup.schemaName,lookup.queryName,filters,cb,lookup.containerPath);
  380. }
  381. else{
  382. //afterParticipantId(configUpload);
  383. fc.afterId(fc);
  384. }
  385. }
  386. crfReviewSection.afterRegistrationLookup=
  387. function(data,displayColumn,fc){
  388. this.parent.print("afterRegistrationLookup");
  389. let entry=data.rows[0];
  390. fc.participantId=entry[displayColumn];
  391. this.parent.print('Setting to '+fc.participantId);
  392. fc.afterId(fc);
  393. //afterParticipantId(configUpload);
  394. }