diff --git a/satpy/tests/writer_tests/test_ninjogeotiff.py b/satpy/tests/writer_tests/test_ninjogeotiff.py index 31fcb25efc..a9b283cf11 100644 --- a/satpy/tests/writer_tests/test_ninjogeotiff.py +++ b/satpy/tests/writer_tests/test_ninjogeotiff.py @@ -20,6 +20,7 @@ import datetime import logging import os +from unittest.mock import Mock import dask.array as da import numpy as np @@ -247,6 +248,12 @@ def test_image_small_arctic_P(test_area_tiny_stereographic_wgs84): "start_time": datetime.datetime(2027, 8, 2, 8, 20), "area": test_area_tiny_stereographic_wgs84, "mode": "P"}) + # simulate an enhancement history such as palettize may add + arr.attrs["enhancement_history"] = [ + {"scale": np.float64(0.01), + "offset": np.float64(0.0), + "colormap": Mock()}] + return to_image(arr) @@ -577,8 +584,8 @@ def test_write_and_read_file_P(test_image_small_arctic_P, tmp_path): test_image_small_arctic_P, filename=fn, fill_value=255, - PhysicUnit="N/A", - PhysicValue="N/A", + PhysicUnit="satdata", + PhysicValue="satdata", SatelliteNameID=6400014, ChannelID=900015, DataType="PPRN", @@ -591,8 +598,8 @@ def test_write_and_read_file_P(test_image_small_arctic_P, tmp_path): tgs = src.tags() assert tgs["ninjo_FileName"] == fn assert tgs["ninjo_DataSource"] == "dowsing rod" - assert "ninjo_Gradient" not in tgs - assert "ninjo_AxisIntercept" not in tgs + assert tgs["ninjo_Gradient"] == "1.0" + assert tgs["ninjo_AxisIntercept"] == "0.0" def test_write_and_read_file_units( diff --git a/satpy/writers/ninjogeotiff.py b/satpy/writers/ninjogeotiff.py index 5f88cc52ed..1d5cfb69ac 100644 --- a/satpy/writers/ninjogeotiff.py +++ b/satpy/writers/ninjogeotiff.py @@ -74,11 +74,13 @@ NinJo has a functionality to read the corresponding quantity (example: brightness temperature or reflectance). To make this possible, the writer adds the tags ``Gradient`` and ``AxisIntercept``. Those tags are added if -and only if the image has mode ``L`` or ``LA`` and ``PhysicUnit`` is not set +and only if the image has mode ``L``, ``P``, or ``LA`` and ``PhysicUnit`` is not set to ``"N/A"``. In other words, to suppress those tags for images with mode ``L`` or ``LA`` (for example, for the composite ``vis_with_ir``, where the physical interpretation of individual pixels is lost), one should set ``PhysicUnit`` to ``"N/A"``, ``"n/a"``, ``"1"``, or ``""`` (empty string). +If the image has mode ``P``, ``Gradient`` is set to ``1.0`` and ``AxisIntercept`` +to ``0.0`` (as expected by NinJo). """ import copy @@ -204,11 +206,22 @@ def save_image( # noqa: D417 overviews_minsize=overviews_minsize, overviews_resampling=overviews_resampling, tags={**(tags or {}), **ninjo_tags}, - scale_offset_tags=(self.scale_offset_tag_names - if self._check_include_scale_offset(image, PhysicUnit) - else None), + scale_offset_tags=self._get_scale_offset_tags(image, PhysicUnit), **gdal_opts) + def _get_scale_offset_tags(self, image, unit): + """Get scale offset tags (tuple or dict).""" + if self._check_include_scale_offset(image, unit): + # image.mode cannot be trusted https://github.com/pytroll/satpy/issues/2300 + try: + mod = image.data.attrs["mode"] + except KeyError: + mod = image.mode + if mod == "P": + return dict(zip(self.scale_offset_tag_names, (1, 0))) + return self.scale_offset_tag_names + return None # explicit is better than implicit + def _fix_units(self, image, quantity, unit): """Adapt units between °C and K. @@ -236,7 +249,7 @@ def _fix_units(self, image, quantity, unit): def _check_include_scale_offset(self, image, unit): """Check if scale-offset tags should be included.""" - if image.mode.startswith("L") and unit.lower() not in ("n/a", "1", ""): + if image.mode[0] in "LP" and unit.lower() not in ("n/a", "1", ""): return True return False