@jbrowse/cli 5.0.0-beta.11 → 5.0.0-beta.14

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 CHANGED
@@ -59,7 +59,7 @@ COMMANDS
59
59
  admin-server Start up a small admin server for JBrowse configuration
60
60
  upgrade Upgrades JBrowse 2 to latest version
61
61
  make-pif Creates pairwise indexed PAF (PIF), with bgzip and tabix
62
- make-density Counts feature starts per bin into a bigWig density sidecar, with bedGraphToBigWig
62
+ make-density Counts feature starts per bin into a bigWig, with bedGraphToBigWig
63
63
  sort-gff Sort a GFF/GTF for tabix: sort -k1,1 -k4,4n, header kept on top
64
64
  sort-bed Sort a BED for tabix: sort -k1,1 -k2,2n, header kept on top
65
65
  add-connection Add a connection to a JBrowse 2 configuration
@@ -280,7 +280,7 @@ Options:
280
280
  displayDefaults
281
281
 
282
282
  --displayDefaults Inline JSON merged into the track displayDefaults
283
- (labels, mouseover, filter, etc.)
283
+ (labels, color, filter, etc.)
284
284
 
285
285
  --multiwig Build a MultiQuantitativeTrack from several BigWigs
286
286
  (in place of the positional track arg): a
@@ -311,11 +311,6 @@ Options:
311
311
 
312
312
  --bed2 Used only for mcscan anchors/simpleAnchors types
313
313
 
314
- --density Path or URL of a features-per-bin bigWig (jbrowse
315
- make-density) to attach as the adapter's
316
- densityAdapter. A local <file>.density.bw beside
317
- the track file is attached without this flag
318
-
319
314
  Notes:
320
315
 
321
316
  --load controls how the data file is placed relative to config.json: copy, move,
@@ -335,21 +330,13 @@ text-index.
335
330
  JSON. Wrap the value in single quotes and use double quotes inside a jexl
336
331
  callback so nothing needs escaping, e.g. --color
337
332
  'jexl:feature.strand==1?"blue":"red"'. --displayDefaults takes inline JSON for
338
- any other appearance setting (labels, mouseover, filter).
333
+ any other appearance setting (labels, facet, filter).
339
334
 
340
335
  --multiwig bundles several BigWigs into one MultiQuantitativeTrack, in place of
341
336
  the positional track argument: pass a comma-separated list of BigWig files/URLs,
342
337
  or a .json file with an array of BigWig locations or subadapter objects (each
343
- carrying its own name/color/group). With --load, local list entries are copied
344
- like any other track file.
345
-
346
- --density attaches a features-per-bin bigWig (jbrowse make-density) as the
347
- adapter's densityAdapter, the band a display draws where the region is too large
348
- to fetch features. A local <file>.density.bw beside the track file is attached
349
- without the flag; a URL cannot be probed, so a remote sidecar needs it. The
350
- adapters carrying the slot are BamAdapter, CramAdapter, HtsgetBamAdapter,
351
- Gff3TabixAdapter, GtfTabixAdapter, BedTabixAdapter, BigBedAdapter,
352
- VcfTabixAdapter and SplitVcfTabixAdapter.
338
+ with its own name/color/group). With --load, local list entries are copied like
339
+ any other track file.
353
340
 
354
341
  For pairwise synteny adapters (PAF/Delta/Chain) --assemblyNames is query,target
355
342
  — the reverse of the minimap2/nucmer input order. For the multi-genome PAF
@@ -382,11 +369,8 @@ $ jbrowse add-track genes.gff3.gz --load copy --color 'jexl:feature.strand==1?"b
382
369
  # bundle several BigWigs into one MultiQuantitativeTrack (no positional track arg)
383
370
  $ jbrowse add-track --multiwig a.bw,b.bw,c.bw --load copy --name "Coverage"
384
371
 
385
- # ...or from a sources.json carrying per-row name/color for each BigWig
372
+ # ...or from a sources.json with per-row name/color for each BigWig
386
373
  $ jbrowse add-track --multiwig sources.json --name "CATlas ATAC"
387
-
388
- # attach a remote density sidecar (a local genes.gff3.density.bw needs no flag)
389
- $ jbrowse add-track https://mywebsite.com/genes.gff3.gz --density https://mywebsite.com/genes.gff3.density.bw
390
374
  ```
391
375
 
392
376
 
@@ -407,9 +391,10 @@ Options:
407
391
 
408
392
  Notes:
409
393
 
410
- A config key JBrowse does not recognize is ignored rather than reported, so a
411
- misspelled slot leaves the track loading normally with the setting doing
412
- nothing. That is what this command is mainly for.
394
+ A config key JBrowse does not recognize does nothing: a track, an adapter or a
395
+ display names it on the browser console and loads without it, and a session
396
+ snapshot drops it in silence. This command reports each one offline, before
397
+ anyone opens the config.
413
398
 
414
399
  Two levels are reported:
415
400
 
@@ -429,7 +414,7 @@ what it cannot draw in a corner notice rather than refusing the track. This
429
414
  command runs the display's own rule list over every "marks" list in the file: an
430
415
  error where a mark draws nothing, never draws or a step cannot run, and a
431
416
  warning where a slot waits unread or the marks draw in an arrangement the author
432
- may not have meant. With --json each finding carries the stable "rule" id of the
417
+ may not have meant. With --json each finding has the stable "rule" id of the
433
418
  rule that made it.
434
419
 
435
420
  Types registered by plugins are not known to this command, so they come through
@@ -703,7 +688,7 @@ sh, sort, bgzip, and tabix on the PATH.
703
688
 
704
689
  Examples:
705
690
 
706
- # creates input.pif.gz and input.pif.gz.tbi in the same directory
691
+ # creates input.pif.gz and input.pif.gz.tbi in the current directory
707
692
  $ jbrowse make-pif input.paf
708
693
 
709
694
  # specify the output file, also creates output.pif.gz.tbi
@@ -726,8 +711,8 @@ $ jbrowse make-pif input.paf --threads 8
726
711
  ## jbrowse make-density
727
712
 
728
713
  ```text
729
- Counts feature starts per bin into a bigWig, the density sidecar a track draws
730
- where the region is too large to fetch its features
714
+ Counts feature starts per bin into a bigWig, which add-track turns into a
715
+ quantitative track of where the features are
731
716
 
732
717
  Usage: jbrowse make-density <file> [options]
733
718
 
@@ -744,25 +729,21 @@ Options:
744
729
  --chrom-sizes
745
730
 
746
731
  --out Where to write the bigWig. Defaults to
747
- <file>.density.bw beside the input, which is where
748
- add-track looks for it
732
+ <file>.density.bw beside the input
749
733
 
750
734
  Notes:
751
735
 
752
- The sidecar is attached to a track through its adapter's densityAdapter slot,
753
- which BamAdapter, CramAdapter, HtsgetBamAdapter, Gff3TabixAdapter,
754
- GtfTabixAdapter, BedTabixAdapter, BigBedAdapter, VcfTabixAdapter and
755
- SplitVcfTabixAdapter declare. add-track attaches it on its own when the default
756
- <file>.density.bw sits beside the track file, so building it before adding the
757
- track is all it takes; --density attaches one by path or URL.
736
+ GFF3 counts only top-level features — a line whose attributes have no Parent= —
737
+ so a gene is one count rather than one per exon. GTF counts its transcript rows
738
+ where it has any, and every row otherwise. BED and VCF have no parent link to
739
+ follow, so every record counts.
758
740
 
759
- GFF3 counts only top-level features — a line whose attributes carry no Parent= —
760
- so a gene is one count rather than one per exon. GTF, BED and VCF have no parent
761
- link to follow, so every record counts.
741
+ Every base is covered, empty bins as zero, so the zoomed-out summaries a bigWig
742
+ keeps average over real counts rather than only the bins that hold something.
762
743
 
763
744
  BAM and CRAM are out of scope: read depth is not feature density, and the tools
764
- that compute it already write bigWig. Point add-track --density at what they
765
- produce.
745
+ that compute it (bamCoverage, mosdepth) already write it as a bigWig or
746
+ bedGraph.
766
747
 
767
748
  Requires bedGraphToBigWig (UCSC) on the PATH.
768
749
 
@@ -1,8 +1,5 @@
1
1
  import fs from 'node:fs';
2
2
  import { adapterTypesToTrackTypeMap, fileNameOf, formats, matchFormat, resolveIndexType, sidecarCandidateNames, trackTypeForAdapter, } from '@jbrowse/add-track-core';
3
- import { isURL } from '../../types/common.js';
4
- import { densitySidecarPath } from '../shared/density.js';
5
- import { configManifest } from '../validate/configManifest.generated.js';
6
3
  function hasLocField(spec) {
7
4
  return 'locField' in spec;
8
5
  }
@@ -25,48 +22,6 @@ export function siblingSidecar(location, suffix) {
25
22
  const candidates = sidecarCandidateNames(location, suffix);
26
23
  return candidates.find(c => fs.existsSync(c)) ?? candidates[0];
27
24
  }
28
- // The adapters that declare a `densityAdapter` slot, read off the generated
29
- // manifest `jbrowse validate` uses. The hand-written list missed `GWASAdapter`,
30
- // which inherits the slot through `bedTabixConfigSchema` instead of spreading
31
- // `densityAdapterConfigSchemaFields`, so `--density` on a Pan-UKBB file was
32
- // refused by a message that listed nine adapters and not the tenth.
33
- const densityAdapterTypes = new Set(Object.entries(configManifest.adapters)
34
- .filter(([, entry]) => entry.slots.some(s => s.name === 'densityAdapter'))
35
- .map(([name]) => name)
36
- .sort());
37
- /**
38
- * The adapter with its density sidecar attached, and the local file to load
39
- * beside the config when there is one.
40
- *
41
- * An explicit `--density` is taken as given, since a URL cannot be probed;
42
- * otherwise the conventional `<file>.density.bw` counts only when it is
43
- * actually there, the way `siblingSidecar` probes an index.
44
- */
45
- export function withDensityAdapter({ adapter, location, density, makeLocation, }) {
46
- const supported = densityAdapterTypes.has(adapter.type);
47
- if (density !== undefined && !supported) {
48
- throw new Error(`--density has no slot on ${adapter.type}. The adapters carrying a density sidecar are: ${[...densityAdapterTypes].join(', ')}`);
49
- }
50
- const probed = location !== undefined && fs.existsSync(densitySidecarPath(location))
51
- ? densitySidecarPath(location)
52
- : undefined;
53
- if (probed !== undefined && !supported) {
54
- console.warn(`Warning: ${probed} sits beside the track file but ${adapter.type} has no densityAdapter slot, so it is not attached. The adapters carrying one are indexed: bgzip and tabix the file, then add it.`);
55
- }
56
- const file = density === undefined ? (supported ? probed : undefined) : density;
57
- return file === undefined
58
- ? { adapter }
59
- : {
60
- adapter: {
61
- ...adapter,
62
- densityAdapter: {
63
- type: 'BigWigAdapter',
64
- bigWigLocation: makeLocation(file),
65
- },
66
- },
67
- file: isURL(file) ? undefined : file,
68
- };
69
- }
70
25
  // builds the adapter object and the list of source files for a spec in one
71
26
  // place, so the config it writes and the files add-track copies can never drift
72
27
  function buildFromSpec(spec, { location, index, bed1, bed2, makeLocation }) {
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { parseArgs } from 'node:util';
3
3
  import { printHelp, readConfigFile, resolveConfigPath } from '../utils.js';
4
- import { guessTrack, guessTrackType, makeLocationProtocol, withDensityAdapter, } from './add-track-utils/adapter-utils.js';
4
+ import { guessTrack, guessTrackType, makeLocationProtocol, } from './add-track-utils/adapter-utils.js';
5
5
  import { loadFiles } from './add-track-utils/file-operations.js';
6
6
  import { buildMultiWiggle } from './add-track-utils/multiwig.js';
7
7
  import { addSyntenyAssemblyNames, buildTrackConfig, mapLocationForFiles, mergeDisplayDefaults, } from './add-track-utils/track-config.js';
@@ -59,7 +59,7 @@ export async function run(args) {
59
59
  },
60
60
  displayDefaults: {
61
61
  type: 'string',
62
- description: 'Inline JSON merged into the track displayDefaults (labels, mouseover, filter, etc.)',
62
+ description: 'Inline JSON merged into the track displayDefaults (labels, color, filter, etc.)',
63
63
  },
64
64
  multiwig: {
65
65
  type: 'string',
@@ -104,10 +104,6 @@ export async function run(args) {
104
104
  type: 'string',
105
105
  description: 'Used only for mcscan anchors/simpleAnchors types',
106
106
  },
107
- density: {
108
- type: 'string',
109
- description: "Path or URL of a features-per-bin bigWig (jbrowse make-density) to attach as the adapter's densityAdapter. A local <file>.density.bw beside the track file is attached without this flag",
110
- },
111
107
  };
112
108
  const { values: flags, positionals } = parseArgs({
113
109
  args,
@@ -131,20 +127,13 @@ export async function run(args) {
131
127
  'writing JSON. Wrap the value in single quotes and use double quotes inside ' +
132
128
  'a jexl callback so nothing needs escaping, e.g. ' +
133
129
  '--color \'jexl:feature.strand==1?"blue":"red"\'. --displayDefaults takes ' +
134
- 'inline JSON for any other appearance setting (labels, mouseover, ' +
130
+ 'inline JSON for any other appearance setting (labels, facet, ' +
135
131
  'filter).\n\n' +
136
132
  '--multiwig bundles several BigWigs into one MultiQuantitativeTrack, in ' +
137
133
  'place of the positional track argument: pass a comma-separated list of ' +
138
134
  'BigWig files/URLs, or a .json file with an array of BigWig locations or ' +
139
- 'subadapter objects (each carrying its own name/color/group). With --load, ' +
135
+ 'subadapter objects (each with its own name/color/group). With --load, ' +
140
136
  'local list entries are copied like any other track file.\n\n' +
141
- '--density attaches a features-per-bin bigWig (jbrowse make-density) as the ' +
142
- "adapter's densityAdapter, the band a display draws where the region is too " +
143
- 'large to fetch features. A local <file>.density.bw beside the track file is ' +
144
- 'attached without the flag; a URL cannot be probed, so a remote sidecar needs ' +
145
- 'it. The adapters carrying the slot are BamAdapter, CramAdapter, ' +
146
- 'HtsgetBamAdapter, Gff3TabixAdapter, GtfTabixAdapter, BedTabixAdapter, ' +
147
- 'BigBedAdapter, VcfTabixAdapter and SplitVcfTabixAdapter.\n\n' +
148
137
  'For pairwise synteny adapters (PAF/Delta/Chain) --assemblyNames is ' +
149
138
  'query,target — the reverse of the minimap2/nucmer input order. For the ' +
150
139
  'multi-genome PAF adapters (MultiGenomePAFAdapter, MultiGenomeIndexedPAFAdapter) it is ' +
@@ -174,11 +163,8 @@ export async function run(args) {
174
163
  '# bundle several BigWigs into one MultiQuantitativeTrack (no positional track arg)',
175
164
  '$ jbrowse add-track --multiwig a.bw,b.bw,c.bw --load copy --name "Coverage"',
176
165
  '',
177
- '# ...or from a sources.json carrying per-row name/color for each BigWig',
166
+ '# ...or from a sources.json with per-row name/color for each BigWig',
178
167
  '$ jbrowse add-track --multiwig sources.json --name "CATlas ATAC"',
179
- '',
180
- '# attach a remote density sidecar (a local genes.gff3.density.bw needs no flag)',
181
- '$ jbrowse add-track https://mywebsite.com/genes.gff3.gz --density https://mywebsite.com/genes.gff3.density.bw',
182
168
  ];
183
169
  if (flags.help) {
184
170
  printHelp({
@@ -200,7 +186,7 @@ export async function run(args) {
200
186
  const mapLocation = (p) => wrap(mapLocationForFiles(p, load, subDir));
201
187
  // build the adapter (and the set of files to load) up front, so the track-arg
202
188
  // and load validation runs before we touch the config on disk
203
- const { adapter: builtAdapter, files, trackType, trackId, } = multiwig
189
+ const { adapter, files, trackType, trackId } = multiwig
204
190
  ? buildMultiWiggleTrack({
205
191
  sources: multiwig,
206
192
  mapLocation,
@@ -220,15 +206,6 @@ export async function run(args) {
220
206
  trackType: flags.trackType,
221
207
  trackId: flags.trackId,
222
208
  });
223
- const { adapter, file: densityFile } = withDensityAdapter({
224
- adapter: builtAdapter,
225
- location,
226
- density: flags.density,
227
- makeLocation: mapLocation,
228
- });
229
- if (densityFile !== undefined && !load) {
230
- throw new Error(`--density names a local file (${densityFile}); pass --load to say how it is placed beside the config`);
231
- }
232
209
  const baseConfigObj = config ? parseConfigFlag(config) : undefined;
233
210
  const displayDefaults = mergeDisplayDefaults({
234
211
  configObj: baseConfigObj,
@@ -267,7 +244,7 @@ export async function run(args) {
267
244
  });
268
245
  const updatedConfig = { ...configContents, tracks };
269
246
  await loadFiles({
270
- files: [...files, densityFile],
247
+ files,
271
248
  destDir: configDir,
272
249
  mode: load,
273
250
  subDir,
@@ -14,7 +14,7 @@ export function densityFormat(file) {
14
14
  const hit = formats.find(f => f.regex.test(file));
15
15
  if (!hit) {
16
16
  throw new Error(alignmentFormat.test(file)
17
- ? `${file} is an alignment file, which make-density cannot read. Count coverage with a tool that reads BAM/CRAM (e.g. "bamCoverage" or "samtools depth" piped to bedGraphToBigWig) and pass the result with add-track --density.`
17
+ ? `${file} is an alignment file, which make-density cannot read. Count coverage with a tool that reads BAM/CRAM (e.g. bamCoverage or mosdepth) and add its bigWig as a track.`
18
18
  : `Cannot tell what kind of file ${file} is. make-density reads GFF3, GTF, BED and VCF, plain or bgzipped.`);
19
19
  }
20
20
  return hit.format;
@@ -7,7 +7,6 @@ import { pipeline } from 'node:stream/promises';
7
7
  import { parseArgs } from 'node:util';
8
8
  import { printHelp, requirePositional } from '../../utils.js';
9
9
  import { describeExit, waitForProcessClose } from '../process-utils.js';
10
- import { densitySidecarPath } from '../shared/density.js';
11
10
  import { validateFileArgument, validateRequiredCommands, } from '../shared/validators.js';
12
11
  import { bedGraphLines, chromSizesLines, countFeatureStarts, densityFormat, parseBinSize, resolveChromSizes, } from './density-generator.js';
13
12
  export async function run(args) {
@@ -31,7 +30,7 @@ export async function run(args) {
31
30
  },
32
31
  out: {
33
32
  type: 'string',
34
- description: 'Where to write the bigWig. Defaults to <file>.density.bw beside the input, which is where add-track looks for it',
33
+ description: 'Where to write the bigWig. Defaults to <file>.density.bw beside the input',
35
34
  },
36
35
  };
37
36
  const { values: flags, positionals } = parseArgs({
@@ -39,19 +38,17 @@ export async function run(args) {
39
38
  options,
40
39
  allowPositionals: true,
41
40
  });
42
- const description = 'Counts feature starts per bin into a bigWig, the density sidecar a track draws where the region is too large to fetch its features';
43
- const notes = "The sidecar is attached to a track through its adapter's densityAdapter " +
44
- 'slot, which BamAdapter, CramAdapter, HtsgetBamAdapter, Gff3TabixAdapter, ' +
45
- 'GtfTabixAdapter, BedTabixAdapter, BigBedAdapter, VcfTabixAdapter and ' +
46
- 'SplitVcfTabixAdapter declare. add-track attaches it on its own when the ' +
47
- 'default <file>.density.bw sits beside the track file, so building it before ' +
48
- 'adding the track is all it takes; --density attaches one by path or URL.\n\n' +
49
- 'GFF3 counts only top-level features — a line whose attributes carry no ' +
50
- 'Parent= — so a gene is one count rather than one per exon. GTF, BED and VCF ' +
41
+ const description = 'Counts feature starts per bin into a bigWig, which add-track turns into a quantitative track of where the features are';
42
+ const notes = 'GFF3 counts only top-level features — a line whose attributes have no ' +
43
+ 'Parent= — so a gene is one count rather than one per exon. GTF counts its ' +
44
+ 'transcript rows where it has any, and every row otherwise. BED and VCF ' +
51
45
  'have no parent link to follow, so every record counts.\n\n' +
46
+ 'Every base is covered, empty bins as zero, so the zoomed-out summaries a ' +
47
+ 'bigWig keeps average over real counts rather than only the bins that hold ' +
48
+ 'something.\n\n' +
52
49
  'BAM and CRAM are out of scope: read depth is not feature density, and the ' +
53
- 'tools that compute it already write bigWig. Point add-track --density at ' +
54
- 'what they produce.\n\n' +
50
+ 'tools that compute it (bamCoverage, mosdepth) already write it as a ' +
51
+ 'bigWig or bedGraph.\n\n' +
55
52
  'Requires bedGraphToBigWig (UCSC) on the PATH.';
56
53
  const examples = [
57
54
  '# writes genes.gff3.density.bw beside the input, in 1kb bins',
@@ -86,7 +83,9 @@ export async function run(args) {
86
83
  assembly: flags.assembly,
87
84
  });
88
85
  validateRequiredCommands(['bedGraphToBigWig']);
89
- const outputFile = flags.out === undefined ? densitySidecarPath(file) : flags.out;
86
+ const outputFile = flags.out === undefined
87
+ ? `${file.replace(/\.b?gz$/i, '')}.density.bw`
88
+ : flags.out;
90
89
  const { bins, records, unknownRefNames } = await countFeatureStarts({
91
90
  file,
92
91
  format,
@@ -124,16 +123,5 @@ export async function run(args) {
124
123
  finally {
125
124
  rmSync(tmpDir, { recursive: true, force: true });
126
125
  }
127
- // The slot lives on the indexed adapters, so a plain text file has to be
128
- // bgzipped and tabix-indexed before the track can carry the sidecar
129
- const indexed = /\.b?gz$/i.test(file);
130
- const preset = format === 'bed' ? 'bed' : format === 'vcf' ? 'vcf' : 'gff';
131
- const trackFile = indexed ? file : `${file}.gz`;
132
- const indexFirst = indexed
133
- ? ''
134
- : ` bgzip ${file} && tabix -p ${preset} ${trackFile}\n`;
135
- const nextCommand = outputFile === densitySidecarPath(file)
136
- ? `Next, add the track it summarizes — a sidecar under this name is picked up automatically:\n${indexFirst} jbrowse add-track ${trackFile} --load copy`
137
- : `Next, add the track it summarizes, naming this sidecar:\n${indexFirst} jbrowse add-track ${trackFile} --load copy --density ${outputFile}`;
138
- console.log(`Created ${outputFile}: ${records} feature start(s) in ${binCount} non-empty ${binSize}bp bin(s)\n\n${nextCommand}`);
126
+ console.log(`Created ${outputFile}: ${records} feature start(s) in ${binCount} non-empty ${binSize}bp bin(s)\n\nNext, add it as a track of its own:\n jbrowse add-track ${outputFile} --load copy`);
139
127
  }
@@ -38,7 +38,7 @@ export async function run(args) {
38
38
  });
39
39
  const description = 'creates pairwise indexed PAF (PIF), with bgzip and tabix';
40
40
  const examples = [
41
- '# creates input.pif.gz and input.pif.gz.tbi in the same directory',
41
+ '# creates input.pif.gz and input.pif.gz.tbi in the current directory',
42
42
  '$ jbrowse make-pif input.paf',
43
43
  '',
44
44
  '# specify the output file, also creates output.pif.gz.tbi',
@@ -31,6 +31,6 @@ export async function indexFileList(flags) {
31
31
  prefixSize,
32
32
  }),
33
33
  });
34
- console.log('Successfully created index for these files. See https://jbrowse.org/storybook/lgv/with-aggregate-text-searching/ for info about usage');
34
+ console.log('Successfully created index for these files. See https://jbrowse.org/storybook/lgv/aggregate-text-search/ for info about usage');
35
35
  }
36
36
  }