import numpy as np
from matplotlib.colors import Colormap, LinearSegmentedColormap, ListedColormap
def _subset_colors(colors, interval, n):
"""
Subset a list of colors based on the provided interval and number of colors (n).
Parameters
----------
colors : array-like
List of RGB or RGBA colors.
interval : tuple
A tuple of two float values between 0 and 1, indicating the fraction of the colormap to retain.
n : int, optional
Number of colors to return. If None, all colors in the specified interval are returned.
Returns
-------
np.ndarray
Subset of colors based on the interval and n.
"""
# Check interval
interval = check_interval(interval)
# Define start and stop integer indices (inclusive)
start = int(np.floor(interval[0] * len(colors)))
stop = int(np.ceil(interval[1] * len(colors))) - 1
# Define actual indices to use to retrieve <n> colors
# - Act as cmap.resampled(n)
if n is None:
index = np.arange(start, stop + 1, dtype=int)
else:
index = np.array(np.rint(np.linspace(start, stop, num=n)), dtype=int)
# Retrieve color list
colors = np.array(colors)[index]
return colors
def _create_new_cmap(colors, old_cmap, name=None):
"""
Create a new colormap with the specified colors.
Parameters
----------
colors : array-like
List of RGB or RGBA colors to define the new colormap.
old_cmap : Colormap
The original colormap to be adapted.
name : str, optional
Name for the new colormap. If None, the name of the original colormap is used.
Returns
-------
Colormap
A new colormap created using the provided colors.
"""
if name is None:
name = old_cmap.name
if isinstance(old_cmap, ListedColormap):
cmap = ListedColormap(name=name, colors=colors)
else:
cmap = LinearSegmentedColormap.from_list(name=name, colors=colors, N=len(colors))
return cmap
[docs]
def check_interval(interval):
"""
Validate that the interval is within the range [0, 1].
Parameters
----------
interval : tuple or None
A tuple of two float values between 0 and 1 representing the range of the colormap.
If None, the interval is set to (0, 1).
Returns
-------
tuple
Validated interval.
Raises
------
ValueError
If the interval is not within the range [0, 1] or if the first value is greater than or equal to the second.
"""
if interval is None:
interval = (0, 1)
if not ((0 <= interval[0] <= 1) and (0 <= interval[1] <= 1)):
raise ValueError(
"The colormap 'interval' must have values between 0 and 1.",
)
if interval[0] >= interval[1]:
raise ValueError("The first value of the interval must be less than the second.")
return interval
[docs]
def get_cmap_colors(cmap, *, interval=None, n=None, alpha=None, bias=1):
"""
Retrieve a list of RGB colors from a colormap, optionally subsetting by an interval and number of colors (n).
Parameters
----------
cmap : matplotlib.colors.Colormap
A colormap instance (e.g., LinearSegmentedColormap or ListedColormap).
interval : tuple of float, optional
A tuple (start, end) with values between 0 and 1, representing the fraction of the colormap to retain.
Defaults to the full colormap (0, 1).
n : int, optional
Number of colors to return. If None, the number of colors depends on the colormap (default: None).
alpha : float, optional
A transparency value to apply to the colors, where 0 is fully transparent and 1 is fully opaque.
If `alpha` is None (the default), the original transparency of the colors is preserved.
If provided, all colors will be updated to have the specified alpha value.
bias : float, optional
A factor that skews the distribution of colors in the colormap.
A `bias` of 1 (default) results in no bias.
Values less than 1 space the colors more widely at the high end of the color map.
Values greater than 1 space the colors more widely at the lower end of the colormap.
Returns
-------
np.ndarray
A NumPy array of RGB colors extracted from the colormap.
Notes
-----
- If the colormap is a LinearSegmentedColormap and does not have an `N` attribute, 256 colors are returned.
- If `interval` is provided, only the specified range of the colormap will be returned.
"""
# Get colors
if hasattr(cmap, "N"):
rgb_colors = cmap(np.linspace(0, 1, cmap.N) ** bias, alpha=alpha)
else:
rgb_colors = cmap(np.linspace(0, 1, 256) ** bias, alpha=alpha)[:, :3]
# Subset colors if asked
rgb_colors = _subset_colors(colors=rgb_colors, interval=interval, n=n)
return rgb_colors
[docs]
def get_cmap_segmentdata(cmap, n=None):
"""
Retrieve the segment data of a colormap, or generate it if not present.
Parameters
----------
cmap : matplotlib.colors.Colormap
A colormap instance (e.g., LinearSegmentedColormap or ListedColormap).
n : int, optional
The number of discrete points to sample from the colormap. If None, the colormap's `N` attribute is used.
Returns
-------
dict
A dictionary representing the colormap's segment data for red, green, and blue channels.
Each entry in the dictionary corresponds to a list of (x, y0, y1) tuples, where:
- `x` is the position (0 to 1) along the colormap.
- `y0` is the color value to the left of `x`.
- `y1` is the color value to the right of `x`.
Notes
-----
- The segment data is used to create `LinearSegmentedColormap` objects.
- If the colormap has a `_segmentdata` attribute, it is returned directly.
- If the colormap is sampled using `n` points, this function constructs the segment data manually.
"""
# Check if the colormap already has `_segmentdata` and return it
if hasattr(cmap, "_segmentdata"):
return cmap._segmentdata
# If `n` is not provided, use the number of colors in the colormap
if n is None:
n = cmap.N
# Sample `n` points from the colormap along the range [0, 1]
x = np.linspace(0, 1, n)
rgb = cmap(x)
# Extract blue channel values at each sample point
b3 = rgb[:, 2] # Right-hand value of blue at sample point
b2 = rgb[:, 2] # Left-hand value of blue at sample point
# Extract green channel values at each sample point
g3 = rgb[:, 1] # Right-hand value of green at sample point
g2 = rgb[:, 1] # Left-hand value of green at sample point
# Extract red channel values at each sample point
r3 = rgb[:, 0] # Right-hand value of red at sample point
r2 = rgb[:, 0] # Left-hand value of red at sample point
# Create lists of tuples for red, green, and blue segment data
R = list(zip(x, r2, r3, strict=False)) # Red segment data
G = list(zip(x, g2, g3, strict=False)) # Green segment data
B = list(zip(x, b2, b3, strict=False)) # Blue segment data
# Create a dictionary to store the segment data for each color channel
k = ["red", "green", "blue"]
segmentdata = dict(zip(k, [R, G, B], strict=False))
return segmentdata
[docs]
def get_cmap_lab(cmap):
"""
Convert a colormap's RGB values into the CAM02-UCS color space.
Parameters
----------
cmap : matplotlib.colors.Colormap
The input colormap, which can be a `ListedColormap` or a `LinearSegmentedColormap`.
Returns
-------
np.ndarray
A NumPy array of LAB values corresponding to the colormap's colors in the CAM02-UCS color space.
The LAB values represent Lightness (L) and color components (A, B) in a perceptually uniform space.
Raises
------
ImportError
If the `colorspacious` package is not installed.
Notes
-----
This function converts the RGB values of the input colormap into the CAM02-UCS color space, which is
designed to provide perceptually uniform color information, meaning that equal distances in this color space
correspond to equal perceptual differences. The conversion is done using the `colorspacious` package.
The LAB values consist of:
- L: Lightness
- A and B: Unique color components
Examples
--------
>>> import matplotlib.pyplot as plt
>>> from matplotlib import cm
>>> cmap = cm.viridis
>>> lab = get_cmap_lab(cmap)
>>> print(lab)
"""
# Check if the colorspacious package is available
try:
from colorspacious import cspace_convert
except ImportError:
raise ImportError(
"The 'colorspacious' package is required but not found. "
"Please install it using the following command: "
"conda install -c conda-forge colorspacious",
) from None
# Get RGB colors
rgb_colors = get_cmap_colors(cmap)[:, :3]
# Convert RGB colors to CAM02 Uniform Color Space
# LAB --> L(ightness) AB unique colors ..
lab = cspace_convert(rgb_colors, "sRGB1", "CAM02-UCS")
return lab
[docs]
def get_cmap_lightness(cmap):
"""
Extract the lightness component of a colormap using the CAM02-UCS color space.
Parameters
----------
cmap : matplotlib.colors.Colormap
The input colormap, which can be a `ListedColormap` or a `LinearSegmentedColormap`.
Returns
-------
lightness : ndarray
A 1D array of lightness values corresponding to the colors in the colormap.
These values are derived from the CAM02-UCS color space's lightness (L) component.
Raises
------
ImportError
If the `colorspacious` package is not installed, an error is raised.
Notes
-----
The function converts the RGB values of the input colormap into the CAM02-UCS
color space, which provides perceptually uniform color information. The lightness
component (L) is then extracted and returned as a 1D array.
Examples
--------
>>> import matplotlib.pyplot as plt
>>> from matplotlib import cm
>>> cmap = cm.viridis
>>> lightness = get_cmap_lightness(cmap)
>>> print(lightness)
"""
lab = get_cmap_lab(cmap)
lightness = lab[:, 0]
return lightness
[docs]
def adapt_cmap(cmap, *, interval=None, n=None, alpha=None, bias=1):
"""
Adapt a colormap by subsetting its colors and applying transparency, if specified.
Parameters
----------
cmap : matplotlib.colors.Colormap
The original colormap to adapt (e.g., LinearSegmentedColormap or ListedColormap).
interval : tuple of float, optional
A tuple (start, end) with values between 0 and 1, indicating the fraction of the colormap to use.
Defaults to using the full colormap (0, 1).
n : int, optional
The number of colors to return. If None, the colormap is not resampled.
alpha : float, optional
A transparency value to apply to the colors, where 0 is fully transparent and 1 is fully opaque.
If `alpha` is None (the default), the original transparency of the colors is preserved.
bias : float, optional
A factor that skews the distribution of colors in the colormap.
A `bias` of 1 (default) results in no bias.
Values less than 1 space the colors more widely at the high end of the color map.
Values greater than 1 space the colors more widely at the lower end of the colormap.
Returns
-------
matplotlib.colors.Colormap
A new colormap that reflects the specified interval, n, alpha and bias values.
Notes
-----
- The function creates a new colormap by extracting a subset of the colors from the original colormap.
- The resulting colormap has the same name as the original, unless specified otherwise in the internal logic.
"""
# Subset colormap (interval and n)
colors = get_cmap_colors(cmap=cmap, interval=interval, n=n, alpha=alpha, bias=bias)
# Create new colormap
cmap = _create_new_cmap(colors=colors, old_cmap=cmap)
return cmap
[docs]
def infer_cmap_type(cmap):
"""
Infer the type of a colormap based on its lightness values and color differences.
Parameters
----------
cmap : matplotlib.colors.Colormap
The input colormap, which can be a `ListedColormap` or a `LinearSegmentedColormap`.
Returns
-------
str
A string indicating the type of colormap:
- 'misc' if the colormap does not fit other categories.
- 'sequential' if lightness values always increase or decrease.
- 'diverging' if the colormap has a central extreme with sequential sides.
- 'cyclic' if the perceptual differences between colors indicate a repeating pattern.
- 'isoluminant' if all lightness values are the same.
Notes
-----
This function analyzes the lightness and color differences of the colormap
to classify it into one of several categories: sequential, diverging, cyclic, or miscellaneous.
It is adapted from the cmasher library's `get_cmap_type` function.
"""
# Extract the LAB color values
lab = get_cmap_lab(cmap)
# Get lightness values of colormap
lightness = lab[:, 0] # get_cmap_lightness(cmap)
# Calculate the difference between consecutive lightness values
lightness_diff = np.diff(lightness)
# Determine the central indices for the lightness array
n = len(lightness) - 1
central_indices = [int(np.floor(n / 2)), int(np.ceil(n / 2))]
# Calculate lightness differences for the left and right halves of the colormap
lightness_diff_left = np.diff(lightness[: central_indices[0] + 1])
lightness_diff_right = np.diff(lightness[central_indices[1] :])
# Calculate the perceptual differences between the last two and first two colors
# --> To test for cyclic colormap
lab_endpoints = lab[[-2, -1, 0, 1]]
deltas = np.sqrt(np.sum(np.diff(lab_endpoints, axis=0) ** 2, axis=-1))
# ISOLUMINANT
# - If all lightness values are the same, categorize as "iso"
if np.allclose(lightness_diff, 0):
return "isoluminant"
# SEQUENTIAL
# - If lightness values always increase or decrease
if np.isclose(np.abs(np.sum(lightness_diff)), np.sum(np.abs(lightness_diff))):
return "sequential"
# DIVERGING
# - If the lightness values have a central extreme and sequential sides, then it is diverging
if np.isclose(np.abs(np.sum(lightness_diff_left)), np.sum(np.abs(lightness_diff_left))) and np.isclose(
np.abs(np.sum(lightness_diff_right)),
np.sum(np.abs(lightness_diff_right)),
):
# If the perceptual difference between the last and first value is
# comparable to the other perceptual differences, it is cyclic
if np.all(np.abs(np.diff(deltas)) < deltas[::2]) and np.diff(deltas[::2]):
return "cyclic"
# Otherwise, it is a normal diverging colormap
return "diverging"
return "misc"
[docs]
def is_sequential_cmap(cmap):
"""
Check if the colormap is of type 'sequential'.
Parameters
----------
cmap : matplotlib.colors.Colormap
The input colormap, which can be a `ListedColormap` or a `LinearSegmentedColormap`.
Returns
-------
bool
True if the colormap is sequential, False otherwise.
"""
return infer_cmap_type(cmap) == "sequential"
[docs]
def is_diverging_cmap(cmap):
"""
Check if the colormap is of type 'diverging'.
Parameters
----------
cmap : matplotlib.colors.Colormap
The input colormap, which can be a `ListedColormap` or a `LinearSegmentedColormap`.
Returns
-------
bool
True if the colormap is diverging, False otherwise.
"""
return infer_cmap_type(cmap) == "diverging"
[docs]
def is_isoluminant_cmap(cmap):
"""
Check if the colormap is of type 'isoluminant'.
Parameters
----------
cmap : matplotlib.colors.Colormap
The input colormap, which can be a `ListedColormap` or a `LinearSegmentedColormap`.
Returns
-------
bool
True if the colormap is isoluminant, False otherwise.
"""
return infer_cmap_type(cmap) == "isoluminant"
[docs]
def is_cyclic_cmap(cmap):
"""
Check if the colormap is of type 'cyclic'.
Parameters
----------
cmap : matplotlib.colors.Colormap
The input colormap, which can be a `ListedColormap` or a `LinearSegmentedColormap`.
Returns
-------
bool
True if the colormap is cyclic, False otherwise.
"""
return infer_cmap_type(cmap) == "cyclic"
[docs]
def get_cvd_cmap(cmap, *, cvd_type, severity=50):
"""
Return a Matplotlib colormap emulating a specified color-vision deficiency (CVD).
This function simulates how the colormap would appear to someone with a particular type of color-vision
deficiency using the `colorspacious` package.
Parameters
----------
cmap : matplotlib.colors.Colormap
The input colormap to be converted.
It can be an instance of either `ListedColormap` or `LinearSegmentedColormap`.
cvd_type : str
The type of color-vision deficiency to simulate. Valid options are:
'deuteranomaly', 'protanomaly', and 'tritanomaly'.
severity : int, optional
The severity of the color-vision deficiency on a scale from 0 (no deficiency) to 100 (complete deficiency),
by default 50. For people suffering of tritanomaly, only severity = 100 actually exists in reality.
Returns
-------
matplotlib.colors.Colormap
A new colormap that simulates the appearance of the input colormap for individuals with the specified
color-vision deficiency.
Examples
--------
>>> import matplotlib.pyplot as plt
>>> from matplotlib.colors import get_cmap
>>> cmap = get_cmap("viridis")
>>> cvd_cmap = get_cvd_cmap(cmap, cvd_type="deuteranomaly", severity=50)
>>> plt.imshow([list(range(256))], cmap=cvd_cmap)
>>> plt.show()
Notes
-----
This function relies on the `colorspacious` package to perform color conversions.
Make sure to install it using `conda install -c conda-forge colorspacious` if not already available.
"""
# Check if the colorspacious package is available
try:
from colorspacious import cspace_convert
except ImportError:
raise ImportError(
"The 'colorspacious' package is required but not found. "
"Please install it using the following command: "
"conda install -c conda-forge colorspacious",
) from None
# Check valid CVD type
valid_cvd_types = ["deuteranomaly", "protanomaly", "tritanomaly"]
if cvd_type not in valid_cvd_types:
raise ValueError(f"Invalid 'cvd_type' {cvd_type}. Valid values are: {valid_cvd_types}.")
# Define CVD space
cvd_space = {"name": "sRGB1+CVD", "cvd_type": cvd_type, "severity": severity}
# Get RGB colors
rgba_colors = get_cmap_colors(cmap)
rgb_colors = rgba_colors[:, :3] # discard alpha
# Convert to CVD
cvd_colors = cspace_convert(rgb_colors, cvd_space, "sRGB1")
cvd_colors = np.clip(cvd_colors, 0, 1)
# Add back the alpha (transparency) channel
if rgba_colors.shape[1] == 4:
cvd_colors = np.column_stack((cvd_colors, rgba_colors[:, 3]))
# Create colormap
cvd_cmap = _create_new_cmap(colors=cvd_colors, old_cmap=cmap)
return cvd_cmap
[docs]
def get_gray_cmap(cmap):
"""Convert a given colormap to its grayscale equivalent.
Grayscale conversion is based on the lightness component of CAM02-UCS color space.
Parameters
----------
cmap : matplotlib.colors.Colormap
The input colormap, which can be a `ListedColormap` or a `LinearSegmentedColormap`.
Returns
-------
cmap_gray : matplotlib.colors.Colormap
The grayscale version of the input colormap, where the RGB values are
set based on the lightness of the corresponding color in the CAM02-UCS
color space. If the original colormap includes transparency (alpha),
it is preserved.
Raises
------
ImportError
If the `colorspacious` package is not installed, an error is raised.
Notes
-----
This function uses the CAM02-UCS color space to convert the colors of the
input colormap to grayscale based on their perceived lightness. The grayscale
colors are created by setting the R, G, and B channels to the normalized
lightness values. If the original colormap contains an alpha channel, it
is maintained in the resulting grayscale colormap.
Examples
--------
>>> import matplotlib.pyplot as plt
>>> from matplotlib import cm
>>> cmap = cm.viridis
>>> cmap_gray = get_gray_cmap(cmap)
>>> plt.imshow([[0, 1]], cmap=cmap_gray)
>>> plt.show()
"""
# Check if the colorspacious package is available
try:
from colorspacious import cspace_convert
except ImportError:
raise ImportError(
"The 'colorspacious' package is required but not found. "
"Please install it using the following command: "
"conda install -c conda-forge colorspacious",
) from None
# Get RGB colors
rgba_colors = get_cmap_colors(cmap)
rgb_colors = get_cmap_colors(cmap)[:, :3]
# Convert RGB colors to CAM02 Uniform Color Space
# LAB --> L(ightness) AB unique colors ..
lab = cspace_convert(rgb_colors, "sRGB1", "CAM02-UCS")
lightness = lab[:, 0]
# Normalize lightness values
lightness = lightness / 99.99871678
# Create an RGB grayscale array (R=G=B=lightness)
rgb_grayscale = np.stack([lightness] * 3, axis=-1)
rgb_grayscale = np.clip(rgb_grayscale, 0, 1)
# Add back the alpha (transparency) channel
if rgba_colors.shape[1] == 4:
rgb_grayscale = np.column_stack((rgb_grayscale, rgba_colors[:, 3]))
# Create colormap
cmap_gray = _create_new_cmap(colors=rgb_grayscale, old_cmap=cmap)
return cmap_gray
[docs]
def get_shifted_cmap(cmap):
"""
Shift the colors of a cyclic colormap, centering the midpoint of the color range.
This function is useful for cyclic colormaps, such as those representing
angles or phases, where the start and end colors should seamlessly wrap around.
The function shifts the colormap so that the midpoint of the color range becomes the new start.
Parameters
----------
cmap : matplotlib.colors.Colormap
The original cyclic colormap to shift.
Returns
-------
matplotlib.colors.Colormap
A new colormap with its colors shifted so that the midpoint of the
original colormap becomes the new starting point.
Notes
-----
- This function is particularly useful for cyclic colormaps where symmetry or phase is important.
- It works by dividing the colormap at its midpoint and swapping the two halves.
"""
# Subset colormap
colors = get_cmap_colors(cmap=cmap)
# Determine the central value index of the colormap
idx = len(colors) // 2
# Shift the entire colormap by this index
colors_shifted = np.r_[colors[idx:], colors[:idx]]
# Create new colormap
cmap = _create_new_cmap(colors=colors_shifted, old_cmap=cmap)
return cmap
def _check_cmaps(cmaps, n):
"""Check and retrieve the specified colormaps, ensuring proper formatting.
Parameters
----------
cmaps : list of Colormap or str
List of colormap instances or their names to be combined.
ns : list of int or None
List of integers specifying the number of colors for each colormap.
If None, defaults to using the number of colors of the colormaps,
or 256 colors for LinearSegmentedColormap defined by segmentdata.
Raises
------
ValueError
If fewer than two colormaps are provided.
Returns
-------
list of Colormap
A list of Colormap instances, resampled if necessary.
"""
import pycolorbar
# Check colormap datatype and convert to list[Colormap]
if len(cmaps) <= 1:
raise ValueError("Expected at least two colormaps to combine.")
# Check ns
if n is None:
n = [None] * len(cmaps)
# Retrieve and resample cmap if necessary
cmaps = [pycolorbar.get_cmap(cm, n=cm_n) for cm, cm_n in zip(cmaps, n, strict=False)]
return cmaps
def _check_nodes(nodes, cmaps):
"""Validate and prepare node positions for colormap blending.
Parameters
----------
nodes : list or numpy.ndarray, optional
List or array of float values indicating blending points.
Nodes values should be one less than the number of colormaps.
cmaps : list of Colormap
List of colormaps being combined.
Raises
------
TypeError
If the nodes are not of a supported type (list or ndarray).
ValueError
If the number of nodes does not match the expected count or if node values
are out of bounds or not in increasing order.
Returns
-------
numpy.ndarray
An array of nodes including the starting (0.0) and ending (1.0) points.
"""
# Generate default nodes for equal separation
if nodes is None:
nodes_arr = np.linspace(0, 1, len(cmaps) + 1)
elif isinstance(nodes, list | np.ndarray):
if len(nodes) != len(cmaps) - 1:
raise ValueError("Number of nodes should be one less than the number of colormaps.")
nodes_arr = np.concatenate([[0.0], nodes, [1.0]])
else:
raise TypeError(f"Unsupported nodes type: {type(nodes)}, expect list of float.")
# Check node values
if any((nodes_arr < 0) | (nodes_arr > 1)) or any(np.diff(nodes_arr) <= 0):
raise ValueError(
"Nodes should only contain increasing values between 0.0 and 1.0.",
)
return nodes_arr
[docs]
def combine_cmaps(
cmaps: list[Colormap | str],
*,
nodes: list[float] | np.ndarray | None = None,
n=None,
output_n: int = 256,
name: str = "combined_cmap",
) -> LinearSegmentedColormap:
"""Create a composite matplotlib colormap by combining multiple colormaps.
Parameters
----------
cmaps : list
List of matplotlib.Colormap or registered colormap names to be combined.
nodes : list of float or np.ndarray, optional
Blending points between colormaps, in the range [0, 1].
Nodes values should be one less than the number of colormaps.
Defaults to equal divisions if None.
n : list of int or None, optional
Number of colors for each colormap. Defaults to None, which uses the
original number of colors for each colormap.
output_n : int, optional
Number of colors in the output colormap. Default is 256.
name : str, optional
Name for the combined colormap. Default is "combined_cmap".
Returns
-------
LinearSegmentedColormap
The composite colormap created from the specified colormaps.
Raises
------
TypeError
If the list contains mixed datatypes or invalid colormap names.
ValueError
If the cmaps contain only one single colormap, or if the number of nodes
is not one less than the number of colormaps, or if the nodes do not
contain incrementing values between 0.0 and 1.0.
Notes
-----
The colormaps are combined from low value to high value end.
Code adapted from CMasher (https://github.com/1313e/CMasher).
Examples
--------
Using predefined colormap names:
custom_cmap_1 = combine_cmaps(
["ocean", "prism", "coolwarm"], nodes=[0.2, 0.75]
)
Using Colormap objects:
cmap_0 = plt.get_cmap("Blues")
cmap_1 = plt.get_cmap("Oranges")
cmap_2 = plt.get_cmap("Greens")
custom_cmap_2 = combine_cmaps([cmap_0, cmap_1, cmap_2])
"""
# Check valid cmaps and resample cmap if ns is not None
cmaps = _check_cmaps(cmaps, n=n)
nodes_arr = _check_nodes(nodes, cmaps=cmaps)
# Retrieve colors for each colormap
cmap_segments = []
for i, cmap in enumerate(cmaps):
# Define positions
start_position = nodes_arr[i]
end_position = nodes_arr[i + 1]
# Calculate the length of the segment
segment_length = int(output_n * (end_position - start_position))
# Append the segment to the combined colormap segments
cmap_segments.append(cmap(np.linspace(0, 1, segment_length)))
# Define new color palette
colors = np.vstack(cmap_segments)
# Define the new colormap by combining the segments
cmap = LinearSegmentedColormap.from_list(
name=name,
colors=colors,
N=output_n,
)
return cmap