@jbrowse/plugin-hic 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/dist/HicAdapter/HicAdapter.d.ts +32 -0
- package/dist/HicAdapter/HicAdapter.js +85 -0
- package/dist/HicAdapter/HicAdapter.js.map +1 -0
- package/dist/HicAdapter/configSchema.d.ts +13 -0
- package/dist/HicAdapter/configSchema.js +22 -0
- package/dist/HicAdapter/configSchema.js.map +1 -0
- package/dist/HicAdapter/index.d.ts +3 -0
- package/dist/HicAdapter/index.js +39 -0
- package/dist/HicAdapter/index.js.map +1 -0
- package/dist/HicRenderer/HicRenderer.d.ts +53 -0
- package/dist/HicRenderer/HicRenderer.js +126 -0
- package/dist/HicRenderer/HicRenderer.js.map +1 -0
- package/dist/HicRenderer/components/HicRendering.d.ts +10 -0
- package/dist/HicRenderer/components/HicRendering.js +16 -0
- package/dist/HicRenderer/components/HicRendering.js.map +1 -0
- package/dist/HicRenderer/configSchema.d.ts +28 -0
- package/dist/HicRenderer/configSchema.js +37 -0
- package/dist/HicRenderer/configSchema.js.map +1 -0
- package/dist/HicRenderer/index.d.ts +3 -0
- package/dist/HicRenderer/index.js +17 -0
- package/dist/HicRenderer/index.js.map +1 -0
- package/dist/HicTrack/configSchema.d.ts +75 -0
- package/dist/HicTrack/configSchema.js +17 -0
- package/dist/HicTrack/configSchema.js.map +1 -0
- package/dist/HicTrack/index.d.ts +3 -0
- package/dist/HicTrack/index.js +20 -0
- package/dist/HicTrack/index.js.map +1 -0
- package/dist/LinearHicDisplay/configSchema.d.ts +33 -0
- package/dist/LinearHicDisplay/configSchema.js +25 -0
- package/dist/LinearHicDisplay/configSchema.js.map +1 -0
- package/dist/LinearHicDisplay/index.d.ts +3 -0
- package/dist/LinearHicDisplay/index.js +24 -0
- package/dist/LinearHicDisplay/index.js.map +1 -0
- package/dist/LinearHicDisplay/model.d.ts +332 -0
- package/dist/LinearHicDisplay/model.js +95 -0
- package/dist/LinearHicDisplay/model.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/esm/HicAdapter/HicAdapter.d.ts +32 -0
- package/esm/HicAdapter/HicAdapter.js +77 -0
- package/esm/HicAdapter/HicAdapter.js.map +1 -0
- package/esm/HicAdapter/configSchema.d.ts +13 -0
- package/esm/HicAdapter/configSchema.js +20 -0
- package/esm/HicAdapter/configSchema.js.map +1 -0
- package/esm/HicAdapter/index.d.ts +3 -0
- package/esm/HicAdapter/index.js +11 -0
- package/esm/HicAdapter/index.js.map +1 -0
- package/esm/HicRenderer/HicRenderer.d.ts +53 -0
- package/esm/HicRenderer/HicRenderer.js +97 -0
- package/esm/HicRenderer/HicRenderer.js.map +1 -0
- package/esm/HicRenderer/components/HicRendering.d.ts +10 -0
- package/esm/HicRenderer/components/HicRendering.js +11 -0
- package/esm/HicRenderer/components/HicRendering.js.map +1 -0
- package/esm/HicRenderer/configSchema.d.ts +28 -0
- package/esm/HicRenderer/configSchema.js +35 -0
- package/esm/HicRenderer/configSchema.js.map +1 -0
- package/esm/HicRenderer/index.d.ts +3 -0
- package/esm/HicRenderer/index.js +12 -0
- package/esm/HicRenderer/index.js.map +1 -0
- package/esm/HicTrack/configSchema.d.ts +75 -0
- package/esm/HicTrack/configSchema.js +15 -0
- package/esm/HicTrack/configSchema.js.map +1 -0
- package/esm/HicTrack/index.d.ts +3 -0
- package/esm/HicTrack/index.js +15 -0
- package/esm/HicTrack/index.js.map +1 -0
- package/esm/LinearHicDisplay/configSchema.d.ts +33 -0
- package/esm/LinearHicDisplay/configSchema.js +23 -0
- package/esm/LinearHicDisplay/configSchema.js.map +1 -0
- package/esm/LinearHicDisplay/index.d.ts +3 -0
- package/esm/LinearHicDisplay/index.js +19 -0
- package/esm/LinearHicDisplay/index.js.map +1 -0
- package/esm/LinearHicDisplay/model.d.ts +332 -0
- package/esm/LinearHicDisplay/model.js +93 -0
- package/esm/LinearHicDisplay/model.js.map +1 -0
- package/esm/index.d.ts +7 -0
- package/esm/index.js +50 -0
- package/esm/index.js.map +1 -0
- package/package.json +60 -0
- package/src/HicAdapter/HicAdapter.ts +150 -0
- package/src/HicAdapter/configSchema.ts +26 -0
- package/src/HicAdapter/index.ts +15 -0
- package/src/HicRenderer/HicRenderer.tsx +170 -0
- package/src/HicRenderer/components/HicRendering.test.tsx +21 -0
- package/src/HicRenderer/components/HicRendering.tsx +24 -0
- package/src/HicRenderer/components/__snapshots__/HicRendering.test.tsx.snap +14 -0
- package/src/HicRenderer/configSchema.ts +42 -0
- package/src/HicRenderer/index.ts +17 -0
- package/src/HicTrack/configSchema.ts +23 -0
- package/src/HicTrack/index.ts +16 -0
- package/src/LinearHicDisplay/configSchema.ts +33 -0
- package/src/LinearHicDisplay/index.ts +21 -0
- package/src/LinearHicDisplay/model.ts +104 -0
- package/src/declare.d.ts +2 -0
- package/src/index.ts +71 -0
package/esm/index.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import Plugin from '@jbrowse/core/Plugin';
|
|
2
|
+
import HicRendererF from './HicRenderer';
|
|
3
|
+
import HicTrackF from './HicTrack';
|
|
4
|
+
import LinearHicDisplayF from './LinearHicDisplay';
|
|
5
|
+
import HicAdapterF from './HicAdapter';
|
|
6
|
+
import { getFileName, } from '@jbrowse/core/util/tracks';
|
|
7
|
+
export default class HicPlugin extends Plugin {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
this.name = 'HicPlugin';
|
|
11
|
+
}
|
|
12
|
+
install(pluginManager) {
|
|
13
|
+
HicAdapterF(pluginManager);
|
|
14
|
+
HicRendererF(pluginManager);
|
|
15
|
+
HicTrackF(pluginManager);
|
|
16
|
+
LinearHicDisplayF(pluginManager);
|
|
17
|
+
pluginManager.addToExtensionPoint('Core-guessAdapterForLocation', (adapterGuesser) => {
|
|
18
|
+
return (file, index, adapterHint) => {
|
|
19
|
+
const regexGuess = /\.hic/i;
|
|
20
|
+
const adapterName = 'HicAdapter';
|
|
21
|
+
const fileName = getFileName(file);
|
|
22
|
+
const obj = {
|
|
23
|
+
type: adapterName,
|
|
24
|
+
hicLocation: file,
|
|
25
|
+
};
|
|
26
|
+
if (regexGuess.test(fileName) && !adapterHint) {
|
|
27
|
+
return obj;
|
|
28
|
+
}
|
|
29
|
+
else if (adapterHint === adapterName) {
|
|
30
|
+
return obj;
|
|
31
|
+
}
|
|
32
|
+
return adapterGuesser(file, index, adapterHint);
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
pluginManager.addToExtensionPoint('Core-guessTrackTypeForLocation', (trackTypeGuesser) => {
|
|
36
|
+
return (adapterName) => {
|
|
37
|
+
if (adapterName === 'HicAdapter') {
|
|
38
|
+
return 'HicTrack';
|
|
39
|
+
}
|
|
40
|
+
return trackTypeGuesser(adapterName);
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
configure(pluginManager) {
|
|
45
|
+
pluginManager.jexl.addFunction('alpha', (color, value) => color.alpha(value));
|
|
46
|
+
pluginManager.jexl.addFunction('hsl', (color) => color.hsl());
|
|
47
|
+
pluginManager.jexl.addFunction('colorString', (color) => color.string());
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
package/esm/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,sBAAsB,CAAA;AAIzC,OAAO,YAAY,MAAM,eAAe,CAAA;AACxC,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,iBAAiB,MAAM,oBAAoB,CAAA;AAClD,OAAO,WAAW,MAAM,cAAc,CAAA;AACtC,OAAO,EAEL,WAAW,GAEZ,MAAM,2BAA2B,CAAA;AAElC,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,MAAM;IAA7C;;QACE,SAAI,GAAG,WAAW,CAAA;IAuDpB,CAAC;IArDC,OAAO,CAAC,aAA4B;QAClC,WAAW,CAAC,aAAa,CAAC,CAAA;QAC1B,YAAY,CAAC,aAAa,CAAC,CAAA;QAC3B,SAAS,CAAC,aAAa,CAAC,CAAA;QACxB,iBAAiB,CAAC,aAAa,CAAC,CAAA;QAEhC,aAAa,CAAC,mBAAmB,CAC/B,8BAA8B,EAC9B,CAAC,cAA8B,EAAE,EAAE;YACjC,OAAO,CACL,IAAkB,EAClB,KAAoB,EACpB,WAAoB,EACpB,EAAE;gBACF,MAAM,UAAU,GAAG,QAAQ,CAAA;gBAC3B,MAAM,WAAW,GAAG,YAAY,CAAA;gBAChC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAA;gBAClC,MAAM,GAAG,GAAG;oBACV,IAAI,EAAE,WAAW;oBACjB,WAAW,EAAE,IAAI;iBAClB,CAAA;gBAED,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE;oBAC7C,OAAO,GAAG,CAAA;iBACX;qBAAM,IAAI,WAAW,KAAK,WAAW,EAAE;oBACtC,OAAO,GAAG,CAAA;iBACX;gBACD,OAAO,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,CAAA;YACjD,CAAC,CAAA;QACH,CAAC,CACF,CAAA;QACD,aAAa,CAAC,mBAAmB,CAC/B,gCAAgC,EAChC,CAAC,gBAAkC,EAAE,EAAE;YACrC,OAAO,CAAC,WAAmB,EAAE,EAAE;gBAC7B,IAAI,WAAW,KAAK,YAAY,EAAE;oBAChC,OAAO,UAAU,CAAA;iBAClB;gBACD,OAAO,gBAAgB,CAAC,WAAW,CAAC,CAAA;YACtC,CAAC,CAAA;QACH,CAAC,CACF,CAAA;IACH,CAAC;IAED,SAAS,CAAC,aAA4B;QACpC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,KAAY,EAAE,KAAa,EAAE,EAAE,CACtE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CACnB,CAAA;QACD,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,KAAY,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAA;QACpE,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC,KAAY,EAAE,EAAE,CAC7D,KAAK,CAAC,MAAM,EAAE,CACf,CAAA;IACH,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jbrowse/plugin-hic",
|
|
3
|
+
"version": "2.6.1",
|
|
4
|
+
"description": "JBrowse 2 hic adapters, tracks, etc.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jbrowse",
|
|
7
|
+
"jbrowse2"
|
|
8
|
+
],
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"homepage": "https://jbrowse.org",
|
|
11
|
+
"bugs": "https://github.com/GMOD/jbrowse-components/issues",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/GMOD/jbrowse-components.git",
|
|
15
|
+
"directory": "plugins/hic"
|
|
16
|
+
},
|
|
17
|
+
"author": "JBrowse Team",
|
|
18
|
+
"distMain": "dist/index.js",
|
|
19
|
+
"srcMain": "src/index.ts",
|
|
20
|
+
"main": "dist/index.js",
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"src",
|
|
24
|
+
"esm"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "npm-run-all build:*",
|
|
28
|
+
"test": "cd ../..; jest plugins/hic",
|
|
29
|
+
"prepublishOnly": "yarn test",
|
|
30
|
+
"prepack": "yarn build && yarn useDist",
|
|
31
|
+
"postpack": "yarn useSrc",
|
|
32
|
+
"useDist": "node ../../scripts/useDist.js",
|
|
33
|
+
"useSrc": "node ../../scripts/useSrc.js",
|
|
34
|
+
"prebuild": "npm run clean",
|
|
35
|
+
"build:esm": "tsc --build tsconfig.build.esm.json",
|
|
36
|
+
"build:es5": "tsc --build tsconfig.build.es5.json",
|
|
37
|
+
"clean": "rimraf dist esm *.tsbuildinfo"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"color": "^3.1.3",
|
|
41
|
+
"hic-straw": "^2.0.3"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@jbrowse/core": "^2.0.0",
|
|
45
|
+
"@jbrowse/plugin-linear-genome-view": "^2.0.0",
|
|
46
|
+
"@mui/material": "^5.0.0",
|
|
47
|
+
"mobx": "^6.0.0",
|
|
48
|
+
"mobx-react": "^7.0.0",
|
|
49
|
+
"mobx-state-tree": "^5.0.0",
|
|
50
|
+
"react": ">=16.8.0",
|
|
51
|
+
"rxjs": "^7.0.0"
|
|
52
|
+
},
|
|
53
|
+
"distModule": "esm/index.js",
|
|
54
|
+
"srcModule": "src/index.ts",
|
|
55
|
+
"module": "esm/index.js",
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"gitHead": "1cbe7ba097fb2d2763c776e5e429e4670cdd583c"
|
|
60
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseFeatureDataAdapter,
|
|
3
|
+
BaseOptions,
|
|
4
|
+
} from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
5
|
+
import { Region, FileLocation } from '@jbrowse/core/util/types'
|
|
6
|
+
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
|
|
7
|
+
import { openLocation } from '@jbrowse/core/util/io'
|
|
8
|
+
import type { GenericFilehandle } from 'generic-filehandle'
|
|
9
|
+
import HicStraw from 'hic-straw'
|
|
10
|
+
import PluginManager from '@jbrowse/core/PluginManager'
|
|
11
|
+
import { getSubAdapterType } from '@jbrowse/core/data_adapters/dataAdapterCache'
|
|
12
|
+
import { AnyConfigurationModel } from '@jbrowse/core/configuration'
|
|
13
|
+
|
|
14
|
+
interface ContactRecord {
|
|
15
|
+
bin1: number
|
|
16
|
+
bin2: number
|
|
17
|
+
counts: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface HicMetadata {
|
|
21
|
+
chromosomes: {
|
|
22
|
+
name: string
|
|
23
|
+
length: number
|
|
24
|
+
id: number
|
|
25
|
+
}[]
|
|
26
|
+
resolutions: number[]
|
|
27
|
+
}
|
|
28
|
+
interface Ref {
|
|
29
|
+
chr: string
|
|
30
|
+
start: number
|
|
31
|
+
end: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface HicOptions extends BaseOptions {
|
|
35
|
+
resolution?: number
|
|
36
|
+
bpPerPx?: number
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// wraps generic-filehandle so the read function only takes a position and length
|
|
40
|
+
// in some ways, generic-filehandle wishes it was just this but it has
|
|
41
|
+
// to adapt to the node.js fs promises API
|
|
42
|
+
class GenericFilehandleWrapper {
|
|
43
|
+
constructor(private filehandle: GenericFilehandle) {}
|
|
44
|
+
|
|
45
|
+
async read(position: number, length: number) {
|
|
46
|
+
const { buffer: b, bytesRead } = await this.filehandle.read(
|
|
47
|
+
Buffer.allocUnsafe(length),
|
|
48
|
+
0,
|
|
49
|
+
length,
|
|
50
|
+
position,
|
|
51
|
+
)
|
|
52
|
+
// xref https://stackoverflow.com/a/31394257/2129219
|
|
53
|
+
return b.buffer.slice(b.byteOffset, b.byteOffset + bytesRead)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function openFilehandleWrapper(
|
|
57
|
+
location: FileLocation,
|
|
58
|
+
pluginManager?: PluginManager,
|
|
59
|
+
) {
|
|
60
|
+
return new GenericFilehandleWrapper(openLocation(location, pluginManager))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface HicParser {
|
|
64
|
+
getContactRecords: (
|
|
65
|
+
normalize: string,
|
|
66
|
+
ref: Ref,
|
|
67
|
+
ref2: Ref,
|
|
68
|
+
units: string,
|
|
69
|
+
binsize: number,
|
|
70
|
+
) => Promise<ContactRecord[]>
|
|
71
|
+
getMetaData: () => Promise<HicMetadata>
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default class HicAdapter extends BaseFeatureDataAdapter {
|
|
75
|
+
private hic: HicParser
|
|
76
|
+
|
|
77
|
+
public constructor(
|
|
78
|
+
config: AnyConfigurationModel,
|
|
79
|
+
getSubAdapter?: getSubAdapterType,
|
|
80
|
+
pluginManager?: PluginManager,
|
|
81
|
+
) {
|
|
82
|
+
super(config, getSubAdapter, pluginManager)
|
|
83
|
+
const hicLocation = this.getConf('hicLocation')
|
|
84
|
+
this.hic = new HicStraw({
|
|
85
|
+
file: openFilehandleWrapper(hicLocation, this.pluginManager),
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private async setup(opts?: BaseOptions) {
|
|
90
|
+
const { statusCallback = () => {} } = opts || {}
|
|
91
|
+
statusCallback('Downloading .hic header')
|
|
92
|
+
const result = await this.hic.getMetaData()
|
|
93
|
+
statusCallback('')
|
|
94
|
+
return result
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public async getHeader(opts?: BaseOptions) {
|
|
98
|
+
const ret = await this.setup(opts)
|
|
99
|
+
const { chromosomes, ...rest } = ret
|
|
100
|
+
return rest
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async getRefNames(opts?: BaseOptions) {
|
|
104
|
+
const metadata = await this.setup(opts)
|
|
105
|
+
return metadata.chromosomes.map(chr => chr.name)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async getResolution(bpPerPx: number, opts?: BaseOptions) {
|
|
109
|
+
const { resolutions } = await this.setup(opts)
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
111
|
+
let chosenResolution = resolutions.at(-1)!
|
|
112
|
+
|
|
113
|
+
for (let i = resolutions.length - 1; i >= 0; i -= 1) {
|
|
114
|
+
const r = resolutions[i]
|
|
115
|
+
if (r <= 2 * bpPerPx) {
|
|
116
|
+
chosenResolution = r
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return chosenResolution
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getFeatures(region: Region, opts: HicOptions = {}) {
|
|
123
|
+
return ObservableCreate<ContactRecord>(async observer => {
|
|
124
|
+
const { refName: chr, start, end } = region
|
|
125
|
+
const { resolution, bpPerPx = 1, statusCallback = () => {} } = opts
|
|
126
|
+
const res = await this.getResolution(bpPerPx / (resolution || 1000), opts)
|
|
127
|
+
statusCallback('Downloading .hic data')
|
|
128
|
+
|
|
129
|
+
const records = await this.hic.getContactRecords(
|
|
130
|
+
'KR',
|
|
131
|
+
{ start, chr, end },
|
|
132
|
+
{ start, chr, end },
|
|
133
|
+
'BP',
|
|
134
|
+
res,
|
|
135
|
+
)
|
|
136
|
+
records.forEach(record => {
|
|
137
|
+
observer.next(record)
|
|
138
|
+
})
|
|
139
|
+
statusCallback('')
|
|
140
|
+
observer.complete()
|
|
141
|
+
}, opts.signal) as any // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// don't do feature stats estimation, similar to bigwigadapter
|
|
145
|
+
async getMultiRegionFeatureDensityStats(_regions: Region[]) {
|
|
146
|
+
return { featureDensity: 0 }
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
freeResources(/* { region } */): void {}
|
|
150
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ConfigurationSchema } from '@jbrowse/core/configuration'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* #config HicAdapter
|
|
5
|
+
* #category adapter
|
|
6
|
+
*/
|
|
7
|
+
function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
8
|
+
|
|
9
|
+
const HicAdapter = ConfigurationSchema(
|
|
10
|
+
'HicAdapter',
|
|
11
|
+
{
|
|
12
|
+
/**
|
|
13
|
+
* #slot
|
|
14
|
+
*/
|
|
15
|
+
hicLocation: {
|
|
16
|
+
type: 'fileLocation',
|
|
17
|
+
defaultValue: {
|
|
18
|
+
uri: '/path/to/my.hic',
|
|
19
|
+
locationType: 'UriLocation',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{ explicitlyTyped: true },
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
export default HicAdapter
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AdapterType } from '@jbrowse/core/pluggableElementTypes'
|
|
2
|
+
import PluginManager from '@jbrowse/core/PluginManager'
|
|
3
|
+
import configSchema from './configSchema'
|
|
4
|
+
|
|
5
|
+
export default (pluginManager: PluginManager) => {
|
|
6
|
+
pluginManager.addAdapterType(
|
|
7
|
+
() =>
|
|
8
|
+
new AdapterType({
|
|
9
|
+
name: 'HicAdapter',
|
|
10
|
+
displayName: 'Hi-C adapter',
|
|
11
|
+
configSchema,
|
|
12
|
+
getAdapterClass: () => import('./HicAdapter').then(r => r.default),
|
|
13
|
+
}),
|
|
14
|
+
)
|
|
15
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import ServerSideRendererType, {
|
|
2
|
+
RenderArgs as ServerSideRenderArgs,
|
|
3
|
+
RenderArgsDeserialized as ServerSideRenderArgsDeserialized,
|
|
4
|
+
ResultsSerialized as ServerSideResultsSerialized,
|
|
5
|
+
ResultsDeserialized as ServerSideResultsDeserialized,
|
|
6
|
+
} from '@jbrowse/core/pluggableElementTypes/renderers/ServerSideRendererType'
|
|
7
|
+
import { Region } from '@jbrowse/core/util/types'
|
|
8
|
+
import { abortBreakPoint } from '@jbrowse/core/util'
|
|
9
|
+
import { renderToAbstractCanvas } from '@jbrowse/core/util/offscreenCanvasUtils'
|
|
10
|
+
import { toArray } from 'rxjs/operators'
|
|
11
|
+
import { readConfObject } from '@jbrowse/core/configuration'
|
|
12
|
+
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
13
|
+
import { getAdapter } from '@jbrowse/core/data_adapters/dataAdapterCache'
|
|
14
|
+
import { AnyConfigurationModel } from '@jbrowse/core/configuration'
|
|
15
|
+
|
|
16
|
+
interface HicFeature {
|
|
17
|
+
bin1: number
|
|
18
|
+
bin2: number
|
|
19
|
+
counts: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface HicDataAdapter extends BaseFeatureDataAdapter {
|
|
23
|
+
getResolution: (bp: number) => Promise<number>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface RenderArgs extends ServerSideRenderArgs {
|
|
27
|
+
regions: Region[]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface RenderArgsDeserialized
|
|
31
|
+
extends ServerSideRenderArgsDeserialized {
|
|
32
|
+
regions: Region[]
|
|
33
|
+
dataAdapter: HicDataAdapter
|
|
34
|
+
bpPerPx: number
|
|
35
|
+
highResolutionScaling: number
|
|
36
|
+
resolution: number
|
|
37
|
+
adapterConfig: AnyConfigurationModel
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface RenderArgsDeserializedWithFeatures
|
|
41
|
+
extends RenderArgsDeserialized {
|
|
42
|
+
features: HicFeature[]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type ResultsSerialized = ServerSideResultsSerialized
|
|
46
|
+
|
|
47
|
+
export type ResultsDeserialized = ServerSideResultsDeserialized
|
|
48
|
+
|
|
49
|
+
export default class HicRenderer extends ServerSideRendererType {
|
|
50
|
+
supportsSVG = true
|
|
51
|
+
|
|
52
|
+
async makeImageData(
|
|
53
|
+
ctx: CanvasRenderingContext2D,
|
|
54
|
+
props: RenderArgsDeserializedWithFeatures,
|
|
55
|
+
) {
|
|
56
|
+
const {
|
|
57
|
+
features,
|
|
58
|
+
config,
|
|
59
|
+
bpPerPx,
|
|
60
|
+
signal,
|
|
61
|
+
resolution,
|
|
62
|
+
sessionId,
|
|
63
|
+
adapterConfig,
|
|
64
|
+
regions,
|
|
65
|
+
} = props
|
|
66
|
+
const [region] = regions
|
|
67
|
+
const { dataAdapter } = await getAdapter(
|
|
68
|
+
this.pluginManager,
|
|
69
|
+
sessionId,
|
|
70
|
+
adapterConfig,
|
|
71
|
+
)
|
|
72
|
+
const res = await (dataAdapter as HicDataAdapter).getResolution(
|
|
73
|
+
bpPerPx / resolution,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
const Color = await import('color').then(f => f.default)
|
|
77
|
+
const w = res / (bpPerPx * Math.sqrt(2))
|
|
78
|
+
const baseColor = Color(readConfObject(config, 'baseColor'))
|
|
79
|
+
if (features.length) {
|
|
80
|
+
const offset = features[0].bin1
|
|
81
|
+
let maxScore = 0
|
|
82
|
+
let minBin = 0
|
|
83
|
+
let maxBin = 0
|
|
84
|
+
await abortBreakPoint(signal)
|
|
85
|
+
for (let i = 0; i < features.length; i++) {
|
|
86
|
+
const { bin1, bin2, counts } = features[i]
|
|
87
|
+
maxScore = Math.max(counts, maxScore)
|
|
88
|
+
minBin = Math.min(Math.min(bin1, bin2), minBin)
|
|
89
|
+
maxBin = Math.max(Math.max(bin1, bin2), maxBin)
|
|
90
|
+
}
|
|
91
|
+
await abortBreakPoint(signal)
|
|
92
|
+
function horizontallyFlip() {
|
|
93
|
+
ctx.scale(-1, 1)
|
|
94
|
+
const width = (region.end - region.start) / bpPerPx
|
|
95
|
+
ctx.translate(-width, 0)
|
|
96
|
+
}
|
|
97
|
+
if (region.reversed === true) {
|
|
98
|
+
horizontallyFlip()
|
|
99
|
+
}
|
|
100
|
+
ctx.rotate(-Math.PI / 4)
|
|
101
|
+
let start = Date.now()
|
|
102
|
+
for (let i = 0; i < features.length; i++) {
|
|
103
|
+
const { bin1, bin2, counts } = features[i]
|
|
104
|
+
ctx.fillStyle = readConfObject(config, 'color', {
|
|
105
|
+
count: counts,
|
|
106
|
+
maxScore,
|
|
107
|
+
baseColor,
|
|
108
|
+
})
|
|
109
|
+
ctx.fillRect((bin1 - offset) * w, (bin2 - offset) * w, w, w)
|
|
110
|
+
if (+Date.now() - start > 400) {
|
|
111
|
+
await abortBreakPoint(signal)
|
|
112
|
+
start = +Date.now()
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async render(renderProps: RenderArgsDeserialized) {
|
|
119
|
+
const { config, regions, bpPerPx } = renderProps
|
|
120
|
+
const [region] = regions
|
|
121
|
+
const width = (region.end - region.start) / bpPerPx
|
|
122
|
+
const height = readConfObject(config, 'maxHeight')
|
|
123
|
+
const features = await this.getFeatures(renderProps)
|
|
124
|
+
|
|
125
|
+
const res = await renderToAbstractCanvas(width, height, renderProps, ctx =>
|
|
126
|
+
this.makeImageData(ctx, {
|
|
127
|
+
...renderProps,
|
|
128
|
+
features,
|
|
129
|
+
}),
|
|
130
|
+
)
|
|
131
|
+
const results = await super.render({
|
|
132
|
+
...renderProps,
|
|
133
|
+
...res,
|
|
134
|
+
features,
|
|
135
|
+
region: renderProps.regions[0],
|
|
136
|
+
height,
|
|
137
|
+
width,
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
...results,
|
|
142
|
+
...res,
|
|
143
|
+
height,
|
|
144
|
+
width,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async getFeatures(args: RenderArgsDeserialized) {
|
|
149
|
+
const { regions, sessionId, adapterConfig } = args
|
|
150
|
+
const { dataAdapter } = await getAdapter(
|
|
151
|
+
this.pluginManager,
|
|
152
|
+
sessionId,
|
|
153
|
+
adapterConfig,
|
|
154
|
+
)
|
|
155
|
+
const features = await (dataAdapter as BaseFeatureDataAdapter)
|
|
156
|
+
.getFeatures(regions[0], args)
|
|
157
|
+
.pipe(toArray())
|
|
158
|
+
.toPromise()
|
|
159
|
+
// cast to any to avoid return-type conflict, because the
|
|
160
|
+
// types of features returned by our getFeatures are quite
|
|
161
|
+
// different from the base interface
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
|
+
return features as any
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export {
|
|
168
|
+
type RenderArgsSerialized,
|
|
169
|
+
type RenderResults,
|
|
170
|
+
} from '@jbrowse/core/pluggableElementTypes/renderers/ServerSideRendererType'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { render } from '@testing-library/react'
|
|
3
|
+
import HicRendering from './HicRendering'
|
|
4
|
+
|
|
5
|
+
// these tests do very little, let's try to expand them at some point
|
|
6
|
+
test('one', () => {
|
|
7
|
+
const { container } = render(
|
|
8
|
+
<HicRendering
|
|
9
|
+
width={500}
|
|
10
|
+
height={500}
|
|
11
|
+
regions={[{ assemblyName: 'volvox', refName: 'zonk', start: 1, end: 3 }]}
|
|
12
|
+
bpPerPx={3}
|
|
13
|
+
blockKey="test"
|
|
14
|
+
/*
|
|
15
|
+
// @ts-expect-error */
|
|
16
|
+
displayModel={{}}
|
|
17
|
+
/>,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
expect(container.firstChild).toMatchSnapshot()
|
|
21
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Region } from '@jbrowse/core/util/types'
|
|
3
|
+
import { PrerenderedCanvas } from '@jbrowse/core/ui'
|
|
4
|
+
import { observer } from 'mobx-react'
|
|
5
|
+
|
|
6
|
+
export default observer(function HicRendering(props: {
|
|
7
|
+
blockKey: string
|
|
8
|
+
width: number
|
|
9
|
+
height: number
|
|
10
|
+
regions: Region[]
|
|
11
|
+
bpPerPx: number
|
|
12
|
+
}) {
|
|
13
|
+
const { width, height } = props
|
|
14
|
+
const canvasWidth = Math.ceil(width)
|
|
15
|
+
// need to call this in render so we get the right observer behavior
|
|
16
|
+
return (
|
|
17
|
+
<div style={{ position: 'relative', width: canvasWidth, height }}>
|
|
18
|
+
<PrerenderedCanvas
|
|
19
|
+
{...props}
|
|
20
|
+
style={{ position: 'absolute', left: 0, top: 0 }}
|
|
21
|
+
/>
|
|
22
|
+
</div>
|
|
23
|
+
)
|
|
24
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`one 1`] = `
|
|
4
|
+
<div
|
|
5
|
+
style="position: relative; width: 500px; height: 500px;"
|
|
6
|
+
>
|
|
7
|
+
<canvas
|
|
8
|
+
data-testid="prerendered_canvas_test"
|
|
9
|
+
height="500"
|
|
10
|
+
style="width: 500px; height: 500px; position: absolute; left: 0px; top: 0px;"
|
|
11
|
+
width="500"
|
|
12
|
+
/>
|
|
13
|
+
</div>
|
|
14
|
+
`;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ConfigurationSchema } from '@jbrowse/core/configuration'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* #config HicRenderer
|
|
5
|
+
* #category renderer
|
|
6
|
+
*/
|
|
7
|
+
function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
8
|
+
|
|
9
|
+
const HicRenderer = ConfigurationSchema(
|
|
10
|
+
'HicRenderer',
|
|
11
|
+
{
|
|
12
|
+
/**
|
|
13
|
+
* #slot
|
|
14
|
+
*/
|
|
15
|
+
baseColor: {
|
|
16
|
+
type: 'color',
|
|
17
|
+
description: 'base color to be used in the hic alignment',
|
|
18
|
+
defaultValue: '#f00',
|
|
19
|
+
},
|
|
20
|
+
/**
|
|
21
|
+
* #slot
|
|
22
|
+
*/
|
|
23
|
+
color: {
|
|
24
|
+
type: 'color',
|
|
25
|
+
description: 'the color of each feature in a hic alignment',
|
|
26
|
+
defaultValue: `jexl:colorString(hsl(alpha(baseColor,min(1,count/(maxScore/20)))))`,
|
|
27
|
+
contextVariable: ['count', 'maxScore', 'baseColor'],
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* #slot
|
|
32
|
+
*/
|
|
33
|
+
maxHeight: {
|
|
34
|
+
type: 'integer',
|
|
35
|
+
description: 'the maximum height to be used in a hic rendering',
|
|
36
|
+
defaultValue: 600,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{ explicitlyTyped: true },
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
export default HicRenderer
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import PluginManager from '@jbrowse/core/PluginManager'
|
|
2
|
+
|
|
3
|
+
import ReactComponent from './components/HicRendering'
|
|
4
|
+
import configSchema from './configSchema'
|
|
5
|
+
import HicRenderer from './HicRenderer'
|
|
6
|
+
|
|
7
|
+
export default (pluginManager: PluginManager) => {
|
|
8
|
+
pluginManager.addRendererType(
|
|
9
|
+
() =>
|
|
10
|
+
new HicRenderer({
|
|
11
|
+
name: 'HicRenderer',
|
|
12
|
+
ReactComponent,
|
|
13
|
+
configSchema,
|
|
14
|
+
pluginManager,
|
|
15
|
+
}),
|
|
16
|
+
)
|
|
17
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ConfigurationSchema } from '@jbrowse/core/configuration'
|
|
2
|
+
import { createBaseTrackConfig } from '@jbrowse/core/pluggableElementTypes'
|
|
3
|
+
import PluginManager from '@jbrowse/core/PluginManager'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* #config HicTrack
|
|
7
|
+
* #category track
|
|
8
|
+
*/
|
|
9
|
+
function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
10
|
+
|
|
11
|
+
const configSchema = (pluginManager: PluginManager) =>
|
|
12
|
+
ConfigurationSchema(
|
|
13
|
+
'HicTrack',
|
|
14
|
+
{},
|
|
15
|
+
{
|
|
16
|
+
/**
|
|
17
|
+
* #baseConfiguration
|
|
18
|
+
*/
|
|
19
|
+
baseConfiguration: createBaseTrackConfig(pluginManager),
|
|
20
|
+
},
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
export default configSchema
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import PluginManager from '@jbrowse/core/PluginManager'
|
|
2
|
+
import TrackType from '@jbrowse/core/pluggableElementTypes/TrackType'
|
|
3
|
+
import { createBaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models'
|
|
4
|
+
import configSchemaF from './configSchema'
|
|
5
|
+
|
|
6
|
+
export default (pluginManager: PluginManager) => {
|
|
7
|
+
pluginManager.addTrackType(() => {
|
|
8
|
+
const configSchema = configSchemaF(pluginManager)
|
|
9
|
+
return new TrackType({
|
|
10
|
+
name: 'HicTrack',
|
|
11
|
+
displayName: 'Hi-C track',
|
|
12
|
+
configSchema,
|
|
13
|
+
stateModel: createBaseTrackModel(pluginManager, 'HicTrack', configSchema),
|
|
14
|
+
})
|
|
15
|
+
})
|
|
16
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ConfigurationSchema } from '@jbrowse/core/configuration'
|
|
2
|
+
import { baseLinearDisplayConfigSchema } from '@jbrowse/plugin-linear-genome-view'
|
|
3
|
+
import { Instance } from 'mobx-state-tree'
|
|
4
|
+
import PluginManager from '@jbrowse/core/PluginManager'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* #config LinearHicDisplay
|
|
8
|
+
* #category display
|
|
9
|
+
*/
|
|
10
|
+
function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
11
|
+
|
|
12
|
+
const HicTrackConfigFactory = (pluginManager: PluginManager) => {
|
|
13
|
+
return ConfigurationSchema(
|
|
14
|
+
'LinearHicDisplay',
|
|
15
|
+
{
|
|
16
|
+
/**
|
|
17
|
+
* #slot
|
|
18
|
+
*/
|
|
19
|
+
renderer: pluginManager.getRendererType('HicRenderer').configSchema,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
/**
|
|
23
|
+
* #baseConfiguration
|
|
24
|
+
*/
|
|
25
|
+
baseConfiguration: baseLinearDisplayConfigSchema,
|
|
26
|
+
explicitlyTyped: true,
|
|
27
|
+
},
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type HicTrackConfigModel = ReturnType<typeof HicTrackConfigFactory>
|
|
32
|
+
export type HicTrackConfig = Instance<HicTrackConfigModel>
|
|
33
|
+
export default HicTrackConfigFactory
|