Source code for mapclassify.util
import numpy as np
from ._classify_API import classify as _classify
[docs]
def get_color_array(
values,
scheme="quantiles",
cmap="viridis",
alpha=1,
nan_color=[255, 255, 255, 255],
as_hex=False,
**kwargs,
):
"""Convert array of values into RGBA or hex colors using a colormap and classifier.
This function is useful for visualization libraries that require users to provide
an array of colors for each object (like pydeck or lonboard) but can also be used
to create a manual column of colors passed to matplotlib.
Parameters
----------
values : list-like
array of input values
scheme : str, optional
string description of a mapclassify classifier, by default `"quantiles"`
cmap : str, optional
name of matplotlib colormap to use, by default "viridis"
alpha : float
alpha parameter that defines transparency. Should be in the range [0,1]
nan_color : list, optional
RGBA color to fill NaN values, by default [255, 255, 255, 255]
as_hex: bool, optional
if True, return a (n,1)-dimensional array of hexcolors instead of a (n,4)
dimensional array of RGBA values.
kwargs : dict
additional keyword arguments are passed to `mapclassify.classify`
Returns
-------
numpy.array
numpy array (aligned with the input array) defining a color for each row. If
`as_hex` is False, the array is :math:`(n,4)` holding an array of RGBA values in
each row. If `as_hex` is True, the array is :math:`(n,1)` holding a hexcolor in
each row.
"""
try:
import pandas as pd
from matplotlib import colormaps
from matplotlib.colors import Normalize, to_hex
except ImportError as e:
raise ImportError("This function requires pandas and matplotlib") from e
if not (alpha <= 1) and (alpha >= 0):
raise ValueError("alpha must be in the range [0,1]")
if not pd.api.types.is_list_like(nan_color) and not len(nan_color) == 4:
raise ValueError("`nan_color` must be list-like of 4 values: (R,G,B,A)")
# only operate on non-NaN values
v = pd.Series(values, dtype=object)
legit_indices = v[~v.isna()].index.values
legit_vals = v.dropna().values
bogus_indices = v[v.isna()].index.values # stash these for use later
# transform (non-NaN) values into class bins
bins = _classify(legit_vals, scheme=scheme, **kwargs).yb
# normalize using the data's range (not strictly 1-k if classifier is degenerate)
norm = Normalize(min(bins), max(bins))
normalized_vals = norm(bins)
# generate RBGA array and convert to series
rgbas = colormaps[cmap](normalized_vals, bytes=True, alpha=alpha)
colors = pd.Series(list(rgbas), index=legit_indices).apply(np.array)
nan_colors = pd.Series(
[nan_color for i in range(len(bogus_indices))], index=bogus_indices
).apply(lambda x: np.array(x).astype(np.uint8))
# put colors in their correct places and fill empty with specified color
v.update(colors)
v.update(nan_colors)
# convert to hexcolors if preferred
if as_hex:
colors = v.apply(lambda x: to_hex(x / 255.0))
return colors.values
return np.stack(v.values)