@genome-spy/core 0.17.0 → 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/dist/index.js +29 -29
- package/dist/{genome-spy-schema.json → schema.json} +18 -0
- package/package.json +8 -7
- package/src/data/collector.js +9 -4
- package/src/data/flowOptimizer.js +6 -0
- package/src/genome/genome.js +14 -2
- package/src/genome/genome.test.js +35 -0
- package/src/spec/root.d.ts +2 -0
- package/src/utils/addBaseUrl.js +19 -0
- package/src/utils/addBaseUrl.test.js +21 -0
- package/src/view/unitView.js +8 -4
|
@@ -2851,6 +2851,9 @@
|
|
|
2851
2851
|
{
|
|
2852
2852
|
"additionalProperties": false,
|
|
2853
2853
|
"properties": {
|
|
2854
|
+
"$schema": {
|
|
2855
|
+
"type": "string"
|
|
2856
|
+
},
|
|
2854
2857
|
"aggregateSamples": {
|
|
2855
2858
|
"items": {
|
|
2856
2859
|
"anyOf": [
|
|
@@ -3010,6 +3013,9 @@
|
|
|
3010
3013
|
{
|
|
3011
3014
|
"additionalProperties": false,
|
|
3012
3015
|
"properties": {
|
|
3016
|
+
"$schema": {
|
|
3017
|
+
"type": "string"
|
|
3018
|
+
},
|
|
3013
3019
|
"aggregateSamples": {
|
|
3014
3020
|
"items": {
|
|
3015
3021
|
"anyOf": [
|
|
@@ -3172,6 +3178,9 @@
|
|
|
3172
3178
|
{
|
|
3173
3179
|
"additionalProperties": false,
|
|
3174
3180
|
"properties": {
|
|
3181
|
+
"$schema": {
|
|
3182
|
+
"type": "string"
|
|
3183
|
+
},
|
|
3175
3184
|
"baseUrl": {
|
|
3176
3185
|
"type": "string"
|
|
3177
3186
|
},
|
|
@@ -3322,6 +3331,9 @@
|
|
|
3322
3331
|
{
|
|
3323
3332
|
"additionalProperties": false,
|
|
3324
3333
|
"properties": {
|
|
3334
|
+
"$schema": {
|
|
3335
|
+
"type": "string"
|
|
3336
|
+
},
|
|
3325
3337
|
"baseUrl": {
|
|
3326
3338
|
"type": "string"
|
|
3327
3339
|
},
|
|
@@ -3471,6 +3483,9 @@
|
|
|
3471
3483
|
{
|
|
3472
3484
|
"additionalProperties": false,
|
|
3473
3485
|
"properties": {
|
|
3486
|
+
"$schema": {
|
|
3487
|
+
"type": "string"
|
|
3488
|
+
},
|
|
3474
3489
|
"baseUrl": {
|
|
3475
3490
|
"type": "string"
|
|
3476
3491
|
},
|
|
@@ -3620,6 +3635,9 @@
|
|
|
3620
3635
|
{
|
|
3621
3636
|
"additionalProperties": false,
|
|
3622
3637
|
"properties": {
|
|
3638
|
+
"$schema": {
|
|
3639
|
+
"type": "string"
|
|
3640
|
+
},
|
|
3623
3641
|
"baseUrl": {
|
|
3624
3642
|
"type": "string"
|
|
3625
3643
|
},
|
package/package.json
CHANGED
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
},
|
|
8
8
|
"contributors": [],
|
|
9
9
|
"license": "BSD-2-Clause",
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.19.0",
|
|
11
11
|
"main": "dist/index.js",
|
|
12
12
|
"module": "src/index.js",
|
|
13
13
|
"exports": {
|
|
14
14
|
".": "./src/index.js",
|
|
15
|
-
"./*": "./src/*"
|
|
15
|
+
"./*": "./src/*",
|
|
16
|
+
"./schema.json": "./dist/schema.json"
|
|
16
17
|
},
|
|
17
18
|
"files": [
|
|
18
19
|
"dist/",
|
|
@@ -20,16 +21,16 @@
|
|
|
20
21
|
],
|
|
21
22
|
"repository": {
|
|
22
23
|
"type": "git",
|
|
23
|
-
"url": "github:
|
|
24
|
+
"url": "github:genome-spy/genome-spy",
|
|
24
25
|
"directory": "packages/core"
|
|
25
26
|
},
|
|
26
27
|
"scripts": {
|
|
27
28
|
"dev": "node dev-server.js",
|
|
28
|
-
"build": "vite build",
|
|
29
|
-
"prepublishOnly": "npm run build
|
|
29
|
+
"build": "vite build && npm run build:schema",
|
|
30
|
+
"prepublishOnly": "npm run build",
|
|
30
31
|
"test:tsc": "tsc -p tsconfig.json",
|
|
31
32
|
"checkSpec": "tsc --allowJs --checkJs --strict --noEmit --moduleResolution node --target es6 src/spec/root.d.ts",
|
|
32
|
-
"build:schema": "mkdir -p dist && ts-json-schema-generator --path 'src/spec/*.ts' --type RootSpec > dist/
|
|
33
|
+
"build:schema": "mkdir -p dist && ts-json-schema-generator --path 'src/spec/*.ts' --type RootSpec > dist/schema.json"
|
|
33
34
|
},
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"@types/d3-array": "^3.0.2",
|
|
@@ -51,5 +52,5 @@
|
|
|
51
52
|
"vega-scale": "^7.1.1",
|
|
52
53
|
"vega-util": "^1.16.0"
|
|
53
54
|
},
|
|
54
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "282eb640bf4c29be3755ef5de3992b8d76ad5f4c"
|
|
55
56
|
}
|
package/src/data/collector.js
CHANGED
|
@@ -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.
|
|
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;
|
package/src/genome/genome.js
CHANGED
|
@@ -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]+)
|
|
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 =
|
|
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
|
+
});
|
package/src/spec/root.d.ts
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} url
|
|
3
|
+
* @param {string} baseUrl
|
|
4
|
+
*/
|
|
5
|
+
export default function addBaseUrl(url, baseUrl) {
|
|
6
|
+
// Regex copied from vega-loader
|
|
7
|
+
if (!baseUrl || /^(data:|([A-Za-z]+:)?\/\/)/.test(url)) {
|
|
8
|
+
return url;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (!url.startsWith("/")) {
|
|
12
|
+
if (!baseUrl.endsWith("/")) {
|
|
13
|
+
baseUrl += "/";
|
|
14
|
+
}
|
|
15
|
+
return baseUrl + url;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return url;
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import addBaseUrl from "./addBaseUrl";
|
|
2
|
+
|
|
3
|
+
test("addBaseUrl adds baseUrl when needed", () => {
|
|
4
|
+
expect(addBaseUrl("foo.html", "https://site.com/")).toEqual(
|
|
5
|
+
"https://site.com/foo.html"
|
|
6
|
+
);
|
|
7
|
+
expect(addBaseUrl("foo.html", "https://site.com")).toEqual(
|
|
8
|
+
"https://site.com/foo.html"
|
|
9
|
+
);
|
|
10
|
+
expect(addBaseUrl("bar/foo.html", "https://site.com/")).toEqual(
|
|
11
|
+
"https://site.com/bar/foo.html"
|
|
12
|
+
);
|
|
13
|
+
expect(addBaseUrl("../foo.html", "https://site.com/bar/")).toEqual(
|
|
14
|
+
"https://site.com/bar/../foo.html"
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("addBaseUrl doesn't add baseUrl when not needed", () => {
|
|
19
|
+
expect(addBaseUrl("/foo.html", "https://site.com/")).toEqual("/foo.html");
|
|
20
|
+
expect(addBaseUrl("foo.html", undefined)).toEqual("foo.html");
|
|
21
|
+
});
|
package/src/view/unitView.js
CHANGED
|
@@ -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
|
-
|
|
342
|
-
|
|
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 ?? {}),
|