@jbrowse/bandage-core 0.1.16 → 0.1.18
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/README.md +4 -2
- package/dist/index.js +216 -101
- package/dist/types/facetGrid.d.ts +21 -0
- package/dist/types/index.d.ts +5 -2
- package/dist/types/pipeline.d.ts +3 -1
- package/dist/types/referenceStrip.d.ts +2 -1
- package/dist/types/renderer/GeometryBuilder.d.ts +1 -0
- package/dist/types/walkEncoding.d.ts +23 -42
- package/dist/types/walkHighlight.d.ts +12 -0
- package/dist/types/walkKey.d.ts +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,11 +9,13 @@ npm install @jbrowse/bandage-core
|
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
- GFA and rGFA text in (`loadGraph`)
|
|
12
|
-
- Layouts: Bandage's FMMM engine as WASM (`loadBandage`, `forceLayout`),
|
|
13
|
-
|
|
12
|
+
- Layouts: Bandage's FMMM engine as WASM (`loadBandage`, `forceLayout`),
|
|
13
|
+
ordered, anchored, sample rows, walk rows, tube map
|
|
14
14
|
- A Canvas2D renderer (`buildGeometry`, `Canvas2DRenderer`), hit testing and
|
|
15
15
|
label placement
|
|
16
16
|
- Bubbles, deletion edges, path colors, gbz-base windows cut to GFA
|
|
17
|
+
- Walks lifted out of the drawing (`walkLift`), one facet panel per walk
|
|
18
|
+
(`facetLifts`, `facetGrid`) and each walk's key in words (`walkKey`)
|
|
17
19
|
- Which assembly a backbone lies on (`graphBackbone`, `backboneAssembly`,
|
|
18
20
|
`assemblyWalk`), and the genes on it: `featuresOnBackbone` renames an
|
|
19
21
|
assembly's genes onto the backbone's refNames, and `genePins` pins only those
|
package/dist/index.js
CHANGED
|
@@ -979,9 +979,15 @@ function fittedTranslateY(bounds, usableHeight, yScale, padTop = FIT_PADDING) {
|
|
|
979
979
|
const leftoverY = usableHeight - bounds.h * yScale;
|
|
980
980
|
return padTop - bounds.minY * yScale + Math.max(0, leftoverY) / 2;
|
|
981
981
|
}
|
|
982
|
-
function fitTransform(bounds, paneWidth, paneHeight, pixelRows, {
|
|
983
|
-
|
|
984
|
-
|
|
982
|
+
function fitTransform(bounds, paneWidth, paneHeight, pixelRows, {
|
|
983
|
+
minScale = 0,
|
|
984
|
+
padLeft = FIT_PADDING,
|
|
985
|
+
padTop = FIT_PADDING,
|
|
986
|
+
padRight = FIT_PADDING,
|
|
987
|
+
padBottom = FIT_PADDING
|
|
988
|
+
} = {}) {
|
|
989
|
+
const usableWidth = paneWidth - padLeft - padRight;
|
|
990
|
+
const usableHeight = paneHeight - padTop - padBottom;
|
|
985
991
|
if (usableWidth <= 0 || usableHeight <= 0 || !(bounds.w > 0 || !pixelRows && bounds.h > 0)) {
|
|
986
992
|
return void 0;
|
|
987
993
|
}
|
|
@@ -2855,10 +2861,11 @@ var EDGE_DEFAULT_COLOR = packAbgr2(119, 119, 119, 217);
|
|
|
2855
2861
|
var EDGE_PATH_FALLBACK_COLOR = packAbgr2(136, 136, 136, 217);
|
|
2856
2862
|
var EDGE_DELETION_COLOR = packAbgr2(24, 24, 28, 240);
|
|
2857
2863
|
var DELETION_THICKNESS_FACTOR = 2.2;
|
|
2864
|
+
var LIFT_BACKDROP_COLOR = packAbgr2(160, 160, 160, 255);
|
|
2858
2865
|
var FADED_ALPHA = 0.18;
|
|
2859
2866
|
var DELETION_DASH_PX = 11;
|
|
2860
2867
|
var MIN_PATH_STRIPE_PX = 1.2;
|
|
2861
|
-
var MIN_WALK_LANE_PX =
|
|
2868
|
+
var MIN_WALK_LANE_PX = 4;
|
|
2862
2869
|
var MIN_SCALE_FOR_OFFSET = 1e-6;
|
|
2863
2870
|
var ARROW_LENGTH_BASE_PX = 7;
|
|
2864
2871
|
var ARROW_LENGTH_PER_EDGE_PX = 3;
|
|
@@ -3445,13 +3452,13 @@ function buildGeometry(options) {
|
|
|
3445
3452
|
if (viewportBounds && !isPolylineInBounds(segments, viewportBounds)) {
|
|
3446
3453
|
continue;
|
|
3447
3454
|
}
|
|
3448
|
-
const
|
|
3455
|
+
const faded = highlight !== void 0 && !highlight.nodeIds.has(nodeId);
|
|
3456
|
+
const own = faded ? LIFT_BACKDROP_COLOR : getNodeColor(
|
|
3449
3457
|
node,
|
|
3450
3458
|
nodeIndexMap.get(nodeId) ?? 0,
|
|
3451
3459
|
colorScheme,
|
|
3452
3460
|
colorRange
|
|
3453
3461
|
);
|
|
3454
|
-
const faded = highlight !== void 0 && !highlight.nodeIds.has(nodeId);
|
|
3455
3462
|
const color = faded ? fadeAbgr(own, FADED_ALPHA) : own;
|
|
3456
3463
|
const width = nodeWidthPx(node, contigThickness, nodeWidth2, depthNorm);
|
|
3457
3464
|
const nodeThickness = width / 2;
|
|
@@ -4081,13 +4088,14 @@ var OVERHANG_PX = 5;
|
|
|
4081
4088
|
function referenceStripBlocks(graph, {
|
|
4082
4089
|
colorScheme,
|
|
4083
4090
|
referenceRamp,
|
|
4084
|
-
walkNodes
|
|
4091
|
+
walkNodes,
|
|
4092
|
+
walkColors
|
|
4085
4093
|
}) {
|
|
4086
4094
|
const range = { ...computeColorSchemeRange(graph), referenceRamp };
|
|
4087
4095
|
const out = [];
|
|
4088
4096
|
graph.nodes.forEach((node, index) => {
|
|
4089
4097
|
if (isBackbone(node)) {
|
|
4090
|
-
const own = getNodeColor(node, index, colorScheme, range);
|
|
4098
|
+
const own = walkNodes ? walkColors?.get(node.id) ?? LIFT_BACKDROP_COLOR : getNodeColor(node, index, colorScheme, range);
|
|
4091
4099
|
out.push({
|
|
4092
4100
|
node: node.id,
|
|
4093
4101
|
bp0: node.stable.start,
|
|
@@ -5243,81 +5251,79 @@ function drawTubeMapConnectors(ctx, connectors, bottom, {
|
|
|
5243
5251
|
// src/walkEncoding.ts
|
|
5244
5252
|
import { packAbgr as packAbgr3 } from "@jbrowse/core/util/colorBits";
|
|
5245
5253
|
var WALK_FIELDS = [
|
|
5246
|
-
{
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
legend: "pale where the walk starts, deep where it ends"
|
|
5250
|
-
},
|
|
5251
|
-
{
|
|
5252
|
-
value: "reference",
|
|
5253
|
-
label: "Reference position",
|
|
5254
|
-
legend: "along the reference left to right, charcoal off it"
|
|
5255
|
-
},
|
|
5256
|
-
{
|
|
5257
|
-
value: "strand",
|
|
5258
|
-
label: "Strand against the reference",
|
|
5259
|
-
legend: "pale where the walk runs as the reference does, deep where reversed"
|
|
5260
|
-
},
|
|
5261
|
-
{
|
|
5262
|
-
value: "visits",
|
|
5263
|
-
label: "Visits",
|
|
5264
|
-
legend: "pale where the walk passes once, deep four times or more"
|
|
5265
|
-
}
|
|
5254
|
+
{ value: "progress", label: "Progress along the walk" },
|
|
5255
|
+
{ value: "walk", label: "One colour for the walk" },
|
|
5256
|
+
{ value: "reference", label: "Reference position" }
|
|
5266
5257
|
];
|
|
5267
5258
|
var WALK_SCHEMES = [
|
|
5268
|
-
{ value: "
|
|
5269
|
-
{ value: "
|
|
5270
|
-
{ value: "
|
|
5271
|
-
{ value: "
|
|
5272
|
-
{ value: "
|
|
5273
|
-
{ value: "
|
|
5274
|
-
{ value: "greys", label: "Greys" }
|
|
5275
|
-
];
|
|
5276
|
-
var DEFAULT_FAMILIES = [
|
|
5277
|
-
"blues",
|
|
5278
|
-
"reds",
|
|
5279
|
-
"greens",
|
|
5280
|
-
"oranges",
|
|
5281
|
-
"purples"
|
|
5259
|
+
{ value: "grey", label: "Grey to black", ends: ["#a3a3a3", "#151515"] },
|
|
5260
|
+
{ value: "blue", label: "Cyan to navy", ends: ["#6ee0f0", "#0b2c7a"] },
|
|
5261
|
+
{ value: "red", label: "Yellow to red", ends: ["#ffd24a", "#b3121b"] },
|
|
5262
|
+
{ value: "purple", label: "Pink to plum", ends: ["#f5a3d8", "#5e1a6e"] },
|
|
5263
|
+
{ value: "green", label: "Lime to forest", ends: ["#b6e36c", "#0b5d3b"] },
|
|
5264
|
+
{ value: "rainbow", label: "Rainbow" }
|
|
5282
5265
|
];
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
};
|
|
5266
|
+
var FAMILIES = ["blue", "red", "purple", "green"];
|
|
5267
|
+
var isField = (v) => WALK_FIELDS.some((f) => f.value === v);
|
|
5268
|
+
var isScheme = (v) => WALK_SCHEMES.some((s) => s.value === v);
|
|
5269
|
+
function resolveEncoding(layer, reference, picked, alone = true) {
|
|
5270
|
+
const { field: askedField, scheme: askedScheme } = layer.color ?? {};
|
|
5271
|
+
const field = isField(askedField) ? askedField : alone ? "progress" : "walk";
|
|
5272
|
+
const family = reference ? "grey" : FAMILIES[picked % FAMILIES.length];
|
|
5273
|
+
const scheme = isScheme(askedScheme) ? askedScheme === "rainbow" && field !== "reference" ? family : askedScheme : family;
|
|
5274
|
+
return { field, scheme };
|
|
5275
|
+
}
|
|
5276
|
+
var BASE_T = 0.5;
|
|
5277
|
+
var toLinear = (c) => c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
5278
|
+
var toGamma = (c) => c <= 31308e-7 ? c * 12.92 : 1.055 * c ** (1 / 2.4) - 0.055;
|
|
5279
|
+
function oklab(hex) {
|
|
5280
|
+
const [r, g, b] = [1, 3, 5].map(
|
|
5281
|
+
(i) => toLinear(Number.parseInt(hex.slice(i, i + 2), 16) / 255)
|
|
5282
|
+
);
|
|
5283
|
+
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
5284
|
+
const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
|
|
5285
|
+
const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
|
|
5286
|
+
return [
|
|
5287
|
+
0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
|
|
5288
|
+
1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
|
|
5289
|
+
0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
|
|
5290
|
+
];
|
|
5288
5291
|
}
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
+
function oklabToRgb([L, a, b]) {
|
|
5293
|
+
const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;
|
|
5294
|
+
const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;
|
|
5295
|
+
const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;
|
|
5296
|
+
return [
|
|
5297
|
+
4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
|
|
5298
|
+
-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
|
|
5299
|
+
-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
|
|
5300
|
+
].map((c) => toGamma(Math.max(0, Math.min(1, c))) * 255);
|
|
5301
|
+
}
|
|
5302
|
+
function schemeRgb(scheme, t) {
|
|
5292
5303
|
const x = Math.max(0, Math.min(1, t));
|
|
5293
|
-
if (scheme === "rainbow") {
|
|
5294
|
-
return { h: x * REFERENCE_RAMP_MAX_HUE, s: 0.7, l: 0.5 };
|
|
5295
|
-
}
|
|
5296
5304
|
const family = WALK_SCHEMES.find((s) => s.value === scheme);
|
|
5297
|
-
|
|
5298
|
-
|
|
5305
|
+
if (!family || !("ends" in family)) {
|
|
5306
|
+
return hslToRgb(x * REFERENCE_RAMP_MAX_HUE, 0.7, 0.5).map((c) => c * 255);
|
|
5307
|
+
}
|
|
5308
|
+
const from = oklab(family.ends[0]);
|
|
5309
|
+
const to = oklab(family.ends[1]);
|
|
5310
|
+
return oklabToRgb(from.map((v, i) => v + (to[i] - v) * x));
|
|
5299
5311
|
}
|
|
5300
5312
|
function schemeCss(scheme, t) {
|
|
5301
|
-
const
|
|
5302
|
-
return `
|
|
5313
|
+
const [r, g, b] = schemeRgb(scheme, t).map(Math.round);
|
|
5314
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
5303
5315
|
}
|
|
5304
5316
|
function schemeColor(scheme, t) {
|
|
5305
|
-
const
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
Math.round(b * 255),
|
|
5311
|
-
255
|
|
5312
|
-
);
|
|
5317
|
+
const [r, g, b] = schemeRgb(scheme, t).map(Math.round);
|
|
5318
|
+
return packAbgr3(r, g, b, 255);
|
|
5319
|
+
}
|
|
5320
|
+
function encodedColor({ field, scheme }, t) {
|
|
5321
|
+
return field === "walk" ? schemeColor(scheme, BASE_T) : t === void 0 ? NO_VALUE_COLOR : schemeColor(scheme, t);
|
|
5313
5322
|
}
|
|
5314
5323
|
var NO_VALUE_COLOR = REFERENCE_RAMP_ALT_COLOR;
|
|
5315
|
-
var STRAND_T = { same: 0.2, reversed: 0.95 };
|
|
5316
5324
|
function encodingSwatchCss({ field, scheme }) {
|
|
5317
|
-
if (field === "
|
|
5318
|
-
|
|
5319
|
-
const reversed = schemeCss(scheme, STRAND_T.reversed);
|
|
5320
|
-
return `linear-gradient(to right, ${same} 50%, ${reversed} 50%)`;
|
|
5325
|
+
if (field === "walk") {
|
|
5326
|
+
return schemeCss(scheme, BASE_T);
|
|
5321
5327
|
}
|
|
5322
5328
|
const stops = Array.from({ length: 7 }, (_, i) => {
|
|
5323
5329
|
const t = i / 6;
|
|
@@ -5325,9 +5331,6 @@ function encodingSwatchCss({ field, scheme }) {
|
|
|
5325
5331
|
});
|
|
5326
5332
|
return `linear-gradient(to right, ${stops.join(", ")})`;
|
|
5327
5333
|
}
|
|
5328
|
-
function fieldLegend(field) {
|
|
5329
|
-
return WALK_FIELDS.find((f) => f.value === field).legend;
|
|
5330
|
-
}
|
|
5331
5334
|
|
|
5332
5335
|
// src/walkHighlight.ts
|
|
5333
5336
|
function referenceOf(graph) {
|
|
@@ -5364,9 +5367,16 @@ function walkHighlight(graph, name) {
|
|
|
5364
5367
|
before += length;
|
|
5365
5368
|
}
|
|
5366
5369
|
const reference = referenceOf(graph);
|
|
5370
|
+
const originName = pathOrigin(name).name;
|
|
5371
|
+
const origin = graph.anchorPaths?.find((a) => a.name === originName && a.length === bp) ?? graph.anchorPaths?.find((a) => a.name === originName);
|
|
5367
5372
|
return {
|
|
5368
5373
|
name,
|
|
5369
5374
|
reference: reference === path,
|
|
5375
|
+
range: origin ? {
|
|
5376
|
+
contig: path.contig ?? panSNContig(origin.name),
|
|
5377
|
+
start: origin.start,
|
|
5378
|
+
end: origin.start + origin.length
|
|
5379
|
+
} : void 0,
|
|
5370
5380
|
nodeIds: new Set(path.nodeIds),
|
|
5371
5381
|
edgeIndexes,
|
|
5372
5382
|
progress,
|
|
@@ -5375,37 +5385,39 @@ function walkHighlight(graph, name) {
|
|
|
5375
5385
|
referenceBp: reference && reference !== path ? reference.nodeIds.reduce((sum, id) => sum + lengthOf(id), 0) : void 0
|
|
5376
5386
|
};
|
|
5377
5387
|
}
|
|
5378
|
-
function laneColors(graph, walk,
|
|
5379
|
-
const colors = /* @__PURE__ */ new Map();
|
|
5388
|
+
function laneColors(graph, walk, encoding, ramp) {
|
|
5380
5389
|
const byId = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
5381
|
-
const
|
|
5382
|
-
const reference = referenceOf(graph);
|
|
5383
|
-
const referencePath = reference ? pathOrigin(reference.name).name : void 0;
|
|
5384
|
-
const path = graph.paths.find((p) => p.name === walk.name);
|
|
5385
|
-
const visits = /* @__PURE__ */ new Map();
|
|
5386
|
-
for (const id of path.nodeIds) {
|
|
5387
|
-
visits.set(id, (visits.get(id) ?? 0) + 1);
|
|
5388
|
-
}
|
|
5389
|
-
const strandOf = (segment, of) => graph.pathVisits?.get(segment)?.find((v) => v.path === of)?.strand;
|
|
5390
|
+
const colors = /* @__PURE__ */ new Map();
|
|
5390
5391
|
for (const [id, progress] of walk.progress) {
|
|
5391
5392
|
const node = byId.get(id);
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
} else if (field === "visits") {
|
|
5396
|
-
t = (Math.min(visits.get(id) ?? 1, 4) - 1) / 3;
|
|
5397
|
-
} else if (field === "reference") {
|
|
5398
|
-
const mid = ramp?.midpoints.get(id);
|
|
5399
|
-
t = ramp && mid !== void 0 && !(node?.stable && node.stable.rank > 0) ? (mid - ramp.start) / ramp.span : void 0;
|
|
5400
|
-
} else if (node) {
|
|
5401
|
-
const own = strandOf(node.name, walkPath);
|
|
5402
|
-
const theirs = strandOf(node.name, referencePath);
|
|
5403
|
-
t = own && theirs ? own === theirs ? STRAND_T.same : STRAND_T.reversed : void 0;
|
|
5404
|
-
}
|
|
5405
|
-
colors.set(id, t === void 0 ? NO_VALUE_COLOR : schemeColor(scheme, t));
|
|
5393
|
+
const mid = ramp?.midpoints.get(id);
|
|
5394
|
+
const t = encoding.field === "progress" ? progress : ramp && mid !== void 0 && !(node?.stable && node.stable.rank > 0) ? (mid - ramp.start) / ramp.span : void 0;
|
|
5395
|
+
colors.set(id, encodedColor(encoding, t));
|
|
5406
5396
|
}
|
|
5407
5397
|
return colors;
|
|
5408
5398
|
}
|
|
5399
|
+
function reversedNodes(graph, walk) {
|
|
5400
|
+
const reference = referenceOf(graph);
|
|
5401
|
+
const reversed = /* @__PURE__ */ new Set();
|
|
5402
|
+
let bp = 0;
|
|
5403
|
+
if (!reference || walk.reference) {
|
|
5404
|
+
return { reversed, bp };
|
|
5405
|
+
}
|
|
5406
|
+
const walkPath = pathOrigin(walk.name).name;
|
|
5407
|
+
const referencePath = pathOrigin(reference.name).name;
|
|
5408
|
+
const byId = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
5409
|
+
for (const id of walk.progress.keys()) {
|
|
5410
|
+
const node = byId.get(id);
|
|
5411
|
+
const visits = node ? graph.pathVisits?.get(node.name) : void 0;
|
|
5412
|
+
const own = visits?.find((v) => v.path === walkPath)?.strand;
|
|
5413
|
+
const theirs = visits?.find((v) => v.path === referencePath)?.strand;
|
|
5414
|
+
if (own && theirs && own !== theirs) {
|
|
5415
|
+
reversed.add(id);
|
|
5416
|
+
bp += node.length;
|
|
5417
|
+
}
|
|
5418
|
+
}
|
|
5419
|
+
return { reversed, bp };
|
|
5420
|
+
}
|
|
5409
5421
|
function walkLift(graph, layers, ramp) {
|
|
5410
5422
|
const seen = /* @__PURE__ */ new Set();
|
|
5411
5423
|
const lifted = layers.filter((layer) => !seen.has(layer.walk) && seen.add(layer.walk)).flatMap((layer) => {
|
|
@@ -5420,22 +5432,120 @@ function walkLift(graph, layers, ramp) {
|
|
|
5420
5432
|
const encoding = resolveEncoding(
|
|
5421
5433
|
layer,
|
|
5422
5434
|
walk.reference,
|
|
5423
|
-
walk.reference ? 0 : picked
|
|
5435
|
+
walk.reference ? 0 : picked++,
|
|
5436
|
+
lifted.length === 1
|
|
5424
5437
|
);
|
|
5438
|
+
const { reversed, bp } = reversedNodes(graph, walk);
|
|
5425
5439
|
return {
|
|
5426
5440
|
...walk,
|
|
5427
5441
|
encoding,
|
|
5428
|
-
colors: laneColors(graph, walk, encoding, ramp)
|
|
5442
|
+
colors: laneColors(graph, walk, encoding, ramp),
|
|
5443
|
+
reversed,
|
|
5444
|
+
reversedBp: bp
|
|
5429
5445
|
};
|
|
5430
5446
|
});
|
|
5447
|
+
return liftOf(walks, ramp);
|
|
5448
|
+
}
|
|
5449
|
+
var FACET_COLOR = { field: "progress", scheme: "red" };
|
|
5450
|
+
function facetLifts(graph, lift, layers, ramp) {
|
|
5451
|
+
return lift.walks.map((walk) => {
|
|
5452
|
+
const stated = layers.find((l) => l.walk === walk.name)?.color;
|
|
5453
|
+
const encoding = resolveEncoding(
|
|
5454
|
+
{ walk: walk.name, color: { ...FACET_COLOR, ...stated } },
|
|
5455
|
+
walk.reference,
|
|
5456
|
+
0
|
|
5457
|
+
);
|
|
5458
|
+
return liftOf(
|
|
5459
|
+
[
|
|
5460
|
+
{
|
|
5461
|
+
...walk,
|
|
5462
|
+
encoding,
|
|
5463
|
+
colors: laneColors(graph, walk, encoding, ramp)
|
|
5464
|
+
}
|
|
5465
|
+
],
|
|
5466
|
+
ramp
|
|
5467
|
+
);
|
|
5468
|
+
});
|
|
5469
|
+
}
|
|
5470
|
+
function liftOf(walks, ramp) {
|
|
5431
5471
|
return {
|
|
5432
5472
|
walks,
|
|
5473
|
+
referenceDomain: ramp ? { start: ramp.start, end: ramp.start + ramp.span } : void 0,
|
|
5433
5474
|
nodeIds: new Set(walks.flatMap((w) => [...w.nodeIds])),
|
|
5434
5475
|
edgeIndexes: new Set(walks.flatMap((w) => [...w.edgeIndexes])),
|
|
5435
5476
|
names: new Set(walks.map((w) => w.name))
|
|
5436
5477
|
};
|
|
5437
5478
|
}
|
|
5438
5479
|
|
|
5480
|
+
// src/walkKey.ts
|
|
5481
|
+
function rangeText(contig, start, end) {
|
|
5482
|
+
const s = Math.round(start);
|
|
5483
|
+
const e = Math.round(end);
|
|
5484
|
+
return `${contig ? `${contig}:` : ""}${s.toLocaleString()}-${e.toLocaleString()} (${formatBp(e - s)})`;
|
|
5485
|
+
}
|
|
5486
|
+
function walkKey(walk, reference) {
|
|
5487
|
+
const { field } = walk.encoding;
|
|
5488
|
+
const own = walk.range ? rangeText(walk.range.contig, walk.range.start, walk.range.end) : void 0;
|
|
5489
|
+
const scale = field === "progress" ? own : field === "reference" && reference ? rangeText(reference.name, reference.start, reference.end) : void 0;
|
|
5490
|
+
return {
|
|
5491
|
+
delta: walk.referenceBp === void 0 || walk.bp === walk.referenceBp ? "" : ` ${walk.bp > walk.referenceBp ? "+" : "\u2212"}${formatBp(Math.abs(walk.bp - walk.referenceBp))}`,
|
|
5492
|
+
reversed: walk.reversedBp > 0 ? `, ${formatBp(walk.reversedBp)} reversed` : "",
|
|
5493
|
+
shades: field !== "walk",
|
|
5494
|
+
scale,
|
|
5495
|
+
hover: scale === own ? void 0 : own
|
|
5496
|
+
};
|
|
5497
|
+
}
|
|
5498
|
+
|
|
5499
|
+
// src/facetGrid.ts
|
|
5500
|
+
var FACET_GAP_PX = 8;
|
|
5501
|
+
var FACET_TITLE_PX = 34;
|
|
5502
|
+
var FACET_PAD_PX = 12;
|
|
5503
|
+
var MIN_FACET_PANEL_PX = 60;
|
|
5504
|
+
function facetGrid({
|
|
5505
|
+
count,
|
|
5506
|
+
bounds,
|
|
5507
|
+
pixelRows,
|
|
5508
|
+
width,
|
|
5509
|
+
room,
|
|
5510
|
+
columns
|
|
5511
|
+
}) {
|
|
5512
|
+
function tile(across) {
|
|
5513
|
+
const rows = Math.ceil(count / across);
|
|
5514
|
+
const panelWidth = Math.floor(
|
|
5515
|
+
(width - (across - 1) * FACET_GAP_PX) / across
|
|
5516
|
+
);
|
|
5517
|
+
const panelRoom = (room - rows * FACET_TITLE_PX - (rows - 1) * FACET_GAP_PX) / rows;
|
|
5518
|
+
const fitX = (panelWidth - 2 * FACET_PAD_PX) / bounds.w;
|
|
5519
|
+
const fitY = bounds.h > 0 ? (panelRoom - 2 * FACET_PAD_PX) / bounds.h : Infinity;
|
|
5520
|
+
const scale = pixelRows ? fitX : Math.min(fitX, fitY);
|
|
5521
|
+
const drawn = pixelRows ? bounds.h : bounds.h * scale;
|
|
5522
|
+
const height = Math.floor(
|
|
5523
|
+
Math.max(
|
|
5524
|
+
MIN_FACET_PANEL_PX,
|
|
5525
|
+
Math.min(drawn + 2 * FACET_PAD_PX, panelRoom)
|
|
5526
|
+
)
|
|
5527
|
+
);
|
|
5528
|
+
return {
|
|
5529
|
+
columns: across,
|
|
5530
|
+
width: panelWidth,
|
|
5531
|
+
height,
|
|
5532
|
+
scale,
|
|
5533
|
+
total: rows * (height + FACET_TITLE_PX) + (rows - 1) * FACET_GAP_PX
|
|
5534
|
+
};
|
|
5535
|
+
}
|
|
5536
|
+
if (columns !== void 0) {
|
|
5537
|
+
return tile(Math.max(1, Math.min(count, Math.round(columns))));
|
|
5538
|
+
}
|
|
5539
|
+
let best = tile(1);
|
|
5540
|
+
for (let across = 2; across <= count; across++) {
|
|
5541
|
+
const grid = tile(across);
|
|
5542
|
+
if (grid.scale > best.scale) {
|
|
5543
|
+
best = grid;
|
|
5544
|
+
}
|
|
5545
|
+
}
|
|
5546
|
+
return best;
|
|
5547
|
+
}
|
|
5548
|
+
|
|
5439
5549
|
// src/bubbles/bubbleLine.ts
|
|
5440
5550
|
var SATURATED_PATH_COUNT = 2147483647;
|
|
5441
5551
|
|
|
@@ -6253,6 +6363,9 @@ export {
|
|
|
6253
6363
|
BUBBLE_SPREADS,
|
|
6254
6364
|
COLOR_SCHEMES,
|
|
6255
6365
|
Canvas2DRenderer,
|
|
6366
|
+
FACET_GAP_PX,
|
|
6367
|
+
FACET_PAD_PX,
|
|
6368
|
+
FACET_TITLE_PX,
|
|
6256
6369
|
FIT_PADDING,
|
|
6257
6370
|
FORCE_LAYOUT_LABEL,
|
|
6258
6371
|
HALO_FACTOR,
|
|
@@ -6292,8 +6405,9 @@ export {
|
|
|
6292
6405
|
encodingSwatchCss,
|
|
6293
6406
|
engineKey,
|
|
6294
6407
|
engineRequest,
|
|
6408
|
+
facetGrid,
|
|
6409
|
+
facetLifts,
|
|
6295
6410
|
featuresOnBackbone,
|
|
6296
|
-
fieldLegend,
|
|
6297
6411
|
findHoveredEdge,
|
|
6298
6412
|
findHoveredNode,
|
|
6299
6413
|
fitTransform,
|
|
@@ -6341,6 +6455,7 @@ export {
|
|
|
6341
6455
|
tubeX,
|
|
6342
6456
|
viewportOf,
|
|
6343
6457
|
walkHighlight,
|
|
6458
|
+
walkKey,
|
|
6344
6459
|
walkLift,
|
|
6345
6460
|
walkRows,
|
|
6346
6461
|
walkRowsExtent,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const FACET_GAP_PX = 8;
|
|
2
|
+
export declare const FACET_TITLE_PX = 34;
|
|
3
|
+
export declare const FACET_PAD_PX = 12;
|
|
4
|
+
export interface FacetGrid {
|
|
5
|
+
columns: number;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
scale: number;
|
|
9
|
+
total: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function facetGrid({ count, bounds, pixelRows, width, room, columns, }: {
|
|
12
|
+
count: number;
|
|
13
|
+
bounds: {
|
|
14
|
+
w: number;
|
|
15
|
+
h: number;
|
|
16
|
+
};
|
|
17
|
+
pixelRows: boolean;
|
|
18
|
+
width: number;
|
|
19
|
+
room: number;
|
|
20
|
+
columns?: number;
|
|
21
|
+
}): FacetGrid;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -32,9 +32,12 @@ export type { Connector, ReferenceNode } from './tubeMap/connectors.js';
|
|
|
32
32
|
export type { TubeMapColumn, TubeMapDrawing } from './layout/tubeMapLayout.js';
|
|
33
33
|
export { deletionEdges } from './deletionEdges.js';
|
|
34
34
|
export type { DeletionEdge } from './deletionEdges.js';
|
|
35
|
-
export { walkHighlight, walkLift } from './walkHighlight.js';
|
|
35
|
+
export { facetLifts, walkHighlight, walkLift } from './walkHighlight.js';
|
|
36
|
+
export { walkKey } from './walkKey.js';
|
|
37
|
+
export { FACET_GAP_PX, FACET_PAD_PX, FACET_TITLE_PX, facetGrid, } from './facetGrid.js';
|
|
38
|
+
export type { FacetGrid } from './facetGrid.js';
|
|
36
39
|
export type { LiftedWalk, WalkLift } from './walkHighlight.js';
|
|
37
|
-
export { WALK_FIELDS, WALK_SCHEMES, encodingSwatchCss,
|
|
40
|
+
export { WALK_FIELDS, WALK_SCHEMES, encodingSwatchCss, resolveEncoding, schemeCss, } from './walkEncoding.js';
|
|
38
41
|
export type { WalkEncoding, WalkField, WalkLayer, WalkScheme, } from './walkEncoding.js';
|
|
39
42
|
export { pathColorsLegible, pathLegend } from './pathColors.js';
|
|
40
43
|
export { bubblesFromGraph } from './bubbles/bubblesFromGraph.js';
|
package/dist/types/pipeline.d.ts
CHANGED
|
@@ -60,10 +60,12 @@ export declare function fitTransform(bounds: {
|
|
|
60
60
|
minY: number;
|
|
61
61
|
w: number;
|
|
62
62
|
h: number;
|
|
63
|
-
}, paneWidth: number, paneHeight: number, pixelRows: boolean, { minScale, padLeft, padTop }?: {
|
|
63
|
+
}, paneWidth: number, paneHeight: number, pixelRows: boolean, { minScale, padLeft, padTop, padRight, padBottom, }?: {
|
|
64
64
|
minScale?: number | undefined;
|
|
65
65
|
padLeft?: number | undefined;
|
|
66
66
|
padTop?: number | undefined;
|
|
67
|
+
padRight?: number | undefined;
|
|
68
|
+
padBottom?: number | undefined;
|
|
67
69
|
}): {
|
|
68
70
|
scale: number;
|
|
69
71
|
translateX: number;
|
|
@@ -9,10 +9,11 @@ export interface StripBlock {
|
|
|
9
9
|
bp1: number;
|
|
10
10
|
color: string;
|
|
11
11
|
}
|
|
12
|
-
export declare function referenceStripBlocks(graph: Graph, { colorScheme, referenceRamp, walkNodes, }: {
|
|
12
|
+
export declare function referenceStripBlocks(graph: Graph, { colorScheme, referenceRamp, walkNodes, walkColors, }: {
|
|
13
13
|
colorScheme: ResolvedColorScheme;
|
|
14
14
|
referenceRamp?: ReferenceRamp;
|
|
15
15
|
walkNodes?: ReadonlySet<string>;
|
|
16
|
+
walkColors?: ReadonlyMap<string, number>;
|
|
16
17
|
}): StripBlock[];
|
|
17
18
|
export interface BpFrame {
|
|
18
19
|
scale: number;
|
|
@@ -4,6 +4,7 @@ import type { Graph, GraphNode, NodeSegment } from '../types.js';
|
|
|
4
4
|
import type { WalkLift } from '../walkHighlight.js';
|
|
5
5
|
import type { RenderBatch } from './types.js';
|
|
6
6
|
import type { AxisScale, BezierCurve } from '../util/geometry.js';
|
|
7
|
+
export declare const LIFT_BACKDROP_COLOR: number;
|
|
7
8
|
export declare const FADED_ALPHA = 0.18;
|
|
8
9
|
export interface BuildOptions {
|
|
9
10
|
nodePositions: Record<string, NodeSegment[]>;
|
|
@@ -1,47 +1,37 @@
|
|
|
1
1
|
export declare const WALK_FIELDS: readonly [{
|
|
2
2
|
readonly value: "progress";
|
|
3
3
|
readonly label: "Progress along the walk";
|
|
4
|
-
|
|
4
|
+
}, {
|
|
5
|
+
readonly value: "walk";
|
|
6
|
+
readonly label: "One colour for the walk";
|
|
5
7
|
}, {
|
|
6
8
|
readonly value: "reference";
|
|
7
9
|
readonly label: "Reference position";
|
|
8
|
-
readonly legend: "along the reference left to right, charcoal off it";
|
|
9
|
-
}, {
|
|
10
|
-
readonly value: "strand";
|
|
11
|
-
readonly label: "Strand against the reference";
|
|
12
|
-
readonly legend: "pale where the walk runs as the reference does, deep where reversed";
|
|
13
|
-
}, {
|
|
14
|
-
readonly value: "visits";
|
|
15
|
-
readonly label: "Visits";
|
|
16
|
-
readonly legend: "pale where the walk passes once, deep four times or more";
|
|
17
10
|
}];
|
|
18
11
|
export type WalkField = (typeof WALK_FIELDS)[number]['value'];
|
|
19
12
|
export declare const WALK_SCHEMES: readonly [{
|
|
20
|
-
readonly value: "
|
|
21
|
-
readonly label: "
|
|
22
|
-
|
|
23
|
-
readonly value: "blues";
|
|
24
|
-
readonly label: "Blues";
|
|
25
|
-
readonly hue: 215;
|
|
13
|
+
readonly value: "grey";
|
|
14
|
+
readonly label: "Grey to black";
|
|
15
|
+
readonly ends: readonly ["#a3a3a3", "#151515"];
|
|
26
16
|
}, {
|
|
27
|
-
readonly value: "
|
|
28
|
-
readonly label: "
|
|
29
|
-
readonly
|
|
17
|
+
readonly value: "blue";
|
|
18
|
+
readonly label: "Cyan to navy";
|
|
19
|
+
readonly ends: readonly ["#6ee0f0", "#0b2c7a"];
|
|
30
20
|
}, {
|
|
31
|
-
readonly value: "
|
|
32
|
-
readonly label: "
|
|
33
|
-
readonly
|
|
21
|
+
readonly value: "red";
|
|
22
|
+
readonly label: "Yellow to red";
|
|
23
|
+
readonly ends: readonly ["#ffd24a", "#b3121b"];
|
|
34
24
|
}, {
|
|
35
|
-
readonly value: "
|
|
36
|
-
readonly label: "
|
|
37
|
-
readonly
|
|
25
|
+
readonly value: "purple";
|
|
26
|
+
readonly label: "Pink to plum";
|
|
27
|
+
readonly ends: readonly ["#f5a3d8", "#5e1a6e"];
|
|
38
28
|
}, {
|
|
39
|
-
readonly value: "
|
|
40
|
-
readonly label: "
|
|
41
|
-
readonly
|
|
29
|
+
readonly value: "green";
|
|
30
|
+
readonly label: "Lime to forest";
|
|
31
|
+
readonly ends: readonly ["#b6e36c", "#0b5d3b"];
|
|
42
32
|
}, {
|
|
43
|
-
readonly value: "
|
|
44
|
-
readonly label: "
|
|
33
|
+
readonly value: "rainbow";
|
|
34
|
+
readonly label: "Rainbow";
|
|
45
35
|
}];
|
|
46
36
|
export type WalkScheme = (typeof WALK_SCHEMES)[number]['value'];
|
|
47
37
|
export interface WalkEncoding {
|
|
@@ -52,19 +42,10 @@ export interface WalkLayer {
|
|
|
52
42
|
walk: string;
|
|
53
43
|
color?: Partial<WalkEncoding>;
|
|
54
44
|
}
|
|
55
|
-
export declare function resolveEncoding(layer: WalkLayer, reference: boolean, picked: number): WalkEncoding;
|
|
56
|
-
export declare function
|
|
57
|
-
h: number;
|
|
58
|
-
s: number;
|
|
59
|
-
l: number;
|
|
60
|
-
};
|
|
45
|
+
export declare function resolveEncoding(layer: WalkLayer, reference: boolean, picked: number, alone?: boolean): WalkEncoding;
|
|
46
|
+
export declare function schemeRgb(scheme: WalkScheme, t: number): number[];
|
|
61
47
|
export declare function schemeCss(scheme: WalkScheme, t: number): string;
|
|
62
48
|
export declare function schemeColor(scheme: WalkScheme, t: number): number;
|
|
49
|
+
export declare function encodedColor({ field, scheme }: WalkEncoding, t?: number): number;
|
|
63
50
|
export declare const NO_VALUE_COLOR: number;
|
|
64
|
-
export declare const NO_VALUE_CSS: string;
|
|
65
|
-
export declare const STRAND_T: {
|
|
66
|
-
same: number;
|
|
67
|
-
reversed: number;
|
|
68
|
-
};
|
|
69
51
|
export declare function encodingSwatchCss({ field, scheme }: WalkEncoding): string;
|
|
70
|
-
export declare function fieldLegend(field: WalkField): "pale where the walk starts, deep where it ends" | "along the reference left to right, charcoal off it" | "pale where the walk runs as the reference does, deep where reversed" | "pale where the walk passes once, deep four times or more";
|
|
@@ -10,16 +10,28 @@ export interface WalkHighlight {
|
|
|
10
10
|
steps: number;
|
|
11
11
|
bp: number;
|
|
12
12
|
referenceBp?: number;
|
|
13
|
+
range?: {
|
|
14
|
+
contig: string;
|
|
15
|
+
start: number;
|
|
16
|
+
end: number;
|
|
17
|
+
};
|
|
13
18
|
}
|
|
14
19
|
export interface LiftedWalk extends WalkHighlight {
|
|
15
20
|
encoding: WalkEncoding;
|
|
16
21
|
colors: Map<string, number>;
|
|
22
|
+
reversed: Set<string>;
|
|
23
|
+
reversedBp: number;
|
|
17
24
|
}
|
|
18
25
|
export interface WalkLift {
|
|
19
26
|
walks: LiftedWalk[];
|
|
27
|
+
referenceDomain?: {
|
|
28
|
+
start: number;
|
|
29
|
+
end: number;
|
|
30
|
+
};
|
|
20
31
|
nodeIds: Set<string>;
|
|
21
32
|
edgeIndexes: Set<number>;
|
|
22
33
|
names: Set<string>;
|
|
23
34
|
}
|
|
24
35
|
export declare function walkHighlight(graph: Graph, name: string): WalkHighlight | undefined;
|
|
25
36
|
export declare function walkLift(graph: Graph, layers: readonly WalkLayer[], ramp?: ReferenceRamp): WalkLift | undefined;
|
|
37
|
+
export declare function facetLifts(graph: Graph, lift: WalkLift, layers: readonly WalkLayer[], ramp?: ReferenceRamp): WalkLift[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { LiftedWalk } from './walkHighlight.js';
|
|
2
|
+
export declare function walkKey(walk: LiftedWalk, reference?: {
|
|
3
|
+
name?: string;
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
}): {
|
|
7
|
+
delta: string;
|
|
8
|
+
reversed: string;
|
|
9
|
+
shades: boolean;
|
|
10
|
+
scale: string | undefined;
|
|
11
|
+
hover: string | undefined;
|
|
12
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/bandage-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
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": {
|