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

Add "row_index" and "column_index" for each well #91

Merged
merged 3 commits into from
Mar 24, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
27 changes: 16 additions & 11 deletions src/main/java/com/glencoesoftware/bioformats2raw/Converter.java
Original file line number Diff line number Diff line change
Expand Up @@ -1199,7 +1199,6 @@ private void saveHCSMetadata(IMetadata meta) throws IOException {

Map<String, Object> well = new HashMap<String, Object>();
well.put("path", wellPath);
wells.add(well);

List<Map<String, Object>> imageList =
new ArrayList<Map<String, Object>>();
Expand Down Expand Up @@ -1228,31 +1227,37 @@ private void saveHCSMetadata(IMetadata meta) throws IOException {
int column = index.getWellColumnIndex();
int row = index.getWellRowIndex();

boolean foundColumn = false;
for (Map<String, Object> colMap : columns) {
if (colMap.get("name").equals(String.valueOf(column))) {
foundColumn = true;
int columnIndex = -1;
for (int c=0; c<columns.size(); c++) {
if (columns.get(c).get("name").equals(String.valueOf(column))) {
columnIndex = c;
break;
}
}
if (!foundColumn) {
if (columnIndex < 0) {
Map<String, Object> colMap = new HashMap<String, Object>();
colMap.put("name", String.valueOf(column));
columnIndex = columns.size();
columns.add(colMap);
}

boolean foundRow = false;
for (Map<String, Object> rowMap : rows) {
if (rowMap.get("name").equals(String.valueOf(row))) {
foundRow = true;
int rowIndex = -1;
for (int r=0; r<rows.size(); r++) {
if (rows.get(r).get("name").equals(String.valueOf(row))) {
rowIndex = r;
break;
}
}
if (!foundRow) {
if (rowIndex < 0) {
Map<String, Object> rowMap = new HashMap<String, Object>();
rowMap.put("name", String.valueOf(row));
rowIndex = rows.size();
rows.add(rowMap);
}

well.put("row_index", rowIndex);
well.put("column_index", columnIndex);
wells.add(well);
}

maxField = (int) Math.max(maxField, index.getFieldIndex());
Expand Down
255 changes: 213 additions & 42 deletions src/test/java/com/glencoesoftware/bioformats2raw/test/ZarrTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -793,31 +793,15 @@ public void testHCSMetadata() throws IOException {

ZarrGroup z = ZarrGroup.open(output);

// check valid group layout
// METADATA.ome.xml, .zattrs (Plate), .zgroup (Plate) and 2 rows
assertEquals(5, Files.list(output).toArray().length);
for (int row=0; row<2; row++) {
Path rowPath = output.resolve(Integer.toString(row));
// .zgroup (Row) and 3 columns
assertEquals(4, Files.list(rowPath).toArray().length);
for (int col=0; col<3; col++) {
Path colPath = rowPath.resolve(Integer.toString(col));
ZarrGroup colGroup = ZarrGroup.open(colPath);
// .zattrs (Column/Image), .zgroup (Column/Image) and 2 fields
assertEquals(4, Files.list(colPath).toArray().length);
for (int field=0; field<2; field++) {
// append resolution index
ZarrArray series0 = colGroup.openArray(field + "/0");
assertArrayEquals(new int[] {1, 1, 1, 512, 512}, series0.getShape());
assertArrayEquals(new int[] {1, 1, 1, 512, 512}, series0.getChunks());
}
}
}
int rowCount = 2;
int colCount = 3;
int fieldCount = 2;
checkPlateGroupLayout(output, rowCount, colCount, fieldCount, 512, 512);

// check plate/well level metadata
Map<String, Object> plate =
(Map<String, Object>) z.getAttributes().get("plate");
assertEquals(2, ((Number) plate.get("field_count")).intValue());
assertEquals(fieldCount, ((Number) plate.get("field_count")).intValue());

List<Map<String, Object>> acquisitions =
(List<Map<String, Object>>) plate.get("acquisitions");
Expand All @@ -831,15 +815,8 @@ public void testHCSMetadata() throws IOException {
assertEquals(1, acquisitions.size());
assertEquals("0", acquisitions.get(0).get("id"));

assertEquals(2, rows.size());
for (int row=0; row<rows.size(); row++) {
assertEquals(String.valueOf(row), rows.get(row).get("name"));
}

assertEquals(3, columns.size());
for (int col=0; col<columns.size(); col++) {
assertEquals(String.valueOf(col), columns.get(col).get("name"));
}
checkDimension(rows, rowCount);
checkDimension(columns, colCount);

assertEquals(rows.size() * columns.size(), wells.size());
for (int row=0; row<rows.size(); row++) {
Expand All @@ -856,21 +833,155 @@ public void testHCSMetadata() throws IOException {
String columnName = (String) column.get("name");
ZarrGroup wellGroup = ZarrGroup.open(
output.resolve(rowName).resolve(columnName));
Map<String, Object> well =
(Map<String, Object>) wellGroup.getAttributes().get("well");
List<Map<String, Object>> images =
(List<Map<String, Object>>) well.get("images");
assertEquals(2, images.size());
Map<String, Object> field1 = images.get(0); // Field 1
assertEquals(field1.get("path"), "0");
assertEquals(0, field1.get("acquisition"));
Map<String, Object> field2 = images.get(1); // Field 2
assertEquals(field2.get("path"), "1");
assertEquals(0, field2.get("acquisition"));
checkWell(wellGroup, fieldCount);
}
}
}

/**
* 96 well plate with only well E6.
*/
@Test
public void testSingleWell() throws IOException {
input = getTestFile("E6-only.ome.xml");
assertTool();

ZarrGroup z = ZarrGroup.open(output);

int rowCount = 8;
int colCount = 12;
int fieldCount = 1;

// check plate/well level metadata
Map<String, Object> plate =
(Map<String, Object>) z.getAttributes().get("plate");
assertEquals(fieldCount, ((Number) plate.get("field_count")).intValue());

List<Map<String, Object>> acquisitions =
(List<Map<String, Object>>) plate.get("acquisitions");
List<Map<String, Object>> rows =
(List<Map<String, Object>>) plate.get("rows");
List<Map<String, Object>> columns =
(List<Map<String, Object>>) plate.get("columns");
List<Map<String, Object>> wells =
(List<Map<String, Object>>) plate.get("wells");

assertEquals(1, acquisitions.size());
assertEquals("0", acquisitions.get(0).get("id"));

checkDimension(rows, rowCount);
checkDimension(columns, colCount);

assertEquals(1, wells.size());
Map<String, Object> well = wells.get(0);
String wellPath = (String) well.get("path");
assertEquals("4/5", wellPath);
assertEquals(4, ((Number) well.get("row_index")).intValue());
assertEquals(5, ((Number) well.get("column_index")).intValue());

// check well metadata
ZarrGroup wellGroup = ZarrGroup.open(output.resolve(wellPath));
checkWell(wellGroup, fieldCount);
}

/**
* 96 well plate with only wells C4 and H2.
*/
@Test
public void testTwoWells() throws IOException {
input = getTestFile("C4-H2-only.ome.xml");
assertTool();

ZarrGroup z = ZarrGroup.open(output);

int rowCount = 8;
int colCount = 12;
int fieldCount = 1;

// check plate/well level metadata
Map<String, Object> plate =
(Map<String, Object>) z.getAttributes().get("plate");
assertEquals(fieldCount, ((Number) plate.get("field_count")).intValue());

List<Map<String, Object>> acquisitions =
(List<Map<String, Object>>) plate.get("acquisitions");
List<Map<String, Object>> rows =
(List<Map<String, Object>>) plate.get("rows");
List<Map<String, Object>> columns =
(List<Map<String, Object>>) plate.get("columns");
List<Map<String, Object>> wells =
(List<Map<String, Object>>) plate.get("wells");

assertEquals(1, acquisitions.size());
assertEquals("0", acquisitions.get(0).get("id"));

checkDimension(rows, rowCount);
checkDimension(columns, colCount);

assertEquals(2, wells.size());
Map<String, Object> well = wells.get(0);
String wellPath = (String) well.get("path");
assertEquals("2/3", wellPath);
assertEquals(2, ((Number) well.get("row_index")).intValue());
assertEquals(3, ((Number) well.get("column_index")).intValue());
ZarrGroup wellGroup = ZarrGroup.open(output.resolve(wellPath));
checkWell(wellGroup, fieldCount);

well = wells.get(1);
wellPath = (String) well.get("path");
assertEquals("7/1", wellPath);
assertEquals(7, ((Number) well.get("row_index")).intValue());
assertEquals(1, ((Number) well.get("column_index")).intValue());
wellGroup = ZarrGroup.open(output.resolve(wellPath));
checkWell(wellGroup, fieldCount);
}

/**
* 96 well plate with all wells in row F.
*/
@Test
public void testOnePlateRow() throws IOException {
input = getTestFile("row-F-only.ome.xml");
assertTool();

ZarrGroup z = ZarrGroup.open(output);

int rowCount = 8;
int colCount = 12;
int fieldCount = 1;

// check plate/well level metadata
Map<String, Object> plate =
(Map<String, Object>) z.getAttributes().get("plate");
assertEquals(fieldCount, ((Number) plate.get("field_count")).intValue());

List<Map<String, Object>> acquisitions =
(List<Map<String, Object>>) plate.get("acquisitions");
List<Map<String, Object>> rows =
(List<Map<String, Object>>) plate.get("rows");
List<Map<String, Object>> columns =
(List<Map<String, Object>>) plate.get("columns");
List<Map<String, Object>> wells =
(List<Map<String, Object>>) plate.get("wells");

assertEquals(1, acquisitions.size());
assertEquals("0", acquisitions.get(0).get("id"));

checkDimension(rows, rowCount);
checkDimension(columns, colCount);

assertEquals(colCount, wells.size());
for (int col=0; col<wells.size(); col++) {
Map<String, Object> well = wells.get(col);
String wellPath = (String) well.get("path");
assertEquals("5/" + col, wellPath);
assertEquals(5, ((Number) well.get("row_index")).intValue());
assertEquals(col, ((Number) well.get("column_index")).intValue());
ZarrGroup wellGroup = ZarrGroup.open(output.resolve(wellPath));
checkWell(wellGroup, fieldCount);
}
}

/**
* Convert an RGB image. Ensure that the Channels are correctly split.
*/
Expand All @@ -889,7 +1000,6 @@ public void testRGBChannelSeparator() throws Exception {
assertEquals(3, pixels.sizeOfChannelList());
}


/**
* Check that a root group and attributes are created and populated.
*/
Expand All @@ -914,4 +1024,65 @@ public void testNoRootGroupOption() throws Exception {
assertTrue(!Files.exists(output.resolve(".zattrs")));
assertTrue(!Files.exists(output.resolve(".zgroup")));
}

private void checkPlateGroupLayout(Path root, int rowCount, int colCount,
int fieldCount, int x, int y)
throws IOException
{
// check valid group layout
// METADATA.ome.xml, .zattrs (Plate), .zgroup (Plate) and rows
assertEquals(rowCount + 3, Files.list(root).toArray().length);
for (int row=0; row<rowCount; row++) {
Path rowPath = root.resolve(Integer.toString(row));
// .zgroup (Row) and columns
assertEquals(colCount + 1, Files.list(rowPath).toArray().length);
for (int col=0; col<colCount; col++) {
Path colPath = rowPath.resolve(Integer.toString(col));
ZarrGroup colGroup = ZarrGroup.open(colPath);
// .zattrs (Column/Image), .zgroup (Column/Image) and fields
assertEquals(fieldCount + 2, Files.list(colPath).toArray().length);
for (int field=0; field<fieldCount; field++) {
// append resolution index
ZarrArray series0 = colGroup.openArray(field + "/0");
assertArrayEquals(new int[] {1, 1, 1, y, x}, series0.getShape());
assertArrayEquals(new int[] {1, 1, 1, y, x}, series0.getChunks());
}
}
}
}

private void checkDimension(List<Map<String, Object>> dims, int dimCount)
throws IOException
{
assertEquals(dimCount, dims.size());
for (int dim=0; dim<dims.size(); dim++) {
assertEquals(String.valueOf(dim), dims.get(dim).get("name"));
}
}

private void checkWell(ZarrGroup wellGroup, int fieldCount)
throws IOException
{
Map<String, Object> well =
(Map<String, Object>) wellGroup.getAttributes().get("well");
List<Map<String, Object>> images =
(List<Map<String, Object>>) well.get("images");
assertEquals(fieldCount, images.size());

for (int i=0; i<fieldCount; i++) {
Map<String, Object> field = images.get(i);
assertEquals(field.get("path"), String.valueOf(i));
assertEquals(0, field.get("acquisition"));
}
}

private Path getTestFile(String resourceName) throws IOException {
try {
return Paths.get(this.getClass().getResource(resourceName).toURI());
}
catch (Exception e) {
throw new IOException(e);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<OME xmlns="http://www.openmicroscopy.org/Schemas/OME/2016-06" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Creator="OME Bio-Formats 6.6.1-SNAPSHOT" xsi:schemaLocation="http://www.openmicroscopy.org/Schemas/OME/2016-06 http://www.openmicroscopy.org/Schemas/OME/2016-06/ome.xsd">
<Plate ColumnNamingConvention="number" Columns="12" ExternalIdentifier="External Identifier" ID="Plate:0" Name="Plate Name 0" RowNamingConvention="letter" Rows="8" Status="Plate status" WellOriginX="0.0" WellOriginXUnit="µm" WellOriginY="1.0" WellOriginYUnit="µm">
<Description>Plate 0 of 1</Description>
<Well Color="255" Column="3" ExternalDescription="External Description" ExternalIdentifier="External Identifier" ID="Well:0_0_0_0" Row="2" Type="Transfection: done">
<WellSample ID="WellSample:0_0_0_0_0_0" Index="0" PositionX="0.0" PositionXUnit="reference frame" PositionY="1.0" PositionYUnit="reference frame" Timepoint="2006-05-04T18:13:51">
<ImageRef ID="Image:0"></ImageRef></WellSample></Well>
<Well Color="255" Column="1" ExternalDescription="External Description" ExternalIdentifier="External Identifier" ID="Well:0_0_1_0" Row="7" Type="Transfection: done">
<WellSample ID="WellSample:0_0_1_0_0_0" Index="1" PositionX="0.0" PositionXUnit="reference frame" PositionY="1.0" PositionYUnit="reference frame" Timepoint="2006-05-04T18:13:51">
<ImageRef ID="Image:1"></ImageRef></WellSample></Well>
<PlateAcquisition EndTime="2006-05-04T18:13:51" ID="PlateAcquisition:0" Name="PlateAcquisition Name 0" StartTime="2006-05-04T18:13:51">
<Description>PlateAcquisition 0 of 1</Description>
<WellSampleRef ID="WellSample:0_0_0_0_0_0"></WellSampleRef>
<WellSampleRef ID="WellSample:0_0_1_0_0_0"></WellSampleRef></PlateAcquisition></Plate>
<Image ID="Image:0" Name="test">
<Description>Image Description 0</Description>
<Pixels BigEndian="false" DimensionOrder="XYZCT" ID="Pixels:0" Interleaved="false" PhysicalSizeX="1.0" PhysicalSizeXUnit="µm" PhysicalSizeY="1.0" PhysicalSizeYUnit="µm" PhysicalSizeZ="1.0" PhysicalSizeZUnit="µm" SignificantBits="8" SizeC="1" SizeT="1" SizeX="2" SizeY="2" SizeZ="1" Type="uint8">
<Channel AcquisitionMode="FluorescenceLifetime" Color="1687603455" ContrastMethod="Brightfield" EmissionWavelength="300.3" EmissionWavelengthUnit="nm" ExcitationWavelength="400.3" ExcitationWavelengthUnit="nm" Fluor="Fluor" ID="Channel:0:0" IlluminationType="Oblique" NDFilter="1.0" Name="Name" PinholeSize="0.5" PinholeSizeUnit="µm" PockelCellSetting="0" SamplesPerPixel="1"/>
<Plane DeltaT="0.1" DeltaTUnit="s" ExposureTime="10.0" ExposureTimeUnit="s" PositionX="1.0" PositionXUnit="reference frame" PositionY="1.0" PositionYUnit="reference frame" PositionZ="1.0" PositionZUnit="reference frame" TheC="0" TheT="0" TheZ="0"/>
<BinData xmlns="http://www.openmicroscopy.org/Schemas/OME/2016-06" Length="4" BigEndian="false">AAAAAA==</BinData></Pixels></Image>
<Image ID="Image:1" Name="test 2">
<Description>Image Description 1</Description>
<Pixels BigEndian="false" DimensionOrder="XYZCT" ID="Pixels:1" Interleaved="false" PhysicalSizeX="1.0" PhysicalSizeXUnit="µm" PhysicalSizeY="1.0" PhysicalSizeYUnit="µm" PhysicalSizeZ="1.0" PhysicalSizeZUnit="µm" SignificantBits="8" SizeC="1" SizeT="1" SizeX="2" SizeY="2" SizeZ="1" Type="uint8">
<Channel AcquisitionMode="FluorescenceLifetime" Color="1687603455" ContrastMethod="Brightfield" EmissionWavelength="300.3" EmissionWavelengthUnit="nm" ExcitationWavelength="400.3" ExcitationWavelengthUnit="nm" Fluor="Fluor" ID="Channel:1:0" IlluminationType="Oblique" NDFilter="1.0" Name="Name" PinholeSize="0.5" PinholeSizeUnit="µm" PockelCellSetting="0" SamplesPerPixel="1"/>
<Plane DeltaT="0.1" DeltaTUnit="s" ExposureTime="10.0" ExposureTimeUnit="s" PositionX="1.0" PositionXUnit="reference frame" PositionY="1.0" PositionYUnit="reference frame" PositionZ="1.0" PositionZUnit="reference frame" TheC="0" TheT="0" TheZ="0"/>
<BinData xmlns="http://www.openmicroscopy.org/Schemas/OME/2016-06" Length="4" BigEndian="false">AQEBAQ==</BinData></Pixels></Image></OME>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<OME xmlns="http://www.openmicroscopy.org/Schemas/OME/2016-06" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Creator="OME Bio-Formats 6.6.1-SNAPSHOT" xsi:schemaLocation="http://www.openmicroscopy.org/Schemas/OME/2016-06 http://www.openmicroscopy.org/Schemas/OME/2016-06/ome.xsd">
<Plate ColumnNamingConvention="number" Columns="12" ExternalIdentifier="External Identifier" ID="Plate:0" Name="Plate Name 0" RowNamingConvention="letter" Rows="8" Status="Plate status" WellOriginX="0.0" WellOriginXUnit="µm" WellOriginY="1.0" WellOriginYUnit="µm">
<Description>Plate 0 of 1</Description>
<Well Color="255" Column="5" ExternalDescription="External Description" ExternalIdentifier="External Identifier" ID="Well:0_0_0_0" Row="4" Type="Transfection: done">
<WellSample ID="WellSample:0_0_0_0_0_0" Index="0" PositionX="0.0" PositionXUnit="reference frame" PositionY="1.0" PositionYUnit="reference frame" Timepoint="2006-05-04T18:13:51">
<ImageRef ID="Image:0"></ImageRef></WellSample></Well>
<PlateAcquisition EndTime="2006-05-04T18:13:51" ID="PlateAcquisition:0" Name="PlateAcquisition Name 0" StartTime="2006-05-04T18:13:51">
<Description>PlateAcquisition 0 of 1</Description>
<WellSampleRef ID="WellSample:0_0_0_0_0_0"></WellSampleRef></PlateAcquisition></Plate>
<Image ID="Image:0" Name="test">
<Description>Image Description 0</Description>
<Pixels BigEndian="false" DimensionOrder="XYZCT" ID="Pixels:0" Interleaved="false" PhysicalSizeX="1.0" PhysicalSizeXUnit="µm" PhysicalSizeY="1.0" PhysicalSizeYUnit="µm" PhysicalSizeZ="1.0" PhysicalSizeZUnit="µm" SignificantBits="8" SizeC="1" SizeT="1" SizeX="2" SizeY="2" SizeZ="1" Type="uint8">
<Channel AcquisitionMode="FluorescenceLifetime" Color="1687603455" ContrastMethod="Brightfield" EmissionWavelength="300.3" EmissionWavelengthUnit="nm" ExcitationWavelength="400.3" ExcitationWavelengthUnit="nm" Fluor="Fluor" ID="Channel:0:0" IlluminationType="Oblique" NDFilter="1.0" Name="Name" PinholeSize="0.5" PinholeSizeUnit="µm" PockelCellSetting="0" SamplesPerPixel="1"/>
<Plane DeltaT="0.1" DeltaTUnit="s" ExposureTime="10.0" ExposureTimeUnit="s" PositionX="1.0" PositionXUnit="reference frame" PositionY="1.0" PositionYUnit="reference frame" PositionZ="1.0" PositionZUnit="reference frame" TheC="0" TheT="0" TheZ="0"/>
<BinData xmlns="http://www.openmicroscopy.org/Schemas/OME/2016-06" Length="4" BigEndian="false">AAAAAA==</BinData></Pixels></Image></OME>
Loading