Skip to content

to_geotiff leaves the previous file's PAM sidecar behind on overwrite #3595

Description

@brendancol

Description

to_geotiff writes PAM .aux.xml sidecars next to the output file: a categorical RAT when the DataArray carries attrs['category_names'] (#3483), and STATISTICS_* entries for color_ramp= (#3537). When a later write targets the same path but produces no sidecar of its own, the old .aux.xml stays on disk and now describes the wrong pixels:

  • open_geotiff merges the sidecar back onto attrs, so a continuous raster written over an old categorical one comes back with category_names / category_colors from the overwritten file. QGIS then renders the float raster as three classes, and a rasterize -> to_geotiff round-trip re-writes the bogus RAT.
  • GDAL tools and QGIS read the stale STATISTICS_MINIMUM / STATISTICS_MAXIMUM and stretch the new data with the old file's range.
import numpy as np, xarray as xr
from xrspatial.geotiff import open_geotiff, to_geotiff

ys = 1000.0 - np.arange(8) * 10.0 - 5.0
xs = 2000.0 + np.arange(8) * 10.0 + 5.0

cat = xr.DataArray(np.arange(64, dtype='uint8').reshape(8, 8) % 3,
                   dims=('y', 'x'), coords={'y': ys, 'x': xs},
                   attrs={'crs': 32611,
                          'category_names': ['water', 'forest', 'urban']})
to_geotiff(cat, 'a.tif')                      # writes a.tif.aux.xml (RAT)

plain = xr.DataArray(np.arange(64, dtype='float32').reshape(8, 8),
                     dims=('y', 'x'), coords={'y': ys, 'x': xs},
                     attrs={'crs': 32611})
to_geotiff(plain, 'a.tif')                    # overwrite, no categories

open_geotiff('a.tif').attrs['category_names']
# ['water', 'forest', 'urban']   <- stale, from the overwritten file

GDAL's GTiff driver deletes associated PAM sidecars when it creates a dataset over an existing path (GDALDriver::QuietDelete), so gdal_translate onto the same path does not hit this.

Expected behavior

Writing a GeoTIFF to a string path should refresh the PAM sidecar: replaced when the new write emits one, removed when it does not. The .qml style sidecar is different. QGIS treats .qml as user styling that persists across data updates, so it should only be replaced by a new color_ramp= write.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggeotiffGeoTIFF module

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions