Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: remove cloning/stringify of tracks #1

Draft
wants to merge 29 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
435f967
perf: remove cloning/stringify of tracks
puehringer Oct 19, 2022
1775ec4
chore: export for getRelativeGenomicPosition
puehringer Nov 15, 2022
c009ab4
Merge branch 'master' into mp/clone_performance
puehringer Jan 30, 2023
422688d
Merge branch 'master' into mp/clone_performance
puehringer Sep 5, 2023
95a4e14
Add vite-plugin-dts for proper type building
puehringer Sep 5, 2023
42a538b
Add useCustomDataFetcher
puehringer Sep 5, 2023
06df357
Update path to types
puehringer Sep 7, 2023
fd5967c
Merge branch 'master' into mp/clone_performance
puehringer Nov 3, 2023
26621b8
Remove knip as it is not compatible with node 16.16
puehringer Nov 3, 2023
bd07a55
Change package export path
puehringer Nov 3, 2023
513fb1e
Update package.json
puehringer Nov 7, 2023
e8dea81
Merge branch 'master' into mp/clone_performance
puehringer Dec 5, 2023
a68fec6
Update index.ts
puehringer Dec 5, 2023
a5bbaf6
Update to latest master
puehringer Jan 9, 2024
a226429
Add dist folder
puehringer Jan 9, 2024
5cfdd97
Remove preinstall
puehringer Jan 9, 2024
2a2e05b
Remove pnpm package manager
puehringer Jan 9, 2024
6d79edc
Remove pnpm-lock.yaml
puehringer Jan 9, 2024
7f907f1
Remvoe dist again
puehringer Jan 9, 2024
0e1d13e
Remove pnpm package manager entry
puehringer Jan 9, 2024
a61a977
Migrate to yarn
puehringer Jan 9, 2024
00e5f09
Merge pull request #2 from datavisyn/mp/clone_performance_v2
puehringer Jan 9, 2024
33a2576
Merge branch 'main' into mp/clone_performance
puehringer Jan 9, 2024
d7c1b7b
feat: add support for custom color palettes
puehringer Jan 11, 2024
d49bb84
Add support for color ranges
puehringer Jan 11, 2024
78523be
Update gosling-track-model.ts
puehringer Jan 12, 2024
d3cfee1
Add rangeSelect always option
puehringer Feb 15, 2024
2f67c81
Add enabled flag to select style
puehringer Feb 15, 2024
cfd177a
Merge branch 'main' into mp/clone_performance
puehringer Jul 17, 2024
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
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# yarn
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

report.*
*.swp
*.swo
Expand Down
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
legacy-peer-deps=true
893 changes: 893 additions & 0 deletions .yarn/releases/yarn-4.0.2.cjs

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
checksumBehavior: update

nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-4.0.2.cjs
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"main": "dist/gosling.js",
"module": "dist/gosling.js",
"types": "dist/src/index.d.ts",
"packageManager": "[email protected]",
"--packageManager": "[email protected]",
"files": [
"dist"
],
Expand All @@ -33,16 +33,18 @@
"build-lib": "vite build --mode lib",
"build-types": "tsc --emitDeclarationOnly -p tsconfig.build.json",
"build-editor": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build",
"build-clear": "rm -rf ./dist",
"build-clear": "rimraf ./dist",
"preview": "vite preview",
"check": "tsc --noEmit",
"test": "vitest",
"coverage": "vitest run --coverage",
"format": "eslint src/ editor/ --fix && prettier 'editor/**/*.css' --write",
"schema": "node scripts/generate-schemas.mjs",
"version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md",
"prepare": "echo 'dummy prepare since prepack has no dev dependencies'",
"prepack": "npm run build",
"knip": "knip --config knip.config.json",
"preinstall": "npx only-allow pnpm",
"--preinstall": "npx only-allow pnpm",
"test-ct": "playwright test -c playwright-ct.config.ts"
},
"peerDependencies": {
Expand Down Expand Up @@ -139,6 +141,7 @@
"react-resize-detector": "^4.2.3",
"react-router-dom": "^5.2.0",
"remark-gfm": "^1.0.0",
"rimraf": "~5.0.5",
"safe-stable-stringify": "^2.4.3",
"strip-json-comments": "^3.1.1",
"ts-json-schema-generator": "^1.0.0",
Expand All @@ -161,5 +164,6 @@
"last 1 firefox version",
"last 1 safari version"
]
}
},
"packageManager": "[email protected]"
}
4 changes: 3 additions & 1 deletion src/compiler/gosling-to-higlass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ export function goslingToHiGlass(
firstResolvedSpec.data.type === 'bam' ||
firstResolvedSpec.data.type === 'vcf' ||
firstResolvedSpec.data.type === 'gff' ||
firstResolvedSpec.data.type === 'bed')
firstResolvedSpec.data.type === 'bed' ||
// TODO: This is a hack to enable custom data fetchers
(firstResolvedSpec.data as any).useCustomDataFetcher)
) {
const getFieldName = (c: 'x' | 'xe' | 'x1' | 'x1e') => {
const cDef = firstResolvedSpec[c];
Expand Down
7 changes: 4 additions & 3 deletions src/core/utils/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ export function resolveSuperposedTracks(track: Track): SingleTrack[] {
return [{ ...track, superpose: undefined } as SingleTrack];
}

const base: SingleTrack = JSON.parse(JSON.stringify(track));
delete (base as Partial<OverlaidTrack>)._overlay; // remove `superpose` from the base spec
// TODO: Is this sufficient? If yes, also apply to other functions doing this.
const { _overlay, ...base } = track as Partial<OverlaidTrack>;
// delete (base as Partial<OverlaidTrack>).overlay; // remove `superpose` from the base spec

const resolved: SingleTrack[] = [];
track._overlay.forEach((subSpec, i) => {
const spec = Object.assign(JSON.parse(JSON.stringify(base)), subSpec) as SingleTrack;
const spec = Object.assign({}, base, subSpec) as SingleTrack;
if (spec.title && i !== 0) {
delete spec.title;
}
Expand Down
6 changes: 5 additions & 1 deletion src/data-fetchers/json/json-data-fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,11 @@ function JsonDataFetcher(HGC: any, ...args: any): any {
// sample the data to make it managable for visualization components
const sizeLimit = this.dataConfig.sampleLength ?? 1000;
if (sizeLimit < tabularData.length) {
tabularData = sampleSize(tabularData, sizeLimit);
// TODO: allow to provide sampling method which incorporates order of JSON array (similar to tabularData.slice(0, sizeLimit))
tabularData =
this.dataConfig.sampleType === 'first'
? tabularData.slice(0, sizeLimit)
: sampleSize(tabularData, sizeLimit);
}

return {
Expand Down
8 changes: 8 additions & 0 deletions src/gosling-schema/gosling.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3469,6 +3469,14 @@
"description": "Specify the number of rows loaded from the URL.\n\n__Default:__ `1000`",
"type": "number"
},
"sampleType": {
"description": "Specify the way of sampling from the data if the number of rows to show exceeds `sampleLength`.\n\n__Default:__ `random`",
"enum": [
"first",
"random"
],
"type": "string"
},
"type": {
"const": "json",
"description": "Define data type.",
Expand Down
13 changes: 11 additions & 2 deletions src/gosling-schema/gosling.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ export type MouseEventsDeep = {
click?: boolean;

/** Whether to send range selection events. */
rangeSelect?: boolean;
rangeSelect?: boolean | 'always';

/** Group marks using keys in a data field. This affects how a set of marks are highlighted/selected by interaction. __Default__: `undefined` */
groupMarksByField?: string;
Expand Down Expand Up @@ -632,7 +632,9 @@ export interface Style {
/**
* Customize visual effects of `rangeSelect` events on marks .
*/
select?: EventStyle;
select?: EventStyle & {
enabled?: boolean;
};

/**
* Customize the style of the brush mark in the `rangeSelect` mouse event.
Expand Down Expand Up @@ -934,6 +936,13 @@ export interface JsonData {
*/
sampleLength?: number;

/**
* Specify the way of sampling from the data if the number of rows to show exceeds `sampleLength`.
*
* __Default:__ `random`
*/
sampleType?: 'first' | 'random';

/** experimental */
genomicFieldsToConvert?: {
chromosomeField: string;
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ export { compile } from './compiler/compile';
export { validateGoslingSpec } from '@gosling-lang/gosling-schema';
export { GoslingComponent } from './core/gosling-component';
export type { GoslingRef } from './core/gosling-component';
export type { HiGlassApi } from './core/higlass-component-wrapper';
export type { GoslingApi } from './api/api';
export { embed } from './core/gosling-embed';
9 changes: 8 additions & 1 deletion src/tracks/gosling-track/gosling-track-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class GoslingTrackModel {

this.theme = theme ?? getTheme();

this.dataAggregated = data; // this will be updated after validity of the spec is checked
this.dataAggregated = data;

this.specOriginal = spec;
this.specComplete = JSON.parse(JSON.stringify(spec));
Expand Down Expand Up @@ -797,6 +797,13 @@ export class GoslingTrackModel {
let interpolate = interpolateViridis;
if (Object.keys(PREDEFINED_COLOR_STR_MAP).includes(range as string)) {
interpolate = PREDEFINED_COLOR_STR_MAP[range as string];
} else if (Array.isArray(range) && range.every(d => typeof d === 'string')) {
// Support for custom color palettes, i.e. ["green", "red", "blue"]
const scaler = scaleLinear(range as string[]).domain(
// Map the range to [0, 0.5, 1] in the above example
range.map((_, i, arr) => i / (arr.length - 1))
);
interpolate = (t: number) => scaler(t);
}
this.channelScales[channelKey] = scaleSequential(interpolate).domain(
domain as [number, number]
Expand Down
14 changes: 8 additions & 6 deletions src/tracks/gosling-track/gosling-track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -939,8 +939,7 @@ const factory: PluginTrackFactory<Tile, GoslingTrackOptions> = (HGC, context, op
*/
getResolvedTracks(forceUpdate = false) {
if (forceUpdate || !this.resolvedTracks) {
const copy = structuredClone(this.options.spec);
const tracks = resolveSuperposedTracks(copy).filter(t => t.mark !== 'brush');
const tracks = resolveSuperposedTracks(this.options.spec).filter(t => t.mark !== 'brush');
// We will never need to access the values field in the data spec. It can be quite large which can degrade performance so we remove it.
tracks.forEach(track => {
if ('values' in track.data) {
Expand Down Expand Up @@ -1071,6 +1070,7 @@ const factory: PluginTrackFactory<Tile, GoslingTrackOptions> = (HGC, context, op
const numOrRows = tabularDataTransformed.length;
PubSub.publish('data-preview', {
id: context.viewUid,
// TODO: Do we need the stringified version? Stringify of large JSON data is very slow.
dataConfig: JSON.stringify({ data: resolvedSpec.data }),
data:
NUM_OF_ROWS_IN_PREVIEW > numOrRows
Expand Down Expand Up @@ -1128,7 +1128,9 @@ const factory: PluginTrackFactory<Tile, GoslingTrackOptions> = (HGC, context, op
// Determine whether to activate a range brush
const mouseEvents = this.options.spec.mouseEvents;
const rangeSelectEnabled = !!mouseEvents || (IsMouseEventsDeep(mouseEvents) && !!mouseEvents.rangeSelect);
this.#isRangeBrushActivated = rangeSelectEnabled && isAltPressed;
this.#isRangeBrushActivated =
rangeSelectEnabled &&
(isAltPressed || (IsMouseEventsDeep(mouseEvents) && mouseEvents.rangeSelect === 'always'));

this.pMouseHover.clear();
}
Expand Down Expand Up @@ -1256,14 +1258,14 @@ const factory: PluginTrackFactory<Tile, GoslingTrackOptions> = (HGC, context, op
) {
publish(eventType, {
id: context.viewUid,
spec: structuredClone(this.options.spec),
spec: this.options.spec,
shape: { x, y, width, height, cx, cy, innerRadius, outerRadius, startAngle, endAngle }
});
}
} else {
publish(eventType, {
id: context.viewUid,
spec: structuredClone(this.options.spec),
spec: this.options.spec,
shape: { x, y, width, height }
});
}
Expand Down Expand Up @@ -1300,7 +1302,7 @@ const factory: PluginTrackFactory<Tile, GoslingTrackOptions> = (HGC, context, op
});
}

if (capturedElements.length !== 0) {
if (capturedElements.length !== 0 && this.options.spec.style?.select?.enabled !== false) {
// selection effect graphics
const g = this.pMouseSelection;

Expand Down
Loading