@jbrowse/bandage-core 9.4.0 → 9.6.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.
@@ -3,7 +3,7 @@ import {
3
3
  WHOLE_FRACTION,
4
4
  bubbleHalos,
5
5
  coversGraph
6
- } from "../chunks/chunk-REM73HCU.js";
6
+ } from "../chunks/chunk-EHUBJDDB.js";
7
7
  import "../chunks/chunk-XKWD2RY3.js";
8
8
  import "../chunks/chunk-FX4RDMDN.js";
9
9
  import "../chunks/chunk-2CVHXFK7.js";
@@ -2,7 +2,7 @@ import {
2
2
  bubblesFromGraph,
3
3
  walkIndexOf,
4
4
  walkRoutes
5
- } from "../chunks/chunk-GOZYKNQ2.js";
5
+ } from "../chunks/chunk-CLOP7UVD.js";
6
6
  import "../chunks/chunk-FX4RDMDN.js";
7
7
  import "../chunks/chunk-HNQPEMYE.js";
8
8
  import "../chunks/chunk-CPMHA4W5.js";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  graphBubbles,
3
3
  superbubblesFromGraph
4
- } from "../chunks/chunk-TF7H5LQS.js";
4
+ } from "../chunks/chunk-C55SC5AJ.js";
5
5
  import "../chunks/chunk-VHW7FDHU.js";
6
- import "../chunks/chunk-REM73HCU.js";
6
+ import "../chunks/chunk-EHUBJDDB.js";
7
7
  import "../chunks/chunk-XKWD2RY3.js";
8
- import "../chunks/chunk-GOZYKNQ2.js";
8
+ import "../chunks/chunk-CLOP7UVD.js";
9
9
  import "../chunks/chunk-FX4RDMDN.js";
10
10
  import "../chunks/chunk-HNQPEMYE.js";
11
11
  import "../chunks/chunk-ST2IBUAN.js";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-VHW7FDHU.js";
4
4
  import {
5
5
  coversGraph
6
- } from "./chunk-REM73HCU.js";
6
+ } from "./chunk-EHUBJDDB.js";
7
7
  import {
8
8
  bubbleSegmentIds
9
9
  } from "./chunk-XKWD2RY3.js";
@@ -11,7 +11,7 @@ import {
11
11
  bubblesFromGraph,
12
12
  walkIndexOf,
13
13
  walkRoutes
14
- } from "./chunk-GOZYKNQ2.js";
14
+ } from "./chunk-CLOP7UVD.js";
15
15
  import {
16
16
  SATURATED_PATH_COUNT
17
17
  } from "./chunk-FX4RDMDN.js";
@@ -227,7 +227,10 @@ function superbubblesFromGraph(graph, span) {
227
227
  (f, i) => !covers[i] && placed(f) && !nested(f, i)
228
228
  );
229
229
  const byId = new Map(nodes.map((n) => [n.id, n]));
230
- const walkIndex = walkIndexOf(graph);
230
+ const walkIndex = walkIndexOf(
231
+ graph,
232
+ outermost.flatMap((f) => [nodes[f.source >> 1].id, nodes[f.sink >> 1].id])
233
+ );
231
234
  return outermost.map((f) => {
232
235
  const source = nodes[f.source >> 1];
233
236
  const sink = nodes[f.sink >> 1];
@@ -38,7 +38,10 @@ function bubblesFromGraph(graph) {
38
38
  const backbone = graph.nodes.filter(isBackbone).sort((a, b) => a.stable.start - b.stable.start);
39
39
  const ends = /* @__PURE__ */ new Set([backbone[0].id, backbone.at(-1).id]);
40
40
  const boundaries = backbone.map((node) => [node, indexOf.get(node.id)]).filter(([node, i]) => ends.has(node.id) || reach[i] === 0).sort(([a, ia], [b, ib]) => ia - ib || a.stable.start - b.stable.start);
41
- const walkIndex = walkIndexOf(graph);
41
+ const walkIndex = walkIndexOf(
42
+ graph,
43
+ boundaries.map(([node]) => node.id)
44
+ );
42
45
  const bubbles = [];
43
46
  for (let i = 0; i + 1 < boundaries.length; i++) {
44
47
  const [start, i0] = boundaries[i];
@@ -104,47 +107,63 @@ function bubblesFromGraph(graph) {
104
107
  }
105
108
  return bubbles;
106
109
  }
107
- function walkIndexOf(graph) {
108
- return graph.paths?.map((p) => {
109
- const at = /* @__PURE__ */ new Map();
110
- p.nodeIds.forEach((id, i) => {
111
- if (!at.has(id)) {
112
- at.set(id, i);
110
+ function walkIndexOf(graph, ids) {
111
+ const paths = graph.paths;
112
+ if (!paths) {
113
+ return void 0;
114
+ }
115
+ const index = /* @__PURE__ */ new Map();
116
+ for (const id of ids) {
117
+ index.set(id, new Int32Array(paths.length).fill(-1));
118
+ }
119
+ paths.forEach((p, k) => {
120
+ const steps = p.nodeIds;
121
+ for (let i = 0; i < steps.length; i++) {
122
+ const at = index.get(steps[i]);
123
+ if (at?.[k] === -1) {
124
+ at[k] = i;
113
125
  }
114
- });
115
- return at;
126
+ }
116
127
  });
128
+ return index;
117
129
  }
118
130
  function walkRoutes(graph, byId, walkIndex, startId, endId) {
119
- const seen = /* @__PURE__ */ new Map();
131
+ const routes = [];
120
132
  let min = Infinity;
121
133
  let max = -Infinity;
122
134
  let left = 0;
135
+ const at0 = walkIndex.get(startId);
136
+ const at1 = walkIndex.get(endId);
123
137
  graph.paths.forEach((p, k) => {
124
- const i0 = walkIndex[k].get(startId);
125
- const i1 = walkIndex[k].get(endId);
126
- if (i0 === void 0 || i1 === void 0) {
127
- if (i0 !== void 0 || i1 !== void 0) {
138
+ const i0 = at0[k];
139
+ const i1 = at1[k];
140
+ if (i0 < 0 || i1 < 0) {
141
+ if (i0 >= 0 || i1 >= 0) {
128
142
  left++;
129
143
  }
130
144
  return;
131
145
  }
132
- const steps = p.nodeIds.slice(Math.min(i0, i1) + 1, Math.max(i0, i1));
133
- if (i1 < i0) {
134
- steps.reverse();
135
- }
136
- let bp = 0;
137
- for (const id of steps) {
138
- bp += byId.get(id)?.length ?? 0;
146
+ const ids = p.nodeIds;
147
+ const lo = Math.min(i0, i1) + 1;
148
+ const hi = Math.max(i0, i1);
149
+ const step = i1 < i0 ? (j) => ids[hi - 1 - j] : (j) => ids[lo + j];
150
+ let route = routes.find(
151
+ (r) => r.steps.length === hi - lo && r.steps.every((id, j) => id === step(j))
152
+ );
153
+ if (!route) {
154
+ const steps = Array.from({ length: hi - lo }, (_, j) => step(j));
155
+ let bp = 0;
156
+ for (const id of steps) {
157
+ bp += byId.get(id)?.length ?? 0;
158
+ }
159
+ route = { steps, bp, walks: [] };
160
+ routes.push(route);
139
161
  }
140
- const key = steps.join(",");
141
- const route = seen.get(key) ?? { steps, bp, walks: [] };
142
162
  route.walks.push(p.name);
143
- seen.set(key, route);
144
- min = Math.min(min, bp);
145
- max = Math.max(max, bp);
163
+ min = Math.min(min, route.bp);
164
+ max = Math.max(max, route.bp);
146
165
  });
147
- return seen.size || left ? { min, max, n: seen.size, left, routes: [...seen.values()] } : void 0;
166
+ return routes.length || left ? { min, max, n: routes.length, left, routes } : void 0;
148
167
  }
149
168
 
150
169
  export {
@@ -55,27 +55,11 @@ function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repe
55
55
  x: ends.reduce((s, p) => s + p.x, 0) / ends.length,
56
56
  y: ends.reduce((s, p) => s + p.y, 0) / ends.length
57
57
  } : labelAt;
58
- const sharing = /* @__PURE__ */ new Map();
59
- for (const route of bubble.routes ?? []) {
60
- for (const id of new Set(route.steps)) {
61
- sharing.set(id, (sharing.get(id) ?? 0) + 1);
62
- }
63
- }
64
58
  const routes = [];
65
- for (const route of bubble.routes ?? []) {
66
- if (bubble.longestAlleleLength < MIN_CHIPPED_BP) {
67
- break;
68
- }
69
- if (route.steps.length === 0) {
70
- continue;
71
- }
72
- const rarest = Math.min(...route.steps.map((id) => sharing.get(id)));
59
+ for (const [route, own] of ownStretches(bubble)) {
73
60
  let at;
74
61
  let far = -1;
75
- for (const id of route.steps) {
76
- if (sharing.get(id) !== rarest) {
77
- continue;
78
- }
62
+ for (const id of own) {
79
63
  for (const p of positions[id] ?? []) {
80
64
  const d = Math.hypot(p.x - anchor.x, p.y - anchor.y);
81
65
  if (d > far) {
@@ -105,6 +89,37 @@ function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repe
105
89
  }
106
90
  return halos;
107
91
  }
92
+ var stretches = /* @__PURE__ */ new WeakMap();
93
+ function ownStretches(bubble) {
94
+ const cached = stretches.get(bubble);
95
+ if (cached) {
96
+ return cached;
97
+ }
98
+ const chipped = bubble.longestAlleleLength < MIN_CHIPPED_BP ? [] : bubble.routes ?? [];
99
+ const sharing = /* @__PURE__ */ new Map();
100
+ chipped.forEach((route, r) => {
101
+ const counted = /* @__PURE__ */ new Map();
102
+ for (const id of route.steps) {
103
+ if (counted.get(id) !== r) {
104
+ counted.set(id, r);
105
+ sharing.set(id, (sharing.get(id) ?? 0) + 1);
106
+ }
107
+ }
108
+ });
109
+ const own = /* @__PURE__ */ new Map();
110
+ for (const route of chipped) {
111
+ let rarest = Infinity;
112
+ for (const id of route.steps) {
113
+ rarest = Math.min(rarest, sharing.get(id));
114
+ }
115
+ const steps = new Set(route.steps.filter((id) => sharing.get(id) === rarest));
116
+ if (steps.size > 0) {
117
+ own.set(route, [...steps]);
118
+ }
119
+ }
120
+ stretches.set(bubble, own);
121
+ return own;
122
+ }
108
123
  function routeText(route, walkLabel) {
109
124
  const names = [...new Set(route.walks.map(walkLabel))].sort();
110
125
  const shown = names.slice(0, NAMED_WALKS).join(", ");
@@ -18,6 +18,7 @@ var UNTANGLE_LINKS = 3;
18
18
  var UNTANGLE_PUSH = 0.3;
19
19
  var SMOOTH_PASSES = 2;
20
20
  var MAX_HOPS = 200;
21
+ var REFERENCE_HOPS = 20;
21
22
  var EPS = 0.1;
22
23
  var WARM = 0.5;
23
24
  function flipped(strand, name) {
@@ -238,7 +239,8 @@ function stressLayout(request, opts = {}) {
238
239
  let idx = c.indexOf[i];
239
240
  let dir = rand() < 0.5 ? -1 : 1;
240
241
  let remaining = length;
241
- for (let hops = 0; hops < MAX_HOPS; hops++) {
242
+ const maxHops = refIdx[comp[i]].length >= 2 ? REFERENCE_HOPS : MAX_HOPS;
243
+ for (let hops = 0; hops < maxHops; hops++) {
242
244
  const points = count[chain];
243
245
  const step = per[chain];
244
246
  const toEnd = (dir > 0 ? points - 1 - idx : idx) * step;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  stressLayout
3
- } from "./chunk-UNOE2NDN.js";
3
+ } from "./chunk-Q6FRNVDU.js";
4
4
  import {
5
5
  loadBandage
6
6
  } from "./chunk-7XHHVYG7.js";
@@ -14,7 +14,7 @@ var LAYOUT_ENGINES = [
14
14
  },
15
15
  {
16
16
  value: "stress",
17
- label: "Stress (experimental)",
17
+ label: "Stress",
18
18
  description: "Stress layout by stochastic gradient descent in plain JS: distances along the graph become distances on the page, so the reference reads straight and a repeat loop reads as a ring."
19
19
  }
20
20
  ];
@@ -45,7 +45,7 @@ import {
45
45
  } from "./chunk-BR25DGIJ.js";
46
46
  import {
47
47
  version
48
- } from "./chunk-BIGORSXS.js";
48
+ } from "./chunk-YSQMOOHY.js";
49
49
  import {
50
50
  walkRowLabels,
51
51
  walkRowsExtent
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var version = "9.4.0";
2
+ var version = "9.6.0";
3
3
 
4
4
  export {
5
5
  version
@@ -8,8 +8,8 @@ import {
8
8
  LAYOUT_ENGINE_VALUES,
9
9
  isLayoutEngineKind,
10
10
  layoutEngine
11
- } from "../chunks/chunk-6EJIU6IA.js";
12
- import "../chunks/chunk-UNOE2NDN.js";
11
+ } from "../chunks/chunk-VK6XMP6B.js";
12
+ import "../chunks/chunk-Q6FRNVDU.js";
13
13
  import "../chunks/chunk-LYJ4US66.js";
14
14
  import {
15
15
  LAYOUT_MODES,
@@ -35,7 +35,7 @@ import "../chunks/chunk-LTUWJKHD.js";
35
35
  import "../chunks/chunk-WSIFAZU7.js";
36
36
  import {
37
37
  figureSvg
38
- } from "../chunks/chunk-4DEOECM3.js";
38
+ } from "../chunks/chunk-WVPC3JVY.js";
39
39
  import "../chunks/chunk-UD5FOCI2.js";
40
40
  import "../chunks/chunk-WBCOREDZ.js";
41
41
  import "../chunks/chunk-4BYTEJGW.js";
@@ -54,7 +54,7 @@ import "../chunks/chunk-2LQ5BWT7.js";
54
54
  import "../chunks/chunk-OXTR3BVF.js";
55
55
  import "../chunks/chunk-BR25DGIJ.js";
56
56
  import "../chunks/chunk-G2FD7S3C.js";
57
- import "../chunks/chunk-BIGORSXS.js";
57
+ import "../chunks/chunk-YSQMOOHY.js";
58
58
  import "../chunks/chunk-3C5UXR2U.js";
59
59
  import {
60
60
  filterSamples,
package/dist/figure.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  figureSvg
3
- } from "./chunks/chunk-4DEOECM3.js";
3
+ } from "./chunks/chunk-WVPC3JVY.js";
4
4
  import "./chunks/chunk-UD5FOCI2.js";
5
5
  import "./chunks/chunk-WBCOREDZ.js";
6
6
  import "./chunks/chunk-4BYTEJGW.js";
@@ -16,7 +16,7 @@ import "./chunks/chunk-2LQ5BWT7.js";
16
16
  import "./chunks/chunk-OXTR3BVF.js";
17
17
  import "./chunks/chunk-BR25DGIJ.js";
18
18
  import "./chunks/chunk-G2FD7S3C.js";
19
- import "./chunks/chunk-BIGORSXS.js";
19
+ import "./chunks/chunk-YSQMOOHY.js";
20
20
  import "./chunks/chunk-3C5UXR2U.js";
21
21
  import "./chunks/chunk-MAUEPAMG.js";
22
22
  import "./chunks/chunk-7GBL7SJY.js";
package/dist/index.js CHANGED
@@ -42,7 +42,7 @@ import {
42
42
  import {
43
43
  graphBubbles,
44
44
  superbubblesFromGraph
45
- } from "./chunks/chunk-TF7H5LQS.js";
45
+ } from "./chunks/chunk-C55SC5AJ.js";
46
46
  import {
47
47
  bubbleSubgraph
48
48
  } from "./chunks/chunk-VHW7FDHU.js";
@@ -54,7 +54,7 @@ import {
54
54
  } from "./chunks/chunk-BXEPA4KS.js";
55
55
  import {
56
56
  bubbleHalos
57
- } from "./chunks/chunk-REM73HCU.js";
57
+ } from "./chunks/chunk-EHUBJDDB.js";
58
58
  import {
59
59
  BUBBLE_KIND_COLORS,
60
60
  BUBBLE_KIND_NAMES,
@@ -63,7 +63,7 @@ import {
63
63
  } from "./chunks/chunk-XKWD2RY3.js";
64
64
  import {
65
65
  bubblesFromGraph
66
- } from "./chunks/chunk-GOZYKNQ2.js";
66
+ } from "./chunks/chunk-CLOP7UVD.js";
67
67
  import "./chunks/chunk-FX4RDMDN.js";
68
68
  import {
69
69
  REFERENCE_STRIP_ZONE_PX,
@@ -74,10 +74,10 @@ import {
74
74
  import {
75
75
  LAYOUT_ENGINES,
76
76
  layoutEngine
77
- } from "./chunks/chunk-6EJIU6IA.js";
77
+ } from "./chunks/chunk-VK6XMP6B.js";
78
78
  import {
79
79
  stressLayout
80
- } from "./chunks/chunk-UNOE2NDN.js";
80
+ } from "./chunks/chunk-Q6FRNVDU.js";
81
81
  import "./chunks/chunk-LYJ4US66.js";
82
82
  import {
83
83
  FORCE_LAYOUT_LABEL,
@@ -119,7 +119,7 @@ import {
119
119
  } from "./chunks/chunk-AZFVORTC.js";
120
120
  import {
121
121
  figureSvg
122
- } from "./chunks/chunk-4DEOECM3.js";
122
+ } from "./chunks/chunk-WVPC3JVY.js";
123
123
  import {
124
124
  WALK_STRIP_CEILING_PX,
125
125
  cutsWholeWalks,
@@ -219,7 +219,7 @@ import {
219
219
  import "./chunks/chunk-G2FD7S3C.js";
220
220
  import {
221
221
  version
222
- } from "./chunks/chunk-BIGORSXS.js";
222
+ } from "./chunks/chunk-YSQMOOHY.js";
223
223
  import {
224
224
  walkRowLabels,
225
225
  walkRowsExtent
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  chains,
3
3
  stressLayout
4
- } from "../chunks/chunk-UNOE2NDN.js";
4
+ } from "../chunks/chunk-Q6FRNVDU.js";
5
5
  import "../chunks/chunk-LYJ4US66.js";
6
6
  import "../chunks/chunk-JVLURPFW.js";
7
7
  import "../chunks/chunk-FYQWPEEY.js";
@@ -3,8 +3,8 @@ import {
3
3
  LAYOUT_ENGINE_VALUES,
4
4
  isLayoutEngineKind,
5
5
  layoutEngine
6
- } from "./chunks/chunk-6EJIU6IA.js";
7
- import "./chunks/chunk-UNOE2NDN.js";
6
+ } from "./chunks/chunk-VK6XMP6B.js";
7
+ import "./chunks/chunk-Q6FRNVDU.js";
8
8
  import "./chunks/chunk-LYJ4US66.js";
9
9
  import "./chunks/chunk-7XHHVYG7.js";
10
10
  import "./chunks/chunk-JVLURPFW.js";
@@ -6,8 +6,9 @@ export interface Routes {
6
6
  n: number;
7
7
  }
8
8
  export declare function bubblesFromGraph(graph: Graph): MinigraphBubble[];
9
- export declare function walkIndexOf(graph: Graph): Map<string, number>[] | undefined;
10
- export declare function walkRoutes(graph: Graph, byId: Map<string, GraphNode>, walkIndex: Map<string, number>[], startId: string, endId: string): (Routes & {
9
+ export type WalkIndex = Map<string, Int32Array>;
10
+ export declare function walkIndexOf(graph: Graph, ids: Iterable<string>): WalkIndex | undefined;
11
+ export declare function walkRoutes(graph: Graph, byId: Map<string, GraphNode>, walkIndex: WalkIndex, startId: string, endId: string): (Routes & {
11
12
  left: number;
12
13
  routes: BubbleRoute[];
13
14
  }) | undefined;
@@ -5,7 +5,7 @@ export declare const LAYOUT_ENGINES: readonly [{
5
5
  readonly description: "Bandage's force-directed layout: OGDF's fast multipole multilevel method, compiled to wasm.";
6
6
  }, {
7
7
  readonly value: "stress";
8
- readonly label: "Stress (experimental)";
8
+ readonly label: "Stress";
9
9
  readonly description: "Stress layout by stochastic gradient descent in plain JS: distances along the graph become distances on the page, so the reference reads straight and a repeat loop reads as a ring.";
10
10
  }];
11
11
  export type LayoutEngineKind = (typeof LAYOUT_ENGINES)[number]['value'];
@@ -1 +1 @@
1
- export declare const version = "9.4.0";
1
+ export declare const version = "9.6.0";
package/dist/version.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  version
3
- } from "./chunks/chunk-BIGORSXS.js";
3
+ } from "./chunks/chunk-YSQMOOHY.js";
4
4
  export {
5
5
  version
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/bandage-core",
3
- "version": "9.4.0",
3
+ "version": "9.6.0",
4
4
  "description": "Pangenome graph layout and drawing with no host: GFA in, the Bandage force-directed engine and reference-anchored layouts, a Canvas2D renderer, hit testing and labels out",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {