jbrowse-plugin-msaview 3.2.0 → 3.4.0
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/dist/AddHighlightModel/GenomeMouseoverHighlight.js +1 -1
- package/dist/AddHighlightModel/MsaToGenomeHighlight.js +1 -1
- package/dist/AddHighlightModel/index.js +1 -1
- package/dist/LaunchMsaView/components/BlastQuery/BlastAutomaticPanel.js +61 -17
- package/dist/LaunchMsaView/components/BlastQuery/BlastManualPanel.js +1 -1
- package/dist/LaunchMsaView/components/BlastQuery/BlastPanel.js +2 -2
- package/dist/LaunchMsaView/components/BlastQuery/CachedBlastResults.d.ts +12 -0
- package/dist/LaunchMsaView/components/BlastQuery/CachedBlastResults.js +21 -2
- package/dist/LaunchMsaView/components/BlastQuery/CachedBlastResults.test.d.ts +1 -0
- package/dist/LaunchMsaView/components/BlastQuery/CachedBlastResults.test.js +29 -0
- package/dist/LaunchMsaView/components/BlastQuery/MsaAlgorithmSelect.js +1 -1
- package/dist/LaunchMsaView/components/BlastQuery/consts.d.ts +28 -0
- package/dist/LaunchMsaView/components/BlastQuery/consts.js +21 -0
- package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js +1 -1
- package/dist/LaunchMsaView/components/OrthologQuery/OrthologPanel.js +9 -4
- package/dist/LaunchMsaView/components/OrthologQuery/OrthologSourceSelect.d.ts +9 -0
- package/dist/LaunchMsaView/components/OrthologQuery/OrthologSourceSelect.js +20 -0
- package/dist/LaunchMsaView/components/SubmitCancelActions.test.js +1 -1
- package/dist/LaunchMsaView/components/useFeatureSequence.js +1 -1
- package/dist/LaunchMsaView/detectQueryRow.d.ts +15 -2
- package/dist/LaunchMsaView/detectQueryRow.js +20 -21
- package/dist/LaunchMsaView/detectQueryRow.test.js +15 -15
- package/dist/LaunchMsaView/useQueryRowName.js +5 -8
- package/dist/MsaViewPanel/afterCreateAutoruns.js +2 -2
- package/dist/MsaViewPanel/components/ErrorBoundary.d.ts +2 -2
- package/dist/MsaViewPanel/components/JobLink.js +7 -1
- package/dist/MsaViewPanel/components/LaunchProgress.d.ts +17 -0
- package/dist/MsaViewPanel/components/LaunchProgress.js +41 -0
- package/dist/MsaViewPanel/components/MsaViewPanel.js +6 -3
- package/dist/MsaViewPanel/components/MsaViewPanel.test.d.ts +1 -0
- package/dist/MsaViewPanel/components/MsaViewPanel.test.js +68 -0
- package/dist/MsaViewPanel/doLaunchBlast.d.ts +1 -1
- package/dist/MsaViewPanel/doLaunchBlast.js +84 -52
- package/dist/MsaViewPanel/doLaunchOrthologs.d.ts +7 -5
- package/dist/MsaViewPanel/doLaunchOrthologs.js +64 -30
- package/dist/MsaViewPanel/doLaunchOrthologs.test.js +106 -1
- package/dist/MsaViewPanel/genomeToMSA.js +4 -2
- package/dist/MsaViewPanel/genomeToMSA.test.js +34 -0
- package/dist/MsaViewPanel/model.d.ts +41 -11
- package/dist/MsaViewPanel/model.js +6 -0
- package/dist/MsaViewPanel/observeProteinHighlights.test.js +11 -0
- package/dist/MsaViewPanel/syncGenomeHoverToMsaColumn.test.js +1 -0
- package/dist/MsaViewPanel/util.d.ts +18 -0
- package/dist/MsaViewPanel/util.js +17 -0
- package/dist/jbrowse-plugin-msaview.umd.production.min.js +47 -35
- package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
- package/dist/utils/blastCache.d.ts +10 -6
- package/dist/utils/blastCache.js +15 -3
- package/dist/utils/ebiBlast.d.ts +1 -1
- package/dist/utils/msa.d.ts +12 -0
- package/dist/utils/msa.js +35 -12
- package/dist/utils/msaRows.d.ts +31 -0
- package/dist/utils/msaRows.js +67 -0
- package/dist/utils/pantherOrthologs.d.ts +79 -0
- package/dist/utils/pantherOrthologs.js +262 -0
- package/dist/utils/phmmer.d.ts +53 -0
- package/dist/utils/phmmer.js +118 -0
- package/dist/utils/taxonomyNames.d.ts +1 -1
- package/dist/utils/taxonomyNames.js +6 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +27 -21
- package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +1 -1
- package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +1 -1
- package/src/AddHighlightModel/index.tsx +1 -1
- package/src/LaunchMsaView/components/BlastQuery/BlastAutomaticPanel.tsx +88 -30
- package/src/LaunchMsaView/components/BlastQuery/BlastManualPanel.tsx +1 -1
- package/src/LaunchMsaView/components/BlastQuery/BlastPanel.tsx +4 -4
- package/src/LaunchMsaView/components/BlastQuery/CachedBlastResults.test.ts +50 -0
- package/src/LaunchMsaView/components/BlastQuery/CachedBlastResults.tsx +23 -3
- package/src/LaunchMsaView/components/BlastQuery/MsaAlgorithmSelect.tsx +1 -1
- package/src/LaunchMsaView/components/BlastQuery/consts.ts +40 -0
- package/src/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.tsx +1 -1
- package/src/LaunchMsaView/components/OrthologQuery/OrthologPanel.tsx +21 -5
- package/src/LaunchMsaView/components/OrthologQuery/OrthologSourceSelect.tsx +52 -0
- package/src/LaunchMsaView/components/SubmitCancelActions.test.tsx +1 -1
- package/src/LaunchMsaView/components/useFeatureSequence.ts +1 -1
- package/src/LaunchMsaView/detectQueryRow.test.ts +17 -15
- package/src/LaunchMsaView/detectQueryRow.ts +34 -23
- package/src/LaunchMsaView/useQueryRowName.ts +6 -9
- package/src/MsaViewPanel/afterCreateAutoruns.ts +2 -2
- package/src/MsaViewPanel/components/ErrorBoundary.tsx +2 -1
- package/src/MsaViewPanel/components/JobLink.tsx +7 -2
- package/src/MsaViewPanel/components/LaunchProgress.tsx +62 -0
- package/src/MsaViewPanel/components/MsaViewPanel.test.tsx +83 -0
- package/src/MsaViewPanel/components/MsaViewPanel.tsx +7 -4
- package/src/MsaViewPanel/doLaunchBlast.ts +127 -69
- package/src/MsaViewPanel/doLaunchOrthologs.test.ts +119 -2
- package/src/MsaViewPanel/doLaunchOrthologs.ts +100 -38
- package/src/MsaViewPanel/genomeToMSA.test.ts +37 -0
- package/src/MsaViewPanel/genomeToMSA.ts +6 -2
- package/src/MsaViewPanel/model.ts +38 -5
- package/src/MsaViewPanel/observeProteinHighlights.test.ts +13 -0
- package/src/MsaViewPanel/syncGenomeHoverToMsaColumn.test.ts +1 -0
- package/src/MsaViewPanel/util.ts +18 -0
- package/src/utils/blastCache.ts +33 -12
- package/src/utils/ebiBlast.ts +1 -1
- package/src/utils/msa.ts +43 -12
- package/src/utils/msaRows.ts +95 -0
- package/src/utils/pantherOrthologs.ts +399 -0
- package/src/utils/phmmer.ts +174 -0
- package/src/utils/taxonomyNames.ts +6 -1
- package/src/version.ts +1 -1
- package/dist/MsaViewPanel/components/LoadingBLAST.d.ts +0 -6
- package/dist/MsaViewPanel/components/LoadingBLAST.js +0 -26
- package/src/MsaViewPanel/components/LoadingBLAST.tsx +0 -48
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import { doLaunchOrthologs } from './doLaunchOrthologs';
|
|
3
2
|
import { launchMSA } from '../utils/msa';
|
|
4
3
|
import { defaultMaxSpecies, fetchOrthologRows, fetchProteinForGene, resolveGeneId, } from '../utils/ncbiOrthologs';
|
|
4
|
+
import { fetchPantherOrthologs } from '../utils/pantherOrthologs';
|
|
5
5
|
import { fetchTaxonomyInfo } from '../utils/taxonomyNames';
|
|
6
|
+
import { doLaunchOrthologs } from './doLaunchOrthologs';
|
|
6
7
|
// Every network call is mocked and nothing else is. What is under test is the
|
|
7
8
|
// argument shaping either side of those calls -- which species get asked for,
|
|
8
9
|
// what becomes the QUERY row, and whether the row earns the Accession that
|
|
@@ -14,11 +15,15 @@ vi.mock('../utils/ncbiOrthologs', async (importOriginal) => ({
|
|
|
14
15
|
fetchProteinForGene: vi.fn(),
|
|
15
16
|
fetchOrthologRows: vi.fn(),
|
|
16
17
|
}));
|
|
18
|
+
vi.mock('../utils/pantherOrthologs', () => ({
|
|
19
|
+
fetchPantherOrthologs: vi.fn(),
|
|
20
|
+
}));
|
|
17
21
|
vi.mock('../utils/msa', () => ({ launchMSA: vi.fn() }));
|
|
18
22
|
vi.mock('../utils/taxonomyNames', () => ({ fetchTaxonomyInfo: vi.fn() }));
|
|
19
23
|
const mockResolveGeneId = vi.mocked(resolveGeneId);
|
|
20
24
|
const mockFetchProtein = vi.mocked(fetchProteinForGene);
|
|
21
25
|
const mockFetchRows = vi.mocked(fetchOrthologRows);
|
|
26
|
+
const mockFetchPanther = vi.mocked(fetchPantherOrthologs);
|
|
22
27
|
const mockLaunchMSA = vi.mocked(launchMSA);
|
|
23
28
|
const mockFetchTaxonomy = vi.mocked(fetchTaxonomyInfo);
|
|
24
29
|
const HUMAN = 9606;
|
|
@@ -199,3 +204,103 @@ describe('the Accession that drives the domain overlay', () => {
|
|
|
199
204
|
expect(queryMetadata(result).Accession).toBeUndefined();
|
|
200
205
|
});
|
|
201
206
|
});
|
|
207
|
+
// The second source. What is under test is the dispatch and what the PANTHER
|
|
208
|
+
// result becomes on the query row -- the rows themselves are shaped upstream,
|
|
209
|
+
// and the tail of the launch (labels, aligner, metadata) is the same code the
|
|
210
|
+
// NCBI tests above already cover.
|
|
211
|
+
describe('the PANTHER source', () => {
|
|
212
|
+
const YEAST = 559292;
|
|
213
|
+
const found = {
|
|
214
|
+
matched: 'CDC28',
|
|
215
|
+
query: {
|
|
216
|
+
code: 'YEAST',
|
|
217
|
+
accession: 'P00546',
|
|
218
|
+
geneRef: 'SGD=S000000364',
|
|
219
|
+
sequence: 'MSGELANYKRLEKVGEGTYGVVYKA',
|
|
220
|
+
},
|
|
221
|
+
rows: [
|
|
222
|
+
{
|
|
223
|
+
taxId: HUMAN,
|
|
224
|
+
label: 'human',
|
|
225
|
+
scientificName: 'Homo sapiens',
|
|
226
|
+
commonName: 'human',
|
|
227
|
+
geneId: 'HGNC=1771',
|
|
228
|
+
protein: 'P24941',
|
|
229
|
+
sequence: 'MENFQKVEKIGEGTYGVVYKARNK',
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
};
|
|
233
|
+
beforeEach(() => {
|
|
234
|
+
mockFetchPanther.mockResolvedValue(found);
|
|
235
|
+
mockFetchTaxonomy.mockResolvedValue(new Map([[YEAST, { sciname: 'Saccharomyces cerevisiae' }]]));
|
|
236
|
+
});
|
|
237
|
+
test('source omitted is NCBI, so an old launch never reaches PANTHER', async () => {
|
|
238
|
+
await doLaunchOrthologs({ self: makeModel(params()) });
|
|
239
|
+
expect(mockFetchPanther).not.toHaveBeenCalled();
|
|
240
|
+
expect(mockResolveGeneId).toHaveBeenCalled();
|
|
241
|
+
});
|
|
242
|
+
test('source panther asks PANTHER with the same species semantics, and skips NCBI', async () => {
|
|
243
|
+
await doLaunchOrthologs({
|
|
244
|
+
self: makeModel({
|
|
245
|
+
taxId: YEAST,
|
|
246
|
+
source: 'panther',
|
|
247
|
+
geneCandidates: ['CDC28'],
|
|
248
|
+
msaAlgorithm: 'clustalo',
|
|
249
|
+
taxa: [HUMAN, YEAST],
|
|
250
|
+
maxSpecies: 7,
|
|
251
|
+
}),
|
|
252
|
+
});
|
|
253
|
+
expect(mockResolveGeneId).not.toHaveBeenCalled();
|
|
254
|
+
expect(mockFetchRows).not.toHaveBeenCalled();
|
|
255
|
+
const { candidates, taxId, taxa, exclude, limit } = mockFetchPanther.mock.calls[0][0];
|
|
256
|
+
expect(candidates).toEqual(['CDC28']);
|
|
257
|
+
expect(taxId).toBe(YEAST);
|
|
258
|
+
expect([...taxa]).toEqual([HUMAN, YEAST]);
|
|
259
|
+
expect(exclude).toBe(YEAST);
|
|
260
|
+
expect(limit).toBe(7);
|
|
261
|
+
});
|
|
262
|
+
test("the query row is PANTHER's own entry for the gene when no sequence was supplied, and carries its UniProt accession for the domain overlay", async () => {
|
|
263
|
+
const result = await doLaunchOrthologs({
|
|
264
|
+
self: makeModel({
|
|
265
|
+
taxId: YEAST,
|
|
266
|
+
source: 'panther',
|
|
267
|
+
geneCandidates: ['CDC28'],
|
|
268
|
+
msaAlgorithm: 'clustalo',
|
|
269
|
+
}),
|
|
270
|
+
});
|
|
271
|
+
expect(queryRowName()).toBe('Saccharomyces_cerevisiae_query');
|
|
272
|
+
expect(queryRowSent()).toBe(found.query.sequence);
|
|
273
|
+
expect(queryMetadata(result)).toEqual({
|
|
274
|
+
'Gene ID': 'SGD=S000000364',
|
|
275
|
+
Accession: 'P00546',
|
|
276
|
+
});
|
|
277
|
+
expect(JSON.parse(result.treeMetadata).human).toMatchObject({
|
|
278
|
+
Accession: 'P24941',
|
|
279
|
+
'Gene ID': 'HGNC=1771',
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
test('a supplied sequence still wins, and a different isoform earns no Accession', async () => {
|
|
283
|
+
const result = await doLaunchOrthologs({
|
|
284
|
+
self: makeModel({
|
|
285
|
+
taxId: YEAST,
|
|
286
|
+
source: 'panther',
|
|
287
|
+
geneCandidates: ['CDC28'],
|
|
288
|
+
msaAlgorithm: 'clustalo',
|
|
289
|
+
proteinSequence: 'MDIFFERENTISOFORM',
|
|
290
|
+
}),
|
|
291
|
+
});
|
|
292
|
+
expect(queryRowSent()).toBe('MDIFFERENTISOFORM');
|
|
293
|
+
expect(queryMetadata(result).Accession).toBeUndefined();
|
|
294
|
+
});
|
|
295
|
+
test('names PANTHER when it has no protein for the query row', async () => {
|
|
296
|
+
mockFetchPanther.mockResolvedValue({ ...found, query: undefined });
|
|
297
|
+
await expect(doLaunchOrthologs({
|
|
298
|
+
self: makeModel({
|
|
299
|
+
taxId: YEAST,
|
|
300
|
+
source: 'panther',
|
|
301
|
+
geneCandidates: ['CDC28'],
|
|
302
|
+
msaAlgorithm: 'clustalo',
|
|
303
|
+
}),
|
|
304
|
+
})).rejects.toThrow(/PANTHER returned no representative protein/);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { getSession } from '@jbrowse/core/util';
|
|
2
|
-
import { hasHoverPosition } from './util';
|
|
2
|
+
import { hasHoverPosition, hasQueryRow } from './util';
|
|
3
3
|
export function genomeToMSA({ model }) {
|
|
4
4
|
const { hovered } = getSession(model);
|
|
5
5
|
const { querySeqName, transcriptToMsaMap, connectedView, mafRegion } = model;
|
|
6
|
-
if (!connectedView?.initialized ||
|
|
6
|
+
if (!connectedView?.initialized ||
|
|
7
|
+
!hasHoverPosition(hovered) ||
|
|
8
|
+
!hasQueryRow(model)) {
|
|
7
9
|
return undefined;
|
|
8
10
|
}
|
|
9
11
|
const { coord, refName } = hovered.hoverPosition;
|
|
@@ -19,6 +19,7 @@ describe('genomeToMSA', () => {
|
|
|
19
19
|
});
|
|
20
20
|
const model = {
|
|
21
21
|
querySeqName: 'hg38.chr1',
|
|
22
|
+
rows: [['hg38.chr1', 'ACGTACGTAC']],
|
|
22
23
|
transcriptToMsaMap: undefined,
|
|
23
24
|
mafRegion: {
|
|
24
25
|
refName: 'chr1',
|
|
@@ -38,6 +39,7 @@ describe('genomeToMSA', () => {
|
|
|
38
39
|
});
|
|
39
40
|
const model = {
|
|
40
41
|
querySeqName: 'hg38.chr1',
|
|
42
|
+
rows: [['hg38.chr1', 'ACGTACGTAC']],
|
|
41
43
|
transcriptToMsaMap: undefined,
|
|
42
44
|
mafRegion: {
|
|
43
45
|
refName: 'chr1',
|
|
@@ -62,6 +64,7 @@ describe('genomeToMSA', () => {
|
|
|
62
64
|
const mockSeqPosToVisibleCol = vi.fn().mockReturnValue(5);
|
|
63
65
|
const model = {
|
|
64
66
|
querySeqName: 'hg38.chr1',
|
|
67
|
+
rows: [['hg38.chr1', 'ACGTACGTAC']],
|
|
65
68
|
transcriptToMsaMap: undefined,
|
|
66
69
|
mafRegion: {
|
|
67
70
|
refName: 'chr1',
|
|
@@ -90,6 +93,7 @@ describe('genomeToMSA', () => {
|
|
|
90
93
|
});
|
|
91
94
|
const model = {
|
|
92
95
|
querySeqName: 'hg38.chr1',
|
|
96
|
+
rows: [['hg38.chr1', 'ACGTACGTAC']],
|
|
93
97
|
transcriptToMsaMap: undefined,
|
|
94
98
|
mafRegion: {
|
|
95
99
|
refName: 'chr1',
|
|
@@ -116,6 +120,7 @@ describe('genomeToMSA', () => {
|
|
|
116
120
|
});
|
|
117
121
|
const model = {
|
|
118
122
|
querySeqName: 'hg38.chr1',
|
|
123
|
+
rows: [['hg38.chr1', 'ACGTACGTAC']],
|
|
119
124
|
transcriptToMsaMap: undefined,
|
|
120
125
|
mafRegion: {
|
|
121
126
|
refName: 'chr1',
|
|
@@ -142,6 +147,7 @@ describe('genomeToMSA', () => {
|
|
|
142
147
|
});
|
|
143
148
|
const model = {
|
|
144
149
|
querySeqName: 'hg38.chr1',
|
|
150
|
+
rows: [['hg38.chr1', 'ACGTACGTAC']],
|
|
145
151
|
transcriptToMsaMap: undefined,
|
|
146
152
|
mafRegion: {
|
|
147
153
|
refName: 'chr1',
|
|
@@ -167,6 +173,7 @@ describe('genomeToMSA', () => {
|
|
|
167
173
|
});
|
|
168
174
|
const model = {
|
|
169
175
|
querySeqName: 'hg38.chr1',
|
|
176
|
+
rows: [['hg38.chr1', 'ACGTACGTAC']],
|
|
170
177
|
transcriptToMsaMap: undefined,
|
|
171
178
|
mafRegion: {
|
|
172
179
|
refName: 'chr1',
|
|
@@ -195,6 +202,7 @@ describe('genomeToMSA', () => {
|
|
|
195
202
|
const mockSeqPosToVisibleCol = vi.fn().mockReturnValue(10);
|
|
196
203
|
const model = {
|
|
197
204
|
querySeqName: 'QUERY',
|
|
205
|
+
rows: [['QUERY', 'MKVLTAEEK']],
|
|
198
206
|
transcriptToMsaMap: {
|
|
199
207
|
refName: 'chr1',
|
|
200
208
|
// g2p is keyed by 0-based genome position, the hover coord is 1-based
|
|
@@ -220,6 +228,7 @@ describe('genomeToMSA', () => {
|
|
|
220
228
|
const mockSeqPosToVisibleCol = vi.fn();
|
|
221
229
|
const model = {
|
|
222
230
|
querySeqName: 'QUERY',
|
|
231
|
+
rows: [['QUERY', 'MKVLTAEEK']],
|
|
223
232
|
transcriptToMsaMap: {
|
|
224
233
|
refName: 'chr1',
|
|
225
234
|
g2p: { 1004: 10 },
|
|
@@ -240,6 +249,7 @@ describe('genomeToMSA', () => {
|
|
|
240
249
|
});
|
|
241
250
|
const model = {
|
|
242
251
|
querySeqName: 'QUERY',
|
|
252
|
+
rows: [['QUERY', 'MKVLTAEEK']],
|
|
243
253
|
transcriptToMsaMap: {
|
|
244
254
|
refName: 'chr1',
|
|
245
255
|
g2p: { 1000: 0 }, // No entry for 1004
|
|
@@ -261,6 +271,7 @@ describe('genomeToMSA', () => {
|
|
|
261
271
|
});
|
|
262
272
|
const model = {
|
|
263
273
|
querySeqName: 'QUERY',
|
|
274
|
+
rows: [['QUERY', 'MKVLTAEEK']],
|
|
264
275
|
transcriptToMsaMap: undefined,
|
|
265
276
|
mafRegion: undefined,
|
|
266
277
|
connectedView: { initialized: true },
|
|
@@ -269,4 +280,27 @@ describe('genomeToMSA', () => {
|
|
|
269
280
|
const result = genomeToMSA({ model });
|
|
270
281
|
expect(result).toBeUndefined();
|
|
271
282
|
});
|
|
283
|
+
// seqPosToVisibleCol answers 0 for a row name it does not know, so without a
|
|
284
|
+
// guard an alignment whose query row is missing -- the default 'QUERY' on an
|
|
285
|
+
// uploaded file, or the empty name the manual panel leaves when it matches
|
|
286
|
+
// nothing -- lights column 0 on every genome hover
|
|
287
|
+
test('returns undefined when querySeqName names no row here', () => {
|
|
288
|
+
mockGetSession.mockReturnValue({
|
|
289
|
+
hovered: {
|
|
290
|
+
hoverFeature: {},
|
|
291
|
+
hoverPosition: { coord: 1005, refName: 'chr1' },
|
|
292
|
+
},
|
|
293
|
+
});
|
|
294
|
+
const seqPosToVisibleCol = vi.fn(() => 0);
|
|
295
|
+
const model = {
|
|
296
|
+
querySeqName: 'QUERY',
|
|
297
|
+
rows: [['some_other_row', 'MKVLTAEEK']],
|
|
298
|
+
transcriptToMsaMap: { refName: 'chr1', g2p: { 1004: 3 } },
|
|
299
|
+
mafRegion: undefined,
|
|
300
|
+
connectedView: { initialized: true },
|
|
301
|
+
seqPosToVisibleCol,
|
|
302
|
+
};
|
|
303
|
+
expect(genomeToMSA({ model })).toBeUndefined();
|
|
304
|
+
expect(seqPosToVisibleCol).not.toHaveBeenCalled();
|
|
305
|
+
});
|
|
272
306
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type { MSAFormat } from 'msa-parsers';
|
|
2
|
+
import type { BlastDatabase, MsaAlgorithm, PhmmerDatabase } from '../LaunchMsaView/components/BlastQuery/consts';
|
|
2
3
|
import type { MafRegion, MsaViewInitState } from './types';
|
|
3
|
-
import type { BlastDatabase, MsaAlgorithm } from '../LaunchMsaView/components/BlastQuery/consts';
|
|
4
4
|
import type { Feature } from '@jbrowse/core/util';
|
|
5
5
|
import type { Instance } from '@jbrowse/mobx-state-tree';
|
|
6
6
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view';
|
|
@@ -11,15 +11,43 @@ export interface IRegion {
|
|
|
11
11
|
start: number;
|
|
12
12
|
end: number;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* A search to run, discriminated by the program that runs it: the two arms
|
|
16
|
+
* differ in which databases they name and in whether an aligner runs at all, so
|
|
17
|
+
* splitting them is what lets doLaunchBlast read the database without asserting
|
|
18
|
+
* whose it is.
|
|
19
|
+
*
|
|
20
|
+
* The field is still `blastDatabase` rather than `database`: it is persisted in
|
|
21
|
+
* session snapshots and in the IndexedDB result cache, so renaming it would
|
|
22
|
+
* orphan every row already written.
|
|
23
|
+
*/
|
|
24
|
+
export type BlastParams = {
|
|
17
25
|
selectedTranscript?: Feature;
|
|
18
26
|
proteinSequence: string;
|
|
19
|
-
}
|
|
27
|
+
} & ({
|
|
28
|
+
/** absent on params written before phmmer existed, which were all blastp */
|
|
29
|
+
searchProgram?: 'blastp';
|
|
30
|
+
blastDatabase: BlastDatabase;
|
|
31
|
+
msaAlgorithm: MsaAlgorithm;
|
|
32
|
+
} | {
|
|
33
|
+
searchProgram: 'phmmer';
|
|
34
|
+
/** phmmer names its databases its own way: `swissprot`, not `uniprotkb_swissprot` */
|
|
35
|
+
blastDatabase: PhmmerDatabase;
|
|
36
|
+
/** phmmer aligns as it searches, so there is no aligner to choose */
|
|
37
|
+
msaAlgorithm?: undefined;
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Where the ortholog set comes from. NCBI's sets cover vertebrates and
|
|
41
|
+
* insects; PANTHER's span its 144 reference proteomes, human to yeast to
|
|
42
|
+
* Arabidopsis, so a gene from outside NCBI's scope aligns only through it.
|
|
43
|
+
*/
|
|
44
|
+
export declare const orthologSources: readonly ["ncbi", "panther"];
|
|
45
|
+
export type OrthologSource = (typeof orthologSources)[number];
|
|
20
46
|
export interface OrthologParams {
|
|
21
47
|
/** NCBI taxon id of the assembly the query gene came from */
|
|
22
48
|
taxId: number;
|
|
49
|
+
/** `ncbi` when omitted, so every launch written before this key keeps its meaning */
|
|
50
|
+
source?: OrthologSource;
|
|
23
51
|
/**
|
|
24
52
|
* taxon ids to include as rows. The query taxon has its own row already, so
|
|
25
53
|
* it is excluded from this set whether or not it is named.
|
|
@@ -57,7 +85,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
57
85
|
id: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
58
86
|
displayName: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
59
87
|
minimized: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
60
|
-
}, "
|
|
88
|
+
}, "id" | "type" | "autoTreeAreaWidth" | "drawLabels" | "drawNodeBubbles" | "drawTree" | "labelsAlignRight" | "showBranchLen" | "treeAreaWidth" | "treeWidth" | "bgColor" | "colorSchemeName" | "msaFormat" | "showColumnStats" | "allowedGappyness" | "colWidth" | "collapsed" | "currentAlignment" | "data" | "drawMsaLetters" | "featureFilters" | "gffFilehandle" | "height" | "hideGaps" | "highlightColumns" | "msaFilehandle" | "relativeTo" | "rowHeight" | "scrollX" | "scrollY" | "scrollZoom" | "showDomainLegend" | "showDomains" | "showOnly" | "subFeatureRows" | "treeFilehandle" | "treeMetadataFilehandle" | "turnedOffTracks"> & Omit<Omit<Omit<{}, "autoTreeAreaWidth" | "drawLabels" | "drawNodeBubbles" | "drawTree" | "labelsAlignRight" | "showBranchLen" | "treeAreaWidth" | "treeWidth"> & {
|
|
61
89
|
drawLabels: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
62
90
|
labelsAlignRight: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
63
91
|
treeAreaWidth: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<number>, [undefined]>;
|
|
@@ -71,7 +99,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
71
99
|
colorSchemeName: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
72
100
|
showColumnStats: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
73
101
|
msaFormat: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<import("msa-parsers").MSAFormat>>;
|
|
74
|
-
}, "
|
|
102
|
+
}, "id" | "type" | "allowedGappyness" | "colWidth" | "collapsed" | "currentAlignment" | "data" | "drawMsaLetters" | "featureFilters" | "gffFilehandle" | "height" | "hideGaps" | "highlightColumns" | "msaFilehandle" | "relativeTo" | "rowHeight" | "scrollX" | "scrollY" | "scrollZoom" | "showDomainLegend" | "showDomains" | "showOnly" | "subFeatureRows" | "treeFilehandle" | "treeMetadataFilehandle" | "turnedOffTracks"> & {
|
|
75
103
|
id: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
76
104
|
showDomains: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
77
105
|
showDomainLegend: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
@@ -477,10 +505,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
477
505
|
setTreeMetadata(treeMetadata?: string): void;
|
|
478
506
|
setGFF(gff?: string): void;
|
|
479
507
|
}, import("@jbrowse/mobx-state-tree")._NotCustomized, {
|
|
480
|
-
|
|
481
|
-
msa: string | undefined;
|
|
482
|
-
treeMetadata: string | undefined;
|
|
483
|
-
gff: string | undefined;
|
|
508
|
+
[k: string]: string | undefined;
|
|
484
509
|
}>, [undefined]>;
|
|
485
510
|
featureFilters: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").IMapType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>>, [undefined]>;
|
|
486
511
|
relativeTo: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
@@ -550,6 +575,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
550
575
|
highlightedColumns: number[] | undefined;
|
|
551
576
|
minimapHeight: number;
|
|
552
577
|
conservationTrackHeight: number;
|
|
578
|
+
sequenceLogoTrackHeight: number;
|
|
553
579
|
marginLeft: number;
|
|
554
580
|
error: unknown;
|
|
555
581
|
annotations: import("msa-parsers").Annotation[];
|
|
@@ -646,6 +672,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
646
672
|
}[];
|
|
647
673
|
readonly colClustalX: Record<string, string>[];
|
|
648
674
|
readonly conservation: number[];
|
|
675
|
+
readonly alphabetMaxBits: number;
|
|
649
676
|
readonly propertyConservation: number[];
|
|
650
677
|
readonly hierarchy: import("react-msaview").HierarchyNode<import("react-msaview").NodeWithIdsAndLength>;
|
|
651
678
|
readonly totalHeight: number;
|
|
@@ -660,6 +687,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
660
687
|
readonly dataInitialized: boolean;
|
|
661
688
|
readonly blocksX: number[];
|
|
662
689
|
readonly blocksY: number[];
|
|
690
|
+
readonly visibleMsaHeight: number;
|
|
663
691
|
} & {
|
|
664
692
|
readonly blocks2d: (readonly [number, number])[];
|
|
665
693
|
readonly isLoading: boolean;
|
|
@@ -695,6 +723,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
695
723
|
}): void;
|
|
696
724
|
} & {
|
|
697
725
|
readonly labelWidthMap: Map<string, number>;
|
|
726
|
+
readonly labelWidthScale: number;
|
|
698
727
|
readonly labelsWidth: number;
|
|
699
728
|
readonly secondaryStructureConsensus: string | undefined;
|
|
700
729
|
readonly seqConsensus: string | undefined;
|
|
@@ -761,6 +790,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
761
790
|
} & {
|
|
762
791
|
setHeaderHeight(arg: number): void;
|
|
763
792
|
setConservationTrackHeight(arg: number): void;
|
|
793
|
+
setSequenceLogoTrackHeight(arg: number): void;
|
|
764
794
|
reset(): void;
|
|
765
795
|
exportSVG(opts: {
|
|
766
796
|
theme: import("@mui/material").Theme;
|
|
@@ -6,6 +6,12 @@ import { autorun } from 'mobx';
|
|
|
6
6
|
import { MSAModelF } from 'react-msaview';
|
|
7
7
|
import { autoLoadProteinDomains, launchBlastIfNeeded, launchOrthologsIfNeeded, loadStoredData, observeProteinHighlights, processInit, runCleanup, storeDataToIndexedDB, syncGenomeHoverToMsaColumn, } from './afterCreateAutoruns';
|
|
8
8
|
import { msaCoordToGenomeCoord, msaCoordToGenomeRegions, } from './msaCoordToGenomeCoord';
|
|
9
|
+
/**
|
|
10
|
+
* Where the ortholog set comes from. NCBI's sets cover vertebrates and
|
|
11
|
+
* insects; PANTHER's span its 144 reference proteomes, human to yeast to
|
|
12
|
+
* Arabidopsis, so a gene from outside NCBI's scope aligns only through it.
|
|
13
|
+
*/
|
|
14
|
+
export const orthologSources = ['ncbi', 'panther'];
|
|
9
15
|
/**
|
|
10
16
|
* #stateModel MsaViewPlugin
|
|
11
17
|
* extends
|
|
@@ -18,6 +18,7 @@ function makeModel({ highlightColumns } = {}) {
|
|
|
18
18
|
const calls = [];
|
|
19
19
|
const model = {
|
|
20
20
|
querySeqName: 'query',
|
|
21
|
+
rows: [['query', 'MKVLTAEEK']],
|
|
21
22
|
connectedViewId: CONNECTED,
|
|
22
23
|
// g2p is indexed by genome coord; identity keeps the arithmetic out of the way
|
|
23
24
|
transcriptToMsaMap: {
|
|
@@ -195,6 +196,16 @@ describe('scope and redundant writes', () => {
|
|
|
195
196
|
run();
|
|
196
197
|
expect(calls).toEqual([]);
|
|
197
198
|
});
|
|
199
|
+
// seqPosToGlobalCol answers 0 for a row name it does not know, so without a
|
|
200
|
+
// guard a structure hover would light column 0 of whatever row is first
|
|
201
|
+
test('a query row this alignment does not have contributes no column', () => {
|
|
202
|
+
const { model, calls } = makeModel();
|
|
203
|
+
Object.assign(model, { rows: [['some_other_row', 'MKVLTAEEK']] });
|
|
204
|
+
const run = observeProteinHighlights(model);
|
|
205
|
+
session({ hover: [{ start: 10, end: 12 }] });
|
|
206
|
+
run();
|
|
207
|
+
expect(calls).toEqual([]);
|
|
208
|
+
});
|
|
198
209
|
test('nothing happens until the view is connected and mapped', () => {
|
|
199
210
|
const { calls } = makeModel();
|
|
200
211
|
const bare = {
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether `querySeqName` names a row this alignment actually has.
|
|
3
|
+
*
|
|
4
|
+
* react-msaview's `seqPosToGlobalCol` answers 0 for a name it does not know, so
|
|
5
|
+
* without this every genome position maps to the first column and hovering the
|
|
6
|
+
* genome — or a connected structure — lights column 0 of an unrelated row. The
|
|
7
|
+
* name is wrong more often than it looks: it defaults to `QUERY`, which an
|
|
8
|
+
* uploaded alignment has no reason to carry, and the manual panel leaves it
|
|
9
|
+
* empty when it cannot match the protein to a row.
|
|
10
|
+
*
|
|
11
|
+
* The other direction has no such hole: msaCoordToGenomeRegions needs the query
|
|
12
|
+
* row's sequence to map a column at all, so a missing row is already nothing
|
|
13
|
+
* there.
|
|
14
|
+
*/
|
|
15
|
+
export declare function hasQueryRow(model: {
|
|
16
|
+
rows: string[][];
|
|
17
|
+
querySeqName: string;
|
|
18
|
+
}): boolean;
|
|
1
19
|
export declare function hasHoverPosition(hovered: unknown): hovered is {
|
|
2
20
|
hoverPosition: {
|
|
3
21
|
coord: number;
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether `querySeqName` names a row this alignment actually has.
|
|
3
|
+
*
|
|
4
|
+
* react-msaview's `seqPosToGlobalCol` answers 0 for a name it does not know, so
|
|
5
|
+
* without this every genome position maps to the first column and hovering the
|
|
6
|
+
* genome — or a connected structure — lights column 0 of an unrelated row. The
|
|
7
|
+
* name is wrong more often than it looks: it defaults to `QUERY`, which an
|
|
8
|
+
* uploaded alignment has no reason to carry, and the manual panel leaves it
|
|
9
|
+
* empty when it cannot match the protein to a row.
|
|
10
|
+
*
|
|
11
|
+
* The other direction has no such hole: msaCoordToGenomeRegions needs the query
|
|
12
|
+
* row's sequence to map a column at all, so a missing row is already nothing
|
|
13
|
+
* there.
|
|
14
|
+
*/
|
|
15
|
+
export function hasQueryRow(model) {
|
|
16
|
+
return model.rows.some(r => r[0] === model.querySeqName);
|
|
17
|
+
}
|
|
1
18
|
export function hasHoverPosition(hovered) {
|
|
2
19
|
return (!!hovered &&
|
|
3
20
|
typeof hovered === 'object' &&
|