@genome-spy/core 0.18.1 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "contributors": [],
9
9
  "license": "BSD-2-Clause",
10
- "version": "0.18.1",
10
+ "version": "0.19.0",
11
11
  "main": "dist/index.js",
12
12
  "module": "src/index.js",
13
13
  "exports": {
@@ -52,5 +52,5 @@
52
52
  "vega-scale": "^7.1.1",
53
53
  "vega-util": "^1.16.0"
54
54
  },
55
- "gitHead": "5f4867844fa8b52f5e7df41b72be698550777f94"
55
+ "gitHead": "282eb640bf4c29be3755ef5de3992b8d76ad5f4c"
56
56
  }
@@ -27,7 +27,7 @@ export default class Collector extends FlowNode {
27
27
  /** @type {(function(Collector):void)[]} */
28
28
  this.observers = [];
29
29
 
30
- /** @type {Map<any | any[], Data>} */
30
+ /** @type {Map<any | any[], Data>} TODO: proper type for key */
31
31
  this.facetBatches = undefined;
32
32
 
33
33
  this._init();
@@ -59,8 +59,6 @@ export default class Collector extends FlowNode {
59
59
  * @param {import("./flowBatch").FlowBatch} flowBatch
60
60
  */
61
61
  beginBatch(flowBatch) {
62
- // TODO: Propagate batches to children(?)
63
-
64
62
  if (isFacetBatch(flowBatch)) {
65
63
  this._data = [];
66
64
  this.facetBatches.set(asArray(flowBatch.facetId), this._data);
@@ -103,7 +101,14 @@ export default class Collector extends FlowNode {
103
101
  }
104
102
 
105
103
  if (this.children.length) {
106
- for (const data of this.facetBatches.values()) {
104
+ for (const [key, data] of this.facetBatches.entries()) {
105
+ if (key) {
106
+ /** @type {import("./flowBatch").FacetBatch} */
107
+ const facetBatch = { type: "facet", facetId: key };
108
+ for (const child of this.children) {
109
+ child.beginBatch(facetBatch);
110
+ }
111
+ }
107
112
  for (const datum of data) {
108
113
  this._propagate(datum);
109
114
  }
@@ -1,3 +1,4 @@
1
+ import Collector from "./collector";
1
2
  import { BEHAVIOR_CLONES } from "./flowNode";
2
3
  import CloneTransform from "./transforms/clone";
3
4
 
@@ -31,6 +32,11 @@ export function validateLinks(node, parent = undefined) {
31
32
  * @param {FlowNode} node
32
33
  */
33
34
  export function removeRedundantCloneTransforms(node, cloneRequired = false) {
35
+ if (node instanceof Collector) {
36
+ // If an object is modified downstream of Collector, it must be cloned
37
+ cloneRequired = true;
38
+ }
39
+
34
40
  if (node instanceof CloneTransform) {
35
41
  if (cloneRequired) {
36
42
  cloneRequired = false;
@@ -257,15 +257,27 @@ export default class Genome {
257
257
  parseInterval(str) {
258
258
  // TODO: consider changing [0-9XY] to support other species besides humans
259
259
  const matches = str.match(
260
- /^(chr[0-9A-Z]+):([0-9,]+)-(?:(chr[0-9A-Z]+):)?([0-9,]+)$/
260
+ /^(chr[0-9A-Z]+)(?::([0-9,]+)(?:-(?:(chr[0-9A-Z]+):)?([0-9,]+))?)?$/
261
261
  );
262
262
 
263
263
  if (matches) {
264
264
  const startChr = matches[1];
265
+
266
+ if (matches.slice(2).every((x) => x === undefined)) {
267
+ const chrom = this.getChromosome(startChr);
268
+ if (chrom) {
269
+ return [chrom.continuousStart, chrom.continuousEnd];
270
+ }
271
+ return;
272
+ }
273
+
265
274
  const endChr = matches[3] || startChr;
266
275
 
267
276
  const startIndex = parseInt(matches[2].replace(/,/g, ""));
268
- const endIndex = parseInt(matches[4].replace(/,/g, ""));
277
+ const endIndex =
278
+ matches[4] !== undefined
279
+ ? parseInt(matches[4].replace(/,/g, ""))
280
+ : startIndex;
269
281
 
270
282
  return [
271
283
  this.toContinuous(startChr, startIndex - 1),
@@ -150,3 +150,38 @@ describe("C. elegans genome, chromosome names prefixed with 'chr'", () => {
150
150
  expect(g.toContinuous("III", 10)).toEqual(30351865);
151
151
  });
152
152
  });
153
+
154
+ describe("Parse interval strings", () => {
155
+ const chromosomes = [
156
+ { name: "chr1", size: 1000 },
157
+ { name: "chr2", size: 2000 },
158
+ { name: "chr3", size: 3000 },
159
+ { name: "chrX", size: 4000 },
160
+ ];
161
+
162
+ const g = new Genome({ name: "random", contigs: chromosomes });
163
+
164
+ test("Parses a single chromosome, returns an interval spanning the chromosome", () => {
165
+ expect(g.parseInterval("chr2")).toEqual([1000, 3000]);
166
+ });
167
+
168
+ test("Returns undefined on unknown chromosome", () => {
169
+ expect(g.parseInterval("chrZ")).toBeUndefined();
170
+ });
171
+
172
+ test("Parses a single coordinate without a thousand separator", () => {
173
+ expect(g.parseInterval("chr2:1500")).toEqual([2499, 2500]);
174
+ });
175
+
176
+ test("Parses a single coordinate with a thousand separator", () => {
177
+ expect(g.parseInterval("chr2:1,500")).toEqual([2499, 2500]);
178
+ });
179
+
180
+ test("Parses an interval within a single chromosome", () => {
181
+ expect(g.parseInterval("chr2:1,500-1,700")).toEqual([2499, 2700]);
182
+ });
183
+
184
+ test("Parses an interval spanning multiple chromosomes", () => {
185
+ expect(g.parseInterval("chr2:1,500-chr3:1,500")).toEqual([2499, 4500]);
186
+ });
187
+ });
@@ -17,6 +17,7 @@ import {
17
17
  import createDomain from "../utils/domainArray";
18
18
  import AxisResolution from "./axisResolution";
19
19
  import { isAggregateSamplesSpec } from "./viewFactory";
20
+ import { peek } from "../utils/arrayUtils";
20
21
 
21
22
  /**
22
23
  *
@@ -337,10 +338,13 @@ export default class UnitView extends ContainerView {
337
338
  if (isAggregateSamplesSpec(this.spec)) {
338
339
  // TODO: Support multiple
339
340
  for (const sumSpec of this.spec.aggregateSamples) {
340
- sumSpec.transform = [
341
- ...(sumSpec.transform ?? []),
342
- { type: "mergeFacets" },
343
- ];
341
+ const transform = sumSpec.transform ?? [];
342
+ if (transform.length && peek(transform).type != "collect") {
343
+ // MergeFacets must be a direct child of Collector
344
+ transform.push({ type: "collect" });
345
+ }
346
+ transform.push({ type: "mergeFacets" });
347
+ sumSpec.transform = transform;
344
348
 
345
349
  sumSpec.encoding = {
346
350
  ...(sumSpec.encoding ?? {}),