Skip to content

Commit 3cbf97c

Browse files
authored
Merge pull request #322 from BimberLab/25.3_fb_merge
Merge discvr-24.11 to discvr-25.3
2 parents 15d613c + cda55fa commit 3cbf97c

File tree

18 files changed

+1648
-1180
lines changed

18 files changed

+1648
-1180
lines changed

jbrowse/package-lock.json

Lines changed: 1458 additions & 1037 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jbrowse/package.json

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,44 +14,45 @@
1414
"jb-pkg": "npm run prepareCli && npx pkg --outdir=./resources/external/jb-cli ./buildCli/node_modules/@jbrowse/cli && rimraf ./buildCli"
1515
},
1616
"dependencies": {
17-
"@gmod/vcf": "^5.0.10",
18-
"@jbrowse/core": "^2.15.0",
19-
"@jbrowse/plugin-linear-genome-view": "^2.15.0",
20-
"@jbrowse/plugin-svg": "^2.15.0",
21-
"@jbrowse/plugin-variants": "^2.15.0",
22-
"@jbrowse/react-linear-genome-view": "^2.15.0",
23-
"@labkey/api": "^1.35.0",
24-
"@labkey/components": "^5.0.0",
25-
"@mui/x-data-grid": "^7.0.0",
26-
"@yao-pkg/pkg": "^5.12.0",
27-
"assert": "^2.0.0",
17+
"@gmod/vcf": "^6.0.9",
18+
"@jbrowse/core": "^3.2.0",
19+
"@jbrowse/product-core": "^3.2.0",
20+
"@jbrowse/plugin-linear-genome-view": "^3.2.0",
21+
"@jbrowse/plugin-svg": "^3.2.0",
22+
"@jbrowse/plugin-variants": "^3.2.0",
23+
"@jbrowse/react-linear-genome-view2": "^3.2.0",
24+
"@labkey/api": "^1.39.0",
25+
"@labkey/components": "^6.32.2",
26+
"@mui/x-data-grid": "^7.28.1",
27+
"@yao-pkg/pkg": "^6.3.2",
28+
"assert": "^2.1.0",
2829
"browserify-zlib": "^0.2.0",
2930
"buffer": "^6.0.3",
3031
"child_process": "^1.0.2",
3132
"fs": "^0.0.1-security",
32-
"jquery": "^3.7.0",
33-
"jspdf": "^2.5.1",
34-
"jspdf-autotable": "^3.5.31",
35-
"node-polyfill-webpack-plugin": "2.0.1",
33+
"jquery": "^3.7.1",
34+
"jspdf": "^3.0.0",
35+
"jspdf-autotable": "^5.0.2",
36+
"node-polyfill-webpack-plugin": "4.1.0",
3637
"path-browserify": "^1.0.1",
37-
"react": "^18.0.0",
38+
"react": "^18.3.0",
3839
"react-data-grid": "7.0.0-beta.46",
39-
"react-dom": "^18.0.0",
40-
"react-google-charts": "^4.0.1",
41-
"react-select": "^5.8.0",
42-
"regenerator-runtime": "^0.13.11",
40+
"react-dom": "^18.3.0",
41+
"react-google-charts": "^5.2.1",
42+
"react-select": "^5.10.1",
43+
"regenerator-runtime": "^0.14.1",
4344
"stream-browserify": "^3.0.0",
4445
"util": "^0.12.5",
45-
"uuid": "^9.0.0",
46+
"uuid": "^11.1.0",
4647
"vm-browserify": "^1.1.2"
4748
},
4849
"devDependencies": {
49-
"@labkey/build": "^8.3.0",
50-
"@types/jexl": "^2.3.1",
51-
"@types/jquery": "^3.0.0",
50+
"@labkey/build": "^8.4.0",
51+
"@types/jexl": "^2.3.4",
52+
"@types/jquery": "^3.5.32",
5253
"@types/node": "^20.14.11",
53-
"@types/react": "^18.0.0",
54-
"@types/react-dom": "^18.0.0",
54+
"@types/react": "^18.3.0",
55+
"@types/react-dom": "^18.3.0",
5556
"rimraf": "^6.0.1",
5657
"typescript": "^5.1.6"
5758
}

jbrowse/src/client/JBrowse/Browser/Browser.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useEffect, useState } from 'react';
22

3-
import { JBrowseLinearGenomeView, ViewModel } from '@jbrowse/react-linear-genome-view';
3+
import { JBrowseLinearGenomeView, ViewModel } from '@jbrowse/react-linear-genome-view2'
44
import { createTheme } from '@mui/material/styles';
55
import LogSession from './plugins/LogSession/index';
66
import ExtendedVariantPlugin from './plugins/ExtendedVariantPlugin/index';
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import React from 'react';
2-
import ReactDOM from 'react-dom';
3-
41
import View from './Browser';
2+
import { createRoot } from 'react-dom/client';
3+
import React from 'react';
54

65
// Need to wait for container element to be available in labkey wrapper before render
76
window.addEventListener('DOMContentLoaded', (event) => {
8-
ReactDOM.render(<View />, document.getElementById('app'))
7+
createRoot(document.getElementById('app')).render(<View />)
98
});
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import React from 'react';
2-
import ReactDOM from 'react-dom';
3-
41
import View from './Browser';
2+
import { createRoot } from 'react-dom/client';
3+
import React from 'react';
54

6-
const render = () => {
7-
ReactDOM.render(<View />, document.getElementById('app'));
8-
};
9-
10-
render();
5+
// Need to wait for container element to be available in labkey wrapper before render
6+
window.addEventListener('DOMContentLoaded', (event) => {
7+
createRoot(document.getElementById('app')).render(<View />)
8+
}, true);

jbrowse/src/client/JBrowse/Browser/plugins/ExtendedVariantPlugin/ExtendedVariantAdapter/ExtendedVariantAdapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default class extends VcfTabixAdapter {
2727
observer.next(v)
2828
})
2929
observer.complete()
30-
}, opts.signal)
30+
}, opts.stopToken)
3131
}
3232

3333
private async getFeaturesAsArray(query: NoAssemblyRegion, opts: BaseOptions = {}) {

jbrowse/src/client/JBrowse/Browser/plugins/ExtendedVariantPlugin/ExtendedVariantAdapter/ExtendedVcfFeature.ts

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,14 @@
11
import { VcfFeature } from '@jbrowse/plugin-variants'
2-
import VcfParser from '@gmod/vcf'
2+
import VcfParser, { Variant } from '@gmod/vcf';
33

44
export default class ExtendedVcfFeature extends VcfFeature {
5-
private readonly vcfParser: VcfParser
6-
7-
constructor(args: { variant: any; parser: VcfParser; id: string }) {
5+
constructor(args: { variant: Variant; parser: VcfParser; id: string }) {
86
args.variant = ExtendedVcfFeature.extractImpact(args.variant)
9-
//args.variant = ExtendedVcfFeature.calculateVariableSamples(args.variant)
107

118
super(args)
12-
13-
this.vcfParser = args.parser
14-
}
15-
16-
public getInfoFieldMeta(propKey: string): VcfParser {
17-
const map = this.vcfParser.getMetadata("INFO")
18-
19-
return map ? map[propKey] : null
209
}
2110

22-
static extractImpact(variant: {
23-
REF: string
24-
POS: number
25-
ALT: string[]
26-
CHROM: string
27-
INFO: any
28-
ID: string[]
29-
}) {
11+
static extractImpact(variant: Variant) {
3012
// Only append if not present:
3113
if (variant.INFO["IMPACT"]) {
3214
return(variant);

jbrowse/src/client/JBrowse/Browser/plugins/ExtendedVariantPlugin/ExtendedVariantAdapter/VcfTabixAdapter.ts

Lines changed: 108 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,158 @@
1+
import { TabixIndexedFile } from '@gmod/tabix'
2+
import VcfParser from '@gmod/vcf'
3+
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
14
import {
2-
BaseFeatureDataAdapter,
3-
BaseOptions,
4-
} from '@jbrowse/core/data_adapters/BaseAdapter'
5-
import { NoAssemblyRegion } from '@jbrowse/core/util/types'
5+
fetchAndMaybeUnzipText,
6+
updateStatus,
7+
} from '@jbrowse/core/util'
68
import { openLocation } from '@jbrowse/core/util/io'
79
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
8-
import { Feature } from '@jbrowse/core/util'
9-
import { TabixIndexedFile } from '@gmod/tabix'
10-
import VcfParser from '@gmod/vcf'
10+
11+
import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter'
12+
import type { Feature } from '@jbrowse/core/util'
13+
import type { NoAssemblyRegion } from '@jbrowse/core/util/types'
1114
import { VcfFeature } from '@jbrowse/plugin-variants';
1215

16+
function shorten2(name: string, max = 70) {
17+
return name.length > max ? `${name.slice(0, max)}...` : name
18+
}
19+
1320
export default class VcfTabixAdapter extends BaseFeatureDataAdapter {
1421
private configured?: Promise<{
1522
vcf: TabixIndexedFile
1623
parser: VcfParser
1724
}>
1825

19-
private async configurePre() {
20-
const pm = this.pluginManager
26+
private async configurePre(_opts?: BaseOptions) {
2127
const vcfGzLocation = this.getConf('vcfGzLocation')
2228
const location = this.getConf(['index', 'location'])
2329
const indexType = this.getConf(['index', 'indexType'])
2430

25-
const filehandle = openLocation(vcfGzLocation, pm)
31+
const filehandle = openLocation(vcfGzLocation, this.pluginManager)
2632
const isCSI = indexType === 'CSI'
2733
const vcf = new TabixIndexedFile({
2834
filehandle,
29-
csiFilehandle: isCSI ? openLocation(location, pm) : undefined,
30-
tbiFilehandle: !isCSI ? openLocation(location, pm) : undefined,
31-
chunkCacheSize: 50 * 2 ** 20
35+
csiFilehandle: isCSI
36+
? openLocation(location, this.pluginManager)
37+
: undefined,
38+
tbiFilehandle: !isCSI
39+
? openLocation(location, this.pluginManager)
40+
: undefined,
41+
chunkCacheSize: 50 * 2 ** 20,
3242
})
3343

34-
const header = await vcf.getHeader()
3544
return {
3645
vcf,
37-
parser: new VcfParser({ header }),
46+
parser: new VcfParser({
47+
header: await vcf.getHeader(),
48+
}),
3849
}
3950
}
4051

41-
protected async configure() {
52+
protected async configurePre2() {
4253
if (!this.configured) {
43-
this.configured = this.configurePre().catch(e => {
54+
this.configured = this.configurePre().catch((e: unknown) => {
4455
this.configured = undefined
4556
throw e
4657
})
4758
}
4859
return this.configured
4960
}
5061

62+
async configure(opts?: BaseOptions) {
63+
const { statusCallback = () => {} } = opts || {}
64+
return updateStatus('Downloading index', statusCallback, () =>
65+
this.configurePre2(),
66+
)
67+
}
5168
public async getRefNames(opts: BaseOptions = {}) {
52-
const { vcf } = await this.configure()
69+
const { vcf } = await this.configure(opts)
5370
return vcf.getReferenceSequenceNames(opts)
5471
}
5572

56-
async getHeader() {
57-
const { vcf } = await this.configure()
73+
async getHeader(opts?: BaseOptions) {
74+
const { vcf } = await this.configure(opts)
5875
return vcf.getHeader()
5976
}
6077

61-
async getMetadata() {
62-
const { parser } = await this.configure()
78+
async getMetadata(opts?: BaseOptions) {
79+
const { parser } = await this.configure(opts)
6380
return parser.getMetadata()
6481
}
6582

6683
public getFeatures(query: NoAssemblyRegion, opts: BaseOptions = {}) {
6784
return ObservableCreate<Feature>(async observer => {
6885
const { refName, start, end } = query
69-
const { vcf, parser } = await this.configure()
70-
await vcf.getLines(refName, start, end, {
71-
lineCallback: (line, fileOffset) => {
72-
observer.next(
73-
new VcfFeature({
74-
variant: parser.parseLine(line),
75-
parser,
76-
id: `${this.id}-vcf-${fileOffset}`,
77-
}),
78-
)
79-
},
80-
...opts,
81-
})
86+
const { statusCallback = () => {} } = opts
87+
const { vcf, parser } = await this.configure(opts)
88+
89+
await updateStatus('Downloading variants', statusCallback, () =>
90+
vcf.getLines(refName, start, end, {
91+
lineCallback: (line, fileOffset) => {
92+
observer.next(
93+
new VcfFeature({
94+
variant: parser.parseLine(line),
95+
parser,
96+
id: `${this.id}-vcf-${fileOffset}`,
97+
}),
98+
)
99+
},
100+
...opts,
101+
}),
102+
)
82103
observer.complete()
83-
}, opts.signal)
104+
}, opts.stopToken)
105+
}
106+
107+
async getSources() {
108+
const conf = this.getConf('samplesTsvLocation')
109+
if (conf.uri === '' || conf.uri === '/path/to/samples.tsv') {
110+
const { parser } = await this.configure()
111+
return parser.samples.map(name => ({
112+
name,
113+
}))
114+
} else {
115+
const txt = await fetchAndMaybeUnzipText(
116+
openLocation(conf, this.pluginManager),
117+
)
118+
const lines = txt.split(/\n|\r\n|\r/)
119+
const header = lines[0]!.split('\t')
120+
const { parser } = await this.configure()
121+
const metadataLines = lines
122+
.slice(1)
123+
.filter(f => !!f)
124+
.map(line => {
125+
const [name, ...rest] = line.split('\t')
126+
return {
127+
...Object.fromEntries(
128+
// force col 0 to be called name
129+
rest.map((c, idx) => [header[idx + 1]!, c] as const),
130+
),
131+
name: name!,
132+
}
133+
})
134+
const vcfSampleSet = new Set(parser.samples)
135+
const metadataSet = new Set(metadataLines.map(r => r.name))
136+
const metadataNotInVcfSamples = [...metadataSet].filter(
137+
f => !vcfSampleSet.has(f),
138+
)
139+
const vcfSamplesNotInMetadata = [...vcfSampleSet].filter(
140+
f => !metadataSet.has(f),
141+
)
142+
if (metadataNotInVcfSamples.length) {
143+
console.warn(
144+
`There are ${metadataNotInVcfSamples.length} samples in metadata file (${metadataLines.length} lines) not in VCF (${parser.samples.length} samples):`,
145+
shorten2(metadataNotInVcfSamples.join(',')),
146+
)
147+
}
148+
if (vcfSamplesNotInMetadata.length) {
149+
console.warn(
150+
`There are ${vcfSamplesNotInMetadata.length} samples in VCF file (${parser.samples.length} samples) not in metadata file (${metadataLines.length} lines):`,
151+
shorten2(vcfSamplesNotInMetadata.map(m => m).join(',')),
152+
)
153+
}
154+
return metadataLines.filter(f => vcfSampleSet.has(f.name))
155+
}
84156
}
85157

86158
public freeResources(/* { region } */): void {}

jbrowse/src/client/JBrowse/Browser/plugins/ExtendedVariantPlugin/ExtendedVariantRenderer/components/ExtendedVariantRendering.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import jexl from 'jexl';
21
import { SvgFeatureRendererReactComponent } from '@jbrowse/plugin-svg';
32
import { observer } from 'mobx-react';
43
import React from 'react';
54
import { deserializeFilters } from '../../InfoFilterWidget/filterUtil';
65
import Diamond from './Diamond';
76
import { passesInfoFilters, passesSampleFilters } from '../../../../../utils';
7+
import { VcfFeature } from '@jbrowse/plugin-variants';
88

99
export function ExtendedVariantRendering(props) {
1010
const { features, rendererConfig } = props
@@ -17,11 +17,11 @@ export function ExtendedVariantRendering(props) {
1717

1818
const sampleFilters = activeSamples.value ? activeSamples.value.split(',') : null
1919

20-
function diamondValidator(feature) {
20+
function diamondValidator(feature: VcfFeature) {
2121
return feature.get('type') === "SNV";
2222
}
2323

24-
function isFeatureDisplayed(feature) {
24+
function isFeatureDisplayed(feature: VcfFeature) {
2525
return passesInfoFilters(feature, expandedFilters) && passesSampleFilters(feature, sampleFilters)
2626
}
2727

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import React from 'react';
2-
import ReactDOM from 'react-dom';
2+
import { createRoot } from 'react-dom/client';
33
import { App } from '@labkey/api';
44

55
import StandaloneSearch from '../StandaloneSearch';
66

77
App.registerApp<any>('jbrowseSearchWebpart', (target: string, sessionId: string) => {
8-
ReactDOM.render(
9-
<StandaloneSearch sessionId={sessionId} />
10-
, document.getElementById(target));
11-
});
8+
createRoot(document.getElementById(target)).render(<StandaloneSearch sessionId={sessionId} />)
9+
});

0 commit comments

Comments
 (0)