From 46e9a2015042a8d522d68bebf78df14cb06c74f8 Mon Sep 17 00:00:00 2001 From: andream Date: Thu, 13 Jun 2024 11:44:47 +0200 Subject: [PATCH 01/11] implement set_alpha_range --- satpy/composites/glm.py | 8 ++++---- satpy/enhancements/__init__.py | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/satpy/composites/glm.py b/satpy/composites/glm.py index e1c9b676c6..3c13d23311 100644 --- a/satpy/composites/glm.py +++ b/satpy/composites/glm.py @@ -50,10 +50,10 @@ def __init__(self, name, min_highlight=0.0, max_highlight=10.0, # noqa: D417 Args: min_highlight (float): Minimum raw value of the "highlight" data that will be used for linearly scaling the data along with - ``max_hightlight``. + ``max_highlight``. max_highlight (float): Maximum raw value of the "highlight" data that will be used for linearly scaling the data along with - ``min_hightlight``. + ``min_highlight``. max_factor (tuple): Maximum effect that the highlight data can have on each channel of the primary image data. This will be multiplied by the linearly scaled highlight data and then @@ -61,8 +61,8 @@ def __init__(self, name, min_highlight=0.0, max_highlight=10.0, # noqa: D417 docstring for more information. By default this is set to ``(0.8, 0.8, -0.8, 0)`` meaning the Red and Green channel will be added to by at most 0.8, the Blue channel will be - subtracted from by at most 0.8, and the Alpha channel will - not be effected. + subtracted from by at most 0.8 (resulting in yellow highlights), + and the Alpha channel will not be affected. """ self.min_highlight = min_highlight diff --git a/satpy/enhancements/__init__.py b/satpy/enhancements/__init__.py index 00a0f8dd4e..e99de29a2f 100644 --- a/satpy/enhancements/__init__.py +++ b/satpy/enhancements/__init__.py @@ -409,7 +409,7 @@ def create_colormap(palette, img=None): # noqa: D417 Colormaps can be loaded from lists of colors provided by the ``colors`` key in the provided dictionary. Each element in the list represents a single color to be mapped to and can be 3 (RGB) or 4 (RGBA) elements long. - By default the value or control point for a color is determined by the + By default, the value or control point for a color is determined by the index in the list (0, 1, 2, ...) divided by the total number of colors to produce a number between 0 and 1. This can be overridden by providing a ``values`` key in the provided dictionary. See the "Set Range" section @@ -479,8 +479,24 @@ def create_colormap(palette, img=None): # noqa: D417 if "min_value" in palette and "max_value" in palette: cmap.set_range(palette["min_value"], palette["max_value"]) elif "min_value" in palette or "max_value" in palette: - raise ValueError("Both 'min_value' and 'max_value' must be specified (or neither)") + raise ValueError("Both 'min_value' and 'max_value' must be specified (or neither).") + if "min_alpha" in palette and "max_alpha" in palette: + cmap = set_alpha_range(cmap, palette["min_alpha"], palette["max_alpha"], color_scale) + elif "min_alpha" in palette or "max_alpha" in palette: + raise ValueError("Both 'min_alpha' and 'max_alpha' must be specified (or neither).") + + return cmap + + +def set_alpha_range(cmap, min_alpha, max_alpha, color_scale): + """Set the alpha channel of a colormap to be between min_alpha and max_alpha in linear steps. + + If the input colormap does not have an alpha channel, it will be added to it.""" + cmap = cmap.to_rgba() + cmap.colors[:, 3] = np.linspace(min_alpha / color_scale, + max_alpha / color_scale, + cmap.colors.shape[0]) return cmap From f52faa0fce8731fd25644fdb6aca2df1544b1fad Mon Sep 17 00:00:00 2001 From: andream Date: Thu, 13 Jun 2024 13:42:20 +0200 Subject: [PATCH 02/11] add docs note --- doc/source/enhancements.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/source/enhancements.rst b/doc/source/enhancements.rst index 9623c1b120..ce4e80c3b9 100644 --- a/doc/source/enhancements.rst +++ b/doc/source/enhancements.rst @@ -100,6 +100,15 @@ the example here:: - {colors: spectral, min_value: 193.15, max_value: 253.149999} - {colors: greys, min_value: 253.15, max_value: 303.15} +In addition, it is also possible to add a linear alpha channel to the colormap, as in the +following example:: + + - name: colorize + method: !!python/name:satpy.enhancements.colorize + kwargs: + palettes: + - {colors: ylorrd, min_alpha: 100, max_alpha: 255} + It is also possible to provide your own custom defined color mapping by specifying a list of RGB values and the corresponding min and max values between which to apply the colors. This is for instance a common use case for From cca88480b79d38e5424dba585a762fbcfa5bbcf3 Mon Sep 17 00:00:00 2001 From: andream Date: Thu, 13 Jun 2024 14:13:20 +0200 Subject: [PATCH 03/11] add tests and simplify create_colormap() --- satpy/enhancements/__init__.py | 55 +++++++++++++------ .../enhancement_tests/test_enhancements.py | 25 +++++++++ 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/satpy/enhancements/__init__.py b/satpy/enhancements/__init__.py index e99de29a2f..ca891331bf 100644 --- a/satpy/enhancements/__init__.py +++ b/satpy/enhancements/__init__.py @@ -455,12 +455,36 @@ def create_colormap(palette, img=None): # noqa: D417 ``max_value``. See :meth:`trollimage.colormap.Colormap.set_range` for more information. + **Set Alpha Range** + + The alpha channel of a created colormap can be added and/or modified by + specifying ``min_alpha`` and ``max_alpha``. + See :meth:`set_alpha_range` for more info. + """ + # are colors between 0-255 or 0-1 + color_scale = palette.get("color_scale", 255) + cmap = _get_cmap_from_palette_info(palette, img, color_scale) + + if palette.get("reverse", False): + cmap.reverse() + if "min_value" in palette and "max_value" in palette: + cmap.set_range(palette["min_value"], palette["max_value"]) + elif "min_value" in palette or "max_value" in palette: + raise ValueError("Both 'min_value' and 'max_value' must be specified (or neither).") + + if "min_alpha" in palette and "max_alpha" in palette: + cmap = set_alpha_range(cmap, palette["min_alpha"], palette["max_alpha"], color_scale) + elif "min_alpha" in palette or "max_alpha" in palette: + raise ValueError("Both 'min_alpha' and 'max_alpha' must be specified (or neither).") + + return cmap + + +def _get_cmap_from_palette_info(palette, img, color_scale): fname = palette.get("filename", None) colors = palette.get("colors", None) dataset = palette.get("dataset", None) - # are colors between 0-255 or 0-1 - color_scale = palette.get("color_scale", 255) if fname: if not os.path.exists(fname): fname = get_config_path(fname) @@ -473,26 +497,23 @@ def create_colormap(palette, img=None): # noqa: D417 cmap = _create_colormap_from_dataset(img, dataset, color_scale) else: raise ValueError("Unknown colormap format: {}".format(palette)) + return cmap - if palette.get("reverse", False): - cmap.reverse() - if "min_value" in palette and "max_value" in palette: - cmap.set_range(palette["min_value"], palette["max_value"]) - elif "min_value" in palette or "max_value" in palette: - raise ValueError("Both 'min_value' and 'max_value' must be specified (or neither).") - - if "min_alpha" in palette and "max_alpha" in palette: - cmap = set_alpha_range(cmap, palette["min_alpha"], palette["max_alpha"], color_scale) - elif "min_alpha" in palette or "max_alpha" in palette: - raise ValueError("Both 'min_alpha' and 'max_alpha' must be specified (or neither).") - return cmap +def set_alpha_range(cmap, min_alpha, max_alpha, color_scale=255): + """Set the colormap alpha channel between two values in linear steps. + If the input colormap does not have an alpha channel, + it will be added to it. If an alpha channel is already existing, + the values will be overwritten. -def set_alpha_range(cmap, min_alpha, max_alpha, color_scale): - """Set the alpha channel of a colormap to be between min_alpha and max_alpha in linear steps. + Args: + cmap: input colormap + min_alpha: start value of the alpha channel + max_alpha: end value of the alpha channel + color_scale: number for normalising the alpha values to 0-1. - If the input colormap does not have an alpha channel, it will be added to it.""" + """ cmap = cmap.to_rgba() cmap.colors[:, 3] = np.linspace(min_alpha / color_scale, max_alpha / color_scale, diff --git a/satpy/tests/enhancement_tests/test_enhancements.py b/satpy/tests/enhancement_tests/test_enhancements.py index ca0d56f11f..deaf0f5700 100644 --- a/satpy/tests/enhancement_tests/test_enhancements.py +++ b/satpy/tests/enhancement_tests/test_enhancements.py @@ -350,6 +350,31 @@ def test_cmap_vrgb_as_rgba(self): assert cmap.values[0] == 0 assert cmap.values[-1] == 1.0 + def test_cmap_with_alpha_set(self): + """Test that the min_alpha and max_alpha arguments set the alpha channel correctly.""" + with closed_named_temp_file(suffix=".npy") as cmap_filename: + cmap_data = _generate_cmap_test_data(None, "RGB") + np.save(cmap_filename, cmap_data) + cmap = create_colormap({"filename": cmap_filename, "min_alpha": 100, "max_alpha": 255}) + assert cmap.colors.shape[0] == 4 + assert cmap.colors.shape[1] == 4 # RGBA + #check that we start from min_alpha + np.testing.assert_equal(cmap.colors[0], [1.0, 0, 0, 100/255.]) + # two thirds of the linear scale + np.testing.assert_almost_equal(cmap.colors[2], [1., 1., 1., (100+(2/3)*(255-100))/255]) + #check that we end at max_alpha + np.testing.assert_equal(cmap.colors[3], [0, 0, 1., 1.0]) + # check that values have not been changed + assert cmap.values.shape[0] == 4 + assert cmap.values[0] == 0 + assert cmap.values[-1] == 1.0 + + # check that if a value is missing we raise a ValueError + with pytest.raises(ValueError, match="Both 'min_value' and 'max_value' must be specified (or neither)."): + create_colormap({"filename": cmap_filename, "max_alpha": 255}) + with pytest.raises(ValueError, match="Both 'min_value' and 'max_value' must be specified (or neither)."): + create_colormap({"filename": cmap_filename, "min_alpha": 255}) + @pytest.mark.parametrize( ("real_mode", "forced_mode"), [ From 60311481219c14ac0514e4916ccf77b118477714 Mon Sep 17 00:00:00 2001 From: andream Date: Thu, 13 Jun 2024 15:22:15 +0200 Subject: [PATCH 04/11] fix test --- satpy/tests/enhancement_tests/test_enhancements.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/satpy/tests/enhancement_tests/test_enhancements.py b/satpy/tests/enhancement_tests/test_enhancements.py index deaf0f5700..b6c31b3ad3 100644 --- a/satpy/tests/enhancement_tests/test_enhancements.py +++ b/satpy/tests/enhancement_tests/test_enhancements.py @@ -370,9 +370,9 @@ def test_cmap_with_alpha_set(self): assert cmap.values[-1] == 1.0 # check that if a value is missing we raise a ValueError - with pytest.raises(ValueError, match="Both 'min_value' and 'max_value' must be specified (or neither)."): + with pytest.raises(ValueError, match="Both 'min_alpha' and 'max_alpha' must be specified*."): create_colormap({"filename": cmap_filename, "max_alpha": 255}) - with pytest.raises(ValueError, match="Both 'min_value' and 'max_value' must be specified (or neither)."): + with pytest.raises(ValueError, match="Both 'min_alpha' and 'max_alpha' must be specified*."): create_colormap({"filename": cmap_filename, "min_alpha": 255}) @pytest.mark.parametrize( From 20a0fdd74f6134ddeb1623a8bfbf1ae290b04df9 Mon Sep 17 00:00:00 2001 From: andream Date: Fri, 14 Jun 2024 11:53:35 +0200 Subject: [PATCH 05/11] change code to use cmap.set_alpha_range() --- satpy/enhancements/__init__.py | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/satpy/enhancements/__init__.py b/satpy/enhancements/__init__.py index ca891331bf..ebb490399f 100644 --- a/satpy/enhancements/__init__.py +++ b/satpy/enhancements/__init__.py @@ -459,7 +459,7 @@ def create_colormap(palette, img=None): # noqa: D417 The alpha channel of a created colormap can be added and/or modified by specifying ``min_alpha`` and ``max_alpha``. - See :meth:`set_alpha_range` for more info. + See :meth:`trollimage.colormap.Colormap.set_alpha_range` for more info. """ # are colors between 0-255 or 0-1 @@ -474,7 +474,8 @@ def create_colormap(palette, img=None): # noqa: D417 raise ValueError("Both 'min_value' and 'max_value' must be specified (or neither).") if "min_alpha" in palette and "max_alpha" in palette: - cmap = set_alpha_range(cmap, palette["min_alpha"], palette["max_alpha"], color_scale) + cmap.set_alpha_range(palette["min_alpha"]/color_scale, + palette["max_alpha"]/color_scale) elif "min_alpha" in palette or "max_alpha" in palette: raise ValueError("Both 'min_alpha' and 'max_alpha' must be specified (or neither).") @@ -500,26 +501,6 @@ def _get_cmap_from_palette_info(palette, img, color_scale): return cmap -def set_alpha_range(cmap, min_alpha, max_alpha, color_scale=255): - """Set the colormap alpha channel between two values in linear steps. - - If the input colormap does not have an alpha channel, - it will be added to it. If an alpha channel is already existing, - the values will be overwritten. - - Args: - cmap: input colormap - min_alpha: start value of the alpha channel - max_alpha: end value of the alpha channel - color_scale: number for normalising the alpha values to 0-1. - - """ - cmap = cmap.to_rgba() - cmap.colors[:, 3] = np.linspace(min_alpha / color_scale, - max_alpha / color_scale, - cmap.colors.shape[0]) - return cmap - def _create_colormap_from_dataset(img, dataset, color_scale): """Create a colormap from an auxiliary variable in a source file.""" From 728e26c2068d8e0f8d55155b0b91b860767346e1 Mon Sep 17 00:00:00 2001 From: andream Date: Mon, 24 Jun 2024 11:34:50 +0200 Subject: [PATCH 06/11] require trollimage 1.24 after https://github.com/pytroll/trollimage/pull/170 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c2ae1a890d..c3396ede4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ dependencies = [ "pyproj>=2.2", "pyresample>=1.24.0", "pyyaml>=5.1", - "trollimage>=1.23", + "trollimage>=1.24", "trollsift", "xarray>=0.14.1", "zarr", From c50661c5439cc97fd48fd22ad947511abe2b03f9 Mon Sep 17 00:00:00 2001 From: andream Date: Mon, 24 Jun 2024 16:22:44 +0200 Subject: [PATCH 07/11] blacklist rioxarray 0.15.6 to solve test failures related to https://github.com/corteva/rioxarray/pull/787 --- pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fb80bf7a1e..9fa13edc9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ avhrr_l1b_gaclac = ["pygac >= 1.3.0"] modis_l1b = ["pyhdf", "python-geotiepoints >= 1.1.7"] geocat = ["pyhdf"] goci2 = ["netCDF4 >= 1.1.8"] -generic_image = ["rasterio", "rioxarray"] +generic_image = ["rasterio", "rioxarray!=0.15.6"] acspo = ["netCDF4 >= 1.1.8"] clavrx = ["netCDF4 >= 1.1.8"] viirs_l1b = ["netCDF4 >= 1.1.8"] @@ -51,9 +51,9 @@ omps_edr = ["h5py >= 2.7.0"] amsr2_l1b = ["h5py >= 2.7.0"] hrpt = ["pyorbital >= 1.3.1", "pygac", "python-geotiepoints >= 1.1.7"] hrit_msg = ["pytroll-schedule"] -msi_safe = ["rioxarray", "bottleneck", "python-geotiepoints", "defusedxml"] +msi_safe = ["rioxarray!=0.15.6", "bottleneck", "python-geotiepoints", "defusedxml"] nc_nwcsaf_msg = ["netCDF4 >= 1.1.8"] -sar_c = ["python-geotiepoints >= 1.1.7", "rasterio", "rioxarray", "defusedxml"] +sar_c = ["python-geotiepoints >= 1.1.7", "rasterio", "rioxarray!=0.15.6", "defusedxml"] abi_l1b = ["h5netcdf"] seviri_l1b_hrit = ["pyorbital >= 1.3.1"] seviri_l1b_native = ["pyorbital >= 1.3.1"] @@ -86,7 +86,7 @@ overlays = ["pycoast", "pydecorate"] satpos_from_tle = ["skyfield", "astropy"] tests = ["behave", "h5py", "netCDF4", "pyhdf", "imageio", "rasterio", "geoviews", "trollimage", "fsspec", "bottleneck", - "rioxarray", "pytest", "pytest-lazy-fixtures", "defusedxml", + "rioxarray!=0.15.6", "pytest", "pytest-lazy-fixtures", "defusedxml", "s3fs", "eccodes", "h5netcdf", "xarray-datatree", "skyfield", "ephem", "pint-xarray", "astropy", "dask-image", "python-geotiepoints", "numba"] From 882e0775270e77f037cd33a603f5b1f737af214f Mon Sep 17 00:00:00 2001 From: andream Date: Mon, 24 Jun 2024 16:24:54 +0200 Subject: [PATCH 08/11] update ci yaml too --- continuous_integration/environment.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/continuous_integration/environment.yaml b/continuous_integration/environment.yaml index 6479ce6b53..b1da2fb54a 100644 --- a/continuous_integration/environment.yaml +++ b/continuous_integration/environment.yaml @@ -30,7 +30,7 @@ dependencies: - gdal - rasterio - bottleneck - - rioxarray + - rioxarray!=0.15.6 - defusedxml - imageio - pyhdf @@ -60,6 +60,6 @@ dependencies: - pip: - pytest-lazy-fixtures - trollsift - - trollimage>=1.23 + - trollimage>=1.24 - pyspectral - pyorbital From b93d0ce0e87e9db1f360cb8b030116ca9b737db7 Mon Sep 17 00:00:00 2001 From: andream Date: Wed, 26 Jun 2024 16:54:34 +0200 Subject: [PATCH 09/11] revert blacklisting of rioxarray 0.15.6 after https://github.com/pytroll/satpy/pull/2837 --- continuous_integration/environment.yaml | 2 +- pyproject.toml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/continuous_integration/environment.yaml b/continuous_integration/environment.yaml index b1da2fb54a..54c9df57ad 100644 --- a/continuous_integration/environment.yaml +++ b/continuous_integration/environment.yaml @@ -30,7 +30,7 @@ dependencies: - gdal - rasterio - bottleneck - - rioxarray!=0.15.6 + - rioxarray - defusedxml - imageio - pyhdf diff --git a/pyproject.toml b/pyproject.toml index 9fa13edc9d..fb80bf7a1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ avhrr_l1b_gaclac = ["pygac >= 1.3.0"] modis_l1b = ["pyhdf", "python-geotiepoints >= 1.1.7"] geocat = ["pyhdf"] goci2 = ["netCDF4 >= 1.1.8"] -generic_image = ["rasterio", "rioxarray!=0.15.6"] +generic_image = ["rasterio", "rioxarray"] acspo = ["netCDF4 >= 1.1.8"] clavrx = ["netCDF4 >= 1.1.8"] viirs_l1b = ["netCDF4 >= 1.1.8"] @@ -51,9 +51,9 @@ omps_edr = ["h5py >= 2.7.0"] amsr2_l1b = ["h5py >= 2.7.0"] hrpt = ["pyorbital >= 1.3.1", "pygac", "python-geotiepoints >= 1.1.7"] hrit_msg = ["pytroll-schedule"] -msi_safe = ["rioxarray!=0.15.6", "bottleneck", "python-geotiepoints", "defusedxml"] +msi_safe = ["rioxarray", "bottleneck", "python-geotiepoints", "defusedxml"] nc_nwcsaf_msg = ["netCDF4 >= 1.1.8"] -sar_c = ["python-geotiepoints >= 1.1.7", "rasterio", "rioxarray!=0.15.6", "defusedxml"] +sar_c = ["python-geotiepoints >= 1.1.7", "rasterio", "rioxarray", "defusedxml"] abi_l1b = ["h5netcdf"] seviri_l1b_hrit = ["pyorbital >= 1.3.1"] seviri_l1b_native = ["pyorbital >= 1.3.1"] @@ -86,7 +86,7 @@ overlays = ["pycoast", "pydecorate"] satpos_from_tle = ["skyfield", "astropy"] tests = ["behave", "h5py", "netCDF4", "pyhdf", "imageio", "rasterio", "geoviews", "trollimage", "fsspec", "bottleneck", - "rioxarray!=0.15.6", "pytest", "pytest-lazy-fixtures", "defusedxml", + "rioxarray", "pytest", "pytest-lazy-fixtures", "defusedxml", "s3fs", "eccodes", "h5netcdf", "xarray-datatree", "skyfield", "ephem", "pint-xarray", "astropy", "dask-image", "python-geotiepoints", "numba"] From 6df6307338c5d76d1e53861edc858f9c5ccc9510 Mon Sep 17 00:00:00 2001 From: andream Date: Mon, 1 Jul 2024 13:25:37 +0200 Subject: [PATCH 10/11] add spaces around / --- satpy/enhancements/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/satpy/enhancements/__init__.py b/satpy/enhancements/__init__.py index ebb490399f..a44ca590cf 100644 --- a/satpy/enhancements/__init__.py +++ b/satpy/enhancements/__init__.py @@ -474,8 +474,8 @@ def create_colormap(palette, img=None): # noqa: D417 raise ValueError("Both 'min_value' and 'max_value' must be specified (or neither).") if "min_alpha" in palette and "max_alpha" in palette: - cmap.set_alpha_range(palette["min_alpha"]/color_scale, - palette["max_alpha"]/color_scale) + cmap.set_alpha_range(palette["min_alpha"] / color_scale, + palette["max_alpha"] / color_scale) elif "min_alpha" in palette or "max_alpha" in palette: raise ValueError("Both 'min_alpha' and 'max_alpha' must be specified (or neither).") From 85f11a34ed8f448633764a4f7fd4a5401d651bed Mon Sep 17 00:00:00 2001 From: andream Date: Mon, 1 Jul 2024 13:41:43 +0200 Subject: [PATCH 11/11] indent asserts after cmap creation and split test for single alpha passing --- .../enhancement_tests/test_enhancements.py | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/satpy/tests/enhancement_tests/test_enhancements.py b/satpy/tests/enhancement_tests/test_enhancements.py index b6c31b3ad3..747d6fc0cd 100644 --- a/satpy/tests/enhancement_tests/test_enhancements.py +++ b/satpy/tests/enhancement_tests/test_enhancements.py @@ -331,11 +331,12 @@ def test_cmap_from_file(self, color_scale, colormap_mode, extra_kwargs, filename kwargs1["color_scale"] = color_scale cmap = create_colormap(kwargs1) - assert cmap.colors.shape[0] == 4 - np.testing.assert_equal(cmap.colors[0], first_color) - assert cmap.values.shape[0] == 4 - assert cmap.values[0] == unset_first_value - assert cmap.values[-1] == unset_last_value + + assert cmap.colors.shape[0] == 4 + np.testing.assert_equal(cmap.colors[0], first_color) + assert cmap.values.shape[0] == 4 + assert cmap.values[0] == unset_first_value + assert cmap.values[-1] == unset_last_value def test_cmap_vrgb_as_rgba(self): """Test that data created as VRGB still reads as RGBA.""" @@ -343,12 +344,13 @@ def test_cmap_vrgb_as_rgba(self): cmap_data = _generate_cmap_test_data(None, "VRGB") np.save(cmap_filename, cmap_data) cmap = create_colormap({"filename": cmap_filename, "colormap_mode": "RGBA"}) - assert cmap.colors.shape[0] == 4 - assert cmap.colors.shape[1] == 4 # RGBA - np.testing.assert_equal(cmap.colors[0], [128 / 255., 1.0, 0, 0]) - assert cmap.values.shape[0] == 4 - assert cmap.values[0] == 0 - assert cmap.values[-1] == 1.0 + + assert cmap.colors.shape[0] == 4 + assert cmap.colors.shape[1] == 4 # RGBA + np.testing.assert_equal(cmap.colors[0], [128 / 255., 1.0, 0, 0]) + assert cmap.values.shape[0] == 4 + assert cmap.values[0] == 0 + assert cmap.values[-1] == 1.0 def test_cmap_with_alpha_set(self): """Test that the min_alpha and max_alpha arguments set the alpha channel correctly.""" @@ -356,24 +358,30 @@ def test_cmap_with_alpha_set(self): cmap_data = _generate_cmap_test_data(None, "RGB") np.save(cmap_filename, cmap_data) cmap = create_colormap({"filename": cmap_filename, "min_alpha": 100, "max_alpha": 255}) - assert cmap.colors.shape[0] == 4 - assert cmap.colors.shape[1] == 4 # RGBA - #check that we start from min_alpha - np.testing.assert_equal(cmap.colors[0], [1.0, 0, 0, 100/255.]) - # two thirds of the linear scale - np.testing.assert_almost_equal(cmap.colors[2], [1., 1., 1., (100+(2/3)*(255-100))/255]) - #check that we end at max_alpha - np.testing.assert_equal(cmap.colors[3], [0, 0, 1., 1.0]) - # check that values have not been changed - assert cmap.values.shape[0] == 4 - assert cmap.values[0] == 0 - assert cmap.values[-1] == 1.0 + + assert cmap.colors.shape[0] == 4 + assert cmap.colors.shape[1] == 4 # RGBA + # check that we start from min_alpha + np.testing.assert_equal(cmap.colors[0], [1.0, 0, 0, 100/255.]) + # two thirds of the linear scale + np.testing.assert_almost_equal(cmap.colors[2], [1., 1., 1., (100+(2/3)*(255-100))/255]) + # check that we end at max_alpha + np.testing.assert_equal(cmap.colors[3], [0, 0, 1., 1.0]) + # check that values have not been changed + assert cmap.values.shape[0] == 4 + assert cmap.values[0] == 0 + assert cmap.values[-1] == 1.0 + + @pytest.mark.parametrize("alpha_arg", ["max_alpha", "min_alpha"]) + def test_cmap_error_with_only_one_alpha_set(self, alpha_arg): + """Test that when only min_alpha or max_alpha arguments are set an error is raised.""" + with closed_named_temp_file(suffix=".npy") as cmap_filename: + cmap_data = _generate_cmap_test_data(None, "RGB") + np.save(cmap_filename, cmap_data) # check that if a value is missing we raise a ValueError with pytest.raises(ValueError, match="Both 'min_alpha' and 'max_alpha' must be specified*."): - create_colormap({"filename": cmap_filename, "max_alpha": 255}) - with pytest.raises(ValueError, match="Both 'min_alpha' and 'max_alpha' must be specified*."): - create_colormap({"filename": cmap_filename, "min_alpha": 255}) + create_colormap({"filename": cmap_filename, alpha_arg: 255}) @pytest.mark.parametrize( ("real_mode", "forced_mode"), @@ -422,12 +430,13 @@ def test_cmap_from_config_path(self, tmp_path): with satpy.config.set(config_path=[tmp_path]): rel_cmap_filename = os.path.join("colormaps", "my_colormap.npy") cmap = create_colormap({"filename": rel_cmap_filename, "colormap_mode": "RGBA"}) - assert cmap.colors.shape[0] == 4 - assert cmap.colors.shape[1] == 4 # RGBA - np.testing.assert_equal(cmap.colors[0], [128 / 255., 1.0, 0, 0]) - assert cmap.values.shape[0] == 4 - assert cmap.values[0] == 0 - assert cmap.values[-1] == 1.0 + + assert cmap.colors.shape[0] == 4 + assert cmap.colors.shape[1] == 4 # RGBA + np.testing.assert_equal(cmap.colors[0], [128 / 255., 1.0, 0, 0]) + assert cmap.values.shape[0] == 4 + assert cmap.values[0] == 0 + assert cmap.values[-1] == 1.0 def test_cmap_from_trollimage(self): """Test that colormaps in trollimage can be loaded."""