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

Store dimension order using new "axes" spec #121

Merged
merged 6 commits into from
Mar 1, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
34 changes: 33 additions & 1 deletion src/main/java/com/glencoesoftware/bioformats2raw/Converter.java
Original file line number Diff line number Diff line change
Expand Up @@ -1220,7 +1220,8 @@ public void saveResolutions(int series)
.nested(nested)
.compressor(CompressorFactory.create(
compressionType.toString(), compressionProperties));
ZarrArray.create(getRootPath().resolve(resolutionString), arrayParams);
ZarrArray.create(getRootPath().resolve(resolutionString),
arrayParams, getArrayAttributes());

nTile = new AtomicInteger(0);
tileCount = (int) Math.ceil((double) scaledWidth / tileWidth)
Expand Down Expand Up @@ -1514,6 +1515,27 @@ private void setSeriesLevelMetadata(int series, int resolutions)
datasets.add(Collections.singletonMap("path", lastPath));
}
multiscale.put("datasets", datasets);

if (dimensionOrder != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under which case would dimensionOrder be null? In this scenario, the multi-scale would contain no axes and be invalid or can we infer a default value?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I originally assumed here that dimensionOrder can't really be null, and this is just being extra safe. Going back and looking at the history of the --dimension-order option though, dimensionOrder can be null if --dimension-order original is used. In that case, you're correct that the axes metadata is missing, so I need to fix that here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7595d77 should fix this so that axes is populated for any value of dimensionOrder.

List<Map<String, String>> axes = new ArrayList<Map<String, String>>();
String axisOrder = dimensionOrder.toString();
for (int i=axisOrder.length()-1; i>=0; i--) {
String axis = axisOrder.substring(i, i + 1).toLowerCase();
String type = "space";
if (axis.equals("t")) {
type = "time";
}
else if (axis.equals("c")) {
type = "channel";
}
Map<String, String> thisAxis = new HashMap<String, String>();
thisAxis.put("name", axis);
thisAxis.put("type", type);
axes.add(thisAxis);
}
multiscale.put("axes", axes);
}

Path subGroupPath = getRootPath().resolve(seriesString);
LOGGER.debug(" creating subgroup {}", subGroupPath);
ZarrGroup subGroup = ZarrGroup.create(subGroupPath);
Expand Down Expand Up @@ -1761,6 +1783,16 @@ private Class<?> getBaseReaderClass() throws FormatException, IOException {
}
}

private Map<String, Object> getArrayAttributes() {
Map<String, Object> attrs = new HashMap<String, Object>();
if (dimensionOrder != null) {
String order = dimensionOrder.toString().toLowerCase();
String[] axes = new StringBuilder(order).reverse().toString().split("");
attrs.put("_ARRAY_DIMENSIONS", axes);
}
return attrs;
}

/**
* Check if the given metadata object contains at least one plate
* with at least one well that links to an image.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,10 @@ public void testMultiscalesMetadata() throws Exception {
(List<Map<String, Object>>) multiscale.get("datasets");
assertTrue(datasets.size() > 0);
assertEquals("0", datasets.get(0).get("path"));

List<Map<String, Object>> axes =
(List<Map<String, Object>>) multiscale.get("axes");
checkAxes(axes, "TCZYX");
}

/**
Expand All @@ -284,6 +288,15 @@ public void testSetXYCZTDimensionOrder() throws Exception {
ZarrGroup z = ZarrGroup.open(output.toString());
ZarrArray array = z.openArray("0/0");
assertArrayEquals(new int[] {1, 1, 2, 512, 512}, array.getShape());

z = ZarrGroup.open(output.resolve("0").toString());
List<Map<String, Object>> multiscales = (List<Map<String, Object>>)
z.getAttributes().get("multiscales");
assertEquals(1, multiscales.size());
Map<String, Object> multiscale = multiscales.get(0);
List<Map<String, Object>> axes =
(List<Map<String, Object>>) multiscale.get("axes");
checkAxes(axes, "TZCYX");
}

/**
Expand Down Expand Up @@ -1413,6 +1426,15 @@ private void checkWell(ZarrGroup wellGroup, int fieldCount)
}
}

private void checkAxes(List<Map<String, Object>> axes, String order) {
assertEquals(axes.size(), order.length());
for (int i=0; i<axes.size(); i++) {
String name = axes.get(i).get("name").toString();
assertEquals(name, order.toLowerCase().substring(i, i + 1));
assertTrue(axes.get(i).containsKey("type"));
}
}

private Path getTestFile(String resourceName) throws IOException {
try {
return Paths.get(this.getClass().getResource(resourceName).toURI());
Expand Down