mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-26 08:18:12 +08:00
TS typing for Dataframe (#2382)
* initial TS typing * first cut at Dataframe TS typing * more Dataframe typing * comments * more Dataframe cleanup * PR review fixes and improvements
This commit is contained in:
@@ -188,8 +188,10 @@ describe("AnnoMatrix", () => {
|
||||
(fetch as any)
|
||||
.once(serverMocks.annotationsObs(["n_genes"]))
|
||||
.once(serverMocks.annotationsObs(["n_genes"]));
|
||||
const ng1 = await am1.fetch("obs", "n_genes");
|
||||
const ng2 = await am2.fetch("obs", "n_genes");
|
||||
const ng1 = (await am1.fetch("obs", "n_genes")) as Dataframe;
|
||||
const ng2 = (await am2.fetch("obs", "n_genes")) as Dataframe;
|
||||
expect(ng1).toBeDefined();
|
||||
expect(ng2).toBeDefined();
|
||||
expect(ng1).toHaveLength(ng2.length);
|
||||
expect(ng1.colIndex.labels()).toEqual(ng2.colIndex.labels());
|
||||
expect(ng1.col("n_genes").asArray()).toEqual(
|
||||
@@ -216,7 +218,7 @@ describe("AnnoMatrix", () => {
|
||||
);
|
||||
expect(base.getMatrixColumns("obs")).not.toContain("foo");
|
||||
expect(am1.getMatrixColumns("obs")).toContain("foo");
|
||||
const foo = await am1.fetch("obs", "foo");
|
||||
const foo: Dataframe = await am1.fetch("obs", "foo");
|
||||
expect(foo).toBeDefined();
|
||||
expect(foo).toBeInstanceOf(Dataframe);
|
||||
expect(foo).toHaveLength(am1.nObs);
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
AnnoMatrixObsCrossfilter,
|
||||
isubsetMask,
|
||||
} from "../../../src/annoMatrix";
|
||||
import { Dataframe } from "../../../src/util/dataframe";
|
||||
import { rangeFill } from "../../../src/util/range";
|
||||
|
||||
enableFetchMocks();
|
||||
@@ -132,7 +133,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
)
|
||||
);
|
||||
|
||||
const df = await annoMatrix.fetch("obs", "louvain");
|
||||
const df: Dataframe = await annoMatrix.fetch("obs", "louvain");
|
||||
const values = df.col("louvain").asArray();
|
||||
const selected = xfltr.allSelectedMask();
|
||||
values.every(
|
||||
@@ -265,7 +266,11 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
expect(xfltr).toBeDefined();
|
||||
expect(xfltr.countSelected()).toEqual(240);
|
||||
|
||||
const df = await annoMatrixSubset.fetch("obs", "louvain");
|
||||
const df: Dataframe = (await annoMatrixSubset.fetch(
|
||||
"obs",
|
||||
"louvain"
|
||||
)) as Dataframe;
|
||||
expect(df).toBeDefined();
|
||||
const values = df.col("louvain").asArray();
|
||||
const selected = xfltr.allSelectedMask();
|
||||
values.every(
|
||||
@@ -354,7 +359,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
).toHaveLength(1);
|
||||
|
||||
// check data update.
|
||||
const df = await xfltr.annoMatrix.fetch("obs", "foo");
|
||||
const df: Dataframe = await xfltr.annoMatrix.fetch("obs", "foo");
|
||||
expect(
|
||||
df
|
||||
.col("foo")
|
||||
@@ -649,7 +654,7 @@ describe("AnnoMatrixCrossfilter", () => {
|
||||
values: ["purple"],
|
||||
});
|
||||
expect(xfltr2.countSelected()).toEqual(2);
|
||||
expect(xfltr2.allSelectedLabels()).toEqual(Int32Array.from([0, 10]));
|
||||
expect(xfltr2.allSelectedLabels()).toEqual(Array.from([0, 10]));
|
||||
});
|
||||
|
||||
test("resetObsColumnValues", async () => {
|
||||
|
||||
@@ -43,7 +43,6 @@ function getEncodedDataframe(colNames: any, length: any, colSchemas: any) {
|
||||
const colIndex = new KeyIndex(colNames);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const columns = colSchemas.map((s: any) => makeMockColumn(s, length));
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
const df = new Dataframe([length, colNames.length], columns, null, colIndex);
|
||||
const body = encodeMatrixFBS(df);
|
||||
return body;
|
||||
@@ -56,7 +55,6 @@ export function dataframeResponse(colNames: any, columns: any) {
|
||||
[columns[0].length, colNames.length],
|
||||
columns,
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
colIndex
|
||||
);
|
||||
const body = encodeMatrixFBS(df);
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
|
||||
import { NumberArray } from "../../src/common/types/arraytypes";
|
||||
import calcCentroid from "../../src/util/centroid";
|
||||
import quantile from "../../src/util/quantile";
|
||||
import { matrixFBSToDataframe } from "../../src/util/stateManager/matrix";
|
||||
import * as REST from "./stateManager/sampleResponses";
|
||||
import { indexEntireSchema } from "../../src/util/stateManager/schemaHelpers";
|
||||
import { normalizeWritableCategoricalSchema } from "../../src/annoMatrix/normalize";
|
||||
import { Dataframe } from "../../src/util/dataframe";
|
||||
|
||||
describe("centroid", () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
let schema: any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
let obsAnnotations: any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
let obsLayout: any;
|
||||
let obsAnnotations: Dataframe;
|
||||
let obsLayout: Dataframe;
|
||||
|
||||
beforeAll(() => {
|
||||
schema = indexEntireSchema(cloneDeep(REST.schema.schema));
|
||||
@@ -43,8 +43,8 @@ describe("centroid", () => {
|
||||
|
||||
// This expected result assumes that all cells belong in all categorical values inside of sample response
|
||||
const expectedResult = [
|
||||
quantile([0.5], obsLayout.col("umap_0").asArray())[0],
|
||||
quantile([0.5], obsLayout.col("umap_1").asArray())[0],
|
||||
quantile([0.5], obsLayout.col("umap_0").asArray() as NumberArray)[0],
|
||||
quantile([0.5], obsLayout.col("umap_1").asArray() as NumberArray)[0],
|
||||
];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
@@ -68,8 +68,8 @@ describe("centroid", () => {
|
||||
|
||||
// This expected result assumes that all cells belong in all categorical values inside of sample response
|
||||
const expectedResult = [
|
||||
quantile([0.5], obsLayout.col("umap_0").asArray())[0],
|
||||
quantile([0.5], obsLayout.col("umap_1").asArray())[0],
|
||||
quantile([0.5], obsLayout.col("umap_0").asArray() as NumberArray)[0],
|
||||
quantile([0.5], obsLayout.col("umap_1").asArray() as NumberArray)[0],
|
||||
];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
|
||||
@@ -6,7 +6,8 @@ describe("dataframe constructor", () => {
|
||||
expect(df).toBeDefined();
|
||||
expect(df.dims).toEqual([0, 0]);
|
||||
expect(df).toHaveLength(0);
|
||||
expect(df.icol(0)).not.toBeDefined();
|
||||
expect(df.ihasCol(0)).toBeFalsy();
|
||||
expect(() => df.icol(0)).toThrow(RangeError);
|
||||
});
|
||||
|
||||
test("create with default indices", () => {
|
||||
@@ -23,13 +24,19 @@ describe("dataframe constructor", () => {
|
||||
expect(df.at(2, 1)).toEqual(1);
|
||||
expect(df.iat(0, 0)).toEqual(0);
|
||||
expect(df.iat(2, 1)).toEqual(1);
|
||||
|
||||
expect(Array.from(df.rowIndex.labels())).toEqual(
|
||||
df.rowIndex.getLabels(df.rowIndex.getOffsets(df.rowIndex.labels()))
|
||||
);
|
||||
expect(Array.from(df.colIndex.labels())).toEqual(
|
||||
df.colIndex.getLabels(df.colIndex.getOffsets(df.colIndex.labels()))
|
||||
);
|
||||
});
|
||||
|
||||
test("create with labelled indices", () => {
|
||||
const df = new Dataframe.Dataframe(
|
||||
[3, 2],
|
||||
[new Int32Array([0, 1, 2]), new Int32Array([3, 4, 5])],
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||
new Dataframe.DenseInt32Index([2, 1, 0]),
|
||||
new Dataframe.KeyIndex(["A", "B"])
|
||||
);
|
||||
@@ -56,7 +63,6 @@ describe("simple data access", () => {
|
||||
new Float64Array([0.0, Number.NaN, Number.POSITIVE_INFINITY, 3.14159]),
|
||||
["red", "blue", "green", "nan"],
|
||||
],
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||
new Dataframe.DenseInt32Index([3, 2, 1, 0]),
|
||||
new Dataframe.KeyIndex(["numbers", "colors"])
|
||||
);
|
||||
@@ -123,7 +129,9 @@ describe("simple data access", () => {
|
||||
expect(df.has(3, "foo")).toBeFalsy();
|
||||
expect(df.has(-1, "numbers")).toBeFalsy();
|
||||
expect(df.has(-1, -1)).toBeFalsy();
|
||||
expect(df.has(null, null)).toBeFalsy();
|
||||
expect(
|
||||
df.has(null as unknown as number, null as unknown as number)
|
||||
).toBeFalsy();
|
||||
expect(df.has(0, "foo")).toBeFalsy();
|
||||
expect(df.has(99, "numbers")).toBeFalsy();
|
||||
expect(df.has(99, "foo")).toBeFalsy();
|
||||
@@ -141,12 +149,10 @@ describe("dataframe subsetting", () => {
|
||||
["red", "green", "blue"],
|
||||
],
|
||||
null, // identity index
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
||||
);
|
||||
|
||||
test("all rows, one column", () => {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||
const dfA = sourceDf.subset(null, ["colors"]);
|
||||
expect(dfA).toBeDefined();
|
||||
expect(dfA.dims).toEqual([3, 1]);
|
||||
@@ -162,7 +168,6 @@ describe("dataframe subsetting", () => {
|
||||
});
|
||||
|
||||
test("all rows, two columns", () => {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||
const dfB = sourceDf.subset(null, ["float32", "colors"]);
|
||||
expect(dfB).toBeDefined();
|
||||
expect(dfB.dims).toEqual([3, 2]);
|
||||
@@ -232,7 +237,6 @@ describe("dataframe subsetting", () => {
|
||||
});
|
||||
|
||||
test("two rows, two colums", () => {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||
const dfF = sourceDf.subset([0, 2], ["int32", "float32"]);
|
||||
expect(dfF).toBeDefined();
|
||||
expect(dfF.dims).toEqual([2, 2]);
|
||||
@@ -242,7 +246,6 @@ describe("dataframe subsetting", () => {
|
||||
expect(dfF.colIndex.labels()).toEqual(["int32", "float32"]);
|
||||
|
||||
// reverse the row and column order
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||
const dfFr = sourceDf.subset([2, 0], ["float32", "int32"]);
|
||||
expect(dfFr).toBeDefined();
|
||||
expect(dfFr.dims).toEqual([2, 2]);
|
||||
@@ -255,26 +258,23 @@ describe("dataframe subsetting", () => {
|
||||
test("withRowIndex", () => {
|
||||
const df = sourceDf.subset(
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||
["int32", "float32"],
|
||||
new Dataframe.DenseInt32Index([3, 2, 1])
|
||||
new Dataframe.DenseInt32Index([2, 1])
|
||||
);
|
||||
expect(df.dims).toEqual([2, 2]);
|
||||
expect(df.colIndex).toBeInstanceOf(Dataframe.KeyIndex);
|
||||
expect(df.rowIndex).toBeInstanceOf(Dataframe.DenseInt32Index);
|
||||
expect(df.at(3, "int32")).toEqual(df.iat(0, 0));
|
||||
expect(df.at(2, "int32")).toEqual(df.iat(0, 0));
|
||||
});
|
||||
|
||||
test("withRowIndex error checks", () => {
|
||||
expect(() =>
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||
sourceDf.subset(null, ["red"], new Dataframe.IdentityInt32Index(1))
|
||||
).toThrow(RangeError);
|
||||
expect(() =>
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||
sourceDf.subset(null, ["red"], new Dataframe.DenseInt32Index([0, 1]))
|
||||
).toThrow(RangeError);
|
||||
expect(() =>
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message
|
||||
sourceDf.subset(null, ["red"], new Dataframe.KeyIndex([0, 1, 2, 3]))
|
||||
).toThrow(RangeError);
|
||||
});
|
||||
@@ -289,14 +289,12 @@ describe("dataframe subsetting", () => {
|
||||
new Float32Array([4.4, 5.5, 6.6]),
|
||||
["red", "green", "blue"],
|
||||
],
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||
new Dataframe.DenseInt32Index([2, 4, 6]),
|
||||
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
||||
);
|
||||
|
||||
const dfA = sourceDf.isubsetMask(
|
||||
new Uint8Array([0, 1, 1]),
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'Uint8Array' is not assignable to... Remove this comment to see the full error message
|
||||
new Uint8Array([1, 0, 0, 1])
|
||||
);
|
||||
expect(dfA.dims).toEqual([2, 2]);
|
||||
@@ -316,7 +314,6 @@ describe("dataframe subsetting", () => {
|
||||
["red", "green", "blue"],
|
||||
],
|
||||
null, // identity index
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["int32", "string", "float32", "colors"])
|
||||
);
|
||||
|
||||
@@ -330,7 +327,6 @@ describe("dataframe subsetting", () => {
|
||||
});
|
||||
|
||||
test("all rows, two cols", () => {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number[]' is not assignable to p... Remove this comment to see the full error message
|
||||
const dfA = sourceDf.isubset(null, [1, 2]);
|
||||
expect(dfA.dims).toEqual([3, 2]);
|
||||
expect(dfA.icol(0).asArray()).toEqual(["A", "B", "C"]);
|
||||
@@ -376,7 +372,6 @@ describe("dataframe factories", () => {
|
||||
const dfA = new Dataframe.Dataframe(
|
||||
[3, 2],
|
||||
[new Int32Array([0, 1, 2]), new Int32Array([3, 4, 5])],
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||
new Dataframe.DenseInt32Index([2, 1, 0]),
|
||||
new Dataframe.KeyIndex(["A", "B"])
|
||||
);
|
||||
@@ -401,7 +396,6 @@ describe("dataframe factories", () => {
|
||||
[true, false],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["colors", "bools"])
|
||||
);
|
||||
const dfA = df.withCol("numbers", [1, 0]);
|
||||
@@ -425,7 +419,6 @@ describe("dataframe factories", () => {
|
||||
[true, false],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||
new Dataframe.DenseInt32Index([74, 75])
|
||||
);
|
||||
const dfA = df.withCol(72, [1, 0]);
|
||||
@@ -451,7 +444,6 @@ describe("dataframe factories", () => {
|
||||
[true, false],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||
new Dataframe.DenseInt32Index([74, 75])
|
||||
);
|
||||
const dfA = df.withCol(999, [1, 0]);
|
||||
@@ -560,7 +552,6 @@ describe("dataframe factories", () => {
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||
);
|
||||
|
||||
@@ -569,14 +560,11 @@ describe("dataframe factories", () => {
|
||||
[3, 1],
|
||||
[["red", "blue", "green"]],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["colorsA"])
|
||||
);
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
expect(() => dfA.withColsFrom(dfB)).toThrow(RangeError);
|
||||
|
||||
/* duplicate labels should throw an error */
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
expect(() => dfA.withColsFrom(dfA)).toThrow(Error);
|
||||
});
|
||||
|
||||
@@ -587,18 +575,15 @@ describe("dataframe factories", () => {
|
||||
[2, 1],
|
||||
[["red", "blue"]],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["colors"])
|
||||
);
|
||||
const dfB = new Dataframe.Dataframe(
|
||||
[2, 1],
|
||||
[[true, false]],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["bools"])
|
||||
);
|
||||
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
const dfLikeA = dfEmpty.withColsFrom(dfA);
|
||||
expect(dfLikeA).toBeDefined();
|
||||
expect(dfLikeA.dims).toEqual(dfA.dims);
|
||||
@@ -607,7 +592,6 @@ describe("dataframe factories", () => {
|
||||
expect(dfLikeA.rowIndex.labels()).toEqual(dfA.rowIndex.labels());
|
||||
expect(dfLikeA.icol(0).asArray()).toEqual(dfA.icol(0).asArray());
|
||||
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
const dfAlsoLikeA = dfA.withColsFrom(dfEmpty);
|
||||
expect(dfAlsoLikeA).toBeDefined();
|
||||
expect(dfAlsoLikeA.dims).toEqual(dfA.dims);
|
||||
@@ -616,7 +600,6 @@ describe("dataframe factories", () => {
|
||||
expect(dfAlsoLikeA.rowIndex.labels()).toEqual(dfA.rowIndex.labels());
|
||||
expect(dfAlsoLikeA.icol(0).asArray()).toEqual(dfA.icol(0).asArray());
|
||||
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
const dfC = dfA.withColsFrom(dfB);
|
||||
expect(dfC).toBeDefined();
|
||||
expect(dfC.dims).toEqual([2, 2]);
|
||||
@@ -633,7 +616,6 @@ describe("dataframe factories", () => {
|
||||
[2, 1],
|
||||
[["red", "blue"]],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["colors"])
|
||||
);
|
||||
const dfB = new Dataframe.Dataframe(
|
||||
@@ -644,7 +626,6 @@ describe("dataframe factories", () => {
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||
);
|
||||
|
||||
@@ -677,7 +658,6 @@ describe("dataframe factories", () => {
|
||||
[2, 1],
|
||||
[["red", "blue"]],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["colors"])
|
||||
);
|
||||
const dfB = new Dataframe.Dataframe(
|
||||
@@ -688,7 +668,6 @@ describe("dataframe factories", () => {
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||
);
|
||||
|
||||
@@ -712,7 +691,6 @@ describe("dataframe factories", () => {
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["colors", "bools", "numbers"])
|
||||
);
|
||||
const dfA = df.dropCol("colors");
|
||||
@@ -784,7 +762,6 @@ describe("dataframe factories", () => {
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'DenseInt32Index' is not assignab... Remove this comment to see the full error message
|
||||
new Dataframe.DenseInt32Index([102, 101, 100])
|
||||
);
|
||||
const dfA = df.dropCol(101);
|
||||
@@ -811,8 +788,7 @@ describe("dataframe factories", () => {
|
||||
new Float64Array(3).fill(1.1),
|
||||
]
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const dfB = dfA.mapColumns((col: any, idx: any) => {
|
||||
const dfB = dfA.mapColumns((col, idx) => {
|
||||
expect(dfA.icol(idx).asArray()).toBe(col);
|
||||
return col;
|
||||
});
|
||||
@@ -855,7 +831,6 @@ describe("dataframe factories", () => {
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["A", "B"])
|
||||
);
|
||||
const dfB = dfA.renameCol("B", "C");
|
||||
@@ -868,8 +843,7 @@ describe("dataframe factories", () => {
|
||||
});
|
||||
|
||||
describe("dataframe col", () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
let df: any = null;
|
||||
let df: Dataframe.Dataframe;
|
||||
beforeEach(() => {
|
||||
df = new Dataframe.Dataframe(
|
||||
[2, 2],
|
||||
@@ -878,7 +852,6 @@ describe("dataframe col", () => {
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["A", "B"])
|
||||
);
|
||||
});
|
||||
@@ -887,8 +860,8 @@ describe("dataframe col", () => {
|
||||
expect(df).toBeDefined();
|
||||
expect(df.col("A")).toBe(df.icol(0));
|
||||
expect(df.col("B")).toBe(df.icol(1));
|
||||
expect(df.col("undefined")).toBeUndefined();
|
||||
expect(df.icol("undefined")).toBeUndefined();
|
||||
expect(() => df.col("undefined")).toThrow(RangeError);
|
||||
expect(() => df.icol("undefined" as unknown as number)).toThrow(RangeError);
|
||||
|
||||
const colA = df.col("A");
|
||||
expect(colA).toBeInstanceOf(Function);
|
||||
@@ -942,13 +915,13 @@ describe("dataframe col", () => {
|
||||
expect(df.col("A").indexOf(true)).toEqual(0);
|
||||
expect(df.col("A").indexOf(false)).toEqual(1);
|
||||
expect(df.col("A").indexOf(99)).toBeUndefined();
|
||||
expect(df.col("A").indexOf(undefined)).toBeUndefined();
|
||||
expect(df.col("A").indexOf(undefined as unknown as number)).toBeUndefined();
|
||||
expect(df.col("A").indexOf(1)).toBeUndefined();
|
||||
|
||||
expect(df.col("B").indexOf(1)).toEqual(0);
|
||||
expect(df.col("B").indexOf(0)).toEqual(1);
|
||||
expect(df.col("B").indexOf(99)).toBeUndefined();
|
||||
expect(df.col("B").indexOf(undefined)).toBeUndefined();
|
||||
expect(df.col("B").indexOf(undefined as unknown as number)).toBeUndefined();
|
||||
expect(df.col("B").indexOf(true)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -991,7 +964,7 @@ describe("label indexing", () => {
|
||||
|
||||
test("offsets", () => {
|
||||
expect(idx.getOffset(1)).toEqual(1);
|
||||
expect(idx.getOffsets([1, 3])).toEqual([1, 3]);
|
||||
expect(idx.getOffsets([1, 3])).toEqual(new Int32Array([1, 3]));
|
||||
});
|
||||
|
||||
test("subset", () => {
|
||||
@@ -1069,7 +1042,7 @@ describe("label indexing", () => {
|
||||
false,
|
||||
])
|
||||
.labels()
|
||||
).toEqual(new Int32Array([]));
|
||||
).toEqual([]);
|
||||
expect(
|
||||
idx
|
||||
.isubsetMask([
|
||||
@@ -1163,16 +1136,14 @@ describe("label indexing", () => {
|
||||
expect(idx.labels()).toEqual(new Int32Array([99, 1002, 48, 0, 22]));
|
||||
expect(idx.size()).toEqual(5);
|
||||
expect(idx.getLabel(0)).toEqual(99);
|
||||
expect(idx.getLabels(new Int32Array([2, 4]))).toEqual(
|
||||
new Int32Array([48, 22])
|
||||
);
|
||||
expect(idx.getLabels(new Int32Array([2, 4]))).toEqual([48, 22]);
|
||||
expect(idx.getLabels([2, 4])).toEqual([48, 22]);
|
||||
});
|
||||
|
||||
test("offsets", () => {
|
||||
expect(idx.getOffset(1002)).toEqual(1);
|
||||
expect(idx.getOffset(0)).toEqual(3);
|
||||
expect(idx.getOffsets([0, 48])).toEqual([3, 2]);
|
||||
expect(idx.getOffsets([0, 48])).toEqual(new Int32Array([3, 2]));
|
||||
});
|
||||
|
||||
test("subset", () => {
|
||||
@@ -1199,7 +1170,7 @@ describe("label indexing", () => {
|
||||
);
|
||||
expect(
|
||||
idx.isubsetMask([false, false, false, false, false]).labels()
|
||||
).toEqual(new Int32Array([]));
|
||||
).toEqual([]);
|
||||
expect(idx.isubsetMask([true, true, false, true, true]).labels()).toEqual(
|
||||
new Int32Array([99, 1002, 0, 22])
|
||||
);
|
||||
@@ -1301,59 +1272,67 @@ describe("corner cases", () => {
|
||||
const idx = new Dataframe.IdentityInt32Index(10);
|
||||
expect(idx.getOffset(0)).toBe(0);
|
||||
expect(idx.getOffset(9)).toBe(9);
|
||||
expect(idx.getOffset(10)).toBeUndefined();
|
||||
expect(idx.getOffset(-1)).toBeUndefined();
|
||||
expect(idx.getOffset("sort")).toBeUndefined();
|
||||
expect(idx.getOffset("length")).toBeUndefined();
|
||||
expect(idx.getOffset(true)).toBeUndefined();
|
||||
expect(idx.getOffset(0.001)).toBeUndefined();
|
||||
expect(idx.getOffset({})).toBeUndefined();
|
||||
expect(idx.getOffset([])).toBeUndefined();
|
||||
expect(idx.getOffset(new Float32Array())).toBeUndefined();
|
||||
expect(idx.getOffset("__proto__")).toBeUndefined();
|
||||
expect(idx.getOffset(10)).toBe(-1);
|
||||
expect(idx.getOffset(-1)).toBe(-1);
|
||||
expect(idx.getOffset("sort")).toBe(-1);
|
||||
expect(idx.getOffset("length")).toBe(-1);
|
||||
expect(idx.getOffset(true as unknown as string)).toBe(-1);
|
||||
expect(idx.getOffset(0.001)).toBe(-1);
|
||||
expect(idx.getOffset({} as unknown as string)).toBe(-1);
|
||||
expect(idx.getOffset([] as unknown as string)).toBe(-1);
|
||||
expect(idx.getOffset(new Float32Array() as unknown as string)).toBe(-1);
|
||||
expect(idx.getOffset("__proto__")).toBe(-1);
|
||||
|
||||
expect(idx.getLabel(0)).toBe(0);
|
||||
expect(idx.getLabel(9)).toBe(9);
|
||||
expect(idx.getLabel(10)).toBeUndefined();
|
||||
expect(idx.getLabel(-1)).toBeUndefined();
|
||||
expect(idx.getLabel("sort")).toBeUndefined();
|
||||
expect(idx.getLabel("length")).toBeUndefined();
|
||||
expect(idx.getLabel(true)).toBeUndefined();
|
||||
expect(idx.getLabel("sort" as unknown as number)).toBeUndefined();
|
||||
expect(idx.getLabel("length" as unknown as number)).toBeUndefined();
|
||||
expect(idx.getLabel(true as unknown as number)).toBeUndefined();
|
||||
expect(idx.getLabel(0.001)).toBeUndefined();
|
||||
expect(idx.getLabel({})).toBeUndefined();
|
||||
expect(idx.getLabel([])).toBeUndefined();
|
||||
expect(idx.getLabel(new Float32Array())).toBeUndefined();
|
||||
expect(idx.getLabel("__proto__")).toBeUndefined();
|
||||
expect(idx.getLabel({} as unknown as number)).toBeUndefined();
|
||||
expect(idx.getLabel([] as unknown as number)).toBeUndefined();
|
||||
expect(
|
||||
idx.getLabel(new Float32Array() as unknown as number)
|
||||
).toBeUndefined();
|
||||
expect(idx.getLabel("__proto__" as unknown as number)).toBeUndefined();
|
||||
});
|
||||
|
||||
test("dense integer index rejects non-integer labels", () => {
|
||||
const idx = new Dataframe.DenseInt32Index([-10, 0, 3, 9, 10]);
|
||||
expect(idx.getOffset(-10)).toBe(0);
|
||||
expect(idx.getOffset(0)).toBe(1);
|
||||
expect(idx.getOffset(3)).toBe(2);
|
||||
expect(idx.getOffset(9)).toBe(3);
|
||||
expect(idx.getOffset(1)).toBeUndefined();
|
||||
expect(idx.getOffset(11)).toBeUndefined();
|
||||
expect(idx.getOffset(-1)).toBeUndefined();
|
||||
expect(idx.getOffset("sort")).toBeUndefined();
|
||||
expect(idx.getOffset("length")).toBeUndefined();
|
||||
expect(idx.getOffset(true)).toBeUndefined();
|
||||
expect(idx.getOffset(0.001)).toBeUndefined();
|
||||
expect(idx.getOffset({})).toBeUndefined();
|
||||
expect(idx.getOffset([])).toBeUndefined();
|
||||
expect(idx.getOffset(new Float32Array())).toBeUndefined();
|
||||
expect(idx.getOffset("__proto__")).toBeUndefined();
|
||||
expect(idx.getOffset(10)).toBe(4);
|
||||
|
||||
expect(idx.getOffset(1)).toBe(-1);
|
||||
expect(idx.getOffset(11)).toBe(-1);
|
||||
expect(idx.getOffset(-1)).toBe(-1);
|
||||
expect(idx.getOffset("sort")).toBe(-1);
|
||||
expect(idx.getOffset("length")).toBe(-1);
|
||||
expect(idx.getOffset(true as unknown as string)).toBe(-1);
|
||||
expect(idx.getOffset(0.001)).toBe(-1);
|
||||
expect(idx.getOffset({} as unknown as string)).toBe(-1);
|
||||
expect(idx.getOffset([] as unknown as string)).toBe(-1);
|
||||
expect(idx.getOffset(new Float32Array() as unknown as string)).toBe(-1);
|
||||
expect(idx.getOffset("__proto__")).toBe(-1);
|
||||
|
||||
expect(idx.getLabel(0)).toBe(-10);
|
||||
expect(idx.getLabel(4)).toBe(10);
|
||||
expect(idx.getLabel(10)).toBeUndefined();
|
||||
expect(idx.getLabel(-1)).toBeUndefined();
|
||||
expect(idx.getLabel("sort")).toBeUndefined();
|
||||
expect(idx.getLabel("length")).toBeUndefined();
|
||||
expect(idx.getLabel(true)).toBeUndefined();
|
||||
expect(idx.getLabel("sort" as unknown as number)).toBeUndefined();
|
||||
expect(idx.getLabel("length" as unknown as number)).toBeUndefined();
|
||||
expect(idx.getLabel(true as unknown as number)).toBeUndefined();
|
||||
expect(idx.getLabel(0.001)).toBeUndefined();
|
||||
expect(idx.getLabel({})).toBeUndefined();
|
||||
expect(idx.getLabel([])).toBeUndefined();
|
||||
expect(idx.getLabel(new Float32Array())).toBeUndefined();
|
||||
expect(idx.getLabel("__proto__")).toBeUndefined();
|
||||
expect(idx.getLabel({} as unknown as number)).toBeUndefined();
|
||||
expect(idx.getLabel([] as unknown as number)).toBeUndefined();
|
||||
expect(
|
||||
idx.getLabel(new Float32Array() as unknown as number)
|
||||
).toBeUndefined();
|
||||
expect(idx.getLabel("__proto__" as unknown as number)).toBeUndefined();
|
||||
});
|
||||
|
||||
test("Empty dataframe rejects bogus labels", () => {
|
||||
@@ -1361,39 +1340,55 @@ describe("corner cases", () => {
|
||||
|
||||
expect(df.hasCol("sort")).toBeFalsy();
|
||||
expect(df.hasCol(0)).toBeFalsy();
|
||||
expect(df.hasCol(true)).toBeFalsy();
|
||||
expect(df.hasCol(false)).toBeFalsy();
|
||||
expect(df.hasCol([])).toBeFalsy();
|
||||
expect(df.hasCol({})).toBeFalsy();
|
||||
expect(df.hasCol(null)).toBeFalsy();
|
||||
expect(df.hasCol(undefined)).toBeFalsy();
|
||||
expect(df.hasCol(true as unknown as number)).toBeFalsy();
|
||||
expect(df.hasCol(false as unknown as number)).toBeFalsy();
|
||||
expect(df.hasCol([] as unknown as number)).toBeFalsy();
|
||||
expect(df.hasCol({} as unknown as number)).toBeFalsy();
|
||||
expect(df.hasCol(null as unknown as number)).toBeFalsy();
|
||||
expect(df.hasCol(undefined as unknown as number)).toBeFalsy();
|
||||
|
||||
expect(df.col("sort")).toBeUndefined();
|
||||
expect(df.col(0)).toBeUndefined();
|
||||
expect(df.col(true)).toBeUndefined();
|
||||
expect(df.col(false)).toBeUndefined();
|
||||
expect(df.col([])).toBeUndefined();
|
||||
expect(df.col({})).toBeUndefined();
|
||||
expect(df.col(null)).toBeUndefined();
|
||||
expect(df.col(undefined)).toBeUndefined();
|
||||
expect(() => df.col("sort")).toThrow(RangeError);
|
||||
expect(() => df.col(0)).toThrow(RangeError);
|
||||
expect(() => df.col(true as unknown as string)).toThrow(RangeError);
|
||||
expect(() => df.col(false as unknown as string)).toThrow(RangeError);
|
||||
expect(() => df.col([] as unknown as string)).toThrow(RangeError);
|
||||
expect(() => df.col({} as unknown as string)).toThrow(RangeError);
|
||||
expect(() => df.col(null as unknown as string)).toThrow(RangeError);
|
||||
expect(() => df.col(undefined as unknown as string)).toThrow(RangeError);
|
||||
|
||||
expect(df.icol("sort")).toBeUndefined();
|
||||
expect(df.icol(0)).toBeUndefined();
|
||||
expect(df.icol(true)).toBeUndefined();
|
||||
expect(df.icol(false)).toBeUndefined();
|
||||
expect(df.icol([])).toBeUndefined();
|
||||
expect(df.icol({})).toBeUndefined();
|
||||
expect(df.icol(null)).toBeUndefined();
|
||||
expect(df.icol(undefined)).toBeUndefined();
|
||||
expect(() => df.icol("sort" as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol(0)).toThrow(RangeError);
|
||||
expect(() => df.icol(true as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol(false as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol([] as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol({} as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol(null as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol(undefined as unknown as number)).toThrow(RangeError);
|
||||
|
||||
expect(df.ihas("sort", "length")).toBeFalsy();
|
||||
expect(df.ihas("0", "0")).toBeFalsy();
|
||||
expect(df.ihas("", "")).toBeFalsy();
|
||||
expect(df.ihas(null, null)).toBeFalsy();
|
||||
expect(df.ihas(undefined, undefined)).toBeFalsy();
|
||||
expect(df.ihas(true, true)).toBeFalsy();
|
||||
expect(df.ihas([], [])).toBeFalsy();
|
||||
expect(df.ihas({}, {})).toBeFalsy();
|
||||
expect(
|
||||
df.ihas("sort" as unknown as number, "length" as unknown as number)
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
df.ihas("0" as unknown as number, "0" as unknown as number)
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
df.ihas("" as unknown as number, "" as unknown as number)
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
df.ihas(null as unknown as number, null as unknown as number)
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
df.ihas(undefined as unknown as number, undefined as unknown as number)
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
df.ihas(true as unknown as number, true as unknown as number)
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
df.ihas([] as unknown as number, [] as unknown as number)
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
df.ihas({} as unknown as number, {} as unknown as number)
|
||||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("Dataframe rejects bogus labels", () => {
|
||||
@@ -1404,58 +1399,64 @@ describe("corner cases", () => {
|
||||
[1, 0],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["A", "B"])
|
||||
);
|
||||
|
||||
expect(df.hasCol("sort")).toBeFalsy();
|
||||
expect(df.hasCol("__proto__")).toBeFalsy();
|
||||
expect(df.hasCol(0)).toBeFalsy();
|
||||
expect(df.hasCol(true)).toBeFalsy();
|
||||
expect(df.hasCol(false)).toBeFalsy();
|
||||
expect(df.hasCol([])).toBeFalsy();
|
||||
expect(df.hasCol({})).toBeFalsy();
|
||||
expect(df.hasCol(null)).toBeFalsy();
|
||||
expect(df.hasCol(undefined)).toBeFalsy();
|
||||
expect(df.hasCol(true as unknown as string)).toBeFalsy();
|
||||
expect(df.hasCol(false as unknown as string)).toBeFalsy();
|
||||
expect(df.hasCol([] as unknown as string)).toBeFalsy();
|
||||
expect(df.hasCol({} as unknown as string)).toBeFalsy();
|
||||
expect(df.hasCol(null as unknown as string)).toBeFalsy();
|
||||
expect(df.hasCol(undefined as unknown as string)).toBeFalsy();
|
||||
|
||||
expect(df.col("sort")).toBeUndefined();
|
||||
expect(df.col("__proto__")).toBeUndefined();
|
||||
expect(df.col(0)).toBeUndefined();
|
||||
expect(df.col(true)).toBeUndefined();
|
||||
expect(df.col(false)).toBeUndefined();
|
||||
expect(df.col([])).toBeUndefined();
|
||||
expect(df.col({})).toBeUndefined();
|
||||
expect(df.col(null)).toBeUndefined();
|
||||
expect(df.col(undefined)).toBeUndefined();
|
||||
expect(() => df.col("sort")).toThrow(RangeError);
|
||||
expect(() => df.col("__proto__")).toThrow(RangeError);
|
||||
expect(() => df.col(0)).toThrow(RangeError);
|
||||
expect(() => df.col(true as unknown as string)).toThrow(RangeError);
|
||||
expect(() => df.col(false as unknown as string)).toThrow(RangeError);
|
||||
expect(() => df.col([] as unknown as string)).toThrow(RangeError);
|
||||
expect(() => df.col({} as unknown as string)).toThrow(RangeError);
|
||||
expect(() => df.col(null as unknown as string)).toThrow(RangeError);
|
||||
expect(() => df.col(undefined as unknown as string)).toThrow(RangeError);
|
||||
|
||||
expect(df.icol("sort")).toBeUndefined();
|
||||
expect(df.icol("__proto__")).toBeUndefined();
|
||||
expect(df.icol(-1)).toBeUndefined();
|
||||
expect(df.icol(true)).toBeUndefined();
|
||||
expect(df.icol(false)).toBeUndefined();
|
||||
expect(df.icol([])).toBeUndefined();
|
||||
expect(df.icol({})).toBeUndefined();
|
||||
expect(df.icol(null)).toBeUndefined();
|
||||
expect(df.icol(undefined)).toBeUndefined();
|
||||
expect(() => df.icol("sort" as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol("__proto__" as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol(-1)).toThrow(RangeError);
|
||||
expect(() => df.icol(true as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol(false as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol([] as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol({} as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol(null as unknown as number)).toThrow(RangeError);
|
||||
expect(() => df.icol(undefined as unknown as number)).toThrow(RangeError);
|
||||
|
||||
expect(df.ihas("sort", "length")).toBeFalsy();
|
||||
expect(df.ihas("__proto__", "__proto__")).toBeFalsy();
|
||||
expect(
|
||||
df.ihas("sort" as unknown as number, "length" as unknown as number)
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
df.ihas(
|
||||
"__proto__" as unknown as number,
|
||||
"__proto__" as unknown as number
|
||||
)
|
||||
).toBeFalsy();
|
||||
|
||||
expect(df.ihas(-1, 0)).toBeFalsy();
|
||||
expect(df.ihas("0", 0)).toBeFalsy();
|
||||
expect(df.ihas("", 0)).toBeFalsy();
|
||||
expect(df.ihas(null, 0)).toBeFalsy();
|
||||
expect(df.ihas(undefined, 0)).toBeFalsy();
|
||||
expect(df.ihas([], 0)).toBeFalsy();
|
||||
expect(df.ihas({}, 0)).toBeFalsy();
|
||||
expect(df.ihas("0" as unknown as number, 0)).toBeFalsy();
|
||||
expect(df.ihas("" as unknown as number, 0)).toBeFalsy();
|
||||
expect(df.ihas(null as unknown as number, 0)).toBeFalsy();
|
||||
expect(df.ihas(undefined as unknown as number, 0)).toBeFalsy();
|
||||
expect(df.ihas([] as unknown as number, 0)).toBeFalsy();
|
||||
expect(df.ihas({} as unknown as number, 0)).toBeFalsy();
|
||||
|
||||
expect(df.ihas(0, -1)).toBeFalsy();
|
||||
expect(df.ihas(0, "0")).toBeFalsy();
|
||||
expect(df.ihas(0, "")).toBeFalsy();
|
||||
expect(df.ihas(0, null)).toBeFalsy();
|
||||
expect(df.ihas(0, undefined)).toBeFalsy();
|
||||
expect(df.ihas(0, [])).toBeFalsy();
|
||||
expect(df.ihas(0, {})).toBeFalsy();
|
||||
expect(df.ihas(0, "0" as unknown as number)).toBeFalsy();
|
||||
expect(df.ihas(0, "" as unknown as number)).toBeFalsy();
|
||||
expect(df.ihas(0, null as unknown as number)).toBeFalsy();
|
||||
expect(df.ihas(0, undefined as unknown as number)).toBeFalsy();
|
||||
expect(df.ihas(0, [] as unknown as number)).toBeFalsy();
|
||||
expect(df.ihas(0, {} as unknown as number)).toBeFalsy();
|
||||
|
||||
expect(df.has("sort", "length")).toBeFalsy();
|
||||
expect(df.has("length", "sort")).toBeFalsy();
|
||||
@@ -1464,17 +1465,17 @@ describe("corner cases", () => {
|
||||
expect(df.has(-1, "A")).toBeFalsy();
|
||||
expect(df.has("0", "A")).toBeFalsy();
|
||||
expect(df.has("", "A")).toBeFalsy();
|
||||
expect(df.has(null, "A")).toBeFalsy();
|
||||
expect(df.has(undefined, "A")).toBeFalsy();
|
||||
expect(df.has([], "A")).toBeFalsy();
|
||||
expect(df.has({}, "A")).toBeFalsy();
|
||||
expect(df.has(null as unknown as string, "A")).toBeFalsy();
|
||||
expect(df.has(undefined as unknown as string, "A")).toBeFalsy();
|
||||
expect(df.has([] as unknown as string, "A")).toBeFalsy();
|
||||
expect(df.has({} as unknown as string, "A")).toBeFalsy();
|
||||
|
||||
expect(df.has(0, -1)).toBeFalsy();
|
||||
expect(df.has(0, "0")).toBeFalsy();
|
||||
expect(df.has(0, "")).toBeFalsy();
|
||||
expect(df.has(0, null)).toBeFalsy();
|
||||
expect(df.has(0, undefined)).toBeFalsy();
|
||||
expect(df.has(0, [])).toBeFalsy();
|
||||
expect(df.has(0, {})).toBeFalsy();
|
||||
expect(df.has(0, null as unknown as string)).toBeFalsy();
|
||||
expect(df.has(0, undefined as unknown as string)).toBeFalsy();
|
||||
expect(df.has(0, [] as unknown as string)).toBeFalsy();
|
||||
expect(df.has(0, {} as unknown as string)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,11 +6,10 @@ describe("Dataframe column histogram", () => {
|
||||
[3, 3],
|
||||
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["name", "cat", "value"])
|
||||
);
|
||||
|
||||
const h1 = df.col("cat").histogram(df.col("name"));
|
||||
const h1 = df.col("cat").histogramCategoricalBy(df.col("name"));
|
||||
expect(h1).toMatchObject(
|
||||
new Map([
|
||||
["n1", new Map([["c1", 1]])],
|
||||
@@ -19,7 +18,9 @@ describe("Dataframe column histogram", () => {
|
||||
])
|
||||
);
|
||||
// memoized?
|
||||
expect(df.col("cat").histogram(df.col("name"))).toMatchObject(h1);
|
||||
expect(df.col("cat").histogramCategoricalBy(df.col("name"))).toMatchObject(
|
||||
h1
|
||||
);
|
||||
});
|
||||
|
||||
test("continuous by categorical", () => {
|
||||
@@ -27,11 +28,10 @@ describe("Dataframe column histogram", () => {
|
||||
[3, 3],
|
||||
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["name", "cat", "value"])
|
||||
);
|
||||
|
||||
const h1 = df.col("value").histogram(3, [0, 2], df.col("name"));
|
||||
const h1 = df.col("value").histogramContinuousBy(3, [0, 2], df.col("name"));
|
||||
expect(h1).toMatchObject(
|
||||
new Map([
|
||||
["n1", [1, 0, 0]],
|
||||
@@ -40,9 +40,9 @@ describe("Dataframe column histogram", () => {
|
||||
])
|
||||
);
|
||||
// memoized?
|
||||
expect(df.col("value").histogram(3, [0, 2], df.col("name"))).toMatchObject(
|
||||
h1
|
||||
);
|
||||
expect(
|
||||
df.col("value").histogramContinuousBy(3, [0, 2], df.col("name"))
|
||||
).toMatchObject(h1);
|
||||
});
|
||||
|
||||
test("categorical", () => {
|
||||
@@ -50,11 +50,10 @@ describe("Dataframe column histogram", () => {
|
||||
[3, 3],
|
||||
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["name", "cat", "value"])
|
||||
);
|
||||
|
||||
const h1 = df.col("cat").histogram();
|
||||
const h1 = df.col("cat").histogramCategorical();
|
||||
expect(h1).toMatchObject(
|
||||
new Map([
|
||||
["c1", 1],
|
||||
@@ -63,7 +62,7 @@ describe("Dataframe column histogram", () => {
|
||||
])
|
||||
);
|
||||
// memoized?
|
||||
expect(df.col("value").histogram(3, [0, 2])).toMatchObject(h1);
|
||||
expect(df.col("cat").histogramCategorical()).toMatchObject(h1);
|
||||
});
|
||||
|
||||
test("continuous", () => {
|
||||
@@ -71,14 +70,13 @@ describe("Dataframe column histogram", () => {
|
||||
[3, 3],
|
||||
[["n1", "n2", "n3"], ["c1", "c2", "c3"], new Int32Array([0, 1, 2])],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["name", "cat", "value"])
|
||||
);
|
||||
|
||||
const h1 = df.col("value").histogram(3, [0, 2]);
|
||||
const h1 = df.col("value").histogramContinuous(3, [0, 2]);
|
||||
expect(h1).toMatchObject([1, 1, 1]);
|
||||
// memoized?
|
||||
expect(df.col("value").histogram(3, [0, 2])).toMatchObject(h1);
|
||||
expect(df.col("value").histogramContinuous(3, [0, 2])).toMatchObject(h1);
|
||||
});
|
||||
|
||||
test("continuous thesholds correct", () => {
|
||||
@@ -88,20 +86,11 @@ describe("Dataframe column histogram", () => {
|
||||
[new Int32Array(vals), new Float32Array(vals)]
|
||||
);
|
||||
|
||||
expect(df.col(0).histogram(5, [0, 100])).toEqual([5, 1, 0, 0, 2]);
|
||||
expect(df.col(1).histogram(5, [0, 100])).toEqual([5, 1, 0, 0, 2]);
|
||||
expect(df.col(0).histogram(2, [0, 10])).toEqual([2, 2]);
|
||||
expect(df.col(0).histogram(10, [0, 100])).toEqual([
|
||||
3,
|
||||
2,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
expect(df.col(0).histogramContinuous(5, [0, 100])).toEqual([5, 1, 0, 0, 2]);
|
||||
expect(df.col(1).histogramContinuous(5, [0, 100])).toEqual([5, 1, 0, 0, 2]);
|
||||
expect(df.col(0).histogramContinuous(2, [0, 10])).toEqual([2, 2]);
|
||||
expect(df.col(0).histogramContinuous(10, [0, 100])).toEqual([
|
||||
3, 2, 1, 0, 0, 0, 0, 0, 0, 2,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ function float32Conversion(f: any) {
|
||||
describe("Dataframe column summary", () => {
|
||||
test("empty column test", () => {
|
||||
const df = Dataframe.Dataframe.create([0, 1], [[]]);
|
||||
const summary = df.icol(0).summarize();
|
||||
const summary = df.icol(0).summarizeCategorical();
|
||||
expect(summary).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
@@ -31,7 +31,6 @@ describe("Dataframe column summary", () => {
|
||||
[1],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex([
|
||||
"name",
|
||||
"nameString",
|
||||
@@ -42,7 +41,7 @@ describe("Dataframe column summary", () => {
|
||||
])
|
||||
);
|
||||
|
||||
expect(df.icol(0).summarize()).toEqual(
|
||||
expect(df.icol(0).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: ["n1"],
|
||||
@@ -50,7 +49,7 @@ describe("Dataframe column summary", () => {
|
||||
numCategories: 1,
|
||||
})
|
||||
);
|
||||
expect(df.icol(1).summarize()).toEqual(
|
||||
expect(df.icol(1).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: ["hi"],
|
||||
@@ -58,7 +57,7 @@ describe("Dataframe column summary", () => {
|
||||
numCategories: 1,
|
||||
})
|
||||
);
|
||||
expect(df.icol(2).summarize()).toEqual(
|
||||
expect(df.icol(2).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: [true],
|
||||
@@ -66,7 +65,7 @@ describe("Dataframe column summary", () => {
|
||||
numCategories: 1,
|
||||
})
|
||||
);
|
||||
expect(df.icol(3).summarize()).toEqual(
|
||||
expect(df.icol(3).summarizeContinuous()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: false,
|
||||
min: float32Conversion(39.3),
|
||||
@@ -76,7 +75,7 @@ describe("Dataframe column summary", () => {
|
||||
pinf: 0,
|
||||
})
|
||||
);
|
||||
expect(df.icol(4).summarize()).toEqual(
|
||||
expect(df.icol(4).summarizeContinuous()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: false,
|
||||
min: 99,
|
||||
@@ -86,7 +85,7 @@ describe("Dataframe column summary", () => {
|
||||
pinf: 0,
|
||||
})
|
||||
);
|
||||
expect(df.icol(5).summarize()).toEqual(
|
||||
expect(df.icol(5).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: [1],
|
||||
@@ -108,7 +107,6 @@ describe("Dataframe column summary", () => {
|
||||
[1, false, "0"],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex([
|
||||
"name",
|
||||
"nameString",
|
||||
@@ -119,7 +117,7 @@ describe("Dataframe column summary", () => {
|
||||
])
|
||||
);
|
||||
|
||||
expect(df.icol(0).summarize()).toEqual(
|
||||
expect(df.icol(0).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining(["n0", "n1", "n2"]),
|
||||
@@ -131,7 +129,7 @@ describe("Dataframe column summary", () => {
|
||||
numCategories: 3,
|
||||
})
|
||||
);
|
||||
expect(df.icol(1).summarize()).toEqual(
|
||||
expect(df.icol(1).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining(["hi", "bye"]),
|
||||
@@ -142,7 +140,7 @@ describe("Dataframe column summary", () => {
|
||||
numCategories: 2,
|
||||
})
|
||||
);
|
||||
expect(df.icol(2).summarize()).toEqual(
|
||||
expect(df.icol(2).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining([true, false]),
|
||||
@@ -153,7 +151,7 @@ describe("Dataframe column summary", () => {
|
||||
numCategories: 2,
|
||||
})
|
||||
);
|
||||
expect(df.icol(3).summarize()).toEqual(
|
||||
expect(df.icol(3).summarizeContinuous()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: false,
|
||||
min: 0,
|
||||
@@ -163,7 +161,7 @@ describe("Dataframe column summary", () => {
|
||||
pinf: 0,
|
||||
})
|
||||
);
|
||||
expect(df.icol(4).summarize()).toEqual(
|
||||
expect(df.icol(4).summarizeContinuous()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: false,
|
||||
min: 99,
|
||||
@@ -173,7 +171,7 @@ describe("Dataframe column summary", () => {
|
||||
pinf: 0,
|
||||
})
|
||||
);
|
||||
expect(df.icol(5).summarize()).toEqual(
|
||||
expect(df.icol(5).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining([1, false, "0"]),
|
||||
@@ -205,7 +203,6 @@ describe("Dataframe column summary", () => {
|
||||
[1, false, "0", "0"],
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex([
|
||||
"name",
|
||||
"nameString",
|
||||
@@ -216,7 +213,7 @@ describe("Dataframe column summary", () => {
|
||||
])
|
||||
);
|
||||
|
||||
expect(df.icol(0).summarize()).toEqual(
|
||||
expect(df.icol(0).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining(["n0", "n1", "n2"]),
|
||||
@@ -228,7 +225,7 @@ describe("Dataframe column summary", () => {
|
||||
numCategories: 3,
|
||||
})
|
||||
);
|
||||
expect(df.icol(1).summarize()).toEqual(
|
||||
expect(df.icol(1).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining(["hi", "bye"]),
|
||||
@@ -239,7 +236,7 @@ describe("Dataframe column summary", () => {
|
||||
numCategories: 2,
|
||||
})
|
||||
);
|
||||
expect(df.icol(2).summarize()).toEqual(
|
||||
expect(df.icol(2).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining([true, false]),
|
||||
@@ -250,7 +247,7 @@ describe("Dataframe column summary", () => {
|
||||
numCategories: 2,
|
||||
})
|
||||
);
|
||||
expect(df.icol(3).summarize()).toEqual(
|
||||
expect(df.icol(3).summarizeContinuous()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: false,
|
||||
min: float32Conversion(39.3),
|
||||
@@ -260,7 +257,7 @@ describe("Dataframe column summary", () => {
|
||||
pinf: 1,
|
||||
})
|
||||
);
|
||||
expect(df.icol(4).summarize()).toEqual(
|
||||
expect(df.icol(4).summarizeContinuous()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: false,
|
||||
min: 99,
|
||||
@@ -270,7 +267,7 @@ describe("Dataframe column summary", () => {
|
||||
pinf: 0,
|
||||
})
|
||||
);
|
||||
expect(df.icol(5).summarize()).toEqual(
|
||||
expect(df.icol(5).summarizeCategorical()).toEqual(
|
||||
expect.objectContaining({
|
||||
categorical: true,
|
||||
categories: expect.arrayContaining([1, false, "0"]),
|
||||
|
||||
@@ -81,7 +81,6 @@ describe("categorical color helpers", () => {
|
||||
),
|
||||
],
|
||||
null,
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
new Dataframe.KeyIndex(["continuousColumn", "categoricalColumn"])
|
||||
);
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ describe("encode/decode", () => {
|
||||
expect(dfA.columns).toEqual(columns);
|
||||
|
||||
const colIndex = new KeyIndex(["a", "b", "c", "d"]);
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
const dfWithColIdx = new Dataframe([3, 4], columns, null, colIndex);
|
||||
const dfB = decodeMatrixFBS(encodeMatrixFBS(dfWithColIdx));
|
||||
expect([dfB.nRows, dfB.nCols]).toEqual(dfWithColIdx.dims);
|
||||
|
||||
@@ -21,90 +21,90 @@ The behavior manifest in these action creators:
|
||||
Note that crossfilter indices are lazy created, as needed.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export const genesetDelete = (genesetName: any) => (
|
||||
import { Dataframe } from "../util/dataframe";
|
||||
|
||||
export const genesetDelete =
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
dispatch: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
getState: any
|
||||
) => {
|
||||
const state = getState();
|
||||
const { genesets } = state;
|
||||
const gs = genesets?.genesets?.get(genesetName) ?? {};
|
||||
const geneSymbols = Array.from(gs.genes.keys());
|
||||
const obsCrossfilter = dropGeneset(dispatch, state, genesetName, geneSymbols);
|
||||
if (genesetName === state.colors.colorAccessor) {
|
||||
(genesetName: any) => (dispatch: any, getState: any) => {
|
||||
const state = getState();
|
||||
const { genesets } = state;
|
||||
const gs = genesets?.genesets?.get(genesetName) ?? {};
|
||||
const geneSymbols = Array.from(gs.genes.keys());
|
||||
const obsCrossfilter = dropGeneset(
|
||||
dispatch,
|
||||
state,
|
||||
genesetName,
|
||||
geneSymbols
|
||||
);
|
||||
if (genesetName === state.colors.colorAccessor) {
|
||||
dispatch({
|
||||
type: "reset colorscale",
|
||||
});
|
||||
}
|
||||
dispatch({
|
||||
type: "reset colorscale",
|
||||
type: "geneset: delete",
|
||||
genesetName,
|
||||
obsCrossfilter,
|
||||
annoMatrix: obsCrossfilter.annoMatrix,
|
||||
});
|
||||
}
|
||||
dispatch({
|
||||
type: "geneset: delete",
|
||||
genesetName,
|
||||
obsCrossfilter,
|
||||
annoMatrix: obsCrossfilter.annoMatrix,
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export const genesetAddGenes = (genesetName: any, genes: any) => async (
|
||||
export const genesetAddGenes =
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
dispatch: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
getState: any
|
||||
) => {
|
||||
const state = getState();
|
||||
const { obsCrossfilter: prevObsCrossfilter, annoMatrix } = state;
|
||||
const { schema } = annoMatrix;
|
||||
const varIndex = schema.annotations.var.index;
|
||||
const df = await annoMatrix.fetch("var", varIndex);
|
||||
const geneNames = df.col(varIndex).asArray();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
genes = genes.reduce((acc: any, gene: any) => {
|
||||
if (geneNames.indexOf(gene.geneSymbol) === -1) {
|
||||
postUserErrorToast(
|
||||
`${gene.geneSymbol} doesn't appear to be a valid gene name.`
|
||||
);
|
||||
} else acc.push(gene);
|
||||
return acc;
|
||||
}, []);
|
||||
(genesetName: any, genes: any) => async (dispatch: any, getState: any) => {
|
||||
const state = getState();
|
||||
const { obsCrossfilter: prevObsCrossfilter, annoMatrix } = state;
|
||||
const { schema } = annoMatrix;
|
||||
const varIndex = schema.annotations.var.index;
|
||||
const df: Dataframe = await annoMatrix.fetch("var", varIndex);
|
||||
const geneNames = df.col(varIndex).asArray();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
genes = genes.reduce((acc: any, gene: any) => {
|
||||
if (geneNames.indexOf(gene.geneSymbol) === -1) {
|
||||
postUserErrorToast(
|
||||
`${gene.geneSymbol} doesn't appear to be a valid gene name.`
|
||||
);
|
||||
} else acc.push(gene);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
const obsCrossfilter = dropGenesetSummaryDimension(
|
||||
prevObsCrossfilter,
|
||||
state,
|
||||
genesetName
|
||||
);
|
||||
dispatch({
|
||||
type: "continuous metadata histogram cancel",
|
||||
continuousNamespace: { isGeneSetSummary: true },
|
||||
selection: genesetName,
|
||||
});
|
||||
return dispatch({
|
||||
type: "geneset: add genes",
|
||||
genesetName,
|
||||
genes,
|
||||
obsCrossfilter,
|
||||
annoMatrix: obsCrossfilter.annoMatrix,
|
||||
});
|
||||
};
|
||||
const obsCrossfilter = dropGenesetSummaryDimension(
|
||||
prevObsCrossfilter,
|
||||
state,
|
||||
genesetName
|
||||
);
|
||||
dispatch({
|
||||
type: "continuous metadata histogram cancel",
|
||||
continuousNamespace: { isGeneSetSummary: true },
|
||||
selection: genesetName,
|
||||
});
|
||||
return dispatch({
|
||||
type: "geneset: add genes",
|
||||
genesetName,
|
||||
genes,
|
||||
obsCrossfilter,
|
||||
annoMatrix: obsCrossfilter.annoMatrix,
|
||||
});
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export const genesetDeleteGenes = (genesetName: any, geneSymbols: any) => (
|
||||
export const genesetDeleteGenes =
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
dispatch: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
getState: any
|
||||
) => {
|
||||
const state = getState();
|
||||
const obsCrossfilter = dropGeneset(dispatch, state, genesetName, geneSymbols);
|
||||
return dispatch({
|
||||
type: "geneset: delete genes",
|
||||
genesetName,
|
||||
geneSymbols,
|
||||
obsCrossfilter,
|
||||
annoMatrix: obsCrossfilter.annoMatrix,
|
||||
});
|
||||
};
|
||||
(genesetName: any, geneSymbols: any) => (dispatch: any, getState: any) => {
|
||||
const state = getState();
|
||||
const obsCrossfilter = dropGeneset(
|
||||
dispatch,
|
||||
state,
|
||||
genesetName,
|
||||
geneSymbols
|
||||
);
|
||||
return dispatch({
|
||||
type: "geneset: delete genes",
|
||||
genesetName,
|
||||
geneSymbols,
|
||||
obsCrossfilter,
|
||||
annoMatrix: obsCrossfilter.annoMatrix,
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Private
|
||||
|
||||
@@ -219,7 +219,7 @@ export default class AnnoMatrix {
|
||||
**/
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
fetch(field, q) {
|
||||
fetch(field, q): Dataframe {
|
||||
/*
|
||||
Return the given query on a single matrix field as a single dataframe.
|
||||
Currently supports ONLY full column query.
|
||||
@@ -248,7 +248,7 @@ export default class AnnoMatrix {
|
||||
1. Fetch the "n_genes" column the "obs":
|
||||
|
||||
const df = await fetch("obs", "n_genes")
|
||||
console.log("Largest number of genes is: ", df.summarize().max);
|
||||
console.log("Largest number of genes is: ", df.summarizeContinuous().max);
|
||||
|
||||
2. Fetch two separate columns from obs. Returns a single dataframe containing
|
||||
the columns:
|
||||
@@ -278,7 +278,7 @@ export default class AnnoMatrix {
|
||||
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
prefetch(field, q) {
|
||||
prefetch(field, q): void {
|
||||
/*
|
||||
Start a data fetch & cache fill. Identical to fetch() except it does
|
||||
not return a value.
|
||||
@@ -287,7 +287,6 @@ export default class AnnoMatrix {
|
||||
overall component rendering latency.
|
||||
*/
|
||||
this._fetch(field, q);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -494,8 +493,8 @@ Return cache keys for columns associated with this query. May return
|
||||
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'field' implicitly has an 'any' type.
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
async _fetch(field, q) {
|
||||
if (!AnnoMatrix.fields().includes(field)) return undefined;
|
||||
async _fetch(field, q): Dataframe {
|
||||
if (!AnnoMatrix.fields().includes(field)) return Dataframe.empty();
|
||||
const queries = Array.isArray(q) ? q : [q];
|
||||
queries.forEach(_queryValidate);
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
||||
const data = (this as any)._cache.obs.col(col).asArray().slice();
|
||||
for (let i = 0, len = rowIndices.length; i < len; i += 1) {
|
||||
const idx = rowIndices[i];
|
||||
if (idx === undefined) throw new Error("Unknown row label");
|
||||
if (idx === -1) throw new Error("Unknown row label");
|
||||
data[idx] = value;
|
||||
}
|
||||
|
||||
@@ -299,8 +299,8 @@ export default class AnnoMatrixLoader extends AnnoMatrix {
|
||||
default:
|
||||
throw new Error("Unknown field name");
|
||||
}
|
||||
|
||||
const buffer = await promiseThrottle.priorityAdd(priority, doRequest);
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'unknown' is not assignable to parameter of type 'ArrayBuffer | ArrayBuffer[]'.... Remove this comment to see the full error message
|
||||
let result = matrixFBSToDataframe(buffer);
|
||||
if (!result || result.isEmpty()) throw Error("Unknown field/col");
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Schema } from "../common/types/schema";
|
||||
import { _getColumnSchema, _isIndex } from "./schema";
|
||||
import catLabelSort from "../util/catLabelSort";
|
||||
import {
|
||||
@@ -5,12 +6,11 @@ import {
|
||||
overflowCategoryLabel,
|
||||
globalConfig,
|
||||
} from "../globals";
|
||||
import { Dataframe } from "../util/dataframe";
|
||||
import { Dataframe, LabelType, DataframeColumn } from "../util/dataframe";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function normalizeResponse(
|
||||
field: string,
|
||||
schema: any, // eslint-disable-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
schema: Schema,
|
||||
response: Dataframe
|
||||
): Dataframe {
|
||||
/**
|
||||
@@ -65,8 +65,7 @@ export function normalizeResponse(
|
||||
return response;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
function castColumnToBoolean(df: Dataframe, label: any): Dataframe {
|
||||
function castColumnToBoolean(df: Dataframe, label: LabelType): Dataframe {
|
||||
const colData = df.col(label).asArray();
|
||||
const newColData = new Array(colData.length);
|
||||
for (let i = 0; i < colData.length; i += 1) newColData[i] = !!colData[i];
|
||||
@@ -75,7 +74,10 @@ function castColumnToBoolean(df: Dataframe, label: any): Dataframe {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function normalizeWritableCategoricalSchema(colSchema: any, col: any) {
|
||||
export function normalizeWritableCategoricalSchema(
|
||||
colSchema: any, // eslint-disable-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
col: DataframeColumn
|
||||
) {
|
||||
/*
|
||||
Ensure all enum writable / categorical schema have a categories array, that
|
||||
the categories array contains all unique values in the data array, AND that
|
||||
@@ -91,12 +93,11 @@ export function normalizeWritableCategoricalSchema(colSchema: any, col: any) {
|
||||
return colSchema;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function normalizeCategorical(
|
||||
df: Dataframe,
|
||||
colLabel: any, // eslint-disable-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
colLabel: LabelType,
|
||||
colSchema: any // eslint-disable-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
) {
|
||||
): Dataframe {
|
||||
/*
|
||||
If writable, ensure schema matches data and we have an unassigned label
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ function _clipAnnoMatrix(field, colLabel, colSchema, colData, df, qmin, qmax) {
|
||||
if (qmax > 1) qmax = 1;
|
||||
if (qmin === 0 && qmax === 1) return colData;
|
||||
|
||||
const quantiles = df.col(colLabel).summarize().percentiles;
|
||||
const quantiles = df.col(colLabel).summarizeContinuous().percentiles;
|
||||
const lower = quantiles[100 * qmin];
|
||||
const upper = quantiles[100 * qmax];
|
||||
const clippedData = clip(colData.slice(), lower, upper, Number.NaN);
|
||||
|
||||
@@ -30,6 +30,22 @@ export type TypedArrayConstructor =
|
||||
|
||||
export type AnyArray = Array<unknown> | TypedArray;
|
||||
|
||||
export interface GenericArrayConstructor<T extends AnyArray> {
|
||||
new (
|
||||
...args: ConstructorParameters<
|
||||
typeof Int8Array &
|
||||
typeof Uint8Array &
|
||||
typeof Int16Array &
|
||||
typeof Uint16Array &
|
||||
typeof Int32Array &
|
||||
typeof Uint32Array &
|
||||
typeof Float32Array &
|
||||
typeof Float64Array &
|
||||
typeof Array
|
||||
>
|
||||
): T;
|
||||
}
|
||||
|
||||
export type NumberArray = Array<number> | TypedArray;
|
||||
|
||||
export type Int8 = Int8Array[0];
|
||||
|
||||
@@ -11,6 +11,7 @@ import Histogram from "./histogram";
|
||||
import HistogramFooter from "./footer";
|
||||
import StillLoading from "./loading";
|
||||
import ErrorLoading from "./error";
|
||||
import { Dataframe } from "../../util/dataframe";
|
||||
|
||||
const MARGIN = {
|
||||
LEFT: 10, // Space for 0 tick label on X axis
|
||||
@@ -116,9 +117,12 @@ class HistogramBrush extends React.PureComponent {
|
||||
};
|
||||
};
|
||||
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'selection' is declared but its value is never rea... Remove this comment to see the full error message
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
onBrushEnd = (selection: any, x: any) =>
|
||||
onBrushEnd =
|
||||
(
|
||||
_selection: any, // eslint-disable-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
x: any // eslint-disable-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
) =>
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
() => {
|
||||
const {
|
||||
@@ -257,18 +261,18 @@ class HistogramBrush extends React.PureComponent {
|
||||
|
||||
const query = this.createQuery();
|
||||
// @ts-expect-error ts-migrate(2488) FIXME: Type 'any[] | null' must have a '[Symbol.iterator]... Remove this comment to see the full error message
|
||||
const df = await annoMatrix.fetch(...query);
|
||||
const df: Dataframe = await annoMatrix.fetch(...query);
|
||||
const column = df.icol(0);
|
||||
|
||||
// if we are clipped, fetch both our value and our unclipped value,
|
||||
// as we need the absolute min/max range, not just the clipped min/max.
|
||||
const summary = column.summarize();
|
||||
const summary = column.summarizeContinuous();
|
||||
const range = [summary.min, summary.max];
|
||||
|
||||
let unclippedRange = [...range];
|
||||
if (isClipped) {
|
||||
const parent = await annoMatrix.viewOf.fetch(...query);
|
||||
const { min, max } = parent.icol(0).summarize();
|
||||
const parent: Dataframe = await annoMatrix.viewOf.fetch(...query);
|
||||
const { min, max } = parent.icol(0).summarizeContinuous();
|
||||
unclippedRange = [min, max];
|
||||
}
|
||||
|
||||
@@ -320,7 +324,8 @@ class HistogramBrush extends React.PureComponent {
|
||||
recalculate expensive stuff, notably bins, summaries, etc.
|
||||
*/
|
||||
const histogramCache = {}; /* maybe change this so that it computes ... */
|
||||
const summary = col.summarize(); /* this is memoized, so it's free the second time you call it */
|
||||
const summary =
|
||||
col.summarizeContinuous(); /* this is memoized, so it's free the second time you call it */
|
||||
const { min: domainMin, max: domainMax } = summary;
|
||||
const numBins = 40;
|
||||
const { TOP: topMargin, LEFT: leftMargin } = newMargin;
|
||||
@@ -333,7 +338,7 @@ class HistogramBrush extends React.PureComponent {
|
||||
.range([leftMargin, leftMargin + newWidth]);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
(histogramCache as any).bins = col.histogram(numBins, [
|
||||
(histogramCache as any).bins = col.histogramContinuous(numBins, [
|
||||
domainMin,
|
||||
domainMax,
|
||||
]);
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
createColorQuery,
|
||||
} from "../../../util/stateManager/colorHelpers";
|
||||
import actions from "../../../actions";
|
||||
import { Dataframe } from "../../../util/dataframe";
|
||||
|
||||
const LABEL_WIDTH = globals.leftSidebarWidth - 100;
|
||||
const ANNO_BUTTON_WIDTH = 50;
|
||||
@@ -165,8 +166,20 @@ class Category extends React.PureComponent {
|
||||
};
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
async fetchData(annoMatrix: any, metadataField: any, colors: any) {
|
||||
async fetchData(
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
annoMatrix: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
metadataField: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
colors: any
|
||||
): Promise<
|
||||
[
|
||||
Dataframe,
|
||||
ReturnType<typeof createCategorySummaryFromDfCol>,
|
||||
Dataframe | null
|
||||
]
|
||||
> {
|
||||
/*
|
||||
fetch our data and the color-by data if appropriate, and then build a summary
|
||||
of our category and a color table for the color-by annotation.
|
||||
@@ -175,7 +188,7 @@ class Category extends React.PureComponent {
|
||||
const { colorAccessor, colorMode } = colors;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'genesets' does not exist on type 'Readon... Remove this comment to see the full error message
|
||||
const { genesets } = this.props;
|
||||
let colorDataPromise = Promise.resolve(null);
|
||||
let colorDataPromise: Promise<Dataframe | null> = Promise.resolve(null);
|
||||
if (colorAccessor) {
|
||||
const query = createColorQuery(
|
||||
colorMode,
|
||||
@@ -185,10 +198,10 @@ class Category extends React.PureComponent {
|
||||
);
|
||||
if (query) colorDataPromise = annoMatrix.fetch(...query);
|
||||
}
|
||||
const [categoryData, colorData] = await Promise.all([
|
||||
annoMatrix.fetch("obs", metadataField),
|
||||
colorDataPromise,
|
||||
]);
|
||||
const [categoryData, colorData] = await Promise.all<
|
||||
Dataframe,
|
||||
Dataframe | null
|
||||
>([annoMatrix.fetch("obs", metadataField), colorDataPromise]);
|
||||
|
||||
// our data
|
||||
const column = categoryData.icol(0);
|
||||
@@ -200,8 +213,8 @@ class Category extends React.PureComponent {
|
||||
return [categoryData, categorySummary, colorData];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
updateColorTable(colorData: any) {
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -- - FIXME: disabled temporarily on migrate to TS.
|
||||
updateColorTable(colorData: Dataframe|null) {
|
||||
// color table, which may be null
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||
const { schema, colors, metadataField } = this.props;
|
||||
|
||||
@@ -25,6 +25,7 @@ import actions from "../../../actions";
|
||||
import MiniHistogram from "../../miniHistogram";
|
||||
import MiniStackedBar from "../../miniStackedBar";
|
||||
import { CategoryCrossfilterContext } from "../categoryContext";
|
||||
import { Dataframe, ContinuousHistogram } from "../../../util/dataframe";
|
||||
|
||||
const STACKED_BAR_HEIGHT = 11;
|
||||
const STACKED_BAR_WIDTH = 100;
|
||||
@@ -327,13 +328,11 @@ class CategoryValue extends React.Component<{}, State> {
|
||||
createHistogramBins = (
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
metadataField: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
categoryData: any,
|
||||
categoryData: Dataframe,
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'colorAccessor' is declared but its value is never... Remove this comment to see the full error message
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
colorAccessor: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
colorData: any,
|
||||
colorData: Dataframe,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
categoryValue: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
@@ -348,17 +347,17 @@ class CategoryValue extends React.Component<{}, State> {
|
||||
*/
|
||||
const groupBy = categoryData.col(metadataField);
|
||||
const col = colorData.icol(0);
|
||||
const range = col.summarize();
|
||||
const range = col.summarizeContinuous();
|
||||
|
||||
const histogramMap = col.histogram(
|
||||
const histogramMap = col.histogramContinuousBy(
|
||||
50,
|
||||
[range.min, range.max],
|
||||
groupBy
|
||||
); /* Because the signature changes we really need different names for histogram to differentiate signatures */
|
||||
);
|
||||
|
||||
const bins = histogramMap.has(categoryValue)
|
||||
? histogramMap.get(categoryValue)
|
||||
: new Array(50).fill(0);
|
||||
? histogramMap.get(categoryValue) as ContinuousHistogram
|
||||
: new Array<number>(50).fill(0);
|
||||
|
||||
const xScale = d3.scaleLinear().domain([0, bins.length]).range([0, width]);
|
||||
|
||||
@@ -377,12 +376,10 @@ class CategoryValue extends React.Component<{}, State> {
|
||||
createStackedGraphBins = (
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
metadataField: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
categoryData: any,
|
||||
categoryData: Dataframe,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
colorAccessor: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
colorData: any,
|
||||
colorData: Dataframe,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
categoryValue: any,
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'colorTable' is declared but its value is never re... Remove this comment to see the full error message
|
||||
@@ -401,7 +398,7 @@ class CategoryValue extends React.Component<{}, State> {
|
||||
const groupBy = categoryData.col(metadataField);
|
||||
const occupancyMap = colorData
|
||||
.col(colorAccessor)
|
||||
.histogramCategorical(groupBy);
|
||||
.histogramCategoricalBy(groupBy);
|
||||
|
||||
const occupancy = occupancyMap.get(categoryValue);
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
Position,
|
||||
} from "@blueprintjs/core";
|
||||
|
||||
import { Dataframe } from "../../../util/dataframe";
|
||||
|
||||
// @ts-expect-error ts-migrate(1238) FIXME: Unable to resolve signature of class decorator whe... Remove this comment to see the full error message
|
||||
@connect((state) => ({
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
@@ -21,34 +23,32 @@ class Occupancy extends React.PureComponent {
|
||||
|
||||
_HEIGHT = 11;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
createHistogram = () => {
|
||||
createHistogram = (): void => {
|
||||
/*
|
||||
Knowing that colorScale is based off continous data,
|
||||
createHistogram fetches the continous data in relation to the cells releveant to the catagory value.
|
||||
It then seperates that data into 50 bins for drawing the mini-histogram
|
||||
Knowing that colorScale is based off continuous data,
|
||||
createHistogram fetches the continuous data in relation to the cells relevant to the category value.
|
||||
It then separates that data into 50 bins for drawing the mini-histogram
|
||||
*/
|
||||
const {
|
||||
const { metadataField, categoryData, colorData, categoryValue } = this
|
||||
.props as {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||
metadataField,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryData' does not exist on type 'Re... Remove this comment to see the full error message
|
||||
categoryData,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorData' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||
colorData,
|
||||
metadataField;
|
||||
categoryData: Dataframe;
|
||||
colorData: Dataframe;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryValue' does not exist on type 'R... Remove this comment to see the full error message
|
||||
categoryValue,
|
||||
} = this.props;
|
||||
categoryValue;
|
||||
};
|
||||
if (!this.canvas) return;
|
||||
const groupBy = categoryData.col(metadataField);
|
||||
const col = colorData.icol(0);
|
||||
const range = col.summarize();
|
||||
const histogramMap = col.histogram(
|
||||
const range = col.summarizeContinuous();
|
||||
const histogramMap = col.histogramContinuousBy(
|
||||
50,
|
||||
[range.min, range.max],
|
||||
groupBy
|
||||
); /* Because the signature changes we really need different names for histogram to differentiate signatures */
|
||||
);
|
||||
const bins = histogramMap.has(categoryValue)
|
||||
? histogramMap.get(categoryValue)
|
||||
? (histogramMap.get(categoryValue) as number[])
|
||||
: new Array(50).fill(0);
|
||||
const xScale = d3
|
||||
.scaleLinear()
|
||||
@@ -71,36 +71,41 @@ class Occupancy extends React.PureComponent {
|
||||
}
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
createOccupancyStack = () => {
|
||||
createOccupancyStack = (): void => {
|
||||
/*
|
||||
Knowing that the color scale is based off of catagorical data,
|
||||
createOccupancyStack obtains a map showing the number if cells per colored value
|
||||
Using the colorScale a stack of colored bars is drawn representing the map
|
||||
*/
|
||||
const {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'metadataField' does not exist on type 'R... Remove this comment to see the full error message
|
||||
metadataField,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryData' does not exist on type 'Re... Remove this comment to see the full error message
|
||||
categoryData,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorAccessor' does not exist on type 'R... Remove this comment to see the full error message
|
||||
colorAccessor,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryValue' does not exist on type 'R... Remove this comment to see the full error message
|
||||
categoryValue,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorTable' does not exist on type 'Read... Remove this comment to see the full error message
|
||||
colorTable,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'schema' does not exist on type 'Readonly... Remove this comment to see the full error message
|
||||
schema,
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'colorData' does not exist on type 'Reado... Remove this comment to see the full error message
|
||||
colorData,
|
||||
} = this.props;
|
||||
} = this.props as {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
metadataField: any;
|
||||
categoryData: Dataframe;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
colorAccessor: any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
categoryValue: any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
colorTable: any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
schema: any;
|
||||
colorData: Dataframe;
|
||||
};
|
||||
const { scale: colorScale } = colorTable;
|
||||
const ctx = this.canvas?.getContext("2d");
|
||||
if (!ctx) return;
|
||||
const groupBy = categoryData.col(metadataField);
|
||||
const occupancyMap = colorData
|
||||
.col(colorAccessor)
|
||||
.histogramCategorical(groupBy);
|
||||
.histogramCategoricalBy(groupBy);
|
||||
const occupancy = occupancyMap.get(categoryValue);
|
||||
if (occupancy && occupancy.size > 0) {
|
||||
// not all categories have occupancy, so occupancy may be undefined.
|
||||
@@ -119,7 +124,7 @@ class Occupancy extends React.PureComponent {
|
||||
let value;
|
||||
for (let i = 0, { length } = categoryValues; i < length; i += 1) {
|
||||
value = categoryValues[i];
|
||||
o = occupancy.get(value);
|
||||
o = occupancy.get(value) as number;
|
||||
scaledValue = x(o);
|
||||
ctx.fillStyle = o
|
||||
? colorScale(categories.indexOf(value))
|
||||
|
||||
@@ -121,6 +121,7 @@ const loadAllEmbeddingCounts = async ({ annoMatrix, available }: any) => {
|
||||
return available.map((name, idx) => ({
|
||||
embeddingName: name,
|
||||
embedding: embeddings[idx],
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'unknown' is not assignable...
|
||||
discreteCellIndex: getDiscreteCellEmbeddingRowIndex(embeddings[idx]),
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
|
||||
import { memoize } from "../../../util/dataframe/util";
|
||||
import parseBulkGeneString from "../../../util/parseBulkGeneString";
|
||||
import { Dataframe } from "../../../util/dataframe";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const renderGene = (fuzzySortResult: any, { handleClick, modifiers }: any) => {
|
||||
@@ -187,7 +188,7 @@ class AddGenes extends React.Component<{}, AddGenesState> {
|
||||
|
||||
this.setState({ status: "pending" });
|
||||
try {
|
||||
const df = await annoMatrix.fetch("var", varIndex);
|
||||
const df: Dataframe = await annoMatrix.fetch("var", varIndex);
|
||||
this.setState({
|
||||
status: "success",
|
||||
geneNames: df.col(varIndex).asArray(),
|
||||
|
||||
@@ -9,6 +9,7 @@ import Gene from "./gene";
|
||||
|
||||
import { postUserErrorToast } from "../framework/toasters";
|
||||
import actions from "../../actions";
|
||||
import { Dataframe, DataframeValue } from "../../util/dataframe";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const usePrevious = (value: any) => {
|
||||
@@ -24,7 +25,7 @@ function QuickGene() {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [isExpanded, setIsExpanded] = useState(true);
|
||||
const [geneNames, setGeneNames] = useState([]);
|
||||
const [geneNames, setGeneNames] = useState([] as DataframeValue[]);
|
||||
const [, setStatus] = useState("pending");
|
||||
|
||||
const { annoMatrix, userDefinedGenes, userDefinedGenesLoading } = useSelector(
|
||||
@@ -50,9 +51,9 @@ function QuickGene() {
|
||||
|
||||
setStatus("pending");
|
||||
try {
|
||||
const df = await annoMatrix.fetch("var", varIndex);
|
||||
const df: Dataframe = await annoMatrix.fetch("var", varIndex);
|
||||
setStatus("success");
|
||||
setGeneNames(df.col(varIndex).asArray());
|
||||
setGeneNames(df.col(varIndex).asArray() as DataframeValue[]);
|
||||
} catch (error) {
|
||||
setStatus("error");
|
||||
throw error;
|
||||
@@ -95,7 +96,6 @@ function QuickGene() {
|
||||
const gene = g.target;
|
||||
if (userDefinedGenes.indexOf(gene) !== -1) {
|
||||
postUserErrorToast("That gene already exists");
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
|
||||
} else if (geneNames.indexOf(gene) === undefined) {
|
||||
postUserErrorToast("That doesn't appear to be a valid gene name.");
|
||||
} else {
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
flagSelected,
|
||||
flagHighlight,
|
||||
} from "../../util/glHelpers";
|
||||
import { Dataframe } from "../../util/dataframe";
|
||||
|
||||
/*
|
||||
Simple 2D transforms control all point painting. There are three:
|
||||
@@ -558,7 +559,11 @@ class Graph extends React.Component<{}, GraphState> {
|
||||
handleEnd = this.handleLassoEnd.bind(this);
|
||||
handleCancel = this.handleLassoCancel.bind(this);
|
||||
}
|
||||
const { svg: newToolSVG, tool, container } = setupSVGandBrushElements(
|
||||
const {
|
||||
svg: newToolSVG,
|
||||
tool,
|
||||
container,
|
||||
} = setupSVGandBrushElements(
|
||||
selectionTool,
|
||||
handleStart,
|
||||
handleDrag,
|
||||
@@ -592,8 +597,7 @@ class Graph extends React.Component<{}, GraphState> {
|
||||
const positions = this.computePointPositions(X, Y, modelTF);
|
||||
const colorTable = this.updateColorTable(colorsProp, colorDf);
|
||||
const colors = this.computePointColors(colorTable.rgb);
|
||||
const { colorAccessor } = colorsProp;
|
||||
const colorByData = colorDf?.col(colorAccessor)?.asArray();
|
||||
const colorByData = colorDf?.icol(0)?.asArray();
|
||||
const {
|
||||
metadataField: pointDilationCategory,
|
||||
categoryField: pointDilationLabel,
|
||||
@@ -627,7 +631,7 @@ class Graph extends React.Component<{}, GraphState> {
|
||||
colors: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
pointDilation: any
|
||||
) {
|
||||
): Promise<[Dataframe, Dataframe | null, Dataframe | null]> {
|
||||
/*
|
||||
fetch all data needed. Includes:
|
||||
- the color by dataframe
|
||||
@@ -635,22 +639,18 @@ class Graph extends React.Component<{}, GraphState> {
|
||||
- the point dilation dataframe
|
||||
*/
|
||||
const { metadataField: pointDilationAccessor } = pointDilation;
|
||||
const promises = [];
|
||||
// layout
|
||||
promises.push(annoMatrix.fetch("emb", layoutChoice.current));
|
||||
// color
|
||||
const query = this.createColorByQuery(colors);
|
||||
if (query) {
|
||||
promises.push(annoMatrix.fetch(...query));
|
||||
} else {
|
||||
promises.push(Promise.resolve(null));
|
||||
}
|
||||
// point highlighting
|
||||
if (pointDilationAccessor) {
|
||||
promises.push(annoMatrix.fetch("obs", pointDilationAccessor));
|
||||
} else {
|
||||
promises.push(Promise.resolve(null));
|
||||
}
|
||||
const promises: [
|
||||
Promise<Dataframe>,
|
||||
Promise<Dataframe | null>,
|
||||
Promise<Dataframe | null>
|
||||
] = [
|
||||
annoMatrix.fetch("emb", layoutChoice.current),
|
||||
query ? annoMatrix.fetch(...query) : Promise.resolve(null),
|
||||
pointDilationAccessor
|
||||
? annoMatrix.fetch("obs", pointDilationAccessor)
|
||||
: Promise.resolve(null),
|
||||
];
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
flagSelected,
|
||||
flagHighlight,
|
||||
} from "../../util/glHelpers";
|
||||
import { Dataframe, DataframeColumn } from "../../util/dataframe";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function createProjectionTF(viewportWidth: any, viewportHeight: any) {
|
||||
@@ -33,9 +34,9 @@ function createProjectionTF(viewportWidth: any, viewportHeight: any) {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function getScale(col: any, rangeMin: any, rangeMax: any) {
|
||||
function getScale(col: DataframeColumn, rangeMin: any, rangeMax: any) {
|
||||
if (!col) return null;
|
||||
const { min, max } = col.summarize();
|
||||
const { min, max } = col.summarizeContinuous();
|
||||
return d3.scaleLinear().domain([min, max]).range([rangeMin, rangeMax]);
|
||||
}
|
||||
const getXScale = memoize(getScale);
|
||||
@@ -276,17 +277,13 @@ class Scatterplot extends React.PureComponent<{}, State> {
|
||||
pointDilation,
|
||||
} = props.watchProps;
|
||||
|
||||
const [
|
||||
expressionXDf,
|
||||
expressionYDf,
|
||||
colorDf,
|
||||
pointDilationDf,
|
||||
] = await this.fetchData(
|
||||
scatterplotXXaccessor,
|
||||
scatterplotYYaccessor,
|
||||
colorsProp,
|
||||
pointDilation
|
||||
);
|
||||
const [expressionXDf, expressionYDf, colorDf, pointDilationDf] =
|
||||
await this.fetchData(
|
||||
scatterplotXXaccessor,
|
||||
scatterplotYYaccessor,
|
||||
colorsProp,
|
||||
pointDilation
|
||||
);
|
||||
const colorTable = this.updateColorTable(colorsProp, colorDf);
|
||||
|
||||
const xCol = expressionXDf.icol(0);
|
||||
@@ -383,37 +380,32 @@ class Scatterplot extends React.PureComponent<{}, State> {
|
||||
colors: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
pointDilation: any
|
||||
) {
|
||||
): Promise<
|
||||
[Dataframe, Dataframe, Dataframe | null, Dataframe | null]
|
||||
> {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'annoMatrix' does not exist on type 'Read... Remove this comment to see the full error message
|
||||
const { annoMatrix } = this.props;
|
||||
const { metadataField: pointDilationAccessor } = pointDilation;
|
||||
|
||||
const promises = [];
|
||||
// X and Y dimensions
|
||||
promises.push(
|
||||
// @ts-expect-error ts-migrate(2488) FIXME: Type '(string | { where: { field: string; column: ... Remove this comment to see the full error message
|
||||
annoMatrix.fetch(...this.createXQuery(scatterplotXXaccessor))
|
||||
);
|
||||
promises.push(
|
||||
annoMatrix.fetch(...this.createXQuery(scatterplotYYaccessor))
|
||||
);
|
||||
|
||||
// color
|
||||
const query = this.createColorByQuery(colors);
|
||||
if (query) {
|
||||
promises.push(annoMatrix.fetch(...query));
|
||||
} else {
|
||||
promises.push(Promise.resolve(null));
|
||||
}
|
||||
|
||||
// point highlighting
|
||||
if (pointDilationAccessor) {
|
||||
promises.push(annoMatrix.fetch("obs", pointDilationAccessor));
|
||||
} else {
|
||||
promises.push(Promise.resolve(null));
|
||||
}
|
||||
const promises: [Dataframe, Dataframe, Dataframe | null, Dataframe | null] =
|
||||
[
|
||||
// @ts-expect-error ts-migrate(2488) FIXME: Type '(string | { where: { field: string; column: ... Remove this comment to see the full error message
|
||||
annoMatrix.fetch(...this.createXQuery(scatterplotXXaccessor)),
|
||||
annoMatrix.fetch(...this.createXQuery(scatterplotYYaccessor)),
|
||||
query ? annoMatrix.fetch(...query) : Promise.resolve(null),
|
||||
pointDilationAccessor
|
||||
? annoMatrix.fetch("obs", pointDilationAccessor)
|
||||
: Promise.resolve(null),
|
||||
];
|
||||
|
||||
return Promise.all(promises);
|
||||
return Promise.all<
|
||||
Dataframe,
|
||||
Dataframe,
|
||||
Dataframe | null,
|
||||
Dataframe | null
|
||||
>(promises);
|
||||
}
|
||||
|
||||
renderCanvas = renderThrottle(() => {
|
||||
|
||||
+10
-18
@@ -1,5 +1,6 @@
|
||||
import quantile from "./quantile";
|
||||
import { memoize } from "./dataframe/util";
|
||||
import { Dataframe } from "./dataframe";
|
||||
import { unassignedCategoryLabel } from "../globals";
|
||||
import {
|
||||
createCategorySummaryFromDfCol,
|
||||
@@ -27,12 +28,10 @@ const getCoordinatesByLabel = (
|
||||
schema: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
categoryName: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
categoryDf: any,
|
||||
categoryDf: Dataframe,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
layoutChoice: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
layoutDf: any
|
||||
layoutDf: Dataframe
|
||||
) => {
|
||||
const coordsByCategoryLabel = new Map();
|
||||
// If the coloredBy is not a categorical col
|
||||
@@ -50,11 +49,8 @@ const getCoordinatesByLabel = (
|
||||
schema.annotations.obsByName[categoryName]
|
||||
);
|
||||
|
||||
const {
|
||||
isUserAnno,
|
||||
categoryValueIndices,
|
||||
categoryValueCounts,
|
||||
} = categorySummary;
|
||||
const { isUserAnno, categoryValueIndices, categoryValueCounts } =
|
||||
categorySummary;
|
||||
|
||||
// Iterate over all cells
|
||||
for (let i = 0, len = categoryArray.length; i < len; i += 1) {
|
||||
@@ -114,12 +110,10 @@ const calcMedianCentroid = (
|
||||
schema: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
categoryName: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
categoryDf: any,
|
||||
categoryDf: Dataframe,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
layoutChoice: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
layoutDf: any
|
||||
layoutDf: Dataframe
|
||||
) => {
|
||||
// generate a map describing the coordinates for each label within the given category
|
||||
const dataMap = getCoordinatesByLabel(
|
||||
@@ -159,13 +153,11 @@ const hashMedianCentroid = (
|
||||
schema: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
categoryName: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
categoryDf: any,
|
||||
categoryDf: Dataframe,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
layoutChoice: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
layoutDf: any
|
||||
) => {
|
||||
layoutDf: Dataframe
|
||||
): string => {
|
||||
const category = categoryDf.col(categoryName);
|
||||
const layoutDimNames = layoutChoice.currentDimNames;
|
||||
const layoutX = layoutDf.col(layoutDimNames[0]);
|
||||
|
||||
@@ -10,21 +10,18 @@ objects.
|
||||
*/
|
||||
|
||||
import { memoize } from "./util";
|
||||
import Dataframe from "./dataframe";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function hashDataframe(df: any) {
|
||||
function hashDataframe(df: Dataframe): string {
|
||||
if (df.isEmpty()) return "";
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
return df.__columnsAccessor.map((c: any) => c.__id).join(",");
|
||||
return df.__columnsAccessor.map((c) => c.__id).join(",");
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function noop(df: any) {
|
||||
function noop(df: Dataframe): Dataframe {
|
||||
return df;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
const dataframeMemo = (capacity = 100) =>
|
||||
const dataframeMemo = (capacity = 100): ((df: Dataframe) => Dataframe) =>
|
||||
memoize(noop, hashDataframe, capacity);
|
||||
|
||||
export default dataframeMemo;
|
||||
|
||||
@@ -1,25 +1,44 @@
|
||||
import { IdentityInt32Index, isLabelIndex } from "./labelIndex";
|
||||
// weird cross-dependency that we should clean up someday...
|
||||
import { callOnceLazy, memoize, __getMemoId } from "./util";
|
||||
import { isTypedArray, isAnyArray } from "../../common/types/arraytypes";
|
||||
import {
|
||||
summarizeContinuous,
|
||||
isTypedArray,
|
||||
isAnyArray,
|
||||
AnyArray,
|
||||
GenericArrayConstructor,
|
||||
} from "../../common/types/arraytypes";
|
||||
import { IdentityInt32Index, LabelIndex, isLabelIndex } from "./labelIndex";
|
||||
import {
|
||||
summarizeContinuous as _summarizeContinuous,
|
||||
summarizeCategorical as _summarizeCategorical,
|
||||
} from "./summarize";
|
||||
import {
|
||||
histogramCategorical as _histogramCategorical,
|
||||
histogramCategoricalBy as _histogramCategoricalBy,
|
||||
hashCategorical,
|
||||
histogramContinuous,
|
||||
hashCategoricalBy,
|
||||
histogramContinuous as _histogramContinuous,
|
||||
histogramContinuousBy as _histogramContinuousBy,
|
||||
hashContinuous,
|
||||
hashContinuousBy,
|
||||
} from "./histogram";
|
||||
import {
|
||||
DataframeValue,
|
||||
DataframeValueArray,
|
||||
DataframeColumn,
|
||||
OffsetType,
|
||||
OffsetArray,
|
||||
LabelType,
|
||||
LabelArray,
|
||||
ContinuousHistogram,
|
||||
ContinuousHistogramBy,
|
||||
} from "./types";
|
||||
|
||||
/*
|
||||
Dataframe is an immutable 2D matrix similiar to Python Pandas Dataframe,
|
||||
Dataframe is an immutable 2D matrix similar to Python Pandas Dataframe,
|
||||
but (currently) without all of the surrounding support functions.
|
||||
Data is stored in column-major layout, and each column is monomorphic.
|
||||
|
||||
It supports:
|
||||
* Relatively efficient creation, cloning and subsetting
|
||||
* Relatively efficient create, clone and subset operations
|
||||
* Very efficient columnar access (eg, sum down a column), and access
|
||||
to the underlying column arrays.
|
||||
* Data access by row/col offset or label. Labels are reasonably well
|
||||
@@ -27,10 +46,10 @@ It supports:
|
||||
|
||||
It does not currently support:
|
||||
* Views on matrix subset - for currently known access patterns,
|
||||
it is more effiicent to copy on subsetting, optimizing for access
|
||||
it is more efficient to copy on subsetting, optimizing for access
|
||||
speed over memory use.
|
||||
* JS iterators - they are too slow. Use explicit iteration over
|
||||
offest or labels.
|
||||
offset or labels.
|
||||
|
||||
Important assumptions embedded in the API:
|
||||
* Columns are implicitly categorical if they are a JS Array and numeric
|
||||
@@ -67,46 +86,55 @@ dominant pattern in cellxgene.
|
||||
Dataframe
|
||||
**/
|
||||
|
||||
interface DataframeConstructor {
|
||||
new (...args: ConstructorParameters<typeof Dataframe>): Dataframe;
|
||||
}
|
||||
|
||||
export type MapColumnsCallbackFn = (
|
||||
data: DataframeValueArray,
|
||||
idx: number,
|
||||
df: Dataframe
|
||||
) => DataframeValueArray;
|
||||
|
||||
/** @internal */
|
||||
function raiseIsNotContinuous<R = void>(): R {
|
||||
throw TypeError("Column is not a continuous data type.");
|
||||
}
|
||||
|
||||
class Dataframe {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
__columns: any;
|
||||
/** @internal */
|
||||
__columns: DataframeValueArray[];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
__columnsAccessor: any;
|
||||
/** @internal */
|
||||
__columnsAccessor: DataframeColumn[] = [];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
__id: any;
|
||||
__id: string;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
colIndex: any;
|
||||
colIndex: LabelIndex;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
dims: any;
|
||||
dims: [number, number];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
length: any;
|
||||
length: number;
|
||||
|
||||
rowIndex: LabelIndex;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
rowIndex: any;
|
||||
/**
|
||||
Constructors & factories
|
||||
**/
|
||||
|
||||
constructor(
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
dims: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
columnarData: any,
|
||||
rowIndex = null,
|
||||
colIndex = null,
|
||||
__columnsAccessor = [] // private interface
|
||||
dims: [number, number],
|
||||
columnarData: DataframeValueArray[],
|
||||
rowIndex?: LabelIndex | null,
|
||||
colIndex?: LabelIndex | null,
|
||||
__columnsAccessor: (DataframeColumn | null)[] = [] // private interface
|
||||
) {
|
||||
/*
|
||||
The base constructor is relatively hard to use - as an alternative,
|
||||
see factory methods and clone/slice, below.
|
||||
|
||||
Parameters:
|
||||
* dims - 2D array describing intendend dimensionality: [nRows,nCols].
|
||||
* dims - 2D array describing intended dimensionality: [nRows,nCols].
|
||||
* columnarData - JS array, nCols in length, containing array
|
||||
or TypedArray of length nRows.
|
||||
* rowIndex/colIndex - null (create default index using offsets as key),
|
||||
@@ -121,11 +149,9 @@ class Dataframe {
|
||||
throw new RangeError("Dataframe dimensions must be positive");
|
||||
}
|
||||
if (!rowIndex) {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'IdentityInt32Index' is not assignable to typ... Remove this comment to see the full error message
|
||||
rowIndex = new IdentityInt32Index(nRows);
|
||||
}
|
||||
if (!colIndex) {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'IdentityInt32Index' is not assignable to typ... Remove this comment to see the full error message
|
||||
colIndex = new IdentityInt32Index(nCols);
|
||||
}
|
||||
Dataframe.__errorChecks(dims, columnarData, rowIndex, colIndex);
|
||||
@@ -141,17 +167,13 @@ class Dataframe {
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
/** @internal */
|
||||
static __errorChecks(
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
dims: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
columnarData: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
rowIndex: any,
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
colIndex: any
|
||||
) {
|
||||
dims: [number, number],
|
||||
columnarData: AnyArray[],
|
||||
rowIndex: LabelIndex,
|
||||
colIndex: LabelIndex
|
||||
): void | never {
|
||||
const [nRows, nCols] = dims;
|
||||
|
||||
/* check for expected types */
|
||||
@@ -189,8 +211,12 @@ class Dataframe {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
static __compileColumn(column: any, getRowByOffset: any, getRowByLabel: any) {
|
||||
/** @internal */
|
||||
static __compileColumn(
|
||||
column: DataframeValueArray,
|
||||
getRowOffset: (label: LabelType) => OffsetType | -1,
|
||||
getRowLabel: (offset: number) => LabelType | undefined
|
||||
): DataframeColumn {
|
||||
/*
|
||||
Each column accessor is a function which will lookup data by
|
||||
index (ie, is equivalent to dataframe.get(row, col), where 'col'
|
||||
@@ -223,16 +249,17 @@ class Dataframe {
|
||||
*/
|
||||
const { length } = column;
|
||||
const __id = __getMemoId();
|
||||
const isContinuous = isTypedArray(column);
|
||||
|
||||
/* get value by row label */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const get = function get(rlabel: any) {
|
||||
return column[getRowByOffset(rlabel)];
|
||||
const get = function get(rlabel: LabelType): DataframeValue | undefined {
|
||||
const idx = getRowOffset(rlabel);
|
||||
if (idx === -1) return undefined;
|
||||
return column[idx];
|
||||
};
|
||||
|
||||
/* get value by row offset */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const iget = function iget(roffset: any) {
|
||||
const iget = function iget(roffset: OffsetType) {
|
||||
return column[roffset];
|
||||
};
|
||||
|
||||
@@ -242,14 +269,12 @@ class Dataframe {
|
||||
};
|
||||
|
||||
/* test for row label inclusion in column */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const has = function has(rlabel: any) {
|
||||
const offset = getRowByOffset(rlabel);
|
||||
const has = function has(rlabel: LabelType) {
|
||||
const offset = getRowOffset(rlabel);
|
||||
return offset >= 0 && offset < length;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const ihas = function ihas(offset: any) {
|
||||
const ihas = function ihas(offset: OffsetType) {
|
||||
return offset >= 0 && offset < length;
|
||||
};
|
||||
|
||||
@@ -260,84 +285,88 @@ class Dataframe {
|
||||
NOTE: not found return is DIFFERENT than the default Array.indexOf as
|
||||
-1 is a plausible Dataframe row/col label.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const indexOf = function indexOf(value: any) {
|
||||
const offset = column.indexOf(value);
|
||||
const _indexOf = function _indexOf(value: DataframeValue) {
|
||||
let offset: number;
|
||||
if (isTypedArray(column)) offset = column.indexOf(value as number);
|
||||
else offset = column.indexOf(value);
|
||||
if (offset === -1) {
|
||||
return undefined;
|
||||
}
|
||||
return getRowByLabel(offset);
|
||||
return getRowLabel(offset);
|
||||
};
|
||||
|
||||
/*
|
||||
Summarize the column data. Lazy eval, memoized
|
||||
*/
|
||||
const summarizeCategorical = callOnceLazy(() =>
|
||||
get.summarizeCategorical = callOnceLazy(() =>
|
||||
_summarizeCategorical(column)
|
||||
);
|
||||
const summarize = callOnceLazy(() =>
|
||||
isTypedArray(column)
|
||||
? summarizeContinuous(column)
|
||||
: summarizeCategorical(column)
|
||||
);
|
||||
get.summarizeContinuous = isContinuous
|
||||
? callOnceLazy(() => _summarizeContinuous(column))
|
||||
: raiseIsNotContinuous;
|
||||
|
||||
/*
|
||||
Create histogram bins for this column. Memoized.
|
||||
*/
|
||||
const _memoHistoCat = memoize(_histogramCategorical, hashCategorical);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const histogramCategorical = (by: any) => _memoHistoCat(get, by);
|
||||
let histogram = null;
|
||||
if (isTypedArray(column)) {
|
||||
const mFn = memoize(histogramContinuous, hashContinuous);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
histogram = (bins: any, domain: any, by: any) =>
|
||||
mFn(get, bins, domain, by);
|
||||
} else {
|
||||
histogram = histogramCategorical;
|
||||
}
|
||||
get.histogramContinuous = isContinuous
|
||||
? (bins: number, domain: [number, number]): ContinuousHistogram =>
|
||||
memoize(_histogramContinuous, hashContinuous)(get, bins, domain)
|
||||
: raiseIsNotContinuous;
|
||||
get.histogramContinuousBy = isContinuous
|
||||
? (
|
||||
bins: number,
|
||||
domain: [number, number],
|
||||
by: DataframeColumn
|
||||
): ContinuousHistogramBy =>
|
||||
memoize(_histogramContinuousBy, hashContinuousBy)(
|
||||
get,
|
||||
bins,
|
||||
domain,
|
||||
by
|
||||
)
|
||||
: raiseIsNotContinuous;
|
||||
get.histogramCategorical = () =>
|
||||
memoize(_histogramCategorical, hashCategorical)(get);
|
||||
get.histogramCategoricalBy = (by: DataframeColumn) =>
|
||||
memoize(_histogramCategoricalBy, hashCategoricalBy)(get, by);
|
||||
|
||||
get.summarize = summarize;
|
||||
get.summarizeCategorical = summarizeCategorical;
|
||||
get.histogram = histogram;
|
||||
get.histogramCategorical = histogramCategorical;
|
||||
get.asArray = asArray;
|
||||
get.has = has;
|
||||
get.ihas = ihas;
|
||||
get.indexOf = indexOf;
|
||||
get.indexOf = _indexOf;
|
||||
get.iget = iget;
|
||||
get.__id = __id;
|
||||
get.isContinuous = isContinuous;
|
||||
|
||||
Object.freeze(get);
|
||||
return get;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
__compile(accessors: any) {
|
||||
/** @internal */
|
||||
__compile(accessors: (DataframeColumn | null)[]): void {
|
||||
/*
|
||||
Compile data accessors for each column.
|
||||
|
||||
Use an existing accessor if provided, else compile a new one.
|
||||
*/
|
||||
const getRowByOffset = this.rowIndex.getOffset.bind(this.rowIndex);
|
||||
const getRowByLabel = this.rowIndex.getLabel.bind(this.rowIndex);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
this.__columnsAccessor = this.__columns.map((column: any, idx: any) => {
|
||||
if (accessors[idx]) {
|
||||
return accessors[idx];
|
||||
const getRowOffset = this.rowIndex.getOffset.bind(this.rowIndex);
|
||||
const getRowLabel = this.rowIndex.getLabel.bind(this.rowIndex);
|
||||
this.__columnsAccessor = this.__columns.map(
|
||||
(column, idx): DataframeColumn => {
|
||||
if (accessors[idx]) {
|
||||
return accessors[idx] as DataframeColumn;
|
||||
}
|
||||
return Dataframe.__compileColumn(column, getRowOffset, getRowLabel);
|
||||
}
|
||||
return Dataframe.__compileColumn(column, getRowByOffset, getRowByLabel);
|
||||
});
|
||||
);
|
||||
Object.freeze(this.__columnsAccessor);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
clone() {
|
||||
clone(): Dataframe {
|
||||
/*
|
||||
Clone this dataframe
|
||||
*/
|
||||
// @ts-expect-error ts-migrate(2351) FIXME: This expression is not constructable.
|
||||
return new this.constructor(
|
||||
return new (this.constructor as DataframeConstructor)(
|
||||
this.dims,
|
||||
[...this.__columns],
|
||||
this.rowIndex,
|
||||
@@ -346,8 +375,11 @@ class Dataframe {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
withCol(label: any, colData: any, withRowIndex = null) {
|
||||
withCol(
|
||||
label: LabelType,
|
||||
colData: DataframeValueArray,
|
||||
withRowIndex?: LabelIndex
|
||||
): Dataframe {
|
||||
/*
|
||||
Create a new DF, which is `this` plus the new column. Example:
|
||||
const newDf = df.withCol("foo", [1,2,3]);
|
||||
@@ -362,11 +394,10 @@ class Dataframe {
|
||||
the rowIndex from `this` will be used (ie, the rowIndex is
|
||||
unchanged).
|
||||
*/
|
||||
let dims;
|
||||
let rowIndex;
|
||||
let dims: [number, number];
|
||||
let rowIndex: LabelIndex | null = null;
|
||||
if (this.isEmpty()) {
|
||||
dims = [colData.length, 1];
|
||||
rowIndex = null;
|
||||
} else {
|
||||
dims = [this.dims[0], this.dims[1] + 1];
|
||||
({ rowIndex } = this);
|
||||
@@ -380,8 +411,7 @@ class Dataframe {
|
||||
columns.push(colData);
|
||||
const colIndex = this.colIndex.withLabel(label);
|
||||
const columnsAccessor = [...this.__columnsAccessor];
|
||||
// @ts-expect-error ts-migrate(2351) FIXME: This expression is not constructable.
|
||||
return new this.constructor(
|
||||
return new (this.constructor as DataframeConstructor)(
|
||||
dims,
|
||||
columns,
|
||||
rowIndex,
|
||||
@@ -390,8 +420,10 @@ class Dataframe {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
withColsFrom(dataframe: any, labels: any) {
|
||||
withColsFrom(
|
||||
dataframe: Dataframe,
|
||||
labels?: Record<string | number, LabelType> | LabelType[]
|
||||
): Dataframe {
|
||||
/*
|
||||
return a new dataframe containing all columns from both `this` and the
|
||||
provided dataframe argument.
|
||||
@@ -417,8 +449,8 @@ class Dataframe {
|
||||
*/
|
||||
|
||||
// resolve the source and dest label names.
|
||||
let srcLabels;
|
||||
let dstLabels;
|
||||
let srcLabels: LabelArray;
|
||||
let dstLabels: LabelArray;
|
||||
if (!labels) {
|
||||
// combine all columns
|
||||
dstLabels = dataframe.colIndex.labels();
|
||||
@@ -453,12 +485,9 @@ class Dataframe {
|
||||
return dataframe;
|
||||
}
|
||||
|
||||
// otherwise, bulid a new dataframe combining columns from both
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const srcOffsets = srcLabels.map((l: any) =>
|
||||
dataframe.colIndex.getOffset(l)
|
||||
);
|
||||
// otherwise, build a new dataframe combining columns from both
|
||||
const srcOffsets = Array.from(dataframe.colIndex.getOffsets(srcLabels));
|
||||
if (srcOffsets.some((i) => i === -1)) throw RangeError("Unknown label.");
|
||||
|
||||
// check for label collisions
|
||||
if (dstLabels.some(this.hasCol, this)) {
|
||||
@@ -466,22 +495,22 @@ class Dataframe {
|
||||
}
|
||||
|
||||
// const dims = [this.dims[0], this.dims[1] + dataframe.dims[1]];
|
||||
const dims = [this.dims[0], this.dims[1] + srcOffsets.length];
|
||||
const dims: [number, number] = [
|
||||
this.dims[0],
|
||||
this.dims[1] + srcOffsets.length,
|
||||
];
|
||||
const { rowIndex } = this;
|
||||
const columns = [
|
||||
const columns: DataframeValueArray[] = [
|
||||
...this.__columns,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
...srcOffsets.map((i: any) => dataframe.__columns[i]),
|
||||
...srcOffsets.map((i) => dataframe.__columns[i]),
|
||||
];
|
||||
const colIndex = this.colIndex.withLabels(dstLabels);
|
||||
const columnsAccessor = [
|
||||
...this.__columnsAccessor,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
...srcOffsets.map((i: any) => dataframe.__columnsAccessor[i]),
|
||||
...srcOffsets.map((i) => dataframe.__columnsAccessor[i]),
|
||||
];
|
||||
|
||||
// @ts-expect-error ts-migrate(2351) FIXME: This expression is not constructable.
|
||||
return new this.constructor(
|
||||
return new (this.constructor as DataframeConstructor)(
|
||||
dims,
|
||||
columns,
|
||||
rowIndex,
|
||||
@@ -490,15 +519,12 @@ class Dataframe {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
withColsFromAll(dataframes = []) {
|
||||
withColsFromAll(dataframes: Dataframe[] = []): Dataframe {
|
||||
dataframes = Array.isArray(dataframes) ? dataframes : [dataframes];
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
return dataframes.reduce((acc, df) => acc.withColsFrom(df), this);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
dropCol(label: any) {
|
||||
dropCol(label: LabelType): Dataframe {
|
||||
/*
|
||||
Create a new dataframe, omitting one columns.
|
||||
|
||||
@@ -517,15 +543,15 @@ class Dataframe {
|
||||
return Dataframe.empty();
|
||||
}
|
||||
|
||||
const dims = [this.dims[0], this.dims[1] - 1];
|
||||
const dims: [number, number] = [this.dims[0], this.dims[1] - 1];
|
||||
const coffset = this.colIndex.getOffset(label);
|
||||
if (coffset === -1) throw new RangeError("Unknown label.");
|
||||
const columns = [...this.__columns];
|
||||
columns.splice(coffset, 1);
|
||||
const colIndex = this.colIndex.dropLabel(label);
|
||||
const columnsAccessor = [...this.__columnsAccessor];
|
||||
columnsAccessor.splice(coffset, 1);
|
||||
// @ts-expect-error ts-migrate(2351) FIXME: This expression is not constructable.
|
||||
return new this.constructor(
|
||||
return new (this.constructor as DataframeConstructor)(
|
||||
dims,
|
||||
columns,
|
||||
this.rowIndex,
|
||||
@@ -534,12 +560,12 @@ class Dataframe {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
renameCol(oldLabel: any, newLabel: any) {
|
||||
renameCol(oldLabel: LabelType, newLabel: LabelType): Dataframe {
|
||||
/*
|
||||
Accelerator for dropping a column and then adding it again with a new label
|
||||
*/
|
||||
const coffset = this.colIndex.getOffset(oldLabel);
|
||||
if (coffset === -1) throw new RangeError("Unknown label.");
|
||||
const colIndex = this.colIndex.dropLabel(oldLabel).withLabel(newLabel);
|
||||
|
||||
const columns = [...this.__columns];
|
||||
@@ -550,8 +576,7 @@ class Dataframe {
|
||||
columnsAccessor.push(columnsAccessor[coffset]);
|
||||
columnsAccessor.splice(coffset, 1);
|
||||
|
||||
// @ts-expect-error ts-migrate(2351) FIXME: This expression is not constructable.
|
||||
return new this.constructor(
|
||||
return new (this.constructor as DataframeConstructor)(
|
||||
this.dims,
|
||||
columns,
|
||||
this.rowIndex,
|
||||
@@ -560,20 +585,21 @@ class Dataframe {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
replaceColData(label: any, newColData: any) {
|
||||
replaceColData(label: LabelType, newColData: DataframeValueArray): Dataframe {
|
||||
/*
|
||||
Accelerator for dropping a column then adding it again with same
|
||||
label and different values.
|
||||
*/
|
||||
const coffset = this.colIndex.getOffset(label);
|
||||
if (coffset === -1) throw RangeError("Unknown column label.");
|
||||
const columns = [...this.__columns];
|
||||
columns[coffset] = newColData;
|
||||
const columnsAccessor = [...this.__columnsAccessor];
|
||||
const columnsAccessor: (DataframeColumn | null)[] = [
|
||||
...this.__columnsAccessor,
|
||||
];
|
||||
columnsAccessor[coffset] = null;
|
||||
|
||||
// @ts-expect-error ts-migrate(2351) FIXME: This expression is not constructable.
|
||||
return new this.constructor(
|
||||
return new (this.constructor as DataframeConstructor)(
|
||||
this.dims,
|
||||
columns,
|
||||
this.rowIndex,
|
||||
@@ -582,20 +608,19 @@ class Dataframe {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
static empty(rowIndex = null, colIndex = null) {
|
||||
const dims = [
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
static empty(rowIndex?: LabelIndex, colIndex?: LabelIndex): Dataframe {
|
||||
const dims: [number, number] = [
|
||||
rowIndex ? rowIndex.size() : 0,
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
colIndex ? colIndex.size() : 0,
|
||||
];
|
||||
if (dims[0] && dims[1]) throw new Error("not an empty dataframe");
|
||||
return new Dataframe(dims, new Array(dims[1]), rowIndex, colIndex);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
static create(dims: any, columnarData: any) {
|
||||
static create(
|
||||
dims: [number, number],
|
||||
columnarData: DataframeValueArray[]
|
||||
): Dataframe {
|
||||
/*
|
||||
Create a dataframe from raw columnar data. All column arrays
|
||||
must have the same length. Identity indexing will be used.
|
||||
@@ -603,12 +628,15 @@ class Dataframe {
|
||||
Example:
|
||||
const df = Dataframe.create([2,2], [new Uint32Array(2), new Float32Array(2)]);
|
||||
*/
|
||||
return new Dataframe(dims, columnarData, null, null);
|
||||
return new Dataframe(dims, columnarData);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
__subset(newRowIndex: any, newColIndex: any) {
|
||||
const dims = [...this.dims];
|
||||
/** @internal */
|
||||
__subset(
|
||||
newRowIndex: LabelIndex | null,
|
||||
newColIndex: LabelIndex | null
|
||||
): Dataframe {
|
||||
const dims: [number, number] = [...this.dims];
|
||||
|
||||
/* subset columns */
|
||||
let { __columns, colIndex, __columnsAccessor } = this;
|
||||
@@ -617,8 +645,10 @@ class Dataframe {
|
||||
__columns = new Array(colOffsets.length);
|
||||
__columnsAccessor = new Array(colOffsets.length);
|
||||
for (let i = 0, l = colOffsets.length; i < l; i += 1) {
|
||||
__columns[i] = this.__columns[colOffsets[i]];
|
||||
__columnsAccessor[i] = this.__columnsAccessor[colOffsets[i]];
|
||||
const colOffset = colOffsets[i];
|
||||
if (colOffset === -1) throw new RangeError("Unexpected column offset.");
|
||||
__columns[i] = this.__columns[colOffset];
|
||||
__columnsAccessor[i] = this.__columnsAccessor[colOffset];
|
||||
}
|
||||
colIndex = newColIndex;
|
||||
dims[1] = colOffsets.length;
|
||||
@@ -627,11 +657,14 @@ class Dataframe {
|
||||
let { rowIndex } = this;
|
||||
if (newRowIndex) {
|
||||
const rowOffsets = this.rowIndex.getOffsets(newRowIndex.labels());
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
__columns = __columns.map((col: any) => {
|
||||
const newCol = new col.constructor(rowOffsets.length);
|
||||
__columns = __columns.map((col) => {
|
||||
const newCol = new (col.constructor as GenericArrayConstructor<
|
||||
typeof col
|
||||
>)(rowOffsets.length);
|
||||
for (let i = 0, l = rowOffsets.length; i < l; i += 1) {
|
||||
newCol[i] = col[rowOffsets[i]];
|
||||
const rowOffset = rowOffsets[i];
|
||||
if (rowOffset === -1) throw new RangeError("Unexpected row offset.");
|
||||
newCol[i] = col[rowOffset];
|
||||
}
|
||||
return newCol;
|
||||
});
|
||||
@@ -650,8 +683,11 @@ class Dataframe {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
subset(rowLabels: any, colLabels = null, withRowIndex = null) {
|
||||
subset(
|
||||
rowLabels: LabelArray | null,
|
||||
colLabels: LabelArray | null,
|
||||
withRowIndex?: LabelIndex | null
|
||||
): Dataframe {
|
||||
/*
|
||||
Subset by row/col labels.
|
||||
|
||||
@@ -673,8 +709,11 @@ class Dataframe {
|
||||
return this.__subset(rowIndex, colIndex);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
isubset(rowOffsets: any, colOffsets = null, withRowIndex = null) {
|
||||
isubset(
|
||||
rowOffsets: OffsetArray | null,
|
||||
colOffsets: OffsetArray | null,
|
||||
withRowIndex?: LabelIndex | null
|
||||
): Dataframe {
|
||||
/*
|
||||
Subset by row/col offset.
|
||||
|
||||
@@ -683,14 +722,14 @@ class Dataframe {
|
||||
indexing. If withRowIndex is a label index object, it will be used
|
||||
for the new dataframe.
|
||||
*/
|
||||
let rowIndex = null;
|
||||
let rowIndex: LabelIndex | null = null;
|
||||
if (withRowIndex) {
|
||||
rowIndex = withRowIndex;
|
||||
} else if (rowOffsets) {
|
||||
rowIndex = this.rowIndex.isubset(rowOffsets);
|
||||
}
|
||||
|
||||
let colIndex = null;
|
||||
let colIndex: LabelIndex | null = null;
|
||||
if (colOffsets) {
|
||||
colIndex = this.colIndex.isubset(colOffsets);
|
||||
}
|
||||
@@ -698,8 +737,11 @@ class Dataframe {
|
||||
return this.__subset(rowIndex, colIndex);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
isubsetMask(rowMask: any, colMask = null, withRowIndex = null) {
|
||||
isubsetMask(
|
||||
rowMask: Uint8Array | boolean[] | null,
|
||||
colMask: Uint8Array | boolean[] | null,
|
||||
withRowIndex?: LabelIndex | null
|
||||
): Dataframe {
|
||||
/*
|
||||
Subset on row/column based upon a truthy/falsey array (a mask).
|
||||
|
||||
@@ -711,15 +753,16 @@ class Dataframe {
|
||||
const [nRows, nCols] = this.dims;
|
||||
if (
|
||||
(rowMask && rowMask.length !== nRows) ||
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
(colMask && colMask.length !== nCols)
|
||||
) {
|
||||
throw new RangeError("boolean arrays must match row/col dimensions");
|
||||
}
|
||||
|
||||
/* convert masks to lists - method wastes space, but is fast */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const toList = (mask: any, maxSize: any) => {
|
||||
const toList = (
|
||||
mask: Uint8Array | boolean[] | null | undefined,
|
||||
maxSize: number
|
||||
) => {
|
||||
if (!mask) {
|
||||
return null;
|
||||
}
|
||||
@@ -735,7 +778,6 @@ class Dataframe {
|
||||
};
|
||||
const rowOffsets = toList(rowMask, nRows);
|
||||
const colOffsets = toList(colMask, nCols);
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'Int32Array | null' is not assign... Remove this comment to see the full error message
|
||||
return this.isubset(rowOffsets, colOffsets, withRowIndex);
|
||||
}
|
||||
|
||||
@@ -743,14 +785,12 @@ class Dataframe {
|
||||
Data access with row/col.
|
||||
**/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
columns() {
|
||||
columns(): DataframeColumn[] {
|
||||
/* return all column accessors as an array, in offset order */
|
||||
return [...this.__columnsAccessor];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
col(columnLabel: any) {
|
||||
col(columnLabel: LabelType): DataframeColumn {
|
||||
/*
|
||||
Return accessor bound to a column. Allows random row access
|
||||
based upon the row indexing. Returns undefined if the
|
||||
@@ -767,39 +807,44 @@ class Dataframe {
|
||||
See __compile() for the functions available in a column accessor.
|
||||
*/
|
||||
const coff = this.colIndex.getOffset(columnLabel);
|
||||
if (coff === -1) throw RangeError("Unknown label.");
|
||||
return this.__columnsAccessor[coff];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
icol(columnOffset: any) {
|
||||
icol(columnOffset: OffsetType): DataframeColumn {
|
||||
/*
|
||||
Return column accessor by offset.
|
||||
*/
|
||||
return Number.isInteger(columnOffset)
|
||||
? this.__columnsAccessor[columnOffset]
|
||||
: undefined;
|
||||
if (
|
||||
Number.isInteger(columnOffset) &&
|
||||
columnOffset >= 0 &&
|
||||
columnOffset < this.__columnsAccessor.length
|
||||
) {
|
||||
return this.__columnsAccessor[columnOffset];
|
||||
}
|
||||
throw new RangeError("Unknown offset.");
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
at(r: any, c: any) {
|
||||
at(r: LabelType, c: LabelType): DataframeValue {
|
||||
/*
|
||||
Access a single value, for a row/col label pair.
|
||||
|
||||
For performance reasons, there are no bounds or existance
|
||||
For performance reasons, there are no bounds or existence
|
||||
checks on labels, and no defined behavior when these are supplied.
|
||||
May return undefined, throw an Error, or do something else for
|
||||
non-existant labels. If you want predictable out-of-bounds
|
||||
non-existent labels. If you want predictable out-of-bounds
|
||||
behavior, use has(), eg,
|
||||
|
||||
const myVal = df.has(r,l) ? df.at(r,l) : undefined;
|
||||
*/
|
||||
const coff = this.colIndex.getOffset(c);
|
||||
const roff = this.rowIndex.getOffset(r);
|
||||
if (coff === undefined || roff === undefined)
|
||||
throw new RangeError("Unknown row or column label.");
|
||||
return this.__columns[coff][roff];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
iat(r: any, c: any) {
|
||||
iat(r: OffsetType, c: OffsetType): DataframeValue {
|
||||
/*
|
||||
Access a single value, for a row/col offset (integer) position.
|
||||
|
||||
@@ -809,11 +854,12 @@ class Dataframe {
|
||||
|
||||
const myVal = df.ihas(r, c) ? df.iat(r, c) : undefined;
|
||||
*/
|
||||
return this.__columns[c][r];
|
||||
if (c >= 0 && c < this.dims[1] && r >= 0 && r < this.dims[0])
|
||||
return this.__columns[c][r];
|
||||
throw new RangeError("Unknown row or column index.");
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
has(r: any, c: any) {
|
||||
has(r: LabelType, c: LabelType): boolean {
|
||||
/*
|
||||
Test if row/col labels exist in the dataframe - returns true/false
|
||||
*/
|
||||
@@ -823,8 +869,7 @@ class Dataframe {
|
||||
return coff >= 0 && coff < nCols && roff >= 0 && roff < nRows;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
ihas(r: any, c: any) {
|
||||
ihas(r: number, c: number): boolean {
|
||||
/*
|
||||
Test if row/col offset (integer) position exists in the
|
||||
dataframe - returns true/false
|
||||
@@ -840,16 +885,23 @@ class Dataframe {
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
hasCol(c: any) {
|
||||
hasCol(c: LabelType): boolean {
|
||||
/*
|
||||
Test if col label exists - return true/false
|
||||
*/
|
||||
return !!this.col(c);
|
||||
const coff = this.colIndex.getOffset(c);
|
||||
return coff !== -1;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
isEmpty() {
|
||||
ihasCol(i: number): boolean {
|
||||
/*
|
||||
Test if col offset exists - return true/false
|
||||
*/
|
||||
const [, nCols] = this.dims;
|
||||
return i >= 0 && i < nCols;
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
/*
|
||||
Return true if this is an empty dataframe, ie, has dimensions [0,0]
|
||||
*/
|
||||
@@ -864,24 +916,20 @@ class Dataframe {
|
||||
add these as useful.
|
||||
****/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
mapColumns(callback: any) {
|
||||
mapColumns(callback: MapColumnsCallbackFn): Dataframe {
|
||||
/*
|
||||
map all columns in the dataframe, returning a new dataframe comprised of the
|
||||
return values, with the same index as the original dataframe.
|
||||
|
||||
callback MUST not modify the column, but instead return a mutated copy.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const columns = this.__columns.map((colData: any, colIdx: any) =>
|
||||
const columns = this.__columns.map((colData, colIdx) =>
|
||||
callback(colData, colIdx, this)
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const columnsAccessor = columns.map((c: any, idx: any) =>
|
||||
this.__columns[idx] === c ? this.__columnsAccessor[idx] : undefined
|
||||
const columnsAccessor: (DataframeColumn | null)[] = columns.map((c, idx) =>
|
||||
this.__columns[idx] === c ? this.__columnsAccessor[idx] : null
|
||||
);
|
||||
// @ts-expect-error ts-migrate(2351) FIXME: This expression is not constructable.
|
||||
return new this.constructor(
|
||||
return new (this.constructor as DataframeConstructor)(
|
||||
this.dims,
|
||||
columns,
|
||||
this.rowIndex,
|
||||
@@ -889,29 +937,6 @@ class Dataframe {
|
||||
columnsAccessor
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
Map & reduce of column or row
|
||||
|
||||
TODO remainder of map/reduce functions: mapCol, mapRow, reduceRow, ...
|
||||
*/
|
||||
/* comment out until we have a use for this
|
||||
|
||||
reduceCol(clabel, callback, initialValue) {
|
||||
const coff = this.colIndex.getOffset(clabel);
|
||||
const column = this.__columns[coff];
|
||||
let start = 0;
|
||||
let acc = initialValue;
|
||||
if (initialValue === undefined) {
|
||||
acc = column[0];
|
||||
start = 1;
|
||||
}
|
||||
for (let i = start, l = column.length; i < l; i += 1) {
|
||||
acc = callback(acc, column[i]);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
export default Dataframe;
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
/*
|
||||
Dataframe histogram
|
||||
*/
|
||||
import { isTypedArray } from "../../common/types/arraytypes";
|
||||
import { NumberArray } from "../../common/types/arraytypes";
|
||||
import {
|
||||
DataframeColumn,
|
||||
ContinuousHistogram,
|
||||
ContinuousHistogramBy,
|
||||
CategoricalHistogram,
|
||||
CategoricalHistogramBy,
|
||||
} from "./types";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function _histogramContinuous(column: any, bins: any, min: any, max: any) {
|
||||
export function histogramContinuous(
|
||||
column: DataframeColumn,
|
||||
bins: number,
|
||||
domain: [number, number]
|
||||
): ContinuousHistogram {
|
||||
const valBins = new Array(bins).fill(0);
|
||||
if (!column) {
|
||||
return valBins;
|
||||
}
|
||||
const [min, max] = domain;
|
||||
const binWidth = (max - min) / bins;
|
||||
const colArray = column.asArray();
|
||||
const colArray: NumberArray = column.asArray() as NumberArray;
|
||||
for (let r = 0, len = colArray.length; r < len; r += 1) {
|
||||
const val = colArray[r];
|
||||
if (val <= max && val >= min) {
|
||||
@@ -22,25 +33,20 @@ function _histogramContinuous(column: any, bins: any, min: any, max: any) {
|
||||
return valBins;
|
||||
}
|
||||
|
||||
function _histogramContinuousBy(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
column: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
bins: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
min: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
max: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
by: any
|
||||
) {
|
||||
export function histogramContinuousBy(
|
||||
column: DataframeColumn,
|
||||
bins: number,
|
||||
domain: [number, number],
|
||||
by: DataframeColumn
|
||||
): ContinuousHistogramBy {
|
||||
const byMap = new Map();
|
||||
if (!column || !by) {
|
||||
return byMap;
|
||||
}
|
||||
const [min, max] = domain;
|
||||
const binWidth = (max - min) / bins;
|
||||
const byArray = by.asArray();
|
||||
const colArray = column.asArray();
|
||||
const colArray = column.asArray() as NumberArray;
|
||||
for (let r = 0, len = colArray.length; r < len; r += 1) {
|
||||
const byBin = byArray[r];
|
||||
let valBins = byMap.get(byBin);
|
||||
@@ -58,8 +64,9 @@ function _histogramContinuousBy(
|
||||
return byMap;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function _histogramCategorical(column: any) {
|
||||
export function histogramCategorical(
|
||||
column: DataframeColumn
|
||||
): CategoricalHistogram {
|
||||
const valMap = new Map();
|
||||
if (!column) {
|
||||
return valMap;
|
||||
@@ -76,8 +83,10 @@ function _histogramCategorical(column: any) {
|
||||
return valMap;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function _histogramCategoricalBy(column: any, by: any) {
|
||||
export function histogramCategoricalBy(
|
||||
column: DataframeColumn,
|
||||
by: DataframeColumn
|
||||
): CategoricalHistogramBy {
|
||||
const byMap = new Map();
|
||||
if (!column || !by) {
|
||||
return byMap;
|
||||
@@ -101,67 +110,38 @@ function _histogramCategoricalBy(column: any, by: any) {
|
||||
return byMap;
|
||||
}
|
||||
|
||||
/*
|
||||
Count category occupancy. Optional group-by category.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function histogramCategorical(column: any, by: any) {
|
||||
if (by && isTypedArray(by)) {
|
||||
throw new Error("Group by column must be categorical");
|
||||
}
|
||||
return by
|
||||
? _histogramCategoricalBy(column, by)
|
||||
: _histogramCategorical(column);
|
||||
}
|
||||
|
||||
/*
|
||||
Memoization hash for histogramCategorical()
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function hashCategorical(column: any, by: any) {
|
||||
if (by) {
|
||||
return `${column.__id}:${by.__id}`;
|
||||
}
|
||||
export function hashCategorical(column: DataframeColumn): string {
|
||||
return `${column.__id}:`;
|
||||
}
|
||||
|
||||
/*
|
||||
Bin counts for continuous/scalar values, with optional group-by category.
|
||||
Values outside domain are ignored.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
export function histogramContinuous(
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
column: any,
|
||||
bins = 40,
|
||||
domain = [0, 1],
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
by: any
|
||||
) {
|
||||
if (by && isTypedArray(by)) {
|
||||
throw new Error("Group by column must be categorical");
|
||||
}
|
||||
const [min, max] = domain;
|
||||
return by
|
||||
? _histogramContinuousBy(column, bins, min, max, by)
|
||||
: _histogramContinuous(column, bins, min, max);
|
||||
export function hashCategoricalBy(
|
||||
column: DataframeColumn,
|
||||
by: DataframeColumn
|
||||
): string {
|
||||
return `${column.__id}:${by.__id}`;
|
||||
}
|
||||
|
||||
/*
|
||||
Memoization hash for histogramContinuous
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
export function hashContinuous(
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
column: any,
|
||||
bins = "",
|
||||
domain = [0, 0],
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
by: any
|
||||
) {
|
||||
column: DataframeColumn,
|
||||
bins: number,
|
||||
domain: [number, number]
|
||||
): string {
|
||||
const [min, max] = domain;
|
||||
if (by) {
|
||||
return `${column.__id}:${bins}:${min}:${max}:${by.__id}`;
|
||||
}
|
||||
return `${column.__id}::${bins}:${min}:${max}`;
|
||||
}
|
||||
|
||||
export function hashContinuousBy(
|
||||
column: DataframeColumn,
|
||||
bins: number,
|
||||
domain: [number, number],
|
||||
by: DataframeColumn
|
||||
): string {
|
||||
const [min, max] = domain;
|
||||
return `${column.__id}:${bins}:${min}:${max}:${by.__id}`;
|
||||
}
|
||||
|
||||
@@ -6,3 +6,16 @@ export {
|
||||
isLabelIndex,
|
||||
} from "./labelIndex";
|
||||
export { default as dataframeMemo } from "./cache";
|
||||
export type {
|
||||
LabelType,
|
||||
DataframeValue,
|
||||
DataframeValueArray,
|
||||
DataframeColumn,
|
||||
ContinuousHistogram,
|
||||
ContinuousHistogramBy,
|
||||
CategoricalHistogram,
|
||||
CategoricalHistogramBy,
|
||||
ContinuousColumnSummary,
|
||||
CategoricalColumnSummary,
|
||||
} from "./types";
|
||||
export type { LabelIndex } from "./labelIndex";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable max-classes-per-file -- Classes are interrelated*/
|
||||
|
||||
/**
|
||||
Label indexing - map a label to & from an integer offset. See Dataframe
|
||||
for how this is used.
|
||||
@@ -6,45 +7,78 @@ for how this is used.
|
||||
|
||||
import { rangeFill as fillRange } from "../range";
|
||||
import { __getMemoId } from "./util";
|
||||
import { OffsetArray, LabelType, LabelArray, GenericLabelArray } from "./types";
|
||||
|
||||
/*
|
||||
Private utility functions
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function extent(tarr: any) {
|
||||
let min = 0x7fffffff;
|
||||
let max = ~min; // eslint-disable-line no-bitwise -- Establishes 0 of same size
|
||||
for (let i = 0, l = tarr.length; i < l; i += 1) {
|
||||
const v = tarr[i];
|
||||
if (v < min) {
|
||||
min = v;
|
||||
}
|
||||
if (v > max) {
|
||||
max = v;
|
||||
}
|
||||
export abstract class LabelIndexBase {
|
||||
readonly __id: string; // memoization helper
|
||||
|
||||
constructor(id: string) {
|
||||
this.__id = id;
|
||||
}
|
||||
return [min, max];
|
||||
|
||||
abstract labels(): LabelArray;
|
||||
|
||||
/**
|
||||
* Look up the offset for the label.
|
||||
*
|
||||
* @param label - label to look up
|
||||
* @returns - offset number or -1 if not found.
|
||||
*/
|
||||
abstract getOffset(label: LabelType): number;
|
||||
|
||||
getOffsets(labels: LabelArray): Int32Array {
|
||||
// labels to offsets
|
||||
const result = new Int32Array(labels.length);
|
||||
for (let i = 0; i < labels.length; i += 1) {
|
||||
result[i] = this.getOffset(labels[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the label for the offset.
|
||||
*
|
||||
* @param offset - offset to look up
|
||||
* @returns - label or undefined if not found.
|
||||
*/
|
||||
abstract getLabel(offset: number): LabelType | undefined;
|
||||
|
||||
getLabels(offsets: OffsetArray): (LabelType | undefined)[] {
|
||||
// offsets to labels
|
||||
const result = new Array(offsets.length);
|
||||
for (let i = 0; i < offsets.length; i += 1) {
|
||||
result[i] = this.getLabel(offsets[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
abstract size(): number;
|
||||
|
||||
abstract subset(labels: LabelArray): LabelIndexBase;
|
||||
|
||||
abstract isubset(offsets: OffsetArray): LabelIndexBase;
|
||||
|
||||
abstract isubsetMask(mask: Uint8Array | boolean[]): LabelIndexBase;
|
||||
|
||||
abstract withLabel(label: LabelType): LabelIndexBase;
|
||||
|
||||
abstract withLabels(labels: LabelArray): LabelIndexBase;
|
||||
|
||||
abstract dropLabel(label: LabelType): LabelIndexBase;
|
||||
}
|
||||
|
||||
class IdentityInt32Index {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
maxOffset: any;
|
||||
export class IdentityInt32Index extends LabelIndexBase {
|
||||
readonly maxOffset: number;
|
||||
|
||||
/*
|
||||
identity/noop index, with small assumptions that labels are int32
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
constructor(maxOffset: any) {
|
||||
constructor(maxOffset: number) {
|
||||
super(`IdentityInt32Index_${maxOffset}`);
|
||||
this.maxOffset = maxOffset;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
get __id() {
|
||||
return `IdentityInt32Index_${this.maxOffset}`;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
labels() {
|
||||
labels(): LabelArray {
|
||||
// memoize
|
||||
const k = fillRange(new Int32Array(this.maxOffset));
|
||||
this.labels = function labels() {
|
||||
@@ -53,77 +87,79 @@ class IdentityInt32Index {
|
||||
return k;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
getOffset(i: any) {
|
||||
getOffset(label: LabelType): number {
|
||||
// label to offset
|
||||
return Number.isInteger(i) && i >= 0 && i < this.maxOffset ? i : undefined;
|
||||
return Number.isInteger(label) && label >= 0 && label < this.maxOffset
|
||||
? (label as number)
|
||||
: -1;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
getOffsets(arr: any) {
|
||||
// labels to offsets
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
return arr.map((i: any) => this.getOffset(i));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
getLabel(i: any) {
|
||||
getLabel(offset: number): number | undefined {
|
||||
// offset to label
|
||||
return Number.isInteger(i) && i >= 0 && i < this.maxOffset ? i : undefined;
|
||||
return Number.isInteger(offset) && offset >= 0 && offset < this.maxOffset
|
||||
? offset
|
||||
: undefined;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
getLabels(arr: any) {
|
||||
// offsets to labels
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
return arr.map((i: any) => this.getLabel(i));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
size() {
|
||||
size(): number {
|
||||
return this.maxOffset;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
__promote(labelArray: any) {
|
||||
/** @internal */
|
||||
__promote(labelArray: LabelArray, allInts: boolean): LabelIndexBase {
|
||||
/*
|
||||
time/space decision - based on the resulting density
|
||||
*/
|
||||
const [minLabel, maxLabel] = extent(labelArray);
|
||||
if (minLabel === 0 && maxLabel === labelArray.length - 1)
|
||||
return new IdentityInt32Index(labelArray.length);
|
||||
if (labelArray.length === 0) return new KeyIndex(Array.from(labelArray));
|
||||
if (allInts) {
|
||||
const [minLabel, maxLabel] = extent(
|
||||
labelArray as GenericLabelArray<number> // safe, as allInts is true
|
||||
);
|
||||
if (minLabel === 0 && maxLabel === labelArray.length - 1)
|
||||
return new IdentityInt32Index(labelArray.length);
|
||||
|
||||
const labelSpaceSize = maxLabel - minLabel + 1;
|
||||
const density = labelSpaceSize / this.maxOffset;
|
||||
/* 0.1 is a magic number, that needs testing to optimize */
|
||||
if (density < 0.1) {
|
||||
return new KeyIndex(labelArray);
|
||||
const labelSpaceSize = maxLabel - minLabel + 1;
|
||||
const density = labelSpaceSize / this.maxOffset;
|
||||
/* 0.1 is a magic number which needs testing to optimize */
|
||||
if (density < 0.1) {
|
||||
return new KeyIndex(Array.from(labelArray));
|
||||
}
|
||||
return new DenseInt32Index(labelArray as GenericLabelArray<number>, [
|
||||
minLabel,
|
||||
maxLabel,
|
||||
]);
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number[]' is not assignable to p... Remove this comment to see the full error message
|
||||
return new DenseInt32Index(labelArray, [minLabel, maxLabel]);
|
||||
return new KeyIndex(Array.from(labelArray));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
subset(labels: any) {
|
||||
subset(labels: LabelArray): LabelIndexBase {
|
||||
/* validate subset */
|
||||
const { maxOffset } = this;
|
||||
for (let i = 0, l = labels.length; i < l; i += 1) {
|
||||
const label = labels[i];
|
||||
if (!Number.isInteger(label) || label < 0 || label >= maxOffset)
|
||||
throw new RangeError(`offset or label: ${label}`);
|
||||
throw new RangeError(`label: ${label}`);
|
||||
}
|
||||
return this.__promote(labels);
|
||||
return this.__promote(labels, true);
|
||||
}
|
||||
|
||||
/* identity index - labels are offsets */
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
isubset(offsets: any) {
|
||||
return this.subset(offsets);
|
||||
isubset(offsets: OffsetArray): LabelIndexBase {
|
||||
/* validate isubset */
|
||||
const { maxOffset } = this;
|
||||
for (let i = 0, l = offsets.length; i < l; i += 1) {
|
||||
const offset = offsets[i];
|
||||
if (!Number.isInteger(offset) || offset < 0 || offset >= maxOffset)
|
||||
throw new RangeError(`offset: ${offset}`);
|
||||
}
|
||||
if (!(offsets instanceof Int32Array)) {
|
||||
offsets = new Int32Array(offsets);
|
||||
}
|
||||
return this.__promote(offsets, true);
|
||||
}
|
||||
|
||||
/* identity index - labels are offsets */
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
isubsetMask(mask: any) {
|
||||
isubsetMask(mask: Uint8Array | boolean[]): LabelIndexBase {
|
||||
let count = 0;
|
||||
if (mask.length !== this.maxOffset) {
|
||||
throw new RangeError("mask has invalid length for index");
|
||||
@@ -139,54 +175,42 @@ class IdentityInt32Index {
|
||||
return this.subset(labels);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
withLabel(label: any) {
|
||||
withLabel(label: LabelType): LabelIndexBase {
|
||||
if (label === this.maxOffset) {
|
||||
return new IdentityInt32Index(label + 1);
|
||||
}
|
||||
return this.__promote([...this.labels(), label]);
|
||||
return this.__promote([...this.labels(), label], Number.isInteger(label));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
withLabels(labels: any) {
|
||||
return this.__promote([...this.labels(), ...labels]);
|
||||
withLabels(labels: LabelArray): LabelIndexBase {
|
||||
return this.__promote(
|
||||
[...this.labels(), ...labels],
|
||||
labels.every(Number.isInteger)
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
dropLabel(label: any) {
|
||||
dropLabel(label: LabelType): LabelIndexBase {
|
||||
if (!Number.isInteger(label) || label < 0 || label > this.maxOffset - 1)
|
||||
throw new RangeError("Invalid label.");
|
||||
if (label === this.maxOffset - 1) {
|
||||
return new IdentityInt32Index(label);
|
||||
}
|
||||
const labelArray = [...this.labels()];
|
||||
labelArray.splice(labelArray.indexOf(label), 1);
|
||||
return this.__promote(labelArray);
|
||||
labelArray.splice(labelArray.indexOf(label as number), 1);
|
||||
return this.__promote(labelArray, true);
|
||||
}
|
||||
}
|
||||
|
||||
class DenseInt32Index {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
__id: any;
|
||||
export class DenseInt32Index extends LabelIndexBase {
|
||||
getLabel: (offset: number) => number | undefined;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
getLabel: any;
|
||||
getOffset: (label: LabelType) => number;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
getLabels: any;
|
||||
index: Int32Array;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
getOffset: any;
|
||||
minLabel: number;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
getOffsets: any;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
index: any;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
minLabel: any;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
rindex: any;
|
||||
rindex: Int32Array;
|
||||
|
||||
/*
|
||||
DenseInt32Index indexes integer labels, and uses Int32Array typed arrays
|
||||
@@ -194,17 +218,16 @@ class DenseInt32Index {
|
||||
of the forward index labels must be known a priori (so that the index
|
||||
array can be pre-allocated).
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
constructor(labels: any, labelRange = null) {
|
||||
if (labels.constructor !== Int32Array) {
|
||||
labels = new Int32Array(labels);
|
||||
}
|
||||
|
||||
constructor(
|
||||
labels: GenericLabelArray<number>,
|
||||
labelRange?: [number, number]
|
||||
) {
|
||||
super(__getMemoId());
|
||||
const int32Labels =
|
||||
labels instanceof Int32Array ? labels : new Int32Array(labels);
|
||||
if (!labelRange) {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'number[]' is not assignable to type 'null'.
|
||||
labelRange = extent(labels);
|
||||
labelRange = extent(int32Labels);
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2488) FIXME: Type 'null' must have a '[Symbol.iterator]()' meth... Remove this comment to see the full error message
|
||||
const [minLabel, maxLabel] = labelRange;
|
||||
const labelSpaceSize = maxLabel - minLabel + 1;
|
||||
const index = new Int32Array(labelSpaceSize).fill(-1);
|
||||
@@ -214,82 +237,70 @@ class DenseInt32Index {
|
||||
}
|
||||
|
||||
this.minLabel = minLabel;
|
||||
this.rindex = labels;
|
||||
this.rindex = int32Labels;
|
||||
this.index = index;
|
||||
this.__id = __getMemoId();
|
||||
this.__compile();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
__compile() {
|
||||
const { minLabel, index, rindex } = this;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
this.getOffset = function getOffset(l: any) {
|
||||
if (!Number.isInteger(l)) return undefined;
|
||||
const offset = index[l - minLabel];
|
||||
return offset === -1 ? undefined : offset;
|
||||
this.getOffset = function getOffset(label: LabelType) {
|
||||
if (!Number.isInteger(label)) return -1;
|
||||
const lblIdx: number = <number>label - minLabel;
|
||||
if (lblIdx < 0 || lblIdx >= index.length) return -1;
|
||||
const offset = index[lblIdx];
|
||||
return offset;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
this.getOffsets = function getOffsets(arr: any) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
return arr.map((i: any) => this.getOffset(i));
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
this.getLabel = function getLabel(i: any) {
|
||||
return Number.isInteger(i) ? rindex[i] : undefined;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
this.getLabels = function getLabels(arr: any) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
return arr.map((i: any) => this.getLabel(i));
|
||||
this.getLabel = function getLabel(offset: number) {
|
||||
return Number.isInteger(offset) ? labels[offset] : undefined;
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
labels() {
|
||||
labels(): LabelArray {
|
||||
return this.rindex;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
size() {
|
||||
size(): number {
|
||||
return this.rindex.length;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
__promote(labelArray: any) {
|
||||
/** @internal */
|
||||
__promote(labelArray: LabelArray, allInts: boolean): LabelIndexBase {
|
||||
/*
|
||||
time/space decision - if we are going to use less than 10% of the
|
||||
dense index space, switch to a KeyIndex (which is slower, but uses
|
||||
less memory for sparse label spaces).
|
||||
*/
|
||||
const [minLabel, maxLabel] = extent(labelArray);
|
||||
const labelSpaceSize = maxLabel - minLabel + 1;
|
||||
const density = labelSpaceSize / this.rindex.length;
|
||||
/* 0.1 is a magic number, that needs testing to optimize */
|
||||
if (density < 0.1) {
|
||||
return new KeyIndex(labelArray);
|
||||
if (labelArray.length === 0) return new KeyIndex(Array.from(labelArray));
|
||||
if (allInts) {
|
||||
if (!(labelArray instanceof Int32Array)) {
|
||||
labelArray = new Int32Array(labelArray as number[]);
|
||||
}
|
||||
const [minLabel, maxLabel] = extent(
|
||||
labelArray as GenericLabelArray<number> // safe, as allInts is true
|
||||
);
|
||||
const labelSpaceSize = maxLabel - minLabel + 1;
|
||||
const density = labelSpaceSize / this.rindex.length;
|
||||
/* 0.1 is a magic number, that needs testing to optimize */
|
||||
if (density < 0.1) {
|
||||
return new KeyIndex(Array.from(labelArray));
|
||||
}
|
||||
return new DenseInt32Index(labelArray as GenericLabelArray<number>, [
|
||||
minLabel,
|
||||
maxLabel,
|
||||
]);
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number[]' is not assignable to p... Remove this comment to see the full error message
|
||||
return new DenseInt32Index(labelArray, [minLabel, maxLabel]);
|
||||
return new KeyIndex(Array.from(labelArray));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
subset(labels: any) {
|
||||
subset(labels: LabelArray): LabelIndexBase {
|
||||
/* validate subset */
|
||||
for (let i = 0, l = labels.length; i < l; i += 1) {
|
||||
const label = labels[i];
|
||||
const offset = this.getOffset(label);
|
||||
if (offset === undefined || offset === -1)
|
||||
throw new RangeError(`unknown label: ${label}`);
|
||||
const label = labels[i]; // if not a number, getOffset will error
|
||||
const offset = this.getOffset(label as number);
|
||||
if (offset === -1) throw new RangeError(`unknown label: ${label}`);
|
||||
}
|
||||
return this.__promote(labels);
|
||||
return this.__promote(labels as GenericLabelArray<number>, true);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
isubset(offsets: any) {
|
||||
isubset(offsets: OffsetArray): LabelIndexBase {
|
||||
/* validate subset */
|
||||
const { rindex } = this;
|
||||
const maxOffset = rindex.length;
|
||||
@@ -300,11 +311,10 @@ class DenseInt32Index {
|
||||
throw new RangeError(`out of bounds offset: ${offset}`);
|
||||
labels[i] = rindex[offset];
|
||||
}
|
||||
return this.__promote(labels);
|
||||
return this.__promote(labels, true);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
isubsetMask(mask: any) {
|
||||
isubsetMask(mask: Uint8Array | boolean[]): LabelIndexBase {
|
||||
const { rindex } = this;
|
||||
if (mask.length !== rindex.length)
|
||||
throw new RangeError("mask has invalid length for index");
|
||||
@@ -317,62 +327,55 @@ class DenseInt32Index {
|
||||
}
|
||||
}
|
||||
labels = labels.slice(0, count);
|
||||
return this.__promote(labels);
|
||||
return this.__promote(labels, true);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
withLabel(label: any) {
|
||||
return this.__promote([...this.labels(), label]);
|
||||
withLabel(label: LabelType): LabelIndexBase {
|
||||
return this.__promote([...this.labels(), label], Number.isInteger(label));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
withLabels(labels: any) {
|
||||
return this.__promote([...this.labels(), ...labels]);
|
||||
withLabels(labels: LabelArray): LabelIndexBase {
|
||||
return this.__promote(
|
||||
[...this.labels(), ...labels],
|
||||
labels.every(Number.isInteger)
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
dropLabel(label: any) {
|
||||
dropLabel(label: LabelType): LabelIndexBase {
|
||||
if (!Number.isInteger(label)) throw new RangeError("Invalid label.");
|
||||
const labelArray = [...this.labels()];
|
||||
labelArray.splice(labelArray.indexOf(label), 1);
|
||||
return this.__promote(labelArray);
|
||||
labelArray.splice(labelArray.indexOf(label as number), 1);
|
||||
return this.__promote(
|
||||
new Int32Array(labelArray as GenericLabelArray<number>),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class KeyIndex {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
__id: any;
|
||||
export class KeyIndex extends LabelIndexBase {
|
||||
getLabel: (offset: number) => LabelType | undefined;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
getLabel: any;
|
||||
getOffset: (label: LabelType) => number | -1;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
getLabels: any;
|
||||
index: Map<string | number, number>;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
getOffset: any;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
getOffsets: any;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
index: any;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
rindex: any;
|
||||
rindex: (string | number)[];
|
||||
|
||||
/*
|
||||
KeyIndex indexes arbitrary JS primitive types, and uses a Map()
|
||||
as its core data structure.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
constructor(labels: any) {
|
||||
const index = new Map();
|
||||
constructor(labels: Array<string | number>) {
|
||||
super(__getMemoId());
|
||||
const index = new Map<string | number, number>();
|
||||
if (labels === undefined) {
|
||||
labels = [];
|
||||
}
|
||||
if (!Array.isArray(labels)) {
|
||||
labels = Array.from(labels);
|
||||
}
|
||||
const rindex = labels;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
labels.forEach((v: any, i: any) => {
|
||||
labels.forEach((v, i) => {
|
||||
index.set(v, i);
|
||||
});
|
||||
|
||||
@@ -383,48 +386,27 @@ class KeyIndex {
|
||||
|
||||
this.index = index;
|
||||
this.rindex = rindex;
|
||||
this.__id = __getMemoId();
|
||||
this.__compile();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
__compile() {
|
||||
const { index, rindex } = this;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
this.getOffset = function getOffset(k: any) {
|
||||
return index.get(k);
|
||||
this.getOffset = function getOffset(label: LabelType) {
|
||||
const offset = index.get(label);
|
||||
if (offset === undefined) return -1;
|
||||
return offset;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
this.getOffsets = function getOffsets(arr: any) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
return arr.map((l: any) => this.getOffset(l));
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
this.getLabel = function getLabel(i: any) {
|
||||
return Number.isInteger(i) ? rindex[i] : undefined;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
this.getLabels = function getLabels(arr: any) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
return arr.map((i: any) => this.getLabel(i));
|
||||
this.getLabel = function getLabel(offset: number) {
|
||||
return Number.isInteger(offset) ? rindex[offset] : undefined;
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
labels() {
|
||||
labels(): LabelArray {
|
||||
return this.rindex;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
size() {
|
||||
size(): number {
|
||||
return this.rindex.length;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
subset(labels: any) {
|
||||
subset(labels: (string | number)[]): LabelIndexBase {
|
||||
/* validate subset */
|
||||
for (let i = 0, l = labels.length; i < l; i += 1) {
|
||||
const label = labels[i];
|
||||
@@ -437,8 +419,7 @@ class KeyIndex {
|
||||
return new KeyIndex(labels);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
isubset(offsets: any) {
|
||||
isubset(offsets: OffsetArray): LabelIndexBase {
|
||||
const { rindex } = this;
|
||||
const maxOffset = rindex.length;
|
||||
const labels = new Array(offsets.length);
|
||||
@@ -452,8 +433,7 @@ class KeyIndex {
|
||||
return new KeyIndex(labels);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
isubsetMask(mask: any) {
|
||||
isubsetMask(mask: Uint8Array | boolean[]): LabelIndexBase {
|
||||
const { rindex } = this;
|
||||
if (mask.length !== rindex.length)
|
||||
throw new RangeError("mask has invalid length for index");
|
||||
@@ -469,18 +449,15 @@ class KeyIndex {
|
||||
return new KeyIndex(labels);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
withLabel(label: any) {
|
||||
withLabel(label: LabelType): LabelIndexBase {
|
||||
return new KeyIndex([...this.rindex, label]);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
withLabels(labels: any) {
|
||||
withLabels(labels: LabelArray): LabelIndexBase {
|
||||
return new KeyIndex([...this.rindex, ...labels]);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
dropLabel(label: any) {
|
||||
dropLabel(label: LabelType): LabelIndexBase {
|
||||
const idx = this.rindex.indexOf(label);
|
||||
const labelArray = [...this.rindex];
|
||||
labelArray.splice(idx, 1);
|
||||
@@ -488,14 +465,31 @@ class KeyIndex {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
function isLabelIndex(i: any) {
|
||||
export type LabelIndex = LabelIndexBase;
|
||||
|
||||
export function isLabelIndex(i: unknown): i is LabelIndex {
|
||||
return (
|
||||
i instanceof LabelIndexBase ||
|
||||
i instanceof IdentityInt32Index ||
|
||||
i instanceof DenseInt32Index ||
|
||||
i instanceof KeyIndex
|
||||
);
|
||||
}
|
||||
|
||||
export { DenseInt32Index, IdentityInt32Index, KeyIndex, isLabelIndex };
|
||||
/** @internal */
|
||||
function extent(tarr: GenericLabelArray<number>): [number, number] {
|
||||
let min = 0x7fffffff;
|
||||
let max = ~min; // eslint-disable-line no-bitwise -- Establishes 0 of same size
|
||||
for (let i = 0, l = tarr.length; i < l; i += 1) {
|
||||
const v = tarr[i];
|
||||
if (v < min) {
|
||||
min = v;
|
||||
}
|
||||
if (v > max) {
|
||||
max = v;
|
||||
}
|
||||
}
|
||||
return [min, max];
|
||||
}
|
||||
|
||||
/* eslint-enable max-classes-per-file -- enable*/
|
||||
|
||||
@@ -5,55 +5,56 @@ TODO / XXX: for scalar/continuous data, this uses a naive method
|
||||
of computing quantiles. Would be good to switch from sort to
|
||||
partition at some point.
|
||||
*/
|
||||
|
||||
import {
|
||||
AnyArray,
|
||||
GenericArrayConstructor,
|
||||
} from "../../common/types/arraytypes";
|
||||
import { ContinuousColumnSummary, CategoricalColumnSummary } from "./types";
|
||||
import quantile from "../quantile";
|
||||
import { sortArray } from "../typedCrossfilter/sort";
|
||||
|
||||
// [ 0, 0.01, 0.02, ..., 1.0]
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'v' is declared but its value is never read.
|
||||
const centileNames = new Array(101).fill(0).map((v, idx) => idx / 100);
|
||||
const centileNames = new Array(101).fill(0).map((_v, idx) => idx / 100);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function summarizeContinuous(col: any) {
|
||||
let min;
|
||||
let max;
|
||||
export function summarizeContinuous(col: AnyArray): ContinuousColumnSummary {
|
||||
let nan = 0;
|
||||
let pinf = 0;
|
||||
let ninf = 0;
|
||||
let percentiles;
|
||||
if (col) {
|
||||
// -Inf < finite < Inf < NaN
|
||||
const sortedCol = sortArray(new col.constructor(col));
|
||||
|
||||
// count non-finites, which are at each end of sorted data
|
||||
for (let i = sortedCol.length - 1; i >= 0; i -= 1) {
|
||||
if (!Number.isNaN(sortedCol[i])) {
|
||||
nan = sortedCol.length - i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let i = 0, l = sortedCol.length; i < l; i += 1) {
|
||||
if (sortedCol[i] !== Number.NEGATIVE_INFINITY) {
|
||||
ninf = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let i = sortedCol.length - nan - 1; i >= 0; i -= 1) {
|
||||
if (sortedCol[i] !== Number.POSITIVE_INFINITY) {
|
||||
pinf = sortedCol.length - i - nan - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// -Inf < finite < Inf < NaN
|
||||
const sortedCol = sortArray(
|
||||
new (col.constructor as GenericArrayConstructor<typeof col>)(col)
|
||||
);
|
||||
|
||||
// compute percentiles on finite data ONLY
|
||||
const sortedColFiniteOnly = sortedCol.slice(
|
||||
ninf,
|
||||
sortedCol.length - nan - pinf
|
||||
);
|
||||
percentiles = quantile(centileNames, sortedColFiniteOnly, true);
|
||||
min = percentiles[0];
|
||||
max = percentiles[100];
|
||||
// count non-finites, which are at each end of sorted data
|
||||
for (let i = sortedCol.length - 1; i >= 0; i -= 1) {
|
||||
if (!Number.isNaN(sortedCol[i])) {
|
||||
nan = sortedCol.length - i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let i = 0, l = sortedCol.length; i < l; i += 1) {
|
||||
if (sortedCol[i] !== Number.NEGATIVE_INFINITY) {
|
||||
ninf = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let i = sortedCol.length - nan - 1; i >= 0; i -= 1) {
|
||||
if (sortedCol[i] !== Number.POSITIVE_INFINITY) {
|
||||
pinf = sortedCol.length - i - nan - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// compute percentiles on finite data ONLY
|
||||
const sortedColFiniteOnly = sortedCol.slice(
|
||||
ninf,
|
||||
sortedCol.length - nan - pinf
|
||||
);
|
||||
const percentiles = quantile(centileNames, sortedColFiniteOnly, true);
|
||||
const min = percentiles[0];
|
||||
const max = percentiles[100];
|
||||
|
||||
return {
|
||||
categorical: false,
|
||||
min,
|
||||
@@ -65,8 +66,7 @@ export function summarizeContinuous(col: any) {
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function summarizeCategorical(col: any) {
|
||||
export function summarizeCategorical(col: AnyArray): CategoricalColumnSummary {
|
||||
const categoryCounts = new Map();
|
||||
if (col) {
|
||||
for (let r = 0, l = col.length; r < l; r += 1) {
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
import { TypedArray } from "../../common/types/arraytypes";
|
||||
|
||||
export type LabelType = number | string;
|
||||
|
||||
type CommonProps<A, B> = {
|
||||
[K in keyof A & keyof B]: A[K] | B[K];
|
||||
};
|
||||
export type GenericLabelArray<T> = CommonProps<Array<T>, Int32Array>;
|
||||
export type LabelArray = GenericLabelArray<number | string>;
|
||||
|
||||
export type OffsetType = number;
|
||||
export type OffsetArray =
|
||||
| Int8Array
|
||||
| Uint8Array
|
||||
| Int16Array
|
||||
| Uint16Array
|
||||
| Int32Array
|
||||
| Uint32Array
|
||||
| number[];
|
||||
|
||||
export type ContinuousColumnSummary = {
|
||||
categorical: false;
|
||||
min: number;
|
||||
max: number;
|
||||
nan: number;
|
||||
pinf: number;
|
||||
ninf: number;
|
||||
percentiles: number[];
|
||||
};
|
||||
|
||||
export type CategoricalColumnSummary = {
|
||||
categorical: true;
|
||||
categories: (number | string | boolean)[];
|
||||
categoryCounts: Map<number | string | boolean, number>;
|
||||
numCategories: number;
|
||||
};
|
||||
|
||||
export type ColumnSummary = ContinuousColumnSummary | CategoricalColumnSummary;
|
||||
|
||||
export type ContinuousHistogram = number[];
|
||||
export type ContinuousHistogramBy = Map<DataframeValue, ContinuousHistogram>;
|
||||
export type CategoricalHistogram = Map<DataframeValue, number>;
|
||||
export type CategoricalHistogramBy = Map<DataframeValue, CategoricalHistogram>;
|
||||
|
||||
export type DataframeValue = number | string | boolean;
|
||||
|
||||
export type DataframeValueArray = DataframeValue[] | TypedArray;
|
||||
|
||||
export type DataframeColumnGetter = (
|
||||
label: LabelType
|
||||
) => DataframeValue | undefined;
|
||||
|
||||
/**
|
||||
* Interface representing a Dataframe column. Eg, returned by
|
||||
* Dataframe.col().
|
||||
*/
|
||||
export interface DataframeColumn extends DataframeColumnGetter {
|
||||
/**
|
||||
* __id is unique per Dataframe and DataframeColumn, and is used as a memoization key.
|
||||
*/
|
||||
readonly __id: string;
|
||||
|
||||
/**
|
||||
* Boolean indicating if the underlying data supports continuous operations, eg,
|
||||
* summarizeContinuous.
|
||||
*/
|
||||
isContinuous: boolean;
|
||||
|
||||
/**
|
||||
* Return underlying column data as an array-like object.
|
||||
*/
|
||||
asArray: () => DataframeValueArray;
|
||||
|
||||
/**
|
||||
* Continuous data summary. Will throw if !isContinuous.
|
||||
*/
|
||||
summarizeContinuous: () => ContinuousColumnSummary;
|
||||
|
||||
/**
|
||||
* Categorical data summary.
|
||||
*/
|
||||
summarizeCategorical: () => CategoricalColumnSummary;
|
||||
|
||||
/**
|
||||
* Continuous bin/histogram. Will throw if !isContinuous.
|
||||
* @param bins - array of bin boundary fractions, in range [0., 1.]
|
||||
* @param domain - data domain [min, max]
|
||||
*/
|
||||
histogramContinuous: (
|
||||
bins: number,
|
||||
domain: [number, number]
|
||||
) => ContinuousHistogram;
|
||||
|
||||
/**
|
||||
* Continuous bin/histogram, grouped by another categorical column. Will throw if !isContinuous.
|
||||
* @param bins - array of bin boundary fractions, in range [0., 1.]
|
||||
* @param domain - data domain [min, max]
|
||||
* @param by - group by categorical column
|
||||
*/
|
||||
histogramContinuousBy: (
|
||||
bins: number,
|
||||
domain: [number, number],
|
||||
by: DataframeColumn
|
||||
) => ContinuousHistogramBy;
|
||||
|
||||
/**
|
||||
* Categorical bin/histogram.
|
||||
*/
|
||||
histogramCategorical: () => CategoricalHistogram;
|
||||
|
||||
/**
|
||||
* Categorical bin/histogram grouped by another column.
|
||||
* @param by - group by categorical column
|
||||
*/
|
||||
histogramCategoricalBy: (by: DataframeColumn) => CategoricalHistogramBy;
|
||||
|
||||
/**
|
||||
* Return true if the column contains the row label.
|
||||
*/
|
||||
has: (rlabel: LabelType) => boolean;
|
||||
|
||||
/**
|
||||
* Return true if the column contains the row offset. Identical to
|
||||
* (offset >= 0 && offset < dataframe.length)
|
||||
*/
|
||||
ihas: (offset: OffsetType) => boolean;
|
||||
|
||||
/**
|
||||
* Return index of the value, as a _label_. Returns undefined if
|
||||
* not present. *NOTE*: unlike Array.indexOf, does not return an
|
||||
* offset.
|
||||
*/
|
||||
indexOf: (value: DataframeValue) => LabelType | undefined;
|
||||
|
||||
/**
|
||||
* Return the value at the given offset, or undefined if not present.
|
||||
*/
|
||||
iget: (offset: OffsetType) => DataframeValue | undefined;
|
||||
}
|
||||
@@ -2,19 +2,19 @@
|
||||
Private utility code for dataframe
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function callOnceLazy(f: any) {
|
||||
export function callOnceLazy<
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- a legitimate use of any.
|
||||
T extends (...args: any[]) => any = (...args: any[]) => any
|
||||
>(fn: T): (...args: Parameters<T>) => ReturnType<T> {
|
||||
/*
|
||||
call function once, and save the result, regardless of arguments (this is not
|
||||
the same as typical memoization).
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
let value: any;
|
||||
let value: ReturnType<T>;
|
||||
let calledOnce = false;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const result = function result(...args: any[]) {
|
||||
const result = function result(...args: Parameters<T>): ReturnType<T> {
|
||||
if (!calledOnce) {
|
||||
value = f(...args);
|
||||
value = fn(...args);
|
||||
calledOnce = true;
|
||||
}
|
||||
return value;
|
||||
@@ -22,8 +22,14 @@ export function callOnceLazy(f: any) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function memoize(fn: any, hashFn: any, maxResultsCached = -1) {
|
||||
export function memoize<
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- a legitimate use of any.
|
||||
T extends (...args: any[]) => any = (...args: any[]) => any
|
||||
>(
|
||||
fn: T,
|
||||
hashFn: (...args: Parameters<T>) => string,
|
||||
maxResultsCached = -1
|
||||
): (...args: Parameters<T>) => ReturnType<T> {
|
||||
/*
|
||||
function memoization, with user-provided hash. hashFn must return a
|
||||
key which will be unique as a Map key (ie, obeys "sameValueZero" algorithm
|
||||
@@ -31,8 +37,7 @@ export function memoize(fn: any, hashFn: any, maxResultsCached = -1) {
|
||||
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Key_equality
|
||||
*/
|
||||
const cache = new Map();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const wrap = function wrap(...args: any[]) {
|
||||
const wrap = function wrap(...args: Parameters<T>): ReturnType<T> {
|
||||
const key = hashFn(...args);
|
||||
if (cache.has(key)) {
|
||||
return cache.get(key);
|
||||
@@ -57,12 +62,11 @@ export function memoize(fn: any, hashFn: any, maxResultsCached = -1) {
|
||||
}
|
||||
|
||||
/**
|
||||
memoization helpers - just a global counter.
|
||||
**/
|
||||
*memoization helpers - just a global counter.
|
||||
*/
|
||||
let __DataframeMemoId__ = 0;
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
export function __getMemoId() {
|
||||
export function __getMemoId(): string {
|
||||
const id = __DataframeMemoId__;
|
||||
__DataframeMemoId__ += 1;
|
||||
return id;
|
||||
return id.toString();
|
||||
}
|
||||
|
||||
@@ -12,17 +12,26 @@ Arguments:
|
||||
|
||||
*/
|
||||
|
||||
import { NumberArray, TypedArrayConstructor } from "../common/types/arraytypes";
|
||||
|
||||
import { sortArray } from "./typedCrossfilter/sort";
|
||||
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'quantArr' implicitly has an 'any' type.
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
export default function quantile(quantArr, tarr, sorted = false) {
|
||||
export default function quantile(
|
||||
quantArr: number[],
|
||||
tarr: NumberArray,
|
||||
sorted = false
|
||||
): number[] {
|
||||
/*
|
||||
start with the naive (sort) implementation. Later, use a faster partition
|
||||
*/
|
||||
const arr = sorted ? tarr : sortArray(new tarr.constructor(tarr)); // copy
|
||||
|
||||
if (tarr.length === 0) {
|
||||
return new Array(quantArr.length).fill(0);
|
||||
}
|
||||
|
||||
const Ctor: TypedArrayConstructor = tarr.constructor as TypedArrayConstructor;
|
||||
const arr = sorted ? tarr : sortArray(new Ctor(tarr)); // copy
|
||||
const len = arr.length;
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'q' implicitly has an 'any' type.
|
||||
return quantArr.map((q) => {
|
||||
if (q === 1) {
|
||||
return arr[len - 1];
|
||||
|
||||
@@ -4,6 +4,7 @@ See also reducers/annotations.js
|
||||
*/
|
||||
|
||||
import { Schema } from "../../common/types/schema";
|
||||
import { Dataframe, LabelType } from "../dataframe";
|
||||
|
||||
/*
|
||||
There are a number of state constraints assumed throughout the
|
||||
@@ -57,9 +58,12 @@ export function isUserAnnotation(annoMatrix, name) {
|
||||
return _isUserAnnotation(annoMatrix.schema, name);
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'df' implicitly has an 'any' type.
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
export function allHaveLabelByMask(df, colName, label, mask) {
|
||||
export function allHaveLabelByMask(
|
||||
df: Dataframe,
|
||||
colName: LabelType,
|
||||
label: string,
|
||||
mask: Uint8Array
|
||||
): boolean {
|
||||
// return true if all rows as indicated by mask have the colname set to label.
|
||||
// False if not.
|
||||
const col = df.col(colName);
|
||||
|
||||
@@ -7,6 +7,7 @@ import memoize from "memoize-one";
|
||||
import * as globals from "../../globals";
|
||||
import parseRGB from "../parseRGB";
|
||||
import { range } from "../range";
|
||||
import { Dataframe, LabelType } from "../dataframe";
|
||||
|
||||
/*
|
||||
given a color mode & accessor, generate an annoMatrix query that will
|
||||
@@ -95,18 +96,19 @@ Returns:
|
||||
}
|
||||
*/
|
||||
function _createColorTable(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
colorMode: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
colorByAccessor: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
colorByData: any,
|
||||
colorMode: string | null,
|
||||
colorByAccessor: LabelType | null,
|
||||
colorByData: Dataframe | null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
schema: any,
|
||||
userColors = null
|
||||
) {
|
||||
if (colorMode === null || colorByData === null)
|
||||
return defaultColors(schema.dataframe.nObs);
|
||||
|
||||
switch (colorMode) {
|
||||
case "color by categorical metadata": {
|
||||
if (colorByAccessor === null) return defaultColors(schema.dataframe.nObs);
|
||||
const data = colorByData.col(colorByAccessor).asArray();
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
if (userColors && colorByAccessor in userColors) {
|
||||
@@ -115,18 +117,19 @@ function _createColorTable(
|
||||
return createColorsByCategoricalMetadata(data, colorByAccessor, schema);
|
||||
}
|
||||
case "color by continuous metadata": {
|
||||
if (colorByAccessor === null) return defaultColors(schema.dataframe.nObs);
|
||||
const col = colorByData.col(colorByAccessor);
|
||||
const { min, max } = col.summarize();
|
||||
const { min, max } = col.summarizeContinuous();
|
||||
return createColorsByContinuousMetadata(col.asArray(), min, max);
|
||||
}
|
||||
case "color by expression": {
|
||||
const col = colorByData.icol(0);
|
||||
const { min, max } = col.summarize();
|
||||
const { min, max } = col.summarizeContinuous();
|
||||
return createColorsByContinuousMetadata(col.asArray(), min, max);
|
||||
}
|
||||
case "color by geneset mean expression": {
|
||||
const col = colorByData.icol(0);
|
||||
const { min, max } = col.summarize();
|
||||
const { min, max } = col.summarizeContinuous();
|
||||
return createColorsByContinuousMetadata(col.asArray(), min, max);
|
||||
}
|
||||
default: {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { flatbuffers } from "flatbuffers";
|
||||
import { NetEncoding } from "./matrix_generated";
|
||||
import { isTypedArray, isFloatTypedArray } from "../../common/types/arraytypes";
|
||||
import {
|
||||
TypedArray,
|
||||
isTypedArray,
|
||||
isFloatTypedArray,
|
||||
} from "../../common/types/arraytypes";
|
||||
import {
|
||||
Dataframe,
|
||||
IdentityInt32Index,
|
||||
@@ -94,14 +98,13 @@ function encodeTypedArray(builder: any, uType: any, uData: any) {
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function encodeMatrixFBS(df: any) {
|
||||
export function encodeMatrixFBS(df: Dataframe): Uint8Array {
|
||||
/*
|
||||
encode the dataframe as an FBS Matrix
|
||||
*/
|
||||
|
||||
/* row indexing not supported currently */
|
||||
if (df.rowIndex.constructor !== IdentityInt32Index) {
|
||||
if (!(df.rowIndex instanceof IdentityInt32Index)) {
|
||||
throw new Error("FBS does not support row index encoding at this time");
|
||||
}
|
||||
|
||||
@@ -115,11 +118,9 @@ export function encodeMatrixFBS(df: any) {
|
||||
let encColumns;
|
||||
|
||||
if (shape[0] > 0 && shape[1] > 0) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const columns = df.columns().map((col: any) => col.asArray());
|
||||
const columns = df.columns().map((col) => col.asArray());
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const cols = columns.map((carr: any) => {
|
||||
const cols = columns.map((carr) => {
|
||||
let uType;
|
||||
let tarr;
|
||||
if (isTypedArray(carr)) {
|
||||
@@ -179,8 +180,7 @@ export function encodeMatrixFBS(df: any) {
|
||||
return builder.asUint8Array();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
function promoteTypedArray(o: any) {
|
||||
function promoteTypedArray(o: TypedArray) {
|
||||
/*
|
||||
Decide what internal data type to use for the data returned from
|
||||
the server.
|
||||
@@ -212,8 +212,9 @@ function promoteTypedArray(o: any) {
|
||||
return new TypedArrayCtor(o);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- - FIXME: disabled temporarily on migrate to TS.
|
||||
export function matrixFBSToDataframe(arrayBuffers: any) {
|
||||
export function matrixFBSToDataframe(
|
||||
arrayBuffers: ArrayBuffer | ArrayBuffer[]
|
||||
): Dataframe {
|
||||
/*
|
||||
Convert array of Matrix FBS to a Dataframe.
|
||||
|
||||
@@ -229,37 +230,30 @@ export function matrixFBSToDataframe(arrayBuffers: any) {
|
||||
arrayBuffers = [arrayBuffers];
|
||||
}
|
||||
if (arrayBuffers.length === 0) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
return (Dataframe as any).Dataframe.empty();
|
||||
return Dataframe.empty();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
const fbs = arrayBuffers.map((ab: any) => decodeMatrixFBS(ab, true)); // leave in place
|
||||
const fbs = arrayBuffers.map((ab) => decodeMatrixFBS(ab, true)); // leave in place
|
||||
/* check that all FBS have same row dimensionality */
|
||||
const { nRows } = fbs[0];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
fbs.forEach((b: any) => {
|
||||
fbs.forEach((b) => {
|
||||
if (b.nRows !== nRows)
|
||||
throw new Error("FBS with inconsistent dimensionality");
|
||||
});
|
||||
const columns = fbs // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.map((fb: any) =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
fb.columns.map((c: any) => {
|
||||
const columns = fbs
|
||||
.map((fb) =>
|
||||
fb.columns.map((c) => {
|
||||
if (isFloatTypedArray(c) || Array.isArray(c)) return c;
|
||||
return promoteTypedArray(c);
|
||||
})
|
||||
)
|
||||
.flat();
|
||||
// colIdx may be TypedArray or Array
|
||||
const colIdx = fbs // eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
.map((b: any) =>
|
||||
Array.isArray(b.colIdx) ? b.colIdx : Array.from(b.colIdx)
|
||||
)
|
||||
const colIdx = fbs
|
||||
.map((b) => (Array.isArray(b.colIdx) ? b.colIdx : Array.from(b.colIdx)))
|
||||
.flat();
|
||||
const nCols = columns.length;
|
||||
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'KeyIndex' is not assignable to p... Remove this comment to see the full error message
|
||||
const df = new Dataframe([nRows, nCols], columns, null, new KeyIndex(colIdx));
|
||||
return df;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ Views can be interogated for their type with the following:
|
||||
|
||||
import { clip, isubsetMask, isubset } from "../../annoMatrix";
|
||||
import { memoize } from "../dataframe/util";
|
||||
import { Dataframe, LabelIndex } from "../dataframe";
|
||||
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'annoMatrix' implicitly has an 'any' typ... Remove this comment to see the full error message
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
@@ -101,7 +102,7 @@ export function _userResetSubsetAnnoMatrix(annoMatrix) {
|
||||
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'annoMatrix' implicitly has an 'any' typ... Remove this comment to see the full error message
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
export function _setEmbeddingSubset(annoMatrix, embeddingDf) {
|
||||
export function _setEmbeddingSubset(annoMatrix, embeddingDf: Dataframe) {
|
||||
/*
|
||||
Set the embedding subset view. Only create a subset view for the embedding
|
||||
when it is needed, ie, there are NaN values in the embeddings.
|
||||
@@ -141,8 +142,10 @@ export function _setEmbeddingSubset(annoMatrix, embeddingDf) {
|
||||
return annoMatrix;
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(6133) FIXME: 'baseRowIndex' is declared but its value is never ... Remove this comment to see the full error message
|
||||
function _getEmbeddingRowOffsets(baseRowIndex, embeddingDf) {
|
||||
function _getEmbeddingRowOffsets(
|
||||
_baseRowIndex: LabelIndex,
|
||||
embeddingDf: Dataframe
|
||||
) {
|
||||
/*
|
||||
given a dataframe containing an embedding:
|
||||
- if the embedding contains no NaN coordinates, return null
|
||||
@@ -167,17 +170,16 @@ function _getEmbeddingRowOffsets(baseRowIndex, embeddingDf) {
|
||||
return offsets.subarray(0, numOffsets);
|
||||
}
|
||||
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'embeddingDf' implicitly has an 'any' ty... Remove this comment to see the full error message
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
export function _getDiscreteCellEmbeddingRowIndex(embeddingDf) {
|
||||
export function _getDiscreteCellEmbeddingRowIndex(
|
||||
embeddingDf: Dataframe
|
||||
): LabelIndex {
|
||||
const idx = _getEmbeddingRowOffsets(embeddingDf.rowIndex, embeddingDf);
|
||||
if (idx === null) return embeddingDf.rowIndex;
|
||||
return embeddingDf.rowIndex.isubset(idx);
|
||||
}
|
||||
export const getDiscreteCellEmbeddingRowIndex = memoize(
|
||||
_getDiscreteCellEmbeddingRowIndex,
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'df' implicitly has an 'any' type.
|
||||
(df) => df.__id
|
||||
(df: Dataframe) => df.__id
|
||||
);
|
||||
|
||||
// @ts-expect-error ts-migrate(7006) FIXME: Parameter 'annoMatrix' implicitly has an 'any' typ... Remove this comment to see the full error message
|
||||
|
||||
@@ -12,9 +12,8 @@ import { makeSortIndex } from "./util";
|
||||
import { isAnyArray } from "../../common/types/arraytypes";
|
||||
|
||||
class NotImplementedError extends Error {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||
constructor(...params: any[]) {
|
||||
super(...params);
|
||||
constructor(msg: string) {
|
||||
super(msg);
|
||||
|
||||
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
||||
if (Error.captureStackTrace) {
|
||||
@@ -63,8 +62,7 @@ export default class ImmutableTypedCrossfilter {
|
||||
Object.preventExtensions(this);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||
size() {
|
||||
size(): number {
|
||||
return this.data.length;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user