Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement support to set alpha range in create_colormap and yaml colorize enhancements #2817

Merged
merged 14 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions doc/source/enhancements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions satpy/composites/glm.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,19 @@ 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
added or subtracted from the highlight channels. See class
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
Expand Down
55 changes: 46 additions & 9 deletions satpy/enhancements/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,58 +409,82 @@
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
below for more information.

See the "Color Scale" section below for more information on the value
range of provided numbers.

**From a builtin colormap**

Colormaps can be loaded by name from the builtin colormaps in the
``trollimage``` package. Specify the name with the ``colors``
key in the provided dictionary (ex. ``{'colors': 'blues'}``).
See :doc:`trollimage:colormap` for the full list of available colormaps.

**From an auxiliary variable**

If the colormap is defined in the same dataset as the data to which the
colormap shall be applied, this can be indicated with
``{'dataset': 'palette_variable'}``, where ``'palette_variable'`` is the
name of the variable containing the palette. This variable must be an
auxiliary variable to the dataset to which the colours are applied. When
using this, it is important that one should **not** set ``min_value`` and
``max_value`` as those will be taken from the ``valid_range`` attribute
on the dataset and if those differ from ``min_value`` and ``max_value``,
the resulting colors will not match the ones in the palette.

**Color Scale**

By default colors are expected to be in a 0-255 range. This
can be overridden by specifying ``color_scale`` in the provided colormap
information. A common alternative to 255 is ``1`` to specify floating
point numbers between 0 and 1. The resulting Colormap uses the normalized
color values (0-1).

**Set Range**

By default the control points or values of the Colormap are between 0 and
1. This means that data values being mapped to a color must also be
between 0 and 1. When this is not the case, the expected input range of
the data can be used to configure the Colormap and change the control point
values. To do this specify the input data range with ``min_value`` and
``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).")

Check warning on line 474 in satpy/enhancements/__init__.py

View check run for this annotation

Codecov / codecov/patch

satpy/enhancements/__init__.py#L474

Added line #L474 was not covered by tests

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)
Expand All @@ -473,14 +497,27 @@
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)")

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])

Check notice on line 520 in satpy/enhancements/__init__.py

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

✅ Getting better: Complex Method

create_colormap decreases in cyclomatic complexity from 14 to 12, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
return cmap


Expand Down
25 changes: 25 additions & 0 deletions satpy/tests/enhancement_tests/test_enhancements.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_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})

@pytest.mark.parametrize(
("real_mode", "forced_mode"),
[
Expand Down
Loading