";
+ let detailHtml = "";
+ if (row?.annotation?.pharmacogenomics) {
+ detailHtml += "";
+ detailHtml += "
";
+ return result;
+ }
+
+ drugsTableFormatter(variant) {
+ const drugsRows = variant.annotation.pharmacogenomics
+ // .filter(item => item.types.includes("Drug"))
+ .map(item => {
+ const phenotypes = item.annotations.map(annotation => `Drugs
";
+ detailHtml += this.drugsTableFormatter(row);
+ detailHtml += "
";
+ }
+ result += detailHtml + "${annotation.phenotypes.join(", ")}
`);
+ const phenotypeTypes = item.annotations.map(annotation => `${annotation.phenotypeType}
`);
+ return `
+ ID | +Name | +Source | +Phenotypes | +Phenotype Types | +
---|
+
+
+ `;
+ }
+
+ getDefaultColumns() {
+ return [
+ [
+ {
+ id: "id",
+ title: "Variant",
+ field: "id",
+ rowspan: 2,
+ colspan: 1,
+ formatter: (value, row, index) => {
+ return VariantGridFormatter.variantFormatter(value, row, index, this.opencgaSession.project.organism.assembly, this._config);
+ },
+ },
+ {
+ id: "genotype",
+ title: "Genotype",
+ rowspan: 2,
+ colspan: 1,
+ field: {
+ sampleId: this.sampleId,
+ quality: this._config.quality,
+ config: this._config,
+ },
+ formatter: VariantInterpreterGridFormatter.sampleGenotypeFormatter,
+ align: "center",
+ nucleotideGenotype: true,
+ visible: !!this.sampleId,
+ },
+ {
+ id: "gene",
+ title: "Gene",
+ field: "gene",
+ rowspan: 2,
+ colspan: 1,
+ formatter: (value, row, index) => VariantGridFormatter.geneFormatter(row, index, {}, this.opencgaSession, this._config),
+ },
+ {
+ id: "consequenceType",
+ title: "Consequence Type",
+ field: "consequenceType",
+ rowspan: 2,
+ colspan: 1,
+ formatter: (value, row) => VariantGridFormatter.consequenceTypeFormatter(value, row, null, this._config),
+ },
+ {
+ id: "populationFrequencies",
+ title: "Reference Population Frequencies",
+ field: "populationFrequencies",
+ rowspan: 2,
+ colspan: 1,
+ formatter: VariantInterpreterGridFormatter.clinicalPopulationFrequenciesFormatter.bind(this),
+ },
+ {
+ id: "clinicalInfo",
+ title: "Clinical Info",
+ rowspan: 1,
+ colspan: 3,
+ align: "center"
+ },
+ ],
+ [
+ {
+ id: "clinvar",
+ title: "ClinVar",
+ field: "clinvar",
+ colspan: 1,
+ rowspan: 1,
+ formatter: VariantGridFormatter.clinicalTraitAssociationFormatter,
+ align: "center",
+ },
+ {
+ id: "cosmic",
+ title: "Cosmic",
+ field: "cosmic",
+ colspan: 1,
+ rowspan: 1,
+ formatter: VariantGridFormatter.clinicalTraitAssociationFormatter,
+ align: "center",
+ },
+ {
+ id: "hotspots",
+ title: "Cancer Hotspots", + field: "hotspots", + colspan: 1, + rowspan: 1, + formatter: VariantGridFormatter.clinicalCancerHotspotsFormatter, + align: "center", + }, + ], + ]; + } + + getDefaultConfig() { + return { + pagination: true, + pageSize: 10, + pageList: [5, 10, 25], + detailView: true, + quality: { + qual: 30, + dp: 20 + }, + populationFrequencies: [ + "1000G:ALL", + "GNOMAD_GENOMES:ALL", + "GNOMAD_EXOMES:ALL", + ], + populationFrequenciesConfig: { + displayMode: "FREQUENCY_BOX" + }, + genotype: { + type: "ALLELES" + }, + geneSet: { + ensembl: true, + refseq: true, + }, + consequenceType: { + // all: false, + maneTranscript: true, + gencodeBasicTranscript: false, + ensemblCanonicalTranscript: true, + refseqTranscript: true, + ccdsTranscript: false, + ensemblTslTranscript: false, + proteinCodingTranscript: false, + highImpactConsequenceTypeTranscript: false, + + showNegativeConsequenceTypes: true + }, + }; + } + +} + +customElements.define("pharmacogenomics-grid", PharmacogenomicsGrid); diff --git a/src/webcomponents/clinical/pharmacogenomics/pharmacogenomics-report.js b/src/webcomponents/clinical/pharmacogenomics/pharmacogenomics-report.js new file mode 100644 index 0000000000..ac4d421cef --- /dev/null +++ b/src/webcomponents/clinical/pharmacogenomics/pharmacogenomics-report.js @@ -0,0 +1,169 @@ +import {LitElement, html, nothing} from "lit"; +import {CellBaseClient} from "../../../core/clients/cellbase/cellbase-client.js"; +import "./pharmacogenomics-grid.js"; +import "../../commons/tool-header.js"; +import "../../loading-spinner.js"; + +export default class PharmacogenomicsReport extends LitElement { + + constructor() { + super(); + this.#init(); + } + + createRenderRoot() { + return this; + } + + static get properties() { + return { + sampleId: { + type: String, + }, + active: { + type: Boolean, + }, + opencgaSession: { + type: Object, + }, + }; + } + + #init() { + this.active = true; + this.loading = false; + this.error = false; + this.variants = []; + this.config = this.getDefaultConfig(); + } + + update(changedProperties) { + if (changedProperties.has("sampleId") || changedProperties.has("opencgaSession") || changedProperties.has("active")) { + this.sampleIdObserver(); + } + super.update(changedProperties); + } + + async sampleIdObserver() { + this.variants = []; + if (this.opencgaSession && this.sampleId && this.active) { + this.error = false; + this.loading = true; + this.requestUpdate(); + try { + // 0. Initialize Cellbase client instance + const cellbaseClient = new CellBaseClient({ + // host: this.opencgaSession?.project?.cellbase?.url || this.opencgaSession?.project?.internal?.cellbase?.url, + host: "https://ws.zettagenomics.com/cellbase", + version: "v5.5", + species: "hsapiens", + }); + + // 1. Import all PGx variants from Cellbase + const pgxVariantsResponse = await cellbaseClient.get("clinical", "pharmacogenomics", null, "distinct", { + field: "variants.location", + assembly: "grch38", + dataRelease: "5", + }); + + // 2. Get the list of variants available in OpenCGA + const pgxVariants = pgxVariantsResponse.responses[0].results; + const variants = new Map(); + for (let i = 0; i < pgxVariants.length; i = i + 200) { + const variantsPromises = []; + const variantsBatch = pgxVariants.slice(i, i + 200); + for (let j = 0; j < variantsBatch.length; j = j + 50) { + const chunk = variantsBatch.slice(j, j + 50); + const query = { + region: chunk.join(","), + sample: this.sampleId, + // include: "id", + study: this.opencgaSession.study.fqn, + includeSampleId: true, + }; + variantsPromises.push(this.opencgaSession.opencgaClient.clinical().queryVariant(query)); + } + const variantsResponses = await Promise.all(variantsPromises); + variantsResponses.forEach(variantResponse => { + variantResponse.responses[0].results.forEach(variant => { + variants.set(variant.id, variant); + }); + }); + } + + // 4. Import pharmacogenomics annotation from cellbase + const ids = Array.from(variants.keys()); + for (let i = 0; i < ids.length; i = i + 200) { + const idsBatch = ids.slice(i, i + 200); + const promises = []; + for (let j = 0; j < idsBatch.length; j = j + 50) { + const chunk = idsBatch.slice(j, j + 50); + const query = { + assembly: "grch38", + dataRelease: "5", + include: "pharmacogenomics", + }; + promises.push(cellbaseClient.get("genomic", "variant", chunk.join(","), "annotation", query)); + } + const responses = await Promise.all(promises); + responses.forEach(pgxAnnotationResponse => { + pgxAnnotationResponse.responses.forEach(response => { + if (variants.has(response.id)) { + variants.get(response.id).annotation.pharmacogenomics = response.results[0].pharmacogenomics; + } + }); + }); + } + + // 5. Save variants and request update + this.variants = Array.from(variants.values()); + } catch (error) { + console.error(error); + this.error = true; + } + this.loading = false; + this.requestUpdate(); + } + } + + render() { + if (this.loading) { + return html` +
+
+
+ `;
+ }
+ if (this.error) {
+ return html`
+
+
+ `;
+ }
+
+ return html`
+
+ Error getting Pharmacogenomics info. Plase try again later.
+
+
+ ${this.config.showToolTitle ? html`
+
+ ` : nothing}
+
+
+
+ `;
+ }
+
+ getDefaultConfig() {
+ return {
+ showToolTitle: true,
+ };
+ }
+
+}
+
+customElements.define("pharmacogenomics-report", PharmacogenomicsReport);
diff --git a/src/webcomponents/clinical/pharmacogenomics/pharmacogenomics-summary.js b/src/webcomponents/clinical/pharmacogenomics/pharmacogenomics-summary.js
new file mode 100644
index 0000000000..df1469be03
--- /dev/null
+++ b/src/webcomponents/clinical/pharmacogenomics/pharmacogenomics-summary.js
@@ -0,0 +1,49 @@
+import {LitElement, html} from "lit";
+
+export default class PharmacogenomicsSummary extends LitElement {
+
+ constructor() {
+ super();
+ this.#init();
+ }
+
+ createRenderRoot() {
+ return this;
+ }
+
+ static get properties() {
+ return {
+ variant: {
+ type: String,
+ },
+ active: {
+ type: Boolean,
+ },
+ opencgaSession: {
+ type: Object,
+ },
+ };
+ }
+
+ #init() {
+ this.active = true;
+ this.config = this.getDefaultConfig();
+ }
+
+ update(changedProperties) {
+ super.update(changedProperties);
+ }
+
+ render() {
+ return html`
+ Pharmacogenomics Summary
+ `;
+ }
+
+ getDefaultConfig() {
+ return {};
+ }
+
+}
+
+customElements.define("pharmacogenomics-summary", PharmacogenomicsSummary);
diff --git a/src/webcomponents/variant/interpretation/variant-interpreter-browser-template.js b/src/webcomponents/variant/interpretation/variant-interpreter-browser-template.js
index 3c1175c46e..9109564ff8 100644
--- a/src/webcomponents/variant/interpretation/variant-interpreter-browser-template.js
+++ b/src/webcomponents/variant/interpretation/variant-interpreter-browser-template.js
@@ -20,6 +20,7 @@ import ClinicalAnalysisManager from "../../clinical/clinical-analysis-manager.js
import LitUtils from "../../commons/utils/lit-utils.js";
import NotificationUtils from "../../commons/utils/notification-utils.js";
import OpencgaCatalogUtils from "../../../core/clients/opencga/opencga-catalog-utils.js";
+import {CellBaseClient} from "../../../core/clients/cellbase/cellbase-client.js";
import UtilsNew from "../../../core/utils-new.js";
import "./variant-interpreter-browser-toolbar.js";
import "./variant-interpreter-grid.js";
@@ -362,6 +363,55 @@ class VariantInterpreterBrowserTemplate extends LitElement {
}
}
+ async onFilterPharmacogenomicsVariants() {
+ // 0. Initialize Cellbase client instance
+ const cellbaseClient = new CellBaseClient({
+ // host: this.opencgaSession?.project?.cellbase?.url || this.opencgaSession?.project?.internal?.cellbase?.url,
+ host: "https://ws.zettagenomics.com/cellbase",
+ version: "v5.5",
+ species: "hsapiens",
+ });
+
+ // 1. Import all PGx variants from Cellbase
+ const pgxVariantsResponse = await cellbaseClient.get("clinical", "pharmacogenomics", null, "distinct", {
+ field: "variants.location",
+ assembly: "grch38",
+ dataRelease: "5",
+ });
+
+ // 2. Get the list of variants available in OpenCGA
+ const pgxVariants = pgxVariantsResponse.responses[0].results;
+ const chunkSize = 200;
+ const promises = [];
+ for (let i = 0; i < pgxVariants.length; i = i + chunkSize) {
+ const chunk = pgxVariants.slice(i, i + chunkSize);
+ const query = {
+ region: chunk.join(","),
+ sample: this.clinicalAnalysis.proband.samples[0].id,
+ include: "id",
+ study: this.opencgaSession.study.fqn,
+ };
+ promises.push(this.opencgaSession.opencgaClient.clinical().queryVariant(query));
+ }
+ const variantsResponses = await Promise.all(promises);
+
+ // 3. Generate the list of unique variants to filter
+ const variantIds = new Set();
+ variantsResponses.forEach(variantResponse => {
+ variantResponse.responses[0].results.forEach(variant => {
+ variantIds.add(variant.id);
+ });
+ });
+
+ // 4. Update the query
+ this.query = {
+ ...this.query,
+ id: Array.from(variantIds).join(","),
+ };
+ this.notifyQueryChange();
+ this.requestUpdate();
+ }
+
render() {
// Check Project exists
if (!this.opencgaSession?.study) {
@@ -459,6 +509,7 @@ class VariantInterpreterBrowserTemplate extends LitElement {
.variantInclusionState="${this.variantInclusionState}"
.write="${OpencgaCatalogUtils.checkPermissions(this.opencgaSession.study, this.opencgaSession.user.id, "WRITE_CLINICAL_ANALYSIS")}"
@filterVariants="${this.onFilterVariants}"
+ @filterPharmacogenomicsVariants="${this.onFilterPharmacogenomicsVariants}"
@resetVariants="${this.onResetVariants}"
@saveInterpretation="${this.onSaveVariants}">
diff --git a/src/webcomponents/variant/interpretation/variant-interpreter-browser-toolbar.js b/src/webcomponents/variant/interpretation/variant-interpreter-browser-toolbar.js
index aa34410a38..bbac872cd3 100644
--- a/src/webcomponents/variant/interpretation/variant-interpreter-browser-toolbar.js
+++ b/src/webcomponents/variant/interpretation/variant-interpreter-browser-toolbar.js
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import {LitElement, html} from "lit";
+import {LitElement, html, nothing} from "lit";
import UtilsNew from "../../../core/utils-new.js";
import LitUtils from "../../commons/utils/lit-utils.js";
@@ -23,8 +23,6 @@ class VariantInterpreterBrowserToolbar extends LitElement {
constructor() {
super();
-
- // Set status and init private properties
this._init();
}
@@ -58,19 +56,22 @@ class VariantInterpreterBrowserToolbar extends LitElement {
_init() {
this._prefix = UtilsNew.randomString(8);
this.write = false;
- }
-
- connectedCallback() {
- super.connectedCallback();
- this._config = {...this.getDefaultConfig(), ...this.config};
+ this._config = this.getDefaultConfig();
}
updated(changedProperties) {
if (changedProperties.has("config")) {
- this._config = {...this.getDefaultConfig(), ...this.config};
+ this._config = {
+ ...this.getDefaultConfig(),
+ ...this.config,
+ };
}
}
+ onFilterPharmacogenomicsVariants() {
+ LitUtils.dispatchCustomEvent(this, "filterPharmacogenomicsVariants", null);
+ }
+
onFilterInclusionVariants() {
const variants = [];
this.variantInclusionState.map(inclusion => variants.push(...inclusion.variants));
@@ -174,6 +175,15 @@ class VariantInterpreterBrowserToolbar extends LitElement {
return html`