jbrowse-plugin-msaview 2.7.2 → 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.
Files changed (44) hide show
  1. package/dist/AddHighlightModel/MsaToGenomeHighlight.js +6 -5
  2. package/dist/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.js +1 -1
  3. package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.d.ts +1 -1
  4. package/dist/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.js +5 -2
  5. package/dist/MsaViewPanel/doLaunchBlast.js +10 -22
  6. package/dist/MsaViewPanel/genomeToMSA.js +13 -6
  7. package/dist/MsaViewPanel/genomeToMSA.test.js +35 -6
  8. package/dist/MsaViewPanel/model.d.ts +68 -66
  9. package/dist/MsaViewPanel/model.js +14 -12
  10. package/dist/MsaViewPanel/msaCoordToGenomeCoord.d.ts +32 -13
  11. package/dist/MsaViewPanel/msaCoordToGenomeCoord.js +43 -14
  12. package/dist/MsaViewPanel/msaCoordToGenomeCoord.test.js +108 -18
  13. package/dist/MsaViewPanel/msaDataStore.js +8 -17
  14. package/dist/MsaViewPanel/syncGenomeHoverToMsaColumn.test.js +8 -6
  15. package/dist/jbrowse-plugin-msaview.umd.production.min.js +31 -31
  16. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
  17. package/dist/utils/blastCache.d.ts +1 -2
  18. package/dist/utils/blastCache.js +9 -22
  19. package/dist/utils/domainCache.js +6 -15
  20. package/dist/utils/idb.d.ts +12 -0
  21. package/dist/utils/idb.js +21 -0
  22. package/dist/utils/taxonomyNames.js +13 -18
  23. package/dist/version.d.ts +1 -1
  24. package/dist/version.js +1 -1
  25. package/package.json +2 -2
  26. package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +6 -8
  27. package/src/LaunchMsaView/components/NCBIBlastQuery/CachedBlastResults.tsx +1 -1
  28. package/src/LaunchMsaView/components/NCBIBlastQuery/useCachedBlastResults.ts +4 -2
  29. package/src/MsaViewPanel/doLaunchBlast.ts +20 -29
  30. package/src/MsaViewPanel/genomeToMSA.test.ts +38 -6
  31. package/src/MsaViewPanel/genomeToMSA.ts +14 -6
  32. package/src/MsaViewPanel/model.ts +17 -12
  33. package/src/MsaViewPanel/msaCoordToGenomeCoord.test.ts +117 -18
  34. package/src/MsaViewPanel/msaCoordToGenomeCoord.ts +70 -26
  35. package/src/MsaViewPanel/msaDataStore.ts +17 -17
  36. package/src/MsaViewPanel/syncGenomeHoverToMsaColumn.test.ts +8 -6
  37. package/src/utils/blastCache.ts +20 -23
  38. package/src/utils/domainCache.ts +14 -18
  39. package/src/utils/idb.ts +28 -0
  40. package/src/utils/taxonomyNames.ts +22 -24
  41. package/src/version.ts +1 -1
  42. package/dist/MsaViewPanel/blosum62.d.ts +0 -2
  43. package/dist/MsaViewPanel/blosum62.js +0 -627
  44. package/src/MsaViewPanel/blosum62.ts +0 -628
@@ -11,11 +11,12 @@ const MsaToGenomeHighlight = observer(function MsaToGenomeHighlight2({ model, })
11
11
  // The persistent click selection always shows. The hover codon is suppressed
12
12
  // while hovering the LGV — GenomeMouseoverHighlight handles the single-bp
13
13
  // display in that case, so we don't stack a wider codon band on top of it.
14
- const clickHighlight = msaView?.connectedClickHighlight;
15
- const hoverHighlight = hasHoverPosition(hovered)
16
- ? undefined
17
- : msaView?.connectedHoverHighlight;
18
- const highlights = [clickHighlight, hoverHighlight].filter((r) => r !== undefined);
14
+ const highlights = [
15
+ ...(msaView?.connectedClickHighlights ?? []),
16
+ ...(hasHoverPosition(hovered)
17
+ ? []
18
+ : (msaView?.connectedHoverHighlights ?? [])),
19
+ ];
19
20
  return highlights.length ? (React.createElement(MsaToGenomeHighlightRenderer, { model: model, highlights: highlights })) : null;
20
21
  });
21
22
  // Inner component: handles the scroll-dependent rendering
@@ -68,7 +68,7 @@ const CachedBlastResults = observer(function ({ model, handleClose, feature, })
68
68
  catch (e) {
69
69
  setOperationError(e);
70
70
  }
71
- } }, "Clear All")),
71
+ } }, "Clear results for this gene")),
72
72
  React.createElement(List, { dense: true, className: classes.resultList }, results.map(result => (React.createElement(ListItem, { key: result.id, disablePadding: true, secondaryAction: React.createElement(IconButton, { edge: "end", size: "small", onClick: async (e) => {
73
73
  e.stopPropagation();
74
74
  try {
@@ -1,5 +1,5 @@
1
1
  export declare function useCachedBlastResults(geneIds: string[]): {
2
- results: any[];
2
+ results: import("../../../utils/blastCache").CachedBlastResult[];
3
3
  error: any;
4
4
  isLoading: boolean;
5
5
  handleDelete: (id: string) => Promise<void>;
@@ -1,5 +1,5 @@
1
1
  import useSWR from 'swr';
2
- import { clearAllCachedResults, deleteCachedResult, getAllCachedResults, } from '../../../utils/blastCache';
2
+ import { deleteCachedResult, getAllCachedResults, } from '../../../utils/blastCache';
3
3
  import { staticSwrConfig } from '../../../utils/swrConfig';
4
4
  export function useCachedBlastResults(geneIds) {
5
5
  const { data: results, error, isLoading, mutate, } = useSWR(`cached-blast-${geneIds.join(',')}`, async () => {
@@ -10,8 +10,11 @@ export function useCachedBlastResults(geneIds) {
10
10
  await deleteCachedResult(id);
11
11
  await mutate(results => results?.filter(result => result.id !== id) ?? [], false);
12
12
  };
13
+ // deletes only what this hook listed, i.e. the results for these gene ids.
14
+ // The list the user is looking at is gene-scoped, so a store-wide clear here
15
+ // would silently throw away every other gene's cached alignments too
13
16
  const handleClearAll = async () => {
14
- await clearAllCachedResults();
17
+ await Promise.all((results ?? []).map(r => deleteCachedResult(r.id)));
15
18
  await mutate([], false);
16
19
  };
17
20
  return {
@@ -7,36 +7,26 @@ import { fetchTaxonomyInfo } from '../utils/taxonomyNames';
7
7
  export async function doLaunchBlast({ self, }) {
8
8
  const { baseUrl, blastDatabase, blastProgram, msaAlgorithm, proteinSequence, selectedTranscript, rid: existingRid, } = self.blastParams;
9
9
  const cleanedSeq = cleanProteinSequence(proteinSequence);
10
- let hits;
11
- let rid;
10
+ const onProgress = (arg) => {
11
+ self.setProgress(arg);
12
+ };
12
13
  if (existingRid) {
14
+ // publish it before the first poll so the view can link out to NCBI while
15
+ // the job is still running
13
16
  self.setRid(existingRid);
14
- const result = await queryBlastFromRid({
15
- rid: existingRid,
16
- baseUrl,
17
- onProgress: arg => {
18
- self.setProgress(arg);
19
- },
20
- });
21
- hits = result.hits;
22
- rid = result.rid;
23
17
  }
24
- else {
25
- const result = await queryBlast({
18
+ const { hits, rid } = existingRid
19
+ ? await queryBlastFromRid({ rid: existingRid, baseUrl, onProgress })
20
+ : await queryBlast({
26
21
  query: cleanedSeq,
27
22
  blastDatabase,
28
23
  blastProgram,
29
24
  baseUrl,
30
- onProgress: arg => {
31
- self.setProgress(arg);
32
- },
25
+ onProgress,
33
26
  onRid: r => {
34
27
  self.setRid(r);
35
28
  },
36
29
  });
37
- hits = result.hits;
38
- rid = result.rid;
39
- }
40
30
  self.setProgress('Fetching species taxonomy info...');
41
31
  const taxids = hits
42
32
  .map(h => h.description[0]?.taxid)
@@ -57,9 +47,7 @@ export async function doLaunchBlast({ self, }) {
57
47
  const result = await launchMSA({
58
48
  algorithm: msaAlgorithm,
59
49
  sequence: [`>QUERY\n${cleanedSeq}`, ...sequences].join('\n'),
60
- onProgress: arg => {
61
- self.setProgress(arg);
62
- },
50
+ onProgress,
63
51
  });
64
52
  const treeMetadataJson = JSON.stringify(treeMetadata);
65
53
  await saveBlastResult({
@@ -6,18 +6,25 @@ export function genomeToMSA({ model }) {
6
6
  if (!connectedView?.initialized || !hasHoverPosition(hovered)) {
7
7
  return undefined;
8
8
  }
9
- const { coord: hoverCoord, refName } = hovered.hoverPosition;
9
+ const { coord, refName } = hovered.hoverPosition;
10
+ // hoverPosition.coord is a 1-based display coordinate (core's pxToBp adds the
11
+ // +1), while g2p and mafRegion are keyed by 0-based genome position
12
+ const genomePos = coord - 1;
10
13
  if (mafRegion) {
11
14
  if (refName !== mafRegion.refName ||
12
15
  !connectedView.assemblyNames.includes(mafRegion.assemblyName) ||
13
- hoverCoord < mafRegion.start ||
14
- hoverCoord >= mafRegion.end) {
16
+ genomePos < mafRegion.start ||
17
+ genomePos >= mafRegion.end) {
15
18
  return undefined;
16
19
  }
17
- return model.seqPosToVisibleCol(querySeqName, hoverCoord - mafRegion.start);
20
+ return model.seqPosToVisibleCol(querySeqName, genomePos - mafRegion.start);
18
21
  }
19
- if (transcriptToMsaMap) {
20
- const seqPos = transcriptToMsaMap.g2p[hoverCoord];
22
+ // session.hovered is global -- set by whichever LinearGenomeView the cursor
23
+ // was last over, on any assembly -- so the refName gate is load bearing:
24
+ // without it the same numeric coordinate on an unrelated chromosome matches a
25
+ // g2p key and lights up a column for a different locus
26
+ if (refName === transcriptToMsaMap?.refName) {
27
+ const seqPos = transcriptToMsaMap.g2p[genomePos];
21
28
  if (seqPos !== undefined) {
22
29
  return model.seqPosToVisibleCol(querySeqName, seqPos);
23
30
  }
@@ -76,8 +76,9 @@ describe('genomeToMSA', () => {
76
76
  seqPosToVisibleCol: mockSeqPosToVisibleCol,
77
77
  };
78
78
  const result = genomeToMSA({ model });
79
- // coord 1005 - start 1000 = ungapped position 5
80
- expect(mockSeqPosToVisibleCol).toHaveBeenCalledWith('hg38.chr1', 5);
79
+ // hover coord 1005 is 1-based, so the 0-based genome position is 1004,
80
+ // which is ungapped position 4 of a region starting at 1000
81
+ expect(mockSeqPosToVisibleCol).toHaveBeenCalledWith('hg38.chr1', 4);
81
82
  expect(result).toBe(5);
82
83
  });
83
84
  test('returns undefined when hover refName does not match mafRegion', () => {
@@ -106,10 +107,11 @@ describe('genomeToMSA', () => {
106
107
  expect(result).toBeUndefined();
107
108
  });
108
109
  test('returns undefined when hover coord is before mafRegion start', () => {
110
+ // 1-based coord 1000 is the 0-based base 999, one before the region
109
111
  mockGetSession.mockReturnValue({
110
112
  hovered: {
111
113
  hoverFeature: {},
112
- hoverPosition: { coord: 999, refName: 'chr1' },
114
+ hoverPosition: { coord: 1000, refName: 'chr1' },
113
115
  },
114
116
  });
115
117
  const model = {
@@ -131,10 +133,11 @@ describe('genomeToMSA', () => {
131
133
  expect(result).toBeUndefined();
132
134
  });
133
135
  test('returns undefined when hover coord is at or after mafRegion end', () => {
136
+ // 1-based coord 1011 is the 0-based base 1010, one past the region
134
137
  mockGetSession.mockReturnValue({
135
138
  hovered: {
136
139
  hoverFeature: {},
137
- hoverPosition: { coord: 1010, refName: 'chr1' },
140
+ hoverPosition: { coord: 1011, refName: 'chr1' },
138
141
  },
139
142
  });
140
143
  const model = {
@@ -193,7 +196,9 @@ describe('genomeToMSA', () => {
193
196
  const model = {
194
197
  querySeqName: 'QUERY',
195
198
  transcriptToMsaMap: {
196
- g2p: { 1005: 10 },
199
+ refName: 'chr1',
200
+ // g2p is keyed by 0-based genome position, the hover coord is 1-based
201
+ g2p: { 1004: 10 },
197
202
  },
198
203
  mafRegion: undefined,
199
204
  connectedView: { initialized: true },
@@ -203,6 +208,29 @@ describe('genomeToMSA', () => {
203
208
  expect(mockSeqPosToVisibleCol).toHaveBeenCalledWith('QUERY', 10);
204
209
  expect(result).toBe(10);
205
210
  });
211
+ test('returns undefined when the hover is on another refName', () => {
212
+ // session.hovered is global, so a hover on an unrelated chromosome can
213
+ // carry a coordinate that happens to be a g2p key
214
+ mockGetSession.mockReturnValue({
215
+ hovered: {
216
+ hoverFeature: {},
217
+ hoverPosition: { coord: 1005, refName: 'chr2' },
218
+ },
219
+ });
220
+ const mockSeqPosToVisibleCol = vi.fn();
221
+ const model = {
222
+ querySeqName: 'QUERY',
223
+ transcriptToMsaMap: {
224
+ refName: 'chr1',
225
+ g2p: { 1004: 10 },
226
+ },
227
+ mafRegion: undefined,
228
+ connectedView: { initialized: true },
229
+ seqPosToVisibleCol: mockSeqPosToVisibleCol,
230
+ };
231
+ expect(genomeToMSA({ model })).toBeUndefined();
232
+ expect(mockSeqPosToVisibleCol).not.toHaveBeenCalled();
233
+ });
206
234
  test('returns undefined when g2p has no mapping for coord', () => {
207
235
  mockGetSession.mockReturnValue({
208
236
  hovered: {
@@ -213,7 +241,8 @@ describe('genomeToMSA', () => {
213
241
  const model = {
214
242
  querySeqName: 'QUERY',
215
243
  transcriptToMsaMap: {
216
- g2p: { 1000: 0 }, // No entry for 1005
244
+ refName: 'chr1',
245
+ g2p: { 1000: 0 }, // No entry for 1004
217
246
  },
218
247
  mafRegion: undefined,
219
248
  connectedView: { initialized: true },
@@ -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" | "drawLabels" | "labelsAlignRight" | "treeAreaWidth" | "treeWidth" | "showBranchLen" | "drawTree" | "drawNodeBubbles" | "autoTreeAreaWidth" | "bgColor" | "colorSchemeName" | "showColumnStats" | "msaFormat" | "data" | "showDomains" | "hideGaps" | "allowedGappyness" | "subFeatureRows" | "drawMsaLetters" | "scrollZoom" | "rowHeight" | "scrollY" | "scrollX" | "colWidth" | "treeFilehandle" | "msaFilehandle" | "treeMetadataFilehandle" | "gffFilehandle" | "currentAlignment" | "collapsed" | "showOnly" | "turnedOffTracks" | "featureFilters" | "relativeTo" | "highlightColumns"> & Omit<Omit<Omit<{}, "drawLabels" | "labelsAlignRight" | "treeAreaWidth" | "treeWidth" | "showBranchLen" | "drawTree" | "drawNodeBubbles" | "autoTreeAreaWidth"> & {
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" | "showColumnStats" | "msaFormat"> & {
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" | "data" | "showDomains" | "hideGaps" | "allowedGappyness" | "subFeatureRows" | "drawMsaLetters" | "scrollZoom" | "rowHeight" | "scrollY" | "scrollX" | "colWidth" | "treeFilehandle" | "msaFilehandle" | "treeMetadataFilehandle" | "gffFilehandle" | "currentAlignment" | "collapsed" | "showOnly" | "turnedOffTracks" | "featureFilters" | "relativeTo" | "highlightColumns"> & {
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: any;
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: any;
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 region under the current MSA hover column. Suppressed on the LGV
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 connectedHoverHighlight: IRegion | undefined;
848
+ readonly connectedHoverHighlights: IRegion[];
849
849
  /**
850
850
  * #getter
851
- * Genome region under the persistent MSA click selection. Shown
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 connectedClickHighlight: IRegion | undefined;
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
- data: {
939
- treeMetadata?: string | undefined;
940
- msa?: string | undefined;
941
- tree?: string | undefined;
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 region under the current MSA hover column. Suppressed on the LGV
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 connectedHoverHighlight() {
126
+ get connectedHoverHighlights() {
127
127
  const { mouseCol } = self;
128
128
  return mouseCol === undefined
129
- ? undefined
130
- : msaCoordToGenomeCoord({ model: self, coord: mouseCol });
129
+ ? []
130
+ : msaCoordToGenomeRegions({ model: self, coord: mouseCol });
131
131
  },
132
132
  /**
133
133
  * #getter
134
- * Genome region under the persistent MSA click selection. Shown
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 connectedClickHighlight() {
137
+ get connectedClickHighlights() {
138
138
  const { mouseClickCol } = self;
139
139
  return mouseClickCol === undefined
140
- ? undefined
141
- : msaCoordToGenomeCoord({ model: self, coord: mouseClickCol });
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.connectedHoverHighlight,
149
- this.connectedClickHighlight,
150
- ].filter((r) => r !== undefined);
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
- export declare function msaCoordToGenomeCoord({ model, coord: mouseCol, }: {
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
- } | undefined;
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 {};