jbrowse-plugin-msaview 2.7.1 → 2.7.3
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/MsaToGenomeHighlight.js +6 -5
- package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js +1 -1
- package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.js +1 -1
- package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.d.ts +1 -1
- package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js +5 -2
- package/dist/LaunchMsaView/components/calculateProteinSequence.d.ts +3 -2
- package/dist/LaunchMsaView/components/calculateProteinSequence.js +31 -15
- package/dist/LaunchMsaView/components/geneticCodes.d.ts +15 -0
- package/dist/LaunchMsaView/components/geneticCodes.js +227 -0
- package/dist/LaunchMsaView/components/types.d.ts +1 -0
- package/dist/LaunchMsaView/index.js +32 -26
- package/dist/MsaViewPanel/doLaunchBlast.js +10 -22
- package/dist/MsaViewPanel/genomeToMSA.js +13 -6
- package/dist/MsaViewPanel/genomeToMSA.test.js +35 -6
- package/dist/MsaViewPanel/model.d.ts +68 -66
- package/dist/MsaViewPanel/model.js +14 -12
- package/dist/MsaViewPanel/msaCoordToGenomeCoord.d.ts +32 -13
- package/dist/MsaViewPanel/msaCoordToGenomeCoord.js +43 -14
- package/dist/MsaViewPanel/msaCoordToGenomeCoord.test.js +108 -18
- package/dist/MsaViewPanel/msaDataStore.js +8 -17
- package/dist/MsaViewPanel/syncGenomeHoverToMsaColumn.test.js +8 -6
- package/dist/jbrowse-plugin-msaview.umd.production.min.js +31 -31
- package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
- package/dist/utils/blastCache.d.ts +1 -2
- package/dist/utils/blastCache.js +9 -22
- package/dist/utils/domainCache.js +6 -15
- package/dist/utils/idb.d.ts +12 -0
- package/dist/utils/idb.js +21 -0
- package/dist/utils/taxonomyNames.js +13 -18
- package/dist/utils/useLocalStorage.d.ts +1 -0
- package/dist/utils/useLocalStorage.js +29 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -3
- package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +6 -8
- package/src/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.tsx +1 -1
- package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.tsx +1 -1
- package/src/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.ts +4 -2
- package/src/LaunchMsaView/components/calculateProteinSequence.ts +35 -20
- package/src/LaunchMsaView/components/geneticCodes.ts +298 -0
- package/src/LaunchMsaView/components/types.ts +3 -0
- package/src/LaunchMsaView/index.ts +44 -35
- package/src/MsaViewPanel/doLaunchBlast.ts +20 -29
- package/src/MsaViewPanel/genomeToMSA.test.ts +38 -6
- package/src/MsaViewPanel/genomeToMSA.ts +14 -6
- package/src/MsaViewPanel/model.ts +17 -12
- package/src/MsaViewPanel/msaCoordToGenomeCoord.test.ts +117 -18
- package/src/MsaViewPanel/msaCoordToGenomeCoord.ts +70 -26
- package/src/MsaViewPanel/msaDataStore.ts +17 -17
- package/src/MsaViewPanel/syncGenomeHoverToMsaColumn.test.ts +8 -6
- package/src/utils/blastCache.ts +20 -23
- package/src/utils/domainCache.ts +14 -18
- package/src/utils/idb.ts +28 -0
- package/src/utils/taxonomyNames.ts +22 -24
- package/src/utils/useLocalStorage.ts +31 -0
- package/src/version.ts +1 -1
- package/dist/MsaViewPanel/blosum62.d.ts +0 -2
- package/dist/MsaViewPanel/blosum62.js +0 -627
- package/src/MsaViewPanel/blosum62.ts +0 -628
|
@@ -29,7 +29,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
29
29
|
id: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
30
30
|
displayName: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
31
31
|
minimized: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
32
|
-
}, "height" | "id" | "type" | "
|
|
32
|
+
}, "height" | "id" | "type" | "autoTreeAreaWidth" | "drawLabels" | "drawNodeBubbles" | "drawTree" | "labelsAlignRight" | "showBranchLen" | "treeAreaWidth" | "treeWidth" | "bgColor" | "colorSchemeName" | "msaFormat" | "showColumnStats" | "allowedGappyness" | "colWidth" | "collapsed" | "currentAlignment" | "data" | "drawMsaLetters" | "featureFilters" | "gffFilehandle" | "hideGaps" | "highlightColumns" | "msaFilehandle" | "relativeTo" | "rowHeight" | "scrollX" | "scrollY" | "scrollZoom" | "showDomains" | "showOnly" | "subFeatureRows" | "treeFilehandle" | "treeMetadataFilehandle" | "turnedOffTracks"> & Omit<Omit<Omit<{}, "autoTreeAreaWidth" | "drawLabels" | "drawNodeBubbles" | "drawTree" | "labelsAlignRight" | "showBranchLen" | "treeAreaWidth" | "treeWidth"> & {
|
|
33
33
|
drawLabels: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
34
34
|
labelsAlignRight: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
35
35
|
treeAreaWidth: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<number>, [undefined]>;
|
|
@@ -38,12 +38,12 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
38
38
|
drawTree: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
39
39
|
drawNodeBubbles: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
40
40
|
autoTreeAreaWidth: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
41
|
-
}, "bgColor" | "colorSchemeName" | "
|
|
41
|
+
}, "bgColor" | "colorSchemeName" | "msaFormat" | "showColumnStats"> & {
|
|
42
42
|
bgColor: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
43
43
|
colorSchemeName: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
44
44
|
showColumnStats: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
45
45
|
msaFormat: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<import("react-msaview").MSAFormat>>;
|
|
46
|
-
}, "height" | "id" | "type" | "
|
|
46
|
+
}, "height" | "id" | "type" | "allowedGappyness" | "colWidth" | "collapsed" | "currentAlignment" | "data" | "drawMsaLetters" | "featureFilters" | "gffFilehandle" | "hideGaps" | "highlightColumns" | "msaFilehandle" | "relativeTo" | "rowHeight" | "scrollX" | "scrollY" | "scrollZoom" | "showDomains" | "showOnly" | "subFeatureRows" | "treeFilehandle" | "treeMetadataFilehandle" | "turnedOffTracks"> & {
|
|
47
47
|
id: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
48
48
|
showDomains: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
49
49
|
hideGaps: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>, [undefined]>;
|
|
@@ -97,18 +97,6 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
97
97
|
authInfo: import("@jbrowse/mobx-state-tree").IType<any, any, any>;
|
|
98
98
|
}> | undefined;
|
|
99
99
|
}, ({
|
|
100
|
-
locationType: "UriLocation";
|
|
101
|
-
uri: string;
|
|
102
|
-
} & Partial<{
|
|
103
|
-
locationType: "UriLocation";
|
|
104
|
-
uri: string;
|
|
105
|
-
baseUri: string | undefined;
|
|
106
|
-
internetAccountId: string | undefined;
|
|
107
|
-
internetAccountPreAuthorization: import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
108
|
-
internetAccountType: string;
|
|
109
|
-
authInfo: any;
|
|
110
|
-
}> | undefined;
|
|
111
|
-
}>) | ({
|
|
112
100
|
blobId: string;
|
|
113
101
|
locationType: "BlobLocation";
|
|
114
102
|
name: string;
|
|
@@ -130,6 +118,18 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
130
118
|
} & Partial<{
|
|
131
119
|
locationType: "LocalPathLocation";
|
|
132
120
|
localPath: string;
|
|
121
|
+
}>) | ({
|
|
122
|
+
locationType: "UriLocation";
|
|
123
|
+
uri: string;
|
|
124
|
+
} & Partial<{
|
|
125
|
+
locationType: "UriLocation";
|
|
126
|
+
uri: string;
|
|
127
|
+
baseUri: string | undefined;
|
|
128
|
+
internetAccountId: string | undefined;
|
|
129
|
+
internetAccountPreAuthorization: import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
130
|
+
internetAccountType: string;
|
|
131
|
+
authInfo: any;
|
|
132
|
+
}> | undefined;
|
|
133
133
|
}>)>, import("@jbrowse/core/util/types/mst").LegacyFileLocation | import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
134
134
|
locationType: "LocalPathLocation";
|
|
135
135
|
localPath: string;
|
|
@@ -191,18 +191,6 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
191
191
|
authInfo: import("@jbrowse/mobx-state-tree").IType<any, any, any>;
|
|
192
192
|
}> | undefined;
|
|
193
193
|
}, ({
|
|
194
|
-
locationType: "UriLocation";
|
|
195
|
-
uri: string;
|
|
196
|
-
} & Partial<{
|
|
197
|
-
locationType: "UriLocation";
|
|
198
|
-
uri: string;
|
|
199
|
-
baseUri: string | undefined;
|
|
200
|
-
internetAccountId: string | undefined;
|
|
201
|
-
internetAccountPreAuthorization: import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
202
|
-
internetAccountType: string;
|
|
203
|
-
authInfo: any;
|
|
204
|
-
}> | undefined;
|
|
205
|
-
}>) | ({
|
|
206
194
|
blobId: string;
|
|
207
195
|
locationType: "BlobLocation";
|
|
208
196
|
name: string;
|
|
@@ -224,6 +212,18 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
224
212
|
} & Partial<{
|
|
225
213
|
locationType: "LocalPathLocation";
|
|
226
214
|
localPath: string;
|
|
215
|
+
}>) | ({
|
|
216
|
+
locationType: "UriLocation";
|
|
217
|
+
uri: string;
|
|
218
|
+
} & Partial<{
|
|
219
|
+
locationType: "UriLocation";
|
|
220
|
+
uri: string;
|
|
221
|
+
baseUri: string | undefined;
|
|
222
|
+
internetAccountId: string | undefined;
|
|
223
|
+
internetAccountPreAuthorization: import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
224
|
+
internetAccountType: string;
|
|
225
|
+
authInfo: any;
|
|
226
|
+
}> | undefined;
|
|
227
227
|
}>)>, import("@jbrowse/core/util/types/mst").LegacyFileLocation | import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
228
228
|
locationType: "LocalPathLocation";
|
|
229
229
|
localPath: string;
|
|
@@ -285,18 +285,6 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
285
285
|
authInfo: import("@jbrowse/mobx-state-tree").IType<any, any, any>;
|
|
286
286
|
}> | undefined;
|
|
287
287
|
}, ({
|
|
288
|
-
locationType: "UriLocation";
|
|
289
|
-
uri: string;
|
|
290
|
-
} & Partial<{
|
|
291
|
-
locationType: "UriLocation";
|
|
292
|
-
uri: string;
|
|
293
|
-
baseUri: string | undefined;
|
|
294
|
-
internetAccountId: string | undefined;
|
|
295
|
-
internetAccountPreAuthorization: import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
296
|
-
internetAccountType: string;
|
|
297
|
-
authInfo: any;
|
|
298
|
-
}> | undefined;
|
|
299
|
-
}>) | ({
|
|
300
288
|
blobId: string;
|
|
301
289
|
locationType: "BlobLocation";
|
|
302
290
|
name: string;
|
|
@@ -318,6 +306,18 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
318
306
|
} & Partial<{
|
|
319
307
|
locationType: "LocalPathLocation";
|
|
320
308
|
localPath: string;
|
|
309
|
+
}>) | ({
|
|
310
|
+
locationType: "UriLocation";
|
|
311
|
+
uri: string;
|
|
312
|
+
} & Partial<{
|
|
313
|
+
locationType: "UriLocation";
|
|
314
|
+
uri: string;
|
|
315
|
+
baseUri: string | undefined;
|
|
316
|
+
internetAccountId: string | undefined;
|
|
317
|
+
internetAccountPreAuthorization: import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
318
|
+
internetAccountType: string;
|
|
319
|
+
authInfo: any;
|
|
320
|
+
}> | undefined;
|
|
321
321
|
}>)>, import("@jbrowse/core/util/types/mst").LegacyFileLocation | import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
322
322
|
locationType: "LocalPathLocation";
|
|
323
323
|
localPath: string;
|
|
@@ -379,18 +379,6 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
379
379
|
authInfo: import("@jbrowse/mobx-state-tree").IType<any, any, any>;
|
|
380
380
|
}> | undefined;
|
|
381
381
|
}, ({
|
|
382
|
-
locationType: "UriLocation";
|
|
383
|
-
uri: string;
|
|
384
|
-
} & Partial<{
|
|
385
|
-
locationType: "UriLocation";
|
|
386
|
-
uri: string;
|
|
387
|
-
baseUri: string | undefined;
|
|
388
|
-
internetAccountId: string | undefined;
|
|
389
|
-
internetAccountPreAuthorization: import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
390
|
-
internetAccountType: string;
|
|
391
|
-
authInfo: any;
|
|
392
|
-
}> | undefined;
|
|
393
|
-
}>) | ({
|
|
394
382
|
blobId: string;
|
|
395
383
|
locationType: "BlobLocation";
|
|
396
384
|
name: string;
|
|
@@ -412,6 +400,18 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
412
400
|
} & Partial<{
|
|
413
401
|
locationType: "LocalPathLocation";
|
|
414
402
|
localPath: string;
|
|
403
|
+
}>) | ({
|
|
404
|
+
locationType: "UriLocation";
|
|
405
|
+
uri: string;
|
|
406
|
+
} & Partial<{
|
|
407
|
+
locationType: "UriLocation";
|
|
408
|
+
uri: string;
|
|
409
|
+
baseUri: string | undefined;
|
|
410
|
+
internetAccountId: string | undefined;
|
|
411
|
+
internetAccountPreAuthorization: import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
412
|
+
internetAccountType: string;
|
|
413
|
+
authInfo: any;
|
|
414
|
+
}> | undefined;
|
|
415
415
|
}>)>, import("@jbrowse/core/util/types/mst").LegacyFileLocation | import("@jbrowse/mobx-state-tree").ModelCreationType<{
|
|
416
416
|
locationType: "LocalPathLocation";
|
|
417
417
|
localPath: string;
|
|
@@ -581,7 +581,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
581
581
|
readonly noTree: boolean;
|
|
582
582
|
readonly noDomains: boolean;
|
|
583
583
|
menuItems(): never[];
|
|
584
|
-
readonly treeMetadata:
|
|
584
|
+
readonly treeMetadata: Record<string, Record<string, string> | undefined>;
|
|
585
585
|
readonly MSA: import("react-msaview").MSAParserType | null;
|
|
586
586
|
readonly numColumns: number;
|
|
587
587
|
readonly tree: import("react-msaview").NodeWithIds;
|
|
@@ -789,7 +789,7 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
789
789
|
accession?: string;
|
|
790
790
|
dbxref?: string;
|
|
791
791
|
} | undefined;
|
|
792
|
-
treeMetadata:
|
|
792
|
+
treeMetadata: Record<string, string> | undefined;
|
|
793
793
|
};
|
|
794
794
|
} & {
|
|
795
795
|
setHeaderHeight(arg: number): void;
|
|
@@ -841,19 +841,21 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
841
841
|
} & {
|
|
842
842
|
/**
|
|
843
843
|
* #getter
|
|
844
|
-
* Genome
|
|
844
|
+
* Genome regions under the current MSA hover column. Suppressed on the LGV
|
|
845
845
|
* while it's being hovered (GenomeMouseoverHighlight shows the crisp 1bp
|
|
846
846
|
* marker there instead of this wider codon band).
|
|
847
847
|
*/
|
|
848
|
-
readonly
|
|
848
|
+
readonly connectedHoverHighlights: IRegion[];
|
|
849
849
|
/**
|
|
850
850
|
* #getter
|
|
851
|
-
* Genome
|
|
851
|
+
* Genome regions under the persistent MSA click selection. Shown
|
|
852
852
|
* regardless of LGV hover, so hovering the genome doesn't hide it.
|
|
853
853
|
*/
|
|
854
|
-
readonly
|
|
854
|
+
readonly connectedClickHighlights: IRegion[];
|
|
855
855
|
/**
|
|
856
856
|
* #getter
|
|
857
|
+
* cross-plugin contract: jbrowse-plugin-mafviewer reads this off the view
|
|
858
|
+
* to draw the same highlights in its own display
|
|
857
859
|
*/
|
|
858
860
|
readonly connectedHighlights: IRegion[];
|
|
859
861
|
} & {
|
|
@@ -935,11 +937,10 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
935
937
|
displayName: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
936
938
|
minimized: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
937
939
|
}> & {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
};
|
|
940
|
+
bgColor: boolean;
|
|
941
|
+
colorSchemeName: string;
|
|
942
|
+
showColumnStats: boolean;
|
|
943
|
+
msaFormat: import("react-msaview").MSAFormat | undefined;
|
|
943
944
|
drawLabels: boolean;
|
|
944
945
|
labelsAlignRight: boolean;
|
|
945
946
|
treeAreaWidth: number;
|
|
@@ -948,10 +949,6 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
948
949
|
drawTree: boolean;
|
|
949
950
|
drawNodeBubbles: boolean;
|
|
950
951
|
autoTreeAreaWidth: boolean;
|
|
951
|
-
bgColor: boolean;
|
|
952
|
-
colorSchemeName: string;
|
|
953
|
-
showColumnStats: boolean;
|
|
954
|
-
msaFormat: import("react-msaview").MSAFormat | undefined;
|
|
955
952
|
id: string;
|
|
956
953
|
showDomains: boolean;
|
|
957
954
|
hideGaps: boolean;
|
|
@@ -1052,6 +1049,11 @@ export default function stateModelFactory(): import("@jbrowse/mobx-state-tree").
|
|
|
1052
1049
|
featureFilters: import("mobx").IKeyValueMap<boolean>;
|
|
1053
1050
|
relativeTo: string | undefined;
|
|
1054
1051
|
highlightColumns: number[] | undefined;
|
|
1052
|
+
data: {
|
|
1053
|
+
tree?: string | undefined;
|
|
1054
|
+
msa?: string | undefined;
|
|
1055
|
+
treeMetadata?: string | undefined;
|
|
1056
|
+
};
|
|
1055
1057
|
} & import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
|
1056
1058
|
export type JBrowsePluginMsaViewStateModel = ReturnType<typeof stateModelFactory>;
|
|
1057
1059
|
export type JBrowsePluginMsaViewModel = Instance<JBrowsePluginMsaViewStateModel>;
|
|
@@ -5,7 +5,7 @@ import { genomeToTranscriptSeqMapping } from 'g2p_mapper';
|
|
|
5
5
|
import { autorun } from 'mobx';
|
|
6
6
|
import { MSAModelF } from 'react-msaview';
|
|
7
7
|
import { autoLoadProteinDomains, launchBlastIfNeeded, loadStoredData, observeProteinHighlights, processInit, runCleanup, storeDataToIndexedDB, syncGenomeHoverToMsaColumn, } from './afterCreateAutoruns';
|
|
8
|
-
import { msaCoordToGenomeCoord } from './msaCoordToGenomeCoord';
|
|
8
|
+
import { msaCoordToGenomeCoord, msaCoordToGenomeRegions, } from './msaCoordToGenomeCoord';
|
|
9
9
|
/**
|
|
10
10
|
* #stateModel MsaViewPlugin
|
|
11
11
|
* extends
|
|
@@ -119,35 +119,37 @@ export default function stateModelFactory() {
|
|
|
119
119
|
.views(self => ({
|
|
120
120
|
/**
|
|
121
121
|
* #getter
|
|
122
|
-
* Genome
|
|
122
|
+
* Genome regions under the current MSA hover column. Suppressed on the LGV
|
|
123
123
|
* while it's being hovered (GenomeMouseoverHighlight shows the crisp 1bp
|
|
124
124
|
* marker there instead of this wider codon band).
|
|
125
125
|
*/
|
|
126
|
-
get
|
|
126
|
+
get connectedHoverHighlights() {
|
|
127
127
|
const { mouseCol } = self;
|
|
128
128
|
return mouseCol === undefined
|
|
129
|
-
?
|
|
130
|
-
:
|
|
129
|
+
? []
|
|
130
|
+
: msaCoordToGenomeRegions({ model: self, coord: mouseCol });
|
|
131
131
|
},
|
|
132
132
|
/**
|
|
133
133
|
* #getter
|
|
134
|
-
* Genome
|
|
134
|
+
* Genome regions under the persistent MSA click selection. Shown
|
|
135
135
|
* regardless of LGV hover, so hovering the genome doesn't hide it.
|
|
136
136
|
*/
|
|
137
|
-
get
|
|
137
|
+
get connectedClickHighlights() {
|
|
138
138
|
const { mouseClickCol } = self;
|
|
139
139
|
return mouseClickCol === undefined
|
|
140
|
-
?
|
|
141
|
-
:
|
|
140
|
+
? []
|
|
141
|
+
: msaCoordToGenomeRegions({ model: self, coord: mouseClickCol });
|
|
142
142
|
},
|
|
143
143
|
/**
|
|
144
144
|
* #getter
|
|
145
|
+
* cross-plugin contract: jbrowse-plugin-mafviewer reads this off the view
|
|
146
|
+
* to draw the same highlights in its own display
|
|
145
147
|
*/
|
|
146
148
|
get connectedHighlights() {
|
|
147
149
|
return [
|
|
148
|
-
this.
|
|
149
|
-
this.
|
|
150
|
-
]
|
|
150
|
+
...this.connectedHoverHighlights,
|
|
151
|
+
...this.connectedClickHighlights,
|
|
152
|
+
];
|
|
151
153
|
},
|
|
152
154
|
}))
|
|
153
155
|
.actions(self => ({
|
|
@@ -1,17 +1,36 @@
|
|
|
1
1
|
import type { MafRegion } from './types';
|
|
2
|
-
|
|
3
|
-
model: {
|
|
4
|
-
querySeqName: string;
|
|
5
|
-
transcriptToMsaMap: {
|
|
6
|
-
refName: string;
|
|
7
|
-
p2g: Record<number, number>;
|
|
8
|
-
} | undefined;
|
|
9
|
-
mafRegion?: MafRegion;
|
|
10
|
-
rows: string[][];
|
|
11
|
-
};
|
|
12
|
-
coord: number;
|
|
13
|
-
}): {
|
|
2
|
+
interface GenomeRegion {
|
|
14
3
|
refName: string;
|
|
15
4
|
start: number;
|
|
16
5
|
end: number;
|
|
17
|
-
}
|
|
6
|
+
}
|
|
7
|
+
interface CoordModel {
|
|
8
|
+
querySeqName: string;
|
|
9
|
+
transcriptToMsaMap: {
|
|
10
|
+
refName: string;
|
|
11
|
+
p2gCodon: Record<number, number[]>;
|
|
12
|
+
} | undefined;
|
|
13
|
+
mafRegion?: MafRegion;
|
|
14
|
+
rows: string[][];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The genome regions covered by MSA column `coord` of the query row, in 0-based
|
|
18
|
+
* half-open coordinates (what bpToPx and navTo take).
|
|
19
|
+
*
|
|
20
|
+
* Usually one region -- one codon, or one base in a MAF alignment -- but a
|
|
21
|
+
* codon split across an exon boundary yields one region per contiguous piece,
|
|
22
|
+
* which is why this returns a list.
|
|
23
|
+
*/
|
|
24
|
+
export declare function msaCoordToGenomeRegions({ model, coord: mouseCol, }: {
|
|
25
|
+
model: CoordModel;
|
|
26
|
+
coord: number;
|
|
27
|
+
}): GenomeRegion[];
|
|
28
|
+
/**
|
|
29
|
+
* A single region spanning the codon at MSA column `coord`, for navigation. For
|
|
30
|
+
* a codon split across an exon boundary this spans the intervening intron.
|
|
31
|
+
*/
|
|
32
|
+
export declare function msaCoordToGenomeCoord(args: {
|
|
33
|
+
model: CoordModel;
|
|
34
|
+
coord: number;
|
|
35
|
+
}): GenomeRegion | undefined;
|
|
36
|
+
export {};
|
|
@@ -1,27 +1,56 @@
|
|
|
1
|
+
import { getCodonRanges } from 'g2p_mapper';
|
|
1
2
|
import { gappedToUngappedPosition } from './structureConnection';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The genome regions covered by MSA column `coord` of the query row, in 0-based
|
|
5
|
+
* half-open coordinates (what bpToPx and navTo take).
|
|
6
|
+
*
|
|
7
|
+
* Usually one region -- one codon, or one base in a MAF alignment -- but a
|
|
8
|
+
* codon split across an exon boundary yields one region per contiguous piece,
|
|
9
|
+
* which is why this returns a list.
|
|
10
|
+
*/
|
|
11
|
+
export function msaCoordToGenomeRegions({ model, coord: mouseCol, }) {
|
|
12
|
+
const { querySeqName, transcriptToMsaMap, mafRegion, rows } = model;
|
|
13
|
+
const querySeq = rows.find(f => f[0] === querySeqName)?.[1];
|
|
5
14
|
if (!querySeq) {
|
|
6
|
-
return
|
|
15
|
+
return [];
|
|
7
16
|
}
|
|
8
17
|
const ungappedPos = gappedToUngappedPosition(querySeq, mouseCol);
|
|
9
18
|
if (ungappedPos === undefined) {
|
|
10
|
-
return
|
|
19
|
+
return [];
|
|
11
20
|
}
|
|
12
21
|
if (mafRegion) {
|
|
13
22
|
const genomePos = mafRegion.start + ungappedPos;
|
|
14
23
|
return genomePos < mafRegion.end
|
|
15
|
-
? { refName: mafRegion.refName, start: genomePos, end: genomePos + 1 }
|
|
16
|
-
:
|
|
24
|
+
? [{ refName: mafRegion.refName, start: genomePos, end: genomePos + 1 }]
|
|
25
|
+
: [];
|
|
17
26
|
}
|
|
18
27
|
if (transcriptToMsaMap) {
|
|
19
|
-
const { refName,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
const { refName, p2gCodon } = transcriptToMsaMap;
|
|
29
|
+
// p2gCodon holds every genomic base of the codon, so the range is exact on
|
|
30
|
+
// either strand. Deriving it from consecutive p2g entries instead
|
|
31
|
+
// (p2g[pos]..p2g[pos+1]) was off by one base on the reverse strand -- where
|
|
32
|
+
// p2g stores the codon's *highest* coordinate -- dropped the final residue,
|
|
33
|
+
// whose successor has no p2g entry, and spanned the whole intron for a
|
|
34
|
+
// codon split across an exon boundary.
|
|
35
|
+
return (getCodonRanges(p2gCodon, ungappedPos)?.map(([start, end]) => ({
|
|
36
|
+
refName,
|
|
37
|
+
start,
|
|
38
|
+
end,
|
|
39
|
+
})) ?? []);
|
|
25
40
|
}
|
|
26
|
-
return
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A single region spanning the codon at MSA column `coord`, for navigation. For
|
|
45
|
+
* a codon split across an exon boundary this spans the intervening intron.
|
|
46
|
+
*/
|
|
47
|
+
export function msaCoordToGenomeCoord(args) {
|
|
48
|
+
const regions = msaCoordToGenomeRegions(args);
|
|
49
|
+
const first = regions[0];
|
|
50
|
+
const last = regions.at(-1);
|
|
51
|
+
// getCodonRanges returns ranges sorted ascending, so first.start..last.end
|
|
52
|
+
// bounds the codon
|
|
53
|
+
return first && last
|
|
54
|
+
? { refName: first.refName, start: first.start, end: last.end }
|
|
55
|
+
: undefined;
|
|
27
56
|
}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
+
import { genomeToTranscriptSeqMapping } from 'g2p_mapper';
|
|
1
2
|
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import { msaCoordToGenomeCoord } from './msaCoordToGenomeCoord';
|
|
3
|
+
import { msaCoordToGenomeCoord, msaCoordToGenomeRegions, } from './msaCoordToGenomeCoord';
|
|
4
|
+
// codon at protein position i covers three consecutive genome bases starting at
|
|
5
|
+
// 100 + i * 3, i.e. a single-exon forward-strand transcript
|
|
6
|
+
function forwardCodons(n) {
|
|
7
|
+
return Object.fromEntries(Array.from({ length: n }, (_, i) => [
|
|
8
|
+
i,
|
|
9
|
+
[100 + i * 3, 101 + i * 3, 102 + i * 3],
|
|
10
|
+
]));
|
|
11
|
+
}
|
|
3
12
|
describe('msaCoordToGenomeCoord', () => {
|
|
4
13
|
test('returns undefined when neither transcriptToMsaMap nor mafRegion is defined', () => {
|
|
5
14
|
const model = {
|
|
@@ -16,7 +25,7 @@ describe('msaCoordToGenomeCoord', () => {
|
|
|
16
25
|
querySeqName: 'QUERY',
|
|
17
26
|
transcriptToMsaMap: {
|
|
18
27
|
refName: 'chr1',
|
|
19
|
-
|
|
28
|
+
p2gCodon: forwardCodons(2),
|
|
20
29
|
},
|
|
21
30
|
rows: [['OTHER', 'MKAA']],
|
|
22
31
|
};
|
|
@@ -28,7 +37,7 @@ describe('msaCoordToGenomeCoord', () => {
|
|
|
28
37
|
querySeqName: 'QUERY',
|
|
29
38
|
transcriptToMsaMap: {
|
|
30
39
|
refName: 'chr1',
|
|
31
|
-
|
|
40
|
+
p2gCodon: forwardCodons(2),
|
|
32
41
|
},
|
|
33
42
|
rows: [['QUERY', 'M-KA']],
|
|
34
43
|
};
|
|
@@ -41,7 +50,7 @@ describe('msaCoordToGenomeCoord', () => {
|
|
|
41
50
|
querySeqName: 'QUERY',
|
|
42
51
|
transcriptToMsaMap: {
|
|
43
52
|
refName: 'chr1',
|
|
44
|
-
|
|
53
|
+
p2gCodon: forwardCodons(4),
|
|
45
54
|
},
|
|
46
55
|
rows: [['QUERY', 'MKAA']],
|
|
47
56
|
};
|
|
@@ -58,7 +67,7 @@ describe('msaCoordToGenomeCoord', () => {
|
|
|
58
67
|
querySeqName: 'QUERY',
|
|
59
68
|
transcriptToMsaMap: {
|
|
60
69
|
refName: 'chr1',
|
|
61
|
-
|
|
70
|
+
p2gCodon: forwardCodons(4),
|
|
62
71
|
},
|
|
63
72
|
rows: [['QUERY', 'M-K-AA']],
|
|
64
73
|
// 012345 gapped positions
|
|
@@ -79,34 +88,33 @@ describe('msaCoordToGenomeCoord', () => {
|
|
|
79
88
|
end: 109,
|
|
80
89
|
});
|
|
81
90
|
});
|
|
82
|
-
test('returns undefined when
|
|
91
|
+
test('returns undefined when the position has no codon mapping', () => {
|
|
83
92
|
const model = {
|
|
84
93
|
querySeqName: 'QUERY',
|
|
85
94
|
transcriptToMsaMap: {
|
|
86
95
|
refName: 'chr1',
|
|
87
|
-
|
|
96
|
+
p2gCodon: forwardCodons(1),
|
|
88
97
|
},
|
|
89
98
|
rows: [['QUERY', 'MKAA']],
|
|
90
99
|
};
|
|
91
|
-
//
|
|
92
|
-
const result = msaCoordToGenomeCoord({ model, coord:
|
|
100
|
+
// ungapped position 1 has no entry in p2gCodon
|
|
101
|
+
const result = msaCoordToGenomeCoord({ model, coord: 1 });
|
|
93
102
|
expect(result).toBeUndefined();
|
|
94
103
|
});
|
|
95
|
-
test('
|
|
104
|
+
test('maps the final residue, whose codon has no successor', () => {
|
|
96
105
|
const model = {
|
|
97
106
|
querySeqName: 'QUERY',
|
|
98
107
|
transcriptToMsaMap: {
|
|
99
108
|
refName: 'chr1',
|
|
100
|
-
|
|
109
|
+
p2gCodon: forwardCodons(4),
|
|
101
110
|
},
|
|
102
111
|
rows: [['QUERY', 'MKAA']],
|
|
103
112
|
};
|
|
104
|
-
|
|
105
|
-
const result = msaCoordToGenomeCoord({ model, coord: 0 });
|
|
113
|
+
const result = msaCoordToGenomeCoord({ model, coord: 3 });
|
|
106
114
|
expect(result).toEqual({
|
|
107
115
|
refName: 'chr1',
|
|
108
|
-
start:
|
|
109
|
-
end:
|
|
116
|
+
start: 109,
|
|
117
|
+
end: 112,
|
|
110
118
|
});
|
|
111
119
|
});
|
|
112
120
|
test('returns undefined for out of bounds coord', () => {
|
|
@@ -114,7 +122,7 @@ describe('msaCoordToGenomeCoord', () => {
|
|
|
114
122
|
querySeqName: 'QUERY',
|
|
115
123
|
transcriptToMsaMap: {
|
|
116
124
|
refName: 'chr1',
|
|
117
|
-
|
|
125
|
+
p2gCodon: forwardCodons(2),
|
|
118
126
|
},
|
|
119
127
|
rows: [['QUERY', 'MK']],
|
|
120
128
|
};
|
|
@@ -127,7 +135,7 @@ describe('msaCoordToGenomeCoord', () => {
|
|
|
127
135
|
querySeqName: 'SEQ2',
|
|
128
136
|
transcriptToMsaMap: {
|
|
129
137
|
refName: 'chr1',
|
|
130
|
-
|
|
138
|
+
p2gCodon: { 0: [200, 201, 202], 1: [203, 204, 205] },
|
|
131
139
|
},
|
|
132
140
|
rows: [
|
|
133
141
|
['SEQ1', 'AAAA'],
|
|
@@ -142,6 +150,88 @@ describe('msaCoordToGenomeCoord', () => {
|
|
|
142
150
|
end: 203,
|
|
143
151
|
});
|
|
144
152
|
});
|
|
153
|
+
// The mapping comes from the real g2p_mapper rather than hand-written
|
|
154
|
+
// fixtures: on the reverse strand p2g stores the codon's *highest*
|
|
155
|
+
// coordinate, which is what the old p2g[pos]..p2g[pos+1] arithmetic got wrong
|
|
156
|
+
describe('real g2p_mapper mappings', () => {
|
|
157
|
+
test('forward strand, single exon', () => {
|
|
158
|
+
const { p2gCodon, refName } = genomeToTranscriptSeqMapping({
|
|
159
|
+
refName: 'chr1',
|
|
160
|
+
start: 100,
|
|
161
|
+
end: 112,
|
|
162
|
+
strand: 1,
|
|
163
|
+
subfeatures: [{ refName: 'chr1', type: 'CDS', start: 100, end: 112 }],
|
|
164
|
+
});
|
|
165
|
+
const model = {
|
|
166
|
+
querySeqName: 'QUERY',
|
|
167
|
+
transcriptToMsaMap: { refName, p2gCodon },
|
|
168
|
+
rows: [['QUERY', 'MKAA']],
|
|
169
|
+
};
|
|
170
|
+
expect(msaCoordToGenomeCoord({ model, coord: 0 })).toEqual({
|
|
171
|
+
refName: 'chr1',
|
|
172
|
+
start: 100,
|
|
173
|
+
end: 103,
|
|
174
|
+
});
|
|
175
|
+
expect(msaCoordToGenomeCoord({ model, coord: 3 })).toEqual({
|
|
176
|
+
refName: 'chr1',
|
|
177
|
+
start: 109,
|
|
178
|
+
end: 112,
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
test('reverse strand codon covers the last three bases of the CDS', () => {
|
|
182
|
+
const { p2gCodon, refName } = genomeToTranscriptSeqMapping({
|
|
183
|
+
refName: 'chr1',
|
|
184
|
+
start: 100,
|
|
185
|
+
end: 112,
|
|
186
|
+
strand: -1,
|
|
187
|
+
subfeatures: [{ refName: 'chr1', type: 'CDS', start: 100, end: 112 }],
|
|
188
|
+
});
|
|
189
|
+
const model = {
|
|
190
|
+
querySeqName: 'QUERY',
|
|
191
|
+
transcriptToMsaMap: { refName, p2gCodon },
|
|
192
|
+
rows: [['QUERY', 'MKAA']],
|
|
193
|
+
};
|
|
194
|
+
// the first residue is translated from the 3' end of the genome region
|
|
195
|
+
expect(msaCoordToGenomeCoord({ model, coord: 0 })).toEqual({
|
|
196
|
+
refName: 'chr1',
|
|
197
|
+
start: 109,
|
|
198
|
+
end: 112,
|
|
199
|
+
});
|
|
200
|
+
expect(msaCoordToGenomeCoord({ model, coord: 3 })).toEqual({
|
|
201
|
+
refName: 'chr1',
|
|
202
|
+
start: 100,
|
|
203
|
+
end: 103,
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
test('codon split across an exon boundary yields one region per piece', () => {
|
|
207
|
+
// exon 1 contributes 4 bases, so residue 1 straddles the intron
|
|
208
|
+
const { p2gCodon, refName } = genomeToTranscriptSeqMapping({
|
|
209
|
+
refName: 'chr1',
|
|
210
|
+
start: 100,
|
|
211
|
+
end: 210,
|
|
212
|
+
strand: 1,
|
|
213
|
+
subfeatures: [
|
|
214
|
+
{ refName: 'chr1', type: 'CDS', start: 100, end: 104 },
|
|
215
|
+
{ refName: 'chr1', type: 'CDS', start: 200, end: 202 },
|
|
216
|
+
],
|
|
217
|
+
});
|
|
218
|
+
const model = {
|
|
219
|
+
querySeqName: 'QUERY',
|
|
220
|
+
transcriptToMsaMap: { refName, p2gCodon },
|
|
221
|
+
rows: [['QUERY', 'MK']],
|
|
222
|
+
};
|
|
223
|
+
expect(msaCoordToGenomeRegions({ model, coord: 1 })).toEqual([
|
|
224
|
+
{ refName: 'chr1', start: 103, end: 104 },
|
|
225
|
+
{ refName: 'chr1', start: 200, end: 202 },
|
|
226
|
+
]);
|
|
227
|
+
// the single-region form bounds the pieces, for navigation
|
|
228
|
+
expect(msaCoordToGenomeCoord({ model, coord: 1 })).toEqual({
|
|
229
|
+
refName: 'chr1',
|
|
230
|
+
start: 103,
|
|
231
|
+
end: 202,
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
});
|
|
145
235
|
// MAF region tests
|
|
146
236
|
describe('mafRegion', () => {
|
|
147
237
|
test('returns genome position for mafRegion mapping', () => {
|
|
@@ -217,7 +307,7 @@ describe('msaCoordToGenomeCoord', () => {
|
|
|
217
307
|
querySeqName: 'hg38.chr1',
|
|
218
308
|
transcriptToMsaMap: {
|
|
219
309
|
refName: 'chr2',
|
|
220
|
-
|
|
310
|
+
p2gCodon: { 0: [5000, 5001, 5002], 1: [5003, 5004, 5005] },
|
|
221
311
|
},
|
|
222
312
|
mafRegion: {
|
|
223
313
|
refName: 'chr1',
|