@vitessce/statistical-plots 3.4.5 → 3.4.7

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.
Files changed (47) hide show
  1. package/dist/deflate-c8c2f459.js +13 -0
  2. package/dist/index-a1925e78.js +206649 -0
  3. package/dist/index.js +13 -91680
  4. package/dist/jpeg-ffd14ffe.js +840 -0
  5. package/dist/lerc-9d1dd17e.js +2014 -0
  6. package/dist/lzw-3705b408.js +128 -0
  7. package/dist/packbits-6f657116.js +30 -0
  8. package/dist/pako.esm-68f84e2a.js +4022 -0
  9. package/dist/raw-0a76dec9.js +12 -0
  10. package/dist/webimage-fbdf3bdf.js +32 -0
  11. package/dist-tsc/CellSetExpressionPlot.d.ts.map +1 -1
  12. package/dist-tsc/CellSetExpressionPlot.js +207 -106
  13. package/dist-tsc/CellSetExpressionPlotOptions.d.ts.map +1 -1
  14. package/dist-tsc/CellSetExpressionPlotOptions.js +14 -4
  15. package/dist-tsc/CellSetExpressionPlotSubscriber.d.ts.map +1 -1
  16. package/dist-tsc/CellSetExpressionPlotSubscriber.js +15 -31
  17. package/dist-tsc/CellSetSizesPlot.d.ts.map +1 -1
  18. package/dist-tsc/CellSetSizesPlotSubscriber.d.ts.map +1 -1
  19. package/dist-tsc/DotPlot.d.ts +28 -0
  20. package/dist-tsc/DotPlot.d.ts.map +1 -0
  21. package/dist-tsc/DotPlot.js +144 -0
  22. package/dist-tsc/DotPlotSubscriber.d.ts +14 -0
  23. package/dist-tsc/DotPlotSubscriber.d.ts.map +1 -0
  24. package/dist-tsc/DotPlotSubscriber.js +54 -0
  25. package/dist-tsc/ExpressionHistogram.d.ts.map +1 -1
  26. package/dist-tsc/ExpressionHistogramSubscriber.d.ts.map +1 -1
  27. package/dist-tsc/dot-plot-hook.d.ts +23 -0
  28. package/dist-tsc/dot-plot-hook.d.ts.map +1 -0
  29. package/dist-tsc/dot-plot-hook.js +69 -0
  30. package/dist-tsc/expr-hooks.d.ts +51 -0
  31. package/dist-tsc/expr-hooks.d.ts.map +1 -0
  32. package/dist-tsc/expr-hooks.js +135 -0
  33. package/dist-tsc/expr-hooks.test.d.ts +2 -0
  34. package/dist-tsc/expr-hooks.test.d.ts.map +1 -0
  35. package/dist-tsc/expr-hooks.test.js +97 -0
  36. package/dist-tsc/index.d.ts +2 -0
  37. package/dist-tsc/index.js +2 -0
  38. package/package.json +10 -7
  39. package/src/CellSetExpressionPlot.js +223 -124
  40. package/src/CellSetExpressionPlotOptions.js +57 -1
  41. package/src/CellSetExpressionPlotSubscriber.js +45 -38
  42. package/src/DotPlot.js +175 -0
  43. package/src/DotPlotSubscriber.js +173 -0
  44. package/src/dot-plot-hook.js +107 -0
  45. package/src/expr-hooks.js +170 -0
  46. package/src/expr-hooks.test.js +116 -0
  47. package/src/index.js +2 -0
@@ -0,0 +1,170 @@
1
+ /* eslint-disable camelcase */
2
+ import { InternMap } from 'internmap';
3
+ import { scaleLinear } from 'd3-scale';
4
+ import {
5
+ bin,
6
+ min,
7
+ max,
8
+ mean as d3_mean,
9
+ deviation as d3_deviation,
10
+ ascending as d3_ascending,
11
+ quantileSorted,
12
+ } from 'd3-array';
13
+
14
+ // Reference: https://github.com/d3/d3-array/issues/180#issuecomment-851378012
15
+ function summarize(iterable, keepZeros) {
16
+ const values = iterable
17
+ .filter(d => keepZeros || d !== 0.0)
18
+ .sort(d3_ascending);
19
+ const minVal = values[0];
20
+ const maxVal = values[values.length - 1];
21
+ const q1 = quantileSorted(values, 0.25);
22
+ const q2 = quantileSorted(values, 0.5);
23
+ const q3 = quantileSorted(values, 0.75);
24
+ const iqr = q3 - q1; // interquartile range
25
+ const r0 = Math.max(minVal, q1 - iqr * 1.5);
26
+ const r1 = Math.min(maxVal, q3 + iqr * 1.5);
27
+ let i = -1;
28
+ while (values[++i] < r0);
29
+ const w0 = values[i];
30
+ while (values[++i] <= r1);
31
+ const w1 = values[i - 1];
32
+
33
+ // Chauvenet
34
+ // Reference: https://en.wikipedia.org/wiki/Chauvenet%27s_criterion
35
+ const mean = d3_mean(values);
36
+ const stdv = d3_deviation(values);
37
+ const c0 = mean - 3 * stdv;
38
+ const c1 = mean + 3 * stdv;
39
+
40
+ return {
41
+ quartiles: [q1, q2, q3],
42
+ range: [r0, r1],
43
+ whiskers: [w0, w1],
44
+ chauvenetRange: [c0, c1],
45
+ nonOutliers: values.filter(v => c0 <= v && v <= c1),
46
+ };
47
+ }
48
+
49
+ /**
50
+ * Supports three-level stratified input
51
+ * (cell set, sample set, gene).
52
+ * @param {*} stratifiedResult
53
+ * @param {*} posThreshold
54
+ * @returns
55
+ */
56
+ export function dotStratifiedExpressionData(
57
+ stratifiedResult, posThreshold,
58
+ ) {
59
+ const result = new InternMap([], JSON.stringify);
60
+ ([...stratifiedResult.keys()]).forEach((cellSetKey) => {
61
+ result.set(cellSetKey, new InternMap([], JSON.stringify));
62
+ ([...stratifiedResult.get(cellSetKey).keys()]).forEach((sampleSetKey) => {
63
+ result.get(cellSetKey).set(sampleSetKey, new InternMap([], JSON.stringify));
64
+
65
+ const allGenes = stratifiedResult.get(cellSetKey).get(sampleSetKey);
66
+
67
+ ([...allGenes.keys()]).forEach((geneKey) => {
68
+ const values = allGenes.get(geneKey);
69
+
70
+ const exprMean = d3_mean(values);
71
+ const numPos = values.reduce((acc, val) => (val > posThreshold ? acc + 1 : acc), 0);
72
+ const fracPos = numPos / values.length;
73
+
74
+ const dotSummary = {
75
+ meanExpInGroup: exprMean,
76
+ fracPosInGroup: fracPos,
77
+ };
78
+
79
+ result.get(cellSetKey).get(sampleSetKey).set(geneKey, dotSummary);
80
+ });
81
+ });
82
+ });
83
+ return result;
84
+ }
85
+
86
+ /**
87
+ * Supports two-level stratified input
88
+ * (cell set, sample set).
89
+ * @param {*} stratifiedResult
90
+ * @param {*} keepZeros
91
+ * @returns
92
+ */
93
+ export function summarizeStratifiedExpressionData(
94
+ stratifiedResult, keepZeros,
95
+ ) {
96
+ const summarizedResult = new InternMap([], JSON.stringify);
97
+
98
+ ([...stratifiedResult.keys()]).forEach((cellSetKey) => {
99
+ summarizedResult.set(cellSetKey, new InternMap([], JSON.stringify));
100
+ ([...stratifiedResult.get(cellSetKey).keys()]).forEach((sampleSetKey) => {
101
+ const values = stratifiedResult.get(cellSetKey).get(sampleSetKey);
102
+ const summary = summarize(values, keepZeros);
103
+ summarizedResult.get(cellSetKey).set(sampleSetKey, summary);
104
+ });
105
+ });
106
+
107
+ return summarizedResult;
108
+ }
109
+
110
+ /**
111
+ * Supports two-level summarized input
112
+ * (cell set, sample set),
113
+ * the output from summarizeStratifiedExpressionData.
114
+ * @param {*} summarizedResult
115
+ * @param {*} binCount
116
+ * @param {*} yMinProp
117
+ * @returns
118
+ */
119
+ export function histogramStratifiedExpressionData(
120
+ summarizedResult, binCount, yMinProp,
121
+ ) {
122
+ const groupSummaries = ([...summarizedResult.keys()]).map(cellSetKey => ({
123
+ key: cellSetKey,
124
+ value: ([...summarizedResult.get(cellSetKey).keys()]).map(sampleSetKey => ({
125
+ key: sampleSetKey,
126
+ value: summarizedResult.get(cellSetKey).get(sampleSetKey),
127
+ })),
128
+ }));
129
+
130
+ const groupData = groupSummaries
131
+ .map(({ key, value }) => ({
132
+ key,
133
+ value: value.map(({ key: subKey, value: subValue }) => (
134
+ { key: subKey, value: subValue.nonOutliers }
135
+ )),
136
+ }));
137
+ const trimmedData = groupData.map(kv => kv.value.map(subKv => subKv.value).flat()).flat();
138
+
139
+ const yMin = (yMinProp === null ? Math.min(0, min(trimmedData)) : yMinProp);
140
+
141
+ // For the y domain, use the yMin prop
142
+ // to support a use case such as 'Aspect Ratio',
143
+ // where the domain minimum should be 1 rather than 0.
144
+ const y = scaleLinear()
145
+ .domain([yMin, max(trimmedData)]);
146
+
147
+ const histogram = bin()
148
+ .thresholds(y.ticks(binCount))
149
+ .domain(y.domain());
150
+
151
+ const groupBins = groupData.map(kv => ({ key: kv.key,
152
+ value: kv.value.map(subKv => (
153
+ { key: subKv.key, value: histogram(subKv.value) }
154
+ )) }));
155
+ const groupBinsMax = max(groupBins
156
+ .flatMap(d => d.value.flatMap(subKv => subKv.value.map(v => v.length))));
157
+
158
+ return {
159
+ // Array of [{ key, value: [
160
+ // { key, value: {
161
+ // quartiles, range, whiskers, chauvenetRange, nonOutliers }
162
+ // }
163
+ // ] }]
164
+ groupSummaries,
165
+ groupData, // Array of [{ key, value: [{ key, value: nonOutliers }] }]
166
+ groupBins, // Array of [{ key, value: [{ key, value: histogram(nonOutliers) }] }]
167
+ groupBinsMax, // Number
168
+ y, // d3.scaleLinear without a range set
169
+ };
170
+ }
@@ -0,0 +1,116 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ stratifyExpressionData,
4
+ aggregateStratifiedExpressionData,
5
+ } from '@vitessce/sets-utils';
6
+ import {
7
+ summarizeStratifiedExpressionData,
8
+ histogramStratifiedExpressionData,
9
+ } from './expr-hooks.js';
10
+
11
+ describe('Utility functions for processing expression data for statistical plots', () => {
12
+ describe('summarizeStratifiedExpressionData function', () => {
13
+ it('computes summarized information accurately', () => {
14
+ const sampleEdges = new Map([
15
+ ['cell1-1', 'donor1'],
16
+ ['cell1-2', 'donor1'],
17
+ ['cell1-3', 'donor1'],
18
+ ['cell1-4', 'donor1'],
19
+
20
+ ['cell2-1', 'donor2'],
21
+ ['cell2-2', 'donor2'],
22
+ ['cell2-3', 'donor2'],
23
+ ['cell2-4', 'donor2'],
24
+ ]);
25
+ const sampleSets = {
26
+ tree: [
27
+ {
28
+ name: 'Clinical groups',
29
+ children: [
30
+ {
31
+ name: 'AKI',
32
+ set: [['donor1', null]],
33
+ },
34
+ {
35
+ name: 'CKD',
36
+ set: [['donor2', null]],
37
+ },
38
+ ],
39
+ },
40
+ ],
41
+ };
42
+ const sampleSetSelection = [
43
+ ['Clinical groups', 'AKI'],
44
+ ['Clinical groups', 'CKD'],
45
+ ];
46
+ const expressionData = [
47
+ // Gene 1
48
+ [10, 20, 30, 40, 11, 21, 31, 41],
49
+ ];
50
+ const obsIndex = ['cell1-1', 'cell1-2', 'cell1-3', 'cell1-4', 'cell2-1', 'cell2-2', 'cell2-3', 'cell2-4'];
51
+ const mergedCellSets = {
52
+ tree: [
53
+ {
54
+ name: 'Cell type',
55
+ children: [
56
+ {
57
+ name: 'T cell',
58
+ set: [['cell1-1', null], ['cell1-3', null], ['cell2-1', null], ['cell2-3', null]],
59
+ },
60
+ {
61
+ name: 'B cell',
62
+ set: [['cell1-2', null], ['cell1-4', null], ['cell2-2', null], ['cell2-4', null]],
63
+ },
64
+ ],
65
+ },
66
+ ],
67
+ };
68
+ const geneSelection = [
69
+ 'Gene 1',
70
+ ];
71
+ const cellSetSelection = [
72
+ ['Cell type', 'T cell'],
73
+ ['Cell type', 'B cell'],
74
+ ];
75
+ const cellSetColor = [
76
+ { set: ['Cell type', 'T cell'], color: [255, 0, 0] },
77
+ { set: ['Cell type', 'B cell'], color: [0, 255, 0] },
78
+ ];
79
+ const featureValueTransform = null;
80
+ const featureValueTransformCoefficient = 1;
81
+
82
+ const [result] = stratifyExpressionData(
83
+ sampleEdges, sampleSets, sampleSetSelection,
84
+ expressionData, obsIndex, mergedCellSets,
85
+ geneSelection, cellSetSelection, cellSetColor,
86
+ featureValueTransform, featureValueTransformCoefficient,
87
+ );
88
+ const aggregateData = aggregateStratifiedExpressionData(
89
+ result, geneSelection,
90
+ );
91
+ const summaryResult = summarizeStratifiedExpressionData(aggregateData, true);
92
+
93
+ expect([...summaryResult.keys()]).toEqual([['Cell type', 'T cell'], ['Cell type', 'B cell']]);
94
+ expect([...summaryResult.get(['Cell type', 'T cell']).keys()]).toEqual([['Clinical groups', 'AKI'], ['Clinical groups', 'CKD']]);
95
+ expect(Object.keys(summaryResult.get(['Cell type', 'T cell']).get(['Clinical groups', 'AKI']))).toEqual([
96
+ 'quartiles',
97
+ 'range',
98
+ 'whiskers',
99
+ 'chauvenetRange',
100
+ 'nonOutliers',
101
+ ]);
102
+
103
+ const histogramResult = histogramStratifiedExpressionData(summaryResult, 16, null);
104
+
105
+ expect(Object.keys(histogramResult)).toEqual([
106
+ 'groupSummaries',
107
+ 'groupData',
108
+ 'groupBins',
109
+ 'groupBinsMax',
110
+ 'y',
111
+ ]);
112
+ expect(histogramResult.groupSummaries.map(d => d.key)).toEqual([['Cell type', 'T cell'], ['Cell type', 'B cell']]);
113
+ expect(histogramResult.groupBinsMax).toEqual(1);
114
+ });
115
+ });
116
+ });
package/src/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  export { CellSetExpressionPlotSubscriber } from './CellSetExpressionPlotSubscriber.js';
2
2
  export { CellSetSizesPlotSubscriber } from './CellSetSizesPlotSubscriber.js';
3
3
  export { ExpressionHistogramSubscriber } from './ExpressionHistogramSubscriber.js';
4
+ export { DotPlotSubscriber } from './DotPlotSubscriber.js';
4
5
  export { FeatureBarPlotSubscriber } from './FeatureBarPlotSubscriber.js';
5
6
  export { default as CellSetSizesPlot } from './CellSetSizesPlot.js';
6
7
  export { default as CellSetExpressionPlot } from './CellSetExpressionPlot.js';
7
8
  export { default as ExpressionHistogram } from './ExpressionHistogram.js';
9
+ export { default as DotPlot } from './DotPlot.js';