Source code for geoh5py.data.color_map
# Copyright (c) 2024 Mira Geoscience Ltd.
#
# This file is part of geoh5py.
#
# geoh5py is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# geoh5py is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with geoh5py. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import TYPE_CHECKING
import numpy as np
from ..shared.exceptions import ShapeValidationError
from ..shared.utils import map_attributes
if TYPE_CHECKING:
from ..workspace import Workspace
from .data_type import DataType
[docs]
class ColorMap:
"""Records colors assigned to value ranges (where Value is the start of the range)."""
_attribute_map = {"File name": "name"}
_names = ["Value", "Red", "Green", "Blue", "Alpha"]
_formats = ["<f8", "u1", "u1", "u1", "u1"]
def __init__(self, **kwargs):
self.parent = None
self.name = "geoh5py_custom.TBL"
self.values = np.empty((0, 5))
map_attributes(self, **kwargs)
@property
def values(self) -> np.ndarray:
"""
:obj:`numpy.array`: Colormap defined by values and corresponding RGBA:
.. code-block:: python
values = [
[V_1, R_1, G_1, B_1, A_1],
..., [V_i, R_i, G_i, B_i, A_i]
]
where V (Values) are sorted floats defining the position of each RGBA.
R (Red), G (Green), B (Blue) and A (Alpha) are integer values between [0, 255].
"""
return np.vstack([self._values[name] for name in self._names])
@values.setter
def values(self, values: np.ndarray):
if not isinstance(values, np.ndarray):
raise TypeError(f"Input 'values' of ColorMap must be of type {np.ndarray}.")
if np.issubdtype(values.dtype.base, np.number):
if values.shape[1] != 5:
raise ShapeValidationError("values", values.shape, "(*, 5)")
self._values = np.core.records.fromarrays(
values.T, names=self._names, formats=self._formats
)
else:
if values.dtype.names is None or not all(
name in self._names for name in values.dtype.names
):
raise ValueError(
f"Input 'values' must contain fields with types {self._names}"
)
self._values = np.asarray(
values, dtype=list(zip(self._names, self._formats, strict=False))
)
if self.workspace is not None and self.parent is not None:
self.workspace.update_attribute(self.parent, "color_map") # pylint: disable=no-member
@property
def name(self) -> str:
"""
:obj:`str`: Name of the colormap
"""
return self._name
@name.setter
def name(self, value: str):
self._name = str(value)
if self.parent is not None:
self.parent.workspace.update_attribute(self.parent, "color_map")
@property
def parent(self) -> DataType | None:
"""Parent data type"""
return self._parent
@parent.setter
def parent(self, data_type: DataType | None):
self._parent = data_type
@property
def workspace(self) -> Workspace | None:
"""Workspace object"""
if self.parent is not None:
return self.parent.workspace
return None
def __len__(self):
return len(self._values)