Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 53 additions & 25 deletions packages/regulation/epigenome-activity/epigenome-activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { html, css, svg, LitElement, type PropertyValues } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { scaleLinear, type ScaleLinear } from 'd3';

import { prepareActivityDataForDisplay } from './prepare-data';
import {
prepareActivityDataForDisplay,
type TrackDataForDisplay
} from './prepare-data';
import { toZeroBased } from '../helpers/toZeroBased';
import {
renderOpenChromatinSignals,
Expand Down Expand Up @@ -53,6 +56,9 @@ export class EpigenomeActivity extends LitElement {
@state()
bedScale: ScaleLinear<number, number> | null = null;

@state()
preparedTracksData: TrackDataForDisplay[] = [];

trackIds: string[][] = [];

connectedCallback(): void {
Expand All @@ -61,13 +67,22 @@ export class EpigenomeActivity extends LitElement {
}

willUpdate(changedProperties: PropertyValues) {
if (
const shouldUpdateScale =
changedProperties.has('start') ||
changedProperties.has('end') ||
changedProperties.has('imageWidth')
) {
changedProperties.has('imageWidth');

if (shouldUpdateScale) {
this.#updateScale();
}

if (
shouldUpdateScale ||
changedProperties.has('tracks') ||
changedProperties.has('trackMetadata')
) {
this.#updatePreparedTracksData();
}
}

updated() {
Expand All @@ -78,7 +93,7 @@ export class EpigenomeActivity extends LitElement {
const resizeObserver = new ResizeObserver((entries) => {
const [hostElementEntry] = entries;
const { width: hostWidth } = hostElementEntry.contentRect;
this.imageWidth = hostWidth;
this.imageWidth = Math.round(hostWidth);
});

resizeObserver.observe(this);
Expand All @@ -88,12 +103,27 @@ export class EpigenomeActivity extends LitElement {
this.bedScale = scaleLinear().domain([
toZeroBased(this.start),
this.end
]).rangeRound([
]).range([
0,
this.imageWidth
]);
}

#updatePreparedTracksData() {
const bedScale = this.bedScale;
if (!bedScale || !this.trackMetadata || !this.tracks.length) {
this.preparedTracksData = [];
return;
}

this.preparedTracksData = prepareActivityDataForDisplay({
location: { start: this.start, end: this.end },
scale: bedScale,
trackMetadata: this.trackMetadata,
tracks: this.tracks
});
}

#reportTrackPositions() {
// Check if the list of track ids has changed since previous render,
// and report to outside if it did
Expand All @@ -117,24 +147,18 @@ export class EpigenomeActivity extends LitElement {
}

render() {
if(!this.bedScale || !this.trackMetadata || !this.tracks.length) {
if (!this.bedScale || !this.preparedTracksData.length) {
return null;
}

const preparedTracksData = prepareActivityDataForDisplay({
location: { start: this.start, end: this.end },
scale: this.bedScale,
trackMetadata: this.trackMetadata,
tracks: this.tracks
});
const imageHeight = TRACK_HEIGHT * preparedTracksData.length;
const imageHeight = TRACK_HEIGHT * this.preparedTracksData.length;

return html`
<svg
viewBox="0 0 ${this.imageWidth} ${imageHeight}"
style="width: 100%; height: ${imageHeight}px;"
>
${this.#renderTracks({ tracks: preparedTracksData })}
${this.#renderTracks({ tracks: this.preparedTracksData })}
${this.#renderVerticalRules({ imageHeight })}
</svg>
`
Expand All @@ -143,30 +167,34 @@ export class EpigenomeActivity extends LitElement {
#renderTracks({
tracks
}: {
tracks: ReturnType<typeof prepareActivityDataForDisplay>
tracks: TrackDataForDisplay[]
}) {
return tracks.map((track, index) => {
return [
renderOpenChromatinSignals({
const renderedTracks: ReturnType<typeof svg>[] = [];

for (const [index, track] of tracks.entries()) {
renderedTracks.push(
...renderOpenChromatinSignals({
trackData: track,
offsetTop: index * TRACK_HEIGHT,
colors: this.colors
}),
renderOpenChromatinPeaks({
...renderOpenChromatinPeaks({
trackData: track,
offsetTop: index * TRACK_HEIGHT,
colors: this.colors
}),
renderHistoneNarrowPeaks({
...renderHistoneNarrowPeaks({
trackData: track,
offsetTop: index * TRACK_HEIGHT
}),
renderHistoneGappedPeaks({
...renderHistoneGappedPeaks({
trackData: track,
offsetTop: index * TRACK_HEIGHT
})
];
});
);
}

return renderedTracks;
}

#renderVerticalRules({
Expand Down Expand Up @@ -211,4 +239,4 @@ declare global {
interface HTMLElementTagNameMap {
'ens-reg-epigenome-activity': EpigenomeActivity;
}
}
}
23 changes: 5 additions & 18 deletions packages/regulation/epigenome-activity/prepare-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,24 +126,11 @@ const prepareOpenChromatinSignalsForTrack = ({
const signalX = scale(toZeroBased(signalStart));
const signalWidth = scale(signalEnd) - signalX;

const previousPreparedSignal = result.at(-1);

const distanceFromPreviousSignal = previousPreparedSignal
? signalX - previousPreparedSignal.x
: 1;

if (distanceFromPreviousSignal >= 1) {
const signal = {
x: signalX,
width: Math.max(signalWidth, 1),
value: signalValue
};
result.push(signal);
} else {
// combine current signal with the previous signal
const newValue = Math.round((signalValue + previousPreparedSignal!.value) / 2);
previousPreparedSignal!.value = newValue;
}
result.push({
x: signalX,
width: signalWidth,
value: signalValue
});
}

return result;
Expand Down
Loading