Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
43d46ee
feat: spatial MVP
dvdkouril Jan 21, 2025
cbbe9a3
chore(editor): spatial examples are the default demo in the editor (#…
sehilyi Mar 19, 2025
07c0d3a
feat: 3D model for a spatial view specified in the layout (#1131)
sehilyi Apr 2, 2025
929d664
chore: move the 3d examples to the top; use the new grammar in exampl…
sehilyi Apr 2, 2025
ee58139
feat(editor): add a 3D yeast model example displayed in three layout …
sehilyi Apr 3, 2025
3f24522
Clean up basic examples (#1141)
dvdkouril Apr 3, 2025
6c37009
feat: remove data requirement for 3D tracks (#1142)
sehilyi Apr 4, 2025
b8985e4
fix: parsed genomic coordinates shouldn't be NaN even if assembly is …
sehilyi Apr 4, 2025
405899a
Example: three different ways of setting color (#1144)
dvdkouril Apr 4, 2025
04170f4
fix: pass the mark option from spec
dvdkouril Apr 4, 2025
9bf6c32
feat: density example (#1145)
dvdkouril Apr 4, 2025
c41c62b
feat(editor): example of composing multiple tracks within one spatial…
dvdkouril Apr 7, 2025
009c1f7
feat(editor): add example using models from Tan 2018 (#1148)
dvdkouril Apr 7, 2025
782117a
feat(editor): Tan example highlights using sequential color (#1149)
dvdkouril Apr 7, 2025
e03c9e5
format
dvdkouril Aug 4, 2025
f235b07
more format/eslint
dvdkouril Aug 4, 2025
3fa27e6
format: remove unused vars
dvdkouril Aug 4, 2025
c528b0a
dirty assert options as SpatialTrackOptions
dvdkouril Aug 4, 2025
0b24814
refactor: somewhat better type check when fetching column from tables
dvdkouril Aug 4, 2025
f64b3e9
refactor: getting rid of squiggly lines
dvdkouril Aug 4, 2025
29f7dbe
refactor: typing of the handleColor function
dvdkouril Aug 4, 2025
9cf7e8f
refactor: type errors in handleSizeField
dvdkouril Aug 4, 2025
2865a15
wip
dvdkouril Aug 4, 2025
dd5f726
temporary fix: doesn't make sense now but new uchimata will fix it
dvdkouril Aug 4, 2025
04cd9d6
refactor: use new library name and update api usage
dvdkouril Sep 25, 2025
6186551
(wip)fix: type errors around spatial views/tracks
dvdkouril Sep 25, 2025
d5198de
suppress warning about `ProcessedSpatialTrack`
dvdkouril Sep 26, 2025
f7fda7b
assert xScale when using certain transforms
dvdkouril Sep 26, 2025
202a894
fix import path
dvdkouril Sep 26, 2025
5632201
cleaning up some properties
dvdkouril Sep 26, 2025
34435be
rename ChromospaceTrack to SpatialTrack
dvdkouril Sep 29, 2025
e7c2e7d
mark a todo for later
dvdkouril Sep 29, 2025
c1523b8
regenerate json schema
dvdkouril Sep 29, 2025
f08e858
add Encoding in the SpatialTrack type
dvdkouril Sep 29, 2025
3480bec
add data to spatialtrack
dvdkouril Sep 29, 2025
35d4c19
wip: copying over some properties
dvdkouril Oct 3, 2025
38774cc
wip(broken): sorted out the types
dvdkouril Oct 3, 2025
aa24d84
working version without type errors
dvdkouril Oct 6, 2025
a3775ef
docs
dvdkouril Oct 7, 2025
9488010
regenerate schema
dvdkouril Oct 7, 2025
f06d63f
cleaning up the changes
dvdkouril Oct 7, 2025
e139212
remove console logs
dvdkouril Oct 7, 2025
1d7b7b5
run prettier on package.json
dvdkouril Oct 9, 2025
3989151
format
dvdkouril Oct 9, 2025
ca10544
Merge branch 'v2' into spatial
dvdkouril Oct 9, 2025
f405765
Update editor/example/json-spec/3d-yeast-model.ts
dvdkouril Oct 15, 2025
2ca29c1
Update editor/example/json-spec/3d-yeast-model.ts
dvdkouril Oct 15, 2025
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
1 change: 1 addition & 0 deletions demo/gosling-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export function GoslingComponent(props: GoslingComponentProps) {
></div>
);
}

/**
* This is the main function. It takes a Gosling spec and renders it using the PixiManager
*/
Expand Down
4 changes: 3 additions & 1 deletion demo/renderer/dataFetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ export function getDataFetcher(spec: SingleTrack | OverlaidTrack, urlToFetchOpti

if (typeof data === 'undefined') {
console.warn('No data in the track spec', spec);
return;
// A data object can be missing in 3D tracks. In this case, just pass an empty data.
// The 3d track can still use the 3D genome model for visual encoding.
return new JsonDataFetcher({ type: 'json', values: [], assembly: spec.assembly ?? 'unknown' });
}

const { type } = data;
Expand Down
19 changes: 19 additions & 0 deletions demo/renderer/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import type { UrlToFetchOptions } from 'src/compiler/compile';
import type { Tile } from '@higlass/services';
import type { DataFetcher } from '@higlass/datafetcher';
import type { OverlaidTrack, SingleTrack } from '@gosling-lang/gosling-schema';
import { createSpatialTrack, type SpatialTrackOptions } from '../../src/tracks/spatial-track/spatial-track';
import type { CsvDataFetcherClass } from 'src/data-fetchers/csv/csv-data-fetcher';

/**
* Takes a list of track definitions and linkedEncodings and renders them
Expand Down Expand Up @@ -146,6 +148,23 @@ export function renderTrackDefs(
const dummyPlot = new DummyTrack(dummyOptions, pixiManager.makeContainer(boundingBox).overlayDiv);
plotDict[trackId] = dummyPlot;
}
// Add a new track type for `spatial` layout (rendered via uchimata)
if (type === TrackType.Spatial) {
// Even though uchimata doesn't use PixiJS, we can use the PixiManager to create a div container that the canvas can be placed into.
// In the final version, we would probably want uchimata to use an existing canvas element (to limit the creation of new elements).
// But for now this gets the job done.
const container = pixiManager.makeContainer(boundingBox).overlayDiv;
const spatialTrackOptions = options as SpatialTrackOptions; //~ TODO: properly assert the type!
console.warn('!@$!#%@# detected spatial track !@#$!#%@#');
if (spatialTrackOptions.spec.data) {
// Ensure to pull all data needed
if ('sampleLength' in spatialTrackOptions.spec.data) {
spatialTrackOptions.spec.data.sampleLength = 30000;
}
}
const datafetcher = getDataFetcher(spatialTrackOptions.spec, urlToFetchOptions);
createSpatialTrack(spatialTrackOptions, datafetcher as CsvDataFetcherClass, container);
}
});
return plotDict;
}
Expand Down
18 changes: 17 additions & 1 deletion demo/track-def/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { type BrushLinearTrackOptions } from '@gosling-lang/brush-linear';
import type { TrackInfo } from '../../src/compiler/bounding-box';
import type { CompleteThemeDeep } from '../../src/core/utils/theme';
import type { GoslingTrackOptions } from '../../src/tracks/gosling-track/gosling-track';
import type { SpatialTrackOptions } from 'src/tracks/spatial-track/spatial-track';

import { proccessTextHeader } from './text';
import { processHeatmapTrack, isHeatmapTrack } from './heatmap';
Expand All @@ -25,7 +26,8 @@ export enum TrackType {
Axis,
BrushLinear,
BrushCircular,
Heatmap
Heatmap,
Spatial
}

/**
Expand All @@ -39,6 +41,7 @@ interface TrackOptionsMap {
[TrackType.BrushLinear]: BrushLinearTrackOptions;
[TrackType.BrushCircular]: BrushCircularTrackOptions;
[TrackType.Heatmap]: HeatmapTrackOptions;
[TrackType.Spatial]: SpatialTrackOptions;
}

/**
Expand Down Expand Up @@ -81,6 +84,19 @@ export function createTrackDefs(trackInfos: TrackInfo[], theme: Required<Complet
// We have a dummy track
const dummyTrackDefs = processDummyTrack(track, boundingBox, theme);
trackDefs.push(...dummyTrackDefs);
} else if ('layout' in track && track.layout === 'spatial') {
// We have a 3D track
const trackDef: TrackDef<SpatialTrackOptions> = {
type: TrackType.Spatial,
trackId: track.id,
boundingBox,
options: {
// @ts-expect-error At this point, the spec is processed
spec: track,
processedSpec: track
}
};
trackDefs.push(trackDef);
} else {
// We have a gosling track
const goslingAxisDefs = processGoslingTrack(track, boundingBox, theme);
Expand Down
24 changes: 20 additions & 4 deletions demo/track-def/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@ import type { DataDeep, Assembly, DummyTrackStyle, Mark, X, Y } from '@gosling-l
*/

/** A Track after it has been compiled */
export type ProcessedTrack = ProcessedLinearTrack | ProcessedCircularTrack | ProcessedDummyTrack;
// TODO: This should be much better expanded to include all the properties that are actually present.
export type ProcessedTrack =
| ProcessedLinearTrack
| ProcessedCircularTrack
| ProcessedDummyTrack
| ProcessedSpatialTrack;
/** All tracks potentially have these properties */
export interface ProcessedTrackBase {
layout?: 'linear' | 'circular';
layout?: 'linear' | 'circular' | 'spatial';
id: string;
height: number;
width: number;
static: boolean;
mark?: string;
mark?: Mark;
orientation: 'horizontal' | 'vertical';
title?: string;
subtitle?: string;
Expand Down Expand Up @@ -51,6 +54,19 @@ export type ProcessedCircularTrack = ProcessedTrackBase & {
innerRadius: number;
};

//~ DK: AFAIK, this needs to loosely fit definitions in Track.
//~ it is force casted via `as ProcessedTrack`, so there's no strict type checking.
export type ProcessedSpatialTrack = ProcessedTrackBase & {
layout: 'spatial';
spatial: {
x: string;
y: string;
z: string;
chr: string;
coord: string;
};
};

export type ProcessedDummyTrack = (ProcessedLinearTrack | ProcessedCircularTrack) & {
type: 'dummy-track';
style?: DummyTrackStyle;
Expand Down
68 changes: 68 additions & 0 deletions docs/spatial-layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# 3D genome structures in Gosling

This file documents the changes in the specification and gosling.js library to
support visualizing 3D structures of genomes.

In principle, there are two ways to define a spatial view:
1. on the **view level**
2. on the **track level**

## view-level specification
We can supply a 3D model data file and bind it to spatial layout properties in
the definition of view's `layout`. This has two advantages: 1) there is no need
to repeat the definitions of a model in each track, and 2) this enables to
merge two data files (one to define the 3D model, and another with a genomic
signal).

```javascript
{
views: [
{
layout: {
type: "spatial",
model: {
type: "csv",
url: "https://.../full-model.csv",
xyz: ["x", "y", "z"],
chromosome: "chr",
position: "coord"
}
},
tracks: [
{ mark: "sphere" },
{ mark: "box" },
]
}
]
}
```

The other method uses simply specifying layout as `spatial` and using the data
in a track for defining the model:
```javascript
{
views: [
{
layout: "spatial",
tracks: [
{
data: { type: "csv", url: "https://.../full-model.csv" },
spatial: {
x: "xfield",
y: "yfield",
z: "zfield"
chr: "chrfield",
coord: "positionfield",
},
mark: "sphere",
}
]
}
]
}
```
This doesn't allow for combining the structural data with any other genomic
formats, unless the genomic data are integrated in the csv already.

Internally, the first method is converted into the second one. The model data
file from the `layout` is pushed down to a dataTransform.
42 changes: 42 additions & 0 deletions editor/example/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import JS_SPEC_ISLANDVIEWER from './spec/islandviewer.ts?raw';
import { spec as JSON_SPEC_ISLANDVIEWER } from './spec/islandviewer';

export type ExampleGroup =
| 'Spatial Layout'
| 'Visual Encoding'
| 'Mouse Events'
| 'Semantic Zooming'
Expand All @@ -44,6 +45,10 @@ export const ExampleGroups: {
name: ExampleGroup;
description: string;
}[] = [
{
name: 'Spatial Layout',
description: 'Visualizations using 3D genome models'
},
{
name: 'Visual Encoding',
description:
Expand Down Expand Up @@ -423,6 +428,43 @@ export const editorExampleObj: {
spec: JsonExampleSpecs.EX_SPEC_PERF_ALIGNMENT,
image: THUMBNAILS.PERF_ALIGNMENT
},
SPATIAL_LAYOUT_MIN: {
group: 'Spatial Layout',
name: 'Minimal Example',
spec: JsonExampleSpecs.EX_SPEC_SPATIAL_MINIMAL,
image: THUMBNAILS.SPATIAL_MINIMAL
},
SPATIAL_LAYOUT_COLORS: {
group: 'Spatial Layout',
name: 'Coloring Strategies',
spec: JsonExampleSpecs.EX_SPEC_SPATIAL_COLOR,
image: THUMBNAILS.SPATIAL_COLOR
},
SPATIAL_LAYOUT_DENSITY: {
group: 'Spatial Layout',
name: 'Density',
spec: JsonExampleSpecs.EX_SPEC_SPATIAL_DENSITY,
image: THUMBNAILS.SPATIAL_DENSITY
},
SPATIAL_LAYOUT_SUPERIMP: {
group: 'Spatial Layout',
name: 'Multiple tracks',
spec: JsonExampleSpecs.EX_SPEC_SPATIAL_MULTIPLE_TRACKS,
image: THUMBNAILS.SPATIAL_MULTIPLE_TRACKS
},
SPATIAL_LAYOUT_TAN_COMP: {
group: 'Spatial Layout',
name: 'Human Cell Model (Tan et al., Science 2018): Comparison',
spec: JsonExampleSpecs.EX_SPEC_SPATIAL_TAN_COMP,
image: THUMBNAILS.SPATIAL_TAN
},
SPATIAL_LAYOUT_3D_YEAST_MODEL: {
group: 'Spatial Layout',
name: '3D Yeast Model (Nature 2010)',
spec: JsonExampleSpecs.EX_SPEC_3D_YEAST_MODEL,
image: THUMBNAILS.SPATIAL_YEAST,
forceShow: true
},
CORCES_ET_AL: {
group: 'Coordinated Multiple Views',
name: 'Corces et al. 2020',
Expand Down
Loading