Source: main.js

  1. import * as UMAP from "https://esm.sh/umap-js@1.3.3";
  2. import * as Plotly from "https://cdn.jsdelivr.net/npm/plotly.js-dist/+esm";
  3. import * as am5 from "https://cdn.jsdelivr.net/npm/@amcharts/amcharts5/+esm";
  4. import * as am5hierarchy from "https://cdn.jsdelivr.net/npm/@amcharts/amcharts5/hierarchy/+esm";
  5. import * as am5themes_Animated from "https://cdn.jsdelivr.net/npm/@amcharts/amcharts5@5.3.7/themes/Animated.js/+esm";
  6. import { default as plotMSPrevalence } from "./mSigPortalScripts/client/src/components/controls/plotly/msPrevalence/msPrevalence.js";
  7. import { default as plotSignatureAssociation } from "./mSigPortalScripts/client/src/components/controls/plotly/msAssociation/msAssociation.js";
  8. import { default as plotMutationalProfileSBS96 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/sbs96.js";
  9. import { default as plotMutationalProfileSBS192 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/sbs192.js";
  10. import { default as plotMutationalProfileSBS288 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/sbs288.js";
  11. import { default as plotMutationalProfileSBS384 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/sbs384.js";
  12. import { default as plotMutationalProfileSBS1536 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/sbs1536.js";
  13. import { default as plotMutationalProfileDBS78 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/dbs78.js";
  14. import { default as plotMutationalProfileDBS186 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/dbs186.js";
  15. import { default as plotMutationalProfileID28 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/id28.js";
  16. import { default as plotMutationalProfileID29 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/id29.js";
  17. import { default as plotMutationalProfileID83 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/id83.js";
  18. import { default as plotMutationalProfileID415 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/id415.js";
  19. import { default as plotMutationalProfileRS32 } from "./mSigPortalScripts/client/src/components/controls/plotly/mutationalProfiles/rs32.js";
  20. import { default as plotMutationalProfileSBS96Comparison } from "./mSigPortalScripts/client/src/components/controls/plotly/profileComparison/sbs96.js";
  21. import { default as plotMutationalProfileSBS192Comparison } from "./mSigPortalScripts/client/src/components/controls/plotly/profileComparison/sbs192.js";
  22. import { default as plotMutationalProfileDBS78Comparison } from "./mSigPortalScripts/client/src/components/controls/plotly/profileComparison/dbs78.js";
  23. import { default as plotMutationalProfileID83Comparison } from "./mSigPortalScripts/client/src/components/controls/plotly/profileComparison/id83.js";
  24. import { default as plotMutationalProfileRS32Comparison } from "./mSigPortalScripts/client/src/components/controls/plotly/profileComparison/rs32.js";
  25. import { preprocessData, kFoldCV } from "./mSigSDKScripts/machineLearning.js";
  26. import {
  27. convertMatrix,
  28. convertWGStoPanel,
  29. init_sbs_mutational_spectra,
  30. convertMutationalSpectraIntoJSON,
  31. } from "./mSigSDKScripts/userData.js";
  32. import {
  33. linspace,
  34. deepCopy,
  35. nnls,
  36. formatHierarchicalClustersToAM5Format,
  37. groupBy,
  38. createDistanceMatrix,
  39. hierarchicalClustering,
  40. doubleClustering,
  41. cosineSimilarity,
  42. } from "./mSigSDKScripts/utils.js";
  43. import {
  44. getProjectsByGene,
  45. getTpmCountsByGenesOnProjects,
  46. getTpmCountsByGenesFromFiles,
  47. getMafInformationFromProjects,
  48. getVariantInformationFromMafFiles,
  49. convertTCGAProjectIntoJSON,
  50. } from "./mSigSDKScripts/tcga.js";
  51. // import every single function one by one from the mSigPortalAPIs.js file
  52. import {
  53. getMutationalSignaturesOptions,
  54. getMutationalSignaturesData,
  55. getMutationalSignaturesSummary,
  56. getMutationalSpectrumOptions,
  57. getMutationalSpectrumData,
  58. getMutationalSpectrumSummary,
  59. getMutationalSignatureAssociationOptions,
  60. getMutationalSignatureAssociationData,
  61. getMutationalSignatureActivityOptions,
  62. getMutationalSignatureActivityData,
  63. getMutationalSignatureLandscapeData,
  64. getMutationalSignatureEtiologyOptions,
  65. getMutationalSignatureEtiologyData,
  66. } from "./mSigSDKScripts/mSigPortalAPIs.js";
  67. // import * as mSigPortalPlotting from "./index.js";
  68. const mSigSDK = (function () {
  69. /**
  70. * @namespace mSigPortalData
  71. */
  72. /**
  73. * @namespace mSigPortalPlots
  74. */
  75. /**
  76. * @namespace machineLearning
  77. */
  78. /**
  79. * @namespace userData
  80. */
  81. /**
  82. * @namespace tcga
  83. */
  84. //#region Plot the summary of a dataset
  85. function plotGraphWithPlotlyAndMakeDataDownloadable(divID, data, layout) {
  86. // Plot the graph using Plotly
  87. Plotly.default.newPlot(divID, data, layout);
  88. // Ensure Font Awesome CSS is included
  89. const fontAwesomeLink =
  90. "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css";
  91. if (!document.querySelector(`link[href="${fontAwesomeLink}"]`)) {
  92. const link = document.createElement("link");
  93. link.rel = "stylesheet";
  94. link.href = fontAwesomeLink;
  95. document.head.appendChild(link);
  96. }
  97. // Get the container of the Plotly graph
  98. const container = document.getElementById(divID);
  99. // Ensure the container has a relative position
  100. container.style.position = "relative";
  101. // Create a download button with only the Font Awesome download icon
  102. const downloadBtn = document.createElement("div");
  103. downloadBtn.innerHTML =
  104. '<button class="btn"><i class="fa fa-download"></i></button>';
  105. const btn = downloadBtn.firstChild;
  106. // Position the button at the bottom right corner of the container
  107. btn.style.position = "absolute";
  108. btn.style.bottom = "0";
  109. btn.style.right = "0";
  110. // Add an event listener to handle the download action
  111. btn.addEventListener("click", function () {
  112. const graphData = {
  113. traces: data,
  114. layout: layout,
  115. };
  116. const blob = new Blob([JSON.stringify(graphData, null, 2)], {
  117. type: "application/json",
  118. });
  119. const url = URL.createObjectURL(blob);
  120. const a = document.createElement("a");
  121. a.href = url;
  122. a.download = "graph_data.json";
  123. a.click();
  124. URL.revokeObjectURL(url);
  125. });
  126. // Append the download button to the container
  127. container.appendChild(btn);
  128. // Add the provided CSS
  129. const css = `
  130. .btn {
  131. background-color: DodgerBlue;
  132. border: none;
  133. border-radius: 100%;
  134. color: white;
  135. padding: 12px 12px;
  136. cursor: pointer;
  137. font-size: 20px;
  138. }
  139. .btn:hover {
  140. background-color: RoyalBlue;
  141. }
  142. `;
  143. const style = document.createElement("style");
  144. style.type = "text/css";
  145. style.appendChild(document.createTextNode(css));
  146. document.head.appendChild(style);
  147. }
  148. /**
  149. Generates a mutational spectrum summary plot and displays it in a given HTML div element.
  150. @async
  151. @function plotProfilerSummary
  152. @memberof mSigPortalPlots
  153. @param {string} [studyName="PCAWG"] - The name of the cancer genomics study to use. Default is "PCAWG".
  154. @param {string} [genomeDataType="WGS"] - The type of genomic data to use. Default is "WGS".
  155. @param {string} [cancerTypeOrGroup="Lung-AdenoCA"] - The cancer type or group to display. Default is "Lung-AdenoCA".
  156. @param {number} [numberOfResults=50] - The maximum number of results to display. Default is 50.
  157. @param {string} [divID="mutationalSpectrumSummary"] - The ID of the HTML div element where the plot will be displayed. Default is "mutationalSpectrumSummary".
  158. @returns {Promise<void>} A Promise that resolves when the plot is displayed or rejects if there is an error.
  159. @throws {Error} If there is an error retrieving or displaying the plot, this function will throw an Error with a message describing the error.
  160. */
  161. // This function plots the mutational spectrum summary for the given parameters.
  162. // Input:
  163. // - studyName: Name of the study for which the data is to be fetched
  164. // - genomeDataType: Type of the genome data to be fetched
  165. // - cancerTypeOrGroup: Cancer type or group for which the data is to be fetched
  166. // - numberOfResults: Number of results to be fetched
  167. // Output: A mutational spectrum summary plot of the given parameters
  168. async function plotProfilerSummary(
  169. studyName = "PCAWG",
  170. genomeDataType = "WGS",
  171. cancerTypeOrGroup = "Lung-AdenoCA",
  172. numberOfResults = 50,
  173. divID = "mutationalSpectrumSummary"
  174. ) {
  175. try {
  176. const summary = await getMutationalSpectrumSummary(
  177. studyName,
  178. genomeDataType,
  179. cancerTypeOrGroup,
  180. numberOfResults
  181. );
  182. let data = await getBarPlotData(summary);
  183. if (data.length == 0) {
  184. // $(`#${divID}`).html(
  185. // `<p style="color:red">Error: no data available for the selected parameters.</p>`
  186. // );
  187. } else {
  188. let layout = {
  189. title: `${studyName} ${cancerTypeOrGroup} ${genomeDataType} Mutational Spectrum Summary`,
  190. xaxis: {
  191. title: "Sample",
  192. },
  193. yaxis: {
  194. title: "Log (Number of Mutations)",
  195. },
  196. barmode: "stack",
  197. };
  198. plotGraphWithPlotlyAndMakeDataDownloadable(divID, data, layout);
  199. }
  200. } catch (err) {
  201. console.error(err);
  202. $(`#${divID}`).html(`<p>Error: ${err.message}</p>`);
  203. }
  204. }
  205. async function getBarPlotData(summary) {
  206. let data = [];
  207. for (let i = 0; i < summary.length; i++) {
  208. if (
  209. !data.some(
  210. (e) => e.name === summary[i]["profile"] + `: ${summary[i]["matrix"]}`
  211. )
  212. ) {
  213. data.push({
  214. x: [summary[i]["sample"]],
  215. y: [summary[i]["logTotalMutations"]],
  216. text: [parseInt(summary[i]["meanTotalMutations"])],
  217. type: "bar",
  218. name: summary[i]["profile"] + `: ${summary[i]["matrix"]}`,
  219. marker: {
  220. color: summary[i].color,
  221. },
  222. });
  223. } else {
  224. let existingData = data.find(
  225. (e) => e.name === summary[i]["profile"] + `: ${summary[i]["matrix"]}`
  226. );
  227. existingData.x.push(summary[i]["sample"]);
  228. existingData.y.push(summary[i]["logTotalMutations"]);
  229. existingData.text.push(parseInt(summary[i]["meanTotalMutations"]));
  230. }
  231. }
  232. return data;
  233. }
  234. // This function plots the mutational spectrum mutational count as boxplots for each cancer type for the given dataset.
  235. /**
  236. Plots the mutational burden by cancer type for a given project.
  237. @async
  238. @function plotProjectMutationalBurdenByCancerType
  239. @memberof mSigPortalPlots
  240. @param {Object} project - An object containing mutational data for different cancer types.
  241. @param {string} divID - The ID of the div where the plot should be displayed.
  242. @returns {Promise} - A Promise that resolves when the plot is displayed.
  243. @example
  244. // Example usage:
  245. plotProjectMutationalBurdenByCancerType(projectData, "plotDiv");
  246. */
  247. async function plotProjectMutationalBurdenByCancerType(project, divID) {
  248. project = groupBy(project, "cancer");
  249. Object.keys(project).forEach(function (key, index) {
  250. project[key] = groupBy(project[key], "sample");
  251. Object.keys(project[key]).forEach(function (patient, index) {
  252. project[key][patient] = Object.values(
  253. extractMutationalSpectra(project[key][patient], "sample")
  254. )[0];
  255. });
  256. });
  257. // Loop through all the cancertypes in project and create a trace for each cancer type and add it to the data array
  258. const cancerTypes = Object.keys(project);
  259. const data = [];
  260. const boxColor = {};
  261. const allColors = linspace(0, 360, cancerTypes.length);
  262. for (var i = 0; i < cancerTypes.length - 1; i++) {
  263. var result = "hsl(" + allColors[i] + ",50%" + ",50%)";
  264. boxColor[cancerTypes[i]] = result;
  265. }
  266. for (let cancerType of cancerTypes) {
  267. const cancerTypeData = Object.values(project[cancerType]);
  268. const trace = {
  269. // x: Object.keys(project[cancerType]),
  270. y: Object.values(cancerTypeData).map((e) =>
  271. Math.log10(Object.values(e).reduce((a, b) => a + b, 0))
  272. ),
  273. type: "box",
  274. name: cancerType,
  275. marker: {
  276. color: boxColor[cancerType],
  277. },
  278. boxpoints: "Outliers",
  279. };
  280. data.push(trace);
  281. }
  282. const layout = {
  283. title: `Mutational Burden by Cancer Type`,
  284. xaxis: {
  285. title: "Cancer Type",
  286. type: "category",
  287. automargin: true,
  288. },
  289. yaxis: {
  290. title: "Log (Number of Mutations)",
  291. },
  292. barmode: "stack",
  293. height: 600,
  294. };
  295. plotGraphWithPlotlyAndMakeDataDownloadable(divID, data, layout);
  296. }
  297. //#endregion
  298. //#region Plot a patient's mutational spectra
  299. /**
  300. * Plots the mutational spectrum for the given parameters.
  301. * @async
  302. * @function plotPatientMutationalSpectrumuserData
  303. * @memberof mSigPortalPlots
  304. * @param {Object} mutationalSpectra - An object containing the mutational spectra data.
  305. * @param {number} [matrixSize=96] - The size of the matrix to be plotted.
  306. * @param {string} [divID="mutationalSpectrumMatrix"] - The ID of the div element where the plot will be displayed.
  307. */
  308. async function plotPatientMutationalSpectrumuserData(
  309. mutationalSpectra,
  310. matrixSize = 96,
  311. divID = "mutationalSpectrumMatrix"
  312. ) {
  313. const numberOfPatients = Object.keys(mutationalSpectra).length;
  314. if (numberOfPatients == 0) {
  315. $(`#${divID}`).html(
  316. `<p style="color:red">Error: no data available for the selected parameters.</p>`
  317. );
  318. } else if (numberOfPatients > 1) {
  319. const layout = {
  320. title: `Mutational Spectra for ${Object.keys(mutationalSpectra).join(
  321. ", "
  322. )}`,
  323. xaxis: { title: "Mutation Type" },
  324. yaxis: { title: "Count" },
  325. barmode: "group",
  326. };
  327. const traces = Object.keys(mutationalSpectra).map((patient) => ({
  328. x: Object.keys(mutationalSpectra[patient]),
  329. y: Object.values(mutationalSpectra[patient]),
  330. name: `${patient}`,
  331. type: "bar",
  332. }));
  333. plotGraphWithPlotlyAndMakeDataDownloadable(divID, traces, layout);
  334. } else {
  335. let traces = [];
  336. const layout = {
  337. title: `Mutational Spectra for ${Object.keys(mutationalSpectra).join(
  338. ", "
  339. )}`,
  340. xaxis: { title: "Mutation Type" },
  341. yaxis: { title: "Count" },
  342. barmode: "group",
  343. };
  344. for (let i = 0; i < Object.keys(mutationalSpectra).length; i++) {
  345. let plotlyData = formatMutationalSpectraData(
  346. mutationalSpectra[Object.keys(mutationalSpectra)[i]],
  347. Object.keys(mutationalSpectra)[i]
  348. );
  349. traces = traces.concat(plotlyData);
  350. }
  351. plotGraphWithPlotlyAndMakeDataDownloadable(divID, traces, layout);
  352. }
  353. }
  354. /**
  355. Renders a plot of the mutational spectra for one or more patients in a given div element ID using Plotly.
  356. @async
  357. @function plotPatientMutationalSpectrum
  358. @memberof mSigPortalPlots
  359. @param {Object} mutationalSpectra - An object containing the mutational spectra data for one or more patients.
  360. @param {number} [matrixSize=96] - The size of the plot matrix. Defaults to 96.
  361. @param {string} [divID='mutationalSpectrumMatrix'] - The ID of the div element to render the plot in. Defaults to 'mutationalSpectrumMatrix'.
  362. @returns {Promise<void>} A promise that resolves when the plot has been rendered.
  363. @throws {Error} An error is thrown if no data is available for the selected parameters.
  364. */
  365. // This function plots the mutational spectrum for the given parameters.
  366. async function plotPatientMutationalSpectrum(
  367. mutationalSpectra,
  368. divID = "mutationalSpectrumMatrix"
  369. ) {
  370. let matrixSize = mutationalSpectra[0].length;
  371. let mutationType = mutationalSpectra[0][0].profile;
  372. const numberOfPatients = Object.keys(mutationalSpectra).length;
  373. console.log(numberOfPatients, mutationType, matrixSize);
  374. if (numberOfPatients == 0) {
  375. $(`#${divID}`).html(
  376. `<p style="color:red">Error: no data available for the selected parameters.</p>`
  377. );
  378. } else if (
  379. numberOfPatients > 2 &&
  380. matrixSize == 96 &&
  381. mutationType == "SBS"
  382. ) {
  383. mutationalSpectra = extractMutationalSpectra(mutationalSpectra);
  384. const layout = {
  385. title: `Mutational Spectra for ${Object.keys(mutationalSpectra).join(
  386. ", "
  387. )}`,
  388. xaxis: { title: "Mutation Type" },
  389. yaxis: { title: "Count" },
  390. barmode: "group",
  391. };
  392. const traces = Object.keys(mutationalSpectra).map((patient) => ({
  393. x: Object.keys(mutationalSpectra[patient]),
  394. y: Object.values(mutationalSpectra[patient]),
  395. name: `${patient}`,
  396. type: "bar",
  397. }));
  398. plotGraphWithPlotlyAndMakeDataDownloadable(divID, traces, layout);
  399. } else if (
  400. numberOfPatients == 2 &&
  401. matrixSize == 96 &&
  402. mutationType == "SBS"
  403. ) {
  404. let traces = plotMutationalProfileSBS96Comparison(
  405. mutationalSpectra[0],
  406. mutationalSpectra[1]
  407. );
  408. plotGraphWithPlotlyAndMakeDataDownloadable(
  409. divID,
  410. traces.traces,
  411. traces.layout
  412. );
  413. return traces;
  414. } else if (
  415. numberOfPatients == 1 &&
  416. matrixSize == 96 &&
  417. mutationType == "SBS"
  418. ) {
  419. let traces = plotMutationalProfileSBS96(mutationalSpectra[0]);
  420. plotGraphWithPlotlyAndMakeDataDownloadable(
  421. divID,
  422. traces.traces,
  423. traces.layout
  424. );
  425. return traces;
  426. } else if (
  427. numberOfPatients == 1 &&
  428. matrixSize == 192 &&
  429. mutationType == "SBS"
  430. ) {
  431. let traces = plotMutationalProfileSBS192(mutationalSpectra[0]);
  432. plotGraphWithPlotlyAndMakeDataDownloadable(
  433. divID,
  434. traces.traces,
  435. traces.layout
  436. );
  437. return traces;
  438. } else if (
  439. numberOfPatients == 2 &&
  440. matrixSize == 192 &&
  441. mutationType == "SBS"
  442. ) {
  443. let traces = plotMutationalProfileSBS192Comparison(
  444. mutationalSpectra[0],
  445. mutationalSpectra[1]
  446. );
  447. plotGraphWithPlotlyAndMakeDataDownloadable(
  448. divID,
  449. traces.traces,
  450. traces.layout
  451. );
  452. return traces;
  453. } else if (
  454. numberOfPatients == 1 &&
  455. matrixSize == 288 &&
  456. mutationType == "SBS"
  457. ) {
  458. let traces = plotMutationalProfileSBS288(mutationalSpectra[0]);
  459. plotGraphWithPlotlyAndMakeDataDownloadable(
  460. divID,
  461. traces.traces,
  462. traces.layout
  463. );
  464. return traces;
  465. } else if (
  466. numberOfPatients == 1 &&
  467. matrixSize == 384 &&
  468. mutationType == "SBS"
  469. ) {
  470. let traces = plotMutationalProfileSBS384(mutationalSpectra[0]);
  471. plotGraphWithPlotlyAndMakeDataDownloadable(
  472. divID,
  473. traces.traces,
  474. traces.layout
  475. );
  476. return traces;
  477. } else if (
  478. numberOfPatients == 1 &&
  479. matrixSize == 1536 &&
  480. mutationType == "SBS"
  481. ) {
  482. let traces = plotMutationalProfileSBS1536(mutationalSpectra[0]);
  483. plotGraphWithPlotlyAndMakeDataDownloadable(
  484. divID,
  485. traces.traces,
  486. traces.layout
  487. );
  488. return traces;
  489. } else if (
  490. numberOfPatients == 1 &&
  491. matrixSize == 78 &&
  492. mutationType == "DBS"
  493. ) {
  494. let traces = plotMutationalProfileDBS78(mutationalSpectra[0]);
  495. plotGraphWithPlotlyAndMakeDataDownloadable(
  496. divID,
  497. traces.traces,
  498. traces.layout
  499. );
  500. return traces;
  501. } else if (
  502. numberOfPatients == 2 &&
  503. matrixSize == 78 &&
  504. mutationType == "DBS"
  505. ) {
  506. let traces = plotMutationalProfileDBS78Comparison(
  507. mutationalSpectra[0],
  508. mutationalSpectra[1],
  509. "pc"
  510. );
  511. plotGraphWithPlotlyAndMakeDataDownloadable(
  512. divID,
  513. traces.traces,
  514. traces.layout
  515. );
  516. return traces;
  517. } else if (
  518. numberOfPatients == 1 &&
  519. matrixSize == 186 &&
  520. mutationType == "DBS"
  521. ) {
  522. let traces = plotMutationalProfileDBS186(mutationalSpectra[0]);
  523. plotGraphWithPlotlyAndMakeDataDownloadable(
  524. divID,
  525. traces.traces,
  526. traces.layout
  527. );
  528. return traces;
  529. } else if (
  530. numberOfPatients == 1 &&
  531. matrixSize == 28 &&
  532. mutationType == "ID"
  533. ) {
  534. let traces = plotMutationalProfileID28(mutationalSpectra[0]);
  535. plotGraphWithPlotlyAndMakeDataDownloadable(
  536. divID,
  537. traces.traces,
  538. traces.layout
  539. );
  540. return traces;
  541. } else if (
  542. numberOfPatients == 1 &&
  543. matrixSize == 29 &&
  544. mutationType == "ID"
  545. ) {
  546. let traces = plotMutationalProfileID29(mutationalSpectra[0]);
  547. plotGraphWithPlotlyAndMakeDataDownloadable(
  548. divID,
  549. traces.traces,
  550. traces.layout
  551. );
  552. return traces;
  553. } else if (
  554. numberOfPatients == 1 &&
  555. matrixSize == 83 &&
  556. mutationType == "ID"
  557. ) {
  558. let traces = plotMutationalProfileID83(mutationalSpectra[0]);
  559. plotGraphWithPlotlyAndMakeDataDownloadable(
  560. divID,
  561. traces.traces,
  562. traces.layout
  563. );
  564. return traces;
  565. } else if (
  566. numberOfPatients == 2 &&
  567. matrixSize == 83 &&
  568. mutationType == "ID"
  569. ) {
  570. let traces = plotMutationalProfileID83Comparison(
  571. mutationalSpectra[0],
  572. mutationalSpectra[1],
  573. "pc"
  574. );
  575. plotGraphWithPlotlyAndMakeDataDownloadable(
  576. divID,
  577. traces.traces,
  578. traces.layout
  579. );
  580. return traces;
  581. } else if (
  582. numberOfPatients == 1 &&
  583. matrixSize == 415 &&
  584. mutationType == "ID"
  585. ) {
  586. let traces = plotMutationalProfileID415(mutationalSpectra[0]);
  587. plotGraphWithPlotlyAndMakeDataDownloadable(
  588. divID,
  589. traces.traces,
  590. traces.layout
  591. );
  592. return traces;
  593. } else if (
  594. numberOfPatients == 1 &&
  595. matrixSize == 32 &&
  596. mutationType == "RS"
  597. ) {
  598. let traces = plotMutationalProfileRS32(mutationalSpectra[0]);
  599. plotGraphWithPlotlyAndMakeDataDownloadable(
  600. divID,
  601. traces.traces,
  602. traces.layout
  603. );
  604. return traces;
  605. } else if (
  606. numberOfPatients == 2 &&
  607. matrixSize == 32 &&
  608. mutationType == "RS"
  609. ) {
  610. let traces = plotMutationalProfileRS32Comparison(
  611. mutationalSpectra[0],
  612. mutationalSpectra[1]
  613. );
  614. plotGraphWithPlotlyAndMakeDataDownloadable(
  615. divID,
  616. traces.traces,
  617. traces.layout
  618. );
  619. return traces;
  620. } else {
  621. let traces = [];
  622. const layout = {
  623. title: `Mutational Spectra for ${Object.keys(mutationalSpectra).join(
  624. ", "
  625. )}`,
  626. xaxis: { title: "Mutation Type" },
  627. yaxis: { title: "Count" },
  628. barmode: "group",
  629. };
  630. for (let i = 0; i < Object.keys(mutationalSpectra).length; i++) {
  631. let plotlyData = formatMutationalSpectraData(
  632. mutationalSpectra[Object.keys(mutationalSpectra)[i]],
  633. Object.keys(mutationalSpectra)[i]
  634. );
  635. traces = traces.concat(plotlyData);
  636. }
  637. plotGraphWithPlotlyAndMakeDataDownloadable(divID, traces, layout);
  638. }
  639. }
  640. /**
  641. * Converts the mutational spectra data to a format that can be used to create a Plotly chart.
  642. * @function formatMutationalSpectraData
  643. * @memberof mSigPortalData
  644. * @param {Object} mutationalSpectrum - An object containing the mutational spectra data.
  645. * @param {string} sample - The name of the sample.
  646. * @returns {Object[]} The data in a format that can be used to create a Plotly chart. The data is an array of objects. Each object has a name, x, y, and type property. The name property is the name of the mutation type. The x property is an array of the mutation names. The y property is an array of the mutation frequencies. The type property is the type of substitution that takes place.
  647. */
  648. function formatMutationalSpectraData(mutationalSpectrum, sample) {
  649. const matrixSize = Object.keys(mutationalSpectrum).length;
  650. if (matrixSize === 96) {
  651. const substitutionTypes = ["C>A", "C>G", "C>T", "T>A", "T>C", "T>G"];
  652. const data = substitutionTypes.map((substitutionType) => {
  653. return {
  654. name: `${substitutionType} ${sample}`,
  655. x: [],
  656. y: [],
  657. type: "bar",
  658. };
  659. });
  660. substitutionTypes.forEach((substitutionType) => {
  661. Object.keys(mutationalSpectrum)
  662. .filter((key) => {
  663. return key.includes(substitutionType);
  664. })
  665. .forEach((key) => {
  666. data
  667. .find((e) => e.name === `${substitutionType} ${sample}`)
  668. .x.push(key);
  669. data
  670. .find((e) => e.name === `${substitutionType} ${sample}`)
  671. .y.push(mutationalSpectrum[key]);
  672. });
  673. });
  674. return data;
  675. } else if (matrixSize === 192) {
  676. console.error("Not supported yet");
  677. } else if (matrixSize === 1536) {
  678. console.error("Not supported yet");
  679. } else {
  680. console.error("Invalid Matrix Size");
  681. }
  682. }
  683. //#endregion
  684. //#region Creates a force directed tree of the patients in the study based on their mutational spectra
  685. /**
  686. * Extracts the mutational spectra out of the mSigPortal API call.
  687. * @function extractMutationalSpectra
  688. * @memberof mSigPortalData
  689. * @param {Object[]} data - An array of objects containing the data from the mSigPortal API call.
  690. * @param {string} [groupName="sample"] - The name of the group to extract the mutational spectra from.
  691. * @returns {Object} An object containing the mutational spectra data grouped by the specified group name.
  692. */
  693. function extractMutationalSpectra(data, groupName = "sample") {
  694. data = data.flat();
  695. // Group all of the dictionaries in the data array by sample name
  696. let groupedData = groupBy(data, groupName);
  697. // Converts the grouped data into mutational spectrum dictionaries that can be used to create a force directed tree.
  698. Object.keys(groupedData).forEach(function (key) {
  699. let mutationalSpectrum = init_sbs_mutational_spectra();
  700. groupedData[key].forEach((mutation) => {
  701. let mutationType = mutation["mutationType"];
  702. if (groupName == "sample") {
  703. mutationalSpectrum[mutationType] = mutation["mutations"];
  704. } else if (groupName == "signatureName") {
  705. mutationalSpectrum[mutationType] = mutation["contribution"];
  706. } else {
  707. console.error("Invalid group name");
  708. }
  709. });
  710. groupedData[key] = mutationalSpectrum;
  711. });
  712. return groupedData;
  713. }
  714. /**
  715. * @async
  716. * @function plotCosineSimilarityHeatMap
  717. * @description Generates a cosine similarity heatmap based on mutational spectra data.
  718. * This function processes grouped mutational data to compute cosine similarities,
  719. * optionally performs double clustering to reorder the data, and then visualizes
  720. * the similarities using a Plotly heatmap. It also supports displaying a table
  721. * representation of the cosine similarity matrix alongside the heatmap.
  722. * @memberof mSigPortalPlots
  723. * @param {Object} groupedData - The input data object where keys represent sample names
  724. * and values are objects representing mutational spectra. The mutational spectra
  725. * should be represented as key-value pairs where keys are mutation types and values
  726. * are counts or frequencies.
  727. * Example:
  728. * ```
  729. * {
  730. * 'Sample1': {'C>A': 10, 'C>G': 15, 'C>T': 20, ...},
  731. * 'Sample2': {'C>A': 5, 'C>G': 8, 'C>T': 12, ...},
  732. * ...
  733. * }
  734. * ```
  735. * The range of keys (mutation types) should be consistent across all samples. The values
  736. * (counts or frequencies) can be integers or floats, and their range can vary based on the
  737. * underlying data, but typically they are non-negative.
  738. *
  739. * @param {string} [studyName="PCAWG"] - The name of the study. This is used in the
  740. * title of the heatmap. Common values include study identifiers like "PCAWG",
  741. * "TCGA", or specific project names. The parameter should be a string and can
  742. * technically accept any string value, but it is intended to represent the name
  743. * of a study or dataset.
  744. *
  745. * @param {string} [genomeDataType="WGS"] - The type of genomic data. This is also
  746. * used in the title of the heatmap. Expected values typically include abbreviations
  747. * for common genomic data types such as "WGS" (Whole Genome Sequencing), "WES"
  748. * (Whole Exome Sequencing), "RNA-Seq", etc. Similar to `studyName`, any string
  749. * is technically accepted, but the intended use is to describe the data type.
  750. *
  751. * @param {string} [cancerType="Lung-AdenoCA"] - The type of cancer. This is included
  752. * in the title of the heatmap. Common values are standard cancer type
  753. * abbreviations or names, like "Lung-AdenoCA" (Lung Adenocarcinoma), "BRCA"
  754. * (Breast Invasive Carcinoma), etc. Any string value is accepted, but it should
  755. * represent a specific cancer type.
  756. *
  757. * @param {string} [divID="cosineSimilarityHeatMap"] - The ID of the HTML element where
  758. * the heatmap will be rendered. This should be a valid HTML element ID. If an element
  759. * with this ID does not exist, one will be created and appended to the document body.
  760. * Any string is accepted, but it should correspond to a unique ID in the HTML
  761. * document to avoid conflicts.
  762. *
  763. * @param {boolean} [conductDoubleClustering=true] - A flag indicating whether to
  764. * perform double clustering (hierarchical clustering on both rows and columns)
  765. * on the cosine similarity matrix. If `true`, the rows and columns of the heatmap
  766. * will be reordered based on the clustering. If `false`, the order of samples in
  767. * `groupedData` will be maintained. Boolean values `true` or `false` are expected.
  768. *
  769. * @param {string} [colorscale="RdBu"] - The Plotly colorscale to use for the heatmap.
  770. * This can be any valid Plotly colorscale name (e.g., "Viridis", "Greys", "YlGnBu",
  771. * "RdBu"). Plotly provides a wide range of predefined colorscales. The chosen
  772. * colorscale will affect the visual representation of the similarity values. Any
  773. * string is accepted but it should correspond to a valid Plotly colorscale for
  774. * optimal results.
  775. *
  776. * @param {boolean} [showTable=false] - A flag indicating whether to display a table
  777. * representation of the cosine similarity matrix alongside the heatmap. If `true`,
  778. * a table will be rendered next to the heatmap. If `false`, only the heatmap will
  779. * be displayed. Boolean values `true` or `false` are expected.
  780. *
  781. * @returns {Promise<number[][]>} A Promise that resolves to the cosine similarity matrix.
  782. * The matrix is a two-dimensional array of numbers, where each number represents
  783. * the cosine similarity between two samples. The values range from 0 to 1, where 1
  784. * indicates perfect similarity and 0 indicates no similarity. The dimensions of
  785. * the matrix will be NxN, where N is the number of samples in `groupedData`.
  786. *
  787. * @throws Will throw an error if the `cosineSimilarity` function or the
  788. * `plotGraphWithPlotlyAndMakeDataDownloadable` function throws an error.
  789. *
  790. */
  791. async function plotCosineSimilarityHeatMap(
  792. groupedData,
  793. studyName = "PCAWG",
  794. genomeDataType = "WGS",
  795. cancerType = "Lung-AdenoCA",
  796. divID = "cosineSimilarityHeatMap",
  797. conductDoubleClustering = true,
  798. colorscale = "RdBu",
  799. showTable = false
  800. ) {
  801. let container = document.getElementById(divID);
  802. if (!container) {
  803. container = document.createElement('div');
  804. container.id = divID;
  805. document.body.appendChild(container);
  806. }
  807. container.innerHTML = '';
  808. container.style.display = 'flex';
  809. container.style.flexDirection = showTable ? 'row' : 'column';
  810. container.style.gap = '20px';
  811. container.style.width = '100%';
  812. container.style.alignItems = 'center'; // Center items vertically
  813. const heatmapDiv = document.createElement('div');
  814. heatmapDiv.id = `${divID}-heatmap`;
  815. heatmapDiv.style.flex = showTable ? '1' : '1';
  816. container.appendChild(heatmapDiv);
  817. groupedData = extractMutationalSpectra(groupedData);
  818. let distanceMatrix = await createDistanceMatrix(
  819. Object.values(groupedData).map((data) => Object.values(data)),
  820. cosineSimilarity,
  821. true
  822. );
  823. let cosSimilarityMatrix = distanceMatrix.map(function (row) {
  824. return row.map(function (cell) {
  825. return 1 - cell;
  826. });
  827. });
  828. let reorderedData;
  829. if (conductDoubleClustering) {
  830. reorderedData = doubleClustering(
  831. cosSimilarityMatrix,
  832. Object.keys(groupedData),
  833. Object.keys(groupedData)
  834. );
  835. } else {
  836. reorderedData = {
  837. matrix: cosSimilarityMatrix,
  838. rowNames: Object.keys(groupedData),
  839. colNames: Object.keys(groupedData),
  840. };
  841. }
  842. let plotlyData = [
  843. {
  844. z: reorderedData.matrix,
  845. x: reorderedData.rowNames,
  846. y: reorderedData.colNames,
  847. type: "heatmap",
  848. colorscale: colorscale,
  849. },
  850. ];
  851. let layout = {
  852. title: `${studyName} ${cancerType} ${genomeDataType} Cosine Similarity Heatmap`,
  853. height: 800,
  854. width: showTable ? container.offsetWidth * 0.6 : container.offsetWidth,
  855. xaxis: {
  856. title: "Sample",
  857. type: "category",
  858. nticks: Object.keys(groupedData).length,
  859. },
  860. yaxis: {
  861. title: "Sample",
  862. type: "category",
  863. nticks: Object.keys(groupedData).length,
  864. },
  865. };
  866. plotGraphWithPlotlyAndMakeDataDownloadable(heatmapDiv.id, plotlyData, layout);
  867. if (showTable) {
  868. const tableDiv = document.createElement('div');
  869. tableDiv.id = `${divID}-table`;
  870. tableDiv.style.flex = '1';
  871. tableDiv.style.overflowX = 'auto';
  872. tableDiv.style.display = 'flex'; // Add flex display
  873. tableDiv.style.alignItems = 'center'; // Center vertically
  874. tableDiv.style.height = '800px'; // Match heatmap height
  875. container.appendChild(tableDiv);
  876. const tableWrapper = document.createElement('div'); // Add wrapper for table
  877. tableWrapper.style.width = '100%';
  878. tableDiv.appendChild(tableWrapper);
  879. const table = document.createElement('table');
  880. table.style.borderCollapse = 'collapse';
  881. table.style.width = '100%';
  882. table.style.fontSize = '12px';
  883. // Create header row with simple styling
  884. const thead = document.createElement('thead');
  885. const headerRow = document.createElement('tr');
  886. headerRow.innerHTML = '<th style="border: 1px solid #ddd; padding: 8px; background-color: #f8f9fa;">Sample</th>';
  887. reorderedData.colNames.forEach(colName => {
  888. headerRow.innerHTML += `<th style="border: 1px solid #ddd; padding: 8px; background-color: #f8f9fa;">${colName}</th>`;
  889. });
  890. thead.appendChild(headerRow);
  891. table.appendChild(thead);
  892. // Create table body with simple styling
  893. const tbody = document.createElement('tbody');
  894. reorderedData.matrix.forEach((row, rowIndex) => {
  895. const tr = document.createElement('tr');
  896. tr.innerHTML = `<td style="border: 1px solid #ddd; padding: 8px; font-weight: bold;">${reorderedData.rowNames[rowIndex]}</td>`;
  897. row.forEach(value => {
  898. const formattedValue = value.toFixed(3);
  899. tr.innerHTML += `<td style="border: 1px solid #ddd; padding: 8px; text-align: center;">${formattedValue}</td>`;
  900. });
  901. tbody.appendChild(tr);
  902. });
  903. table.appendChild(tbody);
  904. tableWrapper.appendChild(table);
  905. }
  906. return cosSimilarityMatrix;
  907. }
  908. /**
  909. * @memberof mSigPortalPlots
  910. * @function plotSignatureActivityDataBy
  911. * @description Generates a box plot of signature activity data, grouped by a specified attribute. The function takes a dataset and groups it by the provided attribute (e.g., "signatureName", "study", "cancerType"). For each group, it creates a box trace where the y-values represent the log10 of the exposure values and the x-values are set to the group name. The box plot displays the distribution of exposure values for each group, with the option to show all individual data points (jittered for better visibility). Hovering over the data points reveals the sample name and the log10 of the exposure value. The plot also indicates the fraction of samples within each group that have non-zero exposure.
  912. *
  913. * @param {string} divID - The ID of the div element where the plot will be rendered.
  914. * @param {Array<object>} data - An array of objects representing the signature activity data. Each object must have at least the following properties:
  915. * - `exposure`: A numeric value representing the exposure of a signature. It can be any positive number or zero.
  916. * - `sample`: A string representing the sample ID.
  917. * - The `data` array must also contain a property matching the name specified by the `group` parameter (e.g., "signatureName", "study", "cancerType").
  918. * @param {string} [group="signatureName"] - The attribute to group the data by. Possible values are any property name present in the data objects, including, but not limited to:
  919. * - `"signatureName"`: Groups the data by signature names.
  920. * - `"study"`: Groups the data by study IDs.
  921. * - `"cancerType"`: Groups the data by cancer types.
  922. * - `"sample"`: Groups the data by sample IDs (Note: this might not result in a meaningful box plot).
  923. * - Any other custom property that exists in the data objects.
  924. * The default value is `"signatureName"`.
  925. * @return {void} - This function does not return a value. It directly renders the plot in the specified `divID`.
  926. */
  927. function plotSignatureActivityDataBy(divID, data, group = "signatureName") {
  928. // Group the data by the specified group using the groupBy function
  929. const groupedData = groupBy(data, group);
  930. // Create an array of box trace objects for each group
  931. const groupTraces = Object.keys(groupedData).map((groupName) => {
  932. const exposures = groupedData[groupName].map((d) =>
  933. Math.log10(d.exposure)
  934. );
  935. const samples = groupedData[groupName].map((d) => d.sample);
  936. const numNonZero = exposures.filter(
  937. (exposure) => exposure !== -Infinity
  938. ).length;
  939. return {
  940. y: exposures,
  941. x: new Array(exposures.length).fill(groupName),
  942. type: "box",
  943. name: groupName,
  944. boxpoints: "all",
  945. jitter: 0.3,
  946. hovertext: samples,
  947. hovertemplate:
  948. `<b>${groupName}</b><br>Log(Exposure): %{y:.2f}<br>` +
  949. `Fraction of samples with non-zero exposure: ${numNonZero} / ${exposures.length}`,
  950. };
  951. });
  952. // Plot the box traces using Plotly and display the plot in the specified divID
  953. plotGraphWithPlotlyAndMakeDataDownloadable(divID, groupTraces, {
  954. title: `Cumulative Exposure for ${group}`,
  955. yaxis: { title: "Log(Exposure)" },
  956. xaxis: { title: group },
  957. });
  958. }
  959. /**
  960. * @memberof mSigPortalPlots
  961. * @function plotForceDirectedTree
  962. * @description This function generates and displays a force-directed tree representing the relationships between patients in a study based on their mutational spectra. It calculates the cosine similarity between the mutational spectra of patients, performs hierarchical clustering based on these similarities, and then visualizes the resulting clusters as a force-directed tree.
  963. *
  964. * @param {object} groupedData - An object where keys represent sample IDs and values are objects containing mutational spectra data. The structure of `groupedData` is expected to be:
  965. * `{ sampleId1: { mutationType1: count1, mutationType2: count2, ... }, sampleId2: { mutationType1: count3, mutationType2: count4, ... }, ... }`
  966. * The inner objects (e.g., `{ mutationType1: count1, ... }`) represent the mutational spectrum for a given sample. `mutationType` keys can be any string representing a type of mutation (e.g., "C>A", "T>G"), and `count` values are non-negative integers representing the number of times that mutation type is observed in the sample.
  967. * @param {string} [studyName="PCAWG"] - The name of the study. This is used for labeling purposes in the visualization. Common values include, but are not limited to:
  968. * - `"PCAWG"`
  969. * - `"TCGA"`
  970. * - Any other string representing a specific study.
  971. * @param {string} [genomeDataType="WGS"] - The type of genome data used. This is also used for labeling purposes. Possible values include:
  972. * - `"WGS"`: Whole Genome Sequencing
  973. * - `"WES"`: Whole Exome Sequencing
  974. * - `"RNA-Seq"`: RNA Sequencing
  975. * @param {string} [cancerType="Lung-AdenoCA"] - The type of cancer being studied. This is used for labeling in the visualization. Examples include:
  976. * - `"Lung-AdenoCA"`: Lung Adenocarcinoma
  977. * - `"Breast-AdenoCA"`: Breast Adenocarcinoma
  978. * - Any valid cancer type identifier.
  979. * @param {string} [divID="forceDirectedTree"] - The ID of the HTML div element where the force-directed tree will be rendered.
  980. * @return {object} - Returns the formatted hierarchical clusters used to generate the force-directed tree. The structure of this object is compatible with the AM5 charting library and represents the hierarchical relationships between samples based on their mutational spectra. The format is a nested object where each level represents a node in the tree. Each node can have properties such as `name`, `value`, `children` (an array of child nodes), and potentially others added during formatting.
  981. */
  982. // This function plots a force directed tree of the patients in the study based on their mutational spectra
  983. async function plotForceDirectedTree(
  984. groupedData,
  985. studyName = "PCAWG",
  986. genomeDataType = "WGS",
  987. cancerType = "Lung-AdenoCA",
  988. divID = "forceDirectedTree"
  989. ) {
  990. groupedData = extractMutationalSpectra(groupedData);
  991. let distanceMatrix = await createDistanceMatrix(
  992. Object.values(groupedData).map((data) => Object.values(data)),
  993. cosineSimilarity,
  994. true
  995. );
  996. let clusters = await hierarchicalClustering(
  997. distanceMatrix,
  998. Object.keys(groupedData)
  999. );
  1000. let formattedClusters = formatHierarchicalClustersToAM5Format(
  1001. clusters,
  1002. studyName,
  1003. genomeDataType,
  1004. cancerType,
  1005. Object.keys(groupedData).length,
  1006. groupedData
  1007. );
  1008. // $(`#${divID}`).css({"width": "100%", "height": "550px", "max-width": "100%"})
  1009. const element = document.getElementById(divID);
  1010. element.style.width = "100%";
  1011. element.style.height = "600px";
  1012. element.style.maxWidth = "100%";
  1013. generateForceDirectedTree(formattedClusters, divID);
  1014. return formattedClusters;
  1015. }
  1016. async function generateForceDirectedTree(data, divID) {
  1017. // Create root element
  1018. // https://www.amcharts.com/docs/v5/getting-started/#Root_element
  1019. var root = am5.Root.new(divID);
  1020. // Set themes
  1021. // https://www.amcharts.com/docs/v5/concepts/themes/
  1022. root.setThemes([am5themes_Animated.default.new(root)]);
  1023. // Create wrapper container
  1024. var container = root.container.children.push(
  1025. am5.Container.new(root, {
  1026. width: am5.percent(100),
  1027. height: am5.percent(100),
  1028. layout: root.verticalLayout,
  1029. })
  1030. );
  1031. // Create series
  1032. // https://www.amcharts.com/docs/v5/charts/hierarchy/#Adding
  1033. var series = container.children.push(
  1034. am5hierarchy.ForceDirected.new(root, {
  1035. singleBranchOnly: false,
  1036. downDepth: 2,
  1037. initialDepth: 0,
  1038. valueField: "totalMutationCount",
  1039. categoryField: "name",
  1040. childDataField: "children",
  1041. minRadius: 20,
  1042. maxRadius: 80,
  1043. centerStrength: 0.5,
  1044. })
  1045. );
  1046. series.nodes.template._settings.tooltipText =
  1047. "Total Mutations: {totalMutationCount}";
  1048. series.adapters.add("fill", function (fill, target) {
  1049. return fill.lighten(target.dataItem.level * 0.25);
  1050. });
  1051. series.data.setAll([data]);
  1052. series.set("selectedDataItem", series.dataItems[0]);
  1053. series.appear(1000, 100);
  1054. }
  1055. //#endregion
  1056. //#region Visualizes a set of mutational spectra using UMAP.
  1057. /**
  1058. * @memberof mSigPortalPlots
  1059. * @function plotUMAPVisualization
  1060. * @description Generates a UMAP (Uniform Manifold Approximation and Projection) visualization of mutational spectra data. UMAP is a dimensionality reduction technique used to project high-dimensional data into a lower-dimensional space (typically 2D or 3D) while preserving the global structure of the data. This function takes mutational spectra data, applies UMAP to reduce its dimensionality, and then creates either a 2D or 3D scatter plot to visualize the results. If `nComponents` is set to 3, it additionally generates a mesh3d trace to highlight the density of points in the 3D space.
  1061. *
  1062. * @param {object} data - An object representing the mutational spectra data. The structure of `data` is expected to be:
  1063. * `{ sampleId1: { mutationType1: count1, mutationType2: count2, ... }, sampleId2: { mutationType1: count3, mutationType2: count4, ... }, ... }`
  1064. * The outer keys (e.g., `sampleId1`, `sampleId2`) are sample identifiers (strings). The inner objects (e.g., `{ mutationType1: count1, ... }`) represent the mutational spectrum for a given sample. `mutationType` keys can be any string representing a type of mutation (e.g., "C>A", "T>G"), and `count` values are non-negative integers representing the number of times that mutation type is observed in the sample.
  1065. * @param {string} [datasetName="PCAWG"] - The name of the dataset being visualized. This is used as part of the plot title. Examples include:
  1066. * - `"PCAWG"`
  1067. * - `"TCGA"`
  1068. * - Any other string that appropriately identifies the dataset.
  1069. * @param {string} divID - The ID of the HTML div element where the plot will be rendered.
  1070. * @param {number} [nComponents=3] - The number of dimensions to reduce the data to using UMAP. This determines whether a 2D or 3D plot is generated. Possible values are:
  1071. * - `2`: Generates a 2D scatter plot.
  1072. * - `3`: Generates a 3D scatter plot with an additional mesh3d trace.
  1073. * Any other positive integer is technically permissible but may not yield meaningful visualizations.
  1074. * @param {number} [minDist=0.1] - The effective minimum distance between embedded points in the UMAP projection. Smaller values result in a more clustered embedding, while larger values preserve more of the global structure. The valid range is between 0.0 and 1.0.
  1075. * @param {number} [nNeighbors=15] - The number of neighboring points to consider when constructing the UMAP. Larger values capture more global structure in the data, while smaller values preserve more local structure. Values should be positive integers, typically in the range of 2 to 100.
  1076. * @return {object} - Returns the trace object used by Plotly to generate the visualization. This object contains the data points, plot type, marker settings, and, in the case of a 3D plot, the mesh3d settings. The structure depends on the value of `nComponents`.
  1077. */
  1078. async function plotUMAPVisualization(
  1079. data,
  1080. datasetName = "PCAWG",
  1081. divID,
  1082. nComponents = 3,
  1083. minDist = 0.1,
  1084. nNeighbors = 15
  1085. ) {
  1086. data = extractMutationalSpectra(data);
  1087. let umap = new UMAP.default.UMAP({
  1088. nComponents: nComponents,
  1089. minDist: minDist,
  1090. nNeighbors: nNeighbors,
  1091. });
  1092. let embeddings = await umap.fit(
  1093. Object.values(data).map((data) => Object.values(data))
  1094. );
  1095. let plotType = nComponents === 3 ? "scatter3d" : "scatter";
  1096. let axisLabels = nComponents === 3 ? ["X", "Y", "Z"] : ["X", "Y"];
  1097. let trace = [
  1098. {
  1099. x: embeddings.map((d) => d[0]),
  1100. y: embeddings.map((d) => d[1]),
  1101. text: Object.keys(data),
  1102. mode: "markers",
  1103. type: plotType,
  1104. marker: { size: 6 },
  1105. },
  1106. ];
  1107. if (nComponents === 3) {
  1108. trace[0].z = embeddings.map((d) => d[2]);
  1109. trace.push({
  1110. alphahull: 7,
  1111. opacity: 0.1,
  1112. type: "mesh3d",
  1113. x: embeddings.map((d) => d[0]),
  1114. y: embeddings.map((d) => d[1]),
  1115. z: embeddings.map((d) => d[2]),
  1116. });
  1117. }
  1118. let layout = {
  1119. title: `${nComponents} Component UMAP Projection of ${datasetName} Dataset`,
  1120. xaxis: { title: axisLabels[0] },
  1121. yaxis: { title: axisLabels[1] },
  1122. };
  1123. if (nComponents === 3) {
  1124. layout.scene = { zaxis: { title: axisLabels[2] } };
  1125. }
  1126. plotGraphWithPlotlyAndMakeDataDownloadable(divID, trace, layout);
  1127. return trace;
  1128. }
  1129. //#endregion
  1130. //#region Signature Fitting
  1131. /**
  1132. * Fits mutational spectra to known mutational signatures using non-negative least squares (NNLS).
  1133. *
  1134. * This function calculates the exposure of mutational signatures for each sample by fitting
  1135. * the observed mutational spectra to the reference mutational signatures. It then filters out
  1136. * signatures whose contribution is below a fraction of the total exposure, by setting their
  1137. * exposures to zero.
  1138. *
  1139. * You can choose to return exposures as absolute values (raw counts from NNLS) or relative values
  1140. * (sum to 1 for each sample). The filtering threshold is a fraction between 0 and 1.
  1141. *
  1142. * @async
  1143. * @function fitMutationalSpectraToSignatures
  1144. * @memberof machineLearning
  1145. * @param {Object} mutationalSignatures - Reference mutational signatures. Each key is a signature name,
  1146. * and each value is an object of mutation types (e.g., {"C>A": weight, "C>G": weight}).
  1147. * @param {Object} mutationalSpectra - Mutational spectra for each sample. Each key is a sample ID,
  1148. * and each value is an object of mutation types with their counts (e.g., {"C>A": count, "C>G": count}).
  1149. * @param {Object} [options] - Configuration options for filtering and output.
  1150. * @param {number} [options.exposureThreshold=0] - Exclude signatures below this fraction of the total,
  1151. * by setting their exposures to zero. Must be between 0 and 1.
  1152. * @param {("absolute"|"relative")} [options.exposureType="relative"] - Return exposures as absolute or relative.
  1153. * @param {boolean} [options.renormalize=true] - Whether to normalize exposures so that they sum to 1 after filtering.
  1154. * @returns {Object} - An object with sample IDs as keys. Each value is an object of signature exposures.
  1155. *
  1156. * @example
  1157. * // Example usage:
  1158. * // 1. Get mutational signatures (e.g., from the mSigPortal API)
  1159. * const mutationalSignatures = await mSigPortal.mSigPortalData.getMutationalSignaturesData(
  1160. * "WGS", "COSMIC_v3_Signatures_GRCh37_SBS96", "SBS", 96, 1000
  1161. * );
  1162. *
  1163. * // 2. Extract mutational spectra for each sample
  1164. * const extractedSpectra = await mSigPortal.mSigPortalData.extractMutationalSpectra(
  1165. * mutationalSignatures, "signatureName"
  1166. * );
  1167. *
  1168. * // 3. Fit spectra to signatures with post-fit filtering
  1169. * const nnlsExposures = await mSigPortal.signatureFitting.fitMutationalSpectraToSignatures(
  1170. * mutationalSignatures,
  1171. * extractedSpectra,
  1172. * {
  1173. * exposureThreshold: 0.1,
  1174. * exposureType: "relative",
  1175. * renormalize: true
  1176. * }
  1177. * );
  1178. *
  1179. * console.log(nnlsExposures);
  1180. * // {
  1181. * // Sample1: { SBS1: 0.75, SBS2: 0.25, SBS3: 0 },
  1182. * // Sample2: { SBS1: 0.9, SBS2: 0.1, SBS3: 0 },
  1183. * // ...
  1184. * // }
  1185. */
  1186. async function fitMutationalSpectraToSignatures(
  1187. mutationalSignatures,
  1188. mutationalSpectra,
  1189. {
  1190. exposureThreshold = 0,
  1191. exposureType = "relative",
  1192. renormalize = true
  1193. } = {}
  1194. ) {
  1195. // Validate the threshold
  1196. if (exposureThreshold < 0 || exposureThreshold > 1) {
  1197. throw new Error("exposureThreshold must be between 0 and 1.");
  1198. }
  1199. const signatureNames = Object.keys(mutationalSignatures);
  1200. const sampleNames = Object.keys(mutationalSpectra);
  1201. // Convert reference signatures to arrays for NNLS
  1202. const nnlsInputSignatures = Object.values(mutationalSignatures).map(signatureData =>
  1203. Object.values(signatureData)
  1204. );
  1205. // Convert mutational spectra to arrays for NNLS
  1206. const nnlsInputMatrix = Object.values(mutationalSpectra).map(spectrumData =>
  1207. Object.values(spectrumData)
  1208. );
  1209. const results = {};
  1210. for (let i = 0; i < sampleNames.length; i++) {
  1211. const sampleName = sampleNames[i];
  1212. const nnlsInput = nnlsInputMatrix[i];
  1213. // 1. Perform NNLS
  1214. const nnlsOutput = await nnls(nnlsInputSignatures, nnlsInput);
  1215. const exposureValues = nnlsOutput.x;
  1216. delete nnlsOutput.x;
  1217. // 2. Build an object of signature exposures (raw from NNLS)
  1218. let sampleExposures = {};
  1219. for (let j = 0; j < signatureNames.length; j++) {
  1220. sampleExposures[signatureNames[j]] = exposureValues[j];
  1221. }
  1222. // 3. Calculate the total exposure
  1223. const totalExposure = Object.values(sampleExposures).reduce((acc, val) => acc + val, 0);
  1224. // 4. Filter out signatures below the fraction threshold by setting to 0
  1225. if (totalExposure > 0) {
  1226. for (let signature of signatureNames) {
  1227. const fraction = sampleExposures[signature] / totalExposure;
  1228. if (fraction < exposureThreshold) {
  1229. sampleExposures[signature] = 0;
  1230. }
  1231. }
  1232. }
  1233. // 5. If renormalize is true, adjust exposures to sum to 1
  1234. if (renormalize) {
  1235. const filteredTotal = Object.values(sampleExposures).reduce((a, b) => a + b, 0);
  1236. if (filteredTotal > 0) {
  1237. for (let signature of signatureNames) {
  1238. sampleExposures[signature] = sampleExposures[signature] / filteredTotal;
  1239. }
  1240. }
  1241. }
  1242. // 6. If returning relative exposures, ensure they sum to 1
  1243. if (exposureType === "relative" && !renormalize) {
  1244. const filteredTotal = Object.values(sampleExposures).reduce((a, b) => a + b, 0);
  1245. if (filteredTotal > 0) {
  1246. for (let signature of signatureNames) {
  1247. sampleExposures[signature] = sampleExposures[signature] / filteredTotal;
  1248. }
  1249. }
  1250. }
  1251. // 7. Store the final exposures for each sample
  1252. results[sampleName] = sampleExposures;
  1253. }
  1254. return results;
  1255. }
  1256. /**
  1257. * @memberof mSigPortalPlots
  1258. * @function plotPatientMutationalSignaturesExposure
  1259. * @description Generates a pie chart visualizing the exposure of a single sample to a set of mutational signatures. The function takes exposure data, which includes the relative contribution of each signature to the sample's mutational profile, and displays it in a pie chart format.
  1260. *
  1261. * @param {object} exposureData - An object containing the exposure data for a set of samples. The structure of `exposureData` is expected to be:
  1262. * `{ sampleId1: { signatureName1: exposureValue1, signatureName2: exposureValue2, ... }, sampleId2: { signatureName1: exposureValue3, signatureName2: exposureValue4, ... }, ... }`
  1263. * The outer keys (e.g., `sampleId1`, `sampleId2`) are sample identifiers (strings). The inner objects (e.g., `{ signatureName1: exposureValue1, ... }`) represent the exposure values for a given sample. `signatureName` keys are strings representing the names of mutational signatures (e.g., "SBS1", "SBS5"), and `exposureValue` are non-negative numbers representing the contribution of that signature to the sample. These values typically sum to 1 for each sample. The `exposureData` object can contain multiple samples, but only the data for the specified `sample` will be used for plotting. `exposureData` must also have a `rnorm` property which is a number.
  1264. * @param {string} divID - The ID of the HTML div element where the pie chart will be rendered.
  1265. * @param {string} sample - The ID of the sample for which to plot the mutational signature exposure. This should be one of the keys in the `exposureData` object (e.g., "sampleId1", "sampleId2").
  1266. * @return {object} - Returns the data object used by Plotly to generate the pie chart. This object contains the labels (signature names), values (exposure values), and other settings for the pie chart. The format is:
  1267. * `{ labels: [signatureName1, signatureName2, ...], values: [exposureValue1, exposureValue2, ...], name: "sample exposure values", textposition: "inside", hole: 0.4, hoverinfo: "name + value", type: "pie" }`
  1268. */
  1269. // This function plots the exposure of a set of samples to a set of mutational signatures
  1270. async function plotPatientMutationalSignaturesExposure(
  1271. exposureData,
  1272. divID,
  1273. sample
  1274. ) {
  1275. let dataset = deepCopy(exposureData);
  1276. const rnorm = dataset["rnorm"];
  1277. delete dataset["rnorm"];
  1278. const plotType = "pie";
  1279. const plotTitle = `Mutational Signature Exposure for ${sample} (r-norm = ${rnorm})`;
  1280. let data = {
  1281. labels: Object.keys(dataset),
  1282. values: Object.values(dataset),
  1283. name: `${sample} exposure values`,
  1284. textposition: "inside",
  1285. hole: 0.4,
  1286. hoverinfo: "name + value",
  1287. type: plotType,
  1288. };
  1289. let layout = {
  1290. title: plotTitle,
  1291. };
  1292. plotGraphWithPlotlyAndMakeDataDownloadable(divID, [data], layout);
  1293. return data;
  1294. }
  1295. /**
  1296. * @memberof mSigPortalPlots
  1297. * @function plotDatasetMutationalSignaturesExposure
  1298. * @description Generates a heatmap visualizing the exposure of multiple samples to a set of mutational signatures within a dataset. The function provides options for displaying relative or absolute exposure values and for performing double hierarchical clustering to reorder the rows and columns of the heatmap. It also allows customization of the color scale used to represent exposure values.
  1299. *
  1300. * @param {object} exposureData - An object containing the exposure data for a set of samples. The structure of `exposureData` is expected to be:
  1301. * `{ sampleId1: { signatureName1: exposureValue1, signatureName2: exposureValue2, ..., rnorm: number }, sampleId2: { signatureName1: exposureValue3, signatureName2: exposureValue4, ..., rnorm: number }, ... }`
  1302. * The outer keys (e.g., `sampleId1`, `sampleId2`) are sample identifiers (strings). The inner objects (e.g., `{ signatureName1: exposureValue1, ... }`) represent the exposure values for a given sample. `signatureName` keys are strings representing the names of mutational signatures (e.g., "SBS1", "SBS5"), and `exposureValue` are non-negative numbers representing the contribution of that signature to the sample. `rnorm` is a number that will be removed from the data before plotting.
  1303. * @param {string} divID - The ID of the HTML div element where the heatmap will be rendered.
  1304. * @param {boolean} [relative=true] - A boolean indicating whether to display relative or absolute exposure values.
  1305. * - `true`: The exposure values for each sample are normalized to sum to 1, representing the relative contribution of each signature.
  1306. * - `false`: The raw exposure values are displayed.
  1307. * @param {string} [datasetName="PCAWG"] - The name of the dataset being visualized. This is used as part of the plot title. Examples include:
  1308. * - `"PCAWG"`
  1309. * - `"TCGA"`
  1310. * - Any other string that appropriately identifies the dataset.
  1311. * @param {boolean} [doubleCluster=true] - A boolean indicating whether to perform double hierarchical clustering on the exposure data.
  1312. * - `true`: The rows and columns of the heatmap are reordered based on the results of double clustering, which groups similar samples and signatures together.
  1313. * - `false`: The rows and columns are displayed in the order they appear in the input `exposureData`.
  1314. * @param {string | Array} [colorscale="Custom"] - The color scale to use for the heatmap. Possible values are:
  1315. * - `"Custom"`: A predefined custom color scale designed for visualizing exposure data.
  1316. * - Any valid Plotly color scale name (e.g., `"Viridis"`, `"Blues"`, `"Hot"`, etc.).
  1317. * - An array of arrays defining a custom color scale, where each inner array specifies a color stop with a value between 0 and 1 and a corresponding RGB color string (e.g., `[["0.0", "rgb(49,54,149)"], ["1.0", "rgb(165,0,38)"]]`).
  1318. * @return {object} - Returns the data object used by Plotly to generate the heatmap. This object contains the z values (exposure values), x values (signature names), y values (sample names), and other settings for the heatmap, including the color scale. The structure is:
  1319. * `{ z: [[exposureValue1, exposureValue2, ...], [exposureValue3, exposureValue4, ...], ...], x: [signatureName1, signatureName2, ...], y: [sampleId1, sampleId2, ...], type: "heatmap", colorscale: colorscale }`
  1320. */
  1321. async function plotDatasetMutationalSignaturesExposure(
  1322. exposureData,
  1323. divID,
  1324. relative = true,
  1325. datasetName = "PCAWG",
  1326. doubleCluster = true,
  1327. colorscale = "Custom"
  1328. ) {
  1329. let dataset = deepCopy(exposureData);
  1330. // Remove the rnorm values from each sample of the exposure data
  1331. for (let sample in dataset) {
  1332. delete dataset[sample]["rnorm"];
  1333. }
  1334. if (relative) {
  1335. for (let sample in dataset) {
  1336. let total = 0;
  1337. for (let signature in dataset[sample]) {
  1338. total += dataset[sample][signature];
  1339. }
  1340. for (let signature in dataset[sample]) {
  1341. dataset[sample][signature] /= total;
  1342. }
  1343. }
  1344. }
  1345. let reorderedData;
  1346. if (doubleCluster) {
  1347. reorderedData = doubleClustering(
  1348. Object.values(dataset).map((data) => Object.values(data)),
  1349. Object.keys(dataset),
  1350. Object.keys(dataset[Object.keys(dataset)[0]])
  1351. );
  1352. } else {
  1353. console.log("data is not ordered");
  1354. reorderedData = {
  1355. matrix: Object.values(dataset).map((data) => Object.values(data)),
  1356. rowNames: Object.keys(dataset),
  1357. colNames: Object.keys(dataset[Object.keys(dataset)[0]]),
  1358. };
  1359. }
  1360. if (colorscale == "custom") {
  1361. colorscale = [
  1362. ["0.0", "rgb(49,54,149)"],
  1363. ["0.025", "rgb(69,117,180)"],
  1364. ["0.05", "rgb(116,173,209)"],
  1365. ["0.075", "rgb(171,217,233)"],
  1366. ["0.1", "rgb(224,243,248)"],
  1367. ["0.125", "rgb(254,224,144)"],
  1368. ["0.15", "rgb(253,174,97)"],
  1369. ["0.175", "rgb(244,109,67)"],
  1370. ["0.2", "rgb(215,48,39)"],
  1371. ["1.0", "rgb(165,0,38)"],
  1372. ];
  1373. }
  1374. let data = {
  1375. z: reorderedData.matrix,
  1376. x: reorderedData.colNames,
  1377. y: reorderedData.rowNames,
  1378. type: "heatmap",
  1379. colorscale: colorscale,
  1380. };
  1381. let layout = {
  1382. title: `Mutational Signature Exposure for ${datasetName} Dataset`,
  1383. xaxis: {
  1384. title: "Samples",
  1385. nticks: Object.keys(dataset[Object.keys(dataset)[0]]).length,
  1386. },
  1387. yaxis: {
  1388. title: "Mutational Signatures",
  1389. nticks: Object.keys(dataset).length,
  1390. },
  1391. height: 800,
  1392. };
  1393. plotGraphWithPlotlyAndMakeDataDownloadable(divID, [data], layout);
  1394. return data;
  1395. }
  1396. /**
  1397. * @memberof mSigPortalPlots
  1398. * @function plotSignatureAssociations
  1399. * @description This function generates and plots a scatter plot with marginal histograms, along with statistical analysis, to visualize the association between two mutational signatures. It calculates and displays the linear regression line, Pearson correlation, and Spearman correlation, providing insights into the relationship between the exposures of two signatures in a set of samples.
  1400. *
  1401. * @param {string} divID - The ID of the HTML div element where the plot will be rendered.
  1402. * @param {object} data - An array of objects representing the exposure data for a set of samples. Each object in the array should have the following properties:
  1403. * - `sample`: A string representing the sample ID.
  1404. * - `signatureName`: A string representing the name of the mutational signature.
  1405. * - `exposure`: A numeric value representing the exposure of the signature in the sample.
  1406. * @param {string} signature1 - The name of the first mutational signature. This should match the `signatureName` values in the `data` array. The values can be any valid signature name present in the dataset, for example, "SBS1", "SBS5", "DBS1", "ID4".
  1407. * @param {string} signature2 - The name of the second mutational signature. This should also match the `signatureName` values in the `data` array. Similar to `signature1`, the values can be any signature name present in the dataset and can also be the same as `signature1` to assess the distribution of a single signature.
  1408. * @return {void} - This function does not return a value. It directly renders the plot in the specified `divID`.
  1409. */
  1410. /**
  1411. * @memberof mSigPortalPlots
  1412. * @function MsAssociation
  1413. * @description Calculates the association between two mutational signatures across a set of samples. It computes the linear regression, Pearson correlation, and Spearman correlation between the log-transformed exposures of the two signatures. The results are used to generate a scatter plot with marginal histograms, visualizing the relationship between the signatures.
  1414. *
  1415. * @param {object[]} data - An array of objects representing the exposure data for a set of samples. Each object in the array should have the following properties:
  1416. * - `sample`: A string representing the sample ID.
  1417. * - `signatureName`: A string representing the name of the mutational signature.
  1418. * - `exposure`: A numeric value representing the exposure of the signature in the sample. This value can theoretically range from 0 to infinity, although in practice, values are often normalized.
  1419. * @param {string} signatureName1 - The name of the first mutational signature. This should match the `signatureName` values in the `data` array.
  1420. * @param {string} signatureName2 - The name of the second mutational signature. This should also match the `signatureName` values in the `data` array. It can be the same as `signatureName1`.
  1421. * @param {boolean} [both=false] - A boolean flag indicating whether to filter the data to include only samples where both signatures have non-zero exposure.
  1422. * - `true`: Only samples with non-zero exposure to both signatures are included in the analysis. If `signatureName1` and `signatureName2` are the same, then no filtering occurs.
  1423. * - `false`: All samples are included in the analysis, regardless of whether they have non-zero exposure to both signatures.
  1424. * @return {object} - Returns an object containing the traces and layout for a Plotly plot.
  1425. * - `traces`: An array of trace objects to be used in a Plotly plot. This includes the main scatter plot trace, the linear regression line trace, and two marginal histogram traces.
  1426. * - `layout`: An object containing the layout configuration for a Plotly plot, including title, axis labels, annotations, and other visual properties.
  1427. */
  1428. function plotSignatureAssociations(divID, data, signature1, signature2) {
  1429. let dat = plotSignatureAssociation(data, signature1, signature2);
  1430. plotGraphWithPlotlyAndMakeDataDownloadable(divID, dat.traces, dat.layout);
  1431. }
  1432. /**
  1433. * @memberof mSigPortalPlots
  1434. * @function plotMSPrevalenceData
  1435. * @description This function is a wrapper around the `plotMSPrevalence` function. It takes the output of `plotMSPrevalence` and uses it to generate a Plotly plot, which is then displayed in a specified div. The plot visualizes the prevalence of mutational signatures.
  1436. *
  1437. * @param {string} divID - The ID of the div element where the plot will be rendered.
  1438. * @param {object} data - An object representing the mutational signature prevalence data. The `data` object is expected to be an array of objects with the following structure:
  1439. * `[{ signatureName: "SBS1", sample: "sample1", exposure: 10, burden: 5 }, { signatureName: "SBS5", sample: "sample1", exposure: 20, burden: 5 }, ... ]`
  1440. * Where `signatureName` is the name of a mutational signature (string), `sample` is a sample identifier (string), `exposure` is a non-negative number representing the exposure of that signature in the sample, and `burden` is a numeric value representing the mutational burden for the sample.
  1441. * @return {void} - This function does not return a value. It directly renders the plot in the specified `divID`.
  1442. */
  1443. /**
  1444. * @memberof mSigPortalPlots
  1445. * @function MSPrevalence
  1446. * @description Calculates and visualizes the prevalence of mutational signatures across a set of samples, grouped by cancer type. The function generates two plots: a pie chart showing the overall prevalence of each signature based on total mutations (exposure) and a bar chart displaying the frequency of each signature across samples, considering a minimum exposure threshold.
  1447. *
  1448. * @param {object} data - An object representing the mutational signature prevalence data. The `data` object is expected to be an array of objects with the following structure:
  1449. * `[{ signatureName: "SBS1", sample: "sample1", exposure: 10, burden: 5 }, { signatureName: "SBS5", sample: "sample1", exposure: 20, burden: 5 }, ... ]`
  1450. * Where `signatureName` is the name of a mutational signature (string), `sample` is a sample identifier (string), `exposure` is a non-negative number representing the exposure of that signature in the sample (can be 0), and `burden` is a numeric value representing the mutational burden for the sample (must be a number).
  1451. * @param {number|null|undefined} minimum - The minimum exposure value for a signature in a sample to be considered prevalent in that sample. Samples with exposure below this threshold are not counted in the frequency calculation for the bar chart. If `minimum` is `null` or `undefined`, it defaults to 100.
  1452. * - `null` or `undefined`: Sets the minimum exposure to 100.
  1453. * - Any positive number: Sets the minimum exposure to that number.
  1454. * @return {{traces: object[], layout: object}} - Returns an object containing the `traces` and `layout` for a Plotly plot.
  1455. * - `traces`: An array of trace objects. If the maximum frequency of signatures (considering the `minimum` threshold) is less than 1%, the array contains only a single pie chart trace. Otherwise, it contains a pie chart trace followed by multiple bar chart traces (one for each signature).
  1456. * - `layout`: An object defining the layout of the plot, including title annotations, axis settings, and overall appearance. It includes conditional logic to handle cases where no signature has a frequency greater than 1%.
  1457. */
  1458. function plotMSPrevalenceData(divID, data) {
  1459. let dat = plotMSPrevalence(data);
  1460. plotGraphWithPlotlyAndMakeDataDownloadable(divID, dat.traces, dat.layout);
  1461. }
  1462. //#endregion
  1463. //#region Define the public members of the mSigSDK
  1464. const mSigPortalData = {
  1465. getMutationalSignaturesOptions,
  1466. getMutationalSignaturesData,
  1467. getMutationalSignaturesSummary,
  1468. getMutationalSpectrumOptions,
  1469. getMutationalSpectrumData,
  1470. getMutationalSpectrumSummary,
  1471. getMutationalSignatureAssociationOptions,
  1472. getMutationalSignatureAssociationData,
  1473. getMutationalSignatureActivityOptions,
  1474. getMutationalSignatureActivityData,
  1475. getMutationalSignatureLandscapeData,
  1476. getMutationalSignatureEtiologyOptions,
  1477. getMutationalSignatureEtiologyData,
  1478. extractMutationalSpectra,
  1479. };
  1480. const mSigPortalPlots = {
  1481. plotProfilerSummary,
  1482. plotPatientMutationalSpectrum,
  1483. plotForceDirectedTree,
  1484. plotCosineSimilarityHeatMap,
  1485. plotUMAPVisualization,
  1486. plotProjectMutationalBurdenByCancerType,
  1487. plotSignatureActivityDataBy,
  1488. plotSignatureAssociations,
  1489. plotMSPrevalenceData,
  1490. };
  1491. const mSigPortal = {
  1492. mSigPortalData,
  1493. mSigPortalPlots,
  1494. };
  1495. const userData = {
  1496. convertMatrix,
  1497. convertWGStoPanel,
  1498. plotPatientMutationalSpectrumuserData,
  1499. convertMutationalSpectraIntoJSON,
  1500. };
  1501. const TCGA = {
  1502. getProjectsByGene,
  1503. getTpmCountsByGenesOnProjects,
  1504. getTpmCountsByGenesFromFiles,
  1505. getMafInformationFromProjects,
  1506. getVariantInformationFromMafFiles,
  1507. convertTCGAProjectIntoJSON,
  1508. };
  1509. const tools = {
  1510. groupBy,
  1511. };
  1512. const signatureFitting = {
  1513. fitMutationalSpectraToSignatures,
  1514. plotPatientMutationalSignaturesExposure,
  1515. plotDatasetMutationalSignaturesExposure,
  1516. };
  1517. const machineLearning = {
  1518. preprocessData,
  1519. kFoldCV,
  1520. };
  1521. //#endregion
  1522. // Public members
  1523. return {
  1524. mSigPortal,
  1525. userData,
  1526. tools,
  1527. machineLearning,
  1528. signatureFitting,
  1529. TCGA,
  1530. };
  1531. })();
  1532. export { mSigSDK };