Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V05 dev2 #36

Merged
merged 44 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
425c53f
Handle 404 for /zarr.json AND /.zattrs
will-moore Jun 7, 2024
d709352
Load v0.5 schemas from github PR branch
will-moore Jun 7, 2024
23d9b26
Fix display of Array info for Zarr v3
will-moore Jun 12, 2024
190c0b7
Fix display of .zarray .zattrs and zarr.json in UI
will-moore Jun 12, 2024
6940281
Update loading of zarr chunks with zarrita
will-moore Jun 13, 2024
f6de93d
Handle 0.5-dev version
will-moore Jun 14, 2024
1054356
Top of 3D cube - align lines with front face
will-moore Jun 14, 2024
f650c1e
Update to zarrita.js 0.4.0-next.14
will-moore Jun 25, 2024
e5b5bef
Update version check to correspond to fix in schemas PR
will-moore Jun 28, 2024
fdd8a55
Handle v0.5-dev2 data
will-moore Jul 3, 2024
e150aa9
Load version.schema for v0.5 schemas
will-moore Jul 4, 2024
e12265f
Check dimension_names for all zarr.json
will-moore Jul 4, 2024
4f54cb4
Temporarily hard-code zarr3 for neuroglancer
joshmoore Jul 11, 2024
8070bc5
Fix loading of zarr v3 plates
will-moore Jul 11, 2024
3a1ecfb
Temporarily hard-code a zarrita-version of vizarr
joshmoore Jul 15, 2024
205ce33
Revert "Temporarily hard-code a zarrita-version of vizarr"
will-moore Aug 7, 2024
56b21f4
Support display of shards
will-moore Aug 14, 2024
7d1f32a
Handle labels for v0.5 data
will-moore Aug 16, 2024
290a066
Update zarrita to 0.4.0-next.15
will-moore Aug 16, 2024
723a104
Load and display Ro-create json
will-moore Aug 21, 2024
5159b0c
Check Ro-Crate name, description, license
will-moore Aug 21, 2024
b816514
Handle data with no sharding codecs
will-moore Aug 22, 2024
0256c07
Try to parse and lookup Organism and Imaging method from Ro-crate
will-moore Aug 22, 2024
e596e00
Use different warning levels for missing metadata
will-moore Aug 22, 2024
e09b012
Improve version checking. Handle missing version 0.4
will-moore Sep 2, 2024
d2dfb1f
Fix bioformats2raw page with v0.5 data
will-moore Sep 3, 2024
0efe2a2
Fix validation of Wells in Plate view
will-moore Sep 3, 2024
1d55e98
Add ro-crate-metadata support to bioformats2raw component
will-moore Sep 24, 2024
c0374f5
Load _version schema. Validate using 'attributes' as JSON root
will-moore Sep 27, 2024
4341aaa
remove console.trace()
will-moore Sep 27, 2024
eb21241
Only validate jsonData.attributes for v0.5 data
will-moore Sep 27, 2024
b1216b6
Handle /OME/zarr.json series metadata for bf2raw data
will-moore Oct 1, 2024
2853654
Fix bytesPerPixel for Zarr v3 dtypes
will-moore Oct 2, 2024
106f6ab
Fix copy-and-paste error in lookupImagingMethod()
will-moore Oct 12, 2024
2522eef
Add OME Logo to nav bar
will-moore Oct 14, 2024
3d4f4b4
Use omeLinkBlue for links etc
will-moore Oct 14, 2024
be301c6
Backgroud white
will-moore Oct 15, 2024
7298e01
Only Open With vizarr for v0.5 data
will-moore Oct 17, 2024
e0cfb42
Fix RO-Crate capitalisation
will-moore Oct 17, 2024
f8ceade
Add links from terms to Ontologies
will-moore Oct 17, 2024
ce6162a
Show Open-with on bioformats2raw page
will-moore Oct 21, 2024
6acf3b2
Fix Open-with links from bioformats2raw page
will-moore Oct 22, 2024
775c3d2
Cleanup and use schema from ome branch on NGFF repo
will-moore Oct 25, 2024
74f4e6f
Fix new-line at end of file
will-moore Oct 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
248 changes: 178 additions & 70 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
},
"dependencies": {
"ajv": "^8.11.0",
"ndarray": "^1.0.19",
"svelte-icons-pack": "^1.4.6",
"svelte-simple-modal": "^1.4.1",
"zarr": "^0.6.0"
"zarrita": "^0.4.0-next.15"
}
}
2 changes: 1 addition & 1 deletion public/ngff_viewers.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"name": "neuroglancer",
"logo": "/neuroglancer.png",
"//": "NB: The {URL} in the href is replaced with NGFF image URL",
"href": "https://neuroglancer-demo.appspot.com/#!{%22layers%22:[{%22source%22:%22zarr://{URL}%22,%22name%22:%22OME-NGFF%22}]}"
"href": "https://neuroglancer-demo.appspot.com/#!{%22layers%22:[{%22source%22:%22zarr3://{URL}%22,%22name%22:%22OME-NGFF%22}]}"
will-moore marked this conversation as resolved.
Show resolved Hide resolved
},
{
"name": "Allen Cell Feature Explorer 3D viewer",
Expand Down
15 changes: 9 additions & 6 deletions src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import Modal from "svelte-simple-modal";
import SplashScreen from "./SplashScreen.svelte";

import { getJson } from "./utils";
import { getZarrGroupAttrs } from "./utils";
import CheckMark from "./CheckMark.svelte";

const searchParams = new URLSearchParams(window.location.search);
Expand All @@ -15,14 +15,17 @@
source = source.slice(0, -1);
}

let location = window.location.href;

let promise;

if (source) {
// load JSON to be validated...
console.log("Loading JSON... " + source + "/.zattrs");
promise = getJson(source + "/.zattrs");
console.log("Loading JSON... " + source);
promise = getZarrGroupAttrs(source);
}

function isBioFormats2Raw(data) {
let omeAttrs = data?.attributes?.ome || data;
return omeAttrs["bioformats2raw.layout"] === 3 && !omeAttrs.plate;
}
</script>

Expand All @@ -38,7 +41,7 @@
{:then data}
<Title {source} zattrs={data} />
<div>
{#if data["bioformats2raw.layout"] === 3 && !data.plate}
{#if isBioFormats2Raw(data)}
<Bioformats2rawLayout rootAttrs={data} {source} />
{:else}
<JsonValidator rootAttrs={data} {source} />
Expand Down
4 changes: 2 additions & 2 deletions src/Bioformats2rawLayout/index.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script>
import { getXmlDom, getJson, validate } from "../utils";
import { getXmlDom, getZarrGroupAttrs, validate } from "../utils";
import JsonBrowser from "../JsonBrowser/index.svelte";
import ImageContainer from "../JsonValidator/Well/ImageContainer.svelte";

Expand Down Expand Up @@ -40,7 +40,7 @@
// wait for schema to be cached, so we don't load them multiple times
// let schemasPromise = getSchema("0.2", "image");
async function preloadSchema(imagePath) {
let imgAttrs = await getJson(imagePath + "/.zattrs");
let imgAttrs = getZarrGroupAttrs(imagePath);
console.log("preloadSchema", imgAttrs);
let errs = await validate(imgAttrs);
return errs;
Expand Down
31 changes: 31 additions & 0 deletions src/JsonBrowser/DetailsPrePanel.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@


<script>
export let jsonData;
export let summary;
</script>

<details>
<summary>{summary}</summary>
<pre><code>{JSON.stringify(jsonData, null, 2)}</code></pre>
</details>


<style>

details {
font-size: 1.1em;
text-align: left;
margin: 0 15px;
}
pre {
margin-top: 10px;
color: #faebd7;
background-color: #2c3e50;
padding: 10px;
font-size: 14px;
border-radius: 10px;
overflow: auto;
}

</style>
will-moore marked this conversation as resolved.
Show resolved Hide resolved
7 changes: 5 additions & 2 deletions src/JsonValidator/Labels/LabelsInfoLink.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<script>
export let source;
export let labelsAttrs;
export let zarrAttrsFileName;
console.log("labelsAttrs:", labelsAttrs);
const url = window.location.origin + window.location.pathname;
let labelsPaths;
if (labelsAttrs.labels) {
labelsPaths = labelsAttrs.labels;
} else if (labelsAttrs?.attributes?.ome?.labels) {
labelsPaths = labelsAttrs.attributes.ome.labels;
}
</script>

Expand All @@ -19,11 +22,11 @@
{/each}
</ul>
{:else}
<div style="color:red">labels/.zattrs has no 'labels' list</div>
<div style="color:red">labels/{zarrAttrsFileName} has no 'labels' list</div>
{/if}

<details>
<summary>labels/.zattrs</summary>
<summary>labels/{zarrAttrsFileName}</summary>
<pre><code>{JSON.stringify(labelsAttrs, null, 2)}</code></pre>
</details>
</div>
Expand Down
36 changes: 31 additions & 5 deletions src/JsonValidator/MultiscaleArrays/Multiscale.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script>
import { getJson } from "../../utils";
import { getZarrArrayJson } from "../../utils";
import CheckMark from "../../CheckMark.svelte";

export let source;
Expand All @@ -15,6 +15,11 @@

const permitDtypeMismatch = ["0.1", "0.2", "0.3", "0.4"].includes(version);
const checkDimSeparator = ["0.2", "0.3", "0.4"].includes(version);
const allowMissingDimNames = ["0.1", "0.2", "0.3", "0.4"].includes(version);
let successMsg = "dtypes match and shapes are consistent";
if (!allowMissingDimNames) {
successMsg = "dimension_names checked, " + successMsg;
}

function allEqual(items) {
return items.every((value) => value == items[0]);
Expand All @@ -29,14 +34,17 @@
let dimCounts = [];
let shapes = [];
let dimSeparators = [];
let zarrayJsonList = [];

for (let i = 0; i < datasets.length; i++) {
let dataset = datasets[i];
let zarray = await getJson(source + "/" + dataset.path + "/.zarray");
let zarray = await getZarrArrayJson(source + "/" + dataset.path);
zarrayJsonList.push(zarray);
// Need to handle Zarr v2 and Zarr v3:
dimCounts.push(zarray.shape.length);
dtypes.push(zarray.dtype);
dtypes.push(zarray.dtype || zarray.data_type);
shapes.push(zarray.shape);
dimSeparators.push(zarray.dimension_separator);
dimSeparators.push(zarray.dimension_separator || zarray.chunk_key_encoding?.configuration?.separator);
}

// Each check is {msg: "Message"}, with status: "warning" if it isn't an Error.
Expand Down Expand Up @@ -72,6 +80,24 @@
});
}
});

if (!allowMissingDimNames) {
let axesNames = JSON.stringify(axes.map(axis => axis.name));
zarrayJsonList.forEach((arrData, i) => {
let msg;
if (!arrData.dimension_names) {
msg = `No dimension_names found for dataset ${i}`;
} else {
let dimNames = JSON.stringify(arrData.dimension_names);
if (dimNames != axesNames) {
msg = `dimension_names: ${dimNames} don't match axes names: ${axesNames}`;
}
}
if (msg) {
checks.push({msg});
}
});
}
}
if (checkDimSeparator) {
dimSeparators.forEach((sep) => {
Expand All @@ -95,7 +121,7 @@
<!-- only show X if not valid - no tick if valid -->
<CheckMark valid={false} />
{:else}
<p title="dtypes match and shapes are consistent">
<p title="{successMsg}">
{datasets.length} Datasets checked <span style="color:green">✓</span>
</p>
{/if}
Expand Down
30 changes: 22 additions & 8 deletions src/JsonValidator/MultiscaleArrays/ZarrArray/ChunkLoader.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
<script>
import { openArray, slice } from "zarr";
import { range } from "../../../utils";
// import { openArray, slice } from "zarr";
will-moore marked this conversation as resolved.
Show resolved Hide resolved
will-moore marked this conversation as resolved.
Show resolved Hide resolved
import { range, getChunkAndShardShapes } from "../../../utils";
import { get, writable } from "svelte/store";
import ChunkViewer from "./ChunkViewer.svelte";
import * as zarr from "zarrita";
import { slice } from "@zarrita/indexing";


export let source;
export let path;
export let zarray;

// zarrita wants /path/to/data.zarr directory
jburel marked this conversation as resolved.
Show resolved Hide resolved
let zarrPath = path.replace("/zarr.json", "").replace("/.zarray", "")

let showChunks = false;
let chunk;

const chunks = zarray.chunks;
const [chunks, shards] = getChunkAndShardShapes(zarray);
const chunkCounts = zarray.shape.map((sh, index) =>
Math.ceil(sh / chunks[index])
);
Expand All @@ -33,20 +39,28 @@
if (!showChunks) return;
// clear previous chunk
chunk = undefined;
const store = await openArray({ store: source + "/" + path, mode: "r" });

// Use zarr like this, otherwise we get "Error: Unknown codec: bytes"
// let zarr = await import("https://cdn.jsdelivr.net/npm/zarrita@next/+esm");
will-moore marked this conversation as resolved.
Show resolved Hide resolved
will-moore marked this conversation as resolved.
Show resolved Hide resolved
let url = source + "/" + zarrPath;
const store = new zarr.FetchStore(url);
const arr = await zarr.open(store, { kind: "array" });

// we want to get exactly 1 chunk
// e.g. chunkIndices is (0, 1, 0, 0) and chunk is (1, 125, 125, 125)
// we want to get [0, 125:250, 0:125, 0:125]
let ch = store.meta.chunks;
const indices = get(chunkIndices).map((index, dim) => {
let ch = arr.chunks;
const indices = get(chunkIndices);
let slices = indices.map((index, dim) => {
if (ch[dim] > 1) {
return slice(index * ch[dim], (index + 1) * ch[dim]);
} else {
return index * ch[dim];
return index;
}
});
chunk = await store.get(indices);
// Updating chunk will trigger ChunkViewer to re-render
console.log("loading chunk", slices)
chunk = await zarr.get(arr, slices);
}

chunkIndices.subscribe(function () {
Expand Down
26 changes: 18 additions & 8 deletions src/JsonValidator/MultiscaleArrays/ZarrArray/ChunkViewer.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script>
import { onMount, afterUpdate } from "svelte";
import { slice } from "zarr";
import { slice, get } from "@zarrita/indexing";
import ndarray from "ndarray";

export let chunk;
// e.g. chunkSlice is [1,0,0]...
Expand All @@ -19,12 +20,11 @@
const shape = chunk2d.shape;
const height = shape[0];
const width = shape[1];
const data = chunk2d.data;
let maxV = 0;
let minV = Infinity;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let rawValue = data[y][x];
let rawValue = chunk2d.get(y, x);
maxV = Math.max(maxV, rawValue);
minV = Math.min(minV, rawValue);
}
Expand All @@ -34,10 +34,18 @@

function sliceArray(ndChunk, toSlice) {
let slice2D = [...toSlice];
slice2D[slice2D.length - 1] = null;
slice2D[slice2D.length - 2] = null;
// don't slice last 2 dims - so we get 2D array
slice2D[slice2D.length - 1] = slice(null);
slice2D[slice2D.length - 2] = slice(null);
return ndChunk.get(slice2D);
let nddata = ndarray(ndChunk.data, ndChunk.shape, ndChunk.stride);

console.log(nddata.shape);

let data2d = nddata.pick(...slice2D);
console.log('nddata', data2d)


return data2d;
}

export function renderTo8bitArray(ndChunks, minMaxValues) {
Expand All @@ -60,9 +68,8 @@
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
for (let p = 0; p < ndChunks.length; p++) {
let data = ndChunks[p].data;
let range = minMaxValues[p];
let rawValue = data[y][x];
let rawValue = ndChunks[p].get(y, x);
let fraction = (rawValue - range[0]) / (range[1] - range[0]);
// for red, green, blue,
for (let i = 0; i < 3; i++) {
Expand All @@ -83,14 +90,17 @@
let chunk2d = chunk;
if (chunkSlice) {
try {
console.log('renderImageToCanvas...', chunk.shape)
chunk2d = sliceArray(chunk, chunkSlice);
// chunk2d = chunk;
will-moore marked this conversation as resolved.
Show resolved Hide resolved
errorMsg = undefined;
} catch (error) {
errorMsg = `Slicing (${chunk.shape}) failed with slice (${chunkSlice})`;
}
}
if (!errorMsg) {
let minMax = getMinMaxValues(chunk2d);
console.log('minMax', minMax);
minMaxMsg = `Min: ${minMax[0]} Max: ${minMax[1]}`;
let rgb = renderTo8bitArray([chunk2d], [minMax]);
ctx.putImageData(new ImageData(rgb, width, height), 0, 0);
Expand Down
Loading