Skip to content

API reference

earthcarekit.colormap

Colormap utilities.

Notes

This module depends on other internal modules:


Cmap

Bases: ListedColormap

Colormap with categorical, gradient, and circular support.

This subclass of matplotlib.colors.ListedColormap adds utilities for continuous and categorical color mappings. Supports labels, ticks, normalization, blending, and transparency adjustments.

Attributes:

Name Type Description
categorical bool

Whether the colormap is discrete/categorical.

gradient bool

Whether the colormap was generated from a gradient.

circular bool

Whether the colormap wraps around cyclically.

ticks list[float]

Optional tick positions for categorical plots.

labels list[str]

Optional labels corresponding to ticks.

norm Normalize | None

Normalization strategy for value mapping.

values list

Associated values for categorical mapping.

Source code in earthcarekit/colormap/_cmap.py
class Cmap(ListedColormap):
    """Colormap with categorical, gradient, and circular support.

    This subclass of `matplotlib.colors.ListedColormap` adds utilities for
    continuous and categorical color mappings. Supports labels, ticks,
    normalization, blending, and transparency adjustments.

    Attributes:
        categorical (bool): Whether the colormap is discrete/categorical.
        gradient (bool): Whether the colormap was generated from a gradient.
        circular (bool): Whether the colormap wraps around cyclically.
        ticks (list[float]): Optional tick positions for categorical plots.
        labels (list[str]): Optional labels corresponding to ticks.
        norm (Normalize | None): Normalization strategy for value mapping.
        values (list): Associated values for categorical mapping.
    """

    def __init__(
        self,
        colors: Sequence,
        name: str = "colormap",
        N: int | None = None,
        categorical: bool = False,
        ticks: List[float] | None = None,
        labels: List[str] | None = None,
        norm: Normalize | None = None,
        values: List | None = None,
        gradient: bool = False,
        circular: bool = False,
    ):
        """Initialize a Cmap.

        Args:
            colors (Sequence): Sequence of colors (strings or ColorLike objects).
            name (str): Name of the colormap. Defaults to "colormap".
            N (int | None): Number of discrete colors. Defaults to None.
            categorical (bool): Whether the colormap is discrete/categorical. Defaults to False.
            ticks (list[float] | None): Optional tick positions for categorical plots. Defaults to None.
            labels (list[str] | None): Optional labels corresponding to ticks. Defaults to None.
            norm (Normalize | None): Normalization strategy for value mapping. Defaults to None.
            gradient (bool): If True, generate intermediate gradient colors. Defaults to False.
            circular (bool): If True, colormap wraps around cyclically. Defaults to False.
        """
        _colors: list = [Color(c) if isinstance(c, str) else c for c in colors]

        if gradient:
            tmp_cmap = LinearSegmentedColormap.from_list("tmp_cmap", _colors, N=256)
            _colors = [tmp_cmap(i) for i in range(256)]

        super().__init__(_colors, name=name, N=N or len(_colors))
        self.categorical = categorical
        self.gradient = gradient
        self.circular = circular
        self.ticks = ticks or []
        self.labels = labels or []
        self.norm = norm
        self.values = values or []

    @classmethod
    def from_colormap(cls, cmap: Colormap, N: int = 256, name: str | None = None) -> "Cmap":
        """Create a Cmap instance from an existing Matplotlib colormap.

        Args:
            cmap (Colormap): Source colormap to convert.
            N (int): Number of discrete colors (if needed, e.g, for categorical
                colormaps with limited number of colors). Defaults to 256.

        Returns:
            Cmap: New colormap.
        """
        if isinstance(cmap, cls):
            return cmap
        elif isinstance(cmap, ListedColormap):
            colors = list(cmap.colors)  # type: ignore
            if isinstance(colors, np.ndarray) and colors.ndim == 2:
                N = len(colors)
            else:
                N = cmap.N
        else:
            colors = [cmap(x) for x in np.linspace(0, 1, N)]

        _colors = []
        for c in colors:
            if (
                isinstance(c, (np.ndarray, list, tuple))
                and not isinstance(c, str)
                and all([_c <= 1 for _c in c])
            ):
                _colors.append(Color(c, is_normalized=True))  # type: ignore
            else:
                _colors = [Color(c) for c in colors]  # type: ignore
                continue
        new_cmap = cls(
            [c.hex for c in _colors],
            name=name or cmap.name,
            N=N,
        )
        new_cmap = copy_extremes(cmap, new_cmap)
        return new_cmap

    def copy(self) -> "Cmap":
        new_cmap = Cmap(
            colors=cast(Sequence, self.colors),
            name=self.name,
            N=self.N,
            categorical=self.categorical,
            ticks=self.ticks,
            labels=self.labels,
            norm=self.norm,
            values=self.values,
            gradient=self.gradient,
            circular=self.circular,
        )
        return copy_extremes(self, new_cmap)

    def to_categorical(
        self,
        values_to_labels: Dict[Any, str] | int,
        endpoint: bool | None = None,
        use_discrete: bool | None = None,
    ) -> "Cmap":
        """Convert a colormap to categorical.

        Args:
            values_to_labels (dict | int): Mapping from values to labels, or
                number of categories if int.
            endpoint (bool | None): Whether the last color is included at 1.0.
            use_discrete (bool | None): If True, use the colormap's defined colors directly rather than sampling across its range.

        Returns:
            Cmap: Categorical version of the colormap.
        """
        if isinstance(values_to_labels, int):
            values_to_labels = {i: str(i) for i in range(values_to_labels)}

        values_to_labels = dict(sorted(values_to_labels.items()))

        keys = list(values_to_labels.keys())
        labels = list(values_to_labels.values())
        sorted_values = keys

        n_classes = len(sorted_values)
        bounds = np.array(sorted_values + [sorted_values[-1] + 1]) - 0.5
        norm = BoundaryNorm(bounds, n_classes)

        ticks = [float(t) for t in np.arange(0.5, n_classes)]

        if use_discrete:
            colors = [self(i) for i in range(n_classes)]
        else:
            if not isinstance(endpoint, bool):
                endpoint = not self.circular
            offset = -1 if endpoint else 0
            colors = [self(i / max(n_classes + offset, 1)) for i in range(n_classes)]

        return Cmap(
            colors=colors,
            name=self.name,
            N=n_classes,
            categorical=True,
            gradient=False,
            circular=self.circular,
            ticks=ticks,
            labels=labels,
            norm=norm,
            values=sorted_values,
        )

    def to_discrete(self, n: int) -> "Cmap":
        """Convert a colormap to a discretized version of itself.

        Args:
            n (int): Number of steps (i.e., discrete colors).

        Returns:
            Cmap: Discretized version of the colormap.
        """
        new_cmap = self.to_categorical(n)
        new_cmap.categorical = False
        new_cmap.ticks = []
        new_cmap.labels = []
        new_cmap.norm = None
        new_cmap.values = []
        return new_cmap

    def set_alpha(self, value: float) -> "Cmap":
        """Return a copy of the colormap with modified alpha transparency.

        Args:
            value (float): Alpha value in the range [0, 1].

        Returns:
            Cmap: Colormap with updated transparency.
        """
        if not 0 <= value <= 1:
            raise ValueError(f"Invalid alpha value: '{value}' (must be in the 0-1 range)")

        new_cmap = Cmap(
            colors=[Color(c).set_alpha(value) for c in np.asarray(self.colors)],
            name=self.name,
            N=self.N,
            categorical=self.categorical,
            gradient=self.gradient,
            circular=self.circular,
            ticks=self.ticks,
            labels=self.labels,
            norm=self.norm,
        )

        if self._rgba_bad is not None:  # type: ignore
            new_cmap._rgba_bad = Color(self._rgba_bad, is_normalized=True).set_alpha(value).rgba  # type: ignore
        if self._rgba_over is not None:  # type: ignore
            new_cmap._rgba_over = Color(self._rgba_over, is_normalized=True).set_alpha(value).rgba  # type: ignore
        if self._rgba_under is not None:  # type: ignore
            new_cmap._rgba_under = Color(self._rgba_under, is_normalized=True).set_alpha(value).rgba  # type: ignore

        return new_cmap

    def blend(self, value: float, blend_color: Color | ColorLike = "white") -> "Cmap":
        """Return a copy of the colormap blended with a second color.

        Args:
            value (float): Blend factor in the range [0, 1].
            blend_color (Color | str): Color to blend with.

        Returns:
            Cmap: Blended colormap.
        """
        if not 0 <= value <= 1:
            raise ValueError(f"Invalid blend value: '{value}' (must be in the 0-1 range)")

        new_cmap = Cmap(
            colors=[Color(c).blend(value, blend_color) for c in np.asarray(self.colors)],
            name=self.name,
            N=self.N,
            categorical=self.categorical,
            gradient=self.gradient,
            circular=self.circular,
            ticks=self.ticks,
            labels=self.labels,
            norm=self.norm,
        )

        if self._rgba_bad is not None:  # type: ignore
            new_cmap._rgba_bad = (  # type: ignore
                Color(self._rgba_bad, is_normalized=True).blend(value, blend_color).rgba  # type: ignore
            )  # type: ignore
        if self._rgba_over is not None:  # type: ignore
            new_cmap._rgba_over = (  # type: ignore
                Color(self._rgba_over, is_normalized=True).blend(value, blend_color).rgba  # type: ignore
            )  # type: ignore
        if self._rgba_under is not None:  # type: ignore
            new_cmap._rgba_under = (  # type: ignore
                Color(self._rgba_under, is_normalized=True).blend(value, blend_color).rgba  # type: ignore
            )  # type: ignore

        return new_cmap

    @property
    def rgba_list(self) -> list[tuple[float, ...]]:
        """List of RGBA tuples representing all colors in the colormap."""
        return [Color(c, is_normalized=True).rgba for c in np.array(self.colors)]

    # def set_alpha_gradient(self, alpha_input: list) -> "Cmap":
    #     from matplotlib.colors import ListedColormap
    #     from scipy.interpolate import interp1d

    #     # Interpolate to 256 values
    #     n_colors = 256
    #     x_old = np.linspace(0, 1, len(alpha_input))
    #     x_new = np.linspace(0, 1, n_colors)
    #     alpha_interp = interp1d(x_old, alpha_input, kind="linear")(x_new)

    #     # Get base colormap and apply interpolated alpha
    #     colors = self(np.linspace(0, 1, n_colors))
    #     colors[:, 3] = alpha_interp  # Replace alpha channel

    #     # Create transparent colormap
    #     new_cmap = Cmap(colors, name=self.name)

    @property
    def opaque(self) -> "Cmap":
        """Return an opaque version of the colormap (alpha set to 1)."""
        return colormap_to_opaque(self)

    @property
    def alphamap(self) -> "Cmap":
        """Return the alpha-mapped version of the colormap."""
        return colormap_to_alphamap(self)

    @property
    def blended(self) -> "Cmap":
        """Return a blended version of the colormap (predefined blending)."""
        return colormap_to_blended(self)

    def __new__(cls, *args, **kwargs):
        """Allow instantiation from an existing Colormap or standard arguments."""
        if len(args) == 1 and isinstance(args[0], Colormap):
            return cls.from_colormap(args[0])
        return super().__new__(cls)

    def reversed(self, name: str | None = None) -> "Cmap":
        return Cmap(
            colors=cast(Sequence, super().reversed(name).colors),
            name=name or self.name.removesuffix("_r")
            if self.name.endswith("_r")
            else self.name + "_r",
            N=self.N,
            categorical=self.categorical,
            ticks=list(reversed(self.ticks)),
            labels=list(reversed(self.labels)),
            norm=self.norm,
            values=list(reversed(self.values)),
            gradient=self.gradient,
            circular=self.circular,
        )

__init__

__init__(
    colors: Sequence,
    name: str = "colormap",
    N: int | None = None,
    categorical: bool = False,
    ticks: List[float] | None = None,
    labels: List[str] | None = None,
    norm: Normalize | None = None,
    values: List | None = None,
    gradient: bool = False,
    circular: bool = False,
)

Initialize a Cmap.

Parameters:

Name Type Description Default
colors Sequence

Sequence of colors (strings or ColorLike objects).

required
name str

Name of the colormap. Defaults to "colormap".

'colormap'
N int | None

Number of discrete colors. Defaults to None.

None
categorical bool

Whether the colormap is discrete/categorical. Defaults to False.

False
ticks list[float] | None

Optional tick positions for categorical plots. Defaults to None.

None
labels list[str] | None

Optional labels corresponding to ticks. Defaults to None.

None
norm Normalize | None

Normalization strategy for value mapping. Defaults to None.

None
gradient bool

If True, generate intermediate gradient colors. Defaults to False.

False
circular bool

If True, colormap wraps around cyclically. Defaults to False.

False
Source code in earthcarekit/colormap/_cmap.py
def __init__(
    self,
    colors: Sequence,
    name: str = "colormap",
    N: int | None = None,
    categorical: bool = False,
    ticks: List[float] | None = None,
    labels: List[str] | None = None,
    norm: Normalize | None = None,
    values: List | None = None,
    gradient: bool = False,
    circular: bool = False,
):
    """Initialize a Cmap.

    Args:
        colors (Sequence): Sequence of colors (strings or ColorLike objects).
        name (str): Name of the colormap. Defaults to "colormap".
        N (int | None): Number of discrete colors. Defaults to None.
        categorical (bool): Whether the colormap is discrete/categorical. Defaults to False.
        ticks (list[float] | None): Optional tick positions for categorical plots. Defaults to None.
        labels (list[str] | None): Optional labels corresponding to ticks. Defaults to None.
        norm (Normalize | None): Normalization strategy for value mapping. Defaults to None.
        gradient (bool): If True, generate intermediate gradient colors. Defaults to False.
        circular (bool): If True, colormap wraps around cyclically. Defaults to False.
    """
    _colors: list = [Color(c) if isinstance(c, str) else c for c in colors]

    if gradient:
        tmp_cmap = LinearSegmentedColormap.from_list("tmp_cmap", _colors, N=256)
        _colors = [tmp_cmap(i) for i in range(256)]

    super().__init__(_colors, name=name, N=N or len(_colors))
    self.categorical = categorical
    self.gradient = gradient
    self.circular = circular
    self.ticks = ticks or []
    self.labels = labels or []
    self.norm = norm
    self.values = values or []

__new__

__new__(*args, **kwargs)

Allow instantiation from an existing Colormap or standard arguments.

Source code in earthcarekit/colormap/_cmap.py
def __new__(cls, *args, **kwargs):
    """Allow instantiation from an existing Colormap or standard arguments."""
    if len(args) == 1 and isinstance(args[0], Colormap):
        return cls.from_colormap(args[0])
    return super().__new__(cls)

alphamap property

alphamap: Cmap

Return the alpha-mapped version of the colormap.

blend

blend(value: float, blend_color: Color | ColorLike = 'white') -> Cmap

Return a copy of the colormap blended with a second color.

Parameters:

Name Type Description Default
value float

Blend factor in the range [0, 1].

required
blend_color Color | str

Color to blend with.

'white'

Returns:

Name Type Description
Cmap Cmap

Blended colormap.

Source code in earthcarekit/colormap/_cmap.py
def blend(self, value: float, blend_color: Color | ColorLike = "white") -> "Cmap":
    """Return a copy of the colormap blended with a second color.

    Args:
        value (float): Blend factor in the range [0, 1].
        blend_color (Color | str): Color to blend with.

    Returns:
        Cmap: Blended colormap.
    """
    if not 0 <= value <= 1:
        raise ValueError(f"Invalid blend value: '{value}' (must be in the 0-1 range)")

    new_cmap = Cmap(
        colors=[Color(c).blend(value, blend_color) for c in np.asarray(self.colors)],
        name=self.name,
        N=self.N,
        categorical=self.categorical,
        gradient=self.gradient,
        circular=self.circular,
        ticks=self.ticks,
        labels=self.labels,
        norm=self.norm,
    )

    if self._rgba_bad is not None:  # type: ignore
        new_cmap._rgba_bad = (  # type: ignore
            Color(self._rgba_bad, is_normalized=True).blend(value, blend_color).rgba  # type: ignore
        )  # type: ignore
    if self._rgba_over is not None:  # type: ignore
        new_cmap._rgba_over = (  # type: ignore
            Color(self._rgba_over, is_normalized=True).blend(value, blend_color).rgba  # type: ignore
        )  # type: ignore
    if self._rgba_under is not None:  # type: ignore
        new_cmap._rgba_under = (  # type: ignore
            Color(self._rgba_under, is_normalized=True).blend(value, blend_color).rgba  # type: ignore
        )  # type: ignore

    return new_cmap

blended property

blended: Cmap

Return a blended version of the colormap (predefined blending).

from_colormap classmethod

from_colormap(cmap: Colormap, N: int = 256, name: str | None = None) -> Cmap

Create a Cmap instance from an existing Matplotlib colormap.

Parameters:

Name Type Description Default
cmap Colormap

Source colormap to convert.

required
N int

Number of discrete colors (if needed, e.g, for categorical colormaps with limited number of colors). Defaults to 256.

256

Returns:

Name Type Description
Cmap Cmap

New colormap.

Source code in earthcarekit/colormap/_cmap.py
@classmethod
def from_colormap(cls, cmap: Colormap, N: int = 256, name: str | None = None) -> "Cmap":
    """Create a Cmap instance from an existing Matplotlib colormap.

    Args:
        cmap (Colormap): Source colormap to convert.
        N (int): Number of discrete colors (if needed, e.g, for categorical
            colormaps with limited number of colors). Defaults to 256.

    Returns:
        Cmap: New colormap.
    """
    if isinstance(cmap, cls):
        return cmap
    elif isinstance(cmap, ListedColormap):
        colors = list(cmap.colors)  # type: ignore
        if isinstance(colors, np.ndarray) and colors.ndim == 2:
            N = len(colors)
        else:
            N = cmap.N
    else:
        colors = [cmap(x) for x in np.linspace(0, 1, N)]

    _colors = []
    for c in colors:
        if (
            isinstance(c, (np.ndarray, list, tuple))
            and not isinstance(c, str)
            and all([_c <= 1 for _c in c])
        ):
            _colors.append(Color(c, is_normalized=True))  # type: ignore
        else:
            _colors = [Color(c) for c in colors]  # type: ignore
            continue
    new_cmap = cls(
        [c.hex for c in _colors],
        name=name or cmap.name,
        N=N,
    )
    new_cmap = copy_extremes(cmap, new_cmap)
    return new_cmap

opaque property

opaque: Cmap

Return an opaque version of the colormap (alpha set to 1).

rgba_list property

rgba_list: list[tuple[float, ...]]

List of RGBA tuples representing all colors in the colormap.

set_alpha

set_alpha(value: float) -> Cmap

Return a copy of the colormap with modified alpha transparency.

Parameters:

Name Type Description Default
value float

Alpha value in the range [0, 1].

required

Returns:

Name Type Description
Cmap Cmap

Colormap with updated transparency.

Source code in earthcarekit/colormap/_cmap.py
def set_alpha(self, value: float) -> "Cmap":
    """Return a copy of the colormap with modified alpha transparency.

    Args:
        value (float): Alpha value in the range [0, 1].

    Returns:
        Cmap: Colormap with updated transparency.
    """
    if not 0 <= value <= 1:
        raise ValueError(f"Invalid alpha value: '{value}' (must be in the 0-1 range)")

    new_cmap = Cmap(
        colors=[Color(c).set_alpha(value) for c in np.asarray(self.colors)],
        name=self.name,
        N=self.N,
        categorical=self.categorical,
        gradient=self.gradient,
        circular=self.circular,
        ticks=self.ticks,
        labels=self.labels,
        norm=self.norm,
    )

    if self._rgba_bad is not None:  # type: ignore
        new_cmap._rgba_bad = Color(self._rgba_bad, is_normalized=True).set_alpha(value).rgba  # type: ignore
    if self._rgba_over is not None:  # type: ignore
        new_cmap._rgba_over = Color(self._rgba_over, is_normalized=True).set_alpha(value).rgba  # type: ignore
    if self._rgba_under is not None:  # type: ignore
        new_cmap._rgba_under = Color(self._rgba_under, is_normalized=True).set_alpha(value).rgba  # type: ignore

    return new_cmap

to_categorical

to_categorical(
    values_to_labels: Dict[Any, str] | int,
    endpoint: bool | None = None,
    use_discrete: bool | None = None,
) -> Cmap

Convert a colormap to categorical.

Parameters:

Name Type Description Default
values_to_labels dict | int

Mapping from values to labels, or number of categories if int.

required
endpoint bool | None

Whether the last color is included at 1.0.

None
use_discrete bool | None

If True, use the colormap's defined colors directly rather than sampling across its range.

None

Returns:

Name Type Description
Cmap Cmap

Categorical version of the colormap.

Source code in earthcarekit/colormap/_cmap.py
def to_categorical(
    self,
    values_to_labels: Dict[Any, str] | int,
    endpoint: bool | None = None,
    use_discrete: bool | None = None,
) -> "Cmap":
    """Convert a colormap to categorical.

    Args:
        values_to_labels (dict | int): Mapping from values to labels, or
            number of categories if int.
        endpoint (bool | None): Whether the last color is included at 1.0.
        use_discrete (bool | None): If True, use the colormap's defined colors directly rather than sampling across its range.

    Returns:
        Cmap: Categorical version of the colormap.
    """
    if isinstance(values_to_labels, int):
        values_to_labels = {i: str(i) for i in range(values_to_labels)}

    values_to_labels = dict(sorted(values_to_labels.items()))

    keys = list(values_to_labels.keys())
    labels = list(values_to_labels.values())
    sorted_values = keys

    n_classes = len(sorted_values)
    bounds = np.array(sorted_values + [sorted_values[-1] + 1]) - 0.5
    norm = BoundaryNorm(bounds, n_classes)

    ticks = [float(t) for t in np.arange(0.5, n_classes)]

    if use_discrete:
        colors = [self(i) for i in range(n_classes)]
    else:
        if not isinstance(endpoint, bool):
            endpoint = not self.circular
        offset = -1 if endpoint else 0
        colors = [self(i / max(n_classes + offset, 1)) for i in range(n_classes)]

    return Cmap(
        colors=colors,
        name=self.name,
        N=n_classes,
        categorical=True,
        gradient=False,
        circular=self.circular,
        ticks=ticks,
        labels=labels,
        norm=norm,
        values=sorted_values,
    )

to_discrete

to_discrete(n: int) -> Cmap

Convert a colormap to a discretized version of itself.

Parameters:

Name Type Description Default
n int

Number of steps (i.e., discrete colors).

required

Returns:

Name Type Description
Cmap Cmap

Discretized version of the colormap.

Source code in earthcarekit/colormap/_cmap.py
def to_discrete(self, n: int) -> "Cmap":
    """Convert a colormap to a discretized version of itself.

    Args:
        n (int): Number of steps (i.e., discrete colors).

    Returns:
        Cmap: Discretized version of the colormap.
    """
    new_cmap = self.to_categorical(n)
    new_cmap.categorical = False
    new_cmap.ticks = []
    new_cmap.labels = []
    new_cmap.norm = None
    new_cmap.values = []
    return new_cmap

cmaps module-attribute

cmaps: dict[str, Colormap] = get_cmaps()

Dictionary of custom colormaps for earthcarekit.

combine_cmaps

combine_cmaps(
    cmap1: str | Colormap | None,
    cmap2: str | Colormap | None,
    name: str = "combined_cmap",
    n: int = 256,
) -> Cmap

Create a combined colormap from two colormaps.

Parameters:

Name Type Description Default
cmap1 str | Colormap | None

Colormap to be modified.

required
cmap2 str | Colormap | None

Colormap to be modified

required
name str

New colormap name. Defaults to "combined_cmap".

'combined_cmap'
n int

Number of colors.

256

Returns:

Name Type Description
Cmap Cmap

The combined colormap.

Source code in earthcarekit/colormap/_combine_cmaps.py
def combine_cmaps(
    cmap1: str | Colormap | None,
    cmap2: str | Colormap | None,
    name: str = "combined_cmap",
    n: int = 256,
) -> Cmap:
    """Create a combined colormap from two colormaps.

    Args:
        cmap1 (str | Colormap | None): Colormap to be modified.
        cmap2 (str | Colormap | None): Colormap to be modified
        name (str): New colormap name. Defaults to "combined_cmap".
        n (int): Number of colors.

    Returns:
        Cmap: The combined colormap.
    """
    return get_cmap(
        combine_mpl_cmaps(
            cmap1=get_cmap(cmap1),
            cmap2=get_cmap(cmap2),
            name=name,
            n=n,
        ),
    )

get_cmap

get_cmap(cmap: CmapLike | None, **kwargs) -> Cmap

Return a colormap given by cmap.

Parameters:

Name Type Description Default
cmap CmapLike | None
  • If a colormap, return it.
  • If a str, return first matching colormap from earthcarekit, cmcrameri, plotly, or matplotlib (in that order).
  • If a list of colors, create a corresponding descrete colormap.
  • If None, return the default colormap ("viridis").
required

Returns: Cmap: The resolved colormap.

Source code in earthcarekit/colormap/_get_cmap.py
def get_cmap(cmap: CmapLike | None, **kwargs) -> Cmap:
    """Return a colormap given by `cmap`.

    Args:
        cmap (CmapLike | None):
            - If a colormap, return it.
            - If a `str`, return first matching colormap from `earthcarekit`, `cmcrameri`,
              `plotly`, or `matplotlib` (in that order).
            - If a `list` of colors, create a corresponding descrete colormap.
            - If None, return the default colormap ("viridis").
    Returns:
        Cmap:
            The resolved colormap.
    """
    if isinstance(cmap, (str, Colormap)) or cmap is None:
        return _get_cmap(cmap, **kwargs)

    if len(kwargs) > 0:
        raise TypeError(f"get_cmap() got an unexpected keyword argument '{tuple(kwargs)[0]}'")

    if isinstance(cmap, Cmap):
        return cmap.copy()

    return Cmap.from_colormap(ListedColormap(cmap))

rename_cmap

rename_cmap(cmap: Colormap, name: str) -> Colormap

Returns the given cmap with the new name.

Source code in earthcarekit/colormap/_rename.py
4
5
6
7
8
def rename_cmap(cmap: Colormap, name: str) -> Colormap:
    """Returns the given `cmap` with the new `name`."""
    result_cmap = cmap.copy()
    result_cmap.name = name
    return result_cmap

shift_cmap

shift_cmap(
    cmap: str | Colormap | None,
    start: float = 0.0,
    midpoint: float = 0.5,
    stop: float = 1.0,
    name: str = "shifted_cmap",
) -> Cmap

Create a colormap with its center point shifted to a specified value.

This function is useful for data with asymmetric ranges (e.g., negative min and positive max) where you want the center of the colormap to align with a specific value like zero.

Parameters:

Name Type Description Default
cmap str | Colormap | None

Colormap to be modified

required
start float

Lower bound of the colormap range (value between 0 and midpoint). Defaults to 0.0.

0.0
midpoint float

New center point of the colormap (value between 0 and 1). Defaults to 0.5. For data ranging from vmin to vmax where you want the center at value v, set midpoint = 1 - vmax/(vmax + abs(vmin))

0.5
stop float

Upper bound of the colormap range (value between midpoint and 1). Defaults to 1.0.

1.0
name str

Name of the new colormap. Defaults to "shifted_cmap".

'shifted_cmap'

Returns:

Name Type Description
Cmap Cmap

New colormap with shifted center

Source code in earthcarekit/colormap/_shift_cmap.py
def shift_cmap(
    cmap: str | Colormap | None,
    start: float = 0.0,
    midpoint: float = 0.5,
    stop: float = 1.0,
    name: str = "shifted_cmap",
) -> Cmap:
    """Create a colormap with its center point shifted to a specified value.

    This function is useful for data with asymmetric ranges (e.g., negative min and
    positive max) where you want the center of the colormap to align with a specific
    value like zero.

    Args:
        cmap (str | Colormap | None): Colormap to be modified
        start (float): Lower bound of the colormap range (value between 0 and `midpoint`). Defaults to 0.0.
        midpoint (float): New center point of the colormap (value between 0 and 1). Defaults to 0.5.
            For data ranging from vmin to vmax where you want the center at value v,
            set midpoint = 1 - vmax/(vmax + abs(vmin))
        stop (float): Upper bound of the colormap range (value between `midpoint` and 1). Defaults to 1.0.
        name (str): Name of the new colormap. Defaults to "shifted_cmap".

    Returns:
        Cmap: New colormap with shifted center
    """
    from ._get_cmap import get_cmap

    cmap_old = get_cmap(cmap)
    cmap_new = shift_mpl_colormap(
        cmap_old,
        start=start,
        midpoint=midpoint,
        stop=stop,
        name=name,
    )
    cmap_new = get_cmap(cmap_new)
    cmap_new.categorical = cmap_old.categorical
    cmap_new.ticks = cmap_old.ticks
    cmap_new.labels = cmap_old.labels
    cmap_new.norm = cmap_old.norm
    cmap_new.values = cmap_old.values
    cmap_new.gradient = cmap_old.gradient
    cmap_new.circular = cmap_old.circular
    return cmap_new