From ef1a0134537af93aae0581298499a55f1f68cb5d Mon Sep 17 00:00:00 2001 From: David Gault Date: Mon, 1 May 2023 09:57:04 +0100 Subject: [PATCH 1/3] Group keys will now be reordered before processing --- src/loci/formats/in/ZarrReader.java | 56 ++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/loci/formats/in/ZarrReader.java b/src/loci/formats/in/ZarrReader.java index 453f219..484d254 100644 --- a/src/loci/formats/in/ZarrReader.java +++ b/src/loci/formats/in/ZarrReader.java @@ -36,10 +36,13 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Stream; import javax.xml.parsers.ParserConfigurationException; @@ -179,7 +182,9 @@ protected void initFile(String id) throws FormatException, IOException { } // Parse group attributes - for (String key: zarrService.getGroupKeys(zarrRootPath)) { + Set groupKeys = zarrService.getGroupKeys(zarrRootPath); + List orderedGroupKeys = reorderGroupKeys(groupKeys); + for (String key: orderedGroupKeys) { Map attributes = zarrService.getGroupAttr(zarrRootPath+File.separator+key); if (attributes != null && !attributes.isEmpty()) { parseResolutionCount(zarrRootPath, key); @@ -289,6 +294,55 @@ protected void initFile(String id) throws FormatException, IOException { setSeries(0); } + private List reorderGroupKeys(Set groupKeys) { + // Reorder group keys to avoid order such A/1, A/10, A/11, A/12, A/2, A/20, A/3, A/4 + List groupKeysList = new ArrayList(); + groupKeysList.addAll(groupKeys); + Collections.sort(groupKeysList, comp); + return groupKeysList; + } + + Comparator comp = (a,b)->{ + String[] aParts = a.split("/"); + String[] bParts = b.split("/"); + + int numParts = aParts.length - bParts.length; + if (numParts != 0) return numParts; + + for (int i = 0; i < aParts.length; i++) { + String aPart = aParts[i]; + String bPart = bParts[i]; + + boolean isAInt = isInteger(aPart); + boolean isBInt = isInteger(bPart); + if (isAInt && !isBInt) return -1; + if (!isAInt && isBInt) return 1; + + if (isAInt) { + int numResult = Integer.compare(Integer.valueOf(aPart), Integer.valueOf(bPart)); + if (numResult != 0) return numResult; + } + else { + int stringResult = aPart.compareTo(bPart); + if (stringResult != 0) return stringResult; + } + } + + return 0; + }; + + private static boolean isInteger(String s) { + if(s.isEmpty()) return false; + for(int i = 0; i < s.length(); i++) { + if(i == 0 && s.charAt(i) == '-') { + if(s.length() == 1) return false; + else continue; + } + if(Character.digit(s.charAt(i), 10) < 0) return false; + } + return true; + } + /** * In the event that .zarray does not contain a 5d shape * The dimensions of the original shape will be assumed based on tczyx From bec6f0f36d47e5317280f60cb9f12c73854c0994 Mon Sep 17 00:00:00 2001 From: David Gault Date: Fri, 5 May 2023 10:44:35 +0100 Subject: [PATCH 2/3] Make group key comparator static --- src/loci/formats/in/ZarrReader.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/loci/formats/in/ZarrReader.java b/src/loci/formats/in/ZarrReader.java index 484d254..4373543 100644 --- a/src/loci/formats/in/ZarrReader.java +++ b/src/loci/formats/in/ZarrReader.java @@ -298,11 +298,11 @@ private List reorderGroupKeys(Set groupKeys) { // Reorder group keys to avoid order such A/1, A/10, A/11, A/12, A/2, A/20, A/3, A/4 List groupKeysList = new ArrayList(); groupKeysList.addAll(groupKeys); - Collections.sort(groupKeysList, comp); + Collections.sort(groupKeysList, keyComparator); return groupKeysList; } - Comparator comp = (a,b)->{ + private static Comparator keyComparator = (a,b)->{ String[] aParts = a.split("/"); String[] bParts = b.split("/"); From 306c0d03bf0d0a1d11f4e81831ed6e3fe5f63714 Mon Sep 17 00:00:00 2001 From: David Gault Date: Thu, 13 Jul 2023 18:28:44 +0100 Subject: [PATCH 3/3] Reorder group keys: Use original series ordering --- src/loci/formats/in/ZarrReader.java | 56 ++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/loci/formats/in/ZarrReader.java b/src/loci/formats/in/ZarrReader.java index 4373543..5f473e8 100644 --- a/src/loci/formats/in/ZarrReader.java +++ b/src/loci/formats/in/ZarrReader.java @@ -160,8 +160,9 @@ protected void initFile(String id) throws FormatException, IOException { initializeZarrService(zarrRootPath); + ArrayList omeSeriesOrder = new ArrayList(); if(omeMetaFile.exists()) { - parseOMEXML(omeMetaFile, store); + parseOMEXML(omeMetaFile, store, omeSeriesOrder); } // Parse base level attributes Map attr = zarrService.getGroupAttr(zarrRootPath); @@ -183,7 +184,7 @@ protected void initFile(String id) throws FormatException, IOException { // Parse group attributes Set groupKeys = zarrService.getGroupKeys(zarrRootPath); - List orderedGroupKeys = reorderGroupKeys(groupKeys); + List orderedGroupKeys = reorderGroupKeys(groupKeys, omeSeriesOrder); for (String key: orderedGroupKeys) { Map attributes = zarrService.getGroupAttr(zarrRootPath+File.separator+key); if (attributes != null && !attributes.isEmpty()) { @@ -294,6 +295,19 @@ protected void initFile(String id) throws FormatException, IOException { setSeries(0); } + private List reorderGroupKeys(Set groupKeys, List originalKeys) { + // Reorder group keys to maintain the original order from the OME-XML provided by bioformats2raw + if (originalKeys.isEmpty() || !groupKeys.containsAll(originalKeys)) { + LOGGER.warn("Mismatch with group key paths and original OME-XML metadata, original ordering wont be maintained"); + return reorderGroupKeys(groupKeys); + } + List groupKeysList = new ArrayList(); + groupKeys.removeAll(originalKeys); + groupKeysList.addAll(originalKeys); + groupKeysList.addAll(groupKeys); + return groupKeysList; + } + private List reorderGroupKeys(Set groupKeys) { // Reorder group keys to avoid order such A/1, A/10, A/11, A/12, A/2, A/20, A/3, A/4 List groupKeysList = new ArrayList(); @@ -769,7 +783,7 @@ private void parseOmeroMetadata(String root, String key) throws IOException, For } } - private void parseOMEXML(Location omeMetaFile, MetadataStore store) throws IOException, FormatException { + private void parseOMEXML(Location omeMetaFile, MetadataStore store, ArrayList origSeries) throws IOException, FormatException { Document omeDocument = null; try (RandomAccessInputStream measurement = new RandomAccessInputStream(omeMetaFile.getAbsolutePath())) { @@ -811,6 +825,24 @@ private void parseOMEXML(Location omeMetaFile, MetadataStore store) throws IOExc int numDatasets = omexmlMeta.getImageCount(); + // Map of the well location for each imageReference + // Later we will map the series index to the imageReference + // This allows us to maintain the series order when parsing the Zarr groups + Map imageRefPaths = new HashMap(); + for (int plateIndex = 0; plateIndex < omexmlMeta.getPlateCount(); plateIndex++) { + for (int wellIndex = 0; wellIndex < omexmlMeta.getWellCount(plateIndex); wellIndex++) { + NonNegativeInteger col = omexmlMeta.getWellColumn(plateIndex, wellIndex); + NonNegativeInteger row = omexmlMeta.getWellRow(plateIndex, wellIndex); + + String rowLetter = getRowString(row.getValue()); + String expectedPath = rowLetter + File.separator + (col.getValue() + 1) + File.separator + "0"; + for (int wellSampleIndex = 0; wellSampleIndex < omexmlMeta.getWellSampleCount(plateIndex, wellIndex); wellSampleIndex++) { + String imageRef = omexmlMeta.getWellSampleImageRef(plateIndex, wellIndex, wellSampleIndex); + imageRefPaths.put(imageRef, expectedPath); + } + } + } + int oldSeries = getSeries(); core.clear(); for (int i=0; i 0) { + sb.append((char)('A' + (rowIndex % 26))); + rowIndex /= 26; + } + return sb.reverse().toString(); + } + private Double getDouble(Map src, String key) { Number val = (Number) src.get(key); if (val == null) {