Skip to content

read_vrt(band=None) only masks band 0's nodata sentinel on multi-band integer VRTs #1611

@brendancol

Description

@brendancol

Describe the bug

read_vrt(path) on a multi-band integer VRT with per-band <NoDataValue> tags only masks band 0's sentinel. Bands 1 and up keep their integer sentinels as literal finite values in the returned float64 array.

The float-VRT path masks per-band sentinels correctly in _vrt._read_data (lines 296-297 and 347-351). For integer rasters the masking happens later, in __init__.py:read_vrt (lines 2795-2809), and only uses vrt.bands[0].nodata, so bands 1+ are left untouched.

Same class of bug as #1598. PR #1602 fixed band=N selection (single-band reads of band N). The band=None multi-band case still mis-masks every non-first band.

To Reproduce

import tempfile, os, numpy as np
from xrspatial.geotiff import read_vrt
from xrspatial.geotiff._writer import write

with tempfile.TemporaryDirectory() as td:
    b0 = np.array([[1, 2], [3, 65535]], dtype=np.uint16)
    b1 = np.array([[7, 8], [9, 65000]], dtype=np.uint16)
    p0, p1 = os.path.join(td, 'b0.tif'), os.path.join(td, 'b1.tif')
    write(b0, p0, nodata=65535, compression='none', tiled=False)
    write(b1, p1, nodata=65000, compression='none', tiled=False)

    vrt = os.path.join(td, 't.vrt')
    open(vrt, 'w').write(f'''<VRTDataset rasterXSize="2" rasterYSize="2">
  <GeoTransform>0.0, 1.0, 0.0, 0.0, 0.0, -1.0</GeoTransform>
  <VRTRasterBand dataType="UInt16" band="1"><NoDataValue>65535</NoDataValue>
    <SimpleSource><SourceFilename relativeToVRT="0">{p0}</SourceFilename><SourceBand>1</SourceBand><SrcRect xOff="0" yOff="0" xSize="2" ySize="2"/><DstRect xOff="0" yOff="0" xSize="2" ySize="2"/></SimpleSource></VRTRasterBand>
  <VRTRasterBand dataType="UInt16" band="2"><NoDataValue>65000</NoDataValue>
    <SimpleSource><SourceFilename relativeToVRT="0">{p1}</SourceFilename><SourceBand>1</SourceBand><SrcRect xOff="0" yOff="0" xSize="2" ySize="2"/><DstRect xOff="0" yOff="0" xSize="2" ySize="2"/></SimpleSource></VRTRasterBand>
</VRTDataset>''')

    r = read_vrt(vrt)
    print(r.values[1, 1, 0], r.values[1, 1, 1])
    # Got: nan 65000.0
    # Expected: nan nan

Expected behavior

Every band's per-band <NoDataValue> sentinel should be NaN-masked in the returned float64 array, matching the float-VRT path.

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions