Skip to content

Commit c547507

Browse files
committed
Better support for non-aligned axes
1 parent 7650b7d commit c547507

File tree

2 files changed

+49
-16
lines changed

2 files changed

+49
-16
lines changed

src/io.ts

+35-16
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,8 @@ export function initLayerStateFromSource(source: SourceData & { id: string }): L
230230
lut: label.lut,
231231
})),
232232
transformSourceSelection: getTransformSourceSelectionFromLabels(
233-
source.labels.map((label) => label.loader[0].labels),
234-
source.loader[0].labels,
233+
source.labels.map((label) => label.loader[0]),
234+
source.loader[0],
235235
),
236236
};
237237
}
@@ -247,25 +247,44 @@ export function initLayerStateFromSource(source: SourceData & { id: string }): L
247247
};
248248
}
249249

250-
function getTransformSourceSelectionFromLabels(labelAxesNames: Array<Array<string>>, sourceAxesNames: Array<string>) {
250+
function getTransformSourceSelectionFromLabels(
251+
labelsResolutions: Array<{ shape: Array<number>; labels: Array<string> }>,
252+
source: { shape: Array<number>; labels: Array<string> },
253+
) {
254+
// representative source for labels
255+
const labelsSource = labelsResolutions[0];
251256
utils.assert(
252-
labelAxesNames[0].every((name) => sourceAxesNames.includes(name)),
253-
() =>
254-
`Label axes names be a subset of source. Source: ${JSON.stringify(sourceAxesNames)} Labels: ${JSON.stringify(labelAxesNames)}`,
257+
source.shape.length === source.labels.length,
258+
`Image source axes and shape are not same rank. Got ${JSON.stringify(source)}`,
255259
);
256-
for (const axes of labelAxesNames) {
260+
utils.assert(
261+
labelsSource.shape.length === labelsSource.labels.length,
262+
`Label axes and shape are not same rank. Got ${JSON.stringify(labelsSource)}`,
263+
);
264+
utils.assert(
265+
utils.zip(labelsSource.labels, source.labels).every(([a, b]) => a === b),
266+
`Label axes MUST be a subset of source. Source: ${JSON.stringify(source.labels)} Labels: ${JSON.stringify(labelsSource.labels)}`,
267+
);
268+
for (const { labels, shape } of labelsResolutions.slice(1)) {
257269
utils.assert(
258-
axes.every((name, i) => name === labelAxesNames[0][i]),
259-
() => {
260-
const mismatchedLabels = labelAxesNames.map((axes) => ({ axes }));
261-
return `Error: All labels must share the same axes. Mismatched labels found: ${JSON.stringify(mismatchedLabels)}`;
262-
},
270+
utils.zip(labels, labelsSource.labels).every(([a, b]) => a === b),
271+
`Error: All labels must share the same axes. Mismatched labels found: ${JSON.stringify(labels)}`,
272+
);
273+
utils.assert(
274+
utils.zip(shape, labelsSource.shape).every(([a, b]) => a === b),
275+
`Error: All labels must share the same shape. Mismatched labels found: ${JSON.stringify(shape)}`,
263276
);
264277
}
278+
// Identify labels that should always map to 0, regardless of the source selection.
279+
const excludeFromTransformedSelection = new Set(
280+
utils
281+
.zip(labelsSource.labels, labelsSource.shape)
282+
.filter(([_, size]) => size === 1)
283+
.map(([name, _]) => name),
284+
);
265285
return (sourceSelection: Array<number>): Array<number> => {
266-
return labelAxesNames[0].map((name) => {
267-
if (name === "c") return 0; // skip
268-
return sourceSelection[sourceAxesNames.indexOf(name)];
269-
});
286+
return labelsSource.labels.map((name) =>
287+
excludeFromTransformedSelection.has(name) ? 0 : sourceSelection[source.labels.indexOf(name)],
288+
);
270289
};
271290
}

src/utils.ts

+14
Original file line numberDiff line numberDiff line change
@@ -577,3 +577,17 @@ export function coordinateTransformationsToMatrix(multiscales: Array<Ome.Multisc
577577

578578
return mat;
579579
}
580+
581+
/**
582+
* Builds N-tuples of elements from the given N arrays with matching indices,
583+
* stopping when the smallest array's end is reached.
584+
*/
585+
export function zip<T extends unknown[]>(...arrays: { [K in keyof T]: ReadonlyArray<T[K]> }): T[] {
586+
const minLength = arrays.reduce((minLength, arr) => Math.min(arr.length, minLength), Number.POSITIVE_INFINITY);
587+
const result: T[] = new Array(minLength);
588+
for (let i = 0; i < minLength; i += 1) {
589+
const arr = arrays.map((it) => it[i]);
590+
result[i] = arr as T;
591+
}
592+
return result;
593+
}

0 commit comments

Comments
 (0)