react-msaview 5.4.0 → 5.4.1
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/bundle/index.js +22 -22
- package/bundle/index.js.LICENSE.txt +1 -1
- package/bundle/index.js.map +1 -1
- package/dist/components/Checkbox2.js +3 -1
- package/dist/components/Checkbox2.js.map +1 -1
- package/dist/components/MSAViewer.js +1 -3
- package/dist/components/MSAViewer.js.map +1 -1
- package/dist/components/dialogs/InterProScanDialog.js +2 -1
- package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
- package/dist/components/msa/renderMSABlock.js +4 -6
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/tracks/renderTracksSvg.js +1 -1
- package/dist/components/tracks/renderTracksSvg.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.js +3 -0
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/hierarchy.js +4 -1
- package/dist/hierarchy.js.map +1 -1
- package/dist/model/msaModel.js.map +1 -1
- package/dist/model.d.ts +4 -2
- package/dist/model.js +30 -16
- package/dist/model.js.map +1 -1
- package/dist/neighborJoining.js +44 -30
- package/dist/neighborJoining.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -5
- package/src/components/Checkbox2.tsx +7 -1
- package/src/components/MSAViewer.tsx +1 -3
- package/src/components/dialogs/InterProScanDialog.tsx +2 -1
- package/src/components/msa/renderMSABlock.ts +2 -8
- package/src/components/tracks/renderTracksSvg.ts +1 -1
- package/src/components/tree/renderTreeCanvas.ts +5 -1
- package/src/hierarchy.ts +4 -1
- package/src/model/msaModel.ts +3 -1
- package/src/model.ts +32 -34
- package/src/neighborJoining.ts +44 -31
- package/src/version.ts +1 -1
package/src/model.ts
CHANGED
|
@@ -249,6 +249,15 @@ function stateModelFactory() {
|
|
|
249
249
|
* #property
|
|
250
250
|
*/
|
|
251
251
|
relativeTo: types.maybe(types.string),
|
|
252
|
+
/**
|
|
253
|
+
* #property
|
|
254
|
+
* declarative seed for the highlighted-columns overlay (visible column
|
|
255
|
+
* indices). Unlike the volatile `highlightedColumns` (driven by
|
|
256
|
+
* transient genome-hover sync), this persists in the snapshot/URL so a
|
|
257
|
+
* shared link can open with specific columns highlighted. Applied once
|
|
258
|
+
* in afterCreate.
|
|
259
|
+
*/
|
|
260
|
+
highlightColumns: types.frozen<number[] | undefined>(),
|
|
252
261
|
}),
|
|
253
262
|
)
|
|
254
263
|
.volatile(() => ({
|
|
@@ -944,7 +953,10 @@ function stateModelFactory() {
|
|
|
944
953
|
get colConsensus() {
|
|
945
954
|
const { colStats, colStatsSums } = this
|
|
946
955
|
return colStats.map((stats, i) => {
|
|
947
|
-
const total = colStatsSums[i]
|
|
956
|
+
const total = colStatsSums[i]
|
|
957
|
+
if (!total) {
|
|
958
|
+
return { letter: '', color: undefined }
|
|
959
|
+
}
|
|
948
960
|
let maxCount = 0
|
|
949
961
|
let letter = ''
|
|
950
962
|
for (const [key, val] of Object.entries(stats)) {
|
|
@@ -1259,12 +1271,8 @@ function stateModelFactory() {
|
|
|
1259
1271
|
*/
|
|
1260
1272
|
zoomIn() {
|
|
1261
1273
|
transaction(() => {
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
maxCellSize,
|
|
1265
|
-
Math.ceil(self.rowHeight * 1.5),
|
|
1266
|
-
)
|
|
1267
|
-
self.scrollX = clamp(self.scrollX, self.maxScrollX, 0)
|
|
1274
|
+
this.zoomInHorizontal()
|
|
1275
|
+
this.zoomInVertical()
|
|
1268
1276
|
})
|
|
1269
1277
|
},
|
|
1270
1278
|
/**
|
|
@@ -1272,15 +1280,8 @@ function stateModelFactory() {
|
|
|
1272
1280
|
*/
|
|
1273
1281
|
zoomOut() {
|
|
1274
1282
|
transaction(() => {
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
Math.floor(self.colWidth * 0.75),
|
|
1278
|
-
)
|
|
1279
|
-
self.rowHeight = Math.max(
|
|
1280
|
-
minRowHeight,
|
|
1281
|
-
Math.floor(self.rowHeight * 0.75),
|
|
1282
|
-
)
|
|
1283
|
-
self.scrollX = clamp(self.scrollX, self.maxScrollX, 0)
|
|
1283
|
+
this.zoomOutHorizontal()
|
|
1284
|
+
this.zoomOutVertical()
|
|
1284
1285
|
})
|
|
1285
1286
|
},
|
|
1286
1287
|
/**
|
|
@@ -1314,9 +1315,13 @@ function stateModelFactory() {
|
|
|
1314
1315
|
)
|
|
1315
1316
|
|
|
1316
1317
|
const anchoredScrollY = offsetY - rowInView * self.rowHeight
|
|
1317
|
-
|
|
1318
|
+
// maxScrollY is -(totalHeight - visibleMsaHeight) when the alignment
|
|
1319
|
+
// overflows, so -maxScrollY is exactly that overflow past the
|
|
1320
|
+
// scrollable MSA viewport (0 when it fits)
|
|
1321
|
+
const overflow = Math.max(0, -self.maxScrollY)
|
|
1322
|
+
const visibleHeight = self.totalHeight - overflow
|
|
1318
1323
|
const topBias =
|
|
1319
|
-
|
|
1324
|
+
visibleHeight > 0 ? clamp(1 - overflow / visibleHeight, 0, 1) : 1
|
|
1320
1325
|
self.scrollY = clamp(
|
|
1321
1326
|
anchoredScrollY * (1 - topBias),
|
|
1322
1327
|
self.maxScrollY,
|
|
@@ -1703,22 +1708,8 @@ function stateModelFactory() {
|
|
|
1703
1708
|
* #action
|
|
1704
1709
|
*/
|
|
1705
1710
|
fit() {
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
self.msaAreaHeight / self.numRows,
|
|
1709
|
-
minRowHeight,
|
|
1710
|
-
maxCellSize,
|
|
1711
|
-
)
|
|
1712
|
-
}
|
|
1713
|
-
if (self.numColumns > 0) {
|
|
1714
|
-
self.colWidth = clamp(
|
|
1715
|
-
self.msaAreaWidth / self.numColumns,
|
|
1716
|
-
minColWidth,
|
|
1717
|
-
maxCellSize,
|
|
1718
|
-
)
|
|
1719
|
-
}
|
|
1720
|
-
self.scrollX = 0
|
|
1721
|
-
self.scrollY = 0
|
|
1711
|
+
this.fitVertically()
|
|
1712
|
+
this.fitHorizontally()
|
|
1722
1713
|
},
|
|
1723
1714
|
/**
|
|
1724
1715
|
* #action
|
|
@@ -1748,6 +1739,13 @@ function stateModelFactory() {
|
|
|
1748
1739
|
},
|
|
1749
1740
|
|
|
1750
1741
|
afterCreate() {
|
|
1742
|
+
// seed the highlighted-columns overlay from the declarative property so
|
|
1743
|
+
// a shared snapshot/URL opens with those columns highlighted (the
|
|
1744
|
+
// volatile highlightedColumns can later be driven by genome-hover sync)
|
|
1745
|
+
if (self.highlightColumns?.length) {
|
|
1746
|
+
self.setHighlightedColumns(self.highlightColumns)
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1751
1749
|
addDisposer(
|
|
1752
1750
|
self,
|
|
1753
1751
|
autorun(() => {
|
package/src/neighborJoining.ts
CHANGED
|
@@ -194,16 +194,10 @@ function neighborJoining(distances: number[][], names: string[]): NJNode {
|
|
|
194
194
|
const ri = r.get(minI)!
|
|
195
195
|
const rj = r.get(minJ)!
|
|
196
196
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
limbI = dij / 2 + (ri - rj) / (2 * (remaining - 2))
|
|
202
|
-
limbJ = dij - limbI
|
|
203
|
-
} else {
|
|
204
|
-
limbI = dij / 2
|
|
205
|
-
limbJ = dij / 2
|
|
206
|
-
}
|
|
197
|
+
// remaining is always > 2 inside this loop; the final two nodes are
|
|
198
|
+
// connected after it
|
|
199
|
+
let limbI = dij / 2 + (ri - rj) / (2 * (remaining - 2))
|
|
200
|
+
let limbJ = dij - limbI
|
|
207
201
|
|
|
208
202
|
// Ensure non-negative branch lengths
|
|
209
203
|
limbI = Math.max(0, limbI)
|
|
@@ -217,19 +211,18 @@ function neighborJoining(distances: number[][], names: string[]): NJNode {
|
|
|
217
211
|
rightLength: limbJ,
|
|
218
212
|
}
|
|
219
213
|
|
|
220
|
-
// Update distance matrix
|
|
221
|
-
const newIdx = minI
|
|
214
|
+
// Update distance matrix, reusing minI's slot for the merged node
|
|
222
215
|
for (const k of active) {
|
|
223
216
|
if (k !== minI && k !== minJ) {
|
|
224
217
|
const newDist = (D[minI]![k]! + D[minJ]![k]! - dij) / 2
|
|
225
|
-
D[
|
|
226
|
-
D[k]![
|
|
218
|
+
D[minI]![k] = Math.max(0, newDist)
|
|
219
|
+
D[k]![minI] = Math.max(0, newDist)
|
|
227
220
|
}
|
|
228
221
|
}
|
|
229
222
|
|
|
230
223
|
// Mark minJ as removed
|
|
231
224
|
nodes[minJ] = undefined
|
|
232
|
-
nodes[
|
|
225
|
+
nodes[minI] = newNode
|
|
233
226
|
|
|
234
227
|
remaining--
|
|
235
228
|
}
|
|
@@ -257,25 +250,45 @@ function neighborJoining(distances: number[][], names: string[]): NJNode {
|
|
|
257
250
|
return nodes[finalActive[0]!]!
|
|
258
251
|
}
|
|
259
252
|
|
|
260
|
-
function
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
result = `'${quotedName}'`
|
|
266
|
-
} else {
|
|
267
|
-
const leftNewick = node.left ? nodeToNewick(node.left, node.leftLength) : ''
|
|
268
|
-
const rightNewick = node.right
|
|
269
|
-
? nodeToNewick(node.right, node.rightLength)
|
|
270
|
-
: ''
|
|
271
|
-
result = `(${leftNewick},${rightNewick})`
|
|
272
|
-
}
|
|
253
|
+
function withBranchLength(newick: string, branchLength?: number) {
|
|
254
|
+
return branchLength === undefined
|
|
255
|
+
? newick
|
|
256
|
+
: `${newick}:${branchLength.toFixed(6)}`
|
|
257
|
+
}
|
|
273
258
|
|
|
274
|
-
|
|
275
|
-
|
|
259
|
+
// Emit Newick iteratively rather than recursively: an NJ tree of N leaves can
|
|
260
|
+
// be a caterpillar of depth ~N, so recursion risks a stack overflow on large
|
|
261
|
+
// alignments (matching the iterative-traversal convention in hierarchy.ts).
|
|
262
|
+
function nodeToNewick(root: NJNode): string {
|
|
263
|
+
const postOrder: NJNode[] = []
|
|
264
|
+
const stack: NJNode[] = [root]
|
|
265
|
+
while (stack.length > 0) {
|
|
266
|
+
const node = stack.pop()!
|
|
267
|
+
postOrder.push(node)
|
|
268
|
+
if (node.left) {
|
|
269
|
+
stack.push(node.left)
|
|
270
|
+
}
|
|
271
|
+
if (node.right) {
|
|
272
|
+
stack.push(node.right)
|
|
273
|
+
}
|
|
276
274
|
}
|
|
277
275
|
|
|
278
|
-
|
|
276
|
+
const newickByNode = new Map<NJNode, string>()
|
|
277
|
+
for (let i = postOrder.length - 1; i >= 0; i--) {
|
|
278
|
+
const node = postOrder[i]!
|
|
279
|
+
if (node.name !== undefined && !node.left && !node.right) {
|
|
280
|
+
newickByNode.set(node, `'${node.name.replaceAll("'", "''")}'`)
|
|
281
|
+
} else {
|
|
282
|
+
const left = node.left
|
|
283
|
+
? withBranchLength(newickByNode.get(node.left)!, node.leftLength)
|
|
284
|
+
: ''
|
|
285
|
+
const right = node.right
|
|
286
|
+
? withBranchLength(newickByNode.get(node.right)!, node.rightLength)
|
|
287
|
+
: ''
|
|
288
|
+
newickByNode.set(node, `(${left},${right})`)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return newickByNode.get(root)!
|
|
279
292
|
}
|
|
280
293
|
|
|
281
294
|
export function calculateNeighborJoiningTree(
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '5.4.
|
|
1
|
+
export const version = '5.4.1'
|