Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions mapclassify/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import contextlib
from importlib.metadata import PackageNotFoundError, version

from . import util
from ._classify_API import classify
from .classifiers import (
CLASSIFIERS,
Expand Down
17 changes: 17 additions & 0 deletions mapclassify/tests/test_rgba.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import geopandas
import numpy as np
from mapclassify.util import get_rgba

world = geopandas.read_file(
"https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_0_countries.zip"
)


def test_rgba():
colors = get_rgba(world.area, cmap="viridis")[0]
assert colors == [
np.float64(68.08602),
np.float64(1.24287),
np.float64(84.000825),
np.float64(255.0),
]
71 changes: 71 additions & 0 deletions mapclassify/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from ._classify_API import classify


def get_rgba(
values,
classifier="quantiles",
cmap="viridis",
alpha=1,
nan_color=[255, 255, 255, 255],
**kwargs
):
"""Convert array of values into RGBA colors using a colormap and classifier.

Parameters
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kwargs should probably be mentioned here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, i'm always unsure what to do in the docstrings when there's a catchall

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I always mention where are they passed to.

----------
values : list-like
array of input values
classifier : 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]

Returns
-------
numpy.array
array of lists with each list containing four values that define a color using
RGBA specification.
"""
try:
import pandas as pd
from matplotlib import cm
from matplotlib.colors import Normalize
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

# transform (non-NaN) values into class bins
bins = classify(v.dropna().values, scheme=classifier, **kwargs).yb

# create a normalizer using the data's range (not strictly 1-k...)
norm = Normalize(min(bins), max(bins))

# map values to colors
n_cmap = cm.ScalarMappable(norm=norm, cmap=cmap)

# create array of RGB values (lists of 4) of length n
vals = [n_cmap.to_rgba(i, alpha=alpha) for i in bins]

# convert decimals to whole numbers
rgbas = []
for val in vals:
# convert each value in the array of lists
rgbas.append([i * 255 for i in val])

# replace non-nan values with colors
colors = pd.Series(rgbas, index=legit_indices)
v.update(colors)
v = v.fillna(f"{nan_color}").apply(list)

return v.values