Skip to content

Commit

Permalink
Merge pull request #290 from marcelo-q/PDBE-HEATMAP-V1
Browse files Browse the repository at this point in the history
Nightingale sequence heatmap update to v1
  • Loading branch information
gustavo-salazar authored Aug 20, 2024
2 parents b7844e3 + ed131c1 commit ba28787
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 120 deletions.
4 changes: 3 additions & 1 deletion dev/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
}
});
customElements.whenDefined("nightingale-sequence-heatmap").then(() => {
setTimeout(() => {
setTimeout(async () => {
const xDomain = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
Expand All @@ -124,6 +124,7 @@
document
.getElementById("heatmapHotmap")
.setHeatmapData(xDomain, yDomain, data);

setTimeout(() => {
const colorScale = d3.scaleLinear([0, 1], ["lightblue", "blue"]);
document
Expand Down Expand Up @@ -185,6 +186,7 @@ <h1>Manager</h1>
height="500"
display-start="5"
display-end="25"
hm-highlight-width="0"
highlight-event="onmouseover"
highlight-color="#EB3BFF66"
></nightingale-sequence-heatmap>
Expand Down
37 changes: 26 additions & 11 deletions packages/nightingale-sequence-heatmap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ Nightingale Sequence Heatmap component is used to generate a heatmap visualisati

It uses [heatmap-component](https://www.npmjs.com/package/heatmap-component) to render the canvas heatmap.

##### Attributes

###### `hm-highlight-width: number (default 0)`

Number of pixels for the border width of the heatmap. See [live demos](https://github.com/PDBeurope/heatmap-component/#live-demos)
for examples with border width 1.

## Usage

The below example shows how to instantiate the component
Expand All @@ -14,6 +21,7 @@ The below example shows how to instantiate the component
heatmap-id="seq-heatmap"
width="400"
height="400"
hm-highlight-width="0"
highlight-event="onmouseover"
highlight-color="#EB3BFF66"
></nightingale-sequence-heatmap>
Expand Down Expand Up @@ -71,16 +79,20 @@ interface HotmapData {
Allows dynamic setting of heatmap color palette

```javascript
customElements.whenDefined("nightingale-sequence-heatmap").then(() => {
customElements.whenDefined("nightingale-sequence-heatmap").then( async() => {
const heatmapElement = document.getElementById(
"id-for-nightingale-sequence-heatmap",
);
heatmapElement.setHeatmapData(xDomain, yDomain, data);

const colorScale = d3.scaleLinear(
[0, 1], // score value domain
["#ffffff", "#00441b"], // color range to map values
);
heatmapElement.heatmapInstance.setColor((d) => colorScale(d.score));

await heatmapElement.updateComplete.then(() => {
heatmapElement.heatmapInstance.setColor((d) => colorScale(d.score));
});
});
```

Expand All @@ -89,18 +101,21 @@ customElements.whenDefined("nightingale-sequence-heatmap").then(() => {
Allows dynamic setting of tooltip HTML content

```javascript
customElements.whenDefined("nightingale-sequence-heatmap").then(() => {
customElements.whenDefined("nightingale-sequence-heatmap").then( async() => {
const heatmapElement = document.getElementById(
"id-for-nightingale-sequence-heatmap",
);

heatmapElement.heatmapInstance.setTooltip((d, x, y, xIndex, yIndex) => {
let returnHTML = `
<b>Your are at</b> <br />
x,y: <b>${d.xValue},${d.yValue}</b><br />
score: <b>${d.score}</b>`;
return returnHTML;
heatmapElement.setHeatmapData(xDomain, yDomain, data);

await heatmapElement.updateComplete.then(() => {
heatmapElement.heatmapInstance.setTooltip((d, x, y, xIndex, yIndex) => {
let returnHTML = `
<b>You are at</b> <br />
x,y: <b>${d.xValue},${d.yValue}</b><br />
score: <b>${d.score}</b>`;
return returnHTML;
});
});
});
```
2 changes: 1 addition & 1 deletion packages/nightingale-sequence-heatmap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"dependencies": {
"@nightingale-elements/nightingale-new-core": "^4.5.0",
"d3": "7.8.5",
"heatmap-component": "^0.9.0"
"heatmap-component": "^1.0.1"
},
"publishConfig": {
"access": "public"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import NightingaleElement, {
withZoom,
} from "@nightingale-elements/nightingale-new-core";
import { Heatmap } from "heatmap-component";
import { formatDataItem } from "heatmap-component/lib/heatmap-component/utils";
import {
interpolateYlOrRd,
scaleSequential,
Expand All @@ -39,6 +38,11 @@ const hexComponentToNumber = (hexComp: string): number => {
return parseInt(hexComp, 16);
};

const formatDataItem = (item: unknown): string => {
if (typeof item === "number") return item.toFixed(3);
else return JSON.stringify(item);
};

const hexToRgb = (
hex: string,
): { r: number; g: number; b: number; a?: number } | null => {
Expand Down Expand Up @@ -73,10 +77,14 @@ class NightingaleSequenceHeatmap extends withManager(
@property({ type: String })
"heatmap-id"!: string;

@property({ type: Number })
"hm-highlight-width": number = 0;

heatmapDomainX?: number[];
heatmapDomainY?: string[];
heatmapData?: HotmapData[];
heatmapInstance?: Heatmap<number, string, HotmapData>;
firstZoom = false;

connectedCallback() {
super.connectedCallback();
Expand Down Expand Up @@ -137,6 +145,8 @@ class NightingaleSequenceHeatmap extends withManager(
let colorString = this["highlight-color"];
let fillValue = 0.9;

const highlightWidth = this["hm-highlight-width"];

const rgb = hexToRgb(this["highlight-color"]);
if (rgb) {
colorString = `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
Expand All @@ -158,12 +168,12 @@ class NightingaleSequenceHeatmap extends withManager(
.heatmap-marker-x {
fill: ${colorString} !important;
fill-opacity: ${fillValue} !important;
stroke-width: 0 !important;
stroke-width: ${highlightWidth} !important;
}
.heatmap-marker-y {
fill: ${colorString} !important;
fill-opacity: ${fillValue} !important;
stroke-width: 0 !important;
stroke-width: ${highlightWidth} !important;
}
${heatmapStyleSheet}
</style>
Expand Down Expand Up @@ -242,7 +252,7 @@ class NightingaleSequenceHeatmap extends withManager(
this.heatmapInstance!.setData({
xDomain: xDomain,
yDomain: yDomain,
items: data,
data: data,
x: (d) => {
const x = d.xValue;
return x;
Expand Down Expand Up @@ -292,7 +302,7 @@ class NightingaleSequenceHeatmap extends withManager(
const hm = Heatmap.create({
xDomain: this.heatmapDomainX!,
yDomain: this.heatmapDomainY!,
items: this.heatmapData!,
data: this.heatmapData!,
x: (d) => {
const x = d.xValue;
return x;
Expand All @@ -313,7 +323,7 @@ class NightingaleSequenceHeatmap extends withManager(

hm.setTooltip((d, _x, _y, _xIndex, _yIndex) => {
const returnHTML = `
<b>Your are at</b> <br />
<b>You are at</b> <br />
x,y: <b>${d.xValue},${d.yValue}</b><br />
score: <b>${formatDataItem(d.score)}</b>`;
Expand All @@ -339,35 +349,51 @@ class NightingaleSequenceHeatmap extends withManager(
// no data, stop zoom from occurring
if (!d) return;
// On heatmap zoom dispatch event to Nightingale
if (d.xMin + 0.5 !== this["display-start"]) {
let xDiff = d.xMin;
// if not zoomed yet but display attr values exist
if (!this.firstZoom && this["display-start"]) {
xDiff = this["display-start"];
}
if (xDiff !== this["display-start"]) {
this.dispatchEvent(
new CustomEvent("change", {
detail: {
value: d.xMin + 0.5,
value: xDiff,
type: "display-start",
},
bubbles: true,
cancelable: true,
}),
);
}
if (d.xMax - 0.5 !== this["display-end"]) {
let xMaxDiff = d.xMax - 1;
// if not zoomed yet but display attr values exist
if (!this.firstZoom && this["display-end"]) {
xMaxDiff = this["display-end"];
}
if (xMaxDiff !== this["display-end"]) {
this.dispatchEvent(
new CustomEvent("change", {
detail: {
value: d.xMax - 0.5,
value: xMaxDiff,
type: "display-end",
},
bubbles: true,
cancelable: true,
}),
);
}
if (!this.firstZoom) {
this.firstZoom = true;
}
});

this.heatmapInstance.events.hover.subscribe((d) => {
// data to send to nightingale can be null if hover outside boundaries
const toSend = d === undefined ? null : `${d.xIndex + 1}:${d.xIndex + 1}`;
let toSend = null;
if (d && d.cell && d.cell.xIndex) {
toSend = `${d.cell.xIndex + 1}:${d.cell.xIndex + 1}`;
}
// On heatmap zoom dispatch event to Nightingale
this.dispatchEvent(
new CustomEvent("change", {
Expand All @@ -387,11 +413,11 @@ class NightingaleSequenceHeatmap extends withManager(
*/
triggerHeatmapZoom() {
const toStart = this["display-start"]!;
const toEnd = this["display-end"]!;
const toEnd = this["display-end"]! + 1;
if (this.heatmapInstance) {
this.heatmapInstance.zoom({
xMin: toStart - 0.5,
xMax: toEnd + 0.5,
xMin: toStart,
xMax: toEnd,
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ exports[`nightingale-sequence-heatmap tests it should display the sequence corre
<!---->
0.359
!important;
stroke-width: 0 !important;
stroke-width:
<!---->
0
!important;
}
.heatmap-marker-y {
fill:
Expand All @@ -47,7 +50,10 @@ exports[`nightingale-sequence-heatmap tests it should display the sequence corre
<!---->
0.359
!important;
stroke-width: 0 !important;
stroke-width:
<!---->
0
!important;
}
<!---->
Expand Down Expand Up @@ -187,11 +193,13 @@ exports[`nightingale-sequence-heatmap tests it should display the sequence corre
style="position: absolute; width: 100%; height: 100%;"
>
<canvas
class="heatmap-canvas"
height="0"
style="position: absolute; width: 100%; height: 100%;"
width="0"
/>
<svg
class="heatmap-svg"
style="position: absolute; width: 100%; height: 100%;"
>
<rect
Expand Down Expand Up @@ -248,7 +256,10 @@ exports[`nightingale-sequence-heatmap tests it should display the sequence heatm
<!---->
0.359
!important;
stroke-width: 0 !important;
stroke-width:
<!---->
0
!important;
}
.heatmap-marker-y {
fill:
Expand All @@ -259,7 +270,10 @@ exports[`nightingale-sequence-heatmap tests it should display the sequence heatm
<!---->
0.359
!important;
stroke-width: 0 !important;
stroke-width:
<!---->
0
!important;
}
<!---->
Expand Down Expand Up @@ -399,11 +413,13 @@ exports[`nightingale-sequence-heatmap tests it should display the sequence heatm
style="position: absolute; width: 100%; height: 100%;"
>
<canvas
class="heatmap-canvas"
height="100"
style="position: absolute; width: 100%; height: 100%;"
width="100"
/>
<svg
class="heatmap-svg"
style="position: absolute; width: 100%; height: 100%;"
/>
</div>
Expand Down Expand Up @@ -450,7 +466,10 @@ exports[`nightingale-sequence-heatmap tests it should zoom in 1`] = `
<!---->
0.359
!important;
stroke-width: 0 !important;
stroke-width:
<!---->
0
!important;
}
.heatmap-marker-y {
fill:
Expand All @@ -461,7 +480,10 @@ exports[`nightingale-sequence-heatmap tests it should zoom in 1`] = `
<!---->
0.359
!important;
stroke-width: 0 !important;
stroke-width:
<!---->
0
!important;
}
<!---->
Expand Down Expand Up @@ -601,11 +623,13 @@ exports[`nightingale-sequence-heatmap tests it should zoom in 1`] = `
style="position: absolute; width: 100%; height: 100%;"
>
<canvas
class="heatmap-canvas"
height="0"
style="position: absolute; width: 100%; height: 100%;"
width="0"
/>
<svg
class="heatmap-svg"
style="position: absolute; width: 100%; height: 100%;"
/>
</div>
Expand Down
Loading

0 comments on commit ba28787

Please sign in to comment.