@jbrowse/bandage-core 0.1.3 → 0.1.5

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/index.js CHANGED
@@ -269,12 +269,12 @@ function parseGFA(file) {
269
269
  });
270
270
  }
271
271
  } else if (line.startsWith("W")) {
272
- const [, sample, hap, contig, start, end, body, ...rest] = line.split(" ");
273
- if (sample && hap && contig && start && end && body) {
272
+ const [, sample, hap, contig2, start, end, body, ...rest] = line.split(" ");
273
+ if (sample && hap && contig2 && start && end && body) {
274
274
  graph.walks.push({
275
275
  sample,
276
276
  haplotype: +hap,
277
- contig,
277
+ contig: contig2,
278
278
  start: start === "*" ? -1 : +start,
279
279
  end: end === "*" ? -1 : +end,
280
280
  segments: parseWalkBody(body),
@@ -660,6 +660,14 @@ function splitRuns(positions, runs, weightOf) {
660
660
  }
661
661
  return out;
662
662
  }
663
+ function polylineSlice(line, from, to) {
664
+ if (line.length === 0) {
665
+ return [];
666
+ }
667
+ const arc = arcPrefix(line);
668
+ const total = arc.at(-1);
669
+ return slice(line, arc, from * total, to * total);
670
+ }
663
671
  function polylineMidpoint(line) {
664
672
  const arc = arcPrefix(line);
665
673
  return pointAt(line, arc, arc.at(-1) / 2);
@@ -5063,6 +5071,7 @@ var HALO_FACTOR = 3.4;
5063
5071
  var LEGEND_INSET_PX = 6;
5064
5072
  var ROUTE_STACK = 8;
5065
5073
  var GENE_PIN_DROP_PX = 18;
5074
+ var GENE_STACK = 2;
5066
5075
  var GLYPH_ROOM_PX = 60;
5067
5076
  var MAX_GLYPH_LABEL_ROWS = 8;
5068
5077
  var TOPMOST_BASELINE = LABEL_PX + LABEL_PAD;
@@ -5151,7 +5160,8 @@ function layoutLabels(m) {
5151
5160
  item: pin,
5152
5161
  x,
5153
5162
  y: y + m.contigThickness + GENE_PIN_DROP_PX,
5154
- text: pin.covered < 0.98 ? `${pin.gene.name} \u2026` : pin.gene.name
5163
+ text: pin.covered < 0.98 ? `${pin.gene.name} \u2026` : pin.gene.name,
5164
+ stack: GENE_STACK
5155
5165
  };
5156
5166
  }),
5157
5167
  frame,
@@ -5200,6 +5210,86 @@ function layoutLabels(m) {
5200
5210
  };
5201
5211
  }
5202
5212
 
5213
+ // src/genes/genePins.ts
5214
+ function contig(name) {
5215
+ return name.split("#").at(-1);
5216
+ }
5217
+ function genePins(graph, genes, positions) {
5218
+ const byContig = /* @__PURE__ */ new Map();
5219
+ const contigOf = /* @__PURE__ */ new Map();
5220
+ for (const node of graph.nodes) {
5221
+ if (isBackbone(node) && positions[node.id]?.length) {
5222
+ const { refName } = node.stable;
5223
+ const name = contigOf.get(refName) ?? contigOf.set(refName, contig(refName)).get(refName);
5224
+ const entry = byContig.get(name) ?? byContig.set(name, { nodes: [], reach: 0 }).get(name);
5225
+ entry.nodes.push(node);
5226
+ entry.reach = Math.max(entry.reach, node.length);
5227
+ }
5228
+ }
5229
+ for (const { nodes } of byContig.values()) {
5230
+ nodes.sort((a, b) => a.stable.start - b.stable.start);
5231
+ }
5232
+ const pins = [];
5233
+ for (const gene of genes) {
5234
+ const backbone = byContig.get(contig(gene.refName));
5235
+ if (!backbone) {
5236
+ continue;
5237
+ }
5238
+ const parts = [];
5239
+ let at;
5240
+ let atDistance = Infinity;
5241
+ let covered = 0;
5242
+ const mid = (gene.start + gene.end) / 2;
5243
+ const { nodes, reach } = backbone;
5244
+ for (let i = firstNodeAtOrAfter(nodes, gene.start - reach); i < nodes.length && nodes[i].stable.start < gene.end; i++) {
5245
+ const node = nodes[i];
5246
+ const nodeStart = node.stable.start;
5247
+ const nodeEnd = nodeStart + node.length;
5248
+ if (nodeEnd <= gene.start) {
5249
+ continue;
5250
+ }
5251
+ const line = positions[node.id];
5252
+ covered += Math.min(nodeEnd, gene.end) - Math.max(nodeStart, gene.start);
5253
+ for (const exon of gene.exons) {
5254
+ const a = Math.max(exon.start, nodeStart);
5255
+ const b = Math.min(exon.end, nodeEnd);
5256
+ if (b <= a) {
5257
+ continue;
5258
+ }
5259
+ const stretch = polylineSlice(
5260
+ line,
5261
+ (a - nodeStart) / node.length,
5262
+ (b - nodeStart) / node.length
5263
+ );
5264
+ if (stretch.length === 1) {
5265
+ stretch.push({ ...stretch[0] });
5266
+ }
5267
+ parts.push(svgPath(stretch));
5268
+ }
5269
+ const pinBp = Math.min(Math.max(mid, nodeStart), nodeEnd);
5270
+ const distance = Math.abs(pinBp - mid);
5271
+ if (distance < atDistance) {
5272
+ atDistance = distance;
5273
+ const [p] = polylineSlice(
5274
+ line,
5275
+ (pinBp - nodeStart) / node.length,
5276
+ (pinBp - nodeStart) / node.length
5277
+ );
5278
+ at = p;
5279
+ }
5280
+ }
5281
+ if (at) {
5282
+ pins.push({
5283
+ gene,
5284
+ exons: parts.join(""),
5285
+ at,
5286
+ covered: covered / (gene.end - gene.start)
5287
+ });
5288
+ }
5289
+ }
5290
+ return pins;
5291
+ }
5292
+
5203
5293
  // src/gbzWindow.ts
5204
5294
  var NoReferenceSampleError = class extends Error {
5205
5295
  constructor(anchor, referenceSamples) {
@@ -5372,6 +5462,7 @@ export {
5372
5462
  fitTransform,
5373
5463
  forceLayout,
5374
5464
  formatBp2 as formatBp,
5465
+ genePins,
5375
5466
  getDpr,
5376
5467
  haplotypeWanted,
5377
5468
  layoutExtent,
@@ -39,6 +39,8 @@ export { ROW_HEIGHT_PX } from './layout/rowSpacing.js';
39
39
  export { HALO_FACTOR, LEGEND_INSET_PX, layoutLabels } from './labelLayout.js';
40
40
  export type { BubbleGlyph, LabelLayout, LabelLayoutSource } from './labelLayout.js';
41
41
  export { formatBp } from './graphLabels.js';
42
+ export { genePins } from './genes/genePins.js';
43
+ export type { GeneModel, GenePin } from './genes/genePins.js';
42
44
  export { LABEL_CHAR_PX, LABEL_PAD, LABEL_PX } from './overlayLabels.js';
43
45
  export type { Graph, GraphEdge, GraphNode, LayoutResult, NodeSegment, } from './types.js';
44
46
  export { cutWindowGFA, haplotypeWanted, referencePathQuery, referenceSamplesOf, resolveReferenceSample, } from './gbzWindow.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/bandage-core",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
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": {