@vitessce/gl 3.3.2 → 3.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{deflate-73d5335b.js → deflate-8259e5d4.js} +1 -1
- package/dist/{index-0d084e33.js → index-901cd86d.js} +214 -136
- package/dist/index.js +2 -2
- package/dist/{jpeg-201a0839.js → jpeg-2919bc92.js} +1 -1
- package/dist/{lerc-4c2149fc.js → lerc-95858d36.js} +1 -1
- package/dist/{lzw-04637fdd.js → lzw-d020357b.js} +1 -1
- package/dist/{packbits-c3fd53d2.js → packbits-2ad8f627.js} +1 -1
- package/dist/{raw-c78b844f.js → raw-93e6f264.js} +1 -1
- package/dist/{webimage-2dd56bbe.js → webimage-33d58a8b.js} +1 -1
- package/dist-tsc/BitmaskLayerBeta.d.ts +14 -6
- package/dist-tsc/BitmaskLayerBeta.d.ts.map +1 -1
- package/dist-tsc/BitmaskLayerBeta.js +21 -7
- package/dist-tsc/bitmask-utils.d.ts +1 -1
- package/dist-tsc/bitmask-utils.d.ts.map +1 -1
- package/dist-tsc/bitmask-utils.js +44 -8
- package/dist-tsc/bitmask-utils.test.js +5 -1
- package/package.json +2 -2
- package/src/BitmaskLayerBeta.js +32 -5
- package/src/bitmask-utils.js +50 -8
- package/src/bitmask-utils.test.js +6 -0
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as distEs6 } from "./index-
|
|
2
|
-
import { o, n, A, r, q, p, i, j, C, l, D, G, e, H, c, M, k, m, d, P, S, h, T, t, b, s, v } from "./index-
|
|
1
|
+
import { f as distEs6 } from "./index-901cd86d.js";
|
|
2
|
+
import { o, n, A, r, q, p, i, j, C, l, D, G, e, H, c, M, k, m, d, P, S, h, T, t, b, s, v } from "./index-901cd86d.js";
|
|
3
3
|
import "react";
|
|
4
4
|
const SELECTION_TYPE = distEs6.SELECTION_TYPE;
|
|
5
5
|
export {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as inflate_1 } from "./pako.esm-68f84e2a.js";
|
|
2
|
-
import { g as getDefaultExportFromCjs, B as BaseDecoder, L as LercParameters, a as LercAddCompression } from "./index-
|
|
2
|
+
import { g as getDefaultExportFromCjs, B as BaseDecoder, L as LercParameters, a as LercAddCompression } from "./index-901cd86d.js";
|
|
3
3
|
import "react";
|
|
4
4
|
var LercDecode = { exports: {} };
|
|
5
5
|
(function(module) {
|
|
@@ -39,7 +39,7 @@ declare class BitmaskLayer extends BitmaskLayer_base {
|
|
|
39
39
|
* This function creates textures from the data
|
|
40
40
|
*/
|
|
41
41
|
dataToTexture(data: any, width: any, height: any): any;
|
|
42
|
-
multiSetsToTexture(multiFeatureValues: any, setColorValues: any, channelIsSetColorMode: any): any[];
|
|
42
|
+
multiSetsToTexture(multiFeatureValues: any, multiMatrixObsIndex: any, setColorValues: any, channelIsSetColorMode: any): any[];
|
|
43
43
|
}
|
|
44
44
|
declare namespace BitmaskLayer {
|
|
45
45
|
export const layerName: string;
|
|
@@ -107,7 +107,7 @@ declare namespace defaultProps {
|
|
|
107
107
|
const compare_7: boolean;
|
|
108
108
|
export { compare_7 as compare };
|
|
109
109
|
}
|
|
110
|
-
namespace
|
|
110
|
+
namespace multiMatrixObsIndex {
|
|
111
111
|
const type_8: string;
|
|
112
112
|
export { type_8 as type };
|
|
113
113
|
const value_7: null;
|
|
@@ -115,7 +115,7 @@ declare namespace defaultProps {
|
|
|
115
115
|
const compare_8: boolean;
|
|
116
116
|
export { compare_8 as compare };
|
|
117
117
|
}
|
|
118
|
-
namespace
|
|
118
|
+
namespace setColorValues {
|
|
119
119
|
const type_9: string;
|
|
120
120
|
export { type_9 as type };
|
|
121
121
|
const value_8: null;
|
|
@@ -123,7 +123,7 @@ declare namespace defaultProps {
|
|
|
123
123
|
const compare_9: boolean;
|
|
124
124
|
export { compare_9 as compare };
|
|
125
125
|
}
|
|
126
|
-
namespace
|
|
126
|
+
namespace channelFeatureValueColormaps {
|
|
127
127
|
const type_10: string;
|
|
128
128
|
export { type_10 as type };
|
|
129
129
|
const value_9: null;
|
|
@@ -131,7 +131,7 @@ declare namespace defaultProps {
|
|
|
131
131
|
const compare_10: boolean;
|
|
132
132
|
export { compare_10 as compare };
|
|
133
133
|
}
|
|
134
|
-
namespace
|
|
134
|
+
namespace channelFeatureValueColormapRanges {
|
|
135
135
|
const type_11: string;
|
|
136
136
|
export { type_11 as type };
|
|
137
137
|
const value_10: null;
|
|
@@ -139,7 +139,7 @@ declare namespace defaultProps {
|
|
|
139
139
|
const compare_11: boolean;
|
|
140
140
|
export { compare_11 as compare };
|
|
141
141
|
}
|
|
142
|
-
namespace
|
|
142
|
+
namespace channelIsStaticColorMode {
|
|
143
143
|
const type_12: string;
|
|
144
144
|
export { type_12 as type };
|
|
145
145
|
const value_11: null;
|
|
@@ -147,6 +147,14 @@ declare namespace defaultProps {
|
|
|
147
147
|
const compare_12: boolean;
|
|
148
148
|
export { compare_12 as compare };
|
|
149
149
|
}
|
|
150
|
+
namespace channelIsSetColorMode {
|
|
151
|
+
const type_13: string;
|
|
152
|
+
export { type_13 as type };
|
|
153
|
+
const value_12: null;
|
|
154
|
+
export { value_12 as value };
|
|
155
|
+
const compare_13: boolean;
|
|
156
|
+
export { compare_13 as compare };
|
|
157
|
+
}
|
|
150
158
|
}
|
|
151
159
|
import { GLSL_COLORMAP_DEFAULT } from "./constants.js";
|
|
152
160
|
//# sourceMappingURL=BitmaskLayerBeta.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitmaskLayerBeta.d.ts","sourceRoot":"","sources":["../src/BitmaskLayerBeta.js"],"names":[],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"BitmaskLayerBeta.d.ts","sourceRoot":"","sources":["../src/BitmaskLayerBeta.js"],"names":[],"mappings":";;;;;;;;;;;AAiEA;;;GAGG;AACH;;IAEE;;;;;;;MAYC;IAED;;;;MAIE;IACF,4CA0BC;IAED;;;;aA6CC;IAED,sBAuHC;IAED;;OAEG;IACH,uDAqBC;IAED,8HAuEC;CACF"}
|
|
@@ -20,6 +20,18 @@ function padWithDefault(arr, defaultValue, padWidth) {
|
|
|
20
20
|
function getColor(arr) {
|
|
21
21
|
return arr ? arr.map(v => v / 255) : [0, 0, 0];
|
|
22
22
|
}
|
|
23
|
+
function isEqualShallow(prevArr, nextArr) {
|
|
24
|
+
if (prevArr === nextArr) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(prevArr) && Array.isArray(nextArr)) {
|
|
28
|
+
if (prevArr.length === nextArr.length) {
|
|
29
|
+
return !prevArr.some((v, i) => (v !== nextArr[i] && ((!Array.isArray(v) && !Array.isArray(nextArr[i]))
|
|
30
|
+
|| (v.length > 0 || nextArr[i].length > 0))));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return prevArr === nextArr;
|
|
34
|
+
}
|
|
23
35
|
const defaultProps = {
|
|
24
36
|
channelStrokeWidths: { type: 'array', value: null, compare: true },
|
|
25
37
|
channelsFilled: { type: 'array', value: null, compare: true },
|
|
@@ -29,6 +41,7 @@ const defaultProps = {
|
|
|
29
41
|
colormap: { type: 'string', value: GLSL_COLORMAP_DEFAULT, compare: true },
|
|
30
42
|
expressionData: { type: 'object', value: null, compare: true },
|
|
31
43
|
multiFeatureValues: { type: 'array', value: null, compare: true },
|
|
44
|
+
multiMatrixObsIndex: { type: 'array', value: null, compare: true },
|
|
32
45
|
setColorValues: { type: 'array', value: null, compare: true },
|
|
33
46
|
channelFeatureValueColormaps: { type: 'array', value: null, compare: true },
|
|
34
47
|
channelFeatureValueColormapRanges: { type: 'array', value: null, compare: true },
|
|
@@ -83,13 +96,14 @@ export default class BitmaskLayer extends XRLayer {
|
|
|
83
96
|
}
|
|
84
97
|
updateState({ props, oldProps, changeFlags }) {
|
|
85
98
|
super.updateState({ props, oldProps, changeFlags });
|
|
86
|
-
if (props.multiFeatureValues
|
|
87
|
-
|| props.
|
|
88
|
-
|| props.
|
|
89
|
-
|
|
99
|
+
if (!isEqualShallow(props.multiFeatureValues, oldProps.multiFeatureValues)
|
|
100
|
+
|| !isEqualShallow(props.multiMatrixObsIndex, oldProps.multiMatrixObsIndex)
|
|
101
|
+
|| !isEqualShallow(props.setColorValues, oldProps.setColorValues)
|
|
102
|
+
|| !isEqualShallow(props.channelIsSetColorMode, oldProps.channelIsSetColorMode)) {
|
|
103
|
+
const { multiFeatureValues, multiMatrixObsIndex, setColorValues, channelIsSetColorMode, } = this.props;
|
|
90
104
|
// Use one expressionTex for all channels,
|
|
91
105
|
// using an offset mechanism.
|
|
92
|
-
const [valueTex, colorTex, valueTexOffsets, colorTexOffsets, valueTexHeight, colorTexHeight,] = this.multiSetsToTexture(multiFeatureValues, setColorValues, channelIsSetColorMode);
|
|
106
|
+
const [valueTex, colorTex, valueTexOffsets, colorTexOffsets, valueTexHeight, colorTexHeight,] = this.multiSetsToTexture(multiFeatureValues, multiMatrixObsIndex, setColorValues, channelIsSetColorMode);
|
|
93
107
|
this.setState({
|
|
94
108
|
valueTex,
|
|
95
109
|
colorTex,
|
|
@@ -196,9 +210,9 @@ export default class BitmaskLayer extends XRLayer {
|
|
|
196
210
|
type: GL.FLOAT,
|
|
197
211
|
});
|
|
198
212
|
}
|
|
199
|
-
multiSetsToTexture(multiFeatureValues, setColorValues, channelIsSetColorMode) {
|
|
213
|
+
multiSetsToTexture(multiFeatureValues, multiMatrixObsIndex, setColorValues, channelIsSetColorMode) {
|
|
200
214
|
const isWebGL2On = isWebGL2(this.context.gl);
|
|
201
|
-
const [totalData, valueTexHeight, indicesOffsets, totalColors, colorTexHeight, colorsOffsets,] = multiSetsToTextureData(multiFeatureValues, setColorValues, channelIsSetColorMode, MULTI_FEATURE_TEX_SIZE);
|
|
215
|
+
const [totalData, valueTexHeight, indicesOffsets, totalColors, colorTexHeight, colorsOffsets,] = multiSetsToTextureData(multiFeatureValues, multiMatrixObsIndex, setColorValues, channelIsSetColorMode, MULTI_FEATURE_TEX_SIZE);
|
|
202
216
|
return [
|
|
203
217
|
// Color indices texture
|
|
204
218
|
new Texture2D(this.context.gl, {
|
|
@@ -8,5 +8,5 @@
|
|
|
8
8
|
* will be determined by the length of the concatenated values.
|
|
9
9
|
* @returns
|
|
10
10
|
*/
|
|
11
|
-
export function multiSetsToTextureData(multiFeatureValues: array[], setColorValues: object[], channelIsSetColorMode: boolean[], texSize: number): (number | any[] | Uint8Array)[];
|
|
11
|
+
export function multiSetsToTextureData(multiFeatureValues: array[], multiMatrixObsIndex: any, setColorValues: object[], channelIsSetColorMode: boolean[], texSize: number): (number | any[] | Uint8Array)[];
|
|
12
12
|
//# sourceMappingURL=bitmask-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bitmask-utils.d.ts","sourceRoot":"","sources":["../src/bitmask-utils.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bitmask-utils.d.ts","sourceRoot":"","sources":["../src/bitmask-utils.js"],"names":[],"mappings":"AAcA;;;;;;;;;GASG;AACH,2DARW,OAAO,4CACP,MAAM,EAAE,yBACR,OAAO,EAAE,WAET,MAAM,mCAwHhB"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable radix */
|
|
2
|
+
/* eslint-disable-next-line camelcase */
|
|
3
|
+
import { extent, max as d3_max } from 'd3-array';
|
|
2
4
|
function normalize(arr) {
|
|
3
5
|
const [min, max] = extent(arr);
|
|
4
6
|
const ratio = 255 / (max - min);
|
|
@@ -15,16 +17,26 @@ function normalize(arr) {
|
|
|
15
17
|
* will be determined by the length of the concatenated values.
|
|
16
18
|
* @returns
|
|
17
19
|
*/
|
|
18
|
-
export function multiSetsToTextureData(multiFeatureValues, setColorValues, channelIsSetColorMode, texSize) {
|
|
20
|
+
export function multiSetsToTextureData(multiFeatureValues, multiMatrixObsIndex, setColorValues, channelIsSetColorMode, texSize) {
|
|
19
21
|
let totalValuesLength = 0;
|
|
20
22
|
let totalColorsLength = 0;
|
|
21
23
|
channelIsSetColorMode.forEach((isSetColorMode, channelIndex) => {
|
|
22
24
|
if (isSetColorMode) {
|
|
23
|
-
totalValuesLength += setColorValues[channelIndex]?.obsIndex?.length || 0;
|
|
25
|
+
// totalValuesLength += setColorValues[channelIndex]?.obsIndex?.length || 0;
|
|
24
26
|
totalColorsLength += (setColorValues[channelIndex]?.setColors?.length || 0) * 3;
|
|
27
|
+
// TODO: if we can assume values are monotonically increasing,
|
|
28
|
+
// we can just use the final array value arr[-1] directly as the max.
|
|
29
|
+
totalValuesLength += (setColorValues[channelIndex]?.obsIndex
|
|
30
|
+
? d3_max(setColorValues[channelIndex].obsIndex.map(d => parseInt(d)))
|
|
31
|
+
: 0);
|
|
25
32
|
}
|
|
26
33
|
else {
|
|
27
|
-
totalValuesLength += multiFeatureValues[channelIndex]?.length || 0;
|
|
34
|
+
// totalValuesLength += multiFeatureValues[channelIndex]?.length || 0;
|
|
35
|
+
// TODO: if we can assume values are monotonically increasing,
|
|
36
|
+
// we can just use the final array value arr[-1] directly as the max.
|
|
37
|
+
totalValuesLength += (multiMatrixObsIndex[channelIndex]
|
|
38
|
+
? d3_max(multiMatrixObsIndex[channelIndex].map(d => parseInt(d)))
|
|
39
|
+
: (multiFeatureValues[channelIndex]?.length || 0));
|
|
28
40
|
}
|
|
29
41
|
});
|
|
30
42
|
const valueTexHeight = Math.max(2, Math.ceil(totalValuesLength / texSize));
|
|
@@ -46,15 +58,27 @@ export function multiSetsToTextureData(multiFeatureValues, setColorValues, chann
|
|
|
46
58
|
let colorOffset = 0;
|
|
47
59
|
// Iterate over the data for each channel.
|
|
48
60
|
channelIsSetColorMode.forEach((isSetColorMode, channelIndex) => {
|
|
61
|
+
const matrixObsIndex = multiMatrixObsIndex[channelIndex];
|
|
62
|
+
// Assume the bitmask values correspond to the values in the matrixObsIndex (off by one).
|
|
63
|
+
const bitmaskValueIsIndex = matrixObsIndex === null;
|
|
49
64
|
if (isSetColorMode) {
|
|
50
65
|
const { setColorIndices, setColors, obsIndex } = setColorValues[channelIndex] || {};
|
|
51
66
|
if (setColorIndices && setColors && obsIndex) {
|
|
52
67
|
for (let i = 0; i < obsIndex.length; i++) {
|
|
68
|
+
let obsId = String(i + 1);
|
|
69
|
+
let obsI = i;
|
|
70
|
+
// TODO: this uses the matrixObsIndex to determine the value of the flag, is that correct?
|
|
71
|
+
if (!bitmaskValueIsIndex) {
|
|
72
|
+
// We cannot assume that the values in the bitmask
|
|
73
|
+
// correspond to the values in the matrixObsIndex.
|
|
74
|
+
obsId = obsIndex[i];
|
|
75
|
+
obsI = parseInt(obsId) - 1;
|
|
76
|
+
}
|
|
53
77
|
// We add one here to account for i being 0-based but the pixel values being 1-based
|
|
54
78
|
// (to account for zero indicating the background of the segmentation bitmask).
|
|
55
|
-
const colorIndex = setColorIndices.get(
|
|
79
|
+
const colorIndex = setColorIndices.get(obsId);
|
|
56
80
|
// Add one to the color index, so that we can use zero to indicate a "null" set color.
|
|
57
|
-
totalData[indexOffset +
|
|
81
|
+
totalData[indexOffset + obsI] = colorIndex === undefined ? 0 : colorIndex + 1;
|
|
58
82
|
}
|
|
59
83
|
for (let i = 0; i < setColors.length; i++) {
|
|
60
84
|
const { color: [r, g, b] } = setColors[i];
|
|
@@ -70,8 +94,20 @@ export function multiSetsToTextureData(multiFeatureValues, setColorValues, chann
|
|
|
70
94
|
}
|
|
71
95
|
else {
|
|
72
96
|
const featureArr = multiFeatureValues[channelIndex];
|
|
73
|
-
|
|
74
|
-
|
|
97
|
+
const normalizedFeatureArr = normalize(featureArr);
|
|
98
|
+
if (!bitmaskValueIsIndex && matrixObsIndex) {
|
|
99
|
+
// We cannot assume that the values in the bitmask
|
|
100
|
+
// correspond to the values in the matrixObsIndex.
|
|
101
|
+
for (let i = 0; i < matrixObsIndex.length; i++) {
|
|
102
|
+
const obsId = matrixObsIndex[i];
|
|
103
|
+
const obsI = parseInt(obsId) - 1;
|
|
104
|
+
totalData[indexOffset + obsI] = normalizedFeatureArr[i];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
// TODO: are these values always already normalized?
|
|
109
|
+
totalData.set(normalizedFeatureArr, indexOffset);
|
|
110
|
+
}
|
|
75
111
|
indicesOffsets.push(indexOffset);
|
|
76
112
|
indexOffset += featureArr.length;
|
|
77
113
|
// Add a color offset so that the number of offsets still equals the number of channels.
|
|
@@ -7,6 +7,10 @@ describe('bitmask utils', () => {
|
|
|
7
7
|
[1, 2, 3, 255, 1000],
|
|
8
8
|
[10, 20, 30], // 3 expression values, one per glomerulus
|
|
9
9
|
];
|
|
10
|
+
const multiObsIndex = [
|
|
11
|
+
['1', '2', '3', '4', '5'],
|
|
12
|
+
['1', '2', '3'], // 3 glomeruli
|
|
13
|
+
];
|
|
10
14
|
const setColorValues = [
|
|
11
15
|
{
|
|
12
16
|
setColorIndices: (new Map([
|
|
@@ -39,7 +43,7 @@ describe('bitmask utils', () => {
|
|
|
39
43
|
true,
|
|
40
44
|
false,
|
|
41
45
|
];
|
|
42
|
-
const [totalData, valueTexHeight, indicesOffsets, totalColors, colorTexHeight, colorsOffsets,] = multiSetsToTextureData(multiFeatureValues, setColorValues, channelIsSetColorMode, 10);
|
|
46
|
+
const [totalData, valueTexHeight, indicesOffsets, totalColors, colorTexHeight, colorsOffsets,] = multiSetsToTextureData(multiFeatureValues, multiObsIndex, setColorValues, channelIsSetColorMode, 10);
|
|
43
47
|
expect(valueTexHeight).toEqual(2);
|
|
44
48
|
expect(colorTexHeight).toEqual(2);
|
|
45
49
|
expect(indicesOffsets).toEqual([0, 5]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitessce/gl",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.3",
|
|
4
4
|
"author": "Gehlenborg Lab",
|
|
5
5
|
"homepage": "http://vitessce.io",
|
|
6
6
|
"repository": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"math.gl": "^3.5.6",
|
|
53
53
|
"mathjs": "^9.2.0",
|
|
54
54
|
"nebula.gl": "0.23.8",
|
|
55
|
-
"@vitessce/utils": "3.3.
|
|
55
|
+
"@vitessce/utils": "3.3.3"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"glsl-colormap": "^1.0.1"
|
package/src/BitmaskLayerBeta.js
CHANGED
|
@@ -29,6 +29,22 @@ function getColor(arr) {
|
|
|
29
29
|
return arr ? arr.map(v => v / 255) : [0, 0, 0];
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
function isEqualShallow(prevArr, nextArr) {
|
|
33
|
+
if (prevArr === nextArr) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(prevArr) && Array.isArray(nextArr)) {
|
|
37
|
+
if (prevArr.length === nextArr.length) {
|
|
38
|
+
return !prevArr.some((v, i) => (v !== nextArr[i] && (
|
|
39
|
+
(!Array.isArray(v) && !Array.isArray(nextArr[i]))
|
|
40
|
+
|| (v.length > 0 || nextArr[i].length > 0)
|
|
41
|
+
)
|
|
42
|
+
));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return prevArr === nextArr;
|
|
46
|
+
}
|
|
47
|
+
|
|
32
48
|
|
|
33
49
|
const defaultProps = {
|
|
34
50
|
channelStrokeWidths: { type: 'array', value: null, compare: true },
|
|
@@ -39,6 +55,7 @@ const defaultProps = {
|
|
|
39
55
|
colormap: { type: 'string', value: GLSL_COLORMAP_DEFAULT, compare: true },
|
|
40
56
|
expressionData: { type: 'object', value: null, compare: true },
|
|
41
57
|
multiFeatureValues: { type: 'array', value: null, compare: true },
|
|
58
|
+
multiMatrixObsIndex: { type: 'array', value: null, compare: true },
|
|
42
59
|
setColorValues: { type: 'array', value: null, compare: true },
|
|
43
60
|
channelFeatureValueColormaps: { type: 'array', value: null, compare: true },
|
|
44
61
|
channelFeatureValueColormapRanges: { type: 'array', value: null, compare: true },
|
|
@@ -102,11 +119,14 @@ export default class BitmaskLayer extends XRLayer {
|
|
|
102
119
|
updateState({ props, oldProps, changeFlags }) {
|
|
103
120
|
super.updateState({ props, oldProps, changeFlags });
|
|
104
121
|
if (
|
|
105
|
-
props.multiFeatureValues
|
|
106
|
-
|| props.
|
|
107
|
-
|| props.
|
|
122
|
+
!isEqualShallow(props.multiFeatureValues, oldProps.multiFeatureValues)
|
|
123
|
+
|| !isEqualShallow(props.multiMatrixObsIndex, oldProps.multiMatrixObsIndex)
|
|
124
|
+
|| !isEqualShallow(props.setColorValues, oldProps.setColorValues)
|
|
125
|
+
|| !isEqualShallow(props.channelIsSetColorMode, oldProps.channelIsSetColorMode)
|
|
108
126
|
) {
|
|
109
|
-
const {
|
|
127
|
+
const {
|
|
128
|
+
multiFeatureValues, multiMatrixObsIndex, setColorValues, channelIsSetColorMode,
|
|
129
|
+
} = this.props;
|
|
110
130
|
// Use one expressionTex for all channels,
|
|
111
131
|
// using an offset mechanism.
|
|
112
132
|
const [
|
|
@@ -118,6 +138,7 @@ export default class BitmaskLayer extends XRLayer {
|
|
|
118
138
|
colorTexHeight,
|
|
119
139
|
] = this.multiSetsToTexture(
|
|
120
140
|
multiFeatureValues,
|
|
141
|
+
multiMatrixObsIndex,
|
|
121
142
|
setColorValues,
|
|
122
143
|
channelIsSetColorMode,
|
|
123
144
|
);
|
|
@@ -289,7 +310,12 @@ export default class BitmaskLayer extends XRLayer {
|
|
|
289
310
|
});
|
|
290
311
|
}
|
|
291
312
|
|
|
292
|
-
multiSetsToTexture(
|
|
313
|
+
multiSetsToTexture(
|
|
314
|
+
multiFeatureValues,
|
|
315
|
+
multiMatrixObsIndex,
|
|
316
|
+
setColorValues,
|
|
317
|
+
channelIsSetColorMode,
|
|
318
|
+
) {
|
|
293
319
|
const isWebGL2On = isWebGL2(this.context.gl);
|
|
294
320
|
|
|
295
321
|
const [
|
|
@@ -301,6 +327,7 @@ export default class BitmaskLayer extends XRLayer {
|
|
|
301
327
|
colorsOffsets,
|
|
302
328
|
] = multiSetsToTextureData(
|
|
303
329
|
multiFeatureValues,
|
|
330
|
+
multiMatrixObsIndex,
|
|
304
331
|
setColorValues,
|
|
305
332
|
channelIsSetColorMode,
|
|
306
333
|
MULTI_FEATURE_TEX_SIZE,
|
package/src/bitmask-utils.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable radix */
|
|
2
|
+
/* eslint-disable-next-line camelcase */
|
|
3
|
+
import { extent, max as d3_max } from 'd3-array';
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
function normalize(arr) {
|
|
@@ -21,17 +23,33 @@ function normalize(arr) {
|
|
|
21
23
|
* @returns
|
|
22
24
|
*/
|
|
23
25
|
export function multiSetsToTextureData(
|
|
24
|
-
multiFeatureValues, setColorValues, channelIsSetColorMode, texSize,
|
|
26
|
+
multiFeatureValues, multiMatrixObsIndex, setColorValues, channelIsSetColorMode, texSize,
|
|
25
27
|
) {
|
|
26
28
|
let totalValuesLength = 0;
|
|
27
29
|
let totalColorsLength = 0;
|
|
28
30
|
|
|
29
31
|
channelIsSetColorMode.forEach((isSetColorMode, channelIndex) => {
|
|
30
32
|
if (isSetColorMode) {
|
|
31
|
-
totalValuesLength += setColorValues[channelIndex]?.obsIndex?.length || 0;
|
|
33
|
+
// totalValuesLength += setColorValues[channelIndex]?.obsIndex?.length || 0;
|
|
32
34
|
totalColorsLength += (setColorValues[channelIndex]?.setColors?.length || 0) * 3;
|
|
35
|
+
|
|
36
|
+
// TODO: if we can assume values are monotonically increasing,
|
|
37
|
+
// we can just use the final array value arr[-1] directly as the max.
|
|
38
|
+
totalValuesLength += (
|
|
39
|
+
setColorValues[channelIndex]?.obsIndex
|
|
40
|
+
? d3_max(setColorValues[channelIndex].obsIndex.map(d => parseInt(d)))
|
|
41
|
+
: 0
|
|
42
|
+
);
|
|
33
43
|
} else {
|
|
34
|
-
totalValuesLength += multiFeatureValues[channelIndex]?.length || 0;
|
|
44
|
+
// totalValuesLength += multiFeatureValues[channelIndex]?.length || 0;
|
|
45
|
+
|
|
46
|
+
// TODO: if we can assume values are monotonically increasing,
|
|
47
|
+
// we can just use the final array value arr[-1] directly as the max.
|
|
48
|
+
totalValuesLength += (
|
|
49
|
+
multiMatrixObsIndex[channelIndex]
|
|
50
|
+
? d3_max(multiMatrixObsIndex[channelIndex].map(d => parseInt(d)))
|
|
51
|
+
: (multiFeatureValues[channelIndex]?.length || 0)
|
|
52
|
+
);
|
|
35
53
|
}
|
|
36
54
|
});
|
|
37
55
|
|
|
@@ -56,15 +74,27 @@ export function multiSetsToTextureData(
|
|
|
56
74
|
let colorOffset = 0;
|
|
57
75
|
// Iterate over the data for each channel.
|
|
58
76
|
channelIsSetColorMode.forEach((isSetColorMode, channelIndex) => {
|
|
77
|
+
const matrixObsIndex = multiMatrixObsIndex[channelIndex];
|
|
78
|
+
// Assume the bitmask values correspond to the values in the matrixObsIndex (off by one).
|
|
79
|
+
const bitmaskValueIsIndex = matrixObsIndex === null;
|
|
59
80
|
if (isSetColorMode) {
|
|
60
81
|
const { setColorIndices, setColors, obsIndex } = setColorValues[channelIndex] || {};
|
|
61
82
|
if (setColorIndices && setColors && obsIndex) {
|
|
62
83
|
for (let i = 0; i < obsIndex.length; i++) {
|
|
84
|
+
let obsId = String(i + 1);
|
|
85
|
+
let obsI = i;
|
|
86
|
+
// TODO: this uses the matrixObsIndex to determine the value of the flag, is that correct?
|
|
87
|
+
if (!bitmaskValueIsIndex) {
|
|
88
|
+
// We cannot assume that the values in the bitmask
|
|
89
|
+
// correspond to the values in the matrixObsIndex.
|
|
90
|
+
obsId = obsIndex[i];
|
|
91
|
+
obsI = parseInt(obsId) - 1;
|
|
92
|
+
}
|
|
63
93
|
// We add one here to account for i being 0-based but the pixel values being 1-based
|
|
64
94
|
// (to account for zero indicating the background of the segmentation bitmask).
|
|
65
|
-
const colorIndex = setColorIndices.get(
|
|
95
|
+
const colorIndex = setColorIndices.get(obsId);
|
|
66
96
|
// Add one to the color index, so that we can use zero to indicate a "null" set color.
|
|
67
|
-
totalData[indexOffset +
|
|
97
|
+
totalData[indexOffset + obsI] = colorIndex === undefined ? 0 : colorIndex + 1;
|
|
68
98
|
}
|
|
69
99
|
for (let i = 0; i < setColors.length; i++) {
|
|
70
100
|
const { color: [r, g, b] } = setColors[i];
|
|
@@ -79,8 +109,20 @@ export function multiSetsToTextureData(
|
|
|
79
109
|
colorOffset += (setColors?.length || 0);
|
|
80
110
|
} else {
|
|
81
111
|
const featureArr = multiFeatureValues[channelIndex];
|
|
82
|
-
|
|
83
|
-
|
|
112
|
+
const normalizedFeatureArr = normalize(featureArr);
|
|
113
|
+
|
|
114
|
+
if (!bitmaskValueIsIndex && matrixObsIndex) {
|
|
115
|
+
// We cannot assume that the values in the bitmask
|
|
116
|
+
// correspond to the values in the matrixObsIndex.
|
|
117
|
+
for (let i = 0; i < matrixObsIndex.length; i++) {
|
|
118
|
+
const obsId = matrixObsIndex[i];
|
|
119
|
+
const obsI = parseInt(obsId) - 1;
|
|
120
|
+
totalData[indexOffset + obsI] = normalizedFeatureArr[i];
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
// TODO: are these values always already normalized?
|
|
124
|
+
totalData.set(normalizedFeatureArr, indexOffset);
|
|
125
|
+
}
|
|
84
126
|
indicesOffsets.push(indexOffset);
|
|
85
127
|
indexOffset += featureArr.length;
|
|
86
128
|
// Add a color offset so that the number of offsets still equals the number of channels.
|
|
@@ -11,6 +11,11 @@ describe('bitmask utils', () => {
|
|
|
11
11
|
[10, 20, 30], // 3 expression values, one per glomerulus
|
|
12
12
|
];
|
|
13
13
|
|
|
14
|
+
const multiObsIndex = [
|
|
15
|
+
['1', '2', '3', '4', '5'], // 5 cells
|
|
16
|
+
['1', '2', '3'], // 3 glomeruli
|
|
17
|
+
];
|
|
18
|
+
|
|
14
19
|
const setColorValues = [
|
|
15
20
|
{
|
|
16
21
|
setColorIndices: (new Map([
|
|
@@ -54,6 +59,7 @@ describe('bitmask utils', () => {
|
|
|
54
59
|
colorsOffsets,
|
|
55
60
|
] = multiSetsToTextureData(
|
|
56
61
|
multiFeatureValues,
|
|
62
|
+
multiObsIndex,
|
|
57
63
|
setColorValues,
|
|
58
64
|
channelIsSetColorMode,
|
|
59
65
|
10,
|