Skip to content

Commit

Permalink
Expose experimental model_matrix API to allow for layer transformat…
Browse files Browse the repository at this point in the history
…ions (#79)

* Expose model matrix as query param and to imjoy API

* disable prettier for multiline type

* expose row-major matrix
  • Loading branch information
manzt authored Mar 8, 2021
1 parent 6e5c701 commit f7c6bc9
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 3 deletions.
7 changes: 6 additions & 1 deletion src/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
MAGENTA_GREEN,
MAX_CHANNELS,
open,
parseMatrix,
range,
RGB,
} from './utils';
Expand All @@ -45,6 +46,7 @@ function loadSingleChannel(config: SingleChannelConfig, data: ZarrPixelSource<st
names: ['channel_0'],
contrast_limits: [contrast_limits ?? [0, max]],
visibilities: [visibility ?? true],
model_matrix: parseMatrix(config.model_matrix),
defaults: {
selection: Array(data[0].shape.length).fill(0),
colormap,
Expand All @@ -55,7 +57,7 @@ function loadSingleChannel(config: SingleChannelConfig, data: ZarrPixelSource<st
}

function loadMultiChannel(config: MultichannelConfig, data: ZarrPixelSource<string[]>[], max: number): SourceData {
const { names, channel_axis, name, opacity = 1, colormap = '' } = config;
const { names, channel_axis, name, model_matrix, opacity = 1, colormap = '' } = config;
let { contrast_limits, visibilities, colors } = config;

const n = data[0].shape[channel_axis as number];
Expand Down Expand Up @@ -104,6 +106,7 @@ function loadMultiChannel(config: MultichannelConfig, data: ZarrPixelSource<stri
names: names ?? range(n).map((i) => `channel_${i}`),
contrast_limits: contrast_limits ?? Array(n).fill([0, max]),
visibilities,
model_matrix: parseMatrix(config.model_matrix),
defaults: {
selection: Array(data[0].shape.length).fill(0),
colormap,
Expand Down Expand Up @@ -181,6 +184,7 @@ export function initLayerStateFromSource(sourceData: SourceData, layerId: string
colors,
visibilities,
contrast_limits,
model_matrix,
defaults,
// Grid
loaders,
Expand Down Expand Up @@ -231,6 +235,7 @@ export function initLayerStateFromSource(sourceData: SourceData, layerId: string
channelIsOn,
opacity,
colormap,
modelMatrix: model_matrix,
onClick,
},
on: true,
Expand Down
5 changes: 4 additions & 1 deletion src/ome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ZarrPixelSource } from '@hms-dbmi/viv';
import pMap from 'p-map';
import { Group as ZarrGroup, HTTPStore, openGroup, ZarrArray } from 'zarr';
import type { ImageLayerConfig, SourceData } from './state';
import { join, loadMultiscales, guessTileSize, range } from './utils';
import { join, loadMultiscales, guessTileSize, range, parseMatrix } from './utils';

export async function loadWell(config: ImageLayerConfig, grp: ZarrGroup, wellAttrs: Ome.Well): Promise<SourceData> {
// Can filter Well fields by URL query ?acquisition=ID
Expand Down Expand Up @@ -64,6 +64,7 @@ export async function loadWell(config: ImageLayerConfig, grp: ZarrGroup, wellAtt
loaders,
...meta,
loader: [loaders[0].loader],
model_matrix: parseMatrix(config.model_matrix),
defaults: {
selection: meta.defaultSelection,
colormap: config.colormap ?? '',
Expand Down Expand Up @@ -154,6 +155,7 @@ export async function loadPlate(config: ImageLayerConfig, grp: ZarrGroup, plateA
loaders,
...meta,
loader: [loaders[0].loader],
model_matrix: parseMatrix(config.model_matrix),
defaults: {
selection: meta.defaultSelection,
colormap: config.colormap ?? '',
Expand Down Expand Up @@ -199,6 +201,7 @@ export async function loadOmeroMultiscales(
return {
loader: loader,
name: meta.name ?? name,
model_matrix: parseMatrix(config.model_matrix),
defaults: {
selection: meta.defaultSelection,
colormap,
Expand Down
5 changes: 4 additions & 1 deletion src/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { ZarrArray } from 'zarr';
import type { ImageLayer, MultiscaleImageLayer, ZarrPixelSource } from '@hms-dbmi/viv';
import type { VivLayerProps } from 'viv-layers';
import type GridLayer from './gridLayer';
import { Matrix4 } from 'math.gl';

export const DEFAULT_VIEW_STATE = { zoom: 0, target: [0, 0, 0], default: true };
export const DEFAULT_LAYER_PROPS = {
Expand All @@ -24,6 +25,7 @@ interface BaseConfig {
colormap?: string;
opacity?: number;
acquisition?: string;
model_matrix?: string | number[];
onClick?: (e: any) => void;
}

Expand Down Expand Up @@ -68,6 +70,7 @@ export type SourceData = {
colormap: string;
opacity: number;
};
model_matrix: Matrix4;
axis_labels: string[];
onClick?: (e: any) => void;
};
Expand Down Expand Up @@ -105,7 +108,7 @@ export const layerStateFamily = atomFamily({
key: 'layerStateFamily',
default: (id: string): LayerState => ({
Layer: null,
layerProps: { id, ...DEFAULT_LAYER_PROPS },
layerProps: { id, modelMatrix: new Matrix4(), ...DEFAULT_LAYER_PROPS },
on: false,
}),
});
Expand Down
25 changes: 25 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ContainsArrayError, HTTPStore, openArray, openGroup, ZarrArray } from 'zarr';
import type { Group as ZarrGroup } from 'zarr';
import { Matrix4 } from 'math.gl';

export const MAX_CHANNELS = 6;

Expand Down Expand Up @@ -105,3 +106,27 @@ export function fitBounds(
const zoom = Math.min(maxZoom, Math.log2(Math.min(scaleX, scaleY)));
return { zoom, target: [width / 2, height / 2, 0] };
}

// prettier-ignore
type Array16 = [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number];

function isArray16(o: unknown): o is Array16 {
if (!Array.isArray(o)) return false;
return o.length === 16 && o.every((i) => typeof i === 'number');
}

export function parseMatrix(model_matrix?: string | number[]): Matrix4 {
if (!model_matrix) return new Matrix4();
const matrix = new Matrix4();
try {
const arr = typeof model_matrix === 'string' ? JSON.parse(model_matrix) : model_matrix;
if (!isArray16(arr)) {
throw Error('Invalid modelMatrix size. Must be 16.');
}
matrix.setRowMajor(...arr);
} catch {
const msg = `Failed to parse modelMatrix. Got ${JSON.stringify(model_matrix)}, using identity.`;
console.warn(msg);
}
return matrix;
}
2 changes: 2 additions & 0 deletions types/viv.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
declare module 'viv-layers' {
import type { Layer } from '@deck.gl/core';
import type { Matrix4 } from 'math.gl';
import type { LayerProps } from '@deck.gl/core/lib/layer';
import type { PixelSource } from '@hms-dbmi/viv';

Expand All @@ -9,5 +10,6 @@ declare module 'viv-layers' {
sliderValues: number[][];
channelIsOn: boolean[];
colormap: null | string;
modelMatrix: Matrix4;
};
}

0 comments on commit f7c6bc9

Please sign in to comment.