Skip to content

Commit

Permalink
Add attrs util. Remove generic axes util.
Browse files Browse the repository at this point in the history
  • Loading branch information
manzt committed Aug 10, 2021
1 parent 452a63a commit 96a9271
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 22 deletions.
9 changes: 5 additions & 4 deletions src/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
COLORS,
CYMRGB,
getAxisLabels,
getAxisLabelsFromMultiscales,
guessTileSize,
hexToRGB,
loadMultiscales,
Expand Down Expand Up @@ -108,7 +107,6 @@ function loadMultiChannel(config: MultichannelConfig, data: ZarrPixelSource<stri
export async function createSourceData(config: ImageLayerConfig): Promise<SourceData> {
const node = await open(config.source);
let data: ZarrArray[];
let axis_labels;

if (node instanceof ZarrGroup) {
const attrs = (await node.attrs.asObject()) as Ome.Attrs;
Expand Down Expand Up @@ -141,12 +139,15 @@ export async function createSourceData(config: ImageLayerConfig): Promise<Source
}

data = await loadMultiscales(node, attrs.multiscales);
axis_labels = getAxisLabelsFromMultiscales(attrs);
if (!config.axis_labels) {
// Update config axis_labels if present in multiscales
config.axis_labels = attrs.multiscales[0].axes;
}
} else {
data = [node];
}

const labels = getAxisLabels(data[0], axis_labels || config.axis_labels);
const labels = getAxisLabels(data[0], config.axis_labels);
const tileSize = guessTileSize(data[0]);
const loader = data.map((d) => new ZarrPixelSource(d, labels, tileSize));
const [base] = loader;
Expand Down
21 changes: 10 additions & 11 deletions 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, getAxisLabelsFromMultiscales, guessTileSize, range, parseMatrix } from './utils';
import { join, loadMultiscales, guessTileSize, range, parseMatrix, attrs } 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 All @@ -28,7 +28,7 @@ export async function loadWell(config: ImageLayerConfig, grp: ZarrGroup, wellAtt
// Need to get acquisitions metadata from parent Plate
const plateUrl = grp.store.url.replace(`${row}/${col}`, '');
const plate = await openGroup(new HTTPStore(plateUrl));
const plateAttrs = (await plate.attrs.asObject()) as { plate: Ome.Plate };
const plateAttrs = await attrs<{ plate: Ome.Plate }>(plate);
acquisitions = plateAttrs?.plate?.acquisitions ?? [];

// filter imagePaths by acquisition
Expand All @@ -42,7 +42,7 @@ export async function loadWell(config: ImageLayerConfig, grp: ZarrGroup, wellAtt
const rows = Math.ceil(imgPaths.length / cols);

// Use first image for rendering settings, resolutions etc.
const imgAttrs = (await grp.getItem(imgPaths[0]).then((g) => g.attrs.asObject())) as Ome.Attrs;
const imgAttrs = await attrs<Ome.Attrs>(grp, imgPaths[0]);
if (!('omero' in imgAttrs)) {
throw Error('Path for image is not valid.');
}
Expand All @@ -51,7 +51,7 @@ export async function loadWell(config: ImageLayerConfig, grp: ZarrGroup, wellAtt
// Create loader for every Image.
const promises = imgPaths.map((p) => grp.getItem(join(p, resolution)));
const data = (await Promise.all(promises)) as ZarrArray[];
const axis_labels = getOmeAxisLabels(imgAttrs);
const axis_labels = getOmeAxisLabels(imgAttrs.multiscales);
const meta = parseOmeroMeta(imgAttrs.omero, axis_labels);

const tileSize = guessTileSize(data[0]);
Expand Down Expand Up @@ -119,13 +119,13 @@ export async function loadPlate(config: ImageLayerConfig, grp: ZarrGroup, plateA
const wellPaths = plateAttrs.wells.map((well) => well.path);

// Use first image as proxy for others.
const wellAttrs = (await grp.getItem(wellPaths[0]).then((g) => g.attrs.asObject())) as Ome.Attrs;
const wellAttrs = await attrs<Ome.Attrs>(grp, wellPaths[0]);
if (!('well' in wellAttrs)) {
throw Error('Path for image is not valid, not a well.');
}

const imgPath = wellAttrs.well.images[0].path;
const imgAttrs = (await grp.getItem(join(wellPaths[0], imgPath)).then((g) => g.attrs.asObject())) as Ome.Attrs;
const imgAttrs = await attrs<Ome.Attrs>(grp, join(wellPaths[0], imgPath));
if (!('omero' in imgAttrs)) {
throw Error('Path for image is not valid.');
}
Expand All @@ -141,7 +141,7 @@ export async function loadPlate(config: ImageLayerConfig, grp: ZarrGroup, plateA
{ concurrency: 10 }
);
const data = await Promise.all(promises);
const axis_labels = getOmeAxisLabels(imgAttrs);
const axis_labels = getOmeAxisLabels(imgAttrs.multiscales);
const meta = parseOmeroMeta(imgAttrs.omero, axis_labels);
const tileSize = guessTileSize(data[0][1]);
const loaders = data.map((d) => {
Expand Down Expand Up @@ -200,7 +200,7 @@ export async function loadOmeroMultiscales(
): Promise<SourceData> {
const { name, opacity = 1, colormap = '' } = config;
const data = await loadMultiscales(grp, attrs.multiscales);
const axis_labels = getOmeAxisLabels(attrs);
const axis_labels = getOmeAxisLabels(attrs.multiscales);
const meta = parseOmeroMeta(attrs.omero, axis_labels);
const tileSize = guessTileSize(data[0]);

Expand Down Expand Up @@ -252,8 +252,7 @@ function parseOmeroMeta({ rdefs, channels, name }: Ome.Omero, axis_labels: strin
};
}

function getOmeAxisLabels(attrs: Ome.Attrs): [...string[], 'y', 'x'] {
let axis_labels = getAxisLabelsFromMultiscales(attrs);
function getOmeAxisLabels(multiscales: Ome.Multiscale[]): [...string[], 'y', 'x'] {
const default_axes = ['t', 'c', 'z', 'y', 'x']; // v0.1 & v0.2
return (axis_labels || default_axes) as [...string[], 'y', 'x'];
return (multiscales[0].axes || default_axes) as [...string[], 'y', 'x'];
}
11 changes: 5 additions & 6 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ export const MAGENTA_GREEN = [COLORS.magenta, COLORS.green];
export const RGB = [COLORS.red, COLORS.green, COLORS.blue];
export const CYMRGB = Object.values(COLORS).slice(0, -2);

export async function attrs<T>(grp: ZarrGroup, path?: string) {
const g = path ? await grp.getItem(path) : grp;
return g.attrs.asObject() as Promise<T>;
}

async function normalizeStore(source: string | Store) {
if (typeof source === 'string') {
let store: AsyncStore<ArrayBuffer>;
Expand Down Expand Up @@ -100,12 +105,6 @@ export function getAxisLabels(arr: ZarrArray, axis_labels?: string[]): [...strin
return axis_labels as [...string[], 'y', 'x'];
}

export function getAxisLabelsFromMultiscales(attrs) {
if ('multiscales' in attrs && attrs.multiscales?.[0]?.axes) {
return attrs.multiscales[0].axes;
}
}

export function isInterleaved(shape: number[]) {
const lastDimSize = shape[shape.length - 1];
return lastDimSize === 3 || lastDimSize === 4;
Expand Down
2 changes: 1 addition & 1 deletion types/ome.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
declare module Ome {
type Version = '0.1';
type Version = '0.1' | '0.2' | '0.3';

interface Channel {
active: boolean;
Expand Down

0 comments on commit 96a9271

Please sign in to comment.