@sjcrh/proteinpaint-client 2.219.1 → 2.221.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (983) hide show
  1. package/dist/2dmaf-7YU3SNKL.js +1362 -0
  2. package/dist/AggMatrixInput-73CDR5FS.js +402 -0
  3. package/dist/AggregateMatrix-NNULVFBM.js +37 -0
  4. package/dist/AppHeader-EZDDLLXU.js +826 -0
  5. package/dist/BoxPlot-463E7CRY.js +1229 -0
  6. package/dist/CorrelationVolcano-LHIIMBPP.js +613 -0
  7. package/dist/Cuminc-UL2TCIKV.js +1217 -0
  8. package/dist/DE-VRFSKFDW.js +85 -0
  9. package/dist/DEinput-FZTQRWVC.js +479 -0
  10. package/dist/DM-PO7CQZNT.js +86 -0
  11. package/dist/DifferentialAnalysis-WK6HE3YH.js +236 -0
  12. package/dist/Disco-YBNQJQFG.js +3384 -0
  13. package/dist/Disco.UI-HC5XYBFV.js +239 -0
  14. package/dist/DmrPlot-7VJ5C66D.js +361 -0
  15. package/dist/GB-VPFQRDRO.js +1388 -0
  16. package/dist/GSEA-ZEJB3QZQ.js +870 -0
  17. package/dist/GeneExpInput-SBDDIY6G.js +38 -0
  18. package/dist/Geomap-23AHGP2V.js +80 -0
  19. package/dist/HicApp-7AQQE4CM.js +2240 -0
  20. package/dist/IDCViewer-NO5Q6VOB.js +10808 -0
  21. package/dist/NumBinaryEditor-DSRP4OOU.js +274 -0
  22. package/dist/NumBinaryEditor.unit.spec-TT666YL4.js +308 -0
  23. package/dist/NumContEditor-6CURFOCH.js +100 -0
  24. package/dist/NumContEditor.unit.spec-MNVCFCMP.js +160 -0
  25. package/dist/NumCustomBinEditor-SQRR5EFL.js +29 -0
  26. package/dist/NumCustomBinEditor.unit.spec-F7BZWGGT.js +393 -0
  27. package/dist/NumDiscreteEditor-U7Z2QNYP.js +165 -0
  28. package/dist/NumDiscreteEditor.unit.spec-EIEBUZCX.js +229 -0
  29. package/dist/NumRegularBinEditor-CVZSWN6Y.js +29 -0
  30. package/dist/NumRegularBinEditor.unit.spec-ZMAJOIHL.js +274 -0
  31. package/dist/NumSplineEditor-U43D5NBJ.js +205 -0
  32. package/dist/NumSplineEditor.unit.spec-C52AADTS.js +220 -0
  33. package/dist/NumericDensity-PUKDZOVI.js +29 -0
  34. package/dist/NumericDensity.unit.spec-2347S76D.js +414 -0
  35. package/dist/NumericHandler-3RT32PTR.js +30 -0
  36. package/dist/NumericHandler.unit.spec-4PADL4KZ.js +225 -0
  37. package/dist/ProteomeInput-NFV4FW4U.js +610 -0
  38. package/dist/Regression-N7M7N6G4.js +1412 -0
  39. package/dist/RunChart2-UPQ7C6QE.js +744 -0
  40. package/dist/SC-KBW2NHUV.js +1290 -0
  41. package/dist/Violin-GWCOP3ZF.js +1092 -0
  42. package/dist/Volcano-X3HT32GQ.js +2661 -0
  43. package/dist/Volcano-X3HT32GQ.js.map +7 -0
  44. package/dist/Wsi-NXAEOYIS.js +636 -0
  45. package/dist/aboutSunburst-5EKXZV2A.js +86 -0
  46. package/dist/aboutSunburst-5EKXZV2A.js.map +7 -0
  47. package/dist/adSandbox-RPEWEEW7.js +29 -0
  48. package/dist/animatedBubbleChart-ILDMZRBX.js +542 -0
  49. package/dist/app-LOUC4J47.js +28 -0
  50. package/dist/app-MRKXZ6AZ.js +38 -0
  51. package/dist/app.js +15 -15
  52. package/dist/bam-SQWPHCZZ.js +872 -0
  53. package/dist/bam-SQWPHCZZ.js.map +7 -0
  54. package/dist/barchart-CJR37234.js +38 -0
  55. package/dist/barchart2-QQYLTHWR.js +305 -0
  56. package/dist/block-GLF6QNKY.js +6203 -0
  57. package/dist/block-GLF6QNKY.js.map +7 -0
  58. package/dist/block.init-YJQTJIDO.js +29 -0
  59. package/dist/block.mds.expressionrank-GBMEI5KQ.js +350 -0
  60. package/dist/block.mds.geneboxplot-XWE3E5IW.js +819 -0
  61. package/dist/block.mds.junction-QLEHFVPE.js +1534 -0
  62. package/dist/block.mds.svcnv-53DTOPBC.js +6413 -0
  63. package/dist/block.svg-57T37ABS.js +155 -0
  64. package/dist/block.tk.aicheck-6DXJTS3H.js +274 -0
  65. package/dist/block.tk.bam-CJFFQDNX.js +1906 -0
  66. package/dist/block.tk.bam-CJFFQDNX.js.map +7 -0
  67. package/dist/block.tk.bigwig.ui-OYIVXE2L.js +202 -0
  68. package/dist/block.tk.hicstraw-UKTGEBWT.js +814 -0
  69. package/dist/block.tk.junction-ZU5KPFQ3.js +2353 -0
  70. package/dist/block.tk.junction.textmatrixui-P4WXTAZR.js +190 -0
  71. package/dist/block.tk.ld-3PQ4O2AE.js +90 -0
  72. package/dist/block.tk.menu-LLITB6UA.js +1050 -0
  73. package/dist/block.tk.pgv-Y3FBXUO3.js +934 -0
  74. package/dist/brainImaging-4B3WXLNP.js +550 -0
  75. package/dist/brainRegions-7VLONUWN.js +213 -0
  76. package/dist/bubbleHeatmap-DI6GJRR6.js +374 -0
  77. package/dist/cellTypeBubbleHeatmap-HJY53DB2.js +274 -0
  78. package/dist/chunk-226MNBZ2.js +240 -0
  79. package/dist/chunk-2CDFU4MQ.js +536 -0
  80. package/dist/chunk-2CDFU4MQ.js.map +7 -0
  81. package/dist/chunk-2CNFGVHU.js +257 -0
  82. package/dist/chunk-2MC3RNKA.js +2685 -0
  83. package/dist/chunk-2OMX5AYB.js +195 -0
  84. package/dist/chunk-2SL4QWUS.js +50 -0
  85. package/dist/chunk-3KGBC5MK.js +692 -0
  86. package/dist/chunk-3PCRAPUV.js +56 -0
  87. package/dist/chunk-4DBOMSKP.js +102 -0
  88. package/dist/chunk-4TJO2DGU.js +2297 -0
  89. package/dist/chunk-4TJO2DGU.js.map +7 -0
  90. package/dist/chunk-57BS6KNI.js +466 -0
  91. package/dist/chunk-5AXS5G4A.js +2334 -0
  92. package/dist/chunk-5DI4UNH5.js +562 -0
  93. package/dist/chunk-5HJG6ECV.js +237 -0
  94. package/dist/chunk-5ZYANHGX.js +550 -0
  95. package/dist/chunk-6T4MN7LV.js +397 -0
  96. package/dist/chunk-75MRUW2K.js +103 -0
  97. package/dist/chunk-7J3W3KCN.js +255 -0
  98. package/dist/chunk-7SFK32JP.js +398 -0
  99. package/dist/chunk-7SFK32JP.js.map +7 -0
  100. package/dist/chunk-AIZYAKIE.js +182 -0
  101. package/dist/chunk-AJNFI6GA.js +2008 -0
  102. package/dist/chunk-BJAWDZBL.js +2799 -0
  103. package/dist/chunk-C6PVZVIH.js +379 -0
  104. package/dist/chunk-C77X5ZUV.js +176 -0
  105. package/dist/chunk-C7KUMZQM.js +59 -0
  106. package/dist/chunk-C7ROKWV2.js +140 -0
  107. package/dist/chunk-CAH6LJ5Z.js +31 -0
  108. package/dist/chunk-CUCP2GMT.js +102 -0
  109. package/dist/chunk-DTGAMBRJ.js +134 -0
  110. package/dist/chunk-DXT7GDHY.js +55 -0
  111. package/dist/chunk-ENPMWVWG.js +5214 -0
  112. package/dist/chunk-EYKJQJ7R.js +382 -0
  113. package/dist/chunk-FE5TCBIT.js +30 -0
  114. package/dist/chunk-FJ2JV2VK.js +217 -0
  115. package/dist/chunk-FPMJJBLV.js +4389 -0
  116. package/dist/chunk-FPMJJBLV.js.map +7 -0
  117. package/dist/chunk-FZYVPRVQ.js +38 -0
  118. package/dist/chunk-GBKQHVKJ.js +274 -0
  119. package/dist/chunk-GUW7VTUL.js +281 -0
  120. package/dist/chunk-H7F6DMJA.js +70 -0
  121. package/dist/chunk-HH3NUAR2.js +96 -0
  122. package/dist/chunk-HRTPGNOG.js +159 -0
  123. package/dist/chunk-IFPRYTS7.js +848 -0
  124. package/dist/chunk-IJSFSUI4.js +302 -0
  125. package/dist/chunk-IRQKX6DL.js +263 -0
  126. package/dist/chunk-JHLF2ZC2.js +472 -0
  127. package/dist/chunk-JNZL7HKB.js +1219 -0
  128. package/dist/chunk-K2ARLT2A.js +26 -0
  129. package/dist/chunk-K3G56J5R.js +299 -0
  130. package/dist/chunk-KKUCG2QE.js +516 -0
  131. package/dist/chunk-KPXCXBNU.js +626 -0
  132. package/dist/chunk-LF5WBI27.js +418 -0
  133. package/dist/chunk-LF5WBI27.js.map +7 -0
  134. package/dist/chunk-MANAUI7R.js +54 -0
  135. package/dist/chunk-MEUSRAOE.js +170 -0
  136. package/dist/chunk-MHWYRNGA.js +348 -0
  137. package/dist/chunk-MSTYU3QO.js +14 -0
  138. package/dist/chunk-MWARRQT4.js +141 -0
  139. package/dist/chunk-MXKYPTZ7.js +203 -0
  140. package/dist/chunk-NX5IB4IY.js +37 -0
  141. package/dist/chunk-OZUF7O2S.js +133 -0
  142. package/dist/chunk-PRTLCJYF.js +2941 -0
  143. package/dist/chunk-PRTLCJYF.js.map +7 -0
  144. package/dist/chunk-PWYMHUXY.js +116 -0
  145. package/dist/chunk-PWYMHUXY.js.map +7 -0
  146. package/dist/chunk-QNCE6EOK.js +82 -0
  147. package/dist/chunk-RIHO7ZD5.js +119 -0
  148. package/dist/chunk-RV335DF2.js +266 -0
  149. package/dist/chunk-SFPZUBPM.js +2102 -0
  150. package/dist/chunk-SFPZUBPM.js.map +7 -0
  151. package/dist/chunk-THAUD62Q.js +1253 -0
  152. package/dist/chunk-VBTBUXXX.js +6375 -0
  153. package/dist/chunk-VHWJK2MP.js +56 -0
  154. package/dist/chunk-VLIOMJDR.js +276 -0
  155. package/dist/chunk-VMK4RHV5.js +54 -0
  156. package/dist/chunk-WD7FZ5EE.js +26536 -0
  157. package/dist/chunk-WD7FZ5EE.js.map +7 -0
  158. package/dist/chunk-WJLRU5OF.js +5786 -0
  159. package/dist/chunk-WJLRU5OF.js.map +7 -0
  160. package/dist/chunk-WKT7RF3C.js +468 -0
  161. package/dist/chunk-WXSMUSU7.js +184 -0
  162. package/dist/chunk-WXSX5OQJ.js +296 -0
  163. package/dist/chunk-WY3IORKG.js +194 -0
  164. package/dist/chunk-WYSOOKFJ.js +480 -0
  165. package/dist/chunk-XBBFFOLS.js +123 -0
  166. package/dist/chunk-XSRQGX5H.js +340 -0
  167. package/dist/chunk-YLL6CTBL.js +54 -0
  168. package/dist/chunk-YPBY37KD.js +1339 -0
  169. package/dist/chunk-YUNJBIK4.js +243 -0
  170. package/dist/chunk-Z5ECCUNG.js +444 -0
  171. package/dist/chunk-ZAC34BZQ.js +35 -0
  172. package/dist/chunk-ZAC34BZQ.js.map +7 -0
  173. package/dist/cohort-5WL6UJOS.js +66 -0
  174. package/dist/cohortSunburst-R3Z5KJQL.js +402 -0
  175. package/dist/condition-2IILUMVB.js +323 -0
  176. package/dist/controls-G3JITZF5.js +30 -0
  177. package/dist/controls.config-BO7KPPET.js +30 -0
  178. package/dist/correlation-CZILLVEM.js +91 -0
  179. package/dist/customdata.inputui-BXFQAMTR.js +280 -0
  180. package/dist/dataDownload-QTWR4IW7.js +326 -0
  181. package/dist/dataDownload-QTWR4IW7.js.map +7 -0
  182. package/dist/databrowser.ui-V2NJQF3U.js +421 -0
  183. package/dist/dictionary-OVAQX6R3.js +109 -0
  184. package/dist/dnaMethylation-DHPFRXB2.js +29 -0
  185. package/dist/dnaMethylation.integration.spec-PJLIRGN5.js +194 -0
  186. package/dist/dofetch-KBTN6OW4.js +49 -0
  187. package/dist/e2pca-O7SNMJGB.js +340 -0
  188. package/dist/ep-NIVLKG4S.js +1247 -0
  189. package/dist/expclust.gdc.spec-LVCD6C43.js +298 -0
  190. package/dist/facet-LB4SCXE4.js +556 -0
  191. package/dist/gb-3IJ4NCPO.js +77 -0
  192. package/dist/geneExpClustering-SIAC7CMA.js +240 -0
  193. package/dist/geneExpression-KPUOZ4PT.js +309 -0
  194. package/dist/geneExpression-P2TTZXN2.js +29 -0
  195. package/dist/geneExpression.unit.spec-Q5D6XHUF.js +151 -0
  196. package/dist/geneORA-PKUIJKTL.js +269 -0
  197. package/dist/geneRanking-ZGT5MHBV.js +544 -0
  198. package/dist/geneVariant-24YNANTT.js +289 -0
  199. package/dist/geneVariant-CDGENHWQ.js +32 -0
  200. package/dist/geneVariant.integration.spec-7QW4C2WO.js +672 -0
  201. package/dist/genefusion.ui-NVXGSBXD.js +299 -0
  202. package/dist/geneset-7STL6UDD.js +199 -0
  203. package/dist/genomeBrowser.spec-OE2CIP7I.js +272 -0
  204. package/dist/grin2-2HXUIY5O.js +66 -0
  205. package/dist/grin2-32IIJR5E.js +945 -0
  206. package/dist/hierCluster-MDZEI2KB.js +51 -0
  207. package/dist/hierCluster-T3PZUGBI.js +55 -0
  208. package/dist/hierCluster.config-7UN6AYGB.js +32 -0
  209. package/dist/hierCluster.integration.spec-DWOYVK6T.js +479 -0
  210. package/dist/hierCluster.interactivity-5OM6XNFG.js +45 -0
  211. package/dist/hierCluster.renderers-YGX6MZZW.js +18 -0
  212. package/dist/imagePlot-KBRXDV5G.js +152 -0
  213. package/dist/importPlot-DJMIC22L.js +8 -0
  214. package/dist/isoformExpression-SWDWADRC.js +31 -0
  215. package/dist/isoformExpression.unit.spec-2U5KCYBP.js +233 -0
  216. package/dist/junction-NMXVVGRG.js +32 -0
  217. package/dist/junction.customTerm-3R2GNE3A.js +15 -0
  218. package/dist/junction.unit.spec-JTGBPPN7.js +178 -0
  219. package/dist/launch.adhoc-YB5SKMNY.js +33 -0
  220. package/dist/leftlabel.sample-QKXIODCS.js +253 -0
  221. package/dist/lollipop-TSZ62PBH.js +162 -0
  222. package/dist/maf-4L5YN4CG.js +451 -0
  223. package/dist/maftimeline-VOYB3NY3.js +583 -0
  224. package/dist/matrix-IWJECVTF.js +55 -0
  225. package/dist/matrix-MMJAJZA7.js +50 -0
  226. package/dist/matrix.cells-5RTZUJVN.js +25 -0
  227. package/dist/matrix.config-DZGOZWJS.js +33 -0
  228. package/dist/matrix.data-Y5TPRGMW.js +22 -0
  229. package/dist/matrix.groups-6DXCAY4P.js +25 -0
  230. package/dist/matrix.integration.spec-2N237E7T.js +3156 -0
  231. package/dist/matrix.interactivity-FL33UUKR.js +33 -0
  232. package/dist/matrix.layout-7SYHV3KJ.js +35 -0
  233. package/dist/matrix.legend-S3E76TVO.js +19 -0
  234. package/dist/matrix.renderers-3SIBT2RP.js +30 -0
  235. package/dist/matrix.serieses-3UGLZW25.js +18 -0
  236. package/dist/matrix.sort-A7CNLDUJ.js +25 -0
  237. package/dist/matrix.sort.unit.spec-L3H44T6I.js +464 -0
  238. package/dist/matrix.sorterUi-6PZR3YOD.js +15 -0
  239. package/dist/matrix.sorterUi.unit.spec-2NRU5UFH.js +334 -0
  240. package/dist/matrix.unit.spec-HRZIJB6T.js +146 -0
  241. package/dist/mavb-ZVRQSDPS.js +726 -0
  242. package/dist/mds.fimo-ZKETTET7.js +509 -0
  243. package/dist/mds.samplescatterplot-ZV3UNRLP.js +1545 -0
  244. package/dist/mds.survivalplot-OVXZRTU4.js +472 -0
  245. package/dist/multivalue-6BE5IA4F.js +79 -0
  246. package/dist/numericDictTermCluster-6XDVVWLE.js +62 -0
  247. package/dist/oncomatrix-XK62NEOO.js +286 -0
  248. package/dist/oncomatrix.spec-YVTCHOPS.js +439 -0
  249. package/dist/plot.2dvaf-NUOBWMNX.js +368 -0
  250. package/dist/plot.app-G6IQWXTV.js +32 -0
  251. package/dist/plot.barplot-6QJ6HEJR.js +93 -0
  252. package/dist/plot.boxplot-XKQJSW2O.js +142 -0
  253. package/dist/plot.brainImaging-UTHFJFXU.js +51 -0
  254. package/dist/plot.disco-3MSCX7TM.js +98 -0
  255. package/dist/plot.ssgq-4KBVHF42.js +130 -0
  256. package/dist/plot.vaf2cov-OGUQSSDS.js +249 -0
  257. package/dist/polar2-V7M56GTZ.js +228 -0
  258. package/dist/profileForms-TS3BJLHH.js +937 -0
  259. package/dist/profilePlot-DP5272HR.js +45 -0
  260. package/dist/proteinView-K4K4SP3L.js +1346 -0
  261. package/dist/proteomeCohortCompare-SFWVGLFK.js +866 -0
  262. package/dist/pseudbulk.unit.spec-NFOA7J2C.js +82 -0
  263. package/dist/pseudobulk-XKZQEZ4I.js +31 -0
  264. package/dist/qualitative-7OSFNVI5.js +241 -0
  265. package/dist/qualitative-OIIN6E4Y.js +34 -0
  266. package/dist/radar2-AHZJKX7S.js +323 -0
  267. package/dist/radarFacility2-OUW6D5E7.js +331 -0
  268. package/dist/rememberedGvQ.unit.spec-SHTMMZGG.js +210 -0
  269. package/dist/render-7UZSGX3Q.js +29 -0
  270. package/dist/report-J7HKTXZ2.js +213 -0
  271. package/dist/sampleView-6547OUIM.js +39 -0
  272. package/dist/samplelst-UHF23UEB.js +114 -0
  273. package/dist/samplematrix-OOKS3TMR.js +2188 -0
  274. package/dist/sc-WF2BLGNG.js +77 -0
  275. package/dist/scatter-ABCVFGRV.js +84 -0
  276. package/dist/scatter-WF7XM3IA.js +919 -0
  277. package/dist/selectGenomeWithTklst-67HU5KRB.js +125 -0
  278. package/dist/singleCellCellType-3FZPJ25V.js +29 -0
  279. package/dist/singleCellCellType.unit.spec-TOMREHWK.js +150 -0
  280. package/dist/singleCellGeneExpression-NQTJ5KJQ.js +29 -0
  281. package/dist/singleCellGeneExpression.unit.spec-ZWUQTU2N.js +144 -0
  282. package/dist/singleCellNumericValue-VI7H722L.js +29 -0
  283. package/dist/singleCellNumericValue.unit.spec-QGLHES7H.js +412 -0
  284. package/dist/singleCellPlot-RU5T6SJK.js +44 -0
  285. package/dist/singlecell-C3CJVNXP.js +1562 -0
  286. package/dist/singlecell-NRQZ7KC6.js +77 -0
  287. package/dist/snp-X6XY65VS.js +29 -0
  288. package/dist/snp.unit.spec-6EENK7GQ.js +167 -0
  289. package/dist/snplocus-R4JA6TFT.js +200 -0
  290. package/dist/snplst-SOWVHSXH.js +36 -0
  291. package/dist/spliceevent.a53ss.diagram-IRLCCVQZ.js +142 -0
  292. package/dist/spliceevent.exonskip.diagram-4KG7LE5D.js +274 -0
  293. package/dist/spliceevent.noeventdiagram-OWXAJJX7.js +451 -0
  294. package/dist/ssGSEA-EMOKPLMP.js +29 -0
  295. package/dist/ssGSEA.unit.spec-KXQ7R5WH.js +79 -0
  296. package/dist/stattable-H2G7MOZG.js +112 -0
  297. package/dist/studyCatalog-3ITQXWFL.js +457 -0
  298. package/dist/summarizeCnvGeneexp-ZIPU6YDY.js +154 -0
  299. package/dist/summarizeGeneexpSurvival-3RYU226R.js +101 -0
  300. package/dist/summarizeMutationCnv-RGDBUB22.js +155 -0
  301. package/dist/summarizeMutationDiagnosis-Z4MZE6Y4.js +31 -0
  302. package/dist/summarizeMutationSurvival-Z5CNRH7E.js +95 -0
  303. package/dist/summary-6QQCNX3B.js +40 -0
  304. package/dist/summary.integration.spec-3ULXTZUP.js +405 -0
  305. package/dist/summaryInput-4QKR34QB.js +238 -0
  306. package/dist/sunburst-KB3BWC72.js +34 -0
  307. package/dist/sunburst-XTFBHZNH.js +274 -0
  308. package/dist/survival-7O6ZK63E.js +49 -0
  309. package/dist/survival-NNCY4K6C.js +1248 -0
  310. package/dist/survival.integration.spec-ZYZHZAXA.js +609 -0
  311. package/dist/svgraph-ZLSFFEAC.js +1377 -0
  312. package/dist/svmr-REBBDEYM.js +3834 -0
  313. package/dist/swimmer-NUBRIWLI.js +993 -0
  314. package/dist/swimmer-NUBRIWLI.js.map +7 -0
  315. package/dist/table-CWIQQESJ.js +192 -0
  316. package/dist/termCollection-7TYJSQ45.js +29 -0
  317. package/dist/termCollection-7Z55QNL7.js +247 -0
  318. package/dist/termCollection.unit.spec-LQ5MIBDH.js +295 -0
  319. package/dist/termCollectionFractionSelection-24DZYVDU.js +38 -0
  320. package/dist/termCollectionFractionSelection.unit.spec-DCV2CFS5.js +184 -0
  321. package/dist/tk-2WZFPRCP.js +37 -0
  322. package/dist/tk-QTLEYIP7.js +1193 -0
  323. package/dist/tk-QTLEYIP7.js.map +7 -0
  324. package/dist/tp.ui-HXQX2UH4.js +1453 -0
  325. package/dist/tvs.categorical-4D3JI2ER.js +28 -0
  326. package/dist/tvs.condition-62FXFHZ5.js +160 -0
  327. package/dist/tvs.density-IGO4I4T2.js +19 -0
  328. package/dist/tvs.dt-FZSVMJOO.js +34 -0
  329. package/dist/tvs.dtcnv.categorical-PPFQIC42.js +31 -0
  330. package/dist/tvs.dtcnv.continuous-TV2IGHY4.js +72 -0
  331. package/dist/tvs.dtfusion-ON4BA4XJ.js +31 -0
  332. package/dist/tvs.dtitd-VFNROOWQ.js +31 -0
  333. package/dist/tvs.dtsnvindel-ZXOP37T5.js +31 -0
  334. package/dist/tvs.dtsv-EUHPTW7J.js +31 -0
  335. package/dist/tvs.multivalue-NHVXZNDI.js +84 -0
  336. package/dist/tvs.numeric-FPWDPO3J.js +32 -0
  337. package/dist/tvs.samplelst-ZZHRNUP4.js +95 -0
  338. package/dist/tvs.survival-F3KSG3U6.js +110 -0
  339. package/dist/tvs.termCollection-B37DZLDY.js +118 -0
  340. package/dist/vocabulary-XNE5FFDK.js +32 -0
  341. package/dist/vocabulary-XNE5FFDK.js.map +7 -0
  342. package/dist/wsi.direct-3YH3QGQD.js +11514 -0
  343. package/package.json +4 -4
  344. package/dist/2dmaf-O2SQ5RGD.js +0 -1362
  345. package/dist/AggMatrixInput-LUCTWXHU.js +0 -402
  346. package/dist/AggregateMatrix-JVMF27YL.js +0 -37
  347. package/dist/AppHeader-DJU6HRKO.js +0 -826
  348. package/dist/BoxPlot-22RXMPRL.js +0 -1229
  349. package/dist/CorrelationVolcano-PBZWPFSN.js +0 -613
  350. package/dist/Cuminc-EL74X5GY.js +0 -1217
  351. package/dist/DE-W5SAMMRW.js +0 -85
  352. package/dist/DEinput-ZKEFJZQU.js +0 -479
  353. package/dist/DM-ABKDXMDG.js +0 -86
  354. package/dist/DifferentialAnalysis-3JTZ5WCQ.js +0 -236
  355. package/dist/Disco-ME53U25C.js +0 -3384
  356. package/dist/Disco.UI-F7XKJMKR.js +0 -239
  357. package/dist/DmrPlot-OWBXUTON.js +0 -361
  358. package/dist/GB-7X6DBWKS.js +0 -1388
  359. package/dist/GSEA-GAZIEGD7.js +0 -870
  360. package/dist/GeneExpInput-BAOC6ICV.js +0 -38
  361. package/dist/Geomap-OZERLL7V.js +0 -80
  362. package/dist/HicApp-WDH5LVTD.js +0 -2240
  363. package/dist/IDCViewer-XBZFU3BU.js +0 -10808
  364. package/dist/NumBinaryEditor-5R4EUQOZ.js +0 -274
  365. package/dist/NumBinaryEditor.unit.spec-ULBXMOYY.js +0 -308
  366. package/dist/NumContEditor-EN6V4FLQ.js +0 -100
  367. package/dist/NumContEditor.unit.spec-VDWKNIFN.js +0 -160
  368. package/dist/NumCustomBinEditor-UB34ALNZ.js +0 -29
  369. package/dist/NumCustomBinEditor.unit.spec-WZXJ7GEC.js +0 -393
  370. package/dist/NumDiscreteEditor-H6J67YEL.js +0 -165
  371. package/dist/NumDiscreteEditor.unit.spec-KJ7YU22W.js +0 -229
  372. package/dist/NumRegularBinEditor-R5JVUG7J.js +0 -29
  373. package/dist/NumRegularBinEditor.unit.spec-RZ73FMNO.js +0 -274
  374. package/dist/NumSplineEditor-AOR6OAJA.js +0 -205
  375. package/dist/NumSplineEditor.unit.spec-Z6ZEI3UO.js +0 -220
  376. package/dist/NumericDensity-SRTFTDQA.js +0 -29
  377. package/dist/NumericDensity.unit.spec-MRREBAYU.js +0 -414
  378. package/dist/NumericHandler-7RALUACA.js +0 -30
  379. package/dist/NumericHandler.unit.spec-MDO23WRB.js +0 -225
  380. package/dist/ProteomeInput-MOBXHRD5.js +0 -610
  381. package/dist/Regression-XWT4NNTG.js +0 -1412
  382. package/dist/RunChart2-Q7W5MWJS.js +0 -744
  383. package/dist/SC-MM3JTEVL.js +0 -1290
  384. package/dist/Violin-XNTBDUPG.js +0 -1092
  385. package/dist/Volcano-GRKXU3WL.js +0 -2619
  386. package/dist/Volcano-GRKXU3WL.js.map +0 -7
  387. package/dist/Wsi-22KJSFVH.js +0 -636
  388. package/dist/adSandbox-TLYWQOOA.js +0 -29
  389. package/dist/animatedBubbleChart-67SY5JGP.js +0 -542
  390. package/dist/app-FG3KPE4R.js +0 -28
  391. package/dist/app-VK5LYO6B.js +0 -38
  392. package/dist/bam-TNLNISLV.js +0 -872
  393. package/dist/bam-TNLNISLV.js.map +0 -7
  394. package/dist/barchart-IGWRVB6W.js +0 -38
  395. package/dist/barchart2-TT6OBJJP.js +0 -305
  396. package/dist/block-5PV2TYWJ.js +0 -6232
  397. package/dist/block-5PV2TYWJ.js.map +0 -7
  398. package/dist/block.init-2Y6CNK7H.js +0 -29
  399. package/dist/block.mds.expressionrank-VZ4JVPTG.js +0 -350
  400. package/dist/block.mds.geneboxplot-NYMS32JP.js +0 -819
  401. package/dist/block.mds.junction-3R6C3B5W.js +0 -1534
  402. package/dist/block.mds.svcnv-SO5CYYIQ.js +0 -6413
  403. package/dist/block.svg-R4ASXXNW.js +0 -155
  404. package/dist/block.tk.aicheck-LYRTDZRA.js +0 -274
  405. package/dist/block.tk.bam-GR7CHGGQ.js +0 -1897
  406. package/dist/block.tk.bam-GR7CHGGQ.js.map +0 -7
  407. package/dist/block.tk.bedgraphdot-GERXK2O6.js +0 -375
  408. package/dist/block.tk.bedgraphdot-GERXK2O6.js.map +0 -7
  409. package/dist/block.tk.bigwig.ui-3KMMZX2M.js +0 -202
  410. package/dist/block.tk.hicstraw-7HH4PGFY.js +0 -814
  411. package/dist/block.tk.junction-BPEKLYS2.js +0 -2353
  412. package/dist/block.tk.junction.textmatrixui-2QU5DL2X.js +0 -190
  413. package/dist/block.tk.ld-TJREYPNY.js +0 -90
  414. package/dist/block.tk.menu-HDBZK4YP.js +0 -1050
  415. package/dist/block.tk.pgv-G5GCYBK2.js +0 -934
  416. package/dist/brainImaging-ODWHF7WZ.js +0 -550
  417. package/dist/brainRegions-DC7DEA7N.js +0 -213
  418. package/dist/bubbleHeatmap-T5ACULRL.js +0 -374
  419. package/dist/cellTypeBubbleHeatmap-RQINXXTK.js +0 -274
  420. package/dist/chunk-24ZS2XWC.js +0 -176
  421. package/dist/chunk-2EPEWVKQ.js +0 -4378
  422. package/dist/chunk-2EPEWVKQ.js.map +0 -7
  423. package/dist/chunk-2PHFY3VP.js +0 -195
  424. package/dist/chunk-2QFMKWNS.js +0 -281
  425. package/dist/chunk-2UB6JZ3I.js +0 -466
  426. package/dist/chunk-3GQ54XTJ.js +0 -70
  427. package/dist/chunk-3IE6FDVA.js +0 -1253
  428. package/dist/chunk-4ENIOXIT.js +0 -133
  429. package/dist/chunk-4OOQ52ET.js +0 -182
  430. package/dist/chunk-5NI77Z3O.js +0 -119
  431. package/dist/chunk-5TPWMYBG.js +0 -274
  432. package/dist/chunk-64JHE3GV.js +0 -50
  433. package/dist/chunk-6MUJGVOH.js +0 -140
  434. package/dist/chunk-6XKAOSQE.js +0 -116
  435. package/dist/chunk-6XKAOSQE.js.map +0 -7
  436. package/dist/chunk-6YGSVJJD.js +0 -54
  437. package/dist/chunk-7PQVNQFR.js +0 -255
  438. package/dist/chunk-7XW4JWMJ.js +0 -170
  439. package/dist/chunk-7ZEJKFGW.js +0 -55
  440. package/dist/chunk-A6ZUYQHO.js +0 -159
  441. package/dist/chunk-ALIMVUHR.js +0 -1219
  442. package/dist/chunk-ANBGNYNP.js +0 -1339
  443. package/dist/chunk-ATZNXW5F.js +0 -237
  444. package/dist/chunk-AUPTEHV7.js +0 -257
  445. package/dist/chunk-B2KYLEYM.js +0 -30
  446. package/dist/chunk-BJCET6RU.js +0 -263
  447. package/dist/chunk-BKW35Z4U.js +0 -26619
  448. package/dist/chunk-BKW35Z4U.js.map +0 -7
  449. package/dist/chunk-CJHNPYFQ.js +0 -2292
  450. package/dist/chunk-CJHNPYFQ.js.map +0 -7
  451. package/dist/chunk-CTVPW77S.js +0 -194
  452. package/dist/chunk-D6U65W7Q.js +0 -626
  453. package/dist/chunk-DJMDETVU.js +0 -2685
  454. package/dist/chunk-DKPAOVJH.js +0 -243
  455. package/dist/chunk-DRESQF33.js +0 -38
  456. package/dist/chunk-DXM5MQCZ.js +0 -382
  457. package/dist/chunk-ETXOEP4N.js +0 -184
  458. package/dist/chunk-FOUMNTII.js +0 -134
  459. package/dist/chunk-FTGLS763.js +0 -56
  460. package/dist/chunk-GN2A5NL5.js +0 -472
  461. package/dist/chunk-GWNCQ5YI.js +0 -468
  462. package/dist/chunk-GX6G2SSW.js +0 -26
  463. package/dist/chunk-H3YF55ZI.js +0 -848
  464. package/dist/chunk-IANE75G3.js +0 -444
  465. package/dist/chunk-IKZQST6E.js +0 -5213
  466. package/dist/chunk-IPRYYK26.js +0 -96
  467. package/dist/chunk-JL3PYV5F.js +0 -6375
  468. package/dist/chunk-K6VYSDB5.js +0 -276
  469. package/dist/chunk-KSS26PXB.js +0 -54
  470. package/dist/chunk-LO2QBHP6.js +0 -418
  471. package/dist/chunk-LO2QBHP6.js.map +0 -7
  472. package/dist/chunk-LSRFRZNP.js +0 -59
  473. package/dist/chunk-LYX4S6WA.js +0 -266
  474. package/dist/chunk-ME3HB3V6.js +0 -5787
  475. package/dist/chunk-ME3HB3V6.js.map +0 -7
  476. package/dist/chunk-MP7BA3GK.js +0 -14
  477. package/dist/chunk-MVSUESEV.js +0 -141
  478. package/dist/chunk-NQMS7WV3.js +0 -2799
  479. package/dist/chunk-NR6WFCPF.js +0 -348
  480. package/dist/chunk-NS2MZN3C.js +0 -562
  481. package/dist/chunk-NUA66GW7.js +0 -37
  482. package/dist/chunk-NYEFSOKD.js +0 -550
  483. package/dist/chunk-OVHQFZAE.js +0 -34
  484. package/dist/chunk-OVHQFZAE.js.map +0 -7
  485. package/dist/chunk-QM724EG2.js +0 -103
  486. package/dist/chunk-RIL33JCW.js +0 -102
  487. package/dist/chunk-RJAJG5KN.js +0 -2954
  488. package/dist/chunk-RJAJG5KN.js.map +0 -7
  489. package/dist/chunk-SLHXR4BZ.js +0 -82
  490. package/dist/chunk-SO76DLSZ.js +0 -299
  491. package/dist/chunk-T7CKGRGP.js +0 -398
  492. package/dist/chunk-T7CKGRGP.js.map +0 -7
  493. package/dist/chunk-TUO5I6LP.js +0 -123
  494. package/dist/chunk-TWTPWEYL.js +0 -240
  495. package/dist/chunk-U2GHNZ4N.js +0 -54
  496. package/dist/chunk-UAB5PGOP.js +0 -56
  497. package/dist/chunk-UCB3W3OT.js +0 -217
  498. package/dist/chunk-UJIB7QM3.js +0 -2334
  499. package/dist/chunk-UYQGTW7I.js +0 -1857
  500. package/dist/chunk-UYQGTW7I.js.map +0 -7
  501. package/dist/chunk-VBDJG6GZ.js +0 -2008
  502. package/dist/chunk-VOXUMZMG.js +0 -379
  503. package/dist/chunk-WCNMP54T.js +0 -516
  504. package/dist/chunk-WETOH7YW.js +0 -692
  505. package/dist/chunk-WKGKKM6F.js +0 -480
  506. package/dist/chunk-WV44DGEJ.js +0 -397
  507. package/dist/chunk-XVEEMQAT.js +0 -31
  508. package/dist/chunk-YBOHXANC.js +0 -302
  509. package/dist/chunk-YNQFOPS6.js +0 -203
  510. package/dist/chunk-YVQ4USPP.js +0 -340
  511. package/dist/chunk-ZWLT5QS3.js +0 -102
  512. package/dist/chunk-ZYAZHJPZ.js +0 -296
  513. package/dist/cohort-QSLKB4ZO.js +0 -66
  514. package/dist/cohortSunburst-AQFSNJ5K.js +0 -402
  515. package/dist/condition-MLS6TJHV.js +0 -323
  516. package/dist/controls-ZT3GZ667.js +0 -30
  517. package/dist/controls.config-F7NIPLKB.js +0 -30
  518. package/dist/correlation-ZEIQJGSQ.js +0 -91
  519. package/dist/customdata.inputui-6PJSAJK2.js +0 -280
  520. package/dist/dataDownload-CHMPXHBY.js +0 -325
  521. package/dist/dataDownload-CHMPXHBY.js.map +0 -7
  522. package/dist/databrowser.ui-EMZ5L2Y7.js +0 -421
  523. package/dist/dictionary-U2BWGY6B.js +0 -109
  524. package/dist/dnaMethylation-R34E2XNC.js +0 -29
  525. package/dist/dnaMethylation.integration.spec-4Z2AJHWY.js +0 -194
  526. package/dist/dofetch-JY4A7BYI.js +0 -47
  527. package/dist/e2pca-WSSCXX6A.js +0 -340
  528. package/dist/ep-ATUWEHDJ.js +0 -1247
  529. package/dist/expclust.gdc.spec-QRIRRPO7.js +0 -298
  530. package/dist/facet-5VDCSP3S.js +0 -556
  531. package/dist/gb-Y4UG6LFA.js +0 -77
  532. package/dist/geneExpClustering-OO67JNJ2.js +0 -240
  533. package/dist/geneExpression-5KGV3MAA.js +0 -29
  534. package/dist/geneExpression-KPRFXKU7.js +0 -309
  535. package/dist/geneExpression.unit.spec-YV45EZ5O.js +0 -151
  536. package/dist/geneORA-R74JPUTC.js +0 -269
  537. package/dist/geneRanking-IJTXNMHV.js +0 -544
  538. package/dist/geneVariant-HBAHT6LU.js +0 -32
  539. package/dist/geneVariant-JT3EGAIH.js +0 -289
  540. package/dist/geneVariant.integration.spec-TFQYPUAS.js +0 -672
  541. package/dist/genefusion.ui-MMTQMTHC.js +0 -299
  542. package/dist/geneset-VMBICNCZ.js +0 -199
  543. package/dist/genomeBrowser.spec-2XLLIYGA.js +0 -272
  544. package/dist/grin2-2RYPEUWV.js +0 -66
  545. package/dist/grin2-Y6KAFVV2.js +0 -945
  546. package/dist/hierCluster-EKGFBQT4.js +0 -51
  547. package/dist/hierCluster-Z4PVNMGS.js +0 -55
  548. package/dist/hierCluster.config-Q6WUNK2K.js +0 -32
  549. package/dist/hierCluster.integration.spec-2LHSHNFC.js +0 -479
  550. package/dist/hierCluster.interactivity-OGQ3KUY6.js +0 -45
  551. package/dist/hierCluster.renderers-3GJZXG75.js +0 -18
  552. package/dist/imagePlot-ZJEZPBX7.js +0 -152
  553. package/dist/importPlot-GFEFYEHZ.js +0 -8
  554. package/dist/isoformExpression-A2X3DSR6.js +0 -31
  555. package/dist/isoformExpression.unit.spec-VKMEGCL4.js +0 -233
  556. package/dist/junction-HWIHLQU2.js +0 -32
  557. package/dist/junction.customTerm-C3VWXEYH.js +0 -15
  558. package/dist/junction.unit.spec-ZYJGDOXJ.js +0 -178
  559. package/dist/launch.adhoc-HW5AZM4T.js +0 -33
  560. package/dist/leftlabel.sample-MTW2HRRQ.js +0 -253
  561. package/dist/lollipop-VWW5H6CR.js +0 -162
  562. package/dist/maf-KEJYO3H4.js +0 -451
  563. package/dist/maftimeline-MJZDSGSR.js +0 -583
  564. package/dist/matrix-3UJW6LOA.js +0 -50
  565. package/dist/matrix-W4AX5OBM.js +0 -55
  566. package/dist/matrix.cells-5DAIZ3E5.js +0 -25
  567. package/dist/matrix.config-PK26VPQT.js +0 -33
  568. package/dist/matrix.data-UK5DGKBK.js +0 -22
  569. package/dist/matrix.groups-NM4Q5YDN.js +0 -25
  570. package/dist/matrix.integration.spec-FGWNBCRR.js +0 -3156
  571. package/dist/matrix.interactivity-4C37PII5.js +0 -33
  572. package/dist/matrix.layout-ODV7WXUP.js +0 -35
  573. package/dist/matrix.legend-5MY7OXWN.js +0 -19
  574. package/dist/matrix.renderers-QA7W7ZUL.js +0 -30
  575. package/dist/matrix.serieses-4FSFJPCK.js +0 -18
  576. package/dist/matrix.sort-3QLFMBJ5.js +0 -25
  577. package/dist/matrix.sort.unit.spec-HVOC6IYT.js +0 -464
  578. package/dist/matrix.sorterUi-EY3SA6CG.js +0 -15
  579. package/dist/matrix.sorterUi.unit.spec-OAXWPZZI.js +0 -334
  580. package/dist/matrix.unit.spec-RAL7AU22.js +0 -146
  581. package/dist/mavb-KIM63AC4.js +0 -726
  582. package/dist/mds.fimo-DMAVM56P.js +0 -509
  583. package/dist/mds.samplescatterplot-KILTR2C7.js +0 -1545
  584. package/dist/mds.survivalplot-PV76ANBP.js +0 -472
  585. package/dist/multivalue-2V5LMQY7.js +0 -79
  586. package/dist/numericDictTermCluster-TGL4X6UC.js +0 -62
  587. package/dist/oncomatrix-2O7SLXHX.js +0 -286
  588. package/dist/oncomatrix.spec-HZJKOF5G.js +0 -439
  589. package/dist/plot.2dvaf-424NNMMA.js +0 -368
  590. package/dist/plot.app-YBZDNST2.js +0 -32
  591. package/dist/plot.barplot-YZQBYJUY.js +0 -93
  592. package/dist/plot.boxplot-5OW6IBQL.js +0 -142
  593. package/dist/plot.brainImaging-H3ABPPD3.js +0 -51
  594. package/dist/plot.disco-X7KCDWGX.js +0 -98
  595. package/dist/plot.ssgq-GYRVHTC7.js +0 -130
  596. package/dist/plot.vaf2cov-B2TELPHL.js +0 -249
  597. package/dist/polar2-5KNZRLXY.js +0 -228
  598. package/dist/profileForms-FY34KXCL.js +0 -937
  599. package/dist/profilePlot-3FX2TPYC.js +0 -45
  600. package/dist/proteinView-WSEO3LD3.js +0 -1346
  601. package/dist/proteomeCohortCompare-KA2DF3EE.js +0 -866
  602. package/dist/pseudbulk.unit.spec-AT3TFCOW.js +0 -82
  603. package/dist/pseudobulk-4ZRHUC7W.js +0 -31
  604. package/dist/qualitative-3OBGJRP6.js +0 -241
  605. package/dist/qualitative-FHJD44OA.js +0 -34
  606. package/dist/radar2-X757WR6V.js +0 -323
  607. package/dist/radarFacility2-GUBAK4Y3.js +0 -331
  608. package/dist/rememberedGvQ.unit.spec-ADO4Y2OE.js +0 -210
  609. package/dist/render-MZEPNEMU.js +0 -29
  610. package/dist/report-TUAFDGAE.js +0 -213
  611. package/dist/sampleView-X6YKCBE7.js +0 -39
  612. package/dist/samplelst-UPNRALBH.js +0 -114
  613. package/dist/samplematrix-W3HZK3IS.js +0 -2188
  614. package/dist/sc-UL7233UR.js +0 -77
  615. package/dist/scatter-FTJ77NUM.js +0 -919
  616. package/dist/scatter-VQQRIW6N.js +0 -84
  617. package/dist/selectGenomeWithTklst-HPYPSPFI.js +0 -125
  618. package/dist/singleCellCellType-XTKGOH6H.js +0 -29
  619. package/dist/singleCellCellType.unit.spec-A62GT72A.js +0 -150
  620. package/dist/singleCellGeneExpression-X7H5GTU3.js +0 -29
  621. package/dist/singleCellGeneExpression.unit.spec-2KQBHG7O.js +0 -144
  622. package/dist/singleCellNumericValue-6YS42PZ2.js +0 -29
  623. package/dist/singleCellNumericValue.unit.spec-DNVXQFKI.js +0 -412
  624. package/dist/singleCellPlot-MGOQ7EQV.js +0 -44
  625. package/dist/singlecell-CIOB5XON.js +0 -77
  626. package/dist/singlecell-QW3SLQD6.js +0 -1562
  627. package/dist/snp-6B4MIPKL.js +0 -29
  628. package/dist/snp.unit.spec-HNILS56E.js +0 -167
  629. package/dist/snplocus-DDFLYZ2Y.js +0 -200
  630. package/dist/snplst-JYKOV73J.js +0 -36
  631. package/dist/spliceevent.a53ss.diagram-IBD5ITXR.js +0 -142
  632. package/dist/spliceevent.exonskip.diagram-ZJGEVUYW.js +0 -274
  633. package/dist/spliceevent.noeventdiagram-RNLNTFOW.js +0 -451
  634. package/dist/ssGSEA-42VQLAXL.js +0 -29
  635. package/dist/ssGSEA.unit.spec-FBJANIKG.js +0 -79
  636. package/dist/stattable-FROSNTJY.js +0 -112
  637. package/dist/studyCatalog-XIYNJ24U.js +0 -457
  638. package/dist/summarizeCnvGeneexp-N3OFI24L.js +0 -154
  639. package/dist/summarizeGeneexpSurvival-J4DO2AL4.js +0 -101
  640. package/dist/summarizeMutationCnv-Y43BBSI4.js +0 -155
  641. package/dist/summarizeMutationDiagnosis-JAEAUFCA.js +0 -31
  642. package/dist/summarizeMutationSurvival-4QZDDXDV.js +0 -95
  643. package/dist/summary-DTJZ7NNA.js +0 -40
  644. package/dist/summary.integration.spec-HRRE3J45.js +0 -405
  645. package/dist/summaryInput-WCADUZBK.js +0 -238
  646. package/dist/sunburst-BGXSCB63.js +0 -274
  647. package/dist/sunburst-DSFFFP33.js +0 -504
  648. package/dist/sunburst-DSFFFP33.js.map +0 -7
  649. package/dist/survival-LFXQIWRT.js +0 -49
  650. package/dist/survival-ONWZ5RFM.js +0 -1248
  651. package/dist/survival.integration.spec-ZP7XWHQH.js +0 -609
  652. package/dist/svgraph-2SL2SJVU.js +0 -1377
  653. package/dist/svmr-ONIPMLC2.js +0 -3834
  654. package/dist/swimmer-2EJZH5PP.js +0 -785
  655. package/dist/swimmer-2EJZH5PP.js.map +0 -7
  656. package/dist/table-LLCFO4KK.js +0 -192
  657. package/dist/termCollection-DAHJGR5P.js +0 -247
  658. package/dist/termCollection-QIN53TIL.js +0 -29
  659. package/dist/termCollection.unit.spec-FQOX2IVP.js +0 -295
  660. package/dist/termCollectionFractionSelection-UKEVVZXL.js +0 -38
  661. package/dist/termCollectionFractionSelection.unit.spec-URGEYBU2.js +0 -184
  662. package/dist/tk-4PYQ6WJQ.js +0 -1116
  663. package/dist/tk-4PYQ6WJQ.js.map +0 -7
  664. package/dist/tk-GM7CJ2LU.js +0 -37
  665. package/dist/tp.ui-TRUHW6GP.js +0 -1453
  666. package/dist/tvs.categorical-IY6YSFVN.js +0 -28
  667. package/dist/tvs.condition-YTD7GOPW.js +0 -160
  668. package/dist/tvs.density-CB24PXDE.js +0 -19
  669. package/dist/tvs.dt-AQQIZD5Z.js +0 -34
  670. package/dist/tvs.dtcnv.categorical-WOAOGJSW.js +0 -31
  671. package/dist/tvs.dtcnv.continuous-TJBEPJGO.js +0 -72
  672. package/dist/tvs.dtfusion-SFMZQKKU.js +0 -31
  673. package/dist/tvs.dtitd-Q5RQTCLD.js +0 -31
  674. package/dist/tvs.dtsnvindel-UEK4O6WI.js +0 -31
  675. package/dist/tvs.dtsv-ECS4KEYG.js +0 -31
  676. package/dist/tvs.multivalue-CJIZ3I54.js +0 -84
  677. package/dist/tvs.numeric-UFAOJR2B.js +0 -32
  678. package/dist/tvs.samplelst-BVFY2P7Q.js +0 -95
  679. package/dist/tvs.survival-L56B3I55.js +0 -110
  680. package/dist/tvs.termCollection-BFIBVBSA.js +0 -118
  681. package/dist/vocabulary-MTKDDDGB.js +0 -32
  682. package/dist/wsi.direct-OSHY7VL4.js +0 -11514
  683. /package/dist/{2dmaf-O2SQ5RGD.js.map → 2dmaf-7YU3SNKL.js.map} +0 -0
  684. /package/dist/{AggMatrixInput-LUCTWXHU.js.map → AggMatrixInput-73CDR5FS.js.map} +0 -0
  685. /package/dist/{AggregateMatrix-JVMF27YL.js.map → AggregateMatrix-NNULVFBM.js.map} +0 -0
  686. /package/dist/{AppHeader-DJU6HRKO.js.map → AppHeader-EZDDLLXU.js.map} +0 -0
  687. /package/dist/{BoxPlot-22RXMPRL.js.map → BoxPlot-463E7CRY.js.map} +0 -0
  688. /package/dist/{CorrelationVolcano-PBZWPFSN.js.map → CorrelationVolcano-LHIIMBPP.js.map} +0 -0
  689. /package/dist/{Cuminc-EL74X5GY.js.map → Cuminc-UL2TCIKV.js.map} +0 -0
  690. /package/dist/{DE-W5SAMMRW.js.map → DE-VRFSKFDW.js.map} +0 -0
  691. /package/dist/{DEinput-ZKEFJZQU.js.map → DEinput-FZTQRWVC.js.map} +0 -0
  692. /package/dist/{DM-ABKDXMDG.js.map → DM-PO7CQZNT.js.map} +0 -0
  693. /package/dist/{DifferentialAnalysis-3JTZ5WCQ.js.map → DifferentialAnalysis-WK6HE3YH.js.map} +0 -0
  694. /package/dist/{Disco-ME53U25C.js.map → Disco-YBNQJQFG.js.map} +0 -0
  695. /package/dist/{Disco.UI-F7XKJMKR.js.map → Disco.UI-HC5XYBFV.js.map} +0 -0
  696. /package/dist/{DmrPlot-OWBXUTON.js.map → DmrPlot-7VJ5C66D.js.map} +0 -0
  697. /package/dist/{GB-7X6DBWKS.js.map → GB-VPFQRDRO.js.map} +0 -0
  698. /package/dist/{GSEA-GAZIEGD7.js.map → GSEA-ZEJB3QZQ.js.map} +0 -0
  699. /package/dist/{GeneExpInput-BAOC6ICV.js.map → GeneExpInput-SBDDIY6G.js.map} +0 -0
  700. /package/dist/{Geomap-OZERLL7V.js.map → Geomap-23AHGP2V.js.map} +0 -0
  701. /package/dist/{HicApp-WDH5LVTD.js.map → HicApp-7AQQE4CM.js.map} +0 -0
  702. /package/dist/{IDCViewer-XBZFU3BU.js.map → IDCViewer-NO5Q6VOB.js.map} +0 -0
  703. /package/dist/{NumBinaryEditor-5R4EUQOZ.js.map → NumBinaryEditor-DSRP4OOU.js.map} +0 -0
  704. /package/dist/{NumBinaryEditor.unit.spec-ULBXMOYY.js.map → NumBinaryEditor.unit.spec-TT666YL4.js.map} +0 -0
  705. /package/dist/{NumContEditor-EN6V4FLQ.js.map → NumContEditor-6CURFOCH.js.map} +0 -0
  706. /package/dist/{NumContEditor.unit.spec-VDWKNIFN.js.map → NumContEditor.unit.spec-MNVCFCMP.js.map} +0 -0
  707. /package/dist/{NumCustomBinEditor-UB34ALNZ.js.map → NumCustomBinEditor-SQRR5EFL.js.map} +0 -0
  708. /package/dist/{NumCustomBinEditor.unit.spec-WZXJ7GEC.js.map → NumCustomBinEditor.unit.spec-F7BZWGGT.js.map} +0 -0
  709. /package/dist/{NumDiscreteEditor-H6J67YEL.js.map → NumDiscreteEditor-U7Z2QNYP.js.map} +0 -0
  710. /package/dist/{NumDiscreteEditor.unit.spec-KJ7YU22W.js.map → NumDiscreteEditor.unit.spec-EIEBUZCX.js.map} +0 -0
  711. /package/dist/{NumRegularBinEditor-R5JVUG7J.js.map → NumRegularBinEditor-CVZSWN6Y.js.map} +0 -0
  712. /package/dist/{NumRegularBinEditor.unit.spec-RZ73FMNO.js.map → NumRegularBinEditor.unit.spec-ZMAJOIHL.js.map} +0 -0
  713. /package/dist/{NumSplineEditor-AOR6OAJA.js.map → NumSplineEditor-U43D5NBJ.js.map} +0 -0
  714. /package/dist/{NumSplineEditor.unit.spec-Z6ZEI3UO.js.map → NumSplineEditor.unit.spec-C52AADTS.js.map} +0 -0
  715. /package/dist/{NumericDensity-SRTFTDQA.js.map → NumericDensity-PUKDZOVI.js.map} +0 -0
  716. /package/dist/{NumericDensity.unit.spec-MRREBAYU.js.map → NumericDensity.unit.spec-2347S76D.js.map} +0 -0
  717. /package/dist/{NumericHandler-7RALUACA.js.map → NumericHandler-3RT32PTR.js.map} +0 -0
  718. /package/dist/{NumericHandler.unit.spec-MDO23WRB.js.map → NumericHandler.unit.spec-4PADL4KZ.js.map} +0 -0
  719. /package/dist/{ProteomeInput-MOBXHRD5.js.map → ProteomeInput-NFV4FW4U.js.map} +0 -0
  720. /package/dist/{Regression-XWT4NNTG.js.map → Regression-N7M7N6G4.js.map} +0 -0
  721. /package/dist/{RunChart2-Q7W5MWJS.js.map → RunChart2-UPQ7C6QE.js.map} +0 -0
  722. /package/dist/{SC-MM3JTEVL.js.map → SC-KBW2NHUV.js.map} +0 -0
  723. /package/dist/{Violin-XNTBDUPG.js.map → Violin-GWCOP3ZF.js.map} +0 -0
  724. /package/dist/{Wsi-22KJSFVH.js.map → Wsi-NXAEOYIS.js.map} +0 -0
  725. /package/dist/{adSandbox-TLYWQOOA.js.map → adSandbox-RPEWEEW7.js.map} +0 -0
  726. /package/dist/{animatedBubbleChart-67SY5JGP.js.map → animatedBubbleChart-ILDMZRBX.js.map} +0 -0
  727. /package/dist/{app-FG3KPE4R.js.map → app-LOUC4J47.js.map} +0 -0
  728. /package/dist/{app-VK5LYO6B.js.map → app-MRKXZ6AZ.js.map} +0 -0
  729. /package/dist/{barchart-IGWRVB6W.js.map → barchart-CJR37234.js.map} +0 -0
  730. /package/dist/{barchart2-TT6OBJJP.js.map → barchart2-QQYLTHWR.js.map} +0 -0
  731. /package/dist/{block.init-2Y6CNK7H.js.map → block.init-YJQTJIDO.js.map} +0 -0
  732. /package/dist/{block.mds.expressionrank-VZ4JVPTG.js.map → block.mds.expressionrank-GBMEI5KQ.js.map} +0 -0
  733. /package/dist/{block.mds.geneboxplot-NYMS32JP.js.map → block.mds.geneboxplot-XWE3E5IW.js.map} +0 -0
  734. /package/dist/{block.mds.junction-3R6C3B5W.js.map → block.mds.junction-QLEHFVPE.js.map} +0 -0
  735. /package/dist/{block.mds.svcnv-SO5CYYIQ.js.map → block.mds.svcnv-53DTOPBC.js.map} +0 -0
  736. /package/dist/{block.svg-R4ASXXNW.js.map → block.svg-57T37ABS.js.map} +0 -0
  737. /package/dist/{block.tk.aicheck-LYRTDZRA.js.map → block.tk.aicheck-6DXJTS3H.js.map} +0 -0
  738. /package/dist/{block.tk.bigwig.ui-3KMMZX2M.js.map → block.tk.bigwig.ui-OYIVXE2L.js.map} +0 -0
  739. /package/dist/{block.tk.hicstraw-7HH4PGFY.js.map → block.tk.hicstraw-UKTGEBWT.js.map} +0 -0
  740. /package/dist/{block.tk.junction-BPEKLYS2.js.map → block.tk.junction-ZU5KPFQ3.js.map} +0 -0
  741. /package/dist/{block.tk.junction.textmatrixui-2QU5DL2X.js.map → block.tk.junction.textmatrixui-P4WXTAZR.js.map} +0 -0
  742. /package/dist/{block.tk.ld-TJREYPNY.js.map → block.tk.ld-3PQ4O2AE.js.map} +0 -0
  743. /package/dist/{block.tk.menu-HDBZK4YP.js.map → block.tk.menu-LLITB6UA.js.map} +0 -0
  744. /package/dist/{block.tk.pgv-G5GCYBK2.js.map → block.tk.pgv-Y3FBXUO3.js.map} +0 -0
  745. /package/dist/{brainImaging-ODWHF7WZ.js.map → brainImaging-4B3WXLNP.js.map} +0 -0
  746. /package/dist/{brainRegions-DC7DEA7N.js.map → brainRegions-7VLONUWN.js.map} +0 -0
  747. /package/dist/{bubbleHeatmap-T5ACULRL.js.map → bubbleHeatmap-DI6GJRR6.js.map} +0 -0
  748. /package/dist/{cellTypeBubbleHeatmap-RQINXXTK.js.map → cellTypeBubbleHeatmap-HJY53DB2.js.map} +0 -0
  749. /package/dist/{chunk-TWTPWEYL.js.map → chunk-226MNBZ2.js.map} +0 -0
  750. /package/dist/{chunk-AUPTEHV7.js.map → chunk-2CNFGVHU.js.map} +0 -0
  751. /package/dist/{chunk-DJMDETVU.js.map → chunk-2MC3RNKA.js.map} +0 -0
  752. /package/dist/{chunk-2PHFY3VP.js.map → chunk-2OMX5AYB.js.map} +0 -0
  753. /package/dist/{chunk-64JHE3GV.js.map → chunk-2SL4QWUS.js.map} +0 -0
  754. /package/dist/{chunk-WETOH7YW.js.map → chunk-3KGBC5MK.js.map} +0 -0
  755. /package/dist/{chunk-UAB5PGOP.js.map → chunk-3PCRAPUV.js.map} +0 -0
  756. /package/dist/{chunk-ZWLT5QS3.js.map → chunk-4DBOMSKP.js.map} +0 -0
  757. /package/dist/{chunk-2UB6JZ3I.js.map → chunk-57BS6KNI.js.map} +0 -0
  758. /package/dist/{chunk-UJIB7QM3.js.map → chunk-5AXS5G4A.js.map} +0 -0
  759. /package/dist/{chunk-NS2MZN3C.js.map → chunk-5DI4UNH5.js.map} +0 -0
  760. /package/dist/{chunk-ATZNXW5F.js.map → chunk-5HJG6ECV.js.map} +0 -0
  761. /package/dist/{chunk-NYEFSOKD.js.map → chunk-5ZYANHGX.js.map} +0 -0
  762. /package/dist/{chunk-WV44DGEJ.js.map → chunk-6T4MN7LV.js.map} +0 -0
  763. /package/dist/{chunk-QM724EG2.js.map → chunk-75MRUW2K.js.map} +0 -0
  764. /package/dist/{chunk-7PQVNQFR.js.map → chunk-7J3W3KCN.js.map} +0 -0
  765. /package/dist/{chunk-4OOQ52ET.js.map → chunk-AIZYAKIE.js.map} +0 -0
  766. /package/dist/{chunk-VBDJG6GZ.js.map → chunk-AJNFI6GA.js.map} +0 -0
  767. /package/dist/{chunk-NQMS7WV3.js.map → chunk-BJAWDZBL.js.map} +0 -0
  768. /package/dist/{chunk-VOXUMZMG.js.map → chunk-C6PVZVIH.js.map} +0 -0
  769. /package/dist/{chunk-24ZS2XWC.js.map → chunk-C77X5ZUV.js.map} +0 -0
  770. /package/dist/{chunk-LSRFRZNP.js.map → chunk-C7KUMZQM.js.map} +0 -0
  771. /package/dist/{chunk-6MUJGVOH.js.map → chunk-C7ROKWV2.js.map} +0 -0
  772. /package/dist/{chunk-XVEEMQAT.js.map → chunk-CAH6LJ5Z.js.map} +0 -0
  773. /package/dist/{chunk-RIL33JCW.js.map → chunk-CUCP2GMT.js.map} +0 -0
  774. /package/dist/{chunk-FOUMNTII.js.map → chunk-DTGAMBRJ.js.map} +0 -0
  775. /package/dist/{chunk-7ZEJKFGW.js.map → chunk-DXT7GDHY.js.map} +0 -0
  776. /package/dist/{chunk-IKZQST6E.js.map → chunk-ENPMWVWG.js.map} +0 -0
  777. /package/dist/{chunk-DXM5MQCZ.js.map → chunk-EYKJQJ7R.js.map} +0 -0
  778. /package/dist/{chunk-B2KYLEYM.js.map → chunk-FE5TCBIT.js.map} +0 -0
  779. /package/dist/{chunk-UCB3W3OT.js.map → chunk-FJ2JV2VK.js.map} +0 -0
  780. /package/dist/{chunk-DRESQF33.js.map → chunk-FZYVPRVQ.js.map} +0 -0
  781. /package/dist/{chunk-5TPWMYBG.js.map → chunk-GBKQHVKJ.js.map} +0 -0
  782. /package/dist/{chunk-2QFMKWNS.js.map → chunk-GUW7VTUL.js.map} +0 -0
  783. /package/dist/{chunk-3GQ54XTJ.js.map → chunk-H7F6DMJA.js.map} +0 -0
  784. /package/dist/{chunk-IPRYYK26.js.map → chunk-HH3NUAR2.js.map} +0 -0
  785. /package/dist/{chunk-A6ZUYQHO.js.map → chunk-HRTPGNOG.js.map} +0 -0
  786. /package/dist/{chunk-H3YF55ZI.js.map → chunk-IFPRYTS7.js.map} +0 -0
  787. /package/dist/{chunk-YBOHXANC.js.map → chunk-IJSFSUI4.js.map} +0 -0
  788. /package/dist/{chunk-BJCET6RU.js.map → chunk-IRQKX6DL.js.map} +0 -0
  789. /package/dist/{chunk-GN2A5NL5.js.map → chunk-JHLF2ZC2.js.map} +0 -0
  790. /package/dist/{chunk-ALIMVUHR.js.map → chunk-JNZL7HKB.js.map} +0 -0
  791. /package/dist/{chunk-GX6G2SSW.js.map → chunk-K2ARLT2A.js.map} +0 -0
  792. /package/dist/{chunk-SO76DLSZ.js.map → chunk-K3G56J5R.js.map} +0 -0
  793. /package/dist/{chunk-WCNMP54T.js.map → chunk-KKUCG2QE.js.map} +0 -0
  794. /package/dist/{chunk-D6U65W7Q.js.map → chunk-KPXCXBNU.js.map} +0 -0
  795. /package/dist/{chunk-6YGSVJJD.js.map → chunk-MANAUI7R.js.map} +0 -0
  796. /package/dist/{chunk-7XW4JWMJ.js.map → chunk-MEUSRAOE.js.map} +0 -0
  797. /package/dist/{chunk-NR6WFCPF.js.map → chunk-MHWYRNGA.js.map} +0 -0
  798. /package/dist/{chunk-MP7BA3GK.js.map → chunk-MSTYU3QO.js.map} +0 -0
  799. /package/dist/{chunk-MVSUESEV.js.map → chunk-MWARRQT4.js.map} +0 -0
  800. /package/dist/{chunk-YNQFOPS6.js.map → chunk-MXKYPTZ7.js.map} +0 -0
  801. /package/dist/{chunk-NUA66GW7.js.map → chunk-NX5IB4IY.js.map} +0 -0
  802. /package/dist/{chunk-4ENIOXIT.js.map → chunk-OZUF7O2S.js.map} +0 -0
  803. /package/dist/{chunk-SLHXR4BZ.js.map → chunk-QNCE6EOK.js.map} +0 -0
  804. /package/dist/{chunk-5NI77Z3O.js.map → chunk-RIHO7ZD5.js.map} +0 -0
  805. /package/dist/{chunk-LYX4S6WA.js.map → chunk-RV335DF2.js.map} +0 -0
  806. /package/dist/{chunk-3IE6FDVA.js.map → chunk-THAUD62Q.js.map} +0 -0
  807. /package/dist/{chunk-JL3PYV5F.js.map → chunk-VBTBUXXX.js.map} +0 -0
  808. /package/dist/{chunk-FTGLS763.js.map → chunk-VHWJK2MP.js.map} +0 -0
  809. /package/dist/{chunk-K6VYSDB5.js.map → chunk-VLIOMJDR.js.map} +0 -0
  810. /package/dist/{chunk-U2GHNZ4N.js.map → chunk-VMK4RHV5.js.map} +0 -0
  811. /package/dist/{chunk-GWNCQ5YI.js.map → chunk-WKT7RF3C.js.map} +0 -0
  812. /package/dist/{chunk-ETXOEP4N.js.map → chunk-WXSMUSU7.js.map} +0 -0
  813. /package/dist/{chunk-ZYAZHJPZ.js.map → chunk-WXSX5OQJ.js.map} +0 -0
  814. /package/dist/{chunk-CTVPW77S.js.map → chunk-WY3IORKG.js.map} +0 -0
  815. /package/dist/{chunk-WKGKKM6F.js.map → chunk-WYSOOKFJ.js.map} +0 -0
  816. /package/dist/{chunk-TUO5I6LP.js.map → chunk-XBBFFOLS.js.map} +0 -0
  817. /package/dist/{chunk-YVQ4USPP.js.map → chunk-XSRQGX5H.js.map} +0 -0
  818. /package/dist/{chunk-KSS26PXB.js.map → chunk-YLL6CTBL.js.map} +0 -0
  819. /package/dist/{chunk-ANBGNYNP.js.map → chunk-YPBY37KD.js.map} +0 -0
  820. /package/dist/{chunk-DKPAOVJH.js.map → chunk-YUNJBIK4.js.map} +0 -0
  821. /package/dist/{chunk-IANE75G3.js.map → chunk-Z5ECCUNG.js.map} +0 -0
  822. /package/dist/{cohort-QSLKB4ZO.js.map → cohort-5WL6UJOS.js.map} +0 -0
  823. /package/dist/{cohortSunburst-AQFSNJ5K.js.map → cohortSunburst-R3Z5KJQL.js.map} +0 -0
  824. /package/dist/{condition-MLS6TJHV.js.map → condition-2IILUMVB.js.map} +0 -0
  825. /package/dist/{controls-ZT3GZ667.js.map → controls-G3JITZF5.js.map} +0 -0
  826. /package/dist/{controls.config-F7NIPLKB.js.map → controls.config-BO7KPPET.js.map} +0 -0
  827. /package/dist/{correlation-ZEIQJGSQ.js.map → correlation-CZILLVEM.js.map} +0 -0
  828. /package/dist/{customdata.inputui-6PJSAJK2.js.map → customdata.inputui-BXFQAMTR.js.map} +0 -0
  829. /package/dist/{databrowser.ui-EMZ5L2Y7.js.map → databrowser.ui-V2NJQF3U.js.map} +0 -0
  830. /package/dist/{dictionary-U2BWGY6B.js.map → dictionary-OVAQX6R3.js.map} +0 -0
  831. /package/dist/{dnaMethylation-R34E2XNC.js.map → dnaMethylation-DHPFRXB2.js.map} +0 -0
  832. /package/dist/{dnaMethylation.integration.spec-4Z2AJHWY.js.map → dnaMethylation.integration.spec-PJLIRGN5.js.map} +0 -0
  833. /package/dist/{dofetch-JY4A7BYI.js.map → dofetch-KBTN6OW4.js.map} +0 -0
  834. /package/dist/{e2pca-WSSCXX6A.js.map → e2pca-O7SNMJGB.js.map} +0 -0
  835. /package/dist/{ep-ATUWEHDJ.js.map → ep-NIVLKG4S.js.map} +0 -0
  836. /package/dist/{expclust.gdc.spec-QRIRRPO7.js.map → expclust.gdc.spec-LVCD6C43.js.map} +0 -0
  837. /package/dist/{facet-5VDCSP3S.js.map → facet-LB4SCXE4.js.map} +0 -0
  838. /package/dist/{gb-Y4UG6LFA.js.map → gb-3IJ4NCPO.js.map} +0 -0
  839. /package/dist/{geneExpClustering-OO67JNJ2.js.map → geneExpClustering-SIAC7CMA.js.map} +0 -0
  840. /package/dist/{geneExpression-KPRFXKU7.js.map → geneExpression-KPUOZ4PT.js.map} +0 -0
  841. /package/dist/{geneExpression-5KGV3MAA.js.map → geneExpression-P2TTZXN2.js.map} +0 -0
  842. /package/dist/{geneExpression.unit.spec-YV45EZ5O.js.map → geneExpression.unit.spec-Q5D6XHUF.js.map} +0 -0
  843. /package/dist/{geneORA-R74JPUTC.js.map → geneORA-PKUIJKTL.js.map} +0 -0
  844. /package/dist/{geneRanking-IJTXNMHV.js.map → geneRanking-ZGT5MHBV.js.map} +0 -0
  845. /package/dist/{geneVariant-JT3EGAIH.js.map → geneVariant-24YNANTT.js.map} +0 -0
  846. /package/dist/{geneVariant-HBAHT6LU.js.map → geneVariant-CDGENHWQ.js.map} +0 -0
  847. /package/dist/{geneVariant.integration.spec-TFQYPUAS.js.map → geneVariant.integration.spec-7QW4C2WO.js.map} +0 -0
  848. /package/dist/{genefusion.ui-MMTQMTHC.js.map → genefusion.ui-NVXGSBXD.js.map} +0 -0
  849. /package/dist/{geneset-VMBICNCZ.js.map → geneset-7STL6UDD.js.map} +0 -0
  850. /package/dist/{genomeBrowser.spec-2XLLIYGA.js.map → genomeBrowser.spec-OE2CIP7I.js.map} +0 -0
  851. /package/dist/{grin2-2RYPEUWV.js.map → grin2-2HXUIY5O.js.map} +0 -0
  852. /package/dist/{grin2-Y6KAFVV2.js.map → grin2-32IIJR5E.js.map} +0 -0
  853. /package/dist/{hierCluster-EKGFBQT4.js.map → hierCluster-MDZEI2KB.js.map} +0 -0
  854. /package/dist/{hierCluster-Z4PVNMGS.js.map → hierCluster-T3PZUGBI.js.map} +0 -0
  855. /package/dist/{hierCluster.config-Q6WUNK2K.js.map → hierCluster.config-7UN6AYGB.js.map} +0 -0
  856. /package/dist/{hierCluster.integration.spec-2LHSHNFC.js.map → hierCluster.integration.spec-DWOYVK6T.js.map} +0 -0
  857. /package/dist/{hierCluster.interactivity-OGQ3KUY6.js.map → hierCluster.interactivity-5OM6XNFG.js.map} +0 -0
  858. /package/dist/{hierCluster.renderers-3GJZXG75.js.map → hierCluster.renderers-YGX6MZZW.js.map} +0 -0
  859. /package/dist/{imagePlot-ZJEZPBX7.js.map → imagePlot-KBRXDV5G.js.map} +0 -0
  860. /package/dist/{importPlot-GFEFYEHZ.js.map → importPlot-DJMIC22L.js.map} +0 -0
  861. /package/dist/{isoformExpression-A2X3DSR6.js.map → isoformExpression-SWDWADRC.js.map} +0 -0
  862. /package/dist/{isoformExpression.unit.spec-VKMEGCL4.js.map → isoformExpression.unit.spec-2U5KCYBP.js.map} +0 -0
  863. /package/dist/{junction-HWIHLQU2.js.map → junction-NMXVVGRG.js.map} +0 -0
  864. /package/dist/{junction.customTerm-C3VWXEYH.js.map → junction.customTerm-3R2GNE3A.js.map} +0 -0
  865. /package/dist/{junction.unit.spec-ZYJGDOXJ.js.map → junction.unit.spec-JTGBPPN7.js.map} +0 -0
  866. /package/dist/{launch.adhoc-HW5AZM4T.js.map → launch.adhoc-YB5SKMNY.js.map} +0 -0
  867. /package/dist/{leftlabel.sample-MTW2HRRQ.js.map → leftlabel.sample-QKXIODCS.js.map} +0 -0
  868. /package/dist/{lollipop-VWW5H6CR.js.map → lollipop-TSZ62PBH.js.map} +0 -0
  869. /package/dist/{maf-KEJYO3H4.js.map → maf-4L5YN4CG.js.map} +0 -0
  870. /package/dist/{maftimeline-MJZDSGSR.js.map → maftimeline-VOYB3NY3.js.map} +0 -0
  871. /package/dist/{matrix-3UJW6LOA.js.map → matrix-IWJECVTF.js.map} +0 -0
  872. /package/dist/{matrix-W4AX5OBM.js.map → matrix-MMJAJZA7.js.map} +0 -0
  873. /package/dist/{matrix.cells-5DAIZ3E5.js.map → matrix.cells-5RTZUJVN.js.map} +0 -0
  874. /package/dist/{matrix.config-PK26VPQT.js.map → matrix.config-DZGOZWJS.js.map} +0 -0
  875. /package/dist/{matrix.data-UK5DGKBK.js.map → matrix.data-Y5TPRGMW.js.map} +0 -0
  876. /package/dist/{matrix.groups-NM4Q5YDN.js.map → matrix.groups-6DXCAY4P.js.map} +0 -0
  877. /package/dist/{matrix.integration.spec-FGWNBCRR.js.map → matrix.integration.spec-2N237E7T.js.map} +0 -0
  878. /package/dist/{matrix.interactivity-4C37PII5.js.map → matrix.interactivity-FL33UUKR.js.map} +0 -0
  879. /package/dist/{matrix.layout-ODV7WXUP.js.map → matrix.layout-7SYHV3KJ.js.map} +0 -0
  880. /package/dist/{matrix.legend-5MY7OXWN.js.map → matrix.legend-S3E76TVO.js.map} +0 -0
  881. /package/dist/{matrix.renderers-QA7W7ZUL.js.map → matrix.renderers-3SIBT2RP.js.map} +0 -0
  882. /package/dist/{matrix.serieses-4FSFJPCK.js.map → matrix.serieses-3UGLZW25.js.map} +0 -0
  883. /package/dist/{matrix.sort-3QLFMBJ5.js.map → matrix.sort-A7CNLDUJ.js.map} +0 -0
  884. /package/dist/{matrix.sort.unit.spec-HVOC6IYT.js.map → matrix.sort.unit.spec-L3H44T6I.js.map} +0 -0
  885. /package/dist/{matrix.sorterUi-EY3SA6CG.js.map → matrix.sorterUi-6PZR3YOD.js.map} +0 -0
  886. /package/dist/{matrix.sorterUi.unit.spec-OAXWPZZI.js.map → matrix.sorterUi.unit.spec-2NRU5UFH.js.map} +0 -0
  887. /package/dist/{matrix.unit.spec-RAL7AU22.js.map → matrix.unit.spec-HRZIJB6T.js.map} +0 -0
  888. /package/dist/{mavb-KIM63AC4.js.map → mavb-ZVRQSDPS.js.map} +0 -0
  889. /package/dist/{mds.fimo-DMAVM56P.js.map → mds.fimo-ZKETTET7.js.map} +0 -0
  890. /package/dist/{mds.samplescatterplot-KILTR2C7.js.map → mds.samplescatterplot-ZV3UNRLP.js.map} +0 -0
  891. /package/dist/{mds.survivalplot-PV76ANBP.js.map → mds.survivalplot-OVXZRTU4.js.map} +0 -0
  892. /package/dist/{multivalue-2V5LMQY7.js.map → multivalue-6BE5IA4F.js.map} +0 -0
  893. /package/dist/{numericDictTermCluster-TGL4X6UC.js.map → numericDictTermCluster-6XDVVWLE.js.map} +0 -0
  894. /package/dist/{oncomatrix-2O7SLXHX.js.map → oncomatrix-XK62NEOO.js.map} +0 -0
  895. /package/dist/{oncomatrix.spec-HZJKOF5G.js.map → oncomatrix.spec-YVTCHOPS.js.map} +0 -0
  896. /package/dist/{plot.2dvaf-424NNMMA.js.map → plot.2dvaf-NUOBWMNX.js.map} +0 -0
  897. /package/dist/{plot.app-YBZDNST2.js.map → plot.app-G6IQWXTV.js.map} +0 -0
  898. /package/dist/{plot.barplot-YZQBYJUY.js.map → plot.barplot-6QJ6HEJR.js.map} +0 -0
  899. /package/dist/{plot.boxplot-5OW6IBQL.js.map → plot.boxplot-XKQJSW2O.js.map} +0 -0
  900. /package/dist/{plot.brainImaging-H3ABPPD3.js.map → plot.brainImaging-UTHFJFXU.js.map} +0 -0
  901. /package/dist/{plot.disco-X7KCDWGX.js.map → plot.disco-3MSCX7TM.js.map} +0 -0
  902. /package/dist/{plot.ssgq-GYRVHTC7.js.map → plot.ssgq-4KBVHF42.js.map} +0 -0
  903. /package/dist/{plot.vaf2cov-B2TELPHL.js.map → plot.vaf2cov-OGUQSSDS.js.map} +0 -0
  904. /package/dist/{polar2-5KNZRLXY.js.map → polar2-V7M56GTZ.js.map} +0 -0
  905. /package/dist/{profileForms-FY34KXCL.js.map → profileForms-TS3BJLHH.js.map} +0 -0
  906. /package/dist/{profilePlot-3FX2TPYC.js.map → profilePlot-DP5272HR.js.map} +0 -0
  907. /package/dist/{proteinView-WSEO3LD3.js.map → proteinView-K4K4SP3L.js.map} +0 -0
  908. /package/dist/{proteomeCohortCompare-KA2DF3EE.js.map → proteomeCohortCompare-SFWVGLFK.js.map} +0 -0
  909. /package/dist/{pseudbulk.unit.spec-AT3TFCOW.js.map → pseudbulk.unit.spec-NFOA7J2C.js.map} +0 -0
  910. /package/dist/{pseudobulk-4ZRHUC7W.js.map → pseudobulk-XKZQEZ4I.js.map} +0 -0
  911. /package/dist/{qualitative-3OBGJRP6.js.map → qualitative-7OSFNVI5.js.map} +0 -0
  912. /package/dist/{qualitative-FHJD44OA.js.map → qualitative-OIIN6E4Y.js.map} +0 -0
  913. /package/dist/{radar2-X757WR6V.js.map → radar2-AHZJKX7S.js.map} +0 -0
  914. /package/dist/{radarFacility2-GUBAK4Y3.js.map → radarFacility2-OUW6D5E7.js.map} +0 -0
  915. /package/dist/{rememberedGvQ.unit.spec-ADO4Y2OE.js.map → rememberedGvQ.unit.spec-SHTMMZGG.js.map} +0 -0
  916. /package/dist/{render-MZEPNEMU.js.map → render-7UZSGX3Q.js.map} +0 -0
  917. /package/dist/{report-TUAFDGAE.js.map → report-J7HKTXZ2.js.map} +0 -0
  918. /package/dist/{sampleView-X6YKCBE7.js.map → sampleView-6547OUIM.js.map} +0 -0
  919. /package/dist/{samplelst-UPNRALBH.js.map → samplelst-UHF23UEB.js.map} +0 -0
  920. /package/dist/{samplematrix-W3HZK3IS.js.map → samplematrix-OOKS3TMR.js.map} +0 -0
  921. /package/dist/{sc-UL7233UR.js.map → sc-WF2BLGNG.js.map} +0 -0
  922. /package/dist/{scatter-VQQRIW6N.js.map → scatter-ABCVFGRV.js.map} +0 -0
  923. /package/dist/{scatter-FTJ77NUM.js.map → scatter-WF7XM3IA.js.map} +0 -0
  924. /package/dist/{selectGenomeWithTklst-HPYPSPFI.js.map → selectGenomeWithTklst-67HU5KRB.js.map} +0 -0
  925. /package/dist/{singleCellCellType-XTKGOH6H.js.map → singleCellCellType-3FZPJ25V.js.map} +0 -0
  926. /package/dist/{singleCellCellType.unit.spec-A62GT72A.js.map → singleCellCellType.unit.spec-TOMREHWK.js.map} +0 -0
  927. /package/dist/{singleCellGeneExpression-X7H5GTU3.js.map → singleCellGeneExpression-NQTJ5KJQ.js.map} +0 -0
  928. /package/dist/{singleCellGeneExpression.unit.spec-2KQBHG7O.js.map → singleCellGeneExpression.unit.spec-ZWUQTU2N.js.map} +0 -0
  929. /package/dist/{singleCellNumericValue-6YS42PZ2.js.map → singleCellNumericValue-VI7H722L.js.map} +0 -0
  930. /package/dist/{singleCellNumericValue.unit.spec-DNVXQFKI.js.map → singleCellNumericValue.unit.spec-QGLHES7H.js.map} +0 -0
  931. /package/dist/{singleCellPlot-MGOQ7EQV.js.map → singleCellPlot-RU5T6SJK.js.map} +0 -0
  932. /package/dist/{singlecell-QW3SLQD6.js.map → singlecell-C3CJVNXP.js.map} +0 -0
  933. /package/dist/{singlecell-CIOB5XON.js.map → singlecell-NRQZ7KC6.js.map} +0 -0
  934. /package/dist/{snp-6B4MIPKL.js.map → snp-X6XY65VS.js.map} +0 -0
  935. /package/dist/{snp.unit.spec-HNILS56E.js.map → snp.unit.spec-6EENK7GQ.js.map} +0 -0
  936. /package/dist/{snplocus-DDFLYZ2Y.js.map → snplocus-R4JA6TFT.js.map} +0 -0
  937. /package/dist/{snplst-JYKOV73J.js.map → snplst-SOWVHSXH.js.map} +0 -0
  938. /package/dist/{spliceevent.a53ss.diagram-IBD5ITXR.js.map → spliceevent.a53ss.diagram-IRLCCVQZ.js.map} +0 -0
  939. /package/dist/{spliceevent.exonskip.diagram-ZJGEVUYW.js.map → spliceevent.exonskip.diagram-4KG7LE5D.js.map} +0 -0
  940. /package/dist/{spliceevent.noeventdiagram-RNLNTFOW.js.map → spliceevent.noeventdiagram-OWXAJJX7.js.map} +0 -0
  941. /package/dist/{ssGSEA-42VQLAXL.js.map → ssGSEA-EMOKPLMP.js.map} +0 -0
  942. /package/dist/{ssGSEA.unit.spec-FBJANIKG.js.map → ssGSEA.unit.spec-KXQ7R5WH.js.map} +0 -0
  943. /package/dist/{stattable-FROSNTJY.js.map → stattable-H2G7MOZG.js.map} +0 -0
  944. /package/dist/{studyCatalog-XIYNJ24U.js.map → studyCatalog-3ITQXWFL.js.map} +0 -0
  945. /package/dist/{summarizeCnvGeneexp-N3OFI24L.js.map → summarizeCnvGeneexp-ZIPU6YDY.js.map} +0 -0
  946. /package/dist/{summarizeGeneexpSurvival-J4DO2AL4.js.map → summarizeGeneexpSurvival-3RYU226R.js.map} +0 -0
  947. /package/dist/{summarizeMutationCnv-Y43BBSI4.js.map → summarizeMutationCnv-RGDBUB22.js.map} +0 -0
  948. /package/dist/{summarizeMutationDiagnosis-JAEAUFCA.js.map → summarizeMutationDiagnosis-Z4MZE6Y4.js.map} +0 -0
  949. /package/dist/{summarizeMutationSurvival-4QZDDXDV.js.map → summarizeMutationSurvival-Z5CNRH7E.js.map} +0 -0
  950. /package/dist/{summary-DTJZ7NNA.js.map → summary-6QQCNX3B.js.map} +0 -0
  951. /package/dist/{summary.integration.spec-HRRE3J45.js.map → summary.integration.spec-3ULXTZUP.js.map} +0 -0
  952. /package/dist/{summaryInput-WCADUZBK.js.map → summaryInput-4QKR34QB.js.map} +0 -0
  953. /package/dist/{termCollection-QIN53TIL.js.map → sunburst-KB3BWC72.js.map} +0 -0
  954. /package/dist/{sunburst-BGXSCB63.js.map → sunburst-XTFBHZNH.js.map} +0 -0
  955. /package/dist/{survival-LFXQIWRT.js.map → survival-7O6ZK63E.js.map} +0 -0
  956. /package/dist/{survival-ONWZ5RFM.js.map → survival-NNCY4K6C.js.map} +0 -0
  957. /package/dist/{survival.integration.spec-ZP7XWHQH.js.map → survival.integration.spec-ZYZHZAXA.js.map} +0 -0
  958. /package/dist/{svgraph-2SL2SJVU.js.map → svgraph-ZLSFFEAC.js.map} +0 -0
  959. /package/dist/{svmr-ONIPMLC2.js.map → svmr-REBBDEYM.js.map} +0 -0
  960. /package/dist/{table-LLCFO4KK.js.map → table-CWIQQESJ.js.map} +0 -0
  961. /package/dist/{termCollectionFractionSelection-UKEVVZXL.js.map → termCollection-7TYJSQ45.js.map} +0 -0
  962. /package/dist/{termCollection-DAHJGR5P.js.map → termCollection-7Z55QNL7.js.map} +0 -0
  963. /package/dist/{termCollection.unit.spec-FQOX2IVP.js.map → termCollection.unit.spec-LQ5MIBDH.js.map} +0 -0
  964. /package/dist/{tk-GM7CJ2LU.js.map → termCollectionFractionSelection-24DZYVDU.js.map} +0 -0
  965. /package/dist/{termCollectionFractionSelection.unit.spec-URGEYBU2.js.map → termCollectionFractionSelection.unit.spec-DCV2CFS5.js.map} +0 -0
  966. /package/dist/{tvs.categorical-IY6YSFVN.js.map → tk-2WZFPRCP.js.map} +0 -0
  967. /package/dist/{tp.ui-TRUHW6GP.js.map → tp.ui-HXQX2UH4.js.map} +0 -0
  968. /package/dist/{tvs.density-CB24PXDE.js.map → tvs.categorical-4D3JI2ER.js.map} +0 -0
  969. /package/dist/{tvs.condition-YTD7GOPW.js.map → tvs.condition-62FXFHZ5.js.map} +0 -0
  970. /package/dist/{tvs.dt-AQQIZD5Z.js.map → tvs.density-IGO4I4T2.js.map} +0 -0
  971. /package/dist/{tvs.numeric-UFAOJR2B.js.map → tvs.dt-FZSVMJOO.js.map} +0 -0
  972. /package/dist/{tvs.dtcnv.categorical-WOAOGJSW.js.map → tvs.dtcnv.categorical-PPFQIC42.js.map} +0 -0
  973. /package/dist/{tvs.dtcnv.continuous-TJBEPJGO.js.map → tvs.dtcnv.continuous-TV2IGHY4.js.map} +0 -0
  974. /package/dist/{tvs.dtfusion-SFMZQKKU.js.map → tvs.dtfusion-ON4BA4XJ.js.map} +0 -0
  975. /package/dist/{tvs.dtitd-Q5RQTCLD.js.map → tvs.dtitd-VFNROOWQ.js.map} +0 -0
  976. /package/dist/{tvs.dtsnvindel-UEK4O6WI.js.map → tvs.dtsnvindel-ZXOP37T5.js.map} +0 -0
  977. /package/dist/{tvs.dtsv-ECS4KEYG.js.map → tvs.dtsv-EUHPTW7J.js.map} +0 -0
  978. /package/dist/{tvs.multivalue-CJIZ3I54.js.map → tvs.multivalue-NHVXZNDI.js.map} +0 -0
  979. /package/dist/{vocabulary-MTKDDDGB.js.map → tvs.numeric-FPWDPO3J.js.map} +0 -0
  980. /package/dist/{tvs.samplelst-BVFY2P7Q.js.map → tvs.samplelst-ZZHRNUP4.js.map} +0 -0
  981. /package/dist/{tvs.survival-L56B3I55.js.map → tvs.survival-F3KSG3U6.js.map} +0 -0
  982. /package/dist/{tvs.termCollection-BFIBVBSA.js.map → tvs.termCollection-B37DZLDY.js.map} +0 -0
  983. /package/dist/{wsi.direct-OSHY7VL4.js.map → wsi.direct-3YH3QGQD.js.map} +0 -0
@@ -1,4378 +0,0 @@
1
- import {
2
- d3lasso
3
- } from "./chunk-JH73IL4C.js";
4
- import {
5
- getId
6
- } from "./chunk-UYQGTW7I.js";
7
- import {
8
- BufferGeometry,
9
- CanvasTexture,
10
- Color,
11
- Float32BufferAttribute,
12
- Line,
13
- LineBasicMaterial,
14
- LinearSRGBColorSpace,
15
- Mesh,
16
- MeshBasicMaterial,
17
- PerspectiveCamera,
18
- PlaneGeometry,
19
- Points,
20
- PointsMaterial,
21
- Scene,
22
- TextureLoader,
23
- Vector2,
24
- Vector3,
25
- WebGLRenderer
26
- } from "./chunk-72PLI3GC.js";
27
- import {
28
- ColorScale,
29
- DataPointInteractions,
30
- Tabs,
31
- addGeneSearchbox,
32
- addNewGroup,
33
- controlsInit,
34
- digestMessage,
35
- downloadSingleSVG,
36
- downloadTable,
37
- fillTermWrapper,
38
- formatHeaderText,
39
- getFilter,
40
- getMaxLabelWidth,
41
- getSamplelstTW,
42
- getSingleCellSpecialCase,
43
- renderTable,
44
- sayerror,
45
- shapeSelector,
46
- shapesArray,
47
- table2col
48
- } from "./chunk-BKW35Z4U.js";
49
- import {
50
- Menu
51
- } from "./chunk-CNFTQSNE.js";
52
- import {
53
- icons
54
- } from "./chunk-3CIL7KH7.js";
55
- import {
56
- calculatePadding,
57
- dofetch3,
58
- getCoordinate,
59
- xAxisOffSet,
60
- yAxisOffSet
61
- } from "./chunk-CJHNPYFQ.js";
62
- import {
63
- dictionaryNumericTypes,
64
- getDateFromNumber,
65
- getDateStrFromNumber,
66
- isNumericTerm,
67
- numericTypes
68
- } from "./chunk-GN2A5NL5.js";
69
- import {
70
- Greys_default,
71
- SINGLECELL_CELLTYPE,
72
- SINGLECELL_GENE_EXPRESSION,
73
- SINGLECELL_NUMERIC_VALUE,
74
- axisBottom,
75
- axisLeft,
76
- density_default,
77
- dt2label,
78
- getColors,
79
- identity,
80
- line_default,
81
- mclass,
82
- morigin,
83
- path_default,
84
- zoom_default
85
- } from "./chunk-ME3HB3V6.js";
86
- import {
87
- copyMerge,
88
- getCompInit
89
- } from "./chunk-HBNB5TRH.js";
90
- import {
91
- extent,
92
- linear,
93
- max,
94
- sequential,
95
- time
96
- } from "./chunk-4OLM3KSB.js";
97
- import {
98
- roundValueAuto
99
- } from "./chunk-TLT4YIG3.js";
100
- import {
101
- create_default,
102
- pointer_default,
103
- select_default
104
- } from "./chunk-I6Y4O3RR.js";
105
- import {
106
- rgb
107
- } from "./chunk-Q5RDQNIT.js";
108
- import {
109
- __commonJS,
110
- __toESM
111
- } from "./chunk-HS5PO5ZQ.js";
112
-
113
- // ../node_modules/d3-regression/dist/d3-regression.js
114
- var require_d3_regression = __commonJS({
115
- "../node_modules/d3-regression/dist/d3-regression.js"(exports, module) {
116
- (function(global, factory) {
117
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = global || self, factory(global.d3 = {}));
118
- })(exports, (function(exports2) {
119
- "use strict";
120
- function _slicedToArray(arr, i) {
121
- return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
122
- }
123
- function _arrayWithHoles(arr) {
124
- if (Array.isArray(arr)) return arr;
125
- }
126
- function _iterableToArrayLimit(arr, i) {
127
- var _arr = [];
128
- var _n = true;
129
- var _d = false;
130
- var _e = void 0;
131
- try {
132
- for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
133
- _arr.push(_s.value);
134
- if (i && _arr.length === i) break;
135
- }
136
- } catch (err) {
137
- _d = true;
138
- _e = err;
139
- } finally {
140
- try {
141
- if (!_n && _i["return"] != null) _i["return"]();
142
- } finally {
143
- if (_d) throw _e;
144
- }
145
- }
146
- return _arr;
147
- }
148
- function _nonIterableRest() {
149
- throw new TypeError("Invalid attempt to destructure non-iterable instance");
150
- }
151
- function points(data, x, y, sort) {
152
- data = data.filter(function(d2, i2) {
153
- var u = x(d2, i2), v = y(d2, i2);
154
- return u != null && isFinite(u) && v != null && isFinite(v);
155
- });
156
- if (sort) {
157
- data.sort(function(a, b) {
158
- return x(a) - x(b);
159
- });
160
- }
161
- var n = data.length, X = new Float64Array(n), Y = new Float64Array(n);
162
- var ux = 0, uy = 0, xv, yv, d;
163
- for (var i = 0; i < n; ) {
164
- d = data[i];
165
- X[i] = xv = +x(d, i, data);
166
- Y[i] = yv = +y(d, i, data);
167
- ++i;
168
- ux += (xv - ux) / i;
169
- uy += (yv - uy) / i;
170
- }
171
- for (var _i = 0; _i < n; ++_i) {
172
- X[_i] -= ux;
173
- Y[_i] -= uy;
174
- }
175
- return [X, Y, ux, uy];
176
- }
177
- function visitPoints(data, x, y, cb) {
178
- var iterations = 0;
179
- for (var i = 0, n = data.length; i < n; i++) {
180
- var d = data[i], dx = +x(d, i, data), dy = +y(d, i, data);
181
- if (dx != null && isFinite(dx) && dy != null && isFinite(dy)) {
182
- cb(dx, dy, iterations++);
183
- }
184
- }
185
- }
186
- function determination(data, x, y, uY, predict) {
187
- var SSE = 0, SST = 0;
188
- visitPoints(data, x, y, function(dx, dy) {
189
- var sse = dy - predict(dx), sst = dy - uY;
190
- SSE += sse * sse;
191
- SST += sst * sst;
192
- });
193
- return 1 - SSE / SST;
194
- }
195
- function angle(line) {
196
- return Math.atan2(line[1][1] - line[0][1], line[1][0] - line[0][0]) * 180 / Math.PI;
197
- }
198
- function midpoint(line) {
199
- return [(line[0][0] + line[1][0]) / 2, (line[0][1] + line[1][1]) / 2];
200
- }
201
- function interpose(xmin, xmax, predict) {
202
- var l = Math.log(xmax - xmin) * Math.LOG10E + 1 | 0;
203
- var precision = 1 * Math.pow(10, -l / 2 - 1), maxIter = 1e4;
204
- var points2 = [px(xmin), px(xmax)], iter = 0;
205
- while (find(points2) && iter < maxIter) {
206
- }
207
- return points2;
208
- function px(x) {
209
- return [x, predict(x)];
210
- }
211
- function find(points3) {
212
- iter++;
213
- var n = points3.length;
214
- var found = false;
215
- for (var i = 0; i < n - 1; i++) {
216
- var p0 = points3[i], p1 = points3[i + 1], m = midpoint([p0, p1]), mp = px(m[0]), a0 = angle([p0, m]), a1 = angle([p0, mp]), a = Math.abs(a0 - a1);
217
- if (a > precision) {
218
- points3.splice(i + 1, 0, mp);
219
- found = true;
220
- }
221
- }
222
- return found;
223
- }
224
- }
225
- function ols(uX, uY, uXY, uX2) {
226
- var delta = uX2 - uX * uX, slope = Math.abs(delta) < 1e-24 ? 0 : (uXY - uX * uY) / delta, intercept = uY - slope * uX;
227
- return [intercept, slope];
228
- }
229
- function exponential() {
230
- var x = function x2(d) {
231
- return d[0];
232
- }, y = function y2(d) {
233
- return d[1];
234
- }, domain;
235
- function exponential2(data) {
236
- var n = 0, Y = 0, YL = 0, XY = 0, XYL = 0, X2Y = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity;
237
- visitPoints(data, x, y, function(dx, dy) {
238
- var ly = Math.log(dy), xy = dx * dy;
239
- ++n;
240
- Y += (dy - Y) / n;
241
- XY += (xy - XY) / n;
242
- X2Y += (dx * xy - X2Y) / n;
243
- YL += (dy * ly - YL) / n;
244
- XYL += (xy * ly - XYL) / n;
245
- if (!domain) {
246
- if (dx < xmin) xmin = dx;
247
- if (dx > xmax) xmax = dx;
248
- }
249
- });
250
- var _ols = ols(XY / Y, YL / Y, XYL / Y, X2Y / Y), _ols2 = _slicedToArray(_ols, 2), a = _ols2[0], b = _ols2[1];
251
- a = Math.exp(a);
252
- var fn = function fn2(x2) {
253
- return a * Math.exp(b * x2);
254
- }, out = interpose(xmin, xmax, fn);
255
- out.a = a;
256
- out.b = b;
257
- out.predict = fn;
258
- out.rSquared = determination(data, x, y, Y, fn);
259
- return out;
260
- }
261
- exponential2.domain = function(arr) {
262
- return arguments.length ? (domain = arr, exponential2) : domain;
263
- };
264
- exponential2.x = function(fn) {
265
- return arguments.length ? (x = fn, exponential2) : x;
266
- };
267
- exponential2.y = function(fn) {
268
- return arguments.length ? (y = fn, exponential2) : y;
269
- };
270
- return exponential2;
271
- }
272
- function linear2() {
273
- var x = function x2(d) {
274
- return d[0];
275
- }, y = function y2(d) {
276
- return d[1];
277
- }, domain;
278
- function linear3(data) {
279
- var n = 0, X = 0, Y = 0, XY = 0, X2 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity;
280
- visitPoints(data, x, y, function(dx, dy) {
281
- ++n;
282
- X += (dx - X) / n;
283
- Y += (dy - Y) / n;
284
- XY += (dx * dy - XY) / n;
285
- X2 += (dx * dx - X2) / n;
286
- if (!domain) {
287
- if (dx < xmin) xmin = dx;
288
- if (dx > xmax) xmax = dx;
289
- }
290
- });
291
- var _ols = ols(X, Y, XY, X2), _ols2 = _slicedToArray(_ols, 2), intercept = _ols2[0], slope = _ols2[1], fn = function fn2(x2) {
292
- return slope * x2 + intercept;
293
- }, out = [[xmin, fn(xmin)], [xmax, fn(xmax)]];
294
- out.a = slope;
295
- out.b = intercept;
296
- out.predict = fn;
297
- out.rSquared = determination(data, x, y, Y, fn);
298
- return out;
299
- }
300
- linear3.domain = function(arr) {
301
- return arguments.length ? (domain = arr, linear3) : domain;
302
- };
303
- linear3.x = function(fn) {
304
- return arguments.length ? (x = fn, linear3) : x;
305
- };
306
- linear3.y = function(fn) {
307
- return arguments.length ? (y = fn, linear3) : y;
308
- };
309
- return linear3;
310
- }
311
- function median(arr) {
312
- arr.sort(function(a, b) {
313
- return a - b;
314
- });
315
- var i = arr.length / 2;
316
- return i % 1 === 0 ? (arr[i - 1] + arr[i]) / 2 : arr[Math.floor(i)];
317
- }
318
- var maxiters = 2, epsilon = 1e-12;
319
- function loess() {
320
- var x = function x2(d) {
321
- return d[0];
322
- }, y = function y2(d) {
323
- return d[1];
324
- }, bandwidth = 0.3;
325
- function loess2(data) {
326
- var _points = points(data, x, y, true), _points2 = _slicedToArray(_points, 4), xv = _points2[0], yv = _points2[1], ux = _points2[2], uy = _points2[3], n = xv.length, bw = Math.max(2, ~~(bandwidth * n)), yhat = new Float64Array(n), residuals = new Float64Array(n), robustWeights = new Float64Array(n).fill(1);
327
- for (var iter = -1; ++iter <= maxiters; ) {
328
- var interval = [0, bw - 1];
329
- for (var i = 0; i < n; ++i) {
330
- var dx = xv[i], i0 = interval[0], i1 = interval[1], edge = dx - xv[i0] > xv[i1] - dx ? i0 : i1;
331
- var W = 0, X = 0, Y = 0, XY = 0, X2 = 0, denom = 1 / Math.abs(xv[edge] - dx || 1);
332
- for (var k = i0; k <= i1; ++k) {
333
- var xk = xv[k], yk = yv[k], w = tricube(Math.abs(dx - xk) * denom) * robustWeights[k], xkw = xk * w;
334
- W += w;
335
- X += xkw;
336
- Y += yk * w;
337
- XY += yk * xkw;
338
- X2 += xk * xkw;
339
- }
340
- var _ols = ols(X / W, Y / W, XY / W, X2 / W), _ols2 = _slicedToArray(_ols, 2), a = _ols2[0], b = _ols2[1];
341
- yhat[i] = a + b * dx;
342
- residuals[i] = Math.abs(yv[i] - yhat[i]);
343
- updateInterval(xv, i + 1, interval);
344
- }
345
- if (iter === maxiters) {
346
- break;
347
- }
348
- var medianResidual = median(residuals);
349
- if (Math.abs(medianResidual) < epsilon) break;
350
- for (var _i = 0, arg, _w; _i < n; ++_i) {
351
- arg = residuals[_i] / (6 * medianResidual);
352
- robustWeights[_i] = arg >= 1 ? epsilon : (_w = 1 - arg * arg) * _w;
353
- }
354
- }
355
- return output(xv, yhat, ux, uy);
356
- }
357
- loess2.bandwidth = function(bw) {
358
- return arguments.length ? (bandwidth = bw, loess2) : bandwidth;
359
- };
360
- loess2.x = function(fn) {
361
- return arguments.length ? (x = fn, loess2) : x;
362
- };
363
- loess2.y = function(fn) {
364
- return arguments.length ? (y = fn, loess2) : y;
365
- };
366
- return loess2;
367
- }
368
- function tricube(x) {
369
- return (x = 1 - x * x * x) * x * x;
370
- }
371
- function updateInterval(xv, i, interval) {
372
- var val = xv[i], left = interval[0], right = interval[1] + 1;
373
- if (right >= xv.length) return;
374
- while (i > left && xv[right] - val <= val - xv[left]) {
375
- interval[0] = ++left;
376
- interval[1] = right;
377
- ++right;
378
- }
379
- }
380
- function output(xv, yhat, ux, uy) {
381
- var n = xv.length, out = [];
382
- var i = 0, cnt = 0, prev = [], v;
383
- for (; i < n; ++i) {
384
- v = xv[i] + ux;
385
- if (prev[0] === v) {
386
- prev[1] += (yhat[i] - prev[1]) / ++cnt;
387
- } else {
388
- cnt = 0;
389
- prev[1] += uy;
390
- prev = [v, yhat[i]];
391
- out.push(prev);
392
- }
393
- }
394
- prev[1] += uy;
395
- return out;
396
- }
397
- function logarithmic() {
398
- var x = function x2(d) {
399
- return d[0];
400
- }, y = function y2(d) {
401
- return d[1];
402
- }, base = Math.E, domain;
403
- function logarithmic2(data) {
404
- var n = 0, X = 0, Y = 0, XY = 0, X2 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity, lb = Math.log(base);
405
- visitPoints(data, x, y, function(dx, dy) {
406
- var lx = Math.log(dx) / lb;
407
- ++n;
408
- X += (lx - X) / n;
409
- Y += (dy - Y) / n;
410
- XY += (lx * dy - XY) / n;
411
- X2 += (lx * lx - X2) / n;
412
- if (!domain) {
413
- if (dx < xmin) xmin = dx;
414
- if (dx > xmax) xmax = dx;
415
- }
416
- });
417
- var _ols = ols(X, Y, XY, X2), _ols2 = _slicedToArray(_ols, 2), intercept = _ols2[0], slope = _ols2[1], fn = function fn2(x2) {
418
- return slope * Math.log(x2) / lb + intercept;
419
- }, out = interpose(xmin, xmax, fn);
420
- out.a = slope;
421
- out.b = intercept;
422
- out.predict = fn;
423
- out.rSquared = determination(data, x, y, Y, fn);
424
- return out;
425
- }
426
- logarithmic2.domain = function(arr) {
427
- return arguments.length ? (domain = arr, logarithmic2) : domain;
428
- };
429
- logarithmic2.x = function(fn) {
430
- return arguments.length ? (x = fn, logarithmic2) : x;
431
- };
432
- logarithmic2.y = function(fn) {
433
- return arguments.length ? (y = fn, logarithmic2) : y;
434
- };
435
- logarithmic2.base = function(n) {
436
- return arguments.length ? (base = n, logarithmic2) : base;
437
- };
438
- return logarithmic2;
439
- }
440
- function quad() {
441
- var x = function x2(d) {
442
- return d[0];
443
- }, y = function y2(d) {
444
- return d[1];
445
- }, domain;
446
- function quadratic(data) {
447
- var _points = points(data, x, y), _points2 = _slicedToArray(_points, 4), xv = _points2[0], yv = _points2[1], ux = _points2[2], uy = _points2[3], n = xv.length;
448
- var X2 = 0, X3 = 0, X4 = 0, XY = 0, X2Y = 0, i, dx, dy, x2;
449
- for (i = 0; i < n; ) {
450
- dx = xv[i];
451
- dy = yv[i++];
452
- x2 = dx * dx;
453
- X2 += (x2 - X2) / i;
454
- X3 += (x2 * dx - X3) / i;
455
- X4 += (x2 * x2 - X4) / i;
456
- XY += (dx * dy - XY) / i;
457
- X2Y += (x2 * dy - X2Y) / i;
458
- }
459
- var Y = 0, n0 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity;
460
- visitPoints(data, x, y, function(dx2, dy2) {
461
- n0++;
462
- Y += (dy2 - Y) / n0;
463
- if (!domain) {
464
- if (dx2 < xmin) xmin = dx2;
465
- if (dx2 > xmax) xmax = dx2;
466
- }
467
- });
468
- var X2X2 = X4 - X2 * X2, d = X2 * X2X2 - X3 * X3, a = (X2Y * X2 - XY * X3) / d, b = (XY * X2X2 - X2Y * X3) / d, c = -a * X2, fn = function fn2(x3) {
469
- x3 = x3 - ux;
470
- return a * x3 * x3 + b * x3 + c + uy;
471
- };
472
- var out = interpose(xmin, xmax, fn);
473
- out.a = a;
474
- out.b = b - 2 * a * ux;
475
- out.c = c - b * ux + a * ux * ux + uy;
476
- out.predict = fn;
477
- out.rSquared = determination(data, x, y, Y, fn);
478
- return out;
479
- }
480
- quadratic.domain = function(arr) {
481
- return arguments.length ? (domain = arr, quadratic) : domain;
482
- };
483
- quadratic.x = function(fn) {
484
- return arguments.length ? (x = fn, quadratic) : x;
485
- };
486
- quadratic.y = function(fn) {
487
- return arguments.length ? (y = fn, quadratic) : y;
488
- };
489
- return quadratic;
490
- }
491
- function polynomial() {
492
- var x = function x2(d) {
493
- return d[0];
494
- }, y = function y2(d) {
495
- return d[1];
496
- }, order = 3, domain;
497
- function polynomial2(data) {
498
- if (order === 1) {
499
- var o = linear2().x(x).y(y).domain(domain)(data);
500
- o.coefficients = [o.b, o.a];
501
- delete o.a;
502
- delete o.b;
503
- return o;
504
- }
505
- if (order === 2) {
506
- var _o = quad().x(x).y(y).domain(domain)(data);
507
- _o.coefficients = [_o.c, _o.b, _o.a];
508
- delete _o.a;
509
- delete _o.b;
510
- delete _o.c;
511
- return _o;
512
- }
513
- var _points = points(data, x, y), _points2 = _slicedToArray(_points, 4), xv = _points2[0], yv = _points2[1], ux = _points2[2], uy = _points2[3], n = xv.length, lhs = [], rhs = [], k = order + 1;
514
- var Y = 0, n0 = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity;
515
- visitPoints(data, x, y, function(dx, dy) {
516
- ++n0;
517
- Y += (dy - Y) / n0;
518
- if (!domain) {
519
- if (dx < xmin) xmin = dx;
520
- if (dx > xmax) xmax = dx;
521
- }
522
- });
523
- var i, j, l, v, c;
524
- for (i = 0; i < k; ++i) {
525
- for (l = 0, v = 0; l < n; ++l) {
526
- v += Math.pow(xv[l], i) * yv[l];
527
- }
528
- lhs.push(v);
529
- c = new Float64Array(k);
530
- for (j = 0; j < k; ++j) {
531
- for (l = 0, v = 0; l < n; ++l) {
532
- v += Math.pow(xv[l], i + j);
533
- }
534
- c[j] = v;
535
- }
536
- rhs.push(c);
537
- }
538
- rhs.push(lhs);
539
- var coef = gaussianElimination(rhs), fn = function fn2(x2) {
540
- x2 -= ux;
541
- var y2 = uy + coef[0] + coef[1] * x2 + coef[2] * x2 * x2;
542
- for (i = 3; i < k; ++i) {
543
- y2 += coef[i] * Math.pow(x2, i);
544
- }
545
- return y2;
546
- }, out = interpose(xmin, xmax, fn);
547
- out.coefficients = uncenter(k, coef, -ux, uy);
548
- out.predict = fn;
549
- out.rSquared = determination(data, x, y, Y, fn);
550
- return out;
551
- }
552
- polynomial2.domain = function(arr) {
553
- return arguments.length ? (domain = arr, polynomial2) : domain;
554
- };
555
- polynomial2.x = function(fn) {
556
- return arguments.length ? (x = fn, polynomial2) : x;
557
- };
558
- polynomial2.y = function(fn) {
559
- return arguments.length ? (y = fn, polynomial2) : y;
560
- };
561
- polynomial2.order = function(n) {
562
- return arguments.length ? (order = n, polynomial2) : order;
563
- };
564
- return polynomial2;
565
- }
566
- function uncenter(k, a, x, y) {
567
- var z = Array(k);
568
- var i, j, v, c;
569
- for (i = 0; i < k; ++i) {
570
- z[i] = 0;
571
- }
572
- for (i = k - 1; i >= 0; --i) {
573
- v = a[i];
574
- c = 1;
575
- z[i] += v;
576
- for (j = 1; j <= i; ++j) {
577
- c *= (i + 1 - j) / j;
578
- z[i - j] += v * Math.pow(x, j) * c;
579
- }
580
- }
581
- z[0] += y;
582
- return z;
583
- }
584
- function gaussianElimination(matrix) {
585
- var n = matrix.length - 1, coef = [];
586
- var i, j, k, r, t;
587
- for (i = 0; i < n; ++i) {
588
- r = i;
589
- for (j = i + 1; j < n; ++j) {
590
- if (Math.abs(matrix[i][j]) > Math.abs(matrix[i][r])) {
591
- r = j;
592
- }
593
- }
594
- for (k = i; k < n + 1; ++k) {
595
- t = matrix[k][i];
596
- matrix[k][i] = matrix[k][r];
597
- matrix[k][r] = t;
598
- }
599
- for (j = i + 1; j < n; ++j) {
600
- for (k = n; k >= i; k--) {
601
- matrix[k][j] -= matrix[k][i] * matrix[i][j] / matrix[i][i];
602
- }
603
- }
604
- }
605
- for (j = n - 1; j >= 0; --j) {
606
- t = 0;
607
- for (k = j + 1; k < n; ++k) {
608
- t += matrix[k][j] * coef[k];
609
- }
610
- coef[j] = (matrix[n][j] - t) / matrix[j][j];
611
- }
612
- return coef;
613
- }
614
- function power() {
615
- var x = function x2(d) {
616
- return d[0];
617
- }, y = function y2(d) {
618
- return d[1];
619
- }, domain;
620
- function power2(data) {
621
- var n = 0, X = 0, Y = 0, XY = 0, X2 = 0, YS = 0, xmin = domain ? +domain[0] : Infinity, xmax = domain ? +domain[1] : -Infinity;
622
- visitPoints(data, x, y, function(dx, dy) {
623
- var lx = Math.log(dx), ly = Math.log(dy);
624
- ++n;
625
- X += (lx - X) / n;
626
- Y += (ly - Y) / n;
627
- XY += (lx * ly - XY) / n;
628
- X2 += (lx * lx - X2) / n;
629
- YS += (dy - YS) / n;
630
- if (!domain) {
631
- if (dx < xmin) xmin = dx;
632
- if (dx > xmax) xmax = dx;
633
- }
634
- });
635
- var _ols = ols(X, Y, XY, X2), _ols2 = _slicedToArray(_ols, 2), a = _ols2[0], b = _ols2[1];
636
- a = Math.exp(a);
637
- var fn = function fn2(x2) {
638
- return a * Math.pow(x2, b);
639
- }, out = interpose(xmin, xmax, fn);
640
- out.a = a;
641
- out.b = b;
642
- out.predict = fn;
643
- out.rSquared = determination(data, x, y, YS, fn);
644
- return out;
645
- }
646
- power2.domain = function(arr) {
647
- return arguments.length ? (domain = arr, power2) : domain;
648
- };
649
- power2.x = function(fn) {
650
- return arguments.length ? (x = fn, power2) : x;
651
- };
652
- power2.y = function(fn) {
653
- return arguments.length ? (y = fn, power2) : y;
654
- };
655
- return power2;
656
- }
657
- exports2.regressionExp = exponential;
658
- exports2.regressionLinear = linear2;
659
- exports2.regressionLoess = loess;
660
- exports2.regressionLog = logarithmic;
661
- exports2.regressionPoly = polynomial;
662
- exports2.regressionPow = power;
663
- exports2.regressionQuad = quad;
664
- Object.defineProperty(exports2, "__esModule", { value: true });
665
- }));
666
- }
667
- });
668
-
669
- // plots/scatter/viewmodel/scatterSampleTable.ts
670
- function getCategoryValue(category, d, tw, includeMutation = false) {
671
- if (category == "") return "";
672
- let value = d[category];
673
- if (tw?.term.type == "geneVariant" && tw.q?.type == "values") {
674
- const mutation = value.split(", ")[0];
675
- for (const id in mclass) {
676
- const class_info = mclass[id];
677
- if (mutation == class_info.label) {
678
- const mname = d.cat_info[category].find((m) => m.class == class_info.key).mname;
679
- if (mname && includeMutation) value = `${mname} ${value}`;
680
- }
681
- }
682
- }
683
- if (tw?.term.type == "date") value = getDateStrFromNumber(value);
684
- else if (tw?.term.type == SINGLECELL_GENE_EXPRESSION && Number.isFinite(d.geneExp)) {
685
- value = roundValueAuto(d.geneExp);
686
- } else if (typeof value == "number" && value % 1 != 0) value = roundValueAuto(value);
687
- return value;
688
- }
689
- function buildSampleTableData(config, itemLabel, samples) {
690
- const hasName = samples.some((d) => !!(d.sample || d.cellId || d.sampleId) || d.sampleId === 0);
691
- const hasInfo = samples.some((d) => "info" in d);
692
- const dims = [
693
- { tw: config.term, key: "x" },
694
- { tw: config.term2, key: "y" },
695
- { tw: config.colorTW, key: "category" },
696
- { tw: config.shapeTW, key: "shape" },
697
- { tw: config.scaleDotTW, key: "scale", sortable: true }
698
- ].filter((d) => d.tw);
699
- const columns = [];
700
- if (hasName) columns.push({ label: config.controlLabels?.Sample || itemLabel });
701
- for (const d of dims) columns.push(d.sortable ? { label: d.tw.term.name, sortable: true } : { label: d.tw.term.name });
702
- if (hasInfo) columns.push({ label: "Info" });
703
- const rows = samples.map((s) => {
704
- const row = [];
705
- if (hasName) row.push({ value: s.sample || s.cellId || s.sampleId || "" });
706
- for (const d of dims) row.push({ value: getCategoryValue(d.key, s, d.tw) });
707
- if (hasInfo)
708
- row.push({
709
- value: "info" in s ? Object.entries(s.info).map(([k, v]) => `${k}: ${v}`).join(", ") : ""
710
- });
711
- return row;
712
- });
713
- return { columns, rows };
714
- }
715
-
716
- // plots/scatter/viewmodel/scatterLasso.ts
717
- var ScatterLasso = class {
718
- constructor(scatter) {
719
- this.scatter = scatter;
720
- this.model = scatter.model;
721
- this.view = scatter.view;
722
- this.interactivity = scatter.interactivity;
723
- const supportedChartTypes = this.scatter.state.currentCohortChartTypes;
724
- this.hasSampleView = supportedChartTypes && supportedChartTypes.includes("sampleView");
725
- }
726
- start(chart) {
727
- if (this.scatter.config.lassoOn) {
728
- chart.lasso.items().attr("transform", (c) => this.model.transform(chart, c, 1 / 2)).style("fill-opacity", (c) => this.model.getOpacity(c) != 0 ? 0.5 : 0).classed("not_possible", true).classed("selected", false);
729
- }
730
- }
731
- draw(chart) {
732
- if (this.scatter.config.lassoOn) {
733
- chart.lasso.possibleItems().attr("transform", (c) => this.model.transform(chart, c, 1.2)).style("fill-opacity", (c) => this.model.getOpacity(c)).classed("not_possible", false).classed("possible", true);
734
- chart.lasso.notPossibleItems().attr("transform", (c) => this.model.transform(chart, c, 1 / 2)).style("fill-opacity", (c) => this.model.getOpacity(c) != 0 ? 0.5 : 0).classed("not_possible", true).classed("possible", false);
735
- }
736
- }
737
- end(dragEnd, chart) {
738
- if (this.scatter.config.lassoOn) {
739
- chart.lasso.items().classed("not_possible", false).classed("possible", false);
740
- chart.lasso.selectedItems().attr("transform", (c) => this.model.transform(chart, c, 1.3));
741
- chart.lasso.items().style("fill-opacity", (c) => this.model.getOpacity(c));
742
- this.selectedItems = [];
743
- for (const item of chart.lasso.selectedItems()) {
744
- const data = item.__data__;
745
- if (!data.isRef && !(data.hidden["category"] || data.hidden["shape"])) this.selectedItems.push(item);
746
- }
747
- chart.lasso.notSelectedItems().attr("transform", (c) => this.model.transform(chart, c));
748
- const samples = this.selectedItems.map((item) => item.__data__);
749
- this.showLassoMenu(dragEnd.sourceEvent, samples);
750
- }
751
- }
752
- showLassoMenu(event, samples) {
753
- this.view.dom.tip.clear().hide();
754
- if (samples.length == 0) return;
755
- if (samples.some((s) => s.sampleId == null)) return;
756
- this.view.dom.tip.show(event.clientX, event.clientY);
757
- const labels = this.scatter.config.controlLabels;
758
- const menuDiv = this.view.dom.tip.d.append("div");
759
- menuDiv.append("div").attr("class", "sja_menuoption sja_sharp_border").text(`List ${samples.length} ${labels.samples}`).on("click", (event2) => {
760
- this.view.dom.tip.hide();
761
- this.showTable(
762
- {
763
- name: "Group " + (this.scatter.config.groups.length + 1),
764
- items: samples
765
- },
766
- event2.clientX,
767
- event2.clientY,
768
- this.scatter.app.getState().nav.header_mode === "with_tabs"
769
- );
770
- });
771
- if (this.scatter.app.getState().nav.header_mode === "with_tabs")
772
- menuDiv.append("div").attr("class", "sja_menuoption sja_sharp_border").text("Add to a group").on("click", async () => {
773
- this.createGroup(samples);
774
- this.view.dom.tip.hide();
775
- });
776
- if (this.scatter.app.getState().nav.header_mode === "with_tabs")
777
- menuDiv.append("div").attr("class", "sja_menuoption sja_sharp_border").text("Add to a group and filter").on("click", () => {
778
- const tw = this.createGroup(samples);
779
- this.interactivity.addToFilter(tw);
780
- this.view.dom.tip.hide();
781
- });
782
- if ("sample" in samples[0] && this.hasSampleView)
783
- menuDiv.append("div").attr("class", "sja_menuoption sja_sharp_border").text("Open sample view").on("click", async () => {
784
- const groupSamples = [];
785
- for (const sample of samples) groupSamples.push({ sampleId: sample.sampleId, sampleName: sample.sample });
786
- this.scatter.app.dispatch({
787
- type: "plot_create",
788
- id: getId(),
789
- config: {
790
- chartType: "sampleView",
791
- samples: groupSamples
792
- }
793
- });
794
- this.view.dom.tip.hide();
795
- });
796
- }
797
- createGroup(samples) {
798
- const group = {
799
- name: "Group",
800
- items: samples
801
- };
802
- const tw = getSamplelstTW([group]);
803
- const filter = getFilter(tw);
804
- addNewGroup(this.scatter.app, filter, this.scatter.state.groups);
805
- return tw;
806
- }
807
- lassoReset(chart) {
808
- const mainG = chart.mainG;
809
- if (this.scatter.config.lassoOn) {
810
- chart.lasso.items(mainG.select(".sjpcb-scatter-series").selectAll('path[name="serie"]')).targetArea(mainG).on("start", () => this.start(chart)).on("draw", () => this.draw(chart)).on("end", (event) => this.end(event, chart));
811
- mainG.on(".zoom", null);
812
- mainG.on("mousedown.drag", null);
813
- mainG.call(chart.lasso);
814
- } else {
815
- chart.mainG.on(".dragstart", null);
816
- chart.mainG.on(".drag", null);
817
- chart.mainG.on(".dragend", null);
818
- }
819
- }
820
- showTable(group, x, y, addGroup) {
821
- const { columns, rows } = buildSampleTableData(this.scatter.config, this.scatter.settings.itemLabel, group.items);
822
- const hasSampleName = "sample" in group.items[0];
823
- this.view.dom.tip.clear();
824
- const div = this.view.dom.tip.d.append("div").style("padding", "5px");
825
- const headerDiv = div.append("div").style("margin-top", "5px");
826
- const groupDiv = headerDiv.append("div").html("&nbsp;" + group.name).style("font-size", "0.9rem").on("click", () => {
827
- const isEdit = groupDiv.select("input").empty();
828
- if (!isEdit) return;
829
- groupDiv.html("");
830
- const input = groupDiv.append("input").attr("value", group.name).on("change", async () => {
831
- const name = input.node().value;
832
- if (name) group.name = name;
833
- else input.node().value = group.name;
834
- groupDiv.html("&nbsp;" + group.name);
835
- });
836
- input.node().focus();
837
- input.node().select();
838
- });
839
- const tableDiv = div.append("div");
840
- let buttons;
841
- if (addGroup) {
842
- const addGroupCallback = {
843
- text: "Add to a group",
844
- callback: (indexes) => {
845
- const items = [];
846
- for (const i of indexes) items.push(this.selectedItems[i].__data__);
847
- const group2 = {
848
- name: `Group ${this.scatter.config.groups.length + 1}`,
849
- items,
850
- index: this.scatter.config.groups.length
851
- };
852
- const filter = getFilter(getSamplelstTW([group2]));
853
- addNewGroup(this.scatter.app, filter, this.scatter.state.groups);
854
- }
855
- };
856
- buttons = [addGroupCallback];
857
- }
858
- const columnButton = {
859
- text: "View",
860
- callback: async (event, i) => {
861
- const sample = group.items[i];
862
- this.interactivity.openSampleView(sample);
863
- }
864
- };
865
- const columnButtons = hasSampleName && this.hasSampleView ? [columnButton] : [];
866
- renderTable({
867
- rows,
868
- columns,
869
- div: tableDiv,
870
- showLines: true,
871
- //maxWidth: columns.length * '15' + 'vw',
872
- maxHeight: "35vh",
873
- buttons,
874
- selectAll: true,
875
- columnButtons
876
- });
877
- this.view.dom.tip.show(x, y, false, false);
878
- }
879
- };
880
-
881
- // plots/scatter/model/ScatterModelBase.ts
882
- var import_d3_regression = __toESM(require_d3_regression(), 1);
883
- var shapes = shapesArray;
884
- var ScatterModelBase = class {
885
- constructor(scatter) {
886
- this.filterSampleStr = null;
887
- this.scatter = scatter;
888
- this.is3D = false;
889
- this.is2DLarge = false;
890
- this.axisOffset = { x: xAxisOffSet, y: yAxisOffSet };
891
- }
892
- createChart(id, data) {
893
- const cohortSamples = data.samples ? data.samples.filter((sample) => !sample.isRef) : [];
894
- if (cohortSamples.length > this.scatter.settings.maxSvgSamplesCutoff) this.is2DLarge = true;
895
- const colorLegend = new Map(data.colorLegend);
896
- const shapeLegend = new Map(data.shapeLegend);
897
- const chart = { id, data, cohortSamples, colorLegend, shapeLegend };
898
- if (data.src) {
899
- chart.src = data.src;
900
- if ("canvasWidth" in data) chart.canvasWidth = data.canvasWidth;
901
- if ("canvasHeight" in data) chart.canvasHeight = data.canvasHeight;
902
- if (data.totalSampleCount) chart.totalSampleCount = data.totalSampleCount;
903
- this.is2DLarge = true;
904
- }
905
- this.charts.push(chart);
906
- }
907
- async initRanges() {
908
- const settings = this.scatter.settings;
909
- let samples = [];
910
- for (const chart of this.charts) samples = samples.concat(chart.data?.samples || []);
911
- if (samples.length == 0) {
912
- if (this.scatter.config.singleCellPlot) {
913
- this.charts[0].ranges = {
914
- xMin: settings.minXScale != null ? settings.minXScale : this.range.xMin,
915
- xMax: settings.maxXScale != null ? settings.maxXScale : this.range.xMax,
916
- yMin: settings.minYScale != null ? settings.minYScale : this.range.yMin,
917
- yMax: settings.maxYScale != null ? settings.maxYScale : this.range.yMax,
918
- geMin: this.range.geMin,
919
- geMax: this.range.geMax
920
- };
921
- }
922
- return;
923
- }
924
- if (samples.length > settings.maxSvgSamplesCutoff) this.is2DLarge = true;
925
- const s0 = samples[0];
926
- const [xMin, xMax, yMin, yMax, zMin, zMax, scaleMin, scaleMax, geMin, geMax] = samples.reduce(
927
- (s, d) => [
928
- d.x < s[0] ? d.x : s[0],
929
- d.x > s[1] ? d.x : s[1],
930
- d.y < s[2] ? d.y : s[2],
931
- d.y > s[3] ? d.y : s[3],
932
- d.z < s[4] ? d.z : s[4],
933
- d.z > s[5] ? d.z : s[5],
934
- "scale" in d ? d.scale < s[6] ? d.scale : s[6] : Number.POSITIVE_INFINITY,
935
- "scale" in d ? d.scale > s[7] ? d.scale : s[7] : Number.NEGATIVE_INFINITY,
936
- "geneExp" in d ? d.geneExp < s[8] ? d.geneExp : s[8] : Number.POSITIVE_INFINITY,
937
- "geneExp" in d ? d.geneExp > s[9] ? d.geneExp : s[9] : Number.NEGATIVE_INFINITY
938
- ],
939
- [s0.x, s0.x, s0.y, s0.y, s0.z, s0.z, s0.scale, s0.scale, s0.geneExp, s0.geneExp]
940
- );
941
- for (const chart of this.charts) {
942
- chart.ranges = {
943
- xMin: settings.minXScale != null ? settings.minXScale : settings.useGlobalMinMax ? this.range.xMin : xMin,
944
- xMax: settings.maxXScale != null ? settings.maxXScale : settings.useGlobalMinMax ? this.range.xMax : xMax,
945
- yMin: settings.minYScale != null ? settings.minYScale : settings.useGlobalMinMax ? this.range.yMin : yMin,
946
- yMax: settings.maxYScale != null ? settings.maxYScale : settings.useGlobalMinMax ? this.range.yMax : yMax,
947
- zMin,
948
- zMax,
949
- scaleMin,
950
- scaleMax,
951
- geMin,
952
- geMax
953
- };
954
- }
955
- }
956
- getOpacity(c) {
957
- if (!c.isRef) {
958
- const hidden = c.hidden?.["category"] || c.hidden?.["shape"];
959
- if (this.filterSampleStr) {
960
- if (!c.sample?.toLowerCase().includes(this.filterSampleStr.toLowerCase())) {
961
- if (hidden) return 0;
962
- else return 0.1;
963
- } else return 1.2;
964
- }
965
- const opacity = hidden ? 0 : this.scatter.settings.opacity;
966
- return opacity;
967
- }
968
- const refOpacity = this.scatter.settings.showRef ? this.scatter.settings.opacity : 0;
969
- return refOpacity;
970
- }
971
- getShape(chart, c) {
972
- const index = chart.shapeLegend.get(c.shape).shape % shapes.length;
973
- return shapes[index];
974
- }
975
- /** Returns the calculated coordinate or the min/max axis
976
- * cap set by the user. */
977
- getCoordinates(chart, c) {
978
- const cx = () => {
979
- return getCoordinate(c.x, this.scatter.settings.minXScale, this.scatter.settings.maxXScale);
980
- };
981
- const cy = () => {
982
- return getCoordinate(c.y, this.scatter.settings.minYScale, this.scatter.settings.maxYScale);
983
- };
984
- const x = chart.xAxisScale(cx());
985
- const y = chart.yAxisScale(cy());
986
- return { x, y };
987
- }
988
- getScale(chart, c, factor = 1) {
989
- const isRef = !!c.isRef;
990
- let scale;
991
- if (!this.scatter.config.scaleDotTW || isRef) {
992
- scale = isRef ? this.scatter.settings.refSize : this.scatter.settings.size;
993
- } else {
994
- const range = this.scatter.settings.maxShapeSize - this.scatter.settings.minShapeSize;
995
- if (this.scatter.settings.scaleDotOrder == "Ascending")
996
- scale = this.scatter.settings.minShapeSize + (c.scale - chart.ranges.scaleMin) / (chart.ranges.scaleMax - chart.ranges.scaleMin) * range;
997
- else
998
- scale = this.scatter.settings.maxShapeSize - (c.scale - chart.ranges.scaleMin) / (chart.ranges.scaleMax - chart.ranges.scaleMin) * range;
999
- }
1000
- const zoom = this.is2DLarge ? this.scatter.zoom : 1;
1001
- scale = zoom * scale * factor / 3;
1002
- if (this.filterSampleStr) {
1003
- if (c.sample?.toLowerCase().includes(this.filterSampleStr.toLowerCase())) scale = scale * 2;
1004
- else scale = scale * 0.8;
1005
- }
1006
- return scale;
1007
- }
1008
- transform(chart, c, factor = 1) {
1009
- const scale = this.getScale(chart, c, factor);
1010
- const particleSize = 16 * scale;
1011
- const { x, y } = this.getCoordinates(chart, c);
1012
- const offSetX = x - particleSize / 2;
1013
- const offSetY = y - particleSize / 2;
1014
- const transform = `translate(${offSetX},${offSetY}) scale(${scale})`;
1015
- return transform;
1016
- }
1017
- getColor(c, chart) {
1018
- if (this.scatter.config.colorTW?.term.type == SINGLECELL_GENE_EXPRESSION) {
1019
- let color;
1020
- if (!c.geneExp) color = this.scatter.settings.noExpColor;
1021
- else if (c.geneExp > chart.ranges.geMax) color = this.scatter.settings.expColor;
1022
- else color = chart.colorGenerator(c.geneExp);
1023
- return color;
1024
- }
1025
- if (this.scatter.config.colorTW?.q.mode == "continuous" && !c.isRef) {
1026
- const [min, max2] = chart.colorGenerator.domain();
1027
- if (c.category < min) return chart.colorGenerator(min);
1028
- if (c.category > max2) return chart.colorGenerator(max2);
1029
- const color = chart.colorGenerator(c.category);
1030
- return color;
1031
- }
1032
- if (c.category == "Default") return this.scatter.settings.defaultColor;
1033
- const category = chart.colorLegend.get(c.category);
1034
- return category.color;
1035
- }
1036
- async addGroup(group) {
1037
- group.plotId = this.scatter.id;
1038
- await this.scatter.app.vocabApi.addGroup(group);
1039
- }
1040
- getStrokeWidth(c) {
1041
- const opacity = this.getOpacity(c);
1042
- if (opacity <= 0.2)
1043
- return 0;
1044
- if (opacity == 1.2)
1045
- return 2;
1046
- return 1;
1047
- }
1048
- initAxes(chart) {
1049
- const config = this.scatter.config;
1050
- const settings = this.scatter.settings;
1051
- if (!chart.data?.samples || chart.data.samples.length == 0) return;
1052
- const offsetX = this.axisOffset.x;
1053
- const offsetY = this.axisOffset.y;
1054
- const xMin = chart.ranges.xMin;
1055
- const xMax = chart.ranges.xMax;
1056
- const yMin = chart.ranges.yMin;
1057
- const yMax = chart.ranges.yMax;
1058
- const extraSpaceX = calculatePadding(settings.minXScale, settings.maxXScale, xMin, xMax);
1059
- const extraSpaceY = calculatePadding(settings.minYScale, settings.maxYScale, yMin, yMax);
1060
- chart.xAxisScale = linear().domain([xMin - extraSpaceX, xMax + extraSpaceX]).range([offsetX, settings.svgw + offsetX]);
1061
- if (config.term && config.term.term.type == "date") {
1062
- const xMinDate = getDateFromNumber(xMin - extraSpaceX);
1063
- const xMaxDate = getDateFromNumber(xMax + extraSpaceX);
1064
- chart.xAxisScaleTime = time().domain([xMinDate, xMaxDate]).range([offsetX, settings.svgw + offsetX]);
1065
- chart.axisBottom = axisBottom(chart.xAxisScaleTime);
1066
- } else chart.axisBottom = axisBottom(chart.xAxisScale);
1067
- const svgh = settings.svgh;
1068
- chart.yAxisScale = linear().domain([yMax + extraSpaceY, yMin - extraSpaceY]).range([offsetY, svgh + offsetY]);
1069
- if (config.term2 && config.term2.term.type == "date") {
1070
- const yMinDate = getDateFromNumber(yMin - extraSpaceY);
1071
- const yMaxDate = getDateFromNumber(yMax + extraSpaceY);
1072
- chart.yAxisScaleTime = time().domain([yMaxDate, yMinDate]).range([offsetY, settings.svgh + offsetY]);
1073
- chart.axisLeft = axisLeft(chart.yAxisScaleTime);
1074
- } else chart.axisLeft = axisLeft(chart.yAxisScale);
1075
- chart.zAxisScale = linear().domain([chart.ranges.zMin, chart.ranges.zMax]).range([0, settings.svgd]);
1076
- this.initColorGenerator(chart);
1077
- }
1078
- initColorDefaults(chartId) {
1079
- const config = this.scatter.config;
1080
- const settings = this.scatter.settings;
1081
- const gradientColor = rgb(settings.defaultColor);
1082
- config.startColor ||= {};
1083
- config.stopColor ||= {};
1084
- if (!config.startColor[chartId]) {
1085
- config.startColor[chartId] = config.colorTW?.term.type == SINGLECELL_GENE_EXPRESSION ? settings.noExpColor : config.colorTW?.term.continuousColorScale?.minColor || gradientColor.brighter().brighter().toString();
1086
- }
1087
- if (!config.stopColor[chartId]) {
1088
- config.stopColor[chartId] = config.colorTW?.term.type == SINGLECELL_GENE_EXPRESSION ? settings.expColor : config.colorTW?.term.continuousColorScale?.maxColor || gradientColor.darker().toString();
1089
- }
1090
- }
1091
- initColorGenerator(chart) {
1092
- const config = this.scatter.config;
1093
- if (!chart.ranges) return;
1094
- this.initColorDefaults(chart.id);
1095
- if (config.colorTW?.q.mode === "continuous") {
1096
- let colorValues;
1097
- if (config.colorTW.term.type == SINGLECELL_GENE_EXPRESSION || config.colorTW.term.type == SINGLECELL_NUMERIC_VALUE && chart.data.src) {
1098
- colorValues = [chart.ranges.geMin, chart.ranges.geMax];
1099
- } else {
1100
- colorValues = chart.cohortSamples.filter((s) => !config.colorTW.term.values || !(s.category in config.colorTW.term.values)).map((s) => Number(s.category)).sort((a, b) => a - b);
1101
- }
1102
- chart.colorValues = colorValues;
1103
- let min, max2, index;
1104
- const colorScaleSettings = config.settings.sampleScatter;
1105
- switch (colorScaleSettings.colorScaleMode) {
1106
- // Fixed mode: Use user-defined min/max values
1107
- // This is useful when you want consistent scaling across different views
1108
- case "fixed":
1109
- min = colorScaleSettings.colorScaleMinFixed;
1110
- max2 = colorScaleSettings.colorScaleMaxFixed;
1111
- break;
1112
- case "percentile":
1113
- min = colorValues[0];
1114
- index = Math.floor(colorValues.length * colorScaleSettings.colorScalePercentile / 100);
1115
- max2 = colorValues[index];
1116
- break;
1117
- case "auto":
1118
- default:
1119
- min = colorValues[0];
1120
- max2 = colorValues[colorValues.length - 1];
1121
- break;
1122
- }
1123
- if (chart.data.src && "colorDomain" in chart.data && chart.data.colorDomain) {
1124
- [min, max2] = chart.data.colorDomain;
1125
- }
1126
- chart.colorGenerator = linear().domain([min, max2]).range([config.startColor[chart.id], config.stopColor[chart.id]]);
1127
- chart.currentColorRange = { min, max: max2 };
1128
- }
1129
- }
1130
- async processData() {
1131
- const term0Values = this.scatter.config.term0?.term.values;
1132
- if (term0Values) {
1133
- const orderedLabels = Object.values(term0Values).sort(
1134
- (a, b) => "order" in a && "order" in b ? a.order - b.order : 0
1135
- );
1136
- this.charts.sort(
1137
- (a, b) => orderedLabels.findIndex((v) => v.label == a.id) - orderedLabels.findIndex((v) => v.label == b.id)
1138
- );
1139
- }
1140
- for (const chart of this.charts) {
1141
- this.initAxes(chart);
1142
- if (!chart.colorGenerator) this.initColorGenerator(chart);
1143
- const regressionType = this.scatter.settings.regression;
1144
- if (!regressionType || regressionType == "None") continue;
1145
- let regression;
1146
- const data = [];
1147
- await chart.cohortSamples.forEach((c) => {
1148
- data.push(this.getCoordinates(chart, c));
1149
- });
1150
- let regressionCurve;
1151
- if (regressionType == "Polynomial") {
1152
- regression = (0, import_d3_regression.regressionPoly)().x((c) => c.x).y((c) => c.y).order(3);
1153
- regressionCurve = regression(data);
1154
- } else if (regressionType == "Lowess") {
1155
- const X = [], Y = [];
1156
- for (const sample of data) {
1157
- X.push(sample.x);
1158
- Y.push(sample.y);
1159
- }
1160
- regressionCurve = await this.scatter.vocabApi.getLowessCurve({ coords: { X, Y } });
1161
- } else {
1162
- throw `unsupported regression type='${regressionType}'`;
1163
- }
1164
- chart.regressionCurve = regressionCurve;
1165
- }
1166
- }
1167
- };
1168
-
1169
- // plots/scatter/model/scatterModel.ts
1170
- var ScatterModel = class extends ScatterModelBase {
1171
- constructor(scatter) {
1172
- super(scatter);
1173
- }
1174
- // creates an opts object for the vocabApi.someMethod(),
1175
- // may need to add a new method to client/termdb/vocabulary.js
1176
- // for now, just add methods to TermdbVocab,
1177
- // later on, add methods with same name to FrontendVocab
1178
- getDataRequestOpts() {
1179
- const c = this.scatter.config;
1180
- const coordTWs = [];
1181
- if (c.term) coordTWs.push(c.term);
1182
- if (c.term2) coordTWs.push(c.term2);
1183
- const filter = this.scatter.parentId ? this.scatter.state.termfilter.filter : this.scatter.getFilter();
1184
- const opts = {
1185
- name: c.name,
1186
- // the actual identifier of the plot, for retrieving data from server
1187
- colorTW: c.colorTW,
1188
- filter,
1189
- coordTWs,
1190
- chartType: this.scatter.type,
1191
- excludeOutliers: this.scatter.settings.excludeOutliers
1192
- };
1193
- if (this.scatter.state.termfilter.filter0) opts.filter0 = this.scatter.state.termfilter.filter0;
1194
- if (c.colorColumn) opts.colorColumn = c.colorColumn;
1195
- if (c.shapeTW) opts.shapeTW = c.shapeTW;
1196
- if (c.scaleDotTW) {
1197
- if (!c.scaleDotTW.q) c.scaleDotTW.q = {};
1198
- c.scaleDotTW.q.mode = "continuous";
1199
- opts.scaleDotTW = c.scaleDotTW;
1200
- }
1201
- if (c.term0) opts.divideByTW = c.term0;
1202
- return opts;
1203
- }
1204
- async initData() {
1205
- try {
1206
- const reqOpts = this.getDataRequestOpts();
1207
- if (reqOpts.coordTWs?.length == 1 && this.scatter.type == "sampleScatter") return;
1208
- const data = await this.scatter.app.vocabApi.getScatterData(
1209
- reqOpts,
1210
- this.scatter.api?.getAbortSignal()
1211
- );
1212
- if ("error" in data || !data.result) throw new Error(data["error"] || "No data received");
1213
- this.charts = [];
1214
- this.range = data.range;
1215
- for (const [key, chartData] of Object.entries(data.result)) {
1216
- const chart = chartData;
1217
- if (!Array.isArray(chart.samples)) throw new Error("data.samples[] not array");
1218
- this.createChart(key, chart);
1219
- }
1220
- this.is3D = this.scatter.config.term0?.q.mode == "continuous";
1221
- this.initRanges();
1222
- } catch (e) {
1223
- if (this.scatter.app.isAbortError(e)) return;
1224
- console.error(e);
1225
- throw e.message || e;
1226
- }
1227
- }
1228
- };
1229
-
1230
- // plots/scatter/viewmodel/scatterLegendInteractivity.ts
1231
- var ScatterLegendInteractivity = class {
1232
- constructor(scatter) {
1233
- this.scatter = scatter;
1234
- }
1235
- onLegendClick(chart, name, key, e, category) {
1236
- const tw = this.scatter.config[name];
1237
- const isColorTW = name == "colorTW";
1238
- const hidden = tw.q.hiddenValues ? key in tw.q.hiddenValues : false;
1239
- const userHidden = Object.keys(tw.q?.hiddenValues ?? {}).filter((k) => !tw.term.values?.[k]?.uncomputable);
1240
- const hiddenCount = userHidden.length;
1241
- if (hidden && hiddenCount == 1 && userHidden[0] == key) {
1242
- this.hideCategory(tw, key, false);
1243
- this.dispatchConfig(name, tw);
1244
- return;
1245
- }
1246
- const menu = new Menu({ padding: "0px" });
1247
- const div = menu.d.append("div");
1248
- div.append("div").attr("class", "sja_menuoption sja_sharp_border").text(hidden ? "Show" : "Hide").on("click", () => {
1249
- this.hideCategory(tw, key, !hidden);
1250
- menu.hide();
1251
- this.dispatchConfig(name, tw);
1252
- });
1253
- div.append("div").attr("class", "sja_menuoption sja_sharp_border").text("Show only").on("click", () => {
1254
- const map = name == "colorTW" ? chart.colorLegend : chart.shapeLegend;
1255
- for (const mapKey of map.keys())
1256
- this.hideCategory(
1257
- tw,
1258
- mapKey,
1259
- tw.term.type == "geneVariant" && tw.q.type == "values" ? !mapKey.startsWith(key) : mapKey != key
1260
- );
1261
- menu.hide();
1262
- this.dispatchConfig(name, tw);
1263
- });
1264
- if (hiddenCount > 1)
1265
- div.append("div").attr("class", "sja_menuoption sja_sharp_border").text("Show all").on("click", () => {
1266
- menu.hide();
1267
- const map = isColorTW ? chart.colorLegend : chart.shapeLegend;
1268
- for (const mapKey of map.keys()) this.hideCategory(tw, mapKey, false);
1269
- this.dispatchConfig(name, tw);
1270
- });
1271
- if (isColorTW) {
1272
- const color = rgb(category.color).formatHex();
1273
- const input = div.append("div").attr("class", "sja_sharp_border").style("padding", "0px 10px").text("Color:").append("input").attr("type", "color").attr("value", color).on("change", () => {
1274
- this.changeColor(category.key, input.node().value);
1275
- menu.hide();
1276
- });
1277
- }
1278
- if (!isColorTW) {
1279
- div.append("div").attr("class", "sja_menuoption sja_sharp_border").text("Change shape").on("click", () => {
1280
- div.selectAll("*").remove();
1281
- const callback = (index) => {
1282
- this.changeShape(category.key, index);
1283
- menu.hide();
1284
- };
1285
- shapeSelector(div, callback);
1286
- });
1287
- }
1288
- menu.showunder(e.target);
1289
- }
1290
- async changeShape(key, shape) {
1291
- const tw = this.scatter.config.shapeTW;
1292
- if (!tw.term.values) tw.term.values = {};
1293
- if (!tw.term.values[key]) tw.term.values[key] = {};
1294
- tw.term.values[key].shape = shape;
1295
- await this.scatter.app.dispatch({
1296
- type: "plot_edit",
1297
- id: this.scatter.id,
1298
- config: { shapeTW: tw }
1299
- });
1300
- }
1301
- dispatchConfig(name, tw) {
1302
- this.scatter.app.dispatch({
1303
- type: "plot_edit",
1304
- id: this.scatter.id,
1305
- config: { [name]: tw }
1306
- });
1307
- }
1308
- hideCategory(tw, key, hide) {
1309
- if (!tw.q) tw.q = {};
1310
- if (!tw.q.hiddenValues) tw.q.hiddenValues = {};
1311
- const value = !(tw.term.type == "geneVariant" && tw.q.type == "values") && tw.term.values?.[key] ? tw.term.values[key] : { key, label: key };
1312
- if (!hide) delete tw.q.hiddenValues[key];
1313
- else tw.q.hiddenValues[key] = value;
1314
- if (key == "Ref") {
1315
- this.scatter.settings.showRef = !hide;
1316
- this.scatter.app.dispatch({
1317
- type: "plot_edit",
1318
- id: this.scatter.id,
1319
- config: {
1320
- settings: { sampleScatter: this.scatter.settings }
1321
- }
1322
- });
1323
- }
1324
- }
1325
- changeGradientColor(chart, color, idx) {
1326
- const hexColor = rgb(color).formatHex();
1327
- const colorKey = idx == 0 ? "startColor" : "stopColor";
1328
- this.scatter.config[colorKey][chart.id] = hexColor;
1329
- const range = chart.currentColorRange || chart.colorGenerator.domain();
1330
- chart.colorGenerator = linear().domain(range).range([this.scatter.config.startColor[chart.id], this.scatter.config.stopColor[chart.id]]);
1331
- this.scatter.app.dispatch({
1332
- type: "plot_edit",
1333
- id: this.scatter.id,
1334
- config: this.scatter.config
1335
- });
1336
- }
1337
- async changeColor(key, color) {
1338
- const tw = this.scatter.config.colorTW;
1339
- if (!tw.term.values) tw.term.values = {};
1340
- if (!tw.term.values[key]) tw.term.values[key] = {};
1341
- tw.term.values[key].color = color;
1342
- await this.scatter.app.dispatch({
1343
- type: "plot_edit",
1344
- id: this.scatter.id,
1345
- config: { colorTW: tw }
1346
- });
1347
- }
1348
- };
1349
-
1350
- // plots/scatter/view/scatterView.ts
1351
- var minShapeSize = 0.2;
1352
- var maxShapeSize = 6;
1353
- var chartSizeMin = 200;
1354
- var chartSizeMax = 800;
1355
- function getShapeDefaultQ() {
1356
- const defaultQ = {};
1357
- for (const type of numericTypes) {
1358
- if (dictionaryNumericTypes.has(type)) continue;
1359
- defaultQ[type] = { mode: "discrete", type: "custom-bin", preferredBins: "median" };
1360
- }
1361
- return defaultQ;
1362
- }
1363
- var ScatterView = class {
1364
- constructor(scatter) {
1365
- this.opts = scatter.opts;
1366
- this.scatter = scatter;
1367
- this.opts.holder.attr("data-testid", "sjpp-scatter-holder");
1368
- const leftDiv = this.opts.holder.insert("div").style("display", "inline-block");
1369
- const rightDiv = this.opts.holder.insert("div").style("display", "inline-block").style("vertical-align", "top");
1370
- const controlsHolder = leftDiv.append("div").style("display", "inline-block").attr("data-testid", "sjpp-scatter-controls-div");
1371
- const domOpts = { controls: controlsHolder, mainWrapper: rightDiv };
1372
- const { errdiv, loadingDiv, banner, renderedData } = scatter.getStandardDomLayout(this.opts.holder, domOpts);
1373
- renderedData.selectAll("*").remove();
1374
- this.dom = {
1375
- controlsHolder,
1376
- toolsDiv: leftDiv.insert("div"),
1377
- errdiv,
1378
- loadingDiv: loadingDiv.attr("data-testid", "sjpp-scatter-loading-div"),
1379
- bannerDiv: banner,
1380
- headerDiv: renderedData.append("div").attr("data-testid", "sjpp-scatter-header-div"),
1381
- renderedData: renderedData.attr("data-testid", "sjpp-scatter-main-div").style("display", "flex").style("flex-direction", "row").style("flex-wrap", "wrap").style("max-width", "100vw"),
1382
- mainDiv: renderedData,
1383
- header: this.opts.header,
1384
- tip: new Menu({ padding: "0px" }),
1385
- tooltip: new Menu({ padding: "2px", offsetX: 10, offsetY: 0 })
1386
- };
1387
- if (this.dom.header) {
1388
- const chartName = splitCamelCase(this.scatter.type).toUpperCase();
1389
- formatHeaderText({
1390
- header: this.dom.header,
1391
- chartType: chartName,
1392
- text: this.scatter.config.name || ""
1393
- });
1394
- }
1395
- }
1396
- getControlInputs() {
1397
- const labels = this.scatter.config.controlLabels;
1398
- const hasRef = this.scatter.model.charts?.[0]?.data?.samples?.find((s) => s.isRef) || false;
1399
- const chartType = "sampleScatter";
1400
- const itemLabel = this.scatter.settings.itemLabel;
1401
- const scaleDotOption = {
1402
- type: "term",
1403
- configKey: "scaleDotTW",
1404
- chartType,
1405
- usecase: { target: "sampleScatter", detail: "numeric" },
1406
- title: `Scale symbol size by term value`,
1407
- label: "Scale by",
1408
- vocabApi: this.scatter.app.vocabApi,
1409
- numericEditMenuVersion: ["continuous"],
1410
- //Eventually this will be corrected with usecase.detail
1411
- //When single cell, only relevant terms will be displayed
1412
- //in the tree
1413
- getDisplayStyle: () => {
1414
- return this.scatter.config?.singleCellPlot ? "none" : "";
1415
- }
1416
- };
1417
- const shapeOption = {
1418
- type: "term",
1419
- configKey: "shapeTW",
1420
- chartType,
1421
- usecase: { target: "sampleScatter", detail: "shapeTW" },
1422
- title: "Categories to assign a shape",
1423
- label: "Shape",
1424
- vocabApi: this.scatter.app.vocabApi,
1425
- numericEditMenuVersion: ["discrete"],
1426
- // only applies when a term is first picked from the tree, so a user-chosen binning
1427
- // from the pill's edit menu is not overridden
1428
- defaultQ4fillTW: getShapeDefaultQ(),
1429
- //Eventually this will be corrected with usecase.detail
1430
- //When single cell, only relevant terms will be displayed
1431
- //in the tree
1432
- getDisplayStyle: () => {
1433
- return this.scatter.config?.singleCellPlot ? "none" : "";
1434
- },
1435
- processInput: async (tw) => {
1436
- if (isNumericTerm(tw?.term)) {
1437
- if (!tw.q) tw.q = {};
1438
- tw.q.mode = "discrete";
1439
- await fillTermWrapper(tw, this.scatter.app.vocabApi);
1440
- }
1441
- }
1442
- };
1443
- const shapeSizeOption = {
1444
- label: `${itemLabel} size`,
1445
- type: "number",
1446
- chartType,
1447
- settingsKey: "size",
1448
- title: `${itemLabel} size, represents the factor used to scale the ${itemLabel.toLowerCase()}`,
1449
- min: minShapeSize,
1450
- max: maxShapeSize,
1451
- step: 0.1
1452
- };
1453
- const step = (maxShapeSize - minShapeSize) / 10;
1454
- const minShapeSizeOption = {
1455
- label: "Min size",
1456
- type: "number",
1457
- chartType,
1458
- settingsKey: "minShapeSize",
1459
- title: "Minimum symbol size",
1460
- min: minShapeSize,
1461
- max: maxShapeSize,
1462
- step
1463
- };
1464
- const maxShapeSizeOption = {
1465
- label: "Max size",
1466
- type: "number",
1467
- chartType,
1468
- settingsKey: "maxShapeSize",
1469
- title: "Maximum symbol size",
1470
- min: minShapeSize,
1471
- max: maxShapeSize,
1472
- step
1473
- };
1474
- const orientation = {
1475
- label: "Scale order",
1476
- type: "radio",
1477
- chartType,
1478
- settingsKey: "scaleDotOrder",
1479
- options: [
1480
- { label: "Ascending", value: "Ascending" },
1481
- { label: "Descending", value: "Descending" }
1482
- ]
1483
- };
1484
- const refSizeOption = {
1485
- label: "Reference size",
1486
- type: "number",
1487
- chartType,
1488
- settingsKey: "refSize",
1489
- title: "Set the area of the reference symbol in square pixels.",
1490
- min: 0,
1491
- max: maxShapeSize,
1492
- step: 0.1
1493
- };
1494
- const showAxes = {
1495
- boxLabel: "",
1496
- label: "Show axes",
1497
- type: "checkbox",
1498
- chartType,
1499
- settingsKey: "showAxes",
1500
- title: `Option to show/hide plot axes`,
1501
- testid: "showAxes"
1502
- };
1503
- const term = this.scatter.config.term ? "term" : "colorTW";
1504
- const specialCase = getSingleCellSpecialCase(this.scatter.config, term, true);
1505
- const inputs = [
1506
- {
1507
- type: "term",
1508
- configKey: "colorTW",
1509
- chartType,
1510
- usecase: { target: "sampleScatter", detail: "colorTW", specialCase },
1511
- title: `Categories to color the ${labels.sample} symbol`,
1512
- label: "Color",
1513
- vocabApi: this.scatter.app.vocabApi,
1514
- numericEditMenuVersion: ["continuous", "discrete"],
1515
- /** Disabling colorBy when two sc terms present.
1516
- * Dots overlap and colorBy is not meaningful in this case. */
1517
- getDisplayStyle: () => {
1518
- return this.scatter.config?.singleCellPlot && this.scatter.config.term2 ? "none" : "";
1519
- }
1520
- },
1521
- {
1522
- label: "Opacity",
1523
- type: "number",
1524
- chartType,
1525
- settingsKey: "opacity",
1526
- title: "Set the opacity of the elements",
1527
- min: 0,
1528
- max: 1,
1529
- step: 0.1
1530
- },
1531
- {
1532
- label: "Chart width",
1533
- type: "number",
1534
- chartType,
1535
- min: chartSizeMin,
1536
- max: chartSizeMax,
1537
- step: 10,
1538
- settingsKey: "svgw"
1539
- },
1540
- {
1541
- label: "Chart height",
1542
- type: "number",
1543
- chartType,
1544
- min: chartSizeMin,
1545
- max: chartSizeMax,
1546
- step: 10,
1547
- settingsKey: "svgh"
1548
- },
1549
- {
1550
- label: "Show contour map",
1551
- boxLabel: "",
1552
- type: "checkbox",
1553
- chartType,
1554
- settingsKey: "showContour",
1555
- title: "Shows the density of point clouds. If 'Color' is used in continous mode, it uses it to weight the points when calculating the density contours. If 'Z/Divide by' is added in continous mode, it used it instead.",
1556
- getDisplayStyle: () => {
1557
- return this.scatter.config?.singleCellPlot && this.scatter.model.is2DLarge ? "none" : "";
1558
- }
1559
- },
1560
- {
1561
- label: "Save zoom transform",
1562
- boxLabel: "",
1563
- type: "checkbox",
1564
- chartType,
1565
- settingsKey: "saveZoomTransform",
1566
- title: `Option to save the zoom transformation in the state. Needed if you want to save a session with the actual zoom and pan applied`,
1567
- processInput: (value) => this.saveZoomTransform(value),
1568
- getDisplayStyle: () => {
1569
- return this.scatter.config?.singleCellPlot && this.scatter.model.is2DLarge ? "none" : "";
1570
- }
1571
- }
1572
- ];
1573
- if (this.scatter.settings.showContour)
1574
- inputs.push(
1575
- {
1576
- label: "Color contours",
1577
- boxLabel: "",
1578
- type: "checkbox",
1579
- chartType,
1580
- settingsKey: "colorContours"
1581
- },
1582
- {
1583
- label: "Contour bandwidth",
1584
- type: "number",
1585
- chartType,
1586
- settingsKey: "contourBandwidth",
1587
- title: "Reduce to increase resolution.",
1588
- min: 5,
1589
- max: 50,
1590
- step: 5
1591
- },
1592
- {
1593
- label: "Contour thresholds",
1594
- type: "number",
1595
- chartType,
1596
- settingsKey: "contourThresholds",
1597
- title: "Increase to enhance contour detail.",
1598
- min: 5,
1599
- max: 30,
1600
- step: 5
1601
- }
1602
- );
1603
- if (this.scatter.config.sampleCategory) {
1604
- const options = Object.values(this.scatter.config.sampleCategory.tw.term.values).map((v) => ({
1605
- label: v.label || v.key,
1606
- value: v.key
1607
- }));
1608
- if (this.scatter.config.sampleCategory.order)
1609
- options.sort((elem1, elem2) => {
1610
- const i1 = this.scatter.config.sampleCategory.order.indexOf(elem1.value);
1611
- const i2 = this.scatter.config.sampleCategory.order.indexOf(elem2.value);
1612
- if (i1 < i2) return -1;
1613
- return 1;
1614
- });
1615
- if (!this.scatter.settings.sampleCategory)
1616
- this.scatter.settings.sampleCategory = this.scatter.config.sampleCategory.defaultValue || "";
1617
- options.push({ label: "All", value: "" });
1618
- const sampleCategory = {
1619
- label: "Sample type",
1620
- type: "dropdown",
1621
- chartType,
1622
- settingsKey: "sampleCategory",
1623
- options
1624
- };
1625
- inputs.push(sampleCategory);
1626
- }
1627
- if (!this.scatter.model.is2DLarge && !this.scatter.config.singleCellPlot) {
1628
- const isPremade = this.scatter.config.name !== void 0 && !this.scatter.config.term;
1629
- inputs.unshift({
1630
- type: "term",
1631
- configKey: "term0",
1632
- chartType,
1633
- usecase: { target: "sampleScatter", detail: "term0" },
1634
- title: "Term to to divide by categories or to use as Z coordinate",
1635
- label: "Z / Divide by",
1636
- vocabApi: this.scatter.app.vocabApi,
1637
- // do not allow 'continuous' mode for now, even if it can be rendered along z-axis,
1638
- // since clicking to barchart/violin/boxplot tab from the scatter tab does not
1639
- // automatically convert the divide-by term to discrete; a continuous mode in those
1640
- // other charts leads to nonsensical chart per unique float/integer value
1641
- numericEditMenuVersion: ["discrete"],
1642
- processInput: (tw) => {
1643
- if (!isPremade && isNumericTerm(tw?.term)) tw.q = { mode: "continuous" };
1644
- }
1645
- });
1646
- } else if (!this.scatter.config.singleCellPlot) {
1647
- inputs.push(
1648
- {
1649
- // below was changed from 'Sample size'
1650
- // TODO: clarify how this is different from `${itemLabel} size`/`Symbol size`?
1651
- label: `${labels.Sample} size`,
1652
- type: "number",
1653
- chartType,
1654
- settingsKey: "threeSize",
1655
- title: `${labels.Sample} size`,
1656
- min: 0,
1657
- max: 1,
1658
- step: 1e-3
1659
- },
1660
- {
1661
- label: "Field of Vision",
1662
- type: "number",
1663
- chartType,
1664
- settingsKey: "threeFOV",
1665
- title: "Field of Vision",
1666
- min: 50,
1667
- max: 90,
1668
- step: 1
1669
- }
1670
- );
1671
- }
1672
- if (this.scatter.config.term) {
1673
- inputs.unshift(
1674
- ...[
1675
- {
1676
- type: "term",
1677
- configKey: "term",
1678
- chartType,
1679
- usecase: { target: "sampleScatter", detail: "numeric", specialCase },
1680
- title: `X coordinate to plot the ${labels.samples}`,
1681
- label: "X",
1682
- vocabApi: this.scatter.app.vocabApi,
1683
- menuOptions: "!remove",
1684
- numericEditMenuVersion: ["continuous"]
1685
- },
1686
- {
1687
- type: "term",
1688
- configKey: "term2",
1689
- chartType,
1690
- usecase: { target: "sampleScatter", detail: "numeric", specialCase },
1691
- title: `Y coordinate to plot the ${labels.samples}`,
1692
- label: "Y",
1693
- vocabApi: this.scatter.app.vocabApi,
1694
- menuOptions: "!remove",
1695
- numericEditMenuVersion: ["continuous"]
1696
- }
1697
- ]
1698
- );
1699
- if (!this.scatter.model.is3D) {
1700
- inputs.splice(4, 0, shapeOption);
1701
- inputs.splice(5, 0, scaleDotOption);
1702
- if (this.scatter.config.scaleDotTW) {
1703
- inputs.splice(6, 0, minShapeSizeOption);
1704
- inputs.splice(7, 0, maxShapeSizeOption);
1705
- inputs.splice(8, 0, orientation);
1706
- if (hasRef) inputs.splice(9, 0, refSizeOption);
1707
- } else {
1708
- inputs.splice(6, 0, shapeSizeOption);
1709
- if (hasRef) inputs.splice(7, 0, refSizeOption);
1710
- }
1711
- inputs.push({
1712
- label: "Show regression",
1713
- type: "dropdown",
1714
- chartType,
1715
- settingsKey: "regression",
1716
- options: [
1717
- { label: "None", value: "None" },
1718
- //{ label: 'Loess', value: 'Loess' },
1719
- { label: "Lowess", value: "Lowess" },
1720
- { label: "Polynomial", value: "Polynomial" }
1721
- ]
1722
- });
1723
- } else {
1724
- inputs.push({
1725
- label: "Chart depth",
1726
- type: "number",
1727
- chartType,
1728
- settingsKey: "svgd"
1729
- });
1730
- inputs.push({
1731
- label: "Field of vision",
1732
- title: "Camera field of view, in degrees",
1733
- type: "number",
1734
- chartType,
1735
- settingsKey: "fov"
1736
- });
1737
- }
1738
- inputs.push(showAxes, ...this.getMinMaxInputs());
1739
- inputs.push({
1740
- label: "Default color",
1741
- type: "color",
1742
- chartType,
1743
- settingsKey: "defaultColor"
1744
- });
1745
- } else if (!this.scatter.model.is2DLarge) {
1746
- inputs.splice(2, 0, shapeOption);
1747
- inputs.splice(3, 0, scaleDotOption);
1748
- if (this.scatter.config.scaleDotTW) {
1749
- inputs.splice(4, 0, minShapeSizeOption);
1750
- inputs.splice(5, 0, maxShapeSizeOption);
1751
- inputs.splice(6, 0, orientation);
1752
- if (hasRef) inputs.splice(7, 0, refSizeOption);
1753
- } else {
1754
- inputs.splice(4, 0, shapeSizeOption);
1755
- if (hasRef) inputs.splice(5, 0, refSizeOption);
1756
- }
1757
- inputs.push(showAxes);
1758
- }
1759
- this.mayAddControlLabels(inputs);
1760
- return this.scatter.config.bySample ? inputs.filter((i) => i.type != "term") : inputs;
1761
- }
1762
- getMinMaxInputs() {
1763
- const range = this.scatter.model.range;
1764
- if (!range) return [];
1765
- const xMin = roundValueAuto(range.xMin);
1766
- const xMax = roundValueAuto(range.xMax);
1767
- const xStep = (xMax - xMin) / 10;
1768
- const yMin = roundValueAuto(range.yMin);
1769
- const yMax = roundValueAuto(range.yMax);
1770
- const yStep = (yMax - yMin) / 10;
1771
- const inputs = [
1772
- {
1773
- label: "X axis minimum",
1774
- type: "number",
1775
- chartType: this.scatter.type,
1776
- settingsKey: "minXScale",
1777
- title: `Set the minimum X axis value between ${xMin} and ${xMax}`,
1778
- placeholder: `${xMin}`,
1779
- min: xMin,
1780
- max: xMax,
1781
- step: xStep
1782
- },
1783
- {
1784
- label: "X axis maximum",
1785
- type: "number",
1786
- chartType: this.scatter.type,
1787
- settingsKey: "maxXScale",
1788
- title: `Set the maximum X axis value between ${xMin} and ${xMax}`,
1789
- placeholder: `${xMax}`,
1790
- min: xMin,
1791
- max: xMax,
1792
- step: xStep,
1793
- processInput: (value) => {
1794
- const n = this.dom.controlsHolder.selectAll("input").filter(function() {
1795
- return this.placeholder == `${xMax}`;
1796
- });
1797
- if (!n.node().value) return xMax;
1798
- else return value;
1799
- }
1800
- },
1801
- {
1802
- label: "Y axis minimum",
1803
- type: "number",
1804
- chartType: this.scatter.type,
1805
- settingsKey: "minYScale",
1806
- title: `Set the minimum Y axis value between ${yMin} and ${yMax}`,
1807
- placeholder: `${yMin}`,
1808
- min: yMin,
1809
- max: yMax,
1810
- step: yStep
1811
- },
1812
- {
1813
- label: "Y axis maximum",
1814
- type: "number",
1815
- chartType: this.scatter.type,
1816
- settingsKey: "maxYScale",
1817
- title: `Set the maximum Y axis value between ${yMin} and ${yMax}`,
1818
- placeholder: `${yMax}`,
1819
- min: yMin,
1820
- max: yMax,
1821
- step: yStep,
1822
- processInput: (value) => {
1823
- const n = this.dom.controlsHolder.selectAll("input").filter(function() {
1824
- return this.placeholder == `${yMax}`;
1825
- });
1826
- if (!n.node().value) return yMax;
1827
- else return value;
1828
- }
1829
- }
1830
- ];
1831
- return inputs;
1832
- }
1833
- mayAddControlLabels(inputs) {
1834
- const controlLabels = structuredClone(this.scatter.config.controlLabels);
1835
- if (!controlLabels) return;
1836
- let term1input, term2input, term0input;
1837
- for (const i of inputs) {
1838
- if (i.configKey == "term") term1input = i;
1839
- else if (i.configKey == "term2") term2input = i;
1840
- else if (i.configKey == "term0") term0input = i;
1841
- }
1842
- if (term1input && term2input) {
1843
- if (controlLabels.term1) term1input.label = controlLabels.term1.label + " (X)";
1844
- if (controlLabels.term2) term2input.label = controlLabels.term2.label + " (Y)";
1845
- if (term0input && controlLabels.term0) term0input.label = controlLabels.term0.label + " (Z)";
1846
- }
1847
- }
1848
- saveZoomTransform(value) {
1849
- if (value) this.scatter.vm.scatterZoom.saveZoomTransform();
1850
- return value;
1851
- }
1852
- };
1853
- function splitCamelCase(text) {
1854
- return text.split(/(?=[A-Z])/).join(" ");
1855
- }
1856
-
1857
- // plots/scatter/viewmodel/scatterLegend.ts
1858
- var ScatterLegend = class {
1859
- constructor(scatter) {
1860
- this.scatter = scatter;
1861
- this.vm = scatter.vm;
1862
- this.model = scatter.model;
1863
- this.interactivity = scatter.interactivity;
1864
- this.legendInteractivity = new ScatterLegendInteractivity(scatter);
1865
- }
1866
- //Dynamically calculate the length of the legend labels
1867
- getLegendLabelWidth(chart, key, svg, size) {
1868
- const legend = chart[`${key}Legend`];
1869
- if (!legend) return 0;
1870
- const labels = [];
1871
- for (const [k, v] of legend.entries()) {
1872
- if (k != "Ref") labels.push(`${k}, n=(${v.sampleCount})`);
1873
- }
1874
- labels.push(this.scatter.config[`${key}TW`]?.term?.name ?? "");
1875
- const width = getMaxLabelWidth(svg, labels, size) + 70;
1876
- return width;
1877
- }
1878
- getFontSize(chart, legend) {
1879
- let fontSize = 0.9;
1880
- if (chart.colorLegend.size < 10 && chart.shapeLegend.size < 10) return fontSize;
1881
- const top = 20;
1882
- if (legend.size > top) {
1883
- fontSize = Math.min(0.9, top / legend.size);
1884
- if (fontSize < 0.7) fontSize = 0.7;
1885
- }
1886
- return fontSize;
1887
- }
1888
- renderLegend(chart, step) {
1889
- const legendG = chart.legendG;
1890
- legendG.selectAll("*").remove();
1891
- let offsetX = 0;
1892
- let offsetY = 15;
1893
- let legendHeight = 0;
1894
- if (!this.scatter.config.colorTW && !this.scatter.config.shapeTW && !this.scatter.config.colorColumn) {
1895
- if (this.scatter.config.scaleDotTW) {
1896
- chart.scaleG = legendG.append("g").attr("transform", `translate(${offsetX + 45},${this.scatter.vm.legendHeight - 150})`);
1897
- this.drawScaleDotLegend(chart);
1898
- }
1899
- return;
1900
- }
1901
- let title;
1902
- let title0;
1903
- if (this.scatter.config.term0) {
1904
- title0 = `${this.scatter.config.term0.term.name + " " + chart.id}, n=${chart.cohortSamples.length}`;
1905
- } else {
1906
- const n = chart.totalSampleCount ?? chart.cohortSamples?.length;
1907
- const noun = this.scatter.config.sampleType || this.scatter.settings.itemLabel.toLowerCase();
1908
- title0 = `${n} ${noun}${n == 1 ? "" : "s"}`;
1909
- }
1910
- if (this.model.filterSampleStr) title0 += `, search = ${this.model.filterSampleStr}`;
1911
- legendG.append("text").attr("x", 0).attr("y", offsetY).text(title0).style("font-weight", "bold");
1912
- const fontSize = this.getFontSize(chart, chart.colorLegend);
1913
- const scale = chart.colorLegend.size > 20 || chart.shapeLegend.size > 20 ? 0.6 : 0.7;
1914
- const colorG = legendG.append("g").style("font-size", `${fontSize}em`).attr("data-testid", "sjpp-color-legend");
1915
- offsetY += step + 20;
1916
- if (this.scatter.config.colorTW || this.scatter.config.colorColumn) {
1917
- title = `${getTitle(
1918
- this.scatter.config.colorTW?.term?.name || this.scatter.config.colorColumn.name,
1919
- 40,
1920
- this.scatter.config.shapeTW == void 0
1921
- )}`;
1922
- const colorRefCategory = chart.colorLegend.get("Ref");
1923
- if (this.scatter.config.colorTW?.term?.type == "geneVariant" && this.scatter.config.colorTW?.q.type == "values") {
1924
- offsetY = this.renderGeneVariantLegend(
1925
- chart,
1926
- offsetX,
1927
- offsetY,
1928
- legendG,
1929
- this.scatter.config.colorTW,
1930
- "category",
1931
- chart.colorLegend,
1932
- scale
1933
- );
1934
- } else {
1935
- this.addLegendTitle(legendG, title, offsetX, offsetY, this.scatter.config.colorTW, "COLOR");
1936
- offsetY += step;
1937
- if (this.scatter.config.colorTW?.q?.mode === "continuous") {
1938
- let [min, max2] = chart.colorGenerator.domain();
1939
- const colorValues = chart.colorValues;
1940
- const scaleG = colorG.append("g").attr("data-testid", "sjpp-scale-legend");
1941
- const colorScale = new ColorScale({
1942
- // Basic visual configuration
1943
- holder: scaleG,
1944
- // SVG group to contain our color scale
1945
- barheight: 20,
1946
- // Height of the color gradient bar
1947
- barwidth: 150,
1948
- // Width of the color gradient bar
1949
- colors: [
1950
- // Start and end colors for our gradient
1951
- this.scatter.config.startColor[chart.id],
1952
- this.scatter.config.stopColor[chart.id]
1953
- ],
1954
- domain: [min, max2],
1955
- // Current numerical range of our data
1956
- position: `0, 100`,
1957
- // Position within the legend
1958
- ticks: 4,
1959
- // Number of tick marks to show
1960
- tickSize: 5,
1961
- // Size of tick marks
1962
- topTicks: true,
1963
- // Display ticks above the gradient bar
1964
- // Callback for when gradient colors are changed via color picker
1965
- setColorsCallback: (val, idx) => {
1966
- this.legendInteractivity.changeGradientColor(chart, val, idx);
1967
- },
1968
- // Configuration for our enhanced scaling modes
1969
- numericInputs: {
1970
- // Start with either the chart's current mode or default to 'auto'
1971
- cutoffMode: this.scatter.settings.colorScaleMode,
1972
- // Default percentile value for percentile mode
1973
- defaultPercentile: this.scatter.settings.colorScalePercentile,
1974
- // This callback handles all mode changes and updates
1975
- callback: (obj) => {
1976
- if (obj.cutoffMode === "auto") {
1977
- min = colorValues[0];
1978
- max2 = colorValues[colorValues.length - 1];
1979
- } else if (obj.cutoffMode === "fixed") {
1980
- min = obj.min;
1981
- max2 = obj.max;
1982
- } else if (obj.cutoffMode === "percentile") {
1983
- min = colorValues[0];
1984
- const index = Math.floor(colorValues.length * obj.percentile / 100);
1985
- max2 = colorValues[index];
1986
- }
1987
- this.scatter.app.dispatch({
1988
- type: "plot_edit",
1989
- id: this.scatter.id,
1990
- config: {
1991
- settings: {
1992
- sampleScatter: {
1993
- colorScaleMode: obj.cutoffMode,
1994
- colorScaleMinFixed: obj.cutoffMode === "fixed" ? min : null,
1995
- colorScaleMaxFixed: obj.cutoffMode === "fixed" ? max2 : null,
1996
- colorScalePercentile: obj.cutoffMode === "percentile" ? obj.percentile : this.scatter.settings.colorScalePercentile
1997
- }
1998
- }
1999
- }
2000
- });
2001
- }
2002
- }
2003
- });
2004
- colorScale.updateScale();
2005
- offsetY += step * 2;
2006
- } else {
2007
- for (const [key, category] of chart.colorLegend) {
2008
- if (key == "Ref") continue;
2009
- const name = key;
2010
- const hidden = this.scatter.config.colorTW?.q.hiddenValues ? key in this.scatter.config.colorTW.q.hiddenValues : false;
2011
- const [circleG, itemG] = this.addLegendItem(
2012
- chart,
2013
- colorG,
2014
- category,
2015
- name,
2016
- key,
2017
- offsetX,
2018
- offsetY,
2019
- scale,
2020
- hidden
2021
- );
2022
- if (!this.scatter.config.colorColumn) {
2023
- circleG.on("click", (e) => this.legendInteractivity.onLegendClick(chart, "colorTW", key, e, category));
2024
- itemG.on("click", (event) => this.legendInteractivity.onLegendClick(chart, "colorTW", key, event, category));
2025
- }
2026
- offsetY += step;
2027
- }
2028
- }
2029
- }
2030
- if (colorRefCategory?.sampleCount > 0) {
2031
- offsetY = offsetY + step;
2032
- const titleG = legendG.append("g");
2033
- titleG.append("text").attr("x", offsetX).attr("y", offsetY).text("Reference").style("font-weight", "bold");
2034
- offsetY = offsetY + step;
2035
- const refColorG = legendG.append("g");
2036
- refColorG.append("path").attr("transform", () => `translate(${offsetX - 2}, ${offsetY - 4}) scale(${scale})`).style("fill", colorRefCategory.color).attr("d", shapes[0]).style("stroke", rgb(colorRefCategory.color).darker());
2037
- refColorG.on("click", (e) => this.legendInteractivity.onLegendClick(chart, "colorTW", "Ref", e, colorRefCategory));
2038
- const refText = legendG.append("g").append("text").attr("name", "sjpp-scatter-legend-label").attr("data-testid", "sjpp-scatter-ref-legend-label").attr("x", offsetX + 20).attr("y", offsetY + 4).text(`n=${colorRefCategory.sampleCount}`).style("text-decoration", !this.scatter.settings.showRef ? "line-through" : "none").attr("alignment-baseline", "middle");
2039
- refText.on("click", (e) => this.legendInteractivity.onLegendClick(chart, "colorTW", "Ref", e, colorRefCategory));
2040
- }
2041
- legendHeight = offsetY;
2042
- }
2043
- if (this.scatter.config.shapeTW) {
2044
- offsetX = chart.colorLegendWidth;
2045
- offsetY = 60;
2046
- title = `${getTitle(this.scatter.config.shapeTW.term.name, 40)}`;
2047
- if (this.scatter.config.shapeTW.term.type == "geneVariant" && this.scatter.config.shapeTW.q.type == "values") {
2048
- offsetY = this.renderGeneVariantLegend(
2049
- chart,
2050
- offsetX,
2051
- offsetY,
2052
- legendG,
2053
- this.scatter.config.shapeTW,
2054
- "shape",
2055
- chart.shapeLegend,
2056
- scale
2057
- );
2058
- } else {
2059
- const shapeG = legendG.append("g").style("font-size", `${this.getFontSize(chart, chart.shapeLegend)}em`).attr("data-testid", "sjpp-shape-legend");
2060
- this.addLegendTitle(legendG, title, offsetX, offsetY, this.scatter.config.shapeTW, "SHAPE");
2061
- offsetY += step;
2062
- const color = "gray";
2063
- for (const [key, shape] of chart.shapeLegend) {
2064
- if (key == "Ref") continue;
2065
- const index = shape.shape % shapes.length;
2066
- const symbol = shapes[index];
2067
- const name = key;
2068
- const count = shape.sampleCount;
2069
- const hidden = this.scatter.config.shapeTW.q.hiddenValues ? key in this.scatter.config.shapeTW.q.hiddenValues : false;
2070
- const itemG = shapeG.append("g");
2071
- itemG.append("path").attr("data-testid", `sjpp-legend-shape-${name}`).attr("transform", () => `translate(${offsetX}, ${offsetY - 4}) scale(${scale + 0.1})`).style("pointer-events", "bounding-box").style("fill", color).attr("d", symbol).style("stroke", rgb(color).darker());
2072
- itemG.append("text").attr("name", "sjpp-scatter-legend-label").attr("data-testid", "sjpp-scatter-shape-legend-label-" + name).attr("x", offsetX + 25).attr("y", offsetY + 4).text(`${name}, n=${count}`).style("text-decoration", hidden ? "line-through" : "none").attr("alignment-baseline", "middle");
2073
- offsetY += step;
2074
- itemG.on("click", (event) => this.legendInteractivity.onLegendClick(chart, "shapeTW", key, event, shape));
2075
- }
2076
- }
2077
- if (offsetY > legendHeight) legendHeight = offsetY;
2078
- }
2079
- if (this.scatter.config.scaleDotTW) {
2080
- chart.scaleG = legendG.append("g").attr("transform", `translate(${0},${legendHeight + 50})`);
2081
- this.drawScaleDotLegend(chart);
2082
- }
2083
- }
2084
- addLegendItem(chart, g, category, name, key, x, y, scale, hidden = false) {
2085
- const circleG = g.append("g");
2086
- circleG.append("path").attr("d", shapes[0]).attr("hex-color", category.color).attr("transform", `translate(${x - 2}, ${y - 4}) scale(${scale})`).attr("data-testid", `sjpp-legend-color-dot-${name}`).style("fill", category.color).style("stroke", rgb(category.color).darker());
2087
- if (!this.scatter.config.colorColumn)
2088
- circleG.on("click", (e) => this.legendInteractivity.onLegendClick(chart, "colorTW", key, e, category));
2089
- const itemG = g.append("g");
2090
- itemG.append("text").attr("name", "sjpp-scatter-legend-label").attr("data-testid", "sjpp-scatter-color-legend-label-" + name).attr("x", x + 20).attr("y", y + 4).text(`${name}, n=${category.sampleCount}`).style("text-decoration", hidden ? "line-through" : "none").attr("alignment-baseline", "middle");
2091
- return [circleG, itemG];
2092
- }
2093
- addLegendTitle(G, title, x, y, tw, extraText) {
2094
- const _t = G.append("text").attr("data-testid", "legendTitle").attr("x", x).attr("y", y).text(title).style("font-weight", "bold");
2095
- if (extraText) {
2096
- _t.append("tspan").text(extraText).attr("dx", 7).style("font-weight", "normal").attr("font-size", ".7em");
2097
- }
2098
- }
2099
- renderGeneVariantLegend(chart, offsetX, offsetY, legendG, tw, cname, map, scale) {
2100
- const step = 125;
2101
- const name = tw.term.name.length > 25 ? tw.term.name.slice(0, 25) + "..." : tw.term.name;
2102
- const title = name;
2103
- const G = legendG.append("g").style("font-size", "0.9em");
2104
- this.addLegendTitle(G, title, offsetX, offsetY, tw, cname == "category" ? "COLOR" : "SHAPE");
2105
- offsetX += step;
2106
- const mutations = [];
2107
- for (const value of map.values())
2108
- if (value.mutation)
2109
- mutations.push(value.mutation);
2110
- const mutationsLabels = /* @__PURE__ */ new Set();
2111
- offsetY += 10;
2112
- for (const mutation of mutations) {
2113
- const dt = mutation.dt;
2114
- const origin = morigin[mutation.origin]?.label;
2115
- const dtlabel = origin ? `${origin[0]} ${dt2label[dt]}` : dt2label[dt];
2116
- if (!mutationsLabels.has(dtlabel)) mutationsLabels.add(dtlabel);
2117
- else continue;
2118
- offsetY += 15;
2119
- G.append("text").attr("x", offsetX - step).attr("y", offsetY).text(origin ? `${origin} ${dt2label[dt]}` : dt2label[dt]).style("font-weight", "bold");
2120
- offsetY += 25;
2121
- for (const [key, category] of map) {
2122
- if (key == "Ref") continue;
2123
- if (!key.includes(dtlabel)) continue;
2124
- const [mkey, cat_dtlabel] = key.split(", ");
2125
- if (!cat_dtlabel.includes(dtlabel)) continue;
2126
- const itemG = G.append("g");
2127
- if (cname == "shape") {
2128
- const index = category.shape % shapes.length;
2129
- itemG.append("path").attr("data-testid", "sjpp-legend-shape").attr("transform", () => `translate(${offsetX - step - 2}, ${offsetY - 8}) scale(${scale})`).style("fill", "gray").style("pointer-events", "bounding-box").attr("d", shapes[index]).style("stroke", rgb("gray").darker());
2130
- itemG.on("click", (e) => this.legendInteractivity.onLegendClick(chart, "shapeTW", key, e, category));
2131
- } else {
2132
- itemG.append("path").attr("d", shapes[0]).attr("transform", `translate(${-2}, ${offsetY - 8}) scale(${scale})`).style("fill", category.color).style("stroke", rgb(category.color).darker());
2133
- itemG.on("click", (e) => this.legendInteractivity.onLegendClick(chart, "colorTW", key, e, category));
2134
- }
2135
- const hidden = tw.q.hiddenValues ? key in tw.q.hiddenValues : false;
2136
- const text = mkey.toUpperCase() + (key.includes(dtlabel) ? `, n=${category.sampleCount}` : "");
2137
- G.append("g").append("text").attr("x", offsetX - step + 24).attr("y", offsetY + 4).attr("name", "sjpp-scatter-legend-label").attr(
2138
- "data-testid",
2139
- (cname == "shape" ? "sjpp-scatter-shape-legend-label-" : "sjpp-scatter-color-legend-label-") + key
2140
- ).style("text-decoration", hidden ? "line-through" : "none").text(text).on(
2141
- "click",
2142
- (event) => this.legendInteractivity.onLegendClick(
2143
- chart,
2144
- cname == "shape" ? "shapeTW" : "colorTW",
2145
- key,
2146
- event,
2147
- category
2148
- )
2149
- );
2150
- offsetY += 25;
2151
- }
2152
- }
2153
- return offsetY;
2154
- }
2155
- drawScaleDotLegend(chart) {
2156
- const scaleG = chart.scaleG;
2157
- scaleG.selectAll("*").remove();
2158
- const width = 70;
2159
- const minScale = this.scatter.settings.minShapeSize / 3;
2160
- const maxScale = this.scatter.settings.maxShapeSize / 3;
2161
- const order = this.scatter.settings.scaleDotOrder;
2162
- const isAscending = order == "Ascending";
2163
- const titleG = scaleG.append("g");
2164
- titleG.append("text").text(this.scatter.config.scaleDotTW.term.name).style("font-weight", "bold");
2165
- const start = roundValueAuto(chart.ranges.scaleMin).toString();
2166
- const end = roundValueAuto(chart.ranges.scaleMax).toString();
2167
- const x = 30;
2168
- const y = 40;
2169
- const defaultSize = 16;
2170
- const minSize = defaultSize * minScale;
2171
- const maxSize = defaultSize * maxScale;
2172
- const minRadius = minSize / 2;
2173
- const maxRadius = maxSize / 2;
2174
- const minG = scaleG.append("g").attr("transform", `translate(${x},${y})`).attr("data-testid", "sjpp-legend-min-scale-g");
2175
- const shift = 30;
2176
- minG.append("path").attr("data-testid", "sjpp-legend-min-scale-dot").attr("d", shapes[0]).style("fill", "#aaa").style("stroke", "#aaa").attr(
2177
- "transform",
2178
- `translate(${isAscending ? -minRadius : -maxRadius}, ${isAscending ? -minRadius : -maxRadius}) scale(${isAscending ? minScale : maxScale})`
2179
- );
2180
- const maxG = scaleG.append("g").attr("transform", `translate(${width + x},${y})`);
2181
- maxG.append("path").attr("data-testid", "sjpp-legend-max-scale-dot").attr("d", shapes[0]).style("fill", "#aaa").style("stroke", "#aaa").attr(
2182
- "transform",
2183
- `translate(${isAscending ? -maxRadius : -minRadius}, ${isAscending ? -maxRadius : -minRadius}) scale(${isAscending ? maxScale : minScale})`
2184
- );
2185
- minG.append("text").attr("x", isAscending ? -minRadius - shift : -maxRadius - shift).attr("y", 5).style("font-size", ".8em").attr("text-anchor", "start").text(start);
2186
- maxG.append("text").attr("x", isAscending ? maxSize + 5 : minSize + 5).attr("y", 5).style("font-size", ".8em").text(end);
2187
- minG.append("line").attr("x1", 0).attr("y1", isAscending ? minRadius : maxRadius).attr("x2", width).attr("y2", isAscending ? maxRadius : minRadius).style("stroke", "#aaa");
2188
- minG.append("line").attr("x1", 0).attr("y1", isAscending ? -minRadius : -maxRadius).attr("x2", width).attr("y2", isAscending ? -maxRadius : -minRadius).style("stroke", "#aaa");
2189
- scaleG.append("rect").attr("width", 110 * this.scatter.zoom).attr("height", 50).attr("fill", "transparent").on("click", (e) => {
2190
- const menu = new Menu({ padding: "3px" });
2191
- const div = menu.d;
2192
- div.append("label").text("Min:");
2193
- const minInput = div.append("input").attr("data-testid", "sjpp-legend-min-scale-input").attr("type", "number").attr("min", minShapeSize).attr("step", "0.5").attr("max", maxShapeSize).style("width", "50px").property("value", this.scatter.settings.minShapeSize).on("change", () => {
2194
- let value = parseFloat(minInput.node().value);
2195
- if (!Number.isFinite(value)) return;
2196
- value = clampValue(value, minShapeSize, maxShapeSize);
2197
- value = value > this.scatter.config.settings.sampleScatter.maxShapeSize ? this.scatter.config.settings.sampleScatter.maxShapeSize : value;
2198
- minInput.property("value", value);
2199
- this.scatter.config.settings.sampleScatter.minShapeSize = value;
2200
- this.scatter.app.dispatch({
2201
- type: "plot_edit",
2202
- id: this.scatter.id,
2203
- config: this.scatter.config
2204
- });
2205
- });
2206
- div.append("label").text("Max:");
2207
- const maxInput = div.append("input").attr("data-testid", "sjpp-legend-max-scale-input").attr("type", "number").attr("step", "0.5").attr("min", minShapeSize).attr("max", maxShapeSize).style("width", "50px").property("value", this.scatter.settings.maxShapeSize).on("change", () => {
2208
- let value = parseFloat(maxInput.node().value);
2209
- if (!Number.isFinite(value)) return;
2210
- value = clampValue(value, minShapeSize, maxShapeSize);
2211
- value = value < this.scatter.config.settings.sampleScatter.minShapeSize ? this.scatter.config.settings.sampleScatter.minShapeSize : value;
2212
- maxInput.property("value", value);
2213
- this.scatter.config.settings.sampleScatter.maxShapeSize = value;
2214
- this.scatter.app.dispatch({
2215
- type: "plot_edit",
2216
- id: this.scatter.id,
2217
- config: this.scatter.config
2218
- });
2219
- });
2220
- const divRadios = menu.d.append("div");
2221
- divRadios.append("label").text("Order: ");
2222
- const data = ["Ascending", "Descending"];
2223
- divRadios.selectAll("input").data(data).enter().append("div").style("display", "inline-block").each((text, i, divs) => {
2224
- const div2 = select_default(divs[i]);
2225
- const input = div2.append("input").attr("type", "radio").attr("name", "order").attr("id", text).attr("value", text).property("checked", (text2) => text2 == order);
2226
- div2.append("label").text(text).attr("for", text);
2227
- input.on("change", (e2) => {
2228
- this.changeScaleDotOrder(e2.target.value);
2229
- });
2230
- });
2231
- menu.showunder(e.target);
2232
- });
2233
- }
2234
- changeScaleDotOrder(order) {
2235
- this.scatter.config.settings.sampleScatter.scaleDotOrder = order;
2236
- this.scatter.app.dispatch({
2237
- type: "plot_edit",
2238
- id: this.scatter.id,
2239
- config: this.scatter.config
2240
- });
2241
- }
2242
- };
2243
- function clampValue(inputValue, minValue, maxValue) {
2244
- if (maxValue < inputValue) inputValue = maxValue;
2245
- if (minValue > inputValue) inputValue = minValue;
2246
- return inputValue;
2247
- }
2248
- function getTitle(name, size = 30, complete = false) {
2249
- if (name.length > size && !complete) name = name.slice(0, size) + "...";
2250
- return name;
2251
- }
2252
-
2253
- // plots/scatter/viewmodel/scatterTooltip.ts
2254
- var HIT_BUFFER_PX = 3;
2255
- var HOVER_RING_MARGIN_PX = 2;
2256
- var ScatterTooltip = class {
2257
- constructor(scatter) {
2258
- /** One DataPointInteractions per chart; a term0 divide-by renders several charts. */
2259
- this.byChart = /* @__PURE__ */ new Map();
2260
- this.scatter = scatter;
2261
- this.view = scatter.view;
2262
- }
2263
- /** Rendered radius of a dot in serie-local px. `transform()` draws each shape in a 16x16
2264
- * box scaled by `getScale()`, so the radius is half of that. `getScale()` already accounts
2265
- * for scaleDotTW sizing, the reference cloud's refSize, and the search-match enlargement,
2266
- * and is zoom-invariant for the svg view. */
2267
- dotRadius(chart, s) {
2268
- return 8 * this.scatter.model.getScale(chart, s);
2269
- }
2270
- /** Projected center + rendered radius of every dot, built once per attach. Hover fires on
2271
- * every mousemove, so recomputing this per event turned plain cursor movement into an O(n)
2272
- * sweep of d3 scale calls over up to maxSvgSamplesCutoff (20k) samples. Everything it
2273
- * depends on — the axis scales and the size settings — is fixed for the life of an attach,
2274
- * and any change to them re-renders, which re-attaches. */
2275
- buildGeom(chart) {
2276
- const geom = /* @__PURE__ */ new Map();
2277
- let maxR = 0;
2278
- for (const s of chart.data.samples) {
2279
- const { x, y } = this.scatter.model.getCoordinates(chart, s);
2280
- const r = this.dotRadius(chart, s);
2281
- if (r > maxR) maxR = r;
2282
- geom.set(s, { x, y, r });
2283
- }
2284
- return { geom, maxR };
2285
- }
2286
- isVisible(s) {
2287
- if (s.isRef && (!this.scatter.settings.showRef || this.scatter.settings.refSize == 0)) return false;
2288
- return this.scatter.model.getOpacity(s) > 0;
2289
- }
2290
- /** Is `b` inside the hover neighbourhood of `a`? The reach is the two dots' radii added
2291
- * together — "close enough that they would overlap at 100%" — but held constant in SCREEN
2292
- * px, so it does not stretch as you zoom.
2293
- *
2294
- * Plain circle overlap looks zoom-invariant (uniform scaling preserves it) but is not what
2295
- * the eye sees: the dots themselves grow with zoom, so at 11x a pair that merely touches
2296
- * spans ~48 screen px and the tooltip reports dots strewn right across the plot. Dividing
2297
- * the reach by the current scale pins it at ~4px on screen at any zoom, matching the
2298
- * screen-constant neighbourhood the old 5/zoom threshold happened to give. At 1x this is
2299
- * exactly circle overlap; it only bites once zoom would have inflated it.
2300
- *
2301
- * `scale` is screenScale(chart), hoisted by the caller — it is a layout read, and this runs
2302
- * once per sample. */
2303
- isNeighbour(chart, a, b, scale = this.screenScale(chart)) {
2304
- const ca = this.scatter.model.getCoordinates(chart, a);
2305
- const cb = this.scatter.model.getCoordinates(chart, b);
2306
- const reach = (this.dotRadius(chart, a) + this.dotRadius(chart, b)) / scale;
2307
- return Math.hypot(ca.x - cb.x, ca.y - cb.y) <= reach;
2308
- }
2309
- /** Screen px per serie-local px. Reads the composite CTM rather than the zoom state so it
2310
- * stays right no matter which ancestor carries the transform. */
2311
- screenScale(chart) {
2312
- return chart.serie?.node()?.getScreenCTM()?.a || 1;
2313
- }
2314
- /** Serie-local px that a constant SCREEN-px length occupies at the current zoom. */
2315
- fromScreenPx(chart, px) {
2316
- return px / this.screenScale(chart);
2317
- }
2318
- /** How close the cursor must get to a dot's center to pick it, in serie-local px: the
2319
- * radius you can see, plus a forgiveness margin that stays the same size on screen at any
2320
- * zoom. Leaving the margin in serie-local px would inflate it with everything else — at
2321
- * 10x zoom a 3px slop becomes 30 screen px of grab area around every dot. */
2322
- hitRadiusFor(chart, s) {
2323
- return this.dotRadius(chart, s) + this.fromScreenPx(chart, HIT_BUFFER_PX);
2324
- }
2325
- /** Scale factor passed to model.transform() to draw the hover ring. The gap is a constant
2326
- * number of SCREEN px, not a fixed multiple of the dot: a 1.6x ring is snug on a 2px dot
2327
- * but becomes a fat halo once zoom has blown the same dot up to 18px. */
2328
- hoverRingFactor(chart, s) {
2329
- const r = this.dotRadius(chart, s);
2330
- if (!r) return 1;
2331
- return 1 + HOVER_RING_MARGIN_PX / this.screenScale(chart) / r;
2332
- }
2333
- /** Rings are drawn inside chart.serie so they inherit the zoom transform and track their
2334
- * dots. renderSerie() wipes chart.serie, so (re)create the layer lazily. */
2335
- getHoverLayer(chart) {
2336
- let g = chart.serie.select("g.sjpp-scatter-hover");
2337
- if (g.empty()) g = chart.serie.append("g").attr("class", "sjpp-scatter-hover").attr("pointer-events", "none");
2338
- return g;
2339
- }
2340
- /** destroy() rather than detach(): attachTo() builds a fresh DataPointInteractions on every
2341
- * renderSerie, and each one owns a Menu that adds a div to <body> plus a body-level
2342
- * mousedown listener. detach() alone would leave both behind on every render. */
2343
- detach(chartId) {
2344
- if (chartId == void 0) {
2345
- for (const dpi of this.byChart.values()) dpi.destroy();
2346
- this.byChart.clear();
2347
- return;
2348
- }
2349
- this.byChart.get(chartId)?.destroy();
2350
- this.byChart.delete(chartId);
2351
- }
2352
- attachTo(chart) {
2353
- this.detach(chart.id);
2354
- if (this.scatter.config.lassoOn) return;
2355
- if (!chart.cover || !chart.data?.samples?.length) return;
2356
- const model = this.scatter.model;
2357
- const { geom, maxR } = this.buildGeom(chart);
2358
- const dpi = new DataPointInteractions({
2359
- cover: chart.cover,
2360
- hoverLayer: this.getHoverLayer(chart),
2361
- hoverTip: this.view.dom.tooltip,
2362
- points: chart.data.samples,
2363
- toLocalCoords: (event) => pointer_default(event, chart.serie.node()),
2364
- getX: (s) => geom.get(s).x,
2365
- getY: (s) => geom.get(s).y,
2366
- // broad quadtree query; must not under-select before the per-dot filter runs
2367
- hitRadius: () => maxR + this.fromScreenPx(chart, HIT_BUFFER_PX),
2368
- perDotRadius: (s) => geom.get(s).r + this.fromScreenPx(chart, HIT_BUFFER_PX),
2369
- isHidden: (s) => !this.isVisible(s),
2370
- // the cursor picks the nearest dot; the cluster then adds every dot whose rendered
2371
- // circle overlaps that one, so "neighbour" means "visibly on top of each other".
2372
- // sorted nearest-first because the module truncates this list to maxTooltipRows —
2373
- // in chart.data.samples order the dot actually under the cursor could be cut.
2374
- getCluster: (seed, all) => {
2375
- const a = geom.get(seed);
2376
- const scale = this.screenScale(chart);
2377
- return all.filter((s) => {
2378
- if (!this.isVisible(s)) return false;
2379
- const b = geom.get(s);
2380
- return Math.hypot(a.x - b.x, a.y - b.y) <= (a.r + b.r) / scale;
2381
- }).sort((s1, s2) => {
2382
- const b1 = geom.get(s1), b2 = geom.get(s2);
2383
- return Math.hypot(a.x - b1.x, a.y - b1.y) - Math.hypot(a.x - b2.x, a.y - b2.y);
2384
- });
2385
- },
2386
- toHoverSpec: (s) => ({
2387
- path: model.getShape(chart, s),
2388
- transform: model.transform(chart, s, this.hoverRingFactor(chart, s)),
2389
- stroke: "black",
2390
- fill: "none"
2391
- }),
2392
- maxTooltipRows: this.scatter.settings.maxTooltipRows,
2393
- itemNoun: this.scatter.settings.itemLabel.toLowerCase(),
2394
- renderSingleHoverTooltip: (s, container) => this.renderSampleRows(s, chart, container),
2395
- buildMultiHitTableData: (dots) => this.buildTableData(dots),
2396
- getActions: (s) => this.getActions(s),
2397
- renderSingleHitInfo: (s, container) => this.renderSampleRows(s, chart, container),
2398
- getRowKey: (s) => s.sample || s.cellId || String(s.sampleId ?? `${s.x},${s.y}`)
2399
- });
2400
- dpi.attach();
2401
- chart.cover.on("click.sjpp-scatter-searchmenu", () => this.scatter.interactivity.searchMenu?.hide());
2402
- this.byChart.set(chart.id, dpi);
2403
- }
2404
- getTW(category) {
2405
- switch (category) {
2406
- case "category":
2407
- return this.scatter.config.colorTW;
2408
- case "shape":
2409
- return this.scatter.config.shapeTW;
2410
- case "scale":
2411
- return this.scatter.config.scaleDotTW;
2412
- case "x":
2413
- return this.scatter.config.term;
2414
- case "y":
2415
- return this.scatter.config.term2;
2416
- default:
2417
- return null;
2418
- }
2419
- }
2420
- /** Two-column detail view of one sample, shared by the hover tooltip and the click
2421
- * action menu. */
2422
- renderSampleRows(sample, chart, container) {
2423
- const config = this.scatter.config;
2424
- const table = table2col({
2425
- holder: container.append("div"),
2426
- disableScroll: true,
2427
- cellPadding: "5px",
2428
- testid: "sjpp-single-hit-table"
2429
- });
2430
- if (config.term) {
2431
- table.addRow(config.term.term.name, this.getCategoryValue("x", sample, config.term));
2432
- if (config.term2) table.addRow(config.term2.term.name, this.getCategoryValue("y", sample, config.term2));
2433
- }
2434
- if (sample.category != "Ref") {
2435
- if (config.colorTW) this.addTermRow(table, "category", sample, chart);
2436
- if (config.shapeTW) this.addTermRow(table, "shape", sample, chart);
2437
- if (config.scaleDotTW)
2438
- table.addRow(config.scaleDotTW.term.name, this.getCategoryValue("scale", sample, config.scaleDotTW));
2439
- }
2440
- if ("info" in sample) for (const [k, v] of Object.entries(sample.info)) table.addRow(k, v);
2441
- const name = sample.sample || sample.cellId || sample.sampleId;
2442
- if (name != null && name !== "") table.addRow(this.scatter.settings.itemLabel, name);
2443
- }
2444
- /** A color/shape term row, drawn with the dot's own glyph so the tooltip matches the plot. */
2445
- addTermRow(table, category, sample, chart) {
2446
- const tw = this.getTW(category);
2447
- const [tdlabel, td] = table.addRow();
2448
- tdlabel.text(tw.term.name);
2449
- const isColor = category == "category";
2450
- const color = isColor ? this.scatter.model.getColor(sample, chart) : this.scatter.config.colorTW ? "gray" : this.scatter.settings.defaultColor;
2451
- const shapeKey = isColor ? "Ref" : sample.shape;
2452
- const shape = shapesArray[chart.shapeLegend.get(shapeKey).shape % shapesArray.length];
2453
- let value = this.getCategoryValue(category, sample, tw);
2454
- let fontColor = "black";
2455
- if (tw?.term.type == "geneVariant" && tw.q.type == "values") {
2456
- const whiteColor = rgb("white").toString();
2457
- for (const id in mclass) {
2458
- const class_info = mclass[id];
2459
- if (!value.toString().includes(class_info.label)) continue;
2460
- if (rgb(class_info.color).toString() != whiteColor) fontColor = class_info.color;
2461
- value = this.getCategoryValue(category, sample, tw, true);
2462
- break;
2463
- }
2464
- }
2465
- const svg = td.append("svg").attr("width", value.toString().length * 9 + 60).attr("height", "25px");
2466
- const g = svg.append("g").attr("transform", "translate(0, 14)");
2467
- g.append("path").attr("d", shape).attr("fill", color).attr("stroke", "#aaa").attr("transform", "translate(0, -4) scale(0.6)");
2468
- g.append("text").attr("x", 15).attr("y", 6).attr("font-size", "0.9em").append("tspan").text(value).attr("fill", fontColor);
2469
- }
2470
- /** Flat table for the multi-hit hover tooltip and click menu. */
2471
- buildTableData(dots) {
2472
- return buildSampleTableData(this.scatter.config, this.scatter.settings.itemLabel, dots);
2473
- }
2474
- getActions(sample) {
2475
- const config = this.scatter.config;
2476
- const interactivity = this.scatter.interactivity;
2477
- const actions = [];
2478
- if (sample.isRef || sample.sampleId == null || config.singleCellPlot) return actions;
2479
- const geneTW = [config.colorTW, config.shapeTW].find((tw) => tw?.term.type == "geneVariant");
2480
- if (geneTW) actions.push({ label: "Lollipop", onClick: () => interactivity.openLollipop(geneTW.term.name) });
2481
- const queries = this.scatter.state.termdbConfig.queries;
2482
- if (this.scatter.state.currentCohortChartTypes.includes("sampleView"))
2483
- actions.push({ label: "Sample view", onClick: () => interactivity.openSampleView(sample) });
2484
- if (queries?.singleSampleMutation)
2485
- actions.push({ label: "Disco", onClick: () => interactivity.openDiscoPlot(sample) });
2486
- if (queries?.singleSampleGenomeQuantification)
2487
- actions.push({ label: "Met Array", onClick: () => interactivity.openMetArray(sample) });
2488
- return actions;
2489
- }
2490
- getCategoryValue(category, d, tw, includeMutation = false) {
2491
- return getCategoryValue(category, d, tw, includeMutation);
2492
- }
2493
- };
2494
-
2495
- // plots/scatter/viewmodel/scatterZoom.ts
2496
- var ScatterZoom = class {
2497
- constructor(scatter) {
2498
- this.zoom = 1;
2499
- this.scatter = scatter;
2500
- this.zoomD3 = zoom_default().scaleExtent([0.1, 10]).on("zoom", (event) => this.handleZoom(event.transform)).filter((event) => {
2501
- if (event.type === "wheel") return event.ctrlKey;
2502
- return true;
2503
- }).on("end", async (event) => {
2504
- this.scatter.transform = event.transform;
2505
- this.scatter.zoom = event.transform.k;
2506
- if (this.scatter.settings.saveZoomTransform) this.saveZoomTransform();
2507
- });
2508
- }
2509
- async saveZoomTransform() {
2510
- const transform = this.scatter.transform?.toString() || null;
2511
- this.scatter.app.dispatch({ type: "plot_edit", id: this.scatter.id, config: { transform } });
2512
- }
2513
- initZoom(toolsDiv) {
2514
- this.zoomD3.scaleExtent([0.1, this.scatter.config.scaleDotTW ? 4 : 10]);
2515
- toolsDiv.selectAll("*").remove();
2516
- const display = "block";
2517
- const resetDiv = toolsDiv.insert("div").style("display", display).style("margin", "15px 10px").attr("name", "sjpp-reset-btn");
2518
- icons["restart"](resetDiv, { handler: () => this.resetToIdentity(), title: "Reset to original zoom" });
2519
- const zoomInDiv = toolsDiv.insert("div").style("display", display).style("margin", "15px 10px").attr("name", "sjpp-zoom-in-btn");
2520
- icons["zoomIn"](zoomInDiv, {
2521
- handler: () => this.zoomIn(),
2522
- title: "Zoom in. You can also zoom in pressing the Ctrl key and using the mouse wheel"
2523
- });
2524
- const zoomOutDiv = toolsDiv.insert("div").style("display", display).style("margin", "15px 10px").attr("name", "sjpp-zoom-out-btn");
2525
- icons["zoomOut"](zoomOutDiv, {
2526
- handler: () => this.zoomOut(),
2527
- title: "Zoom out. You can also zoom out pressing the Ctrl key and using the mouse wheel"
2528
- });
2529
- for (const chart of this.scatter.model.charts) {
2530
- chart.mainG.call(this.zoomD3);
2531
- }
2532
- if (this.scatter.config.scaleDotTW && this.zoom > 4) this.resetToIdentity();
2533
- }
2534
- handleZoom(transform) {
2535
- this.zoom = transform.scale(1).k;
2536
- for (const chart of this.scatter.model.charts) {
2537
- const new_xScale = transform.rescaleX(chart.xAxisScale);
2538
- const new_yScale = transform.rescaleY(chart.yAxisScale);
2539
- chart.serie.attr("transform", transform);
2540
- chart.regressionG?.attr("transform", transform);
2541
- chart.xAxis.call(chart.axisBottom.scale(new_xScale));
2542
- chart.yAxis.call(chart.axisLeft.scale(new_yScale));
2543
- if (this.scatter.config.lassoOn)
2544
- chart.lasso.selectedItems().attr("transform", (c) => this.scatter.model.transform(chart, c, 1.2));
2545
- if (this.scatter.config.scaleDotTW) this.scatter.vm.legendvm.drawScaleDotLegend(chart);
2546
- }
2547
- }
2548
- zoomIn() {
2549
- this.zoom = this.zoom * 1.2;
2550
- if (!this.scatter.model.is2DLarge)
2551
- for (const chart of this.scatter.model.charts) this.zoomD3.scaleBy(chart.mainG.transition().duration(500), 1.2);
2552
- }
2553
- zoomOut() {
2554
- this.zoom = this.zoom * 0.8;
2555
- if (!this.scatter.model.is2DLarge)
2556
- for (const chart of this.scatter.model.charts) this.zoomD3.scaleBy(chart.mainG.transition().duration(500), 0.8);
2557
- }
2558
- resetToIdentity() {
2559
- this.zoom = 1;
2560
- if (!this.scatter.model.is2DLarge)
2561
- for (const chart of this.scatter.model.charts)
2562
- chart.mainG.transition().duration(500).call(this.zoomD3.transform, identity);
2563
- }
2564
- };
2565
-
2566
- // plots/scatter/viewmodel/scatterViewModelBase.ts
2567
- var ScatterViewModelBase = class {
2568
- constructor(scatter) {
2569
- this.scatter = scatter;
2570
- this.view = scatter.view;
2571
- this.model = scatter.model;
2572
- this.interactivity = scatter.interactivity;
2573
- this.legendvm = new ScatterLegend(scatter);
2574
- this.scatterTooltip = new ScatterTooltip(scatter);
2575
- this.scatterZoom = new ScatterZoom(scatter);
2576
- }
2577
- render() {
2578
- const chartDivs = this.view.dom.mainDiv.selectAll(":scope > div").data(this.model.charts, (chart) => chart?.id);
2579
- chartDivs.exit().remove();
2580
- chartDivs.each((chart, i, divs) => {
2581
- const div = select_default(divs[i]);
2582
- this.renderChart(chart, div);
2583
- });
2584
- chartDivs.enter().append("div").style("vertical-align", "top").each((chart, i, divs) => {
2585
- const div = select_default(divs[i]);
2586
- this.renderChart(chart, div);
2587
- });
2588
- if (!this.model.charts?.length) {
2589
- this.view.dom.bannerDiv.html(`<span>No visible scatter plot data to render</span>`).style("display", "block");
2590
- return;
2591
- } else {
2592
- this.view.dom.bannerDiv.style("display", "none");
2593
- }
2594
- }
2595
- renderChart(chart, div, removePrevious = true) {
2596
- const s = this.scatter.settings;
2597
- div.style("opacity", 0).style("display", "inline-block").attr("data-testid", `sjpp-scatter-chart-div-${chart?.id ?? "Default"}`);
2598
- chart.svg = div.select("svg").empty() ? div.append("svg") : div.select("svg");
2599
- this.renderSVG(chart, s, removePrevious);
2600
- div.transition().duration(s.duration).style("opacity", 1);
2601
- chart.chartDiv = div;
2602
- }
2603
- async renderSVG(chart, s, removePrevious) {
2604
- const svg = chart.svg;
2605
- let step = Math.min(20 * 40 / chart.colorLegend.size, 25);
2606
- if (step < 18) step = 18;
2607
- this.step = step;
2608
- let colorLegendSize = chart.colorLegend.size * step;
2609
- if (chart.colorLegend.get("Ref")?.sampleCount > 0) colorLegendSize += 60;
2610
- const scaleHeight = this.scatter.config.scaleDotTW ? 200 : 100;
2611
- this.legendHeight = Math.max(colorLegendSize, chart.shapeLegend.size * 25) + scaleHeight;
2612
- let fontSize = this.legendvm.getFontSize(chart, chart.colorLegend);
2613
- const labels = [];
2614
- if (this.scatter.config.colorTW) labels.push(getTitle(this.scatter.config.colorTW.term.name, 40) + " COLOR");
2615
- else if (this.scatter.config.colorColumn && this.scatter.config.bySample)
2616
- labels.push(getTitle(this.scatter.config.colorColumn.name, 40) + " COLOR");
2617
- if (this.scatter.config.scaleDotTW) labels.push(getTitle(this.scatter.config.scaleDotTW.term.name, 40) + " SHAPE");
2618
- if (labels.length > 0) {
2619
- const labelsWidth = getMaxLabelWidth(svg, labels) + 40;
2620
- chart.colorLegendWidth = this.scatter.config?.colorTW?.q.mode == "continuous" ? Math.max(175, labelsWidth) : Math.max(this.legendvm.getLegendLabelWidth(chart, "color", svg, `${fontSize}em`), labelsWidth);
2621
- } else chart.colorLegendWidth = 0;
2622
- fontSize = this.legendvm.getFontSize(chart, chart.shapeLegend);
2623
- const shapeWidth = this.legendvm.getLegendLabelWidth(chart, "shape", svg, `${fontSize}em`);
2624
- const width = s.svgw + chart.colorLegendWidth + shapeWidth + 125;
2625
- svg.attr("width", width).attr("height", Math.max(s.svgh + 200, this.legendHeight)).transition().duration(s.duration);
2626
- this.fillSvgSubElems(chart);
2627
- await this.renderSerie(chart, removePrevious);
2628
- this.legendvm.renderLegend(chart, step);
2629
- }
2630
- fillSvgSubElems(chart) {
2631
- const svg = chart.svg;
2632
- let axisG, labelsG;
2633
- if (svg.select(".sjpcb-scatter-mainG").size() == 0) {
2634
- chart.G = svg.append("g").attr("class", "sjpcb-scatter-G");
2635
- chart.mainG = chart.G.append("g").attr("class", "sjpcb-scatter-mainG");
2636
- axisG = svg.append("g").attr("class", "sjpcb-scatter-axis");
2637
- labelsG = svg.append("g").attr("class", "sjpcb-scatter-labelsG");
2638
- chart.xAxis = axisG.append("g").attr("class", "sjpcb-scatter-x-axis");
2639
- chart.yAxis = axisG.append("g").attr("class", "sjpcb-scatter-y-axis").attr("transform", `translate(${this.model.axisOffset.x}, 0)`);
2640
- chart.mainG.append("rect").attr("class", "zoom").attr("x", this.model.axisOffset.x).attr("y", this.model.axisOffset.y).attr("width", this.scatter.settings.svgw).attr("height", this.scatter.settings.svgh).attr("fill", "white");
2641
- const id = "clip" + this.scatter.id;
2642
- chart.clipRect = chart.svg.append("defs").append("clipPath").attr("id", id).append("rect").attr("x", this.model.axisOffset.x).attr("y", this.model.axisOffset.y).attr("width", this.scatter.settings.svgw + 10).attr("height", this.scatter.settings.svgh);
2643
- chart.serie = chart.mainG.append("g").attr("class", "sjpcb-scatter-series");
2644
- chart.regressionG = chart.mainG.append("g").attr("class", "sjpcb-scatter-lowess");
2645
- chart.cover = chart.mainG.append("rect").attr("class", "sjpp-scatter-cover").attr("x", this.model.axisOffset.x).attr("y", this.model.axisOffset.y).attr("width", this.scatter.settings.svgw).attr("height", this.scatter.settings.svgh).attr("fill", "none").style("pointer-events", "all");
2646
- chart.legendG = svg.append("g").attr("class", "sjpcb-scatter-legend");
2647
- if (this.scatter.state.config.transform && chart.mainG.attr("transform") != this.scatter.state.config.transform) {
2648
- chart.mainG.attr("transform", this.scatter.state.config.transform);
2649
- }
2650
- chart.G.attr("clip-path", `url(#${id})`);
2651
- } else {
2652
- chart.G = svg.select(".sjpcb-scatter-G");
2653
- chart.mainG = svg.select(".sjpcb-scatter-mainG");
2654
- chart.serie = chart.mainG.select(".sjpcb-scatter-series");
2655
- chart.regressionG = chart.mainG.select(".sjpcb-scatter-lowess");
2656
- chart.cover = chart.mainG.select(".sjpp-scatter-cover");
2657
- axisG = svg.select(".sjpcb-scatter-axis");
2658
- labelsG = svg.select(".sjpcb-scatter-labelsG");
2659
- chart.xAxis = axisG.select(".sjpcb-scatter-x-axis");
2660
- chart.yAxis = axisG.select(".sjpcb-scatter-y-axis");
2661
- chart.legendG = svg.select(".sjpcb-scatter-legend");
2662
- chart.clipRect = svg.select("defs").select("clipPath").select("rect");
2663
- }
2664
- chart.axisG = axisG;
2665
- chart.labelsG = labelsG;
2666
- chart.cover.attr("width", this.scatter.settings.svgw).attr("height", this.scatter.settings.svgh);
2667
- chart.xAxis.attr("transform", `translate(0, ${this.scatter.settings.svgh + this.model.axisOffset.y})`);
2668
- chart.legendG.attr("transform", `translate(${this.scatter.settings.svgw + this.model.axisOffset.x + 50}, 20)`);
2669
- if (chart.axisBottom) {
2670
- chart.xAxis.call(chart.axisBottom);
2671
- chart.yAxis.call(chart.axisLeft);
2672
- }
2673
- if (this.scatter.config.term) {
2674
- let termName = getTitle(this.scatter.config.term.term.name, 60);
2675
- if (!this.scatter.config.colorTW && !this.scatter.config.shapeTW && !this.scatter.config.term0)
2676
- termName = `${termName}, n=${chart.cohortSamples.length || chart.totalSampleCount}`;
2677
- labelsG.selectAll("*").remove();
2678
- let text = labelsG.append("text").attr(
2679
- "transform",
2680
- `translate(${this.model.axisOffset.x + this.scatter.settings.svgw / 2}, ${this.scatter.settings.svgh + this.model.axisOffset.y + 40})`
2681
- ).attr("text-anchor", "middle").text(termName).style("font-size", "0.9em");
2682
- if (termName.length > 65) {
2683
- text.on("mouseenter", (event) => {
2684
- this.scatter.interactivity.showText(event, this.scatter.config.term.term.name);
2685
- }).on("mouseleave", () => this.view.dom.tooltip.hide());
2686
- }
2687
- if (this.scatter.config.term0 && !this.scatter.config.colorTW && !this.scatter.config.shapeTW) {
2688
- const term0Name = `${chart.id}, n=${chart.cohortSamples.length}`;
2689
- labelsG.append("text").attr(
2690
- "transform",
2691
- `translate(${this.model.axisOffset.x + this.scatter.settings.svgw / 2}, ${this.scatter.settings.svgh + this.model.axisOffset.y + 65})`
2692
- ).attr("text-anchor", "middle").text(term0Name);
2693
- }
2694
- if (this.scatter.config.term2) {
2695
- const t2name = this.scatter.config.term2.term.name;
2696
- const term2Name = getTitle(t2name, 60);
2697
- text = labelsG.append("text").attr(
2698
- "transform",
2699
- `translate(${this.model.axisOffset.x - 50}, ${this.scatter.settings.svgh / 2 + this.model.axisOffset.y}) rotate(-90)`
2700
- ).attr("text-anchor", "middle").text(term2Name).style("font-size", "0.9em");
2701
- if (term2Name.length > 60) {
2702
- text.on("mouseenter", (event) => {
2703
- this.scatter.interactivity.showText(event, this.scatter.config.term2.term.name);
2704
- }).on("mouseleave", () => this.view.dom.tooltip.hide());
2705
- }
2706
- }
2707
- }
2708
- }
2709
- renderSerie(chart, removePrevious) {
2710
- const duration = this.scatter.settings.duration;
2711
- if (this.canvas) this.canvas.remove();
2712
- const g = chart.serie;
2713
- const data = chart.data;
2714
- if (removePrevious) chart.serie.selectAll("*").remove();
2715
- const labelPointTestId = (c) => "sjpp-scatter-dot-" + (c.sample ?? c.sampleId ?? "");
2716
- const symbols = g.selectAll('path[name="serie"]').data(data.samples);
2717
- symbols.transition().duration(duration).attr("name", "serie").attr("data-testid", labelPointTestId).attr("transform", (c) => this.model.transform(chart, c)).attr("d", (c) => this.model.getShape(chart, c)).attr("fill", (c) => this.model.getColor(c, chart)).attr("stroke", (c) => this.model.getColor(c, chart)).attr("stroke-width", (c) => this.model.getStrokeWidth(c)).style("fill-opacity", (c) => this.model.getOpacity(c));
2718
- symbols.enter().append("path").attr("name", "serie").attr("data-testid", labelPointTestId).attr("transform", (c) => this.model.transform(chart, c)).attr("d", (c) => this.model.getShape(chart, c)).attr("fill", (c) => this.model.getColor(c, chart)).attr("stroke", (c) => this.model.getColor(c, chart)).attr("stroke-width", (c) => this.model.getStrokeWidth(c)).style("fill-opacity", (c) => this.model.getOpacity(c)).transition().duration(duration);
2719
- this.mayRenderSampleLabels(chart);
2720
- this.mayRenderRegression();
2721
- }
2722
- /** Draw the sample name as a text label next to each cohort (db) sample dot. Used by per-sample
2723
- * (bySample) scatterplots, where a single highlighted dot sits among a reference cloud. */
2724
- mayRenderSampleLabels(chart) {
2725
- const g = chart.serie;
2726
- const labelData = this.scatter.config.bySample && chart.data?.samples ? chart.data.samples.filter((c) => !c.isRef && c.sample) : [];
2727
- const labels = g.selectAll('text[name="sampleLabel"]').data(labelData, (c) => c.sample);
2728
- labels.exit().remove();
2729
- labels.enter().append("text").attr("name", "sampleLabel").attr("pointer-events", "none").attr("font-size", "12px").attr("font-weight", "bold").attr("paint-order", "stroke").attr("stroke", "white").attr("stroke-width", "3px").attr("fill", "black").merge(labels).attr("x", (c) => this.model.getCoordinates(chart, c).x + 8).attr("y", (c) => this.model.getCoordinates(chart, c).y + 4).text((c) => c.sample);
2730
- }
2731
- async mayRenderRegression() {
2732
- for (const chart of this.model.charts) {
2733
- chart.regressionG?.selectAll("*").remove();
2734
- if (chart.regressionCurve) {
2735
- const l = line_default().x((d) => d[0]).y((d) => d[1]);
2736
- const regressionPath = chart.regressionG.append("path");
2737
- regressionPath.attr("d", l(chart.regressionCurve)).attr("stroke", "blue").attr("fill", "none").style("stroke-width", "2");
2738
- }
2739
- }
2740
- }
2741
- async addGroup(group) {
2742
- this.model.addGroup(group);
2743
- this.view.dom.tip.hide();
2744
- }
2745
- setTools() {
2746
- if (!this.model.charts[0]) return;
2747
- const toolsDiv = this.view.dom.toolsDiv.style("background-color", "white");
2748
- toolsDiv.selectAll("*").remove();
2749
- if (!(this.model.is2DLarge && this.scatter.config.singleCellPlot)) this.scatterZoom.initZoom(toolsDiv);
2750
- }
2751
- /** Applies to the ViewModel only
2752
- * Note: legendvm.renderLegend called in this file applies to all
2753
- * inherited classes. The g dimensions are different
2754
- * between the svg rendered scatter and the 2D Large/3D scatter.
2755
- * Hence the similar function in scatterViewModel. */
2756
- addLegendSVG(chart) {
2757
- chart.chartDiv.style("margin", "20px 20px");
2758
- chart.legendDiv = this.view.dom.mainDiv.insert("div").style("display", "inline-block").style("vertical-align", "top");
2759
- chart.legendG = chart.legendDiv.append("svg").attr("width", this.scatter.settings.svgw / 2).attr("height", this.scatter.settings.svgh).append("g").attr("transform", "translate(20, 20)");
2760
- }
2761
- };
2762
-
2763
- // plots/scatter/viewmodel/scatterViewModel.ts
2764
- var ScatterViewModel = class extends ScatterViewModelBase {
2765
- constructor(scatter) {
2766
- super(scatter);
2767
- this.scatterLasso = new ScatterLasso(scatter);
2768
- }
2769
- fillSvgSubElems(chart) {
2770
- super.fillSvgSubElems(chart);
2771
- chart.axisG.style("opacity", this.scatter.settings.showAxes ? 1 : 0);
2772
- chart.labelsG.style("opacity", this.scatter.settings.showAxes ? 1 : 0);
2773
- }
2774
- renderSerie(chart, removePrevious) {
2775
- super.renderSerie(chart, removePrevious);
2776
- if (this.scatter.settings.showContour) this.renderContours(chart);
2777
- this.scatterTooltip.attachTo(chart);
2778
- }
2779
- renderContours(chart) {
2780
- const contourG = chart.serie;
2781
- let zAxisScale;
2782
- if (this.scatter.config.colorTW?.q.mode == "continuous") {
2783
- const [zMin, zMax] = extent(chart.data.samples, (d) => d.category);
2784
- zAxisScale = linear().domain([zMin, zMax]).range([0, 1]);
2785
- }
2786
- const data = chart.data.samples.filter((s) => this.model.getOpacity(s) > 0).map((s) => {
2787
- return { x: chart.xAxisScale(s.x), y: chart.yAxisScale(s.y), z: zAxisScale ? zAxisScale(s.category) : 1 };
2788
- });
2789
- renderContours(
2790
- contourG,
2791
- data,
2792
- this.scatter.settings.svgw,
2793
- this.scatter.settings.svgh,
2794
- this.scatter.settings.colorContours,
2795
- this.scatter.settings.contourBandwidth,
2796
- this.scatter.settings.contourThresholds
2797
- );
2798
- }
2799
- async mayRenderRegression() {
2800
- for (const chart of this.model.charts) {
2801
- chart.regressionG?.selectAll("*").remove();
2802
- if (chart.regressionCurve) {
2803
- const l = line_default().x((d) => d[0]).y((d) => d[1]);
2804
- const regressionPath = chart.regressionG.append("path");
2805
- regressionPath.attr("d", l(chart.regressionCurve)).attr("stroke", "blue").attr("fill", "none").style("stroke-width", "2");
2806
- }
2807
- }
2808
- }
2809
- async toggleLasso() {
2810
- this.scatter.config.lassoOn = !this.scatter.config.lassoOn;
2811
- this.scatter.app.dispatch({ type: "plot_edit", id: this.scatter.id, config: this.scatter.config });
2812
- }
2813
- async addGroup(group) {
2814
- this.model.addGroup(group);
2815
- this.view.dom.tip.hide();
2816
- }
2817
- setTools() {
2818
- super.setTools();
2819
- if (this.scatter.config.singleCellPlot || this.scatter.config.bySample) return;
2820
- const toolsDiv = this.view.dom.toolsDiv;
2821
- const display = "block";
2822
- const searchDiv = toolsDiv.insert("div").style("display", display).style("margin", "15px 10px");
2823
- this.view.dom.lassoDiv = toolsDiv.insert("div").style("display", display).style("margin", "15px 10px");
2824
- icons["search"](searchDiv, { handler: (e) => this.interactivity.searchSample(e), title: "Search samples" });
2825
- icons["lasso"](this.view.dom.lassoDiv, {
2826
- handler: () => this.toggleLasso(),
2827
- enabled: this.scatter.config.lassoOn,
2828
- title: "Select a group of samples"
2829
- });
2830
- this.view.dom.groupDiv = toolsDiv.insert("div").style("display", display).style("margin", "15px 10px");
2831
- for (const chart of this.model.charts) {
2832
- if (!chart.lasso) chart.lasso = d3lasso();
2833
- this.scatterLasso.lassoReset(chart);
2834
- }
2835
- }
2836
- /** Applies to 2D large and 3D add an svg for the legend
2837
- * Note: legendvm.renderLegend called in ViewModeBase applies to all
2838
- * inherited classes. The g dimensions are different
2839
- * between the svg rendered scatter and the 2D Large/3D scatter.
2840
- * Hence the similar function in scatterViewModelBase.*/
2841
- addLegendSVG(chart) {
2842
- chart.chartDiv.style("margin", "20px 20px");
2843
- chart.legendDiv = this.view.dom.mainDiv.insert("div").style("display", "inline-block").style("vertical-align", "top");
2844
- chart.legendG = chart.legendDiv.append("svg").attr("width", this.scatter.settings.svgw / 2).attr("height", this.scatter.vm.legendHeight).append("g").attr("transform", "translate(20, 20)");
2845
- }
2846
- };
2847
- function renderContours(contourG, data, width, height, colorContours, bandwidth, thresholds) {
2848
- const contours = density_default().x((s) => s.x).y((s) => s.y).weight((s) => s.z).size([width, height]).cellSize(2).bandwidth(bandwidth).thresholds(thresholds)(data);
2849
- const colorScale = sequential().domain([0, max(contours, (d) => d.value)]).interpolator(Greys_default);
2850
- contourG.attr("fill", "none").attr("stroke", "gray").attr("stroke-linejoin", "round").selectAll().data(contours).join("path").attr("stroke-width", (d, i) => i % 5 ? 0.25 : 1).attr("d", path_default()).attr("fill", colorContours ? (d) => colorScale(d.value) : "none").attr("fill-opacity", 0.05);
2851
- }
2852
-
2853
- // plots/scatter/viewmodel/scatterViewModel2DLarge.ts
2854
- var ScatterViewModel2DLarge = class extends ScatterViewModel {
2855
- constructor(scatter) {
2856
- super(scatter);
2857
- this.isSingleCell = false;
2858
- this.isSingleCell = scatter.config?.singleCellPlot;
2859
- }
2860
- async renderSerie(chart) {
2861
- if (this.isSingleCell && chart.src) {
2862
- this.renderLargeSingleCell(chart);
2863
- return;
2864
- }
2865
- const s = this.scatter.settings;
2866
- const offsetX = this.model.axisOffset.x;
2867
- const offsetY = this.model.axisOffset.y;
2868
- const div = select_default(chart.svg.node().parentNode);
2869
- div.style("position", "relative");
2870
- div.selectAll("canvas").remove();
2871
- chart.serie?.selectAll("*").remove();
2872
- chart.regressionG?.selectAll("*").remove();
2873
- this.canvas = div.append("canvas").style("position", "absolute").style("left", `${offsetX}px`).style("top", `${offsetY}px`).node();
2874
- this.canvas.width = s.svgw;
2875
- this.canvas.height = s.svgh;
2876
- const fov = s.threeFOV;
2877
- const near = 0.1;
2878
- const far = 1e3;
2879
- const camera = new PerspectiveCamera(fov, 1, near, far);
2880
- const scene = new Scene();
2881
- camera.position.set(0, 0, 1 / Math.tan(fov * Math.PI / 180 / 2));
2882
- camera.lookAt(scene.position);
2883
- camera.updateMatrix();
2884
- const geometry = new BufferGeometry();
2885
- const { vertices, colors } = this.getVertices(chart);
2886
- geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3));
2887
- geometry.setAttribute("color", new Float32BufferAttribute(colors, 3));
2888
- const tex = getThreeCircle(128);
2889
- const material = new PointsMaterial({
2890
- size: this.scatter.settings.threeSize,
2891
- sizeAttenuation: true,
2892
- transparent: true,
2893
- opacity: this.scatter.settings.opacity,
2894
- map: tex,
2895
- vertexColors: true
2896
- });
2897
- const particles = new Points(geometry, material);
2898
- scene.add(particles);
2899
- const renderer = new WebGLRenderer({
2900
- antialias: true,
2901
- canvas: this.canvas,
2902
- preserveDrawingBuffer: true,
2903
- alpha: true
2904
- });
2905
- renderer.setClearColor(0, 0);
2906
- renderer.setSize(this.scatter.settings.svgw, this.scatter.settings.svgh);
2907
- renderer.setPixelRatio(window.devicePixelRatio);
2908
- this.canvas.addEventListener("wheel", (event) => {
2909
- if (!event.ctrlKey) return;
2910
- event.preventDefault();
2911
- const zoomState = this.scatter.vm.scatterZoom;
2912
- const factor = event.deltaY < 0 ? 1.1 : 0.9;
2913
- zoomState.zoom = Math.max(0.1, Math.min(10, zoomState.zoom * factor));
2914
- });
2915
- this.renderAxes(chart);
2916
- this.animate(chart, camera, scene, renderer);
2917
- }
2918
- /** Redraw the given chart's x/y axes to match the current WebGL zoom. camera.zoom scales the point
2919
- * cloud by k about the plot center, so express that as a d3 zoom transform and rescale the axes the
2920
- * way ScatterZoom.handleZoom() does for the small plots. Rescaling keeps each axis RANGE pinned to
2921
- * the plot edges (only the visible data window is relabeled), so the two axes stay joined at the
2922
- * corner and neither the ticks nor the spine spill past the canvas when zoomed in. Ticks that fall
2923
- * outside the data range (e.g. when zoomed out past the data) are dropped.
2924
- *
2925
- * The zoom is tracked per chart (chart.currentAxisZoom), not on the view model, because a
2926
- * categorical term0 renders multiple charts — each with its own canvas and animation loop — that
2927
- * all share one zoom level; per-chart tracking keeps every chart's axes in sync, not just the last. */
2928
- renderAxes(chart) {
2929
- if (!chart?.axisBottom || !chart?.axisLeft || !chart.xAxis || !chart.yAxis) return;
2930
- const s = this.scatter.settings;
2931
- const k = this.scatter.vm.scatterZoom.zoom || 1;
2932
- const offsetX = this.model.axisOffset.x;
2933
- const offsetY = this.model.axisOffset.y;
2934
- const cx = offsetX + s.svgw / 2;
2935
- const cy = offsetY + s.svgh / 2;
2936
- const transform = identity.translate(cx * (1 - k), cy * (1 - k)).scale(k);
2937
- const xBase = chart.xAxisScaleTime || chart.xAxisScale;
2938
- const yBase = chart.yAxisScaleTime || chart.yAxisScale;
2939
- const xScale = transform.rescaleX(xBase);
2940
- const yScale = transform.rescaleY(yBase);
2941
- chart.xAxis.call(chart.axisBottom.scale(xScale).tickValues(this.ticksWithinData(xScale, xBase)));
2942
- chart.yAxis.call(chart.axisLeft.scale(yScale).tickValues(this.ticksWithinData(yScale, yBase)));
2943
- chart.currentAxisZoom = k;
2944
- }
2945
- /** Ticks of the zoomed scale that still fall within the base (data) domain, so zooming out past
2946
- * the data does not render tick marks for values below the minimum or above the maximum. */
2947
- ticksWithinData(zoomedScale, baseScale) {
2948
- const [d0, d1] = baseScale.domain();
2949
- const lo = Math.min(d0, d1);
2950
- const hi = Math.max(d0, d1);
2951
- return zoomedScale.ticks().filter((t) => t >= lo && t <= hi);
2952
- }
2953
- animate(chart, camera, scene, renderer) {
2954
- if (this.scatter.vm !== this) {
2955
- renderer.domElement.remove();
2956
- renderer.dispose();
2957
- return;
2958
- }
2959
- requestAnimationFrame(() => this.animate(chart, camera, scene, renderer));
2960
- const k = this.scatter.vm.scatterZoom.zoom;
2961
- camera.zoom = k;
2962
- camera.updateProjectionMatrix();
2963
- if (k !== chart.currentAxisZoom) this.renderAxes(chart);
2964
- renderer.render(scene, camera);
2965
- }
2966
- getVertices(chart) {
2967
- const xAxisScale = chart.xAxisScale.copy().range([-1, 1]);
2968
- const yAxisScale = chart.yAxisScale.copy().range([1, -1]);
2969
- const vertices = [];
2970
- const colors = [];
2971
- for (const sample of chart.data.samples) {
2972
- const opacity = this.model.getOpacity(sample);
2973
- if (opacity == 0) continue;
2974
- const x = xAxisScale(sample.x);
2975
- const y = yAxisScale(sample.y);
2976
- const z = 0;
2977
- vertices.push(x, y, z);
2978
- const color = new Color(rgb(this.model.getColor(sample, chart)).toString());
2979
- colors.push(color.r, color.g, color.b);
2980
- }
2981
- return { vertices, colors };
2982
- }
2983
- /** Renders the server generated image for a single cell */
2984
- renderLargeSingleCell(chart) {
2985
- chart.svg.selectAll(".sjpp-scatter-img-g").remove();
2986
- const imgG = chart.svg.append("g").attr("class", "sjpp-scatter-img-g");
2987
- const img = imgG.append("image").attr("xlink:href", chart.src);
2988
- if (chart.canvasWidth) img.attr("width", chart.canvasWidth);
2989
- if (chart.canvasHeight) img.attr("height", chart.canvasHeight);
2990
- this.canvas = img;
2991
- }
2992
- };
2993
- function getThreeCircle(size) {
2994
- const c = document.createElement("canvas");
2995
- c.width = size;
2996
- c.height = size;
2997
- const ctx = c.getContext("2d");
2998
- ctx.clearRect(0, 0, size, size);
2999
- ctx.fillStyle = "white";
3000
- ctx.beginPath();
3001
- ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI);
3002
- ctx.fill();
3003
- const tex = new CanvasTexture(c);
3004
- return tex;
3005
- }
3006
-
3007
- // plots/singleCellPlot.js
3008
- var SAMPLES_TAB = 1;
3009
- var PLOTS_TAB = 2;
3010
- var DIFFERENTIAL_EXPRESSION_TAB = 3;
3011
- var GENE_EXPRESSION_TAB = 4;
3012
- var IMAGES_TAB = 5;
3013
- var VIOLIN_TAB = 6;
3014
- var noExpColor = "#F5F5F5";
3015
- var DE_GENES_TAB = 8;
3016
- var DE_GSEA_TAB = 7;
3017
- var singleCellPlot = class _singleCellPlot {
3018
- static type = "singleCellPlot";
3019
- constructor() {
3020
- this.type = _singleCellPlot.type;
3021
- this.tip = new Menu({ padding: "4px", offsetX: 10, offsetY: 0 });
3022
- this.tip.d.style("max-height", "300px").style("overflow", "scroll").style("font-size", "0.9em");
3023
- this.startGradient = {};
3024
- this.stopGradient = {};
3025
- }
3026
- async init(appState) {
3027
- const state = this.getState(appState);
3028
- if (this.opts.header) this.opts.header.html(`SINGLE CELL PLOT`).style("font-size", "0.9em");
3029
- this.tabs = [];
3030
- const activeTab = state.config.activeTab;
3031
- const isVisible = () => this.isValidSample;
3032
- this.tabs.push({
3033
- label: "Samples",
3034
- id: SAMPLES_TAB,
3035
- isVisible,
3036
- active: activeTab == SAMPLES_TAB,
3037
- callback: () => this.setActiveTab(SAMPLES_TAB)
3038
- });
3039
- this.tabs.push({
3040
- label: "Plots",
3041
- id: PLOTS_TAB,
3042
- active: activeTab == PLOTS_TAB,
3043
- isVisible,
3044
- callback: () => this.setActiveTab(PLOTS_TAB)
3045
- });
3046
- if (state.termdbConfig.queries.singleCell.DEgenes) {
3047
- this.tabs.push({
3048
- label: "Differential Expression",
3049
- id: DIFFERENTIAL_EXPRESSION_TAB,
3050
- active: activeTab == DIFFERENTIAL_EXPRESSION_TAB,
3051
- isVisible,
3052
- testid: "sjppoldscTabDE",
3053
- callback: () => this.setActiveTab(DIFFERENTIAL_EXPRESSION_TAB)
3054
- });
3055
- }
3056
- if (state.termdbConfig.queries.singleCell.geneExpression)
3057
- this.tabs.push({
3058
- label: "Gene Expression",
3059
- id: GENE_EXPRESSION_TAB,
3060
- active: activeTab == GENE_EXPRESSION_TAB,
3061
- isVisible,
3062
- testid: "sjppoldscTabGE",
3063
- callback: () => this.setActiveTab(GENE_EXPRESSION_TAB)
3064
- });
3065
- this.tabs.push({
3066
- label: "Summary",
3067
- id: VIOLIN_TAB,
3068
- active: activeTab == VIOLIN_TAB,
3069
- isVisible,
3070
- testid: "sjppoldscTabSummary",
3071
- callback: () => this.setActiveTab(VIOLIN_TAB)
3072
- });
3073
- if (state.termdbConfig.queries.singleCell.images)
3074
- this.tabs.push({
3075
- label: state.termdbConfig.queries.singleCell.images.label,
3076
- id: IMAGES_TAB,
3077
- active: activeTab == IMAGES_TAB,
3078
- isVisible,
3079
- callback: () => this.setActiveTab(IMAGES_TAB)
3080
- });
3081
- const q = state.termdbConfig.queries;
3082
- this.opts.holder.style("position", "relative").style("min-height", "200px");
3083
- this.mainDivId = `${this.id}-sandbox`;
3084
- const errorDiv = this.opts.holder.append("div");
3085
- const mainDiv = this.opts.holder.insert("div").style("display", "inline-block").style("vertical-align", "top").style("white-space", "nowrap").attr("id", this.mainDivId);
3086
- const leftDiv = mainDiv.append("div").style("display", "inline-block").style("vertical-align", "top");
3087
- const controlsDiv = leftDiv.append("div").attr("class", "pp-termdb-plot-controls");
3088
- const contentDiv = mainDiv.append("div").style("display", "inline-block").style("vertical-align", "top").style("padding-left", "10px").style("min-height", "300px");
3089
- this.tabsComp = await new Tabs({
3090
- holder: contentDiv,
3091
- tabsPosition: "horizontal",
3092
- tabs: this.tabs
3093
- });
3094
- this.tabsComp.main();
3095
- const headerDiv = contentDiv.append("div").style("display", "inline-block").style("padding-bottom", "10px");
3096
- const samplesPromptDiv = headerDiv.append("div").style("display", "none").text("Select a sample below to see its data:").style("padding", "0px 40px 10px 10px");
3097
- const showDiv = headerDiv.append("div").style("padding-bottom", "10px").style("display", "none");
3098
- if (state.config.plots.length > 1) this.renderShowPlots(showDiv, state);
3099
- const geDiv = headerDiv.append("div").style("display", "none");
3100
- const violinSelectDiv = headerDiv.append("div").style("padding-left", "30px").style("display", "none");
3101
- const deDiv = headerDiv.append("div").style("display", "none");
3102
- const sampleDiv = headerDiv.append("div").style("display", "inline-block").html(await this.getSampleDetails(state)).style("padding", "10px 20px");
3103
- const plotsDivParent = contentDiv.append("div");
3104
- const samplesTableDiv = plotsDivParent.append("div").style("padding-bottom", "10px");
3105
- const plotsDiv = plotsDivParent.append("div").style("display", "flex").style("flex-wrap", "wrap").style("justify-content", "flex-start");
3106
- const loadingDiv = this.opts.holder.append("div").style("position", "absolute").style("top", "0").style("left", "0").style("width", "100%").style("height", "100%").style("background-color", "rgba(255, 255, 255, 0.95)").style("text-align", "center");
3107
- this.dom = {
3108
- sampleDiv,
3109
- samplesPromptDiv,
3110
- samplesTableDiv,
3111
- showDiv,
3112
- mainDiv,
3113
- loadingDiv,
3114
- tip: new Menu({ padding: "0px" }),
3115
- tooltip: new Menu({ padding: "2px", offsetX: 10, offsetY: 0 }),
3116
- controlsHolder: controlsDiv,
3117
- geDiv,
3118
- violinSelectDiv,
3119
- deDiv,
3120
- plotsDiv,
3121
- plotsDivParent,
3122
- errorDiv
3123
- };
3124
- if (q.singleCell?.geneExpression) this.renderGeneExpressionControls(geDiv, state);
3125
- const offsetX = 80;
3126
- this.axisOffset = { x: offsetX, y: 30 };
3127
- if (q.singleCell?.DEgenes) {
3128
- const label = this.dom.deDiv.append("label").html("View differentially expressed genes for cells of a cluster versus rest of the cells:&nbsp;");
3129
- this.dom.deselect = label.append("select").attr("data-testid", "sjppoldscDEselect").on("change", (e) => {
3130
- const display = this.dom.deselect.node().value ? "inline-block" : "none";
3131
- const cluster = this.dom.deselect.node().value.split(" ")[1];
3132
- this.genes = null;
3133
- this.app.dispatch({ type: "plot_edit", id: this.id, config: { cluster, gene: null } });
3134
- });
3135
- this.dom.deselect.append("option").text("");
3136
- }
3137
- this.settings = {};
3138
- document.addEventListener("scroll", (event) => this?.tip?.hide());
3139
- select_default(".sjpp-output-sandbox-content").on("scroll", (event) => this.tip.hide());
3140
- }
3141
- getState(appState) {
3142
- const config = appState.plots.find((p) => p.id === this.id);
3143
- if (!config) {
3144
- throw `No plot with id='${this.id}' found. Did you set this.id before this.api = getComponentApi(this)?`;
3145
- }
3146
- return {
3147
- config,
3148
- dslabel: appState.vocab.dslabel,
3149
- genome: appState.vocab.genome,
3150
- termdbConfig: appState.termdbConfig,
3151
- termfilter: appState.termfilter,
3152
- vocab: appState.vocab
3153
- };
3154
- }
3155
- // called in relevant dispatch when reactsTo==true
3156
- // or current.state != replcament.state
3157
- async main() {
3158
- this.dom.mainDiv.style("display", "block");
3159
- this.dom.loadingDiv.selectAll("*").remove();
3160
- this.dom.loadingDiv.style("display", "").append("div").style("position", "relative").style("top", "50%").text("Loading...");
3161
- try {
3162
- const body = {
3163
- genome: this.state.genome,
3164
- dslabel: this.state.dslabel,
3165
- filter0: this.state.termfilter.filter0 || null
3166
- };
3167
- const result = await dofetch3("termdb/singlecellSamples", { body });
3168
- if (result.error) throw result.error;
3169
- this.samples = result.samples;
3170
- if (this.samples.length == 0) {
3171
- this.showNoMatchingDataMessage();
3172
- return;
3173
- }
3174
- this.isValidSample = this.state.config.sample && this.samples.find((i) => i.sample == this.state.config.sample);
3175
- this.colorByGene = this.state.config.activeTab == GENE_EXPRESSION_TAB || this.state.config.activeTab == DIFFERENTIAL_EXPRESSION_TAB;
3176
- this.config = structuredClone(this.state.config);
3177
- copyMerge(this.settings, this.config.settings.singleCellPlot);
3178
- this.plotColorByDivs = [];
3179
- this.plots = [];
3180
- this.legendRendered = false;
3181
- this.dom.plotsDiv.selectAll("*").remove();
3182
- await this.getData();
3183
- await this.setControls();
3184
- this.dom.sampleDiv.html(await this.getSampleDetails(this.state));
3185
- this.showActiveTab();
3186
- this.dom.loadingDiv.style("display", "none");
3187
- } catch (e) {
3188
- this.app.tip.hide();
3189
- this.dom.loadingDiv.style("display", "none");
3190
- if (e.stack) console.log(e.stack);
3191
- sayerror(this.dom.errorDiv, e);
3192
- }
3193
- }
3194
- async getData() {
3195
- if (!this.state.config.sample) return;
3196
- const plots = [];
3197
- for (const plot of this.config.plots) {
3198
- if (plot.selected) plots.push(plot.name);
3199
- }
3200
- const body = {
3201
- genome: this.state.genome,
3202
- dslabel: this.state.dslabel,
3203
- plots,
3204
- filter0: this.state.termfilter.filter0
3205
- };
3206
- body.sample = {
3207
- eID: this.state.config.experimentID,
3208
- sID: this.state.config.sample
3209
- };
3210
- if (this.state.config.gene && (this.state.config.activeTab == GENE_EXPRESSION_TAB || this.state.config.activeTab == DIFFERENTIAL_EXPRESSION_TAB))
3211
- body.gene = this.state.config.gene;
3212
- else body.colorBy = this.state.config.colorBy;
3213
- const result = await dofetch3("termdb/singlecellData", { body });
3214
- if (result.error) throw result.error;
3215
- this.refName = result.refName;
3216
- this.data = result;
3217
- }
3218
- async getSampleDetails(state) {
3219
- if (!this.samples) return "";
3220
- const sampleIdx = this.samples.findIndex((i) => i.sample == state.config.sample);
3221
- if (sampleIdx == -1) return "";
3222
- const extraText = [];
3223
- if (state.config.experimentID) {
3224
- extraText.push(
3225
- '<span style="margin-left:15px;font-size:.7em">SAMPLE</span> ' + this.samples[sampleIdx].experiments?.find((i) => i.experimentID == state.config.experimentID)?.sampleName
3226
- );
3227
- } else if (this.samples[sampleIdx].experiments) {
3228
- extraText.push(
3229
- '<span style="margin-left:15px;font-size:.7em">SAMPLE</span> ' + this.samples[sampleIdx].experiments[0].sampleName
3230
- );
3231
- }
3232
- if (state.termdbConfig.queries.singleCell.samples.extraSampleTabLabel) {
3233
- const termname = (await this.app.vocabApi.getterm(state.termdbConfig.queries.singleCell.samples.extraSampleTabLabel)).name;
3234
- const sampleValue = this.samples[sampleIdx][state.termdbConfig.queries.singleCell.samples.extraSampleTabLabel];
3235
- extraText.push(`<span style="margin-left:15px;font-size:.7em">${termname.toUpperCase()}</span> ${sampleValue}`);
3236
- }
3237
- return `<span style="font-size:.7em">${state.config.settings.singleCellPlot.uiLabels.sample.toUpperCase()}</span>
3238
- ${this.samples[sampleIdx].sample}
3239
- ${extraText.join("")}`;
3240
- }
3241
- async getSampleFilename(state) {
3242
- const sampleIdx = this.samples.findIndex((i) => i.sample == state.config.sample);
3243
- if (sampleIdx == -1) return "";
3244
- const extraText = [];
3245
- if (state.config.experimentID) {
3246
- extraText.push(
3247
- "SAMPLE_" + this.samples[sampleIdx].experiments?.find((i) => i.experimentID == state.config.experimentID)?.sampleName
3248
- );
3249
- } else if (this.samples[sampleIdx].experiments) {
3250
- extraText.push("SAMPLE_" + this.samples[sampleIdx].experiments[0].sampleName);
3251
- }
3252
- if (state.termdbConfig.queries.singleCell.samples.extraSampleTabLabel) {
3253
- const termname = (await this.app.vocabApi.getterm(state.termdbConfig.queries.singleCell.samples.extraSampleTabLabel)).name;
3254
- const sampleValue = this.samples[sampleIdx][state.termdbConfig.queries.singleCell.samples.extraSampleTabLabel];
3255
- extraText.push(`${termname.toUpperCase()}_${sampleValue}`);
3256
- }
3257
- if (this.state.config.activeTab == GENE_EXPRESSION_TAB) extraText.push(this.state.config.gene);
3258
- if (this.state.config.activeTab == DIFFERENTIAL_EXPRESSION_TAB) extraText.push(this.state.config.cluster);
3259
- if (this.state.config.activeTab == VIOLIN_TAB && this.dom.expressionBySelect)
3260
- extraText.push(this.dom.expressionBySelect.node().value);
3261
- const filename = `${state.config.settings.singleCellPlot.uiLabels.sample.toUpperCase()}_
3262
- ${this.samples[sampleIdx].sample}_
3263
- ${extraText.join("_")}`;
3264
- return filename.replace(/[^0-9a-z_]/gi, "");
3265
- }
3266
- renderShowPlots(showDiv, state) {
3267
- showDiv.append("label").text("Plots:").style("font-size", "1.1em");
3268
- for (const plot of state.config.plots) {
3269
- const id = plot.name.replace(/\s+/g, "");
3270
- const key = `show${id}`;
3271
- showDiv.append("input").attr("type", "checkbox").attr("id", key).property("checked", plot.selected).on("change", (e) => {
3272
- let plots = structuredClone(this.state.config.plots);
3273
- plots.find((p) => p.name == plot.name).selected = e.target.checked;
3274
- const selectedCount = plots.filter((p) => p.selected).length;
3275
- const defaultSettings = getDefaultSingleCellSettings();
3276
- let settings = { svgw: defaultSettings.svgw, svgh: defaultSettings.svgh };
3277
- if (selectedCount > 1) {
3278
- const width = 800;
3279
- const height = 800;
3280
- settings.svgh = width / selectedCount;
3281
- settings.svgw = height / selectedCount;
3282
- settings.contourBandwidth = 10;
3283
- }
3284
- this.app.dispatch({
3285
- type: "plot_edit",
3286
- id: this.id,
3287
- config: { plots, settings: { singleCellPlot: settings } }
3288
- });
3289
- });
3290
- showDiv.append("label").attr("for", key).text(plot.name);
3291
- }
3292
- }
3293
- renderGeneExpressionControls(geDiv, state) {
3294
- this.dom.searchboxDiv = geDiv.append("div").style("display", "inline-block");
3295
- this.dom.geneSearch = addGeneSearchbox({
3296
- tip: new Menu({ padding: "0px" }),
3297
- genome: this.app.opts.genome,
3298
- row: this.dom.searchboxDiv,
3299
- searchOnly: "gene",
3300
- placeholder: state.config.gene || "Gene",
3301
- callback: () => this.colorByGeneExp(),
3302
- emptyInputCallback: () => this.colorByGeneExp(),
3303
- hideHelp: true,
3304
- focusOff: true
3305
- });
3306
- this.dom.searchbox = this.dom.geneSearch?.searchbox;
3307
- }
3308
- async setActiveTab(tab) {
3309
- if (!this.state) return;
3310
- await this.app.dispatch({ type: "plot_edit", id: this.id, config: { activeTab: tab } });
3311
- }
3312
- async showActiveTab() {
3313
- let id = this.state.config.activeTab || this.tabs[0].id;
3314
- if (!this.isValidSample && id != SAMPLES_TAB) {
3315
- id = SAMPLES_TAB;
3316
- this.config.activeTab = SAMPLES_TAB;
3317
- }
3318
- const index = this.tabs.findIndex((t) => t.id == id);
3319
- const tab = this.tabs[index];
3320
- tab.active = true;
3321
- this.tabsComp.update(index);
3322
- this.dom.deDiv.style("display", "none");
3323
- this.dom.geDiv.style("display", "none");
3324
- this.dom.showDiv.style("display", "none");
3325
- this.dom.violinSelectDiv.style("display", "none");
3326
- this.dom.samplesTableDiv.style("display", "none");
3327
- this.dom.samplesPromptDiv.style("display", "none");
3328
- this.dom.controlsHolder.style("display", "none");
3329
- switch (id) {
3330
- case SAMPLES_TAB:
3331
- this.dom.samplesTableDiv.style("display", "block");
3332
- this.dom.samplesPromptDiv.style("display", "inline-block");
3333
- this.renderSamplesTable();
3334
- break;
3335
- case PLOTS_TAB:
3336
- await this.renderPlots();
3337
- this.dom.showDiv.style("display", "inline-block");
3338
- this.dom.controlsHolder.style("display", "block");
3339
- break;
3340
- case GENE_EXPRESSION_TAB:
3341
- this.dom.controlsHolder.style("display", "block");
3342
- await this.renderPlots();
3343
- this.dom.geDiv.style("display", "inline-block");
3344
- this.dom.searchbox.node().focus();
3345
- if (this.state.config.gene) this.dom.searchbox.node().value = this.state.config.gene;
3346
- break;
3347
- case DIFFERENTIAL_EXPRESSION_TAB:
3348
- this.dom.deDiv.style("display", "inline-block");
3349
- this.renderDETable();
3350
- break;
3351
- case IMAGES_TAB:
3352
- this.renderImage();
3353
- break;
3354
- case VIOLIN_TAB:
3355
- this.dom.geDiv.style("display", "inline-block");
3356
- this.renderViolinTab();
3357
- this.dom.searchbox.node().focus();
3358
- break;
3359
- }
3360
- }
3361
- addZoomIcons(iconsDiv, plot) {
3362
- const zoomInDiv = iconsDiv.append("div").style("margin", "20px 0px");
3363
- icons["zoomIn"](zoomInDiv, {
3364
- handler: () => {
3365
- plot.particles.position.z += 0.1;
3366
- },
3367
- title: "Zoom in. You can also zoom in moving the mouse wheel with the Ctrl key pressed."
3368
- });
3369
- const zoomOutDiv = iconsDiv.append("div").style("margin", "20px 0px");
3370
- icons["zoomOut"](zoomOutDiv, {
3371
- handler: () => {
3372
- plot.particles.position.z -= 0.1;
3373
- },
3374
- title: "Zoom out. You can also zoom out moving the mouse wheel with the Ctrl key pressed."
3375
- });
3376
- const identityDiv = iconsDiv.append("div").style("margin", "20px 0px");
3377
- icons["restart"](identityDiv, {
3378
- handler: () => {
3379
- plot.particles.position.z = 0;
3380
- plot.particles.position.x = 0;
3381
- plot.particles.position.y = 0;
3382
- },
3383
- title: "Reset plot to defaults"
3384
- });
3385
- }
3386
- async renderImage() {
3387
- const sample = this.state.config.sample || this.samples[0].sample;
3388
- const i = this.state.termdbConfig.queries.singleCell.images;
3389
- const result = await dofetch3(`img?file=${i.folder}${i.folder.endsWith("/") ? "" : "/"}${sample}/${i.fileName}`);
3390
- if (!result.src || result.error) {
3391
- sayerror(this.dom.plotsDiv, "Cannot load image: " + (result.error || ""));
3392
- return;
3393
- }
3394
- this.dom.plotsDiv.append("img").attr("src", result.src).attr("height", 400);
3395
- }
3396
- async renderViolinTab() {
3397
- if (!this.state.config.gene) return;
3398
- const selectDiv = this.dom.violinSelectDiv.style("display", "inline-block");
3399
- selectDiv.selectAll("*").remove();
3400
- const plotDiv = this.dom.plotsDiv.append("div").style("width", "100%");
3401
- const options = /* @__PURE__ */ new Set();
3402
- let selectedOption = "";
3403
- for (const plot of this.data.plots) {
3404
- const colorBy = this.state.config.colorBy?.[plot.name] || plot.colorColumns[0];
3405
- if (!selectedOption) selectedOption = colorBy;
3406
- for (const c of plot.colorColumns) options.add(c);
3407
- }
3408
- if (options.size > 1) {
3409
- selectDiv.append("label").text("Show expression by: ");
3410
- const expressionBySelect = selectDiv.append("select").on("change", async (e) => {
3411
- const expressionBy = e.target.value;
3412
- violinDiv.selectAll("*").remove();
3413
- this.renderViolin(expressionBy, violinDiv);
3414
- });
3415
- this.dom.expressionBySelect = expressionBySelect;
3416
- expressionBySelect.selectAll("option").data(Array.from(options)).enter().append("option").attr("value", (d) => d).attr("selected", (d) => d == selectedOption ? d : null).html((d) => d);
3417
- } else selectDiv.append("label").text(`Expression by ${selectedOption}:`);
3418
- const violinDiv = this.dom.plotsDiv.append("div");
3419
- this.renderViolin(selectedOption, violinDiv);
3420
- }
3421
- async renderViolin(colorBy, violinDiv) {
3422
- const gene = this.state.config.gene;
3423
- const plot = this.data.plots.find((p) => p.colorColumns.find((c) => c == colorBy));
3424
- this.initPlot(plot);
3425
- const values = {};
3426
- for (const cluster of plot.clusters) {
3427
- values[cluster] = { key: cluster, value: cluster };
3428
- }
3429
- const downloadFilename = await this.getSampleFilename(this.state) + "_VIOLIN";
3430
- const opts = {
3431
- holder: violinDiv,
3432
- state: {
3433
- vocab: this.state.vocab,
3434
- plots: [
3435
- {
3436
- chartType: "violin",
3437
- term: {
3438
- $id: await digestMessage(`${gene}-${this.state.config.sample}-${this.state.config.experimentID}`),
3439
- term: {
3440
- type: SINGLECELL_GENE_EXPRESSION,
3441
- id: gene,
3442
- gene,
3443
- name: gene,
3444
- sample: {
3445
- sID: this.state.config.sample,
3446
- eID: this.state.config.experimentID
3447
- }
3448
- },
3449
- q: { mode: "continuous" }
3450
- },
3451
- term2: {
3452
- $id: await digestMessage(`${colorBy}-${this.state.config.sample}-${this.state.config.experimentID}`),
3453
- term: {
3454
- type: SINGLECELL_CELLTYPE,
3455
- id: colorBy,
3456
- name: colorBy,
3457
- sample: {
3458
- sID: this.state.config.sample,
3459
- eID: this.state.config.experimentID
3460
- },
3461
- //plot and color by are used to read the sample categories from the plot
3462
- plot: plot.name,
3463
- colorBy,
3464
- values
3465
- }
3466
- },
3467
- downloadFilename
3468
- }
3469
- ]
3470
- }
3471
- };
3472
- const plotImport = await import("./plot.app-YBZDNST2.js");
3473
- const plotAppApi = await plotImport.appInit(opts);
3474
- }
3475
- async renderGSEA(holder) {
3476
- const gsea_params = {
3477
- genes: this.genes,
3478
- fold_change: this.fold_changes,
3479
- genome: this.app.vocabApi.opts.state.vocab.genome
3480
- };
3481
- const downloadFilename = await this.getSampleFilename(this.state) + "_GSEA";
3482
- const config = {
3483
- chartType: "gsea",
3484
- gsea_params,
3485
- // if getPlotHolder is defined, use this.mainDivId as insertBefore,
3486
- // so that in GDC frontend framework, plots that are launched from scRNAseq
3487
- // will be inserted before it. TODO: may insert after the scRNAseq plot instead???
3488
- insertBefore: this.app.opts?.app?.getPlotHolder ? this.mainDivId : this.id,
3489
- downloadFilename
3490
- };
3491
- const opts = {
3492
- genome: this.app.opts.genome,
3493
- holder,
3494
- state: {
3495
- vocab: this.state.vocab,
3496
- plots: [config]
3497
- }
3498
- };
3499
- const plotImport = await import("./plot.app-YBZDNST2.js");
3500
- const plotAppApi = await plotImport.appInit(opts);
3501
- }
3502
- async renderDETable() {
3503
- this.dom.deselect.selectAll("*").remove();
3504
- this.dom.deselect.append("option").text("");
3505
- const plot = this.data.plots[0];
3506
- this.initPlot(plot);
3507
- for (const cluster of plot.clusters) this.dom.deselect.append("option").text(cluster);
3508
- const categoryName = this.state.config.cluster;
3509
- this.dom.deselect.node().value = categoryName != void 0 ? `Cluster ${categoryName}` : "";
3510
- if (!categoryName) return;
3511
- const columnName = this.state.termdbConfig.queries.singleCell.DEgenes.termId;
3512
- const sample = this.state.config.experimentID || this.state.config.sample || this.samples?.[0]?.experiments[0]?.experimentID;
3513
- const DEContentDiv = this.dom.plotsDiv.append("div").style("width", "100%");
3514
- const tabsDiv = DEContentDiv.append("div");
3515
- const tableDiv = DEContentDiv.append("div");
3516
- const GSEADiv = DEContentDiv.append("div").style("display", "none");
3517
- let result;
3518
- try {
3519
- const args = { genome: this.state.genome, dslabel: this.state.dslabel, categoryName, sample, columnName };
3520
- result = await dofetch3("termdb/singlecellDEgenes", { body: args });
3521
- if (result.error) {
3522
- tableDiv.text(result.error);
3523
- return;
3524
- }
3525
- if (!result.data || !result?.data?.length) {
3526
- tableDiv.text("No differentially expressed genes found.");
3527
- return;
3528
- }
3529
- } catch (e) {
3530
- if (e.stack) console.error(e.stack);
3531
- else throw `Error fetching DE genes: ${e.message || e} [singleCellPlot.renderDETable()]`;
3532
- return;
3533
- }
3534
- const tabs = [
3535
- {
3536
- label: "Differentially Expressed Genes",
3537
- id: DE_GENES_TAB,
3538
- active: true,
3539
- callback: () => showActiveDETab(DE_GENES_TAB)
3540
- }
3541
- ];
3542
- if (this.app.opts.genome.termdbs) {
3543
- tabs.push({
3544
- label: "Gene Set Enrichment Analysis (GSEA)",
3545
- id: DE_GSEA_TAB,
3546
- active: false,
3547
- callback: () => showActiveDETab(DE_GSEA_TAB)
3548
- });
3549
- }
3550
- function showActiveDETab(id) {
3551
- tableDiv.style("display", "none");
3552
- GSEADiv.style("display", "none");
3553
- if (id == DE_GENES_TAB) tableDiv.style("display", "block");
3554
- if (id == DE_GSEA_TAB) GSEADiv.style("display", "block");
3555
- }
3556
- if (tabs.length > 1) {
3557
- const deTabs = await new Tabs({
3558
- holder: tabsDiv,
3559
- tabsPosition: "horizontal",
3560
- tabs
3561
- });
3562
- deTabs.main();
3563
- }
3564
- tableDiv.append("div").style("padding-bottom", "10px").text("Select a gene to view its expression:");
3565
- const tableDivContent = tableDiv.append("div").style("padding-bottom", "10px");
3566
- const columns = [
3567
- { label: "Gene", width: "15vw" },
3568
- { label: "Log2FC", width: "12vw", barplot: {} },
3569
- { label: "Adjusted P-value", width: "12vw" }
3570
- ];
3571
- const rows = [];
3572
- this.genes = [];
3573
- this.fold_changes = [];
3574
- result.data.sort((a, b) => b.fold_change - a.fold_change);
3575
- const selectedRows = [];
3576
- let i = 0;
3577
- for (const gene of result.data) {
3578
- const row = [
3579
- { value: gene.gene_name },
3580
- { value: gene.fold_change },
3581
- { value: roundValueAuto(gene.adjusted_p_value) }
3582
- ];
3583
- rows.push(row);
3584
- this.genes.push(gene.gene_name);
3585
- this.fold_changes.push(gene.fold_change);
3586
- if (gene.gene_name == this.state.config.gene) selectedRows.push(i);
3587
- i++;
3588
- }
3589
- this.DETable = { rows, columns };
3590
- const downloadFilename = `${await this.getSampleFilename(this.state)}_DE_GENES.tsv`;
3591
- renderTable({
3592
- rows,
3593
- columns,
3594
- maxHeight: "50vh",
3595
- div: tableDivContent,
3596
- singleMode: true,
3597
- noButtonCallback: (i2, node) => {
3598
- const gene = result.data[i2].gene_name;
3599
- this.app.dispatch({
3600
- type: "plot_edit",
3601
- id: this.id,
3602
- config: {
3603
- gene,
3604
- sample: this.state.config.sample || this.samples?.[0]?.sample,
3605
- experimentID: this.state.config.experimentID || this.samples?.[0].experiments?.[0]?.experimentID,
3606
- activeTab: GENE_EXPRESSION_TAB
3607
- }
3608
- });
3609
- },
3610
- selectedRows,
3611
- resize: true,
3612
- dataTestId: "sjppoldscDEtable",
3613
- download: { fileName: downloadFilename }
3614
- });
3615
- this.renderGSEA(GSEADiv);
3616
- }
3617
- colorByGeneExp() {
3618
- const gene = this.dom.searchbox.node().value;
3619
- for (const div of this.plotColorByDivs) div.style("display", "none");
3620
- this.app.dispatch({
3621
- type: "plot_edit",
3622
- id: this.id,
3623
- config: {
3624
- gene,
3625
- sample: this.state.config.sample || this.samples?.[0]?.sample,
3626
- experimentID: this.state.config.experimentID || this.samples?.[0].experiments?.[0]?.experimentID
3627
- }
3628
- });
3629
- }
3630
- async setControls() {
3631
- this.dom.controlsHolder.selectAll("*").remove();
3632
- const inputs = [
3633
- {
3634
- label: "Chart width",
3635
- title: "Chart width",
3636
- type: "number",
3637
- chartType: "singleCellPlot",
3638
- settingsKey: "svgw",
3639
- min: 300,
3640
- max: 1e3
3641
- },
3642
- {
3643
- label: "Chart height",
3644
- title: "Chart height",
3645
- type: "number",
3646
- chartType: "singleCellPlot",
3647
- settingsKey: "svgh",
3648
- min: 300,
3649
- max: 1e3
3650
- },
3651
- {
3652
- label: "Dot size",
3653
- type: "number",
3654
- chartType: "singleCellPlot",
3655
- settingsKey: "sampleSizeThree",
3656
- title: "Dot size",
3657
- min: 1e-3,
3658
- max: 0.1,
3659
- step: 1e-3
3660
- },
3661
- {
3662
- label: "Dot opacity",
3663
- type: "number",
3664
- chartType: "singleCellPlot",
3665
- settingsKey: "opacity",
3666
- title: "Dot opacity",
3667
- min: 0.1,
3668
- max: 1,
3669
- step: 0.1
3670
- },
3671
- {
3672
- label: "Show grid",
3673
- boxLabel: "",
3674
- type: "checkbox",
3675
- chartType: "singleCellPlot",
3676
- settingsKey: "showGrid",
3677
- title: "Show grid"
3678
- }
3679
- ];
3680
- const enableContour = this.state.config.activeTab == GENE_EXPRESSION_TAB && this.state.config.gene;
3681
- if (enableContour)
3682
- inputs.push({
3683
- label: "Show contour map",
3684
- boxLabel: "",
3685
- type: "checkbox",
3686
- chartType: "singleCellPlot",
3687
- settingsKey: "showContour",
3688
- title: "Shows the density of point clouds. It uses gene expression to weight the points when calculating the density contours."
3689
- });
3690
- if (enableContour && this.settings.showContour)
3691
- inputs.push(
3692
- {
3693
- label: "Color contours",
3694
- boxLabel: "",
3695
- type: "checkbox",
3696
- chartType: "singleCellPlot",
3697
- settingsKey: "colorContours"
3698
- },
3699
- {
3700
- label: "Contour bandwidth",
3701
- type: "number",
3702
- chartType: "singleCellPlot",
3703
- settingsKey: "contourBandwidth",
3704
- title: "Reduce to increase resolution. ",
3705
- min: 5,
3706
- max: 50,
3707
- step: 5
3708
- },
3709
- {
3710
- label: "Contour thresholds",
3711
- type: "number",
3712
- chartType: "singleCellPlot",
3713
- settingsKey: "contourThresholds",
3714
- title: "Dot size",
3715
- min: 5,
3716
- max: 30,
3717
- step: 5
3718
- }
3719
- );
3720
- if ((this.state.config.activeTab == GENE_EXPRESSION_TAB || this.state.config.activeTab == DIFFERENTIAL_EXPRESSION_TAB) && this.state.config.gene)
3721
- inputs.unshift({
3722
- label: "Show unexpressed cells",
3723
- boxLabel: "",
3724
- type: "checkbox",
3725
- chartType: "singleCellPlot",
3726
- settingsKey: "showNoExpCells",
3727
- title: "Show cells not expressing the selected gene"
3728
- });
3729
- this.components = {
3730
- controls: await controlsInit({
3731
- app: this.app,
3732
- id: this.id,
3733
- holder: this.dom.controlsHolder,
3734
- inputs
3735
- })
3736
- };
3737
- this.components.controls.on("downloadClick.singleCellPlot", async () => {
3738
- if (!this.state) return;
3739
- const filename = await this.getSampleFilename(this.state);
3740
- if (this.state.config.activeTab == GENE_EXPRESSION_TAB || this.state.config.activeTab == PLOTS_TAB)
3741
- for (const plot of this.plots) this.downloadPlot(plot, filename);
3742
- });
3743
- }
3744
- downloadSCTable(name, table) {
3745
- downloadTable(table.rows, table.columns, name);
3746
- }
3747
- downloadPlot(plot, filename) {
3748
- downloadSingleSVG(plot.legendSVG, filename + "_LEGEND.svg", this.opts.holder.node());
3749
- const downloadImgName = plot.name;
3750
- const a = document.createElement("a");
3751
- document.body.appendChild(a);
3752
- const dataURL = plot.canvas.toDataURL();
3753
- a.addEventListener(
3754
- "click",
3755
- () => {
3756
- a.download = filename + "_" + downloadImgName + ".png";
3757
- a.href = dataURL;
3758
- document.body.removeChild(a);
3759
- },
3760
- false
3761
- );
3762
- a.click();
3763
- }
3764
- showNoMatchingDataMessage() {
3765
- this.dom.mainDiv.style("display", "none");
3766
- this.dom.loadingDiv.selectAll("*").remove();
3767
- this.dom.loadingDiv.style("display", "").append("div").style("font-size", "1.2em").html("No matching cohort data.");
3768
- }
3769
- renderPlots() {
3770
- const result = this.data;
3771
- if (result.nodata) return;
3772
- for (const plot of result.plots) {
3773
- if ((this.state.config.activeTab == DIFFERENTIAL_EXPRESSION_TAB || this.state.config.activeTab == GENE_EXPRESSION_TAB) && this.state.config.gene && !plot.expCells.length)
3774
- continue;
3775
- this.renderPlot(plot);
3776
- }
3777
- if (this.plots.length == 0) this.dom.plotsDiv.append("div").text("No data to plot");
3778
- }
3779
- renderPlot(plot) {
3780
- if (!plot.plotDiv) {
3781
- const plotDiv = this.dom.plotsDiv.append("div").style("display", "inline-block").style("vertical-align", "top");
3782
- const leftDiv = plotDiv.append("div").style("display", "inline-block").style("vertical-align", "top").style("padding-top", "30px");
3783
- plot.plotDiv = plotDiv.append("div").style("display", "inline-block");
3784
- this.addZoomIcons(leftDiv, plot);
3785
- }
3786
- const colorMap = {};
3787
- this.initPlot(plot);
3788
- const cat2Color = getColors(plot.clusters.length + 2);
3789
- for (const cluster of plot.clusters)
3790
- colorMap[cluster] = plot.colorMap?.[cluster] ? plot.colorMap[cluster] : cat2Color(cluster);
3791
- plot.colorMap = colorMap;
3792
- this.initAxes(plot);
3793
- plot.headerDiv = plot.plotDiv.append("div");
3794
- plot.headerDiv.append("label").text(plot.name).style("font-size", "1.2em").style("margin-right", "10px");
3795
- if (this.colorByGene && this.state.config.gene) {
3796
- if (!this.config.startColor[plot.name]) this.config.startColor[plot.name] = "#fffee0";
3797
- if (!this.config.stopColor[plot.name]) this.config.stopColor[plot.name] = "red";
3798
- const startColor = this.config.startColor[plot.name];
3799
- const stopColor = this.config.stopColor[plot.name];
3800
- let min, max2;
3801
- const expCells = plot.expCells;
3802
- const values = expCells.map((cell) => cell.geneExp).sort();
3803
- plot.colorValues = values;
3804
- if (values.length == 0) {
3805
- plot.colorGenerator = null;
3806
- } else {
3807
- switch (this.settings.colorScaleMode) {
3808
- // Fixed mode: Use user-defined min/max values
3809
- // This is useful when you want consistent scaling across different views
3810
- case "fixed":
3811
- min = this.settings.colorScaleMinFixed;
3812
- max2 = this.settings.colorScaleMaxFixed;
3813
- break;
3814
- case "percentile":
3815
- min = values[0];
3816
- const index = Math.floor(values.length * this.settings.colorScalePercentile / 100);
3817
- max2 = values[index];
3818
- break;
3819
- case "auto":
3820
- default:
3821
- min = values[0];
3822
- max2 = values[values.length - 1];
3823
- break;
3824
- }
3825
- plot.colorGenerator = linear().domain([min, max2]).range([startColor, stopColor]);
3826
- }
3827
- }
3828
- this.renderLargePlotThree(plot);
3829
- this.renderLegend(plot);
3830
- }
3831
- initPlot(plot) {
3832
- this.plots.push(plot);
3833
- const expCells = plot.expCells.sort((a, b) => a.geneExp - b.geneExp);
3834
- plot.cells = [...plot.noExpCells, ...expCells];
3835
- plot.id = plot.name.replace(/\s+/g, "");
3836
- let clusters = new Set(plot.cells.map((c) => c.category));
3837
- plot.clusters = Array.from(clusters).sort((a, b) => {
3838
- const num1 = parseInt(a.split(" ")[1]);
3839
- const num2 = parseInt(b.split(" ")[1]);
3840
- return num1 - num2;
3841
- });
3842
- }
3843
- getOpacity(d) {
3844
- if (this.config.hiddenClusters[d.category]) return 0;
3845
- if (this.colorByGene && this.state.config.gene && !d.geneExp)
3846
- return this.settings.showNoExpCells ? this.settings.opacity : 0;
3847
- return this.settings.opacity;
3848
- }
3849
- getColor(d, plot) {
3850
- let color = plot.colorMap[d.category];
3851
- if (this.colorByGene && this.state.config.gene) {
3852
- if (!d.geneExp) color = noExpColor;
3853
- else if (d.geneExp > plot.max) color = plot.colorGenerator(plot.max);
3854
- else color = plot.colorGenerator(d.geneExp);
3855
- }
3856
- return color;
3857
- }
3858
- handleZoom(e, plot) {
3859
- plot.mainG.attr("transform", e.transform);
3860
- }
3861
- initAxes(plot) {
3862
- if (!plot.cells.length) return;
3863
- const s0 = plot.cells[0];
3864
- const [xMin, xMax, yMin, yMax] = plot.cells.reduce(
3865
- (s, d) => [d.x < s[0] ? d.x : s[0], d.x > s[1] ? d.x : s[1], d.y < s[2] ? d.y : s[2], d.y > s[3] ? d.y : s[3]],
3866
- [s0.x, s0.x, s0.y, s0.y]
3867
- );
3868
- plot.xAxisScale = linear().domain([xMin, xMax]).range([-1, 1]);
3869
- plot.yAxisScale = linear().domain([yMin, yMax]).range([-1, 1]);
3870
- }
3871
- renderLegend(plot) {
3872
- const colorMap = plot.colorMap;
3873
- let legendSVG = plot.legendSVG;
3874
- const clustersHeight = 20 * Object.keys(colorMap).length + 50;
3875
- const height = Math.max(this.settings.svgh, clustersHeight);
3876
- if (!plot.legendSVG) {
3877
- const activeTab = this.tabs.find((tab) => tab.active);
3878
- if (activeTab.id == PLOTS_TAB) {
3879
- const app = this.app;
3880
- if (plot.colorColumns.length > 1) {
3881
- const plotColorByDiv = plot.headerDiv.append("div").style("display", "inline-block").style("padding-bottom", "20px");
3882
- plotColorByDiv.append("label").text("Color by:").style("margin-right", "5px");
3883
- const colorBySelect = plotColorByDiv.append("select");
3884
- this.plotColorByDivs.push(plotColorByDiv);
3885
- colorBySelect.selectAll("option").data(plot.colorColumns).enter().append("option").attr("value", (d) => d).property("selected", (d) => d == this.state.config.colorBy?.[plot.name]).html((d) => d);
3886
- colorBySelect.on("change", () => {
3887
- const colorBy = colorBySelect.node().value;
3888
- app.dispatch({
3889
- type: "plot_edit",
3890
- id: this.id,
3891
- config: { colorBy: { [plot.name]: colorBy } }
3892
- });
3893
- });
3894
- }
3895
- }
3896
- legendSVG = plot.plotDiv.append("svg").attr("width", 250).attr("height", height).style("display", "inline-block").style("vertical-align", "top").style("font-size", "0.9em");
3897
- plot.legendSVG = legendSVG;
3898
- }
3899
- legendSVG.selectAll("*").remove();
3900
- this.legendRendered = true;
3901
- if ((this.state.config.activeTab == GENE_EXPRESSION_TAB || this.state.config.activeTab == DIFFERENTIAL_EXPRESSION_TAB) && this.state.config.gene) {
3902
- this.renderColorGradient(plot);
3903
- return;
3904
- }
3905
- let x = 20;
3906
- plot.legendSVG.append("text").attr("transform", `translate(${x}, ${25})`).style("font-weight", "bold").text(`${plot.colorBy}`);
3907
- let step = 25;
3908
- if (height < 500) {
3909
- plot.legendSVG.style("font-size", "0.8em");
3910
- step = 20;
3911
- }
3912
- let y = 50;
3913
- const configPlot = this.state.config.plots.find((p) => p.name == plot.name);
3914
- const aliases = configPlot.colorColumns.find((c) => c.name == plot.colorBy)?.aliases;
3915
- for (const cluster in colorMap) {
3916
- const clusterCells = plot.cells.filter((item) => item.category == cluster);
3917
- const hidden = this.config.hiddenClusters?.[cluster];
3918
- const n = clusterCells.length;
3919
- const color = colorMap[cluster];
3920
- const itemG = plot.legendSVG.append("g").attr("transform", (c) => `translate(${x}, ${y})`);
3921
- itemG.append("circle").attr("r", 5).attr("fill", color);
3922
- itemG.append("g").attr("transform", `translate(15, 5)`).append("text").text(
3923
- `${cluster == "ref" ? this.state.termdbConfig.queries.singleCell.data.refName : cluster == "query" ? this.state.config.sample || this.samples[0].sample : aliases ? aliases[cluster] : cluster} n=${n}`
3924
- ).style("text-decoration", hidden ? "line-through" : "none").on("click", (e) => this.showLegendItemMenu(e, cluster, plot));
3925
- y += step;
3926
- }
3927
- }
3928
- hideCategory(key, hidden) {
3929
- this.app.dispatch({
3930
- type: "plot_edit",
3931
- id: this.id,
3932
- config: { hiddenClusters: { [key]: hidden } }
3933
- });
3934
- }
3935
- showLegendItemMenu(e, key, plot) {
3936
- let hiddenCount = 0;
3937
- for (const cluster in this.state.config.hiddenClusters) if (this.state.config.hiddenClusters[cluster]) hiddenCount++;
3938
- const hidden = this.state.config.hiddenClusters?.[key];
3939
- if (hidden && hiddenCount == 1) {
3940
- this.hideCategory(key, false, plot.legendSVG);
3941
- return;
3942
- }
3943
- const menu = this.tip.clear();
3944
- const div = menu.d.append("div");
3945
- div.append("div").attr("class", "sja_menuoption sja_sharp_border").text(hidden ? "Show" : "Hide").on("click", () => {
3946
- this.hideCategory(key, !hidden, plot.legendSVG);
3947
- menu.hide();
3948
- });
3949
- div.append("div").attr("class", "sja_menuoption sja_sharp_border").text("Show only").on("click", () => {
3950
- for (const cluster in plot.colorMap) if (key != cluster) this.hideCategory(cluster, true, plot.legendSVG);
3951
- this.hideCategory(key, false, plot.legendSVG);
3952
- menu.hide();
3953
- });
3954
- if (hiddenCount > 1)
3955
- div.append("div").attr("class", "sja_menuoption sja_sharp_border").text("Show all").on("click", () => {
3956
- menu.hide();
3957
- for (const mapKey in plot.colorMap) this.hideCategory(mapKey, false, plot.legendSVG);
3958
- });
3959
- menu.showunder(e.target);
3960
- }
3961
- renderColorGradient(plot) {
3962
- if (plot.cells.length == 0 || !plot.colorGenerator) return;
3963
- const colors = [this.config.startColor[plot.name], this.config.stopColor[plot.name]];
3964
- const gene = this.state.config.gene;
3965
- let offsetY = 20;
3966
- const barwidth = 100;
3967
- plot.legendSVG.append("g").attr("transform", `translate(${20}, ${offsetY})`).append("text").text(`${gene} expression`);
3968
- const legendG = plot.legendSVG.append("g").attr("transform", `translate(20, ${2 * offsetY})`);
3969
- const colorScale = new ColorScale({
3970
- holder: legendG,
3971
- barwidth,
3972
- barheight: 20,
3973
- colors,
3974
- domain: plot.colorGenerator.domain(),
3975
- position: "0, 20",
3976
- ticks: 4,
3977
- tickSize: 5,
3978
- topTicks: true,
3979
- setColorsCallback: (val, idx) => {
3980
- this.changeGradientColor(plot, val, idx);
3981
- },
3982
- numericInputs: {
3983
- cutoffMode: this.settings.colorScaleMode,
3984
- defaultPercentile: this.settings.colorScalePercentile,
3985
- callback: (obj) => {
3986
- let min, max2;
3987
- const colorValues = plot.colorValues;
3988
- if (obj.cutoffMode === "auto") {
3989
- min = colorValues[0];
3990
- max2 = colorValues[colorValues.length - 1];
3991
- } else if (obj.cutoffMode === "fixed") {
3992
- min = obj.min;
3993
- max2 = obj.max;
3994
- } else if (obj.cutoffMode === "percentile") {
3995
- min = colorValues[0];
3996
- const index = Math.floor(colorValues.length * obj.percentile / 100);
3997
- max2 = colorValues[index];
3998
- }
3999
- this.app.dispatch({
4000
- type: "plot_edit",
4001
- id: this.id,
4002
- config: {
4003
- settings: {
4004
- singleCellPlot: {
4005
- colorScaleMode: obj.cutoffMode,
4006
- colorScaleMinFixed: obj.cutoffMode === "fixed" ? min : null,
4007
- colorScaleMaxFixed: obj.cutoffMode === "fixed" ? max2 : null,
4008
- colorScalePercentile: obj.cutoffMode === "percentile" ? obj.percentile : this.settings.colorScalePercentile
4009
- }
4010
- }
4011
- }
4012
- });
4013
- }
4014
- }
4015
- });
4016
- colorScale.updateScale();
4017
- }
4018
- changeGradientColor = function(plot, newColor, idx) {
4019
- const colorKey = idx == 0 ? "startColor" : "stopColor";
4020
- this.config[colorKey][plot.name] = newColor;
4021
- this.app.dispatch({
4022
- type: "plot_edit",
4023
- id: this.id,
4024
- config: this.config
4025
- });
4026
- };
4027
- showTooltip(event, plot) {
4028
- if (this.onClick && event.type == "click") {
4029
- this.onClick = false;
4030
- this.tip.hide();
4031
- return;
4032
- }
4033
- if (event.target.tagName == "circle") {
4034
- this.onClick = event.type == "click";
4035
- const d = event.target.__data__;
4036
- const menu = this.tip.clear();
4037
- const table = menu.d.append("table");
4038
- let tr = table.append("tr");
4039
- tr.append("td").style("color", "#aaa").text(plot.colorBy);
4040
- let td = tr.append("td");
4041
- td.text(d.category);
4042
- if ("geneExp" in d) {
4043
- tr = table.append("tr");
4044
- tr.append("td").style("color", "#aaa").text("Gene expression");
4045
- td = tr.append("td");
4046
- const svg = td.append("svg").attr("width", 150).attr("height", 20);
4047
- const x = 10;
4048
- const y = 12;
4049
- const g = svg.append("g").attr("transform", `translate(${x}, ${y})`);
4050
- g.append("circle").attr("fill", this.getColor(d, plot)).attr("r", 4);
4051
- svg.append("g").attr("transform", `translate(${x + 15}, ${y + 4})`).append("text").text(roundValueAuto(d.geneExp));
4052
- }
4053
- menu.show(event.clientX, event.clientY, true, true);
4054
- } else this.onMouseOut(event);
4055
- }
4056
- onMouseOut(event) {
4057
- this.tip.hide();
4058
- }
4059
- async renderSamplesTable() {
4060
- const state = this.state;
4061
- const div = this.dom.samplesTableDiv;
4062
- div.selectAll("*").remove();
4063
- const [rows, columns] = await this.getTableData(state);
4064
- if (columns.length > 5) div.style("font-size", "0.9em");
4065
- const selectedRows = [];
4066
- const i = this.samples.findIndex((i2) => i2.sample == state.config.sample);
4067
- if (i != -1) selectedRows.push(i);
4068
- renderTable({
4069
- rows,
4070
- columns,
4071
- resize: true,
4072
- singleMode: true,
4073
- div,
4074
- maxWidth: columns.length > 3 ? "98vw" : "40vw",
4075
- maxHeight: "50vh",
4076
- dataTestId: "sjppoldscSampleTable",
4077
- noButtonCallback: (index) => {
4078
- const sample = rows[index][0].value;
4079
- const hiddenClusters = {};
4080
- for (const cluster in this.config.hiddenClusters) hiddenClusters[cluster] = false;
4081
- const settings = {
4082
- colorScaleMode: "auto",
4083
- colorScaleMinFixed: null,
4084
- colorScaleMaxFixed: null,
4085
- colorScalePercentile: 95,
4086
- showNoExpCells: false,
4087
- showContour: false,
4088
- colorContours: false,
4089
- contourBandwidth: 15,
4090
- contourThresholds: 10
4091
- };
4092
- const config = {
4093
- chartType: "singleCellPlot",
4094
- sample,
4095
- // track sample name to identify it in this.samples[]
4096
- activeTab: PLOTS_TAB,
4097
- // on selecting a sample from table, auto switch to plots to directly show this sample's plots, to save user a click
4098
- cluster: null,
4099
- // reset cluster
4100
- hiddenClusters,
4101
- // reset hidden clusters
4102
- settings: { singleCellPlot: settings }
4103
- };
4104
- this.genes = null;
4105
- if (rows[index][0].__experimentID) {
4106
- config.experimentID = rows[index][0].__experimentID;
4107
- }
4108
- this.app.dispatch({ type: "plot_edit", id: this.id, config });
4109
- },
4110
- selectedRows,
4111
- striped: true,
4112
- header: { style: { "text-transform": "capitalize" } }
4113
- // to show header in title case; if it results in a conflict (e.g. a sample name showing in 1st tab has to be lower case), then use sampleColumns[].columnHeader as override of term name
4114
- });
4115
- }
4116
- async getTableData(state) {
4117
- const { uiLabels } = state.config.settings.singleCellPlot;
4118
- const s = state.termdbConfig.queries?.singleCell?.samples || {};
4119
- const samples = this.samples;
4120
- const rows = [];
4121
- const hasExperiments = samples.some((i) => i.experiments);
4122
- const columns = [{ label: uiLabels.Sample }];
4123
- if (hasExperiments) columns.push({ label: "Sample" });
4124
- for (const c of s.sampleColumns || []) {
4125
- let label = c.termid;
4126
- try {
4127
- label = (await this.app.vocabApi.getterm(c.termid)).name;
4128
- } catch (e) {
4129
- }
4130
- columns.push({ label, width: "14vw" });
4131
- }
4132
- if (hasExperiments) columns.push({ label: "Experiment" });
4133
- for (const sample of samples) {
4134
- if (hasExperiments)
4135
- for (const exp of sample.experiments) {
4136
- const row = [{ value: sample.sample, __experimentID: exp.experimentID }];
4137
- row.push({ value: exp.sampleName });
4138
- for (const c of s.sampleColumns || []) {
4139
- row.push({ value: sample[c.termid] });
4140
- }
4141
- const urlTemp = this.state.termdbConfig?.urlTemplates?.scrnaExperimentId;
4142
- if (urlTemp) row.push({ value: exp.experimentID, url: `${urlTemp.base}${exp.experimentID}` });
4143
- else row.push({ value: exp.experimentID });
4144
- rows.push(row);
4145
- }
4146
- else {
4147
- const row = [{ value: sample.sample }];
4148
- for (const c of s.sampleColumns || []) {
4149
- row.push({ value: sample[c.termid] });
4150
- }
4151
- rows.push(row);
4152
- }
4153
- }
4154
- return [rows, columns];
4155
- }
4156
- renderLargePlotThree = async function(plot) {
4157
- if (!plot.canvas) {
4158
- const canvas = plot.plotDiv.append("canvas").attr("data-testid", "sjppoldsccanvas").style("display", "inline-block").style("vertical-align", "top");
4159
- plot.canvas = canvas.node();
4160
- plot.canvas.width = this.settings.svgw;
4161
- plot.canvas.height = this.settings.svgh;
4162
- plot.renderer = new WebGLRenderer({ antialias: true, canvas: plot.canvas, preserveDrawingBuffer: true });
4163
- } else plot.renderer.clear();
4164
- const renderer = plot.renderer;
4165
- renderer.outputColorSpace = LinearSRGBColorSpace;
4166
- const DragControls = await import("./DragControls-VBN4LBU5.js");
4167
- const fov = this.settings.threeFOV;
4168
- const near = 0.1;
4169
- const far = 1e3;
4170
- const camera = new PerspectiveCamera(fov, 1, near, far);
4171
- const scene = new Scene();
4172
- camera.position.set(0, 0, 2);
4173
- camera.lookAt(scene.position);
4174
- camera.updateMatrix();
4175
- const whiteColor = new Color("rgb(255,255,255)");
4176
- scene.background = whiteColor;
4177
- const geometry = new BufferGeometry();
4178
- const { vertices, colors } = this.getVertices(plot);
4179
- geometry.setAttribute("position", new Float32BufferAttribute(vertices, 3));
4180
- geometry.setAttribute("color", new Float32BufferAttribute(colors, 3));
4181
- const tex = getThreeCircle(256);
4182
- const material = new PointsMaterial({
4183
- size: this.settings.sampleSizeThree,
4184
- sizeAttenuation: true,
4185
- transparent: true,
4186
- opacity: this.settings.opacity,
4187
- map: tex,
4188
- vertexColors: true
4189
- });
4190
- const particles = new Points(geometry, material);
4191
- plot.particles = particles;
4192
- scene.add(particles);
4193
- renderer.setSize(this.settings.svgw, this.settings.svgh);
4194
- renderer.setPixelRatio(window.devicePixelRatio);
4195
- plot.canvas.addEventListener("mousewheel", (event) => {
4196
- if (!event.ctrlKey) return;
4197
- event.preventDefault();
4198
- particles.position.z -= event.deltaY / 500;
4199
- });
4200
- if (this.settings.showContour && this.state.config.gene && this.state.config.activeTab == GENE_EXPRESSION_TAB) {
4201
- const cells = plot.expCells.length > 0 ? plot.expCells : plot.cells;
4202
- const xAxisScale = plot.xAxisScale.range([0, this.settings.svgw]);
4203
- const yAxisScale = plot.yAxisScale.range([this.settings.svgh, 0]);
4204
- let zAxisScale;
4205
- if (plot.expCells.length > 0) {
4206
- const [min, max2] = extent(plot.expCells, (d) => d.geneExp);
4207
- zAxisScale = linear().domain([min, max2]).range([0, 1]);
4208
- }
4209
- const xCoords = cells.map((c) => xAxisScale(c.x));
4210
- const yCoords = cells.map((c) => yAxisScale(c.y));
4211
- const zCoords = cells.map((c) => zAxisScale ? zAxisScale(c.geneExp) : 1);
4212
- await this.renderContourMap(scene, xCoords, yCoords, zCoords, plot);
4213
- }
4214
- const controls = new DragControls.DragControls([particles], camera, renderer.domElement);
4215
- function animate() {
4216
- requestAnimationFrame(animate);
4217
- renderer.render(scene, camera);
4218
- }
4219
- animate();
4220
- if (this.settings.showGrid) this.renderThreeGrid(scene);
4221
- };
4222
- async renderContourMap(scene, xCoords, yCoords, zCoords, plot) {
4223
- const data = xCoords.map((x, i) => ({ x, y: yCoords[i], z: zCoords[i] }));
4224
- const imageUrl = getContourImage(
4225
- data,
4226
- this.settings.svgw,
4227
- this.settings.svgh,
4228
- this.settings.colorContours,
4229
- this.settings.contourBandwidth,
4230
- this.settings.contourThresholds
4231
- );
4232
- const loader = new TextureLoader();
4233
- loader.load(imageUrl, (texture) => {
4234
- const geometry = new PlaneGeometry(2, 2);
4235
- const material = new MeshBasicMaterial({ map: texture, transparent: true, color: 1315860 });
4236
- const plane = new Mesh(geometry, material);
4237
- scene.add(plane);
4238
- plot.plane = plane;
4239
- plane.position.z = 1e-5;
4240
- plot.particles.add(plane);
4241
- });
4242
- }
4243
- renderThreeGrid(scene) {
4244
- let x = -1;
4245
- const lineMaterial = new LineBasicMaterial({ color: 4292072403 });
4246
- const lines = 10;
4247
- const step = 2 / lines;
4248
- for (let i = 0; i < lines; i++) {
4249
- let points = [];
4250
- points.push(new Vector3(x, 1.5, 0));
4251
- points.push(new Vector3(x, -1.5, 0));
4252
- let lineGeometry = new BufferGeometry().setFromPoints(points);
4253
- let line = new Line(lineGeometry, lineMaterial);
4254
- line.position.z = 1;
4255
- scene.add(line);
4256
- points = [];
4257
- points.push(new Vector3(-1.5, x, 0));
4258
- points.push(new Vector3(1.5, x, 0));
4259
- lineGeometry = new BufferGeometry().setFromPoints(points);
4260
- line = new Line(lineGeometry, lineMaterial);
4261
- scene.add(line);
4262
- x += step;
4263
- line.position.z = 1;
4264
- }
4265
- }
4266
- getVertices(plot) {
4267
- const vertices = [];
4268
- const colors = [];
4269
- for (const c of plot.cells) {
4270
- const opacity = this.getOpacity(c);
4271
- if (opacity == 0) continue;
4272
- let x = plot.xAxisScale(c.x);
4273
- let y = plot.yAxisScale(c.y);
4274
- const rgbColor = rgb(this.getColor(c, plot));
4275
- vertices.push(x, y, 0);
4276
- colors.push(rgbColor.r / 255, rgbColor.g / 255, rgbColor.b / 255);
4277
- }
4278
- return { vertices, colors };
4279
- }
4280
- };
4281
- function getContourImage(data, width, height, colorContours, bandwidth, thresholds) {
4282
- const svg = create_default("svg").attr("width", width).attr("height", height);
4283
- renderContours(svg.append("g"), data, width, height, colorContours, bandwidth, thresholds);
4284
- const svgString = new XMLSerializer().serializeToString(svg.node());
4285
- const encodedSvg = encodeURIComponent(svgString);
4286
- const imageUrl = "data:image/svg+xml;charset=utf-8," + encodedSvg;
4287
- return imageUrl;
4288
- }
4289
- function getMouseNDC(event, rect) {
4290
- return new Vector2(
4291
- (event.clientX - rect.left) / rect.width * 2 - 1,
4292
- -(event.clientY - rect.top) / rect.height * 2 + 1
4293
- );
4294
- }
4295
- var scatterInit = getCompInit(singleCellPlot);
4296
- var componentInit = scatterInit;
4297
- async function getPlotConfig(opts, app) {
4298
- try {
4299
- const data = app.vocabApi.termdbConfig?.queries?.singleCell?.data;
4300
- const plots = data?.plots;
4301
- let settings = getDefaultSingleCellSettings();
4302
- if (data.settings)
4303
- for (const key in data.settings) {
4304
- settings[key] = data.settings[key];
4305
- }
4306
- const config = {
4307
- hiddenClusters: {},
4308
- settings: {
4309
- singleCellPlot: settings,
4310
- controls: { isOpen: false }
4311
- },
4312
- startColor: {},
4313
- stopColor: {},
4314
- plots,
4315
- hidePlotFilter: true
4316
- };
4317
- const result = copyMerge(config, opts);
4318
- return result;
4319
- } catch (e) {
4320
- console.log(e);
4321
- throw `${e} [singleCellPlot getPlotConfig()]`;
4322
- }
4323
- }
4324
- function getDefaultSingleCellSettings() {
4325
- return {
4326
- svgw: 600,
4327
- svgh: 600,
4328
- showGrid: true,
4329
- sampleSize: 1.5,
4330
- sampleSizeThree: 0.04,
4331
- threeFOV: 60,
4332
- opacity: 0.8,
4333
- showNoExpCells: false,
4334
- showContour: false,
4335
- colorContours: false,
4336
- contourBandwidth: 15,
4337
- contourThresholds: 10,
4338
- uiLabels: {
4339
- // allow customized user interface labels (buttons, menus, etc) by dataset override,
4340
- // for example in GDC, use 'Case' instead of 'Sample'
4341
- // TODO: different plots should use the same uiLabels override,
4342
- // should not need to define separately for matrix, single cell, etc
4343
- Samples: "Samples",
4344
- samples: "samples",
4345
- Sample: "Sample",
4346
- sample: "sample"
4347
- },
4348
- colorScaleMode: "auto",
4349
- // Default to automatic scaling based on data range
4350
- // Other options: 'fixed' (user-defined range) or
4351
- // 'percentile' (scale based on data distribution)
4352
- colorScalePercentile: 95,
4353
- // Default percentile for percentile mode
4354
- // This means we'll scale colors based on values
4355
- // up to the 95th percentile by default
4356
- colorScaleMinFixed: null,
4357
- // User-defined minimum value for fixed mode
4358
- // Null indicates this hasn't been set yet
4359
- colorScaleMaxFixed: null
4360
- // User-defined maximum value for fixed mode
4361
- };
4362
- }
4363
-
4364
- export {
4365
- ScatterModelBase,
4366
- ScatterModel,
4367
- ScatterView,
4368
- ScatterViewModel,
4369
- ScatterViewModel2DLarge,
4370
- getThreeCircle,
4371
- getContourImage,
4372
- getMouseNDC,
4373
- scatterInit,
4374
- componentInit,
4375
- getPlotConfig,
4376
- getDefaultSingleCellSettings
4377
- };
4378
- //# sourceMappingURL=chunk-2EPEWVKQ.js.map