@jbrowse/bandage-core 4.0.24 → 4.0.25
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/chunks/{chunk-4AOHEU76.js → chunk-B5ZHLU4N.js} +589 -36
- package/dist/cli/figure.js +61 -56
- package/dist/index.js +47 -242
- package/dist/types/cli/figure.d.ts +8 -8
- package/dist/types/figure.d.ts +3 -1
- package/dist/types/gbzCut.d.ts +33 -0
- package/dist/types/genes/geneFiles.d.ts +10 -0
- package/dist/types/index.d.ts +5 -1
- package/dist/types/labelLayout.d.ts +14 -0
- package/dist/types/referenceStrip.d.ts +4 -3
- package/dist/types/version.d.ts +1 -0
- package/dist/types/walkKey.d.ts +1 -0
- package/package.json +3 -2
|
@@ -1772,9 +1772,9 @@ function sampleRowLayout(graph, region, keep = []) {
|
|
|
1772
1772
|
},
|
|
1773
1773
|
positions: nodePositions
|
|
1774
1774
|
});
|
|
1775
|
-
const
|
|
1775
|
+
const referenceSample2 = parsePanSN(backbone[0].stable.refName).sample;
|
|
1776
1776
|
const rowLabels = [
|
|
1777
|
-
{ label:
|
|
1777
|
+
{ label: referenceSample2, y: 0 },
|
|
1778
1778
|
...samples.map((sample) => ({
|
|
1779
1779
|
label: sample,
|
|
1780
1780
|
y: rowOf.get(sample) * ROW_HEIGHT_PX
|
|
@@ -2818,10 +2818,10 @@ function brightenAbgr(c, factor) {
|
|
|
2818
2818
|
|
|
2819
2819
|
// src/util/edgeCurves.ts
|
|
2820
2820
|
var cache = /* @__PURE__ */ new WeakMap();
|
|
2821
|
-
function baseEdgeCurves(nodePositions, graph, axis, deletions,
|
|
2821
|
+
function baseEdgeCurves(nodePositions, graph, axis, deletions, version2) {
|
|
2822
2822
|
const { scaleX, scaleY } = axis;
|
|
2823
2823
|
const cached2 = cache.get(nodePositions);
|
|
2824
|
-
if (cached2?.graph === graph && cached2.scaleX === scaleX && cached2.scaleY === scaleY && cached2.deletions === deletions && cached2.version ===
|
|
2824
|
+
if (cached2?.graph === graph && cached2.scaleX === scaleX && cached2.scaleY === scaleY && cached2.deletions === deletions && cached2.version === version2) {
|
|
2825
2825
|
return cached2.curves;
|
|
2826
2826
|
}
|
|
2827
2827
|
const curves = /* @__PURE__ */ new Map();
|
|
@@ -2850,7 +2850,7 @@ function baseEdgeCurves(nodePositions, graph, axis, deletions, version) {
|
|
|
2850
2850
|
scaleX,
|
|
2851
2851
|
scaleY,
|
|
2852
2852
|
deletions,
|
|
2853
|
-
version,
|
|
2853
|
+
version: version2,
|
|
2854
2854
|
curves
|
|
2855
2855
|
});
|
|
2856
2856
|
return curves;
|
|
@@ -3312,7 +3312,7 @@ function buildGeometry(options) {
|
|
|
3312
3312
|
referenceRamp,
|
|
3313
3313
|
deletions,
|
|
3314
3314
|
hiddenEdges,
|
|
3315
|
-
version = 0
|
|
3315
|
+
version: version2 = 0
|
|
3316
3316
|
} = options;
|
|
3317
3317
|
const depthNorm = nodeWidth2 === "depth" ? meanDepth(graph) : 0;
|
|
3318
3318
|
const scale = axis.scaleX;
|
|
@@ -3322,7 +3322,7 @@ function buildGeometry(options) {
|
|
|
3322
3322
|
graph,
|
|
3323
3323
|
axis,
|
|
3324
3324
|
deletions,
|
|
3325
|
-
|
|
3325
|
+
version2
|
|
3326
3326
|
);
|
|
3327
3327
|
const nodeStrokes = [];
|
|
3328
3328
|
const nodeStrokeRuns = /* @__PURE__ */ new Map();
|
|
@@ -3871,10 +3871,10 @@ function labelOrder(nodePositions, nodeLengths) {
|
|
|
3871
3871
|
return order;
|
|
3872
3872
|
}
|
|
3873
3873
|
var arcCache = /* @__PURE__ */ new WeakMap();
|
|
3874
|
-
function arcPlacements(nodePositions, deletions, axis,
|
|
3874
|
+
function arcPlacements(nodePositions, deletions, axis, version2) {
|
|
3875
3875
|
const { scaleX, scaleY } = axis;
|
|
3876
3876
|
const cached2 = arcCache.get(nodePositions);
|
|
3877
|
-
if (cached2?.deletions === deletions && cached2.scaleX === scaleX && cached2.scaleY === scaleY && cached2.version ===
|
|
3877
|
+
if (cached2?.deletions === deletions && cached2.scaleX === scaleX && cached2.scaleY === scaleY && cached2.version === version2) {
|
|
3878
3878
|
return cached2.arcs;
|
|
3879
3879
|
}
|
|
3880
3880
|
const arcs = [];
|
|
@@ -3892,7 +3892,7 @@ function arcPlacements(nodePositions, deletions, axis, version) {
|
|
|
3892
3892
|
});
|
|
3893
3893
|
}
|
|
3894
3894
|
}
|
|
3895
|
-
arcCache.set(nodePositions, { deletions, scaleX, scaleY, version, arcs });
|
|
3895
|
+
arcCache.set(nodePositions, { deletions, scaleX, scaleY, version: version2, arcs });
|
|
3896
3896
|
return arcs;
|
|
3897
3897
|
}
|
|
3898
3898
|
function sizeLabelCandidates({
|
|
@@ -3905,7 +3905,7 @@ function sizeLabelCandidates({
|
|
|
3905
3905
|
translateY,
|
|
3906
3906
|
width,
|
|
3907
3907
|
height,
|
|
3908
|
-
version = 0
|
|
3908
|
+
version: version2 = 0
|
|
3909
3909
|
}) {
|
|
3910
3910
|
const { scaleX, scaleY } = axis;
|
|
3911
3911
|
const deletionCandidates = [];
|
|
@@ -3914,7 +3914,7 @@ function sizeLabelCandidates({
|
|
|
3914
3914
|
nodePositions,
|
|
3915
3915
|
deletions,
|
|
3916
3916
|
axis,
|
|
3917
|
-
|
|
3917
|
+
version2
|
|
3918
3918
|
)) {
|
|
3919
3919
|
if (extent >= MIN_DELETION_LABEL_PX) {
|
|
3920
3920
|
const text = deletionText(deletion.bp);
|
|
@@ -4292,6 +4292,15 @@ function walkKey(walk, reference) {
|
|
|
4292
4292
|
hover: scale === own ? void 0 : own
|
|
4293
4293
|
};
|
|
4294
4294
|
}
|
|
4295
|
+
function walkPosition(walk, nodeId, length) {
|
|
4296
|
+
const progress = walk.progress.get(nodeId);
|
|
4297
|
+
const range = walk.range;
|
|
4298
|
+
if (progress === void 0 || !range) {
|
|
4299
|
+
return void 0;
|
|
4300
|
+
}
|
|
4301
|
+
const start = Math.round(range.start + progress * walk.bp - length / 2);
|
|
4302
|
+
return `${range.contig}:${start.toLocaleString()}-${(start + length).toLocaleString()}`;
|
|
4303
|
+
}
|
|
4295
4304
|
|
|
4296
4305
|
// src/facetGrid.ts
|
|
4297
4306
|
var FACET_GAP_PX = 8;
|
|
@@ -4364,6 +4373,223 @@ function facetCells(names, by) {
|
|
|
4364
4373
|
return cells.includes(-1) || new Set(cells).size < cells.length ? wrap : { columns, count: rows.length * columns, cells };
|
|
4365
4374
|
}
|
|
4366
4375
|
|
|
4376
|
+
// src/genes/genePins.ts
|
|
4377
|
+
function genePins(graph, genes, positions) {
|
|
4378
|
+
const byRefName = /* @__PURE__ */ new Map();
|
|
4379
|
+
for (const node of graph.nodes) {
|
|
4380
|
+
if (isBackbone(node)) {
|
|
4381
|
+
const { refName } = node.stable;
|
|
4382
|
+
if (positions[node.id]?.length) {
|
|
4383
|
+
const entry = byRefName.get(refName) ?? byRefName.set(refName, { nodes: [], reach: 0 }).get(refName);
|
|
4384
|
+
entry.nodes.push(node);
|
|
4385
|
+
entry.reach = Math.max(entry.reach, node.length);
|
|
4386
|
+
}
|
|
4387
|
+
}
|
|
4388
|
+
}
|
|
4389
|
+
for (const { nodes } of byRefName.values()) {
|
|
4390
|
+
nodes.sort((a, b) => a.stable.start - b.stable.start);
|
|
4391
|
+
}
|
|
4392
|
+
const pins = [];
|
|
4393
|
+
for (const gene of genes) {
|
|
4394
|
+
const backbone = byRefName.get(gene.refName);
|
|
4395
|
+
if (!backbone) {
|
|
4396
|
+
continue;
|
|
4397
|
+
}
|
|
4398
|
+
const parts = [];
|
|
4399
|
+
const exonsByNode = [];
|
|
4400
|
+
let at;
|
|
4401
|
+
let atDistance = Infinity;
|
|
4402
|
+
let covered = 0;
|
|
4403
|
+
const mid = (gene.start + gene.end) / 2;
|
|
4404
|
+
const { nodes, reach } = backbone;
|
|
4405
|
+
for (let i = firstNodeAtOrAfter(nodes, gene.start - reach); i < nodes.length && nodes[i].stable.start < gene.end; i++) {
|
|
4406
|
+
const node = nodes[i];
|
|
4407
|
+
const nodeStart = node.stable.start;
|
|
4408
|
+
const nodeEnd = nodeStart + node.length;
|
|
4409
|
+
if (nodeEnd <= gene.start) {
|
|
4410
|
+
continue;
|
|
4411
|
+
}
|
|
4412
|
+
const line = positions[node.id];
|
|
4413
|
+
covered += Math.min(nodeEnd, gene.end) - Math.max(nodeStart, gene.start);
|
|
4414
|
+
const nodeParts = [];
|
|
4415
|
+
for (const exon of gene.exons) {
|
|
4416
|
+
const a = Math.max(exon.start, nodeStart);
|
|
4417
|
+
const b = Math.min(exon.end, nodeEnd);
|
|
4418
|
+
if (b <= a) {
|
|
4419
|
+
continue;
|
|
4420
|
+
}
|
|
4421
|
+
const stretch = polylineSlice(
|
|
4422
|
+
line,
|
|
4423
|
+
(a - nodeStart) / node.length,
|
|
4424
|
+
(b - nodeStart) / node.length
|
|
4425
|
+
);
|
|
4426
|
+
if (stretch.length === 1) {
|
|
4427
|
+
stretch.push({ ...stretch[0] });
|
|
4428
|
+
}
|
|
4429
|
+
nodeParts.push(svgPath(stretch));
|
|
4430
|
+
}
|
|
4431
|
+
if (nodeParts.length > 0) {
|
|
4432
|
+
parts.push(...nodeParts);
|
|
4433
|
+
exonsByNode.push({ nodeId: node.id, d: nodeParts.join("") });
|
|
4434
|
+
}
|
|
4435
|
+
const pinBp = Math.min(Math.max(mid, nodeStart), nodeEnd);
|
|
4436
|
+
const distance = Math.abs(pinBp - mid);
|
|
4437
|
+
if (distance < atDistance) {
|
|
4438
|
+
atDistance = distance;
|
|
4439
|
+
const [p] = polylineSlice(
|
|
4440
|
+
line,
|
|
4441
|
+
(pinBp - nodeStart) / node.length,
|
|
4442
|
+
(pinBp - nodeStart) / node.length
|
|
4443
|
+
);
|
|
4444
|
+
at = p;
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
if (at) {
|
|
4448
|
+
pins.push({
|
|
4449
|
+
gene,
|
|
4450
|
+
exons: parts.join(""),
|
|
4451
|
+
exonsByNode,
|
|
4452
|
+
at,
|
|
4453
|
+
covered: covered / (gene.end - gene.start)
|
|
4454
|
+
});
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
return pins;
|
|
4458
|
+
}
|
|
4459
|
+
|
|
4460
|
+
// src/labelLayout.ts
|
|
4461
|
+
var HALO_FACTOR = 3.4;
|
|
4462
|
+
var LEGEND_INSET_PX = 6;
|
|
4463
|
+
var ROUTE_STACK = 8;
|
|
4464
|
+
var GENE_PIN_DROP_PX = 18;
|
|
4465
|
+
var GENE_STACK = 2;
|
|
4466
|
+
var TOPMOST_BASELINE = LABEL_PX + LABEL_PAD;
|
|
4467
|
+
function geneCoverageNote(pin) {
|
|
4468
|
+
const length = pin.gene.end - pin.gene.start;
|
|
4469
|
+
if (pin.covered >= 0.98) {
|
|
4470
|
+
return void 0;
|
|
4471
|
+
}
|
|
4472
|
+
const [per, unit] = length >= 1e6 ? [1e6, "Mb"] : length >= 1e3 ? [1e3, "kb"] : [1, "bp"];
|
|
4473
|
+
const amount = (bp) => +(bp / per).toFixed(per === 1 ? 0 : 1);
|
|
4474
|
+
return `${amount(pin.covered * length)} of ${amount(length)} ${unit}`;
|
|
4475
|
+
}
|
|
4476
|
+
function geneLabelCandidates(pins, screen, contigThickness) {
|
|
4477
|
+
return byExtent(pins, (pin) => pin.gene.end - pin.gene.start).map((pin) => {
|
|
4478
|
+
const { x, y } = screen(pin.at);
|
|
4479
|
+
const note = geneCoverageNote(pin);
|
|
4480
|
+
return {
|
|
4481
|
+
item: pin,
|
|
4482
|
+
x,
|
|
4483
|
+
y: y + contigThickness + GENE_PIN_DROP_PX,
|
|
4484
|
+
text: note ? `${pin.gene.name} \xB7 ${note}` : pin.gene.name,
|
|
4485
|
+
fallback: note ? `${pin.gene.name} \u2026` : void 0,
|
|
4486
|
+
stack: GENE_STACK
|
|
4487
|
+
};
|
|
4488
|
+
});
|
|
4489
|
+
}
|
|
4490
|
+
function byExtent(items, extent) {
|
|
4491
|
+
return [...items].sort((a, b) => extent(b) - extent(a));
|
|
4492
|
+
}
|
|
4493
|
+
function layoutLabels(m) {
|
|
4494
|
+
const { paneWidth: width, canvasHeight: height, translateX, translateY } = m;
|
|
4495
|
+
const { scaleX, scaleY } = m.axisScale;
|
|
4496
|
+
const frame = { width, height };
|
|
4497
|
+
const screen = (p) => ({
|
|
4498
|
+
x: p.x * scaleX + translateX,
|
|
4499
|
+
y: p.y * scaleY + translateY
|
|
4500
|
+
});
|
|
4501
|
+
const reserved = m.drawnRowLabels.map(
|
|
4502
|
+
({ label, y }) => rowLabelBox(label, y * scaleY + translateY)
|
|
4503
|
+
);
|
|
4504
|
+
const stripPx = m.referenceStripZonePx ?? 0;
|
|
4505
|
+
if (stripPx > 0) {
|
|
4506
|
+
reserved.push({ x0: 0, x1: width, y0: 0, y1: stripPx });
|
|
4507
|
+
}
|
|
4508
|
+
if (m.legendSize.width > 0) {
|
|
4509
|
+
reserved.push({
|
|
4510
|
+
x0: width - LEGEND_INSET_PX - m.legendSize.width,
|
|
4511
|
+
x1: width,
|
|
4512
|
+
y0: 0,
|
|
4513
|
+
y1: stripPx + LEGEND_INSET_PX + m.legendSize.height
|
|
4514
|
+
});
|
|
4515
|
+
}
|
|
4516
|
+
if (m.poppedFrom) {
|
|
4517
|
+
reserved.push({
|
|
4518
|
+
x0: 0,
|
|
4519
|
+
x1: 60 + m.poppedFrom.label.length * LABEL_CHAR_PX * 1.2,
|
|
4520
|
+
y0: 0,
|
|
4521
|
+
y1: 44
|
|
4522
|
+
});
|
|
4523
|
+
}
|
|
4524
|
+
const take = occupancy(frame, reserved);
|
|
4525
|
+
const onRows = m.drawnRowLabels.length > 0;
|
|
4526
|
+
const rowsTop = onRows ? Math.min(...m.drawnRowLabels.map((r) => r.y)) : Infinity;
|
|
4527
|
+
const halo = m.contigThickness * HALO_FACTOR;
|
|
4528
|
+
const byBubble = byExtent(m.bubbleHalos, (h) => h.members);
|
|
4529
|
+
const bubbles = placeLabels(
|
|
4530
|
+
byBubble.map((h) => {
|
|
4531
|
+
const { x, y } = screen({
|
|
4532
|
+
x: h.labelAt.x,
|
|
4533
|
+
y: Math.min(h.labelAt.y, rowsTop)
|
|
4534
|
+
});
|
|
4535
|
+
const baseline = y - halo / 2 - 6;
|
|
4536
|
+
return {
|
|
4537
|
+
item: h,
|
|
4538
|
+
x,
|
|
4539
|
+
y: onRows ? Math.max(baseline, TOPMOST_BASELINE) : baseline,
|
|
4540
|
+
text: h.label
|
|
4541
|
+
};
|
|
4542
|
+
}),
|
|
4543
|
+
frame,
|
|
4544
|
+
take
|
|
4545
|
+
);
|
|
4546
|
+
const genes = placeLabels(
|
|
4547
|
+
geneLabelCandidates(m.genePins, screen, m.contigThickness),
|
|
4548
|
+
frame,
|
|
4549
|
+
take
|
|
4550
|
+
);
|
|
4551
|
+
const sizeCandidates = m.nodePositions && m.labelsNodeSizes ? sizeLabelCandidates({
|
|
4552
|
+
nodePositions: m.nodePositions,
|
|
4553
|
+
nodeLengths: m.nodeLengths,
|
|
4554
|
+
deletions: m.showDeletionEdges ? m.deletions : [],
|
|
4555
|
+
alleleDeletions: m.alleleDeletions,
|
|
4556
|
+
axis: m.axisScale,
|
|
4557
|
+
translateX,
|
|
4558
|
+
translateY,
|
|
4559
|
+
width,
|
|
4560
|
+
height,
|
|
4561
|
+
version: m.positionsVersion
|
|
4562
|
+
}) : { deletions: [], nodes: [] };
|
|
4563
|
+
const deletionLabels = placeSizeLabels(sizeCandidates.deletions, take);
|
|
4564
|
+
const routes = placeLabels(
|
|
4565
|
+
byBubble.flatMap(
|
|
4566
|
+
(h) => h.routes.map((route) => {
|
|
4567
|
+
const { x, y } = screen(route.at);
|
|
4568
|
+
return {
|
|
4569
|
+
item: { halo: h, route },
|
|
4570
|
+
x,
|
|
4571
|
+
y: y + 4,
|
|
4572
|
+
text: route.text,
|
|
4573
|
+
stack: ROUTE_STACK
|
|
4574
|
+
};
|
|
4575
|
+
})
|
|
4576
|
+
),
|
|
4577
|
+
frame,
|
|
4578
|
+
take
|
|
4579
|
+
);
|
|
4580
|
+
const nodeLabels = placeSizeLabels(
|
|
4581
|
+
sizeCandidates.nodes,
|
|
4582
|
+
take,
|
|
4583
|
+
nodeLabelBudget(width, height)
|
|
4584
|
+
);
|
|
4585
|
+
return {
|
|
4586
|
+
bubbles,
|
|
4587
|
+
genes,
|
|
4588
|
+
routes,
|
|
4589
|
+
sizes: [...deletionLabels, ...nodeLabels]
|
|
4590
|
+
};
|
|
4591
|
+
}
|
|
4592
|
+
|
|
4367
4593
|
// src/renderer/svgCanvas.ts
|
|
4368
4594
|
var n = (v) => +v.toFixed(1);
|
|
4369
4595
|
function paint(css) {
|
|
@@ -4380,9 +4606,43 @@ function paintAttrs(kind, css) {
|
|
|
4380
4606
|
const { color, opacity } = paint(css);
|
|
4381
4607
|
return `${kind}="${color}"${opacity < 1 ? ` ${kind}-opacity="${n(opacity)}"` : ""}`;
|
|
4382
4608
|
}
|
|
4609
|
+
var DOT_PX = 0.5;
|
|
4610
|
+
var DOT_CELL_PX = 0.25;
|
|
4383
4611
|
function svgCanvas(width, height) {
|
|
4384
4612
|
const out = [];
|
|
4385
|
-
let
|
|
4613
|
+
let subpaths = [];
|
|
4614
|
+
const start = (x, y) => {
|
|
4615
|
+
const s = { d: `M${n(x)} ${n(y)}`, segments: 0, x0: x, x1: x, y0: y, y1: y };
|
|
4616
|
+
subpaths.push(s);
|
|
4617
|
+
return s;
|
|
4618
|
+
};
|
|
4619
|
+
const reach = (points) => {
|
|
4620
|
+
const s = subpaths.at(-1) ?? start(points[0], points[1]);
|
|
4621
|
+
for (let i = 0; i < points.length; i += 2) {
|
|
4622
|
+
s.x0 = Math.min(s.x0, points[i]);
|
|
4623
|
+
s.x1 = Math.max(s.x1, points[i]);
|
|
4624
|
+
s.y0 = Math.min(s.y0, points[i + 1]);
|
|
4625
|
+
s.y1 = Math.max(s.y1, points[i + 1]);
|
|
4626
|
+
}
|
|
4627
|
+
s.segments++;
|
|
4628
|
+
return s;
|
|
4629
|
+
};
|
|
4630
|
+
const pathData = (dots) => {
|
|
4631
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4632
|
+
return subpaths.map((s) => {
|
|
4633
|
+
if (!dots || s.x1 - s.x0 >= DOT_PX || s.y1 - s.y0 >= DOT_PX) {
|
|
4634
|
+
return s.d;
|
|
4635
|
+
}
|
|
4636
|
+
const x = (s.x0 + s.x1) / 2;
|
|
4637
|
+
const y = (s.y0 + s.y1) / 2;
|
|
4638
|
+
const cell = `${Math.round(x / DOT_CELL_PX)} ${Math.round(y / DOT_CELL_PX)}`;
|
|
4639
|
+
if (s.segments === 0 || seen.has(cell)) {
|
|
4640
|
+
return "";
|
|
4641
|
+
}
|
|
4642
|
+
seen.add(cell);
|
|
4643
|
+
return `M${n(x)} ${n(y)}h0`;
|
|
4644
|
+
}).join("");
|
|
4645
|
+
};
|
|
4386
4646
|
const ctx = {
|
|
4387
4647
|
canvas: void 0,
|
|
4388
4648
|
fillStyle: "#000",
|
|
@@ -4391,21 +4651,25 @@ function svgCanvas(width, height) {
|
|
|
4391
4651
|
lineCap: "butt",
|
|
4392
4652
|
lineJoin: "miter",
|
|
4393
4653
|
beginPath() {
|
|
4394
|
-
|
|
4654
|
+
subpaths = [];
|
|
4395
4655
|
},
|
|
4396
4656
|
moveTo(x, y) {
|
|
4397
|
-
|
|
4657
|
+
start(x, y);
|
|
4398
4658
|
},
|
|
4399
4659
|
lineTo(x, y) {
|
|
4400
|
-
d += `L${n(x)} ${n(y)}`;
|
|
4660
|
+
reach([x, y]).d += `L${n(x)} ${n(y)}`;
|
|
4401
4661
|
},
|
|
4402
4662
|
bezierCurveTo(cx0, cy0, cx1, cy1, x, y) {
|
|
4403
|
-
d += `C${n(cx0)} ${n(cy0)} ${n(cx1)} ${n(cy1)} ${n(x)} ${n(y)}`;
|
|
4663
|
+
reach([cx0, cy0, cx1, cy1, x, y]).d += `C${n(cx0)} ${n(cy0)} ${n(cx1)} ${n(cy1)} ${n(x)} ${n(y)}`;
|
|
4404
4664
|
},
|
|
4405
4665
|
closePath() {
|
|
4406
|
-
|
|
4666
|
+
const s = subpaths.at(-1);
|
|
4667
|
+
if (s) {
|
|
4668
|
+
s.d += "Z";
|
|
4669
|
+
}
|
|
4407
4670
|
},
|
|
4408
4671
|
stroke() {
|
|
4672
|
+
const d = pathData(ctx.lineCap !== "butt");
|
|
4409
4673
|
if (d) {
|
|
4410
4674
|
out.push(
|
|
4411
4675
|
`<path d="${d}" fill="none" ${paintAttrs("stroke", ctx.strokeStyle)} stroke-width="${n(ctx.lineWidth)}" stroke-linecap="${ctx.lineCap}" stroke-linejoin="${ctx.lineJoin}"/>`
|
|
@@ -4413,6 +4677,7 @@ function svgCanvas(width, height) {
|
|
|
4413
4677
|
}
|
|
4414
4678
|
},
|
|
4415
4679
|
fill() {
|
|
4680
|
+
const d = pathData(false);
|
|
4416
4681
|
if (d) {
|
|
4417
4682
|
out.push(`<path d="${d}" ${paintAttrs("fill", ctx.fillStyle)}/>`);
|
|
4418
4683
|
}
|
|
@@ -4437,6 +4702,9 @@ function svgCanvas(width, height) {
|
|
|
4437
4702
|
};
|
|
4438
4703
|
}
|
|
4439
4704
|
|
|
4705
|
+
// src/version.ts
|
|
4706
|
+
var version = "4.0.25";
|
|
4707
|
+
|
|
4440
4708
|
// src/viewport.ts
|
|
4441
4709
|
function axisScaleOf(scale, pixelRows) {
|
|
4442
4710
|
return { scaleX: scale, scaleY: pixelRows ? 1 : scale, pixelRows };
|
|
@@ -4484,6 +4752,11 @@ var BAR_PX = 48;
|
|
|
4484
4752
|
var SWATCH_PX = 18;
|
|
4485
4753
|
var KEY_GAP_PX = 16;
|
|
4486
4754
|
var FADED = "rgb(160,160,160)";
|
|
4755
|
+
var EXON_COLOR = "#daa520";
|
|
4756
|
+
var GENE_INK = "#1c1c22";
|
|
4757
|
+
var MIN_LANE_PX = 4;
|
|
4758
|
+
var EXON_GAP_PX = 1;
|
|
4759
|
+
var EXON_LINE_PX = 2;
|
|
4487
4760
|
function esc(s) {
|
|
4488
4761
|
return s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
4489
4762
|
}
|
|
@@ -4512,6 +4785,15 @@ function walkKeySvg(id, x, y, walk, label, reference) {
|
|
|
4512
4785
|
key.scale
|
|
4513
4786
|
);
|
|
4514
4787
|
}
|
|
4788
|
+
function screenPath(d, t) {
|
|
4789
|
+
return d.replaceAll(
|
|
4790
|
+
/([ML])(-?[\d.e-]+),(-?[\d.e-]+)/g,
|
|
4791
|
+
(_, cmd, x, y) => `${cmd}${+(Number(x) * t.scaleX + t.translateX).toFixed(1)},${+(Number(y) * t.scaleY + t.translateY).toFixed(1)}`
|
|
4792
|
+
);
|
|
4793
|
+
}
|
|
4794
|
+
function chip(x, y, w, name, note) {
|
|
4795
|
+
return `<rect x="${x - w / 2}" y="${y - LABEL_PX - LABEL_PAD + 2}" width="${w}" height="${LABEL_PX + LABEL_PAD * 2 - 2}" rx="3" fill="#fff" fill-opacity="0.85" stroke="${EXON_COLOR}"/><text x="${x}" y="${y}" font-family="Helvetica, Arial, sans-serif" font-size="${LABEL_PX}" fill="${GENE_INK}" text-anchor="middle"><tspan font-style="italic" font-weight="600">${esc(name)}</tspan>${note ? esc(note) : ""}</text>`;
|
|
4796
|
+
}
|
|
4515
4797
|
function figureSvg(graph, layout, o = {}) {
|
|
4516
4798
|
const width = o.width ?? 1200;
|
|
4517
4799
|
const room = o.height ?? 800;
|
|
@@ -4538,6 +4820,58 @@ function figureSvg(graph, layout, o = {}) {
|
|
|
4538
4820
|
...lift.referenceDomain,
|
|
4539
4821
|
name: region?.refName
|
|
4540
4822
|
};
|
|
4823
|
+
const contigThickness = o.contigThickness ?? 6;
|
|
4824
|
+
const nodeWidth2 = o.nodeWidth ?? "depth";
|
|
4825
|
+
const pins = o.genes?.length && !layout.tubeMap ? genePins(graph, o.genes, layout.nodePositions) : [];
|
|
4826
|
+
const ink = nodeInk(graph, nodeById, contigThickness, nodeWidth2);
|
|
4827
|
+
let masks = 0;
|
|
4828
|
+
function overlays(highlight, t, w, h) {
|
|
4829
|
+
const out = [];
|
|
4830
|
+
const inkPx = (nodeId) => {
|
|
4831
|
+
const own = ink.halfWidthPx(nodeId) * 2;
|
|
4832
|
+
return highlight?.nodeIds.has(nodeId) ? Math.max(own, highlight.walks.length * MIN_LANE_PX) : own;
|
|
4833
|
+
};
|
|
4834
|
+
const stretches = pins.flatMap(
|
|
4835
|
+
(pin) => pin.exonsByNode.map(({ nodeId, d }) => ({
|
|
4836
|
+
d: screenPath(d, t),
|
|
4837
|
+
inner: inkPx(nodeId) + 2 * EXON_GAP_PX
|
|
4838
|
+
}))
|
|
4839
|
+
);
|
|
4840
|
+
if (stretches.length > 0) {
|
|
4841
|
+
const id = `exons${masks++}`;
|
|
4842
|
+
const stroke = (color, width2, d) => `<path d="${d}" fill="none" stroke="${color}" stroke-width="${width2}" stroke-linecap="round" stroke-linejoin="round"/>`;
|
|
4843
|
+
out.push(
|
|
4844
|
+
`<mask id="${id}" maskUnits="userSpaceOnUse" x="0" y="0" width="${w}" height="${h}">${stretches.map((s) => stroke("#fff", s.inner + 2 * EXON_LINE_PX, s.d)).join("")}${stretches.map((s) => stroke("#000", s.inner, s.d)).join(
|
|
4845
|
+
""
|
|
4846
|
+
)}</mask><rect width="${w}" height="${h}" fill="${EXON_COLOR}" mask="url(#${id})"/>`
|
|
4847
|
+
);
|
|
4848
|
+
}
|
|
4849
|
+
const screen = (p) => ({
|
|
4850
|
+
x: p.x * t.scaleX + t.translateX,
|
|
4851
|
+
y: p.y * t.scaleY + t.translateY
|
|
4852
|
+
});
|
|
4853
|
+
const frame = { width: w, height: h };
|
|
4854
|
+
for (const { item: pin, x, y, w: cw, text } of placeLabels(
|
|
4855
|
+
geneLabelCandidates(pins, screen, contigThickness),
|
|
4856
|
+
frame,
|
|
4857
|
+
occupancy(frame)
|
|
4858
|
+
)) {
|
|
4859
|
+
const pinY = screen(pin.at).y + contigThickness / 2;
|
|
4860
|
+
out.push(
|
|
4861
|
+
`<line x1="${x}" x2="${x}" y1="${y - LABEL_PX - 2}" y2="${pinY}" stroke="${GENE_INK}" stroke-width="0.8" stroke-opacity="0.6"/>`,
|
|
4862
|
+
chip(x, y, cw, pin.gene.name, text.slice(pin.gene.name.length))
|
|
4863
|
+
);
|
|
4864
|
+
}
|
|
4865
|
+
for (const { label, y } of layout.rowLabels ?? []) {
|
|
4866
|
+
const sy = y * t.scaleY + t.translateY;
|
|
4867
|
+
if (sy >= 0 && sy <= h) {
|
|
4868
|
+
out.push(
|
|
4869
|
+
`<text x="6" y="${sy + 4}" ${FONT} stroke="#fff" stroke-width="3" paint-order="stroke">${esc(label)}</text>`
|
|
4870
|
+
);
|
|
4871
|
+
}
|
|
4872
|
+
}
|
|
4873
|
+
return out.join("");
|
|
4874
|
+
}
|
|
4541
4875
|
function drawing(highlight, w, h) {
|
|
4542
4876
|
const fit = fitTransform(
|
|
4543
4877
|
bounds,
|
|
@@ -4563,10 +4897,10 @@ function figureSvg(graph, layout, o = {}) {
|
|
|
4563
4897
|
graph,
|
|
4564
4898
|
nodeById,
|
|
4565
4899
|
colorScheme,
|
|
4566
|
-
contigThickness
|
|
4900
|
+
contigThickness,
|
|
4567
4901
|
connectorThickness: o.connectorThickness ?? 2,
|
|
4568
4902
|
drawPaths: false,
|
|
4569
|
-
nodeWidth:
|
|
4903
|
+
nodeWidth: nodeWidth2,
|
|
4570
4904
|
highlight,
|
|
4571
4905
|
axis,
|
|
4572
4906
|
referenceRamp,
|
|
@@ -4576,15 +4910,15 @@ function figureSvg(graph, layout, o = {}) {
|
|
|
4576
4910
|
)
|
|
4577
4911
|
})
|
|
4578
4912
|
);
|
|
4579
|
-
|
|
4913
|
+
const t = {
|
|
4580
4914
|
scaleX: axis.scaleX,
|
|
4581
4915
|
scaleY: axis.scaleY,
|
|
4582
4916
|
translateX: fit.translateX,
|
|
4583
|
-
translateY: fit.translateY
|
|
4584
|
-
|
|
4585
|
-
});
|
|
4917
|
+
translateY: fit.translateY
|
|
4918
|
+
};
|
|
4919
|
+
renderer.updateTransform({ ...t, dpr: 1 });
|
|
4586
4920
|
renderer.render([1, 1, 1, 1]);
|
|
4587
|
-
return markup();
|
|
4921
|
+
return markup() + overlays(highlight, t, w, h);
|
|
4588
4922
|
}
|
|
4589
4923
|
const parts = [];
|
|
4590
4924
|
let height;
|
|
@@ -4663,10 +4997,169 @@ function figureSvg(graph, layout, o = {}) {
|
|
|
4663
4997
|
);
|
|
4664
4998
|
height = header + h;
|
|
4665
4999
|
}
|
|
4666
|
-
|
|
5000
|
+
const metadata = JSON.stringify({
|
|
5001
|
+
generator: `@jbrowse/bandage-core@${version}`,
|
|
5002
|
+
...o.spec === void 0 ? {} : { spec: o.spec }
|
|
5003
|
+
});
|
|
5004
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><metadata>${esc(metadata)}</metadata><rect width="${width}" height="${height}" fill="#fff"/>${parts.join("")}</svg>
|
|
4667
5005
|
`;
|
|
4668
5006
|
}
|
|
4669
5007
|
|
|
5008
|
+
// src/genes/geneFiles.ts
|
|
5009
|
+
var GENE_TYPE = /(gene|gene_segment|RNA|transcript)$/i;
|
|
5010
|
+
var isGene = (type) => GENE_TYPE.test(type) || type === "CDS" || type === "exon";
|
|
5011
|
+
function mergedIntervals(intervals) {
|
|
5012
|
+
const out = [];
|
|
5013
|
+
for (const iv of [...intervals].sort((a, b) => a.start - b.start)) {
|
|
5014
|
+
const last = out.at(-1);
|
|
5015
|
+
if (last && iv.start <= last.end) {
|
|
5016
|
+
last.end = Math.max(last.end, iv.end);
|
|
5017
|
+
} else {
|
|
5018
|
+
out.push({ ...iv });
|
|
5019
|
+
}
|
|
5020
|
+
}
|
|
5021
|
+
return out;
|
|
5022
|
+
}
|
|
5023
|
+
function strandOf(s) {
|
|
5024
|
+
return s === "+" ? 1 : s === "-" ? -1 : 0;
|
|
5025
|
+
}
|
|
5026
|
+
function unescape(value) {
|
|
5027
|
+
try {
|
|
5028
|
+
return decodeURIComponent(value);
|
|
5029
|
+
} catch {
|
|
5030
|
+
return value;
|
|
5031
|
+
}
|
|
5032
|
+
}
|
|
5033
|
+
function attributes(column) {
|
|
5034
|
+
const out = /* @__PURE__ */ new Map();
|
|
5035
|
+
for (const pair of column.split(";")) {
|
|
5036
|
+
const eq = pair.indexOf("=");
|
|
5037
|
+
if (eq > 0) {
|
|
5038
|
+
out.set(pair.slice(0, eq).trim(), unescape(pair.slice(eq + 1).trim()));
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
5041
|
+
return out;
|
|
5042
|
+
}
|
|
5043
|
+
function gff3Row(line) {
|
|
5044
|
+
const cols = line.split(" ");
|
|
5045
|
+
const start = Number(cols[3]);
|
|
5046
|
+
const end = Number(cols[4]);
|
|
5047
|
+
if (cols.length < 9 || !Number.isInteger(start) || !Number.isInteger(end)) {
|
|
5048
|
+
return void 0;
|
|
5049
|
+
}
|
|
5050
|
+
return {
|
|
5051
|
+
refName: cols[0],
|
|
5052
|
+
type: cols[2],
|
|
5053
|
+
start: start - 1,
|
|
5054
|
+
end,
|
|
5055
|
+
strand: strandOf(cols[6]),
|
|
5056
|
+
attrs: attributes(cols[8])
|
|
5057
|
+
};
|
|
5058
|
+
}
|
|
5059
|
+
function genesFromGff3Lines(lines) {
|
|
5060
|
+
const rows = [];
|
|
5061
|
+
for (const line of lines) {
|
|
5062
|
+
if (line.startsWith("##FASTA")) {
|
|
5063
|
+
break;
|
|
5064
|
+
}
|
|
5065
|
+
const row = line.startsWith("#") ? void 0 : gff3Row(line);
|
|
5066
|
+
if (row) {
|
|
5067
|
+
rows.push(row);
|
|
5068
|
+
}
|
|
5069
|
+
}
|
|
5070
|
+
const parentOf = /* @__PURE__ */ new Map();
|
|
5071
|
+
for (const { attrs } of rows) {
|
|
5072
|
+
const id = attrs.get("ID");
|
|
5073
|
+
const parent = attrs.get("Parent")?.split(",")[0];
|
|
5074
|
+
if (id && parent) {
|
|
5075
|
+
parentOf.set(id, parent);
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
5078
|
+
const rootOf = (row) => {
|
|
5079
|
+
let id = row.attrs.get("Parent")?.split(",")[0] ?? row.attrs.get("ID");
|
|
5080
|
+
if (!id) {
|
|
5081
|
+
return row.attrs.get("gene_id");
|
|
5082
|
+
}
|
|
5083
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5084
|
+
while (id && parentOf.has(id) && !seen.has(id)) {
|
|
5085
|
+
seen.add(id);
|
|
5086
|
+
id = parentOf.get(id);
|
|
5087
|
+
}
|
|
5088
|
+
return id;
|
|
5089
|
+
};
|
|
5090
|
+
const groups = /* @__PURE__ */ new Map();
|
|
5091
|
+
rows.forEach((row, i) => {
|
|
5092
|
+
const root = rootOf(row) ?? `#${i}`;
|
|
5093
|
+
const key = `${row.refName} ${root}`;
|
|
5094
|
+
const group = groups.get(key) ?? groups.set(key, { rows: [] }).get(key);
|
|
5095
|
+
group.rows.push(row);
|
|
5096
|
+
if (!row.attrs.has("Parent") && !group.top) {
|
|
5097
|
+
group.top = row;
|
|
5098
|
+
}
|
|
5099
|
+
});
|
|
5100
|
+
const genes = [];
|
|
5101
|
+
for (const [key, { top, rows: rows2 }] of groups) {
|
|
5102
|
+
if (top && !isGene(top.type)) {
|
|
5103
|
+
continue;
|
|
5104
|
+
}
|
|
5105
|
+
const first = top ?? rows2[0];
|
|
5106
|
+
const start = top?.start ?? Math.min(...rows2.map((r) => r.start));
|
|
5107
|
+
const end = top?.end ?? Math.max(...rows2.map((r) => r.end));
|
|
5108
|
+
const a = first.attrs;
|
|
5109
|
+
const exons = rows2.filter((r) => r.type === "exon").map((r) => ({ start: r.start, end: r.end }));
|
|
5110
|
+
genes.push({
|
|
5111
|
+
name: a.get("Name") ?? a.get("gene_name") ?? a.get("gene") ?? a.get("gene_id") ?? key.split(" ")[1],
|
|
5112
|
+
refName: first.refName,
|
|
5113
|
+
start,
|
|
5114
|
+
end,
|
|
5115
|
+
strand: first.strand,
|
|
5116
|
+
exons: exons.length ? mergedIntervals(exons) : [{ start, end }]
|
|
5117
|
+
});
|
|
5118
|
+
}
|
|
5119
|
+
return genes;
|
|
5120
|
+
}
|
|
5121
|
+
function genesFromBed(text) {
|
|
5122
|
+
const genes = /* @__PURE__ */ new Map();
|
|
5123
|
+
for (const line of text.split("\n")) {
|
|
5124
|
+
const cols = line.replace(/\r$/, "").split(" ");
|
|
5125
|
+
const start = Number(cols[1]);
|
|
5126
|
+
const end = Number(cols[2]);
|
|
5127
|
+
if (/^(#|track|browser)/.test(line) || cols.length < 3 || !Number.isInteger(start) || !(end > start)) {
|
|
5128
|
+
continue;
|
|
5129
|
+
}
|
|
5130
|
+
const refName = cols[0];
|
|
5131
|
+
const name = cols[3] || `${refName}:${start + 1}-${end}`;
|
|
5132
|
+
const sizes = cols[10]?.split(",").filter((s) => s !== "").map(Number);
|
|
5133
|
+
const starts = cols[11]?.split(",").filter((s) => s !== "").map(Number);
|
|
5134
|
+
const blocks = sizes?.length && sizes.length === starts?.length ? sizes.map((size, i) => ({
|
|
5135
|
+
start: start + starts[i],
|
|
5136
|
+
end: start + starts[i] + size
|
|
5137
|
+
})) : [{ start, end }];
|
|
5138
|
+
const key = `${refName} ${name}`;
|
|
5139
|
+
const gene = genes.get(key);
|
|
5140
|
+
if (gene) {
|
|
5141
|
+
gene.start = Math.min(gene.start, start);
|
|
5142
|
+
gene.end = Math.max(gene.end, end);
|
|
5143
|
+
gene.exons = mergedIntervals([...gene.exons, ...blocks]);
|
|
5144
|
+
} else {
|
|
5145
|
+
genes.set(key, {
|
|
5146
|
+
name,
|
|
5147
|
+
refName,
|
|
5148
|
+
start,
|
|
5149
|
+
end,
|
|
5150
|
+
strand: strandOf(cols[5]),
|
|
5151
|
+
exons: mergedIntervals(blocks)
|
|
5152
|
+
});
|
|
5153
|
+
}
|
|
5154
|
+
}
|
|
5155
|
+
return [...genes.values()];
|
|
5156
|
+
}
|
|
5157
|
+
function genesFromText(text) {
|
|
5158
|
+
const first = text.split("\n", 1e3).find((l) => l.trim() !== "" && !/^(#|track|browser)/.test(l));
|
|
5159
|
+
const cols = first?.split(" ") ?? [];
|
|
5160
|
+
return /^\d+$/.test(cols[1] ?? "") && /^\d+$/.test(cols[2] ?? "") ? genesFromBed(text) : genesFromGff3Lines(text.split(/\r?\n/));
|
|
5161
|
+
}
|
|
5162
|
+
|
|
4670
5163
|
// src/reference.ts
|
|
4671
5164
|
var WELL_KNOWN_SAMPLES = /* @__PURE__ */ new Map([
|
|
4672
5165
|
["hg38", "GRCh38"],
|
|
@@ -4841,9 +5334,9 @@ function resolveReferenceSample({
|
|
|
4841
5334
|
}
|
|
4842
5335
|
return sample;
|
|
4843
5336
|
}
|
|
4844
|
-
async function referencePathQuery(db,
|
|
5337
|
+
async function referencePathQuery(db, referenceSample2, refName) {
|
|
4845
5338
|
const path = (await db.paths()).find(
|
|
4846
|
-
(p) => p.isIndexed && p.name.sample ===
|
|
5339
|
+
(p) => p.isIndexed && p.name.sample === referenceSample2 && p.name.contig === refName
|
|
4847
5340
|
);
|
|
4848
5341
|
return path ? {
|
|
4849
5342
|
sample: path.name.sample,
|
|
@@ -4872,6 +5365,60 @@ async function cutWindowGFA(db, query, start, end, { keep, ...opts }) {
|
|
|
4872
5365
|
return subgraph ? subgraph.toGFA({ names: "resolved" }) : "";
|
|
4873
5366
|
}
|
|
4874
5367
|
|
|
5368
|
+
// src/gbzCut.ts
|
|
5369
|
+
import { GBZBase } from "@gmod/gbz-base";
|
|
5370
|
+
var HPRC_GBZ = {
|
|
5371
|
+
db: "https://s3-us-west-2.amazonaws.com/human-pangenomics/pangenomes/freeze/release2/minigraph-cactus/v2.1/hprc-v2.1-mc-grch38/hprc-v2.1-mc-grch38.gbz.db",
|
|
5372
|
+
index: "https://jbrowse.org/demos/hprc/hprc-v2.1-mc-grch38.haplotype-index.anchored.db"
|
|
5373
|
+
};
|
|
5374
|
+
var WALK_LIMIT = 1e5;
|
|
5375
|
+
function parseRegion(text) {
|
|
5376
|
+
const m = /^\s*([^:\s]+):([\d,]+)-([\d,]+)\s*$/.exec(text);
|
|
5377
|
+
if (!m) {
|
|
5378
|
+
throw new Error(
|
|
5379
|
+
`"${text}" is not a region like chr6:160,614,798-160,647,758`
|
|
5380
|
+
);
|
|
5381
|
+
}
|
|
5382
|
+
const n2 = (s) => Number(s.replaceAll(",", ""));
|
|
5383
|
+
return { refName: m[1], start: n2(m[2]), end: n2(m[3]) };
|
|
5384
|
+
}
|
|
5385
|
+
async function openGbz(db, index) {
|
|
5386
|
+
const base = await GBZBase.open(db, index ? { haplotypeIndex: index } : {});
|
|
5387
|
+
return { base, referenceSamples: await referenceSamplesOf(base) };
|
|
5388
|
+
}
|
|
5389
|
+
function referenceSample(ref, samples) {
|
|
5390
|
+
try {
|
|
5391
|
+
return resolveReferenceSample({
|
|
5392
|
+
configured: "",
|
|
5393
|
+
anchorPrefix: ref ?? samples[0] ?? "",
|
|
5394
|
+
referenceSamples: samples
|
|
5395
|
+
});
|
|
5396
|
+
} catch (e) {
|
|
5397
|
+
if (ref) {
|
|
5398
|
+
return ref;
|
|
5399
|
+
}
|
|
5400
|
+
throw e;
|
|
5401
|
+
}
|
|
5402
|
+
}
|
|
5403
|
+
async function cutGbzRegion({ base, referenceSamples }, src, signal) {
|
|
5404
|
+
const region = parseRegion(src.region);
|
|
5405
|
+
const sample = referenceSample(src.referenceSample, referenceSamples);
|
|
5406
|
+
const query = await referencePathQuery(base, sample, region.refName);
|
|
5407
|
+
if (!query) {
|
|
5408
|
+
throw new Error(`${sample} has no indexed path named ${region.refName}`);
|
|
5409
|
+
}
|
|
5410
|
+
signal?.throwIfAborted();
|
|
5411
|
+
const wanted = src.haplotypes?.length ? src.haplotypes : void 0;
|
|
5412
|
+
const text = await cutWindowGFA(base, query, region.start, region.end, {
|
|
5413
|
+
context: src.context ?? 1e3,
|
|
5414
|
+
snarls: src.snarls ?? "contained",
|
|
5415
|
+
limit: WALK_LIMIT,
|
|
5416
|
+
signal,
|
|
5417
|
+
...wanted ? { keep: (name) => haplotypeWanted(name, wanted) } : {}
|
|
5418
|
+
});
|
|
5419
|
+
return { text, region, sample };
|
|
5420
|
+
}
|
|
5421
|
+
|
|
4875
5422
|
// src/loadBandage.ts
|
|
4876
5423
|
var cached;
|
|
4877
5424
|
function loadBandage() {
|
|
@@ -4884,12 +5431,10 @@ function loadBandage() {
|
|
|
4884
5431
|
|
|
4885
5432
|
export {
|
|
4886
5433
|
isBackbone,
|
|
4887
|
-
firstNodeAtOrAfter,
|
|
4888
5434
|
BUBBLE_SPREADS,
|
|
4889
5435
|
panSNSample,
|
|
4890
5436
|
panSNHaplotype,
|
|
4891
5437
|
panSNContig,
|
|
4892
|
-
polylineSlice,
|
|
4893
5438
|
loadGraph,
|
|
4894
5439
|
engineRequest,
|
|
4895
5440
|
engineKey,
|
|
@@ -4935,13 +5480,7 @@ export {
|
|
|
4935
5480
|
LABEL_PX,
|
|
4936
5481
|
LABEL_CHAR_PX,
|
|
4937
5482
|
LABEL_PAD,
|
|
4938
|
-
occupancy,
|
|
4939
|
-
placeLabels,
|
|
4940
|
-
rowLabelBox,
|
|
4941
5483
|
formatBp,
|
|
4942
|
-
sizeLabelCandidates,
|
|
4943
|
-
nodeLabelBudget,
|
|
4944
|
-
placeSizeLabels,
|
|
4945
5484
|
WALK_FIELDS,
|
|
4946
5485
|
WALK_SCHEMES,
|
|
4947
5486
|
resolveEncoding,
|
|
@@ -4953,12 +5492,19 @@ export {
|
|
|
4953
5492
|
facetLifts,
|
|
4954
5493
|
rangeText,
|
|
4955
5494
|
walkKey,
|
|
5495
|
+
walkPosition,
|
|
4956
5496
|
FACET_GAP_PX,
|
|
4957
5497
|
FACET_TITLE_PX,
|
|
4958
5498
|
FACET_PAD_PX,
|
|
4959
5499
|
facetGrid,
|
|
4960
5500
|
facetCells,
|
|
5501
|
+
genePins,
|
|
5502
|
+
HALO_FACTOR,
|
|
5503
|
+
LEGEND_INSET_PX,
|
|
5504
|
+
geneCoverageNote,
|
|
5505
|
+
layoutLabels,
|
|
4961
5506
|
svgCanvas,
|
|
5507
|
+
version,
|
|
4962
5508
|
axisScaleOf,
|
|
4963
5509
|
viewportOf,
|
|
4964
5510
|
padded,
|
|
@@ -4966,6 +5512,9 @@ export {
|
|
|
4966
5512
|
zoomAbout,
|
|
4967
5513
|
screenToLayout,
|
|
4968
5514
|
figureSvg,
|
|
5515
|
+
genesFromGff3Lines,
|
|
5516
|
+
genesFromBed,
|
|
5517
|
+
genesFromText,
|
|
4969
5518
|
WELL_KNOWN_SAMPLES,
|
|
4970
5519
|
wellKnownSample,
|
|
4971
5520
|
graphBackbone,
|
|
@@ -4978,5 +5527,9 @@ export {
|
|
|
4978
5527
|
resolveReferenceSample,
|
|
4979
5528
|
referencePathQuery,
|
|
4980
5529
|
cutWindowGFA,
|
|
5530
|
+
HPRC_GBZ,
|
|
5531
|
+
parseRegion,
|
|
5532
|
+
openGbz,
|
|
5533
|
+
cutGbzRegion,
|
|
4981
5534
|
loadBandage
|
|
4982
5535
|
};
|