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(`${
+ 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 }}
- View phenotype:
-
-
-
+ {{ 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)"
>
-