From dce3b0a4e4628b1e32acf6096d83274f8fbe4abc Mon Sep 17 00:00:00 2001 From: Annie Moriondo <104587901+moriondo2022@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:51:56 -0500 Subject: [PATCH] Hover pin (#813) * clickable dots register what is clicked * tooltip can be pinned! now to unpin * little close link in tooltip * tooltip can be unpinned * visibility hide/show for little x close box * styling the close button * links appear to be working * preparing to put links in phewas hover * almost there * links working * links on phenotype page too --- src/components/PigeanPlot.vue | 50 ++++++++++++++++--- src/components/PigeanTable.vue | 2 + .../researchPortal/ResearchPheWAS.vue | 43 +++++++++++----- src/views/PIGEAN/Gene/Template.vue | 11 +--- src/views/PIGEAN/Gene/main.js | 16 ------ src/views/PIGEAN/GeneSet/Template.vue | 2 + 6 files changed, 79 insertions(+), 45 deletions(-) diff --git a/src/components/PigeanPlot.vue b/src/components/PigeanPlot.vue index 80a22942f..75f7c10a4 100644 --- a/src/components/PigeanPlot.vue +++ b/src/components/PigeanPlot.vue @@ -17,11 +17,14 @@ import Vue from "vue"; import * as d3 from "d3"; import DownloadChart from "./DownloadChart.vue"; import plotUtils from "@/utils/plotUtils"; +import bioIndexUtils from "@/utils/bioIndexUtils"; import Formatters from "@/utils/formatters"; +import { BootstrapVueIcons } from "bootstrap-vue"; +Vue.use(BootstrapVueIcons); export default Vue.component("pigean-plot", { components: { }, - props: ["pigeanData", "config", "phenotypeMap", "filter"], + props: ["pigeanData", "config", "phenotypeMap", "filter", "genesetSize", "traitGroup"], data() { return { plotId: `pigean-plot-${Math.floor(Math.random() * 10e9)}`, @@ -34,6 +37,7 @@ export default Vue.component("pigean-plot", { xMedian: 0, tooltip: null, tooltipElement: null, + tooltipPinned: false, colorMap: this.groupColors(), allHoverFields: this.getHoverFields(), hoverBoxPosition: this.config.hoverBoxPosition || "left", @@ -56,10 +60,17 @@ export default Vue.component("pigean-plot", { data = data.filter(this.filter); } return data; + }, + linkSuffix(){ + return `&genesetSize=${this.$store.state.genesetSize + || bioIndexUtils.DEFAULT_GENESET_SIZE + }&traitGroup=${this.$store.state.traitGroup + || bioIndexUtils.DEFAULT_TRAIT_GROUP}`; } }, methods: { drawChart(){ + this.tooltipPinned = false; let margin = { top: 10, right: 30, @@ -74,7 +85,6 @@ export default Vue.component("pigean-plot", { .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) - .on("mouseleave", () => this.hideTooltip()) .append("g") .attr("transform", `translate(${margin.left},${margin.top})`); @@ -151,6 +161,16 @@ export default Vue.component("pigean-plot", { .attr("stroke", this.dotOutlineColor) .on("mouseover", (g) => this.hoverDot(JSON.stringify(g))); + + // Click behavior for dots + this.svg.selectAll("circle") + .on("click", d => { + if (!this.tooltipPinned){ + let closeButton = this.tooltip.select("a"); + closeButton.style("visibility", "visible"); + this.tooltipPinned = true; + } + }); }, extremeVal(field, min=true){ let filteredData = this.pigeanData.filter(d => @@ -166,9 +186,10 @@ export default Vue.component("pigean-plot", { return val; }, hoverDot(dotString) { + if (this.tooltipPinned){ + return; + } this.unHoverDot(); - - this.$emit("dotHovered", dotString); let xcoord = d3.event.layerX; let ycoord = d3.event.layerY; @@ -176,6 +197,11 @@ export default Vue.component("pigean-plot", { this.tooltip .style("opacity", 1) .html(this.getTooltipContent(dotString)); + this.tooltip.selectAll("a") + .on("click", () => { + this.tooltipPinned = false; + this.hideTooltip(); + }); let leftOffset = this.tooltipElement.clientWidth; let hoverLeft = this.dotHoverLeft(dotString); @@ -196,11 +222,16 @@ export default Vue.component("pigean-plot", { : this.hoverBoxPosition === "left"; }, getTooltipContent(dotString){ + console.log(dotString); let dot = JSON.parse(dotString); + let dKey = this.config.dotKey; + let dKeyContent = dot[dKey]; // Get raw content before formatting dot.phenotype = this.phDesc(dot.phenotype); - let tooltipText = `${ - Formatters.tissueFormatter(this.config.dotKey)}: ${ - dot[this.config.dotKey]}`; + let linkAddress = `/pigean/${dKey}.html?${dKey}=${dKeyContent}${this.linkSuffix}`; + let tooltipText = '

'; + tooltipText = tooltipText.concat('x

') + tooltipText=tooltipText.concat(`${ + Formatters.tissueFormatter(dKey)}: ${dot[dKey]}`); tooltipText = tooltipText.concat( `${this.config.xAxisLabel}: ${ dot[this.config.xField]}`); @@ -282,4 +313,9 @@ export default Vue.component("pigean-plot", { .tooltip span { display: block; } + p.close-tooltip{ + text-align: right; + margin: 0px; + padding: 0px; + } diff --git a/src/components/PigeanTable.vue b/src/components/PigeanTable.vue index 7c87cfab6..094fe0612 100644 --- a/src/components/PigeanTable.vue +++ b/src/components/PigeanTable.vue @@ -354,6 +354,8 @@ export default Vue.component("pigean-table", { :plot-name="`PIGEAN_${row.item.phenotype}`" :phenotypes-data="phewasData[phewasKey(row.item)]" :phenotype-map="phenotypeMap || $store.state.bioPortal.phenotypeMap" + :linkPhenotypes="true" + :isPigean="true" :colors="plotColors" :render-config="phewasRenderConfig" :utils="utilsBox" diff --git a/src/components/researchPortal/ResearchPheWAS.vue b/src/components/researchPortal/ResearchPheWAS.vue index 65876e070..04f6df926 100644 --- a/src/components/researchPortal/ResearchPheWAS.vue +++ b/src/components/researchPortal/ResearchPheWAS.vue @@ -31,8 +31,13 @@ - {{ ptKey }}
+ {{ ptKey }} + + + {{ phenotypeMap[ptKey].description }} + + +
= yLoc[0] && y <= yLoc[1]) { yValue.map((xPos) => { if (x >= xPos.start && x <= xPos.end) { - this.hoverItems[xPos.name] = xPos; - infoContent += - "" + - xPos.name + - "
"; - + if (this.linkPhenotypes){ + this.hoverItems[xPos.id] = xPos; + } else { + this.hoverItems[xPos.name] = xPos; + } + infoContent +=`${xPos.name}
`; this.renderConfig["hover content"].map( (h) => { infoContent += @@ -755,13 +763,11 @@ export default Vue.component("ResearchPhewasPlot", { canvasHeight - plotMargin.bottom - yFromMinY * yStep; - + let rawPhenotype = p[this.renderConfig["render by"]]; let pName = this.phenotypeMapConfig == null - ? p[this.renderConfig["render by"]] - : this.phenotypeMap[ - p[this.renderConfig["render by"]] - ]["description"]; + ? rawPhenotype + : this.phenotypeMap[rawPhenotype]["description"]; let passesThreshold = this.greaterThan ? p.rawPValue >= Number(this.renderConfig["thresholds"][0]) @@ -1081,6 +1087,17 @@ export default Vue.component("ResearchPhewasPlot", { action: "remove", }); }, + phenotypeLink(rawPhenotype){ + let destination = `/phenotype.html?phenotype=${rawPhenotype}`; + if (this.isPigean){ + let suffix = `&genesetSize=${this.$store.state.genesetSize + || bioIndexUtils.DEFAULT_GENESET_SIZE + }&traitGroup=${this.$store.state.traitGroup + || bioIndexUtils.DEFAULT_TRAIT_GROUP}`; + destination = `/pigean${destination}${suffix}`; + } + return destination; + } }, }); diff --git a/src/views/PIGEAN/Gene/Template.vue b/src/views/PIGEAN/Gene/Template.vue index cc320aa85..53cffbcca 100644 --- a/src/views/PIGEAN/Gene/Template.vue +++ b/src/views/PIGEAN/Gene/Template.vue @@ -141,6 +141,8 @@ :phenotype-map=" $parent.pigeanMap " + :linkPhenotypes="true" + :isPigean="true" :colors="$parent.plotColors" :render-config="$parent.renderConfig" :utils="$parent.utilsBox" @@ -160,17 +162,8 @@ $parent.pigeanMap " :filter="filter" - @dotHovered="(dot) => $parent.showLink(dot)" > -

diff --git a/src/views/PIGEAN/Gene/main.js b/src/views/PIGEAN/Gene/main.js index 4d5f5c99f..8aa57465c 100644 --- a/src/views/PIGEAN/Gene/main.js +++ b/src/views/PIGEAN/Gene/main.js @@ -43,7 +43,6 @@ new Vue({ data() { return { pigeanPhenotypeMap: {}, - hoverPhenotype: "", filterFields: [ { key: "combined", label: "Combined genetic support" }, { key: "huge_score", label: "Direct support w/o gene sets" }, @@ -170,17 +169,6 @@ new Vue({ phewasAllData(){ return this.$store.state.phewasData; }, - phenotypeLinkAddress(){ - if (!this.hoverPhenotype){ - return ""; - } - return `/pigean/phenotype.html?phenotype=${this.hoverPhenotype - }&genesetSize=${this.$store.state.genesetSize}&traitGroup=${ - this.$store.state.traitGroup}`; - }, - phenotypeLinkText(){ - return this.pigeanMap[this.hoverPhenotype]?.description || this.hoverPhenotype; - } }, watch: { diseaseGroup(group) { @@ -207,10 +195,6 @@ new Vue({ }&start=${r.start - expanded}&end=${r.end + expanded}`; } }, - showLink(dot){ - let dotObject = JSON.parse(dot); - this.hoverPhenotype = dotObject.phenotype; - } }, render(createElement, context) { diff --git a/src/views/PIGEAN/GeneSet/Template.vue b/src/views/PIGEAN/GeneSet/Template.vue index fde671d07..83234ca52 100644 --- a/src/views/PIGEAN/GeneSet/Template.vue +++ b/src/views/PIGEAN/GeneSet/Template.vue @@ -119,6 +119,8 @@ $parent.phewasAdjustedData " :phenotype-map="$parent.pigeanMap" + :linkPhenotypes="true" + :isPigean="true" :colors="$parent.plotColors" :render-config="$parent.renderConfig" :utils="$parent.utilsBox"