@jbrowse/img 2.1.7 → 2.2.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/README.md +1 -4
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +2 -2
- package/dist/bin.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +207 -235
- package/dist/index.js.map +1 -0
- package/dist/index.testmod.d.ts +1 -0
- package/dist/index.testmod.js +166 -246
- package/dist/index.testmod.js.map +1 -0
- package/dist/parseArgv.d.ts +8 -0
- package/dist/parseArgv.js +42 -38
- package/dist/parseArgv.js.map +1 -0
- package/dist/parseArgv.testmod.d.ts +1 -0
- package/dist/parseArgv.testmod.js +25 -7
- package/dist/parseArgv.testmod.js.map +1 -0
- package/dist/renderRegion.d.ts +35 -0
- package/dist/renderRegion.js +350 -450
- package/dist/renderRegion.js.map +1 -0
- package/dist/util.d.ts +5 -0
- package/dist/util.js +31 -11
- package/dist/util.js.map +1 -0
- package/esm/bin.d.ts +2 -0
- package/esm/bin.js +4 -0
- package/esm/bin.js.map +1 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.js +185 -0
- package/esm/index.js.map +1 -0
- package/esm/index.testmod.d.ts +1 -0
- package/esm/index.testmod.js +141 -0
- package/esm/index.testmod.js.map +1 -0
- package/esm/parseArgv.d.ts +8 -0
- package/esm/parseArgv.js +42 -0
- package/esm/parseArgv.js.map +1 -0
- package/esm/parseArgv.testmod.d.ts +1 -0
- package/esm/parseArgv.testmod.js +24 -0
- package/esm/parseArgv.testmod.js.map +1 -0
- package/esm/renderRegion.d.ts +35 -0
- package/esm/renderRegion.js +366 -0
- package/esm/renderRegion.js.map +1 -0
- package/esm/util.d.ts +5 -0
- package/esm/util.js +25 -0
- package/esm/util.js.map +1 -0
- package/package.json +18 -17
- package/src/bin.js +2 -0
- package/src/index.testmod.js +163 -0
- package/src/index.ts +209 -0
- package/src/parseArgv.testmod.js +29 -0
- package/src/parseArgv.ts +48 -0
- package/src/renderRegion.tsx +456 -0
- package/src/util.ts +32 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import yargs from 'yargs'
|
|
3
|
+
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
|
|
4
|
+
import fetch, { Headers, Response, Request } from 'node-fetch'
|
|
5
|
+
import { JSDOM } from 'jsdom'
|
|
6
|
+
import { Image, createCanvas } from 'canvas'
|
|
7
|
+
|
|
8
|
+
// locals
|
|
9
|
+
import { standardizeArgv, parseArgv } from './parseArgv'
|
|
10
|
+
import { renderRegion, Opts } from './renderRegion'
|
|
11
|
+
import { convert } from './util'
|
|
12
|
+
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
global.nodeImage = Image
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
global.nodeCreateCanvas = createCanvas
|
|
17
|
+
|
|
18
|
+
const { document } = new JSDOM(`...`).window
|
|
19
|
+
global.document = document
|
|
20
|
+
|
|
21
|
+
// force use of node-fetch polyfill, even if node 18+ fetch is available.
|
|
22
|
+
// native node 18+ fetch currently gives errors related to unidici and
|
|
23
|
+
// Uint8Array:
|
|
24
|
+
//
|
|
25
|
+
//
|
|
26
|
+
// % node --version
|
|
27
|
+
// v18.12.1
|
|
28
|
+
//
|
|
29
|
+
// % jb2export --fasta https://jbrowse.org/code/jb2/main/test_data/volvox/volvox.fa --bam https://jbrowse.org/code/jb2/main/test_data/volvox/volvox-sorted.bam --loc ctgA:1-1000 --out out4.svg
|
|
30
|
+
// [
|
|
31
|
+
// '(node:1387934) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time\n' +
|
|
32
|
+
// '(Use `node --trace-warnings ...` to show where the warning was created)'
|
|
33
|
+
// ]
|
|
34
|
+
// [
|
|
35
|
+
// RangeError: offset is out of bounds
|
|
36
|
+
// at Uint8Array.set (<anonymous>)
|
|
37
|
+
// at Response.arrayBuffer (node:internal/deps/undici/undici:6117:23)
|
|
38
|
+
// at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
|
|
39
|
+
// ]
|
|
40
|
+
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
global.fetch = fetch
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
global.Headers = Headers
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
global.Response = Response
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
global.Request = Request
|
|
49
|
+
|
|
50
|
+
const err = console.error
|
|
51
|
+
console.error = (...p: unknown[]) => {
|
|
52
|
+
if (!`${p[0]}`.match('useLayoutEffect')) {
|
|
53
|
+
err(p)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const warn = console.warn
|
|
58
|
+
console.warn = (...p: unknown[]) => {
|
|
59
|
+
if (!`${p[0]}`.match('estimation reached timeout')) {
|
|
60
|
+
warn(p)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// note: yargs is actually unused except for printing help
|
|
65
|
+
// we do custom command line parsing, see parseArgv.ts
|
|
66
|
+
|
|
67
|
+
yargs
|
|
68
|
+
.command('jb2export', 'Creates a jbrowse 2 image snapshot')
|
|
69
|
+
.option('config', {
|
|
70
|
+
description: 'Path to config file',
|
|
71
|
+
type: 'string',
|
|
72
|
+
})
|
|
73
|
+
.option('session', {
|
|
74
|
+
description: 'Path to session file',
|
|
75
|
+
type: 'string',
|
|
76
|
+
})
|
|
77
|
+
.option('assembly', {
|
|
78
|
+
description:
|
|
79
|
+
'Path to an assembly configuration, or a name of an assembly in the configFile',
|
|
80
|
+
type: 'string',
|
|
81
|
+
})
|
|
82
|
+
.option('tracks', {
|
|
83
|
+
description: 'Path to tracks portion of a session',
|
|
84
|
+
type: 'string',
|
|
85
|
+
})
|
|
86
|
+
.option('loc', {
|
|
87
|
+
description:
|
|
88
|
+
'A locstring to navigate to, or --loc all to view the whole genome',
|
|
89
|
+
type: 'string',
|
|
90
|
+
})
|
|
91
|
+
.option('fasta', {
|
|
92
|
+
description: 'Supply a fasta for the assembly',
|
|
93
|
+
type: 'string',
|
|
94
|
+
})
|
|
95
|
+
.option('aliases', {
|
|
96
|
+
description:
|
|
97
|
+
'Supply aliases for the assembly, e.g. mapping of 1 to chr1. Tab separated file where column 1 matches the names from the FASTA',
|
|
98
|
+
type: 'string',
|
|
99
|
+
})
|
|
100
|
+
.option('width', {
|
|
101
|
+
description:
|
|
102
|
+
'Set the width of the window that jbrowse renders to, default: 1500px',
|
|
103
|
+
type: 'number',
|
|
104
|
+
})
|
|
105
|
+
.option('pngwidth', {
|
|
106
|
+
description:
|
|
107
|
+
'Set the width of the png canvas if using png output, default 2048px',
|
|
108
|
+
type: 'number',
|
|
109
|
+
default: 2048,
|
|
110
|
+
})
|
|
111
|
+
// track types
|
|
112
|
+
.option('configtracks', {
|
|
113
|
+
description: 'A list of track labels from a config file',
|
|
114
|
+
type: 'array',
|
|
115
|
+
})
|
|
116
|
+
.option('bam', {
|
|
117
|
+
description:
|
|
118
|
+
'A bam file, flag --bam can be used multiple times to specify multiple bam files',
|
|
119
|
+
type: 'array',
|
|
120
|
+
})
|
|
121
|
+
.option('bigwig', {
|
|
122
|
+
description:
|
|
123
|
+
'A bigwig file, the --bigwig flag can be used multiple times to specify multiple bigwig files',
|
|
124
|
+
type: 'array',
|
|
125
|
+
})
|
|
126
|
+
.option('cram', {
|
|
127
|
+
description:
|
|
128
|
+
'A cram file, the --cram flag can be used multiple times to specify multiple cram files',
|
|
129
|
+
type: 'array',
|
|
130
|
+
})
|
|
131
|
+
.option('vcfgz', {
|
|
132
|
+
description:
|
|
133
|
+
'A tabixed VCF, the --vcfgz flag can be used multiple times to specify multiple vcfgz files',
|
|
134
|
+
type: 'array',
|
|
135
|
+
})
|
|
136
|
+
.option('gffgz', {
|
|
137
|
+
description:
|
|
138
|
+
'A tabixed GFF, the --gffgz can be used multiple times to specify multiple gffgz files',
|
|
139
|
+
type: 'array',
|
|
140
|
+
})
|
|
141
|
+
.option('hic', {
|
|
142
|
+
description:
|
|
143
|
+
'A .hic file, the --hic can be used multiple times to specify multiple hic files',
|
|
144
|
+
type: 'array',
|
|
145
|
+
})
|
|
146
|
+
.option('bigbed', {
|
|
147
|
+
description:
|
|
148
|
+
'A .bigBed file, the --bigbed can be used multiple times to specify multiple bigbed files',
|
|
149
|
+
type: 'array',
|
|
150
|
+
})
|
|
151
|
+
.option('bedgz', {
|
|
152
|
+
description:
|
|
153
|
+
'A bed tabix file, the --bedgz can be used multiple times to specify multiple bedtabix files',
|
|
154
|
+
type: 'array',
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
// other
|
|
158
|
+
.option('out', {
|
|
159
|
+
description:
|
|
160
|
+
'File to output to. Default: out.svg. If a filename with extension .png is supplied the program will try to automatically execute rsvg-convert to convert it to png',
|
|
161
|
+
type: 'string',
|
|
162
|
+
default: 'out.svg',
|
|
163
|
+
})
|
|
164
|
+
.option('noRasterize', {
|
|
165
|
+
description:
|
|
166
|
+
'Use full SVG rendering with no rasterized layers, this can substantially increase filesize',
|
|
167
|
+
type: 'boolean',
|
|
168
|
+
})
|
|
169
|
+
.option('defaultSession', {
|
|
170
|
+
description: 'Use the defaultSession from config.json',
|
|
171
|
+
type: 'boolean',
|
|
172
|
+
})
|
|
173
|
+
.help()
|
|
174
|
+
.alias('help', 'h')
|
|
175
|
+
.alias('width', 'w').argv
|
|
176
|
+
|
|
177
|
+
const args = standardizeArgv(parseArgv(process.argv.slice(2)), [
|
|
178
|
+
'bam',
|
|
179
|
+
'cram',
|
|
180
|
+
'vcfgz',
|
|
181
|
+
'hic',
|
|
182
|
+
'bigwig',
|
|
183
|
+
'bigbed',
|
|
184
|
+
'bedgz',
|
|
185
|
+
'gffgz',
|
|
186
|
+
'configtracks',
|
|
187
|
+
])
|
|
188
|
+
|
|
189
|
+
;(async () => {
|
|
190
|
+
try {
|
|
191
|
+
const result = await renderRegion(args as Opts)
|
|
192
|
+
const { out = 'out.svg', pngwidth = '2048' } = args
|
|
193
|
+
if (out.endsWith('.png')) {
|
|
194
|
+
convert(result, { out, pngwidth })
|
|
195
|
+
} else if (out.endsWith('.pdf')) {
|
|
196
|
+
convert(result, { out, pngwidth }, ['-f', 'pdf'])
|
|
197
|
+
} else {
|
|
198
|
+
fs.writeFileSync(out, result)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// manually exit the process after done rendering because autoruns or
|
|
202
|
+
// something similar otherwise keeps the nodejs process alive xref
|
|
203
|
+
// https://github.com/GMOD/jb2export/issues/6
|
|
204
|
+
process.exit(0)
|
|
205
|
+
} catch (e) {
|
|
206
|
+
console.error(e)
|
|
207
|
+
process.exit(1)
|
|
208
|
+
}
|
|
209
|
+
})()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { parseArgv } from './parseArgv'
|
|
2
|
+
|
|
3
|
+
test('parse', () => {
|
|
4
|
+
const args =
|
|
5
|
+
'--bam dad.bam color:red --vcf variants.vcf --bam mom.bam --defaultSession --out out.svg --noRasterize'
|
|
6
|
+
|
|
7
|
+
expect(parseArgv(args.split(' '))).toEqual([
|
|
8
|
+
['bam', ['dad.bam', 'color:red']],
|
|
9
|
+
['vcf', ['variants.vcf']],
|
|
10
|
+
['bam', ['mom.bam']],
|
|
11
|
+
['defaultSession', []],
|
|
12
|
+
['out', ['out.svg']],
|
|
13
|
+
['noRasterize', []],
|
|
14
|
+
])
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('parse', () => {
|
|
18
|
+
const args =
|
|
19
|
+
'--bam dad.bam color:red --vcf variants.vcf --bam mom.bam force:true --defaultSession --out out.svg --noRasterize'
|
|
20
|
+
|
|
21
|
+
expect(parseArgv(args.split(' '))).toEqual([
|
|
22
|
+
['bam', ['dad.bam', 'color:red']],
|
|
23
|
+
['vcf', ['variants.vcf']],
|
|
24
|
+
['bam', ['mom.bam', 'force:true']],
|
|
25
|
+
['defaultSession', []],
|
|
26
|
+
['out', ['out.svg']],
|
|
27
|
+
['noRasterize', []],
|
|
28
|
+
])
|
|
29
|
+
})
|
package/src/parseArgv.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type Entry = [string, string[]]
|
|
2
|
+
|
|
3
|
+
// example (see parseArgv.test.js):
|
|
4
|
+
// const args =
|
|
5
|
+
// '--bam dad.bam color:red --vcf variants.vcf --bam mom.bam --defaultSession --out out.svg --noRasterize'
|
|
6
|
+
//
|
|
7
|
+
// expect(parseArgv(args.split(' '))).toEqual([
|
|
8
|
+
// ['bam', ['dad.bam', 'color:red']],
|
|
9
|
+
// ['vcf', ['variants.vcf']],
|
|
10
|
+
// ['bam', ['mom.bam']],
|
|
11
|
+
// ['defaultSession', []],
|
|
12
|
+
// ['out', ['out.svg']],
|
|
13
|
+
// ['noRasterize', []],
|
|
14
|
+
// ])
|
|
15
|
+
export function parseArgv(argv: string[]) {
|
|
16
|
+
const map = [] as Entry[]
|
|
17
|
+
while (argv.length) {
|
|
18
|
+
const val = argv[0].slice(2)
|
|
19
|
+
argv = argv.slice(1)
|
|
20
|
+
const next = argv.findIndex(arg => arg.startsWith('-'))
|
|
21
|
+
|
|
22
|
+
if (next !== -1) {
|
|
23
|
+
map.push([val, argv.slice(0, next)])
|
|
24
|
+
argv = argv.slice(next)
|
|
25
|
+
} else {
|
|
26
|
+
map.push([val, argv])
|
|
27
|
+
break
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return map
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function standardizeArgv(args: Entry[], trackTypes: string[]) {
|
|
34
|
+
const result = { trackList: [] } as {
|
|
35
|
+
trackList: Entry[]
|
|
36
|
+
out?: string
|
|
37
|
+
pngwidth?: string
|
|
38
|
+
[key: string]: unknown
|
|
39
|
+
}
|
|
40
|
+
args.forEach(arg => {
|
|
41
|
+
if (trackTypes.includes(arg[0])) {
|
|
42
|
+
result.trackList.push(arg)
|
|
43
|
+
} else {
|
|
44
|
+
result[arg[0]] = arg[1][0] || true
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
return result
|
|
48
|
+
}
|