diff --git a/assay/api-src/org/labkey/api/assay/plate/ExcelPlateReader.java b/assay/api-src/org/labkey/api/assay/plate/ExcelPlateReader.java index 55c28b70013..ad79de1e87e 100644 --- a/assay/api-src/org/labkey/api/assay/plate/ExcelPlateReader.java +++ b/assay/api-src/org/labkey/api/assay/plate/ExcelPlateReader.java @@ -28,7 +28,6 @@ import java.io.File; import java.io.IOException; import java.util.List; -import java.util.Map; /** * User: Karl Lum @@ -37,6 +36,8 @@ public class ExcelPlateReader extends AbstractPlateReader implements PlateReader { public static final String TYPE = "xls"; + + double emptyWellValue = 0.0d; @Override public String getType() @@ -102,4 +103,15 @@ protected boolean isValidStartRow(Sheet sheet, int row) } return false; } + + @Override + public double getEmptyWellValue() + { + return emptyWellValue; + } + + public void setEmptyWellValue(double emptyWellValue) + { + this.emptyWellValue = emptyWellValue; + } } diff --git a/assay/api-src/org/labkey/api/assay/plate/PlateReader.java b/assay/api-src/org/labkey/api/assay/plate/PlateReader.java index 39b3527ad89..703ecfcd6ef 100644 --- a/assay/api-src/org/labkey/api/assay/plate/PlateReader.java +++ b/assay/api-src/org/labkey/api/assay/plate/PlateReader.java @@ -81,4 +81,10 @@ public interface PlateReader * @throws ValidationException - if the value cannot be converted, will halt parsing of the plate */ double convertWellValue(String token) throws ValidationException; + + // Issue 51553: Empty well value should be 0.0d by default but can be overridden via the PlateReader implementation + default double getEmptyWellValue() + { + return 0.0d; + } } diff --git a/assay/api-src/org/labkey/api/assay/plate/PlateUtils.java b/assay/api-src/org/labkey/api/assay/plate/PlateUtils.java index 4b864543062..3cebadf0c3a 100644 --- a/assay/api-src/org/labkey/api/assay/plate/PlateUtils.java +++ b/assay/api-src/org/labkey/api/assay/plate/PlateUtils.java @@ -340,7 +340,7 @@ public static double[] parseRowAt(RowMap rowMap, int startCol, int expec // If the value is not null or a number, stop parsing. Object value = rowMap.get(startCol + j); if (value == null) - cells[j] = 0.0d; + cells[j] = reader != null ? reader.getEmptyWellValue() : 0.0d; else if (value instanceof String) { try diff --git a/assay/src/org/labkey/assay/plate/AssayPlateMetadataServiceImpl.java b/assay/src/org/labkey/assay/plate/AssayPlateMetadataServiceImpl.java index 0d3055c518f..bb9c4587a36 100644 --- a/assay/src/org/labkey/assay/plate/AssayPlateMetadataServiceImpl.java +++ b/assay/src/org/labkey/assay/plate/AssayPlateMetadataServiceImpl.java @@ -696,6 +696,7 @@ private List> parsePlateGrids( { // parse the data file for each distinct plate type found in the set of plates for the plateSetId ExcelPlateReader plateReader = new ExcelPlateReader(); + plateReader.setEmptyWellValue(Double.NaN); // Issue 51553 MultiValuedMap plateTypeGrids = new HashSetValuedHashMap<>(); boolean hasPlateIdentifiers = false; @@ -772,7 +773,7 @@ else if (multipleMeasures && measureProperties.isEmpty()) // get wells guarantees a consistent row/column oriented order for (Well well : dataForPlate.getWells()) { - measureDataRows.computeIfAbsent(well, f -> getDataRowFromWell(currentPlate.getPlateId(), well, measureName)).put(measureName, well.getValue()); + measureDataRows.computeIfAbsent(well, f -> getDataRowFromWell(currentPlate.getPlateId(), well, measureName)).put(measureName, getWellValue(well)); } } @@ -829,10 +830,17 @@ private Map getDataRowFromWell(String plateId, Well well, String Map row = new CaseInsensitiveHashMap<>(); row.put(AssayResultDomainKind.PLATE_COLUMN_NAME, plateId); row.put(AssayResultDomainKind.WELL_LOCATION_COLUMN_NAME, well.getDescription()); - row.put(measure, well.getValue()); + row.put(measure, getWellValue(well)); return row; } + // Issue 51553: account for empty wells in the plate graphical parsing by using Double.NaN + private @Nullable Double getWellValue(Well well) + { + double value = well.getValue(); + return Double.isNaN(value) ? null : value; + } + @Override @NotNull public OntologyManager.UpdateableTableImportHelper getImportHelper(