@jbrowse/bandage-core 4.0.26 → 4.0.27

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  HPRC_GBZ,
4
- LAYOUT_MODE_VALUES,
4
+ LAYOUT_MODES,
5
5
  cutGbzRegion,
6
6
  featuresOnBackbone,
7
7
  figureSvg,
@@ -10,12 +10,14 @@ import {
10
10
  genesFromGff3Lines,
11
11
  genesFromText,
12
12
  graphBackbone,
13
+ haplotypeIndexBeside,
13
14
  layoutModeByValue,
14
15
  loadBandage,
15
16
  loadGraph,
16
17
  openGbz,
17
- parseRegion
18
- } from "../chunks/chunk-75KVO2WV.js";
18
+ parseRegion,
19
+ refNameBinding
20
+ } from "../chunks/chunk-VNCGWA2N.js";
19
21
 
20
22
  // src/cli/figure.ts
21
23
  import { access, open, readFile, writeFile } from "node:fs/promises";
@@ -28,12 +30,9 @@ function byteSource(location) {
28
30
  if (isUrl(location)) {
29
31
  return {
30
32
  async read(length, position) {
31
- const res = await fetch(location, {
33
+ const res = await fetchOk(location, {
32
34
  headers: { range: `bytes=${position}-${position + length - 1}` }
33
35
  });
34
- if (!res.ok) {
35
- throw new Error(`HTTP ${res.status} reading ${location}`);
36
- }
37
36
  return new Uint8Array(await res.arrayBuffer());
38
37
  },
39
38
  async stat() {
@@ -71,30 +70,48 @@ async function readGenes(genes, graph, resolve) {
71
70
  if (!backbone) {
72
71
  return [];
73
72
  }
74
- const file = resolve(genes.file);
73
+ const bind = refNameBinding(
74
+ backbone.contigs.map((c) => c.refName),
75
+ genes.refNames
76
+ );
75
77
  const format = genes.format ?? (/\.bed(\.gz)?$/i.test(genes.file) ? "bed" : "gff3");
76
- if (!genes.index) {
77
- return featuresOnBackbone(genesFromText(await text(file)), backbone);
78
+ const { names, features } = genes.index ? await indexedGenes(
79
+ resolve(genes.file),
80
+ resolve(genes.index),
81
+ format,
82
+ backbone.contigs,
83
+ bind
84
+ ) : namedBy(genesFromText(await text(resolve(genes.file))));
85
+ if (!names.some((name) => bind(name) !== void 0)) {
86
+ const shown = names.slice(0, 4).join(", ");
87
+ console.warn(
88
+ `bandage-figure: no sequence in ${genes.file} names ${backbone.contigs.map((c) => c.contig).join(", ")}` + (names.length ? `; it has ${shown}${names.length > 4 ? ", \u2026" : ""}` : "") + `. Give the file's name under genes.refNames, as { "chr6": "NC_000006.12" }`
89
+ );
78
90
  }
79
- const index = resolve(genes.index);
91
+ return featuresOnBackbone(features, backbone, genes.refNames);
92
+ }
93
+ function namedBy(features) {
94
+ return { names: [...new Set(features.map((f) => f.refName))], features };
95
+ }
96
+ async function indexedGenes(file, index, format, contigs, bind) {
80
97
  const csi = index.endsWith(".csi");
81
98
  const tabix = new TabixIndexedFile(
82
99
  isUrl(file) ? { url: file, ...csi ? { csiUrl: index } : { tbiUrl: index } } : { path: file, ...csi ? { csiPath: index } : { tbiPath: index } }
83
100
  );
84
- const indexed = new Set(await tabix.getReferenceSequenceNames());
101
+ const names = await tabix.getReferenceSequenceNames();
85
102
  const lines = [];
86
- for (const contig of backbone.contigs) {
87
- const refName = [contig.contig, contig.refName].find((n) => indexed.has(n));
88
- if (refName !== void 0) {
89
- await tabix.getLines(refName, contig.start, contig.end, {
103
+ for (const contig of contigs) {
104
+ const name = names.find((n) => bind(n) === contig.refName);
105
+ if (name !== void 0) {
106
+ await tabix.getLines(name, contig.start, contig.end, {
90
107
  lineCallback: (line) => lines.push(line)
91
108
  });
92
109
  }
93
110
  }
94
- return featuresOnBackbone(
95
- format === "gff3" ? genesFromGff3Lines(lines) : genesFromBed(lines.join("\n")),
96
- backbone
97
- );
111
+ return {
112
+ names,
113
+ features: format === "gff3" ? genesFromGff3Lines(lines) : genesFromBed(lines.join("\n"))
114
+ };
98
115
  }
99
116
  var engine = async (request) => {
100
117
  const bandage = await loadBandage();
@@ -111,22 +128,18 @@ async function exists(location) {
111
128
  }
112
129
  }
113
130
  async function siblingIndex(db) {
114
- const sibling = db.replace(/\.gbz\.db$/i, ".haplotype-index.db");
115
- return sibling !== db && await exists(sibling) ? sibling : void 0;
131
+ const sibling = haplotypeIndexBeside(db);
132
+ return sibling && await exists(sibling) ? sibling : void 0;
116
133
  }
117
- var UNDRAWABLE = /* @__PURE__ */ new Set(["walkrows", "tubemap", "tubemapref"]);
134
+ var DRAWABLE = LAYOUT_MODES.filter((m) => m.drawsNodes).map(
135
+ (m) => m.value
136
+ );
118
137
  function checkLayout(layout) {
119
- if (layout === void 0) {
120
- return;
121
- }
122
- if (!LAYOUT_MODE_VALUES.includes(layout)) {
138
+ if (layout !== void 0 && !DRAWABLE.includes(layout)) {
123
139
  throw new Error(
124
- `unknown layout "${layout}": one of ${LAYOUT_MODE_VALUES.filter((v) => !UNDRAWABLE.has(v)).join(", ")}`
140
+ `a figure draws no "${layout}" layout: one of ${DRAWABLE.join(", ")}`
125
141
  );
126
142
  }
127
- if (UNDRAWABLE.has(layout)) {
128
- throw new Error(`a figure cannot draw the "${layout}" layout yet`);
129
- }
130
143
  }
131
144
  async function renderSpec(spec, base) {
132
145
  checkLayout(spec.layout);
package/dist/index.js CHANGED
@@ -102,7 +102,7 @@ import {
102
102
  wellKnownSample,
103
103
  yToXOf,
104
104
  zoomAbout
105
- } from "./chunks/chunk-75KVO2WV.js";
105
+ } from "./chunks/chunk-VNCGWA2N.js";
106
106
 
107
107
  // src/index.ts
108
108
  import { getDpr } from "@jbrowse/render-core/canvas2dUtils";
@@ -722,15 +722,16 @@ function extentOf(commands) {
722
722
  }
723
723
  return { x0, x1 };
724
724
  }
725
- function shapeOf(d, color, alpha) {
725
+ function shapeOf(d, color, alpha, track) {
726
726
  const commands = parsePath(d);
727
- return { commands, color, alpha, ...extentOf(commands) };
727
+ return { commands, color, track, alpha, ...extentOf(commands) };
728
728
  }
729
- function layerOf(layout, type, tubes) {
729
+ function layerOf(layout, type) {
730
730
  const { shapes } = layout;
731
- const colorOf = (s) => tubes?.[s.id] ?? s.color;
731
+ const trackOf = (s) => type === "haplotype" ? s.id : void 0;
732
732
  const rects = [...shapes.rectangles, ...shapes.verticalRectangles].filter((r) => r.type === type).map((r) => ({
733
- color: colorOf(r),
733
+ color: r.color,
734
+ track: trackOf(r),
734
735
  alpha: r.alpha ?? 1,
735
736
  x0: r.xStart,
736
737
  x1: r.xEnd + 1,
@@ -738,30 +739,22 @@ function layerOf(layout, type, tubes) {
738
739
  y1: r.yEnd + 1
739
740
  }));
740
741
  const curves = curvePaths(shapes.curves, type).map(
741
- (c) => shapeOf(c.path, colorOf(c), c.alpha ?? 1)
742
+ (c) => shapeOf(c.path, c.color, c.alpha ?? 1, trackOf(c))
742
743
  );
743
- const corners = shapes.corners.filter((c) => c.type === type).map((c) => shapeOf(c.path, colorOf(c), 1));
744
+ const corners = shapes.corners.filter((c) => c.type === type).map((c) => shapeOf(c.path, c.color, 1, trackOf(c)));
744
745
  return { rects, shapes: [...curves, ...corners] };
745
746
  }
746
- function tubeMapPicture(layout, colors = {}) {
747
+ function tubeMapPicture(layout) {
747
748
  const nodes = [];
748
749
  layout.nodes.forEach((node) => {
749
750
  if (node.order >= 0) {
750
751
  const commands = parsePath(nodeOutlinePath(node));
751
- nodes.push({
752
- name: node.name,
753
- commands,
754
- ...extentOf(commands),
755
- color: colors.nodes?.get(node.name)
756
- });
752
+ nodes.push({ name: node.name, commands, ...extentOf(commands) });
757
753
  }
758
754
  });
759
755
  return {
760
756
  bounds: layout.bounds,
761
- layers: [
762
- layerOf(layout, "haplotype", colors.tubes),
763
- layerOf(layout, "read")
764
- ],
757
+ layers: [layerOf(layout, "haplotype"), layerOf(layout, "read")],
765
758
  nodes,
766
759
  mismatches: tubeMapMismatches(layout).filter(
767
760
  (m) => m.kind !== "insertion" || !m.softClip
@@ -807,11 +800,11 @@ function trace(ctx, commands, x, y) {
807
800
  }
808
801
  }
809
802
  }
810
- function fillByColor(ctx, items, visible, addTo) {
803
+ function fillByColor(ctx, items, visible, colorOf, addTo) {
811
804
  const byColor = /* @__PURE__ */ new Map();
812
805
  for (const item of items) {
813
806
  if (visible(item)) {
814
- const key = `${item.color}|${item.alpha}`;
807
+ const key = `${colorOf(item)}|${item.alpha}`;
815
808
  const list = byColor.get(key);
816
809
  if (list) {
817
810
  list.push(item);
@@ -821,7 +814,7 @@ function fillByColor(ctx, items, visible, addTo) {
821
814
  }
822
815
  }
823
816
  for (const list of byColor.values()) {
824
- ctx.fillStyle = list[0].color;
817
+ ctx.fillStyle = colorOf(list[0]);
825
818
  ctx.globalAlpha = list[0].alpha;
826
819
  ctx.beginPath();
827
820
  for (const item of list) {
@@ -840,13 +833,14 @@ var NODE_TINT_ALPHA = 0.55;
840
833
  function drawTubeMap(ctx, picture, frame) {
841
834
  const { x, y, width } = frame;
842
835
  const visible = (item) => x(item.x1) >= 0 && x(item.x0) <= width;
836
+ const colorOf = (item) => item.track !== void 0 && frame.tubeColors?.[item.track] || item.color;
843
837
  for (const layer of picture.layers) {
844
- fillByColor(ctx, layer.rects, visible, (r) => {
838
+ fillByColor(ctx, layer.rects, visible, colorOf, (r) => {
845
839
  const left = x(r.x0);
846
840
  const top = y(r.y0);
847
841
  ctx.rect(left, top, x(r.x1) - left, y(r.y1) - top);
848
842
  });
849
- fillByColor(ctx, layer.shapes, visible, (s) => {
843
+ fillByColor(ctx, layer.shapes, visible, colorOf, (s) => {
850
844
  trace(ctx, s.commands, x, y);
851
845
  });
852
846
  }
@@ -858,7 +852,7 @@ function drawTubeMap(ctx, picture, frame) {
858
852
  const lit = node.name === frame.highlightNode;
859
853
  ctx.beginPath();
860
854
  trace(ctx, node.commands, x, y);
861
- const tint = lit ? void 0 : node.color;
855
+ const tint = lit ? void 0 : frame.nodeColors?.get(node.name);
862
856
  ctx.fillStyle = lit ? "rgba(255,192,203,0.5)" : tint ?? fill;
863
857
  ctx.strokeStyle = lit ? "#ff0000" : stroke;
864
858
  ctx.globalAlpha = tint ? NODE_TINT_ALPHA : 1;
@@ -1724,19 +1718,14 @@ function bubbleSubgraph(graph, segmentIds) {
1724
1718
  const keep = new Set(segmentIds);
1725
1719
  const nodes = graph.nodes.filter((n) => keep.has(n.name));
1726
1720
  const ids = new Set(nodes.map((n) => n.id));
1727
- const lengthOf = new Map(graph.nodes.map((n) => [n.id, n.length]));
1728
- const bpOf = (steps) => steps.reduce((sum, id) => sum + (lengthOf.get(id) ?? 0), 0);
1729
- const stretches = /* @__PURE__ */ new Map();
1721
+ const kept = /* @__PURE__ */ new Map();
1730
1722
  const paths = graph.paths?.flatMap((p) => {
1731
1723
  const first = p.nodeIds.findIndex((id) => ids.has(id));
1732
1724
  if (first < 0) {
1733
1725
  return [];
1734
1726
  }
1735
1727
  const nodeIds = p.nodeIds.filter((id) => ids.has(id));
1736
- stretches.set(p.name, {
1737
- dropped: bpOf(p.nodeIds.slice(0, first)),
1738
- bp: bpOf(nodeIds)
1739
- });
1728
+ kept.set(p.name, { first, nodeIds });
1740
1729
  return [{ ...p, nodeIds }];
1741
1730
  });
1742
1731
  return {
@@ -1744,7 +1733,7 @@ function bubbleSubgraph(graph, segmentIds) {
1744
1733
  nodes,
1745
1734
  edges: graph.edges.filter((e) => ids.has(e.from) && ids.has(e.to)),
1746
1735
  ...paths?.length ? { paths } : {},
1747
- anchorPaths: graph.anchorPaths && trimOrigins(graph.anchorPaths, graph.paths ?? [], stretches),
1736
+ anchorPaths: trimOrigins(graph, kept),
1748
1737
  pathVisits: graph.pathVisits,
1749
1738
  anchoredBy: graph.anchoredBy,
1750
1739
  referencePath: graph.referencePath
@@ -16,5 +16,6 @@ export interface FigureSpec extends Omit<FigureOptions, 'walks' | 'region' | 'ge
16
16
  file: string;
17
17
  index?: string;
18
18
  format?: 'gff3' | 'bed';
19
+ refNames?: Record<string, string>;
19
20
  };
20
21
  }
@@ -13,6 +13,7 @@ export declare const HPRC_GBZ: {
13
13
  db: string;
14
14
  index: string;
15
15
  };
16
+ export declare function haplotypeIndexBeside(db: string): string | undefined;
16
17
  export declare function parseRegion(text: string): {
17
18
  refName: string;
18
19
  start: number;
@@ -17,6 +17,7 @@ export interface GraphLabel {
17
17
  kind: 'node' | 'deletion';
18
18
  leader?: Leader;
19
19
  }
20
+ export declare function groupDigits(n: number): string;
20
21
  export declare function formatBp(bp: number): string;
21
22
  interface SizeLabelArgs {
22
23
  nodePositions: Record<string, NodeSegment[]>;
@@ -19,7 +19,7 @@ export { wheelZoomFactor } from './util/wheelZoom.js';
19
19
  export { REFERENCE_STRIP_ZONE_PX, drawReferenceStrip, referenceStripBlocks, stripBlockAt, } from './referenceStrip.js';
20
20
  export type { StripBlock } from './referenceStrip.js';
21
21
  export { drawTubeMap, tubeMapPicture } from './tubeMap/draw.js';
22
- export type { TubeMapColors, TubeMapFrame, TubeMapPicture, } from './tubeMap/draw.js';
22
+ export type { TubeMapFrame, TubeMapPicture } from './tubeMap/draw.js';
23
23
  export { tubeMapNodeColors } from './tubeMap/nodeColors.js';
24
24
  export { referenceKnots, warpX } from './tubeMap/warp.js';
25
25
  export { tubeMapFrame, tubeMapNodeAt } from './tubeMap/frame.js';
@@ -17,6 +17,7 @@ export interface LayoutMode {
17
17
  cutMargins: boolean;
18
18
  wholeWalks: boolean;
19
19
  drawsLocally: (graph: Graph) => boolean;
20
+ drawsNodes: boolean;
20
21
  }
21
22
  export declare const LAYOUT_MODES: readonly [{
22
23
  readonly value: "auto";
@@ -27,6 +28,7 @@ export declare const LAYOUT_MODES: readonly [{
27
28
  readonly wholeWalks: false;
28
29
  readonly available: (graph: Graph) => boolean;
29
30
  readonly drawsLocally: (graph: Graph) => boolean;
31
+ readonly drawsNodes: true;
30
32
  }, {
31
33
  readonly value: "samplerows";
32
34
  readonly label: "Sample rows";
@@ -36,6 +38,7 @@ export declare const LAYOUT_MODES: readonly [{
36
38
  readonly wholeWalks: false;
37
39
  readonly available: (graph: Graph) => boolean;
38
40
  readonly drawsLocally: (graph: Graph) => boolean;
41
+ readonly drawsNodes: true;
39
42
  }, {
40
43
  readonly value: "walkrows";
41
44
  readonly label: "Walk rows";
@@ -45,6 +48,7 @@ export declare const LAYOUT_MODES: readonly [{
45
48
  readonly wholeWalks: true;
46
49
  readonly available: (graph: Graph) => boolean;
47
50
  readonly drawsLocally: (graph: Graph) => boolean;
51
+ readonly drawsNodes: false;
48
52
  }, {
49
53
  readonly value: "ordered";
50
54
  readonly label: "Ordered";
@@ -54,6 +58,7 @@ export declare const LAYOUT_MODES: readonly [{
54
58
  readonly wholeWalks: false;
55
59
  readonly available: (graph: Graph) => boolean;
56
60
  readonly drawsLocally: (graph: Graph) => boolean;
61
+ readonly drawsNodes: true;
57
62
  }, {
58
63
  readonly value: "tubemap";
59
64
  readonly label: "Tube map";
@@ -63,6 +68,7 @@ export declare const LAYOUT_MODES: readonly [{
63
68
  readonly wholeWalks: false;
64
69
  readonly available: typeof hasTubeMapPaths;
65
70
  readonly drawsLocally: typeof hasTubeMapPaths;
71
+ readonly drawsNodes: false;
66
72
  }, {
67
73
  readonly value: "tubemapref";
68
74
  readonly label: "Tube map on reference";
@@ -72,6 +78,7 @@ export declare const LAYOUT_MODES: readonly [{
72
78
  readonly wholeWalks: false;
73
79
  readonly available: (graph: Graph) => boolean;
74
80
  readonly drawsLocally: (graph: Graph) => boolean;
81
+ readonly drawsNodes: false;
75
82
  }, {
76
83
  readonly value: "force";
77
84
  readonly label: "Force-directed layout";
@@ -81,6 +88,7 @@ export declare const LAYOUT_MODES: readonly [{
81
88
  readonly wholeWalks: false;
82
89
  readonly available: () => true;
83
90
  readonly drawsLocally: () => false;
91
+ readonly drawsNodes: true;
84
92
  }];
85
93
  export type LayoutModeValue = (typeof LAYOUT_MODES)[number]['value'];
86
94
  export declare const LAYOUT_MODE_VALUES: ("auto" | "ordered" | "samplerows" | "walkrows" | "tubemap" | "tubemapref" | "force")[];
@@ -94,6 +102,7 @@ export declare function layoutModeByValue(value: string): {
94
102
  readonly wholeWalks: false;
95
103
  readonly available: (graph: Graph) => boolean;
96
104
  readonly drawsLocally: (graph: Graph) => boolean;
105
+ readonly drawsNodes: true;
97
106
  } | {
98
107
  readonly value: "samplerows";
99
108
  readonly label: "Sample rows";
@@ -103,6 +112,7 @@ export declare function layoutModeByValue(value: string): {
103
112
  readonly wholeWalks: false;
104
113
  readonly available: (graph: Graph) => boolean;
105
114
  readonly drawsLocally: (graph: Graph) => boolean;
115
+ readonly drawsNodes: true;
106
116
  } | {
107
117
  readonly value: "walkrows";
108
118
  readonly label: "Walk rows";
@@ -112,6 +122,7 @@ export declare function layoutModeByValue(value: string): {
112
122
  readonly wholeWalks: true;
113
123
  readonly available: (graph: Graph) => boolean;
114
124
  readonly drawsLocally: (graph: Graph) => boolean;
125
+ readonly drawsNodes: false;
115
126
  } | {
116
127
  readonly value: "ordered";
117
128
  readonly label: "Ordered";
@@ -121,6 +132,7 @@ export declare function layoutModeByValue(value: string): {
121
132
  readonly wholeWalks: false;
122
133
  readonly available: (graph: Graph) => boolean;
123
134
  readonly drawsLocally: (graph: Graph) => boolean;
135
+ readonly drawsNodes: true;
124
136
  } | {
125
137
  readonly value: "tubemap";
126
138
  readonly label: "Tube map";
@@ -130,6 +142,7 @@ export declare function layoutModeByValue(value: string): {
130
142
  readonly wholeWalks: false;
131
143
  readonly available: typeof hasTubeMapPaths;
132
144
  readonly drawsLocally: typeof hasTubeMapPaths;
145
+ readonly drawsNodes: false;
133
146
  } | {
134
147
  readonly value: "tubemapref";
135
148
  readonly label: "Tube map on reference";
@@ -139,6 +152,7 @@ export declare function layoutModeByValue(value: string): {
139
152
  readonly wholeWalks: false;
140
153
  readonly available: (graph: Graph) => boolean;
141
154
  readonly drawsLocally: (graph: Graph) => boolean;
155
+ readonly drawsNodes: false;
142
156
  } | {
143
157
  readonly value: "force";
144
158
  readonly label: "Force-directed layout";
@@ -148,4 +162,5 @@ export declare function layoutModeByValue(value: string): {
148
162
  readonly wholeWalks: false;
149
163
  readonly available: () => true;
150
164
  readonly drawsLocally: () => false;
165
+ readonly drawsNodes: true;
151
166
  };
@@ -1,4 +1,4 @@
1
- import type { Graph, GraphPath, PathOrigin, PathVisit } from './types.js';
1
+ import type { Graph, PathOrigin, PathVisit } from './types.js';
2
2
  export declare function pathOrigin(pathName: string): {
3
3
  name: string;
4
4
  start: number;
@@ -18,7 +18,7 @@ export declare function surveyPaths(paths: PathSteps[], lengthOf: (segmentId: st
18
18
  export declare function chooseReferencePath(anchorPaths: PathOrigin[], preferred: string | undefined): PathOrigin | undefined;
19
19
  export declare function anchorFromPaths(graph: Graph, preferred: string | undefined): Graph;
20
20
  export declare function anchorGraph(graph: Graph, preferred: string | undefined): Graph;
21
- export declare function trimOrigins(origins: PathOrigin[], paths: GraphPath[], stretches: Map<string, {
22
- dropped: number;
23
- bp: number;
24
- }>): PathOrigin[];
21
+ export declare function trimOrigins(graph: Graph, kept: Map<string, {
22
+ first: number;
23
+ nodeIds: string[];
24
+ }>): PathOrigin[] | undefined;
@@ -19,7 +19,8 @@ export declare function wellKnownSample(assemblyName: string): string | undefine
19
19
  export declare function graphBackbone(graph: Graph): Backbone | undefined;
20
20
  export declare function backboneAssembly<T extends AssemblyNames>(backbone: Backbone | undefined, assemblies: T[]): T | undefined;
21
21
  export declare function assemblyWalk(graph: Graph, assembly: AssemblyNames): PathOrigin | undefined;
22
- export declare function refNameBinding(refNames: Iterable<string>): (name: string) => string | undefined;
22
+ export declare function contigNames(contig: string): string[];
23
+ export declare function refNameBinding(refNames: Iterable<string>, aliases?: Record<string, string>): (name: string) => string | undefined;
23
24
  export declare function featuresOnBackbone<T extends {
24
25
  refName: string;
25
- }>(features: readonly T[], backbone: Backbone): T[];
26
+ }>(features: readonly T[], backbone: Backbone, aliases?: Record<string, string>): T[];
@@ -31,6 +31,7 @@ type Command = {
31
31
  export declare function parsePath(d: string): Command[];
32
32
  interface Filled {
33
33
  color: string;
34
+ track?: number;
34
35
  alpha: number;
35
36
  x0: number;
36
37
  x1: number;
@@ -54,19 +55,16 @@ export interface TubeMapPicture {
54
55
  commands: Command[];
55
56
  x0: number;
56
57
  x1: number;
57
- color?: string;
58
58
  }[];
59
59
  mismatches: TubeMapMismatch[];
60
60
  }
61
- export interface TubeMapColors {
62
- tubes?: readonly string[];
63
- nodes?: ReadonlyMap<string, string>;
64
- }
65
- export declare function tubeMapPicture(layout: TubeMapLayout, colors?: TubeMapColors): TubeMapPicture;
61
+ export declare function tubeMapPicture(layout: TubeMapLayout): TubeMapPicture;
66
62
  export interface TubeMapFrame extends TubeMapTransform {
67
63
  width: number;
68
64
  highlightNode?: string | null;
69
65
  darkMode?: boolean;
66
+ tubeColors?: readonly string[];
67
+ nodeColors?: ReadonlyMap<string, string>;
70
68
  }
71
69
  export declare function drawTubeMap(ctx: CanvasRenderingContext2D, picture: TubeMapPicture, frame: TubeMapFrame): void;
72
70
  export declare function mismatchesLegible(yScale: number): boolean;
@@ -1 +1 @@
1
- export declare const version = "4.0.26";
1
+ export declare const version = "4.0.27";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/bandage-core",
3
- "version": "4.0.26",
3
+ "version": "4.0.27",
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": {