spatialquery.js 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +138 -2
- package/dist/assert.d.ts +15 -0
- package/dist/assert.d.ts.map +1 -0
- package/dist/assert.js +23 -0
- package/dist/assert.js.map +1 -0
- package/dist/fpgrowth.d.ts +10 -0
- package/dist/fpgrowth.d.ts.map +1 -0
- package/dist/fpgrowth.js +35 -0
- package/dist/fpgrowth.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/multi-fov.d.ts +115 -0
- package/dist/multi-fov.d.ts.map +1 -0
- package/dist/multi-fov.js +325 -0
- package/dist/multi-fov.js.map +1 -0
- package/dist/nested.d.ts +17 -0
- package/dist/nested.d.ts.map +1 -0
- package/dist/nested.js +106 -0
- package/dist/nested.js.map +1 -0
- package/dist/single-fov.d.ts +149 -0
- package/dist/single-fov.d.ts.map +1 -0
- package/dist/single-fov.js +488 -0
- package/dist/single-fov.js.map +1 -0
- package/dist/stats.d.ts +25 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +141 -0
- package/dist/stats.js.map +1 -0
- package/package.json +35 -3
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
// Port of the multi-FOV class spatial_query_multi.
|
|
2
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py
|
|
3
|
+
import { buildContext, findCellIndicesOfType, knnTransactions, radiusTransactions, centerQueryPoints, knnNeighborhood, radiusNeighborhood, countMotifs, computeMotifEnrichment, normalizeMotifs, normalizeMotifList, motifCompositionRows, assertEnrichmentMode, findFpKnn as findFpKnnSingle, findFpDist as findFpDistSingle, } from './single-fov.js';
|
|
4
|
+
import { mineFrequentPatterns } from './fpgrowth.js';
|
|
5
|
+
import { nestedMotifDescent } from './nested.js';
|
|
6
|
+
import { applyFdrCorrection, fdrCorrection, mannWhitneyU, rankAverage, median, mean } from './stats.js';
|
|
7
|
+
// Build the multi-FOV context object.
|
|
8
|
+
// Unlike Python, which derives unique FOV names from the (possibly repeated) dataset names
|
|
9
|
+
// ('name' -> 'name_0', 'name_1', ...), each FOV has an explicit ID and class.
|
|
10
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L43
|
|
11
|
+
export function buildMultiContext(fovs) {
|
|
12
|
+
const datasetIds = fovs.map(fov => fov.datasetId);
|
|
13
|
+
const duplicates = datasetIds.filter((id, i) => datasetIds.indexOf(id) !== i);
|
|
14
|
+
if (duplicates.length > 0) {
|
|
15
|
+
throw new Error(`Dataset IDs must be unique. Found duplicates: ${Array.from(new Set(duplicates)).join(', ')}`);
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
datasetIds,
|
|
19
|
+
datasetClasses: fovs.map(fov => fov.datasetClass),
|
|
20
|
+
contexts: fovs.map(fov => buildContext(fov)),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
// The datasets (FOVs) belonging to the selected classes (all classes if not provided).
|
|
24
|
+
function selectFovs(multi, datasetClass) {
|
|
25
|
+
const validClasses = new Set(multi.datasetClasses);
|
|
26
|
+
const selected = datasetClass === undefined
|
|
27
|
+
? validClasses
|
|
28
|
+
: new Set(typeof datasetClass === 'string' ? [datasetClass] : datasetClass);
|
|
29
|
+
for (const c of selected) {
|
|
30
|
+
if (!validClasses.has(c)) {
|
|
31
|
+
throw new Error(`Invalid dataset class: ${c}. Valid dataset classes are: ${Array.from(validClasses).join(', ')}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return multi.contexts
|
|
35
|
+
.map((context, i) => ({ datasetId: multi.datasetIds[i], datasetClass: multi.datasetClasses[i], context }))
|
|
36
|
+
.filter(fov => selected.has(fov.datasetClass));
|
|
37
|
+
}
|
|
38
|
+
// Throws if the cell type is absent from every FOV (selected or not, as in Python).
|
|
39
|
+
function assertCellTypeInAnyFov(multi, ct) {
|
|
40
|
+
if (!multi.contexts.some(context => context.labels.includes(ct))) {
|
|
41
|
+
throw new Error(`Found no ${ct} in any datasets!`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Unique cell type labels across all FOVs.
|
|
45
|
+
function allLabels(multi) {
|
|
46
|
+
return new Set(multi.contexts.flatMap(context => context.labels));
|
|
47
|
+
}
|
|
48
|
+
// Find frequent patterns within the k-NN neighborhoods of a cell type, pooling the
|
|
49
|
+
// neighborhoods of all selected FOVs.
|
|
50
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L116
|
|
51
|
+
export async function multiFindFpKnn(multi, params) {
|
|
52
|
+
const { ct, datasetClass, k = 30, minSupport = 0.5, maxDist = 20, ifMax = true } = params;
|
|
53
|
+
assertCellTypeInAnyFov(multi, ct);
|
|
54
|
+
const transactions = selectFovs(multi, datasetClass).flatMap(({ context }) => (knnTransactions(context, findCellIndicesOfType(context, ct), k, maxDist)));
|
|
55
|
+
return mineFrequentPatterns(transactions, minSupport, ifMax);
|
|
56
|
+
}
|
|
57
|
+
// Find frequent patterns within the radius-based neighborhoods of a cell type, pooling the
|
|
58
|
+
// neighborhoods of all selected FOVs.
|
|
59
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L219
|
|
60
|
+
export async function multiFindFpDist(multi, params) {
|
|
61
|
+
const { ct, datasetClass, maxDist = 20, minSize = 0, minSupport = 0.5, ifMax = true } = params;
|
|
62
|
+
assertCellTypeInAnyFov(multi, ct);
|
|
63
|
+
const transactions = selectFovs(multi, datasetClass).flatMap(({ context }) => {
|
|
64
|
+
const points = centerQueryPoints(context, findCellIndicesOfType(context, ct));
|
|
65
|
+
return radiusTransactions(context, points, maxDist, minSize).transactions;
|
|
66
|
+
});
|
|
67
|
+
return mineFrequentPatterns(transactions, minSupport, ifMax);
|
|
68
|
+
}
|
|
69
|
+
function getFov(multi, datasetId) {
|
|
70
|
+
const index = multi.datasetIds.indexOf(datasetId);
|
|
71
|
+
if (index === -1) {
|
|
72
|
+
throw new Error(`Found no dataset with ID ${datasetId}.`);
|
|
73
|
+
}
|
|
74
|
+
return multi.contexts[index];
|
|
75
|
+
}
|
|
76
|
+
// Find frequent (maximal) patterns within the k-NN neighborhoods of a cell type in a single FOV.
|
|
77
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L993
|
|
78
|
+
export async function findFpKnnFov(multi, params) {
|
|
79
|
+
const { ct, datasetId, k = 30, minSupport = 0.5, maxDist = 20 } = params;
|
|
80
|
+
const context = getFov(multi, datasetId);
|
|
81
|
+
if (!context.labels.includes(ct))
|
|
82
|
+
return [];
|
|
83
|
+
return findFpKnnSingle(context, { ct, k, minSupport, maxDist });
|
|
84
|
+
}
|
|
85
|
+
// Find frequent (maximal) patterns within the radius-based neighborhoods of a cell type in a single FOV.
|
|
86
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L1049
|
|
87
|
+
export async function findFpDistFov(multi, params) {
|
|
88
|
+
const { ct, datasetId, maxDist = 20, minSize = 0, minSupport = 0.5 } = params;
|
|
89
|
+
const context = getFov(multi, datasetId);
|
|
90
|
+
if (!context.labels.includes(ct))
|
|
91
|
+
return [];
|
|
92
|
+
return findFpDistSingle(context, { ct, maxDist, minSize, minSupport });
|
|
93
|
+
}
|
|
94
|
+
// Normalize user-specified motifs against the labels of all FOVs, throwing if none remain.
|
|
95
|
+
function normalizeMultiMotifs(multi, motifs) {
|
|
96
|
+
const filtered = normalizeMotifs(motifs, allLabels(multi));
|
|
97
|
+
if (filtered.length === 0) {
|
|
98
|
+
throw new Error("All cell types in motifs are missing in the cell type labels.");
|
|
99
|
+
}
|
|
100
|
+
return filtered;
|
|
101
|
+
}
|
|
102
|
+
function multiMotifEnrichment(fovs, ct, motifs, neighborhood, returnCellIds) {
|
|
103
|
+
const totals = motifs.map(() => ({ numCells: 0, numCenter: 0, numMotif: 0, numCenterMotif: 0 }));
|
|
104
|
+
const neighborIds = motifs.map(() => ({}));
|
|
105
|
+
const centerIds = motifs.map(() => ({}));
|
|
106
|
+
for (const { datasetId, context } of fovs) {
|
|
107
|
+
const counts = countMotifs(context, ct, motifs, neighborhood(context), returnCellIds);
|
|
108
|
+
counts.forEach((c, m) => {
|
|
109
|
+
totals[m].numCells += c.numCells;
|
|
110
|
+
totals[m].numCenter += c.numCenter;
|
|
111
|
+
totals[m].numMotif += c.numMotif;
|
|
112
|
+
totals[m].numCenterMotif += c.numCenterMotif;
|
|
113
|
+
if (returnCellIds && c.centerIndices.length > 0) {
|
|
114
|
+
neighborIds[m][datasetId] = c.neighborIndices.map(j => context.obsIndex[j]);
|
|
115
|
+
centerIds[m][datasetId] = c.centerIndices.map(i => context.obsIndex[i]);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
const out = motifs.map((motif, m) => {
|
|
120
|
+
const { neighborIds: _n, centerIds: _c, ...result } = computeMotifEnrichment({ center: ct, motif, ...totals[m] });
|
|
121
|
+
return returnCellIds
|
|
122
|
+
? { ...result, neighborIds: neighborIds[m], centerIds: centerIds[m] }
|
|
123
|
+
: result;
|
|
124
|
+
});
|
|
125
|
+
return applyFdrCorrection(out);
|
|
126
|
+
}
|
|
127
|
+
// Perform motif enrichment analysis using k-nearest neighbors in multiple FOVs.
|
|
128
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L319
|
|
129
|
+
export async function multiMotifEnrichmentKnn(multi, params) {
|
|
130
|
+
const { ct, datasetClass, k = 30, minSupport = 0.5, maxDist = 20, returnCellIds = false, mode = 'maximal' } = params;
|
|
131
|
+
const fovs = selectFovs(multi, datasetClass);
|
|
132
|
+
assertCellTypeInAnyFov(multi, ct);
|
|
133
|
+
assertEnrichmentMode(mode);
|
|
134
|
+
if (mode === 'nested' && params.motifs === undefined) {
|
|
135
|
+
return nestedMotifDescent({
|
|
136
|
+
testMotifs: motifs => multiMotifEnrichmentKnn(multi, { ...params, motifs, mode: 'maximal' }),
|
|
137
|
+
frequentPatterns: await multiFindFpKnn(multi, { ct, datasetClass, k, minSupport, maxDist, ifMax: false }),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const motifs = params.motifs === undefined
|
|
141
|
+
? (await multiFindFpKnn(multi, { ct, datasetClass, k, minSupport, maxDist })).map(p => p.itemsets)
|
|
142
|
+
: normalizeMultiMotifs(multi, params.motifs);
|
|
143
|
+
return multiMotifEnrichment(fovs, ct, motifs, context => knnNeighborhood(context, k, maxDist), returnCellIds);
|
|
144
|
+
}
|
|
145
|
+
// Perform motif enrichment analysis within a radius-based neighborhood in multiple FOVs.
|
|
146
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L581
|
|
147
|
+
export async function multiMotifEnrichmentDist(multi, params) {
|
|
148
|
+
const { ct, datasetClass, maxDist = 20, minSize = 0, minSupport = 0.5, returnCellIds = false, mode = 'maximal' } = params;
|
|
149
|
+
const fovs = selectFovs(multi, datasetClass);
|
|
150
|
+
assertCellTypeInAnyFov(multi, ct);
|
|
151
|
+
assertEnrichmentMode(mode);
|
|
152
|
+
if (mode === 'nested' && params.motifs === undefined) {
|
|
153
|
+
return nestedMotifDescent({
|
|
154
|
+
testMotifs: motifs => multiMotifEnrichmentDist(multi, { ...params, motifs, mode: 'maximal' }),
|
|
155
|
+
frequentPatterns: await multiFindFpDist(multi, { ct, datasetClass, maxDist, minSize, minSupport, ifMax: false }),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const motifs = params.motifs === undefined
|
|
159
|
+
? (await multiFindFpDist(multi, { ct, datasetClass, maxDist, minSize, minSupport })).map(p => p.itemsets)
|
|
160
|
+
: normalizeMultiMotifs(multi, params.motifs);
|
|
161
|
+
return multiMotifEnrichment(fovs, ct, motifs, context => radiusNeighborhood(context, maxDist), returnCellIds);
|
|
162
|
+
}
|
|
163
|
+
// Pool the motif composition over the selected FOVs.
|
|
164
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L851
|
|
165
|
+
function multiMotifComposition(multi, ct, motifsParam, datasetClass, neighborhood) {
|
|
166
|
+
const fovs = selectFovs(multi, datasetClass);
|
|
167
|
+
assertCellTypeInAnyFov(multi, ct);
|
|
168
|
+
const motifs = normalizeMotifList(motifsParam, allLabels(multi));
|
|
169
|
+
return fovs.flatMap(({ datasetId, context }) => {
|
|
170
|
+
const cinds = findCellIndicesOfType(context, ct);
|
|
171
|
+
const labelsUnique = new Set(context.labels);
|
|
172
|
+
// A motif with a cell type missing from this FOV has no motif-positive center here.
|
|
173
|
+
const active = motifs.filter(m => m.every(t => labelsUnique.has(t)));
|
|
174
|
+
if (cinds.length === 0 || active.length === 0)
|
|
175
|
+
return [];
|
|
176
|
+
return motifCompositionRows(context, ct, active, cinds, neighborhood(context))
|
|
177
|
+
.map(row => ({ datasetId, ...row }));
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
// Compute the composition of motif cell types in the k-NN neighborhoods of center cells across multiple FOVs.
|
|
181
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L931
|
|
182
|
+
export function multiMotifCompositionKnn(multi, params) {
|
|
183
|
+
const { ct, motifs, datasetClass, k = 30, maxDist = 20 } = params;
|
|
184
|
+
return multiMotifComposition(multi, ct, motifs, datasetClass, context => knnNeighborhood(context, k, maxDist));
|
|
185
|
+
}
|
|
186
|
+
// Compute the composition of motif cell types in the radius-based neighborhoods of center cells across multiple FOVs.
|
|
187
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L888
|
|
188
|
+
export function multiMotifCompositionDist(multi, params) {
|
|
189
|
+
const { ct, motifs, datasetClass, maxDist = 20 } = params;
|
|
190
|
+
return multiMotifComposition(multi, ct, motifs, datasetClass, context => radiusNeighborhood(context, maxDist));
|
|
191
|
+
}
|
|
192
|
+
// Normalize motifs as differential_analysis_motif_* does (no filtering of unknown cell types).
|
|
193
|
+
function toDifferentialMotifs(motifs) {
|
|
194
|
+
if (typeof motifs === 'string')
|
|
195
|
+
return [[motifs]];
|
|
196
|
+
if (motifs.length > 0 && typeof motifs[0] === 'string')
|
|
197
|
+
return [motifs];
|
|
198
|
+
return motifs;
|
|
199
|
+
}
|
|
200
|
+
// Test every motif for a difference in support between the datasets of two classes.
|
|
201
|
+
// Returns all tested motifs, unlike differentialAnalysisKnn/Dist which return only the significant ones.
|
|
202
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_differential_pattern.py
|
|
203
|
+
function differentialTests(multi, datasetClasses, ct, motifsParam,
|
|
204
|
+
// Support of each motif among the given center cells of a dataset.
|
|
205
|
+
supportsInFov) {
|
|
206
|
+
const motifs = [];
|
|
207
|
+
const motifKeys = new Set();
|
|
208
|
+
for (const motif of toDifferentialMotifs(motifsParam)) {
|
|
209
|
+
const sorted = motif.toSorted();
|
|
210
|
+
const key = JSON.stringify(sorted);
|
|
211
|
+
if (!motifKeys.has(key)) {
|
|
212
|
+
motifKeys.add(key);
|
|
213
|
+
motifs.push(sorted);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const supports = motifs.map(() => Object.fromEntries(datasetClasses.map(c => [c, []])));
|
|
217
|
+
for (const datasetClass of datasetClasses) {
|
|
218
|
+
for (const { context } of selectFovs(multi, datasetClass)) {
|
|
219
|
+
const cinds = findCellIndicesOfType(context, ct);
|
|
220
|
+
const fovSupports = cinds.length === 0 ? motifs.map(() => 0) : supportsInFov(context, cinds, motifs);
|
|
221
|
+
fovSupports.forEach((s, m) => supports[m][datasetClass].push(s));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const [c0, c1] = datasetClasses;
|
|
225
|
+
const results = motifs.map((itemsets, m) => {
|
|
226
|
+
const group1 = supports[m][c0];
|
|
227
|
+
const group2 = supports[m][c1];
|
|
228
|
+
let pValue = 1.0;
|
|
229
|
+
let datasetClassHigherFrequency = 'neither';
|
|
230
|
+
if (group1.length > 0 && group2.length > 0) {
|
|
231
|
+
pValue = mannWhitneyU(group1, group2).pValue;
|
|
232
|
+
// Determine which class has higher frequency using the median rank.
|
|
233
|
+
const ranks = rankAverage([...group1, ...group2]);
|
|
234
|
+
const medianRank1 = median(ranks.slice(0, group1.length));
|
|
235
|
+
const medianRank2 = median(ranks.slice(group1.length));
|
|
236
|
+
datasetClassHigherFrequency = medianRank1 > medianRank2 ? c0 : c1;
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
itemsets,
|
|
240
|
+
supports: supports[m],
|
|
241
|
+
supportMean: { [c0]: mean(group1), [c1]: mean(group2) },
|
|
242
|
+
pValue,
|
|
243
|
+
datasetClassHigherFrequency,
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
if (results.length > 1) {
|
|
247
|
+
const { rejected, adjusted } = fdrCorrection(results.map(r => r.pValue), 0.05);
|
|
248
|
+
return results.map((r, i) => ({ ...r, adjPValue: adjusted[i], ifSignificant: rejected[i] }));
|
|
249
|
+
}
|
|
250
|
+
return results.map(r => ({ ...r, adjPValue: r.pValue, ifSignificant: r.pValue < 0.05 }));
|
|
251
|
+
}
|
|
252
|
+
// Split the significant results by the class with the higher frequency, sorted by adjusted p-value.
|
|
253
|
+
function splitSignificant(results, datasetClasses) {
|
|
254
|
+
return Object.fromEntries(datasetClasses.map(c => [
|
|
255
|
+
c,
|
|
256
|
+
results
|
|
257
|
+
.filter(r => r.datasetClassHigherFrequency === c && r.ifSignificant)
|
|
258
|
+
.map(({ itemsets, supportMean, adjPValue }) => ({ itemsets, supportMean, adjPValue }))
|
|
259
|
+
.toSorted((a, b) => a.adjPValue - b.adjPValue),
|
|
260
|
+
]));
|
|
261
|
+
}
|
|
262
|
+
// Union of the frequent patterns discovered in each dataset of the two classes.
|
|
263
|
+
async function discoverMotifs(multi, datasetClasses, findFpFov) {
|
|
264
|
+
const motifs = new Map();
|
|
265
|
+
for (const datasetClass of datasetClasses) {
|
|
266
|
+
for (const { datasetId } of selectFovs(multi, datasetClass)) {
|
|
267
|
+
for (const { itemsets } of await findFpFov(datasetId)) {
|
|
268
|
+
motifs.set(JSON.stringify(itemsets.toSorted()), itemsets.toSorted());
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return Array.from(motifs.values());
|
|
273
|
+
}
|
|
274
|
+
function validateDifferentialClasses(multi, datasetClasses) {
|
|
275
|
+
if (datasetClasses.length !== 2) {
|
|
276
|
+
throw new Error("Require 2 dataset classes for differential analysis.");
|
|
277
|
+
}
|
|
278
|
+
selectFovs(multi, datasetClasses);
|
|
279
|
+
}
|
|
280
|
+
// Fraction of the center cells whose neighborhood contains every motif cell type
|
|
281
|
+
// (0 for motifs with a cell type missing from the dataset).
|
|
282
|
+
function motifSupports(context, cinds, motifs, neighborsOf, isValidCenter = () => true) {
|
|
283
|
+
const labelsUnique = new Set(context.labels);
|
|
284
|
+
const neighborTypes = cinds.map((i) => {
|
|
285
|
+
const neighbors = neighborsOf(i);
|
|
286
|
+
return isValidCenter(neighbors) ? new Set(neighbors.map(j => context.labels[j])) : null;
|
|
287
|
+
});
|
|
288
|
+
return motifs.map((motif) => {
|
|
289
|
+
if (!motif.every(t => labelsUnique.has(t)))
|
|
290
|
+
return 0;
|
|
291
|
+
const count = neighborTypes.filter(types => types !== null && motif.every(t => types.has(t))).length;
|
|
292
|
+
return count / cinds.length;
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
// Test all motifs for differential support between two dataset classes using k-NN neighborhoods.
|
|
296
|
+
// Returns every tested motif (including non-significant ones).
|
|
297
|
+
export async function differentialTestsKnn(multi, params) {
|
|
298
|
+
const { ct, datasetClasses, k = 30, minSupport = 0.5, maxDist = 20 } = params;
|
|
299
|
+
validateDifferentialClasses(multi, datasetClasses);
|
|
300
|
+
const motifs = params.motifs ?? await discoverMotifs(multi, datasetClasses, datasetId => (findFpKnnFov(multi, { ct, datasetId, k, minSupport, maxDist })));
|
|
301
|
+
return differentialTests(multi, datasetClasses, ct, motifs, (context, cinds, ms) => (motifSupports(context, cinds, ms, knnNeighborhood(context, k, maxDist))));
|
|
302
|
+
}
|
|
303
|
+
// Perform differential analysis of motif patterns between two dataset classes using k-NN neighborhoods.
|
|
304
|
+
// Returns, for each class, the motifs significantly more frequent in that class.
|
|
305
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L1105
|
|
306
|
+
export async function differentialAnalysisKnn(multi, params) {
|
|
307
|
+
return splitSignificant(await differentialTestsKnn(multi, params), params.datasetClasses);
|
|
308
|
+
}
|
|
309
|
+
// Test all motifs for differential support between two dataset classes using radius-based neighborhoods.
|
|
310
|
+
// Returns every tested motif (including non-significant ones).
|
|
311
|
+
export async function differentialTestsDist(multi, params) {
|
|
312
|
+
const { ct, datasetClasses, maxDist = 20, minSupport = 0.5, minSize = 0 } = params;
|
|
313
|
+
validateDifferentialClasses(multi, datasetClasses);
|
|
314
|
+
const motifs = params.motifs ?? await discoverMotifs(multi, datasetClasses, datasetId => (findFpDistFov(multi, { ct, datasetId, maxDist, minSize, minSupport })));
|
|
315
|
+
// Center cells with neighborhoods not larger than minSize never count as having the motif,
|
|
316
|
+
// but still count in the denominator of the support.
|
|
317
|
+
return differentialTests(multi, datasetClasses, ct, motifs, (context, cinds, ms) => (motifSupports(context, cinds, ms, radiusNeighborhood(context, maxDist), neighbors => neighbors.length > minSize)));
|
|
318
|
+
}
|
|
319
|
+
// Perform differential analysis of motif patterns between two dataset classes using radius-based neighborhoods.
|
|
320
|
+
// Returns, for each class, the motifs significantly more frequent in that class.
|
|
321
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_query_multiple_fov.py#L1206
|
|
322
|
+
export async function differentialAnalysisDist(multi, params) {
|
|
323
|
+
return splitSignificant(await differentialTestsDist(multi, params), params.datasetClasses);
|
|
324
|
+
}
|
|
325
|
+
//# sourceMappingURL=multi-fov.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-fov.js","sourceRoot":"","sources":["../src/multi-fov.ts"],"names":[],"mappings":"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"}
|
package/dist/nested.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type FrequentPattern } from './fpgrowth.js';
|
|
2
|
+
type TestedMotif = {
|
|
3
|
+
motifs: string[];
|
|
4
|
+
pValue: number;
|
|
5
|
+
adjPValue?: number;
|
|
6
|
+
ifSignificant?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type NestedMotifDescentParams<T> = {
|
|
9
|
+
testMotifs: (motifs: string[][]) => Promise<T[]>;
|
|
10
|
+
frequentPatterns: FrequentPattern[];
|
|
11
|
+
supportTol?: number;
|
|
12
|
+
maxTestedPatterns?: number;
|
|
13
|
+
maxExpansionFactor?: number;
|
|
14
|
+
};
|
|
15
|
+
export declare function nestedMotifDescent<T extends TestedMotif>(params: NestedMotifDescentParams<T>): Promise<T[]>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=nested.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested.d.ts","sourceRoot":"","sources":["../src/nested.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AA4B1E,KAAK,WAAW,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAKrG,KAAK,wBAAwB,CAAC,CAAC,IAAI;IAGjC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAGjD,gBAAgB,EAAE,eAAe,EAAE,CAAC;IAEpC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAIF,wBAAsB,kBAAkB,CAAC,CAAC,SAAS,WAAW,EAAE,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAwFjH"}
|
package/dist/nested.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { applyFdrCorrection } from './stats.js';
|
|
2
|
+
import { findMaximalPatterns } from './fpgrowth.js';
|
|
3
|
+
// Nested motif testing.
|
|
4
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_utils.py#L97
|
|
5
|
+
//
|
|
6
|
+
// The maximal-pattern reduction happens BEFORE the hypergeometric test, so a sub-pattern
|
|
7
|
+
// of a non-significant maximal pattern never enters the tested set at all. When a maximal
|
|
8
|
+
// pattern is diluted by one abundant, unrelated cell type, the whole pattern fails the
|
|
9
|
+
// test and the informative core inside it is never examined.
|
|
10
|
+
//
|
|
11
|
+
// Nested testing walks into those patterns:
|
|
12
|
+
//
|
|
13
|
+
// 1. Test every maximal pattern, exactly as the maximal mode does.
|
|
14
|
+
// 2. A maximal pattern that IS significant is a finding in its own right -- stop, and do
|
|
15
|
+
// not test its sub-patterns.
|
|
16
|
+
// 3. A maximal pattern that is NOT significant is expanded into its immediate (k-1)
|
|
17
|
+
// sub-patterns, which are then tested.
|
|
18
|
+
// 4. Descent continues only along branches that stay non-significant. A branch ends when
|
|
19
|
+
// it becomes significant or reaches length 1.
|
|
20
|
+
// 5. A sub-pattern reachable from several parents is tested once.
|
|
21
|
+
// 6. Multiple-testing correction is applied over every pattern actually tested.
|
|
22
|
+
// 7. A child whose support equals its parent's marks the same neighborhoods as the
|
|
23
|
+
// parent, so it carries no extra information and is not reported.
|
|
24
|
+
const NESTED_SUPPORT_TOL = 1e-9;
|
|
25
|
+
const NESTED_MAX_TESTED_PATTERNS = 5000;
|
|
26
|
+
const NESTED_MAX_EXPANSION_FACTOR = 50.0;
|
|
27
|
+
// Canonical motif key: the sorted motif.
|
|
28
|
+
const canonicalKey = (motif) => JSON.stringify(motif.toSorted());
|
|
29
|
+
// Run the nested descent and return the corrected results over everything tested.
|
|
30
|
+
// Reference: https://github.com/ShaokunAn/Spatial-Query/blob/9250b61/SpatialQuery/spatial_utils.py#L161
|
|
31
|
+
export async function nestedMotifDescent(params) {
|
|
32
|
+
const { testMotifs, frequentPatterns, supportTol = NESTED_SUPPORT_TOL, maxTestedPatterns = NESTED_MAX_TESTED_PATTERNS, maxExpansionFactor = NESTED_MAX_EXPANSION_FACTOR, } = params;
|
|
33
|
+
if (frequentPatterns.length === 0) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
const supportOf = new Map(frequentPatterns.map(p => [canonicalKey(p.itemsets), p.support]));
|
|
37
|
+
const maximal = findMaximalPatterns(frequentPatterns).map(p => p.itemsets.toSorted());
|
|
38
|
+
// Level 0 is the maximal patterns; gating them decides where the descent starts.
|
|
39
|
+
const gateRes = maximal.length > 0 ? await testMotifs(maximal) : [];
|
|
40
|
+
if (gateRes.length === 0) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
const significance = (results) => new Map(results.map(r => [canonicalKey(r.motifs), Boolean(r.ifSignificant)]));
|
|
44
|
+
const gateSig = significance(gateRes);
|
|
45
|
+
// `tested` records every pattern the descent touches, significant or not: correction
|
|
46
|
+
// in rule 6 must cover them all. Insertion order keeps the final results reproducible.
|
|
47
|
+
const tested = new Set(maximal.map(canonicalKey));
|
|
48
|
+
const parentOf = new Map();
|
|
49
|
+
const levelTables = [gateRes];
|
|
50
|
+
let frontier = maximal.filter(m => !gateSig.get(canonicalKey(m)));
|
|
51
|
+
while (frontier.length > 0) {
|
|
52
|
+
const children = [];
|
|
53
|
+
for (const parent of frontier) {
|
|
54
|
+
if (parent.length <= 1)
|
|
55
|
+
continue;
|
|
56
|
+
// Immediate sub-patterns, in the order of itertools.combinations(parent, len(parent) - 1).
|
|
57
|
+
for (let drop = parent.length - 1; drop >= 0; drop--) {
|
|
58
|
+
const child = parent.filter((_, n) => n !== drop);
|
|
59
|
+
const childKey = canonicalKey(child);
|
|
60
|
+
if (tested.has(childKey)) {
|
|
61
|
+
// Reachable from an earlier parent already: test it once, and keep the
|
|
62
|
+
// shallowest parent, which breadth-first order guarantees is this one.
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
tested.add(childKey);
|
|
66
|
+
parentOf.set(childKey, canonicalKey(parent));
|
|
67
|
+
children.push(child);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (children.length === 0)
|
|
71
|
+
break;
|
|
72
|
+
if (tested.size > maxTestedPatterns || tested.size > maxExpansionFactor * Math.max(maximal.length, 1)) {
|
|
73
|
+
console.warn(`Nested descent stopped early at ${tested.size} tested patterns `
|
|
74
|
+
+ `(limits: maxTestedPatterns=${maxTestedPatterns}, `
|
|
75
|
+
+ `maxExpansionFactor=${maxExpansionFactor} x ${maximal.length} maximal patterns). `
|
|
76
|
+
+ `Reported results cover the patterns reached so far.`);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
const levelRes = await testMotifs(children);
|
|
80
|
+
levelTables.push(levelRes);
|
|
81
|
+
const levelSig = significance(levelRes);
|
|
82
|
+
frontier = children.filter(c => !levelSig.get(canonicalKey(c)));
|
|
83
|
+
}
|
|
84
|
+
// Every field except the FDR ones depends only on the motif and the data, so the
|
|
85
|
+
// results computed level by level are reused; only the correction is redone over the union.
|
|
86
|
+
const seen = new Set();
|
|
87
|
+
const combined = levelTables.flat().filter((r) => {
|
|
88
|
+
const key = canonicalKey(r.motifs);
|
|
89
|
+
if (seen.has(key))
|
|
90
|
+
return false;
|
|
91
|
+
seen.add(key);
|
|
92
|
+
return true;
|
|
93
|
+
});
|
|
94
|
+
// Rule 7: a child marking the same neighborhoods as its parent adds nothing. It stays
|
|
95
|
+
// in the correction -- it was tested -- but is not reported.
|
|
96
|
+
const redundant = new Set();
|
|
97
|
+
for (const [child, parent] of parentOf) {
|
|
98
|
+
const supportChild = supportOf.get(child);
|
|
99
|
+
const supportParent = supportOf.get(parent);
|
|
100
|
+
if (supportChild !== undefined && supportParent !== undefined && Math.abs(supportChild - supportParent) <= supportTol) {
|
|
101
|
+
redundant.add(child);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return applyFdrCorrection(combined).filter(r => !redundant.has(canonicalKey(r.motifs)));
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=nested.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nested.js","sourceRoot":"","sources":["../src/nested.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import Flatbush from 'flatbush';
|
|
2
|
+
import { type FrequentPattern } from './fpgrowth.js';
|
|
3
|
+
export declare function generateObsIdToObsSetName(obsSetsMembership: Map<string, string[][]>, currSelectedSetGroup: string): (obsId: string) => string;
|
|
4
|
+
type ToObsSetNameFunc = ReturnType<typeof generateObsIdToObsSetName>;
|
|
5
|
+
type Coords = Float32Array | Float64Array;
|
|
6
|
+
export type InitParams = {
|
|
7
|
+
obsIndex: string[];
|
|
8
|
+
xCoords: Coords;
|
|
9
|
+
yCoords: Coords;
|
|
10
|
+
obsIdToObsSetName: ToObsSetNameFunc;
|
|
11
|
+
leafSize?: number;
|
|
12
|
+
normalizeSpatialCoord?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export type SqContext = {
|
|
15
|
+
obsIndex: string[];
|
|
16
|
+
labels: string[];
|
|
17
|
+
xCoords: Coords;
|
|
18
|
+
yCoords: Coords;
|
|
19
|
+
flatbushIndex: Flatbush;
|
|
20
|
+
xExtent: [number, number];
|
|
21
|
+
yExtent: [number, number];
|
|
22
|
+
};
|
|
23
|
+
export declare function normalizeSpatialCoords(xCoords: Coords, yCoords: Coords): {
|
|
24
|
+
xCoords: Float64Array<ArrayBuffer>;
|
|
25
|
+
yCoords: Float64Array<ArrayBuffer>;
|
|
26
|
+
scaleFactor: number;
|
|
27
|
+
};
|
|
28
|
+
export declare function buildContext(params: InitParams): SqContext;
|
|
29
|
+
export declare function findCellIndicesOfType(context: SqContext, ct: string): number[];
|
|
30
|
+
export type QueryPoint = {
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
exclude?: number;
|
|
34
|
+
};
|
|
35
|
+
export declare function knnNeighborhood(context: SqContext, k: number, maxDist: number): (i: number) => number[];
|
|
36
|
+
export declare function radiusNeighborhood(context: SqContext, maxDist: number): (i: number) => number[];
|
|
37
|
+
export declare function radiusTransactions(context: SqContext, points: QueryPoint[], maxDist: number, minSize: number): {
|
|
38
|
+
transactions: string[][];
|
|
39
|
+
neighborLists: number[][];
|
|
40
|
+
};
|
|
41
|
+
export declare function knnTransactions(context: SqContext, cinds: number[], k: number, maxDist: number): string[][];
|
|
42
|
+
type FindPatternsParams = {
|
|
43
|
+
maxDist?: number;
|
|
44
|
+
minSize?: number;
|
|
45
|
+
minSupport?: number;
|
|
46
|
+
returnCellIds?: boolean;
|
|
47
|
+
};
|
|
48
|
+
export declare function buildGridPoints(context: SqContext, maxDist?: number): [number, number][];
|
|
49
|
+
export declare function findPatternsGrid(context: SqContext, params?: FindPatternsParams): Promise<FrequentPattern[]>;
|
|
50
|
+
export declare function findPatternsRand(context: SqContext, params?: FindPatternsParams & {
|
|
51
|
+
nPoints?: number;
|
|
52
|
+
}): Promise<FrequentPattern[]>;
|
|
53
|
+
type FindFpKnnParams = {
|
|
54
|
+
ct: string;
|
|
55
|
+
k?: number;
|
|
56
|
+
minSupport?: number;
|
|
57
|
+
maxDist?: number;
|
|
58
|
+
ifMax?: boolean;
|
|
59
|
+
};
|
|
60
|
+
export declare function findFpKnn(context: SqContext, params: FindFpKnnParams): Promise<FrequentPattern[]>;
|
|
61
|
+
type FindFpDistParams = {
|
|
62
|
+
ct: string;
|
|
63
|
+
maxDist?: number;
|
|
64
|
+
minSize?: number;
|
|
65
|
+
minSupport?: number;
|
|
66
|
+
ifMax?: boolean;
|
|
67
|
+
};
|
|
68
|
+
export declare function findFpDist(context: SqContext, params: FindFpDistParams): Promise<FrequentPattern[]>;
|
|
69
|
+
export declare function centerQueryPoints(context: SqContext, cinds: number[]): QueryPoint[];
|
|
70
|
+
type MotifEnrichmentCountsParams = {
|
|
71
|
+
center: string;
|
|
72
|
+
motif: string[];
|
|
73
|
+
numCells: number;
|
|
74
|
+
numCenter: number;
|
|
75
|
+
numMotif: number;
|
|
76
|
+
numCenterMotif: number;
|
|
77
|
+
};
|
|
78
|
+
export type MotifEnrichmentResult = {
|
|
79
|
+
center: string;
|
|
80
|
+
motifs: string[];
|
|
81
|
+
nCenterMotif: number;
|
|
82
|
+
nCenter: number;
|
|
83
|
+
nMotif: number;
|
|
84
|
+
expectation: number;
|
|
85
|
+
pValue: number;
|
|
86
|
+
ifSignificant?: boolean;
|
|
87
|
+
adjPValue?: number;
|
|
88
|
+
neighborIds?: string[];
|
|
89
|
+
centerIds?: string[];
|
|
90
|
+
};
|
|
91
|
+
export declare function computeMotifEnrichment(params: MotifEnrichmentCountsParams): MotifEnrichmentResult;
|
|
92
|
+
export type MotifsParam = string | string[] | string[][];
|
|
93
|
+
export declare function normalizeMotifs(motifs: MotifsParam, labelsUnique: Set<string>): string[][];
|
|
94
|
+
export declare function normalizeMotifList(motifs: MotifsParam, labelsUnique: Set<string>): string[][];
|
|
95
|
+
export type MotifCounts = {
|
|
96
|
+
numCells: number;
|
|
97
|
+
numCenter: number;
|
|
98
|
+
numMotif: number;
|
|
99
|
+
numCenterMotif: number;
|
|
100
|
+
centerIndices?: number[];
|
|
101
|
+
neighborIndices?: number[];
|
|
102
|
+
};
|
|
103
|
+
export declare function countMotifs(context: SqContext, ct: string, motifs: string[][], neighborsOf: (i: number) => number[], returnCellIds: boolean): MotifCounts[];
|
|
104
|
+
export type EnrichmentMode = 'maximal' | 'nested';
|
|
105
|
+
export declare function assertEnrichmentMode(mode: string): void;
|
|
106
|
+
type MotifEnrichmentKnnParams = {
|
|
107
|
+
ct: string;
|
|
108
|
+
motifs?: MotifsParam;
|
|
109
|
+
k?: number;
|
|
110
|
+
minSupport?: number;
|
|
111
|
+
maxDist?: number;
|
|
112
|
+
returnCellIds?: boolean;
|
|
113
|
+
mode?: EnrichmentMode;
|
|
114
|
+
};
|
|
115
|
+
export declare function motifEnrichmentKnn(context: SqContext, params: MotifEnrichmentKnnParams): Promise<MotifEnrichmentResult[]>;
|
|
116
|
+
type MotifEnrichmentDistParams = {
|
|
117
|
+
ct: string;
|
|
118
|
+
motifs?: MotifsParam;
|
|
119
|
+
maxDist?: number;
|
|
120
|
+
minSize?: number;
|
|
121
|
+
minSupport?: number;
|
|
122
|
+
returnCellIds?: boolean;
|
|
123
|
+
mode?: EnrichmentMode;
|
|
124
|
+
};
|
|
125
|
+
export declare function motifEnrichmentDist(context: SqContext, params: MotifEnrichmentDistParams): Promise<MotifEnrichmentResult[]>;
|
|
126
|
+
export type MotifCompositionRow = {
|
|
127
|
+
center: string;
|
|
128
|
+
motifs: string[];
|
|
129
|
+
cellType: string;
|
|
130
|
+
nCells: number;
|
|
131
|
+
nMotifCells: number;
|
|
132
|
+
proportion: number;
|
|
133
|
+
};
|
|
134
|
+
export declare function motifCompositionRows(context: SqContext, ct: string, motifs: string[][], cinds: number[], neighborsOf: (i: number) => number[]): MotifCompositionRow[];
|
|
135
|
+
type MotifCompositionKnnParams = {
|
|
136
|
+
ct: string;
|
|
137
|
+
motifs: MotifsParam;
|
|
138
|
+
k?: number;
|
|
139
|
+
maxDist?: number;
|
|
140
|
+
};
|
|
141
|
+
export declare function motifCompositionKnn(context: SqContext, params: MotifCompositionKnnParams): MotifCompositionRow[];
|
|
142
|
+
type MotifCompositionDistParams = {
|
|
143
|
+
ct: string;
|
|
144
|
+
motifs: MotifsParam;
|
|
145
|
+
maxDist?: number;
|
|
146
|
+
};
|
|
147
|
+
export declare function motifCompositionDist(context: SqContext, params: MotifCompositionDistParams): MotifCompositionRow[];
|
|
148
|
+
export {};
|
|
149
|
+
//# sourceMappingURL=single-fov.d.ts.map
|