Skip to content

Colors

This module collects functions for manipulating color legends for matplotlib plots and a collections of color palettes.

ColorEncoder

color-encoding a categoric vector

Example
>>> from ridgeplot.colors import ColorEncoder, ColorPalette
>>> categorical_vector = ['group a','group b','group c','group a']
>>> colors = ColorPalette["okabeito"]
>>> ce = ColorEncoder()
>>> ce.fit(categorical_vector, colors)
>>> ce.encoder
OrderedDict([('group a', '#E69F00'),
     ('group b', '#56B4E9'),
     ('group c', '#009E73')])
>>> ce.transform(["group b", "group c", "group a"])
['#56B4E9', '#009E73', '#E69F00']
or
>>> ce = ColorEncoder()
>>> ce.fit_transform(categorical_vector, colors)
['#E69F00', '#56B4E9', '#009E73', '#E69F00']
access color encoder
>>> ce.encoder
OrderedDict([('group a', '#E69F00'),
     ('group b', '#56B4E9'),
     ('group c', '#009E73')])
Source code in src/ridgeplot/colors.py
class ColorEncoder:
    """
    color-encoding a categoric vector

    Example:
        ```
        >>> from ridgeplot.colors import ColorEncoder, ColorPalette
        >>> categorical_vector = ['group a','group b','group c','group a']
        >>> colors = ColorPalette["okabeito"]
        >>> ce = ColorEncoder()
        >>> ce.fit(categorical_vector, colors)
        >>> ce.encoder
        OrderedDict([('group a', '#E69F00'),
             ('group b', '#56B4E9'),
             ('group c', '#009E73')])
        >>> ce.transform(["group b", "group c", "group a"])
        ['#56B4E9', '#009E73', '#E69F00']
        ```

    or:
        ```
        >>> ce = ColorEncoder()
        >>> ce.fit_transform(categorical_vector, colors)
        ['#E69F00', '#56B4E9', '#009E73', '#E69F00']
        ```

    access color encoder:
        ```
        >>> ce.encoder
        OrderedDict([('group a', '#E69F00'),
             ('group b', '#56B4E9'),
             ('group c', '#009E73')])
        ```
    """

    def __init__(self):
        self.x: List[str] = list()
        self.distinct_categories: List[str] = []
        self.encoder: OrderedDict[str, str] = OrderedDict()

    def fit(self, categories: List[str], colors: List[str] = ColorPalette["invitae"]) -> None:
        """
        mapping colors to the unique categories in the input list
        basically fill the encoder dictionary

        Example:
            ```
            >>> categorical_vector = ['group a','group b','group c','group a']
            >>> colors = ColorPalette["okabeito"]
            >>> ce = ColorEncoder()
            >>> ce.fit(categroical_vector, colors)
            ```

        Args:
            categories: list of input values (i.e. labels of the samples), can be duplicated
            colors: list of colors, intentionally not checked for duplication
        Returns:
            NoneType
        """
        self.distinct_categories = check_color_vector_size(categories, colors)
        self.encoder = OrderedDict({category: col for category, col in zip(self.distinct_categories, colors)})

    def transform(self, categories: List[str]) -> List[str]:
        """
        mapping color to the a list of category in the input list

        Example:
            ```
            >>> categorical_vector = ['group a','group b','group c','group a']
            >>> colors = ColorPalette["okabeito"]
            >>> ce = color_encoder()
            >>> ce.fit(categroical_vector, colors)
            >>> new_categorical_vector = ["group b", "group c"]
            >>> ce.transform(new_categorical_vector)
            ['#56B4E9', '#009E73']
            ```

        Args:
            categories: list of input values (i.e. labels of the samples), can be duplicated
        Returns:
            list of colors for the input list according to the fitted color encoder
        """
        if not self.encoder:
            raise ValueError("Call color_encoder.fit() first!!")

        union_set = set(self.distinct_categories).union(set(categories))
        if len(union_set) != len(self.distinct_categories):
            unseen = union_set - set(self.distinct_categories)
            unseen_str = ", ".join(sorted(list(unseen)))
            raise ValueError(f"Input [categories] contain unseen data!!: {unseen_str}")

        return [self.encoder[category] for category in categories]

    def fit_transform(self, categories: List[str], colors: List[str] = ColorPalette["invitae"]) -> List[str]:
        """
        first map the color to the categories, and then return the
        corresponding color for each category in the input list

        Example:
            ```
            >>> categorical_vector = ["group1", "group2", "group1"]
            >>> colors = ["salmon","gold"]
            >>> ce = ColorEncoder()
            >>> ce.fit_transform(categorical_vector, colors)
            ['salmon', 'gold', 'salmon']
            ```

        Args:
            categories: list of input values (i.e. labels of the samples), can be duplicated
            colors: list of colors to be assigned to the categories
        Returns:
            list of colors corresponding to the input
        """
        self.fit(categories, colors=colors)
        return self.transform(categories)

    def show_legend(
        self,
        ax: matplotlib.axes._axes.Axes,
        sort: bool = False,
        **kwargs: Dict[str, Any],
    ) -> legend.Legend:
        """
        Adding matplotlib legend describing the color encoder to a matplotlib ax object

        Args:
            ax: matplotlib ax object
            sort: sort the legend by the category
            **kwargs: keyword arguments for matplotlib.pyplot.legend

        Returns:
            the matplotlib legend object
        """

        if sort:
            self.encoder = OrderedDict(sorted(self.encoder.items(), key=lambda item: item[0]))
        pat = [mpatches.Patch(color=col, label=lab) for lab, col in self.encoder.items()]
        lgd = ax.legend(handles=pat, **kwargs)
        return lgd

fit(categories, colors=ColorPalette['invitae'])

mapping colors to the unique categories in the input list basically fill the encoder dictionary

Example
>>> categorical_vector = ['group a','group b','group c','group a']
>>> colors = ColorPalette["okabeito"]
>>> ce = ColorEncoder()
>>> ce.fit(categroical_vector, colors)

Parameters:

Name Type Description Default
categories List[str]

list of input values (i.e. labels of the samples), can be duplicated

required
colors List[str]

list of colors, intentionally not checked for duplication

ColorPalette['invitae']

Returns: NoneType

Source code in src/ridgeplot/colors.py
def fit(self, categories: List[str], colors: List[str] = ColorPalette["invitae"]) -> None:
    """
    mapping colors to the unique categories in the input list
    basically fill the encoder dictionary

    Example:
        ```
        >>> categorical_vector = ['group a','group b','group c','group a']
        >>> colors = ColorPalette["okabeito"]
        >>> ce = ColorEncoder()
        >>> ce.fit(categroical_vector, colors)
        ```

    Args:
        categories: list of input values (i.e. labels of the samples), can be duplicated
        colors: list of colors, intentionally not checked for duplication
    Returns:
        NoneType
    """
    self.distinct_categories = check_color_vector_size(categories, colors)
    self.encoder = OrderedDict({category: col for category, col in zip(self.distinct_categories, colors)})

fit_transform(categories, colors=ColorPalette['invitae'])

first map the color to the categories, and then return the corresponding color for each category in the input list

Example
>>> categorical_vector = ["group1", "group2", "group1"]
>>> colors = ["salmon","gold"]
>>> ce = ColorEncoder()
>>> ce.fit_transform(categorical_vector, colors)
['salmon', 'gold', 'salmon']

Parameters:

Name Type Description Default
categories List[str]

list of input values (i.e. labels of the samples), can be duplicated

required
colors List[str]

list of colors to be assigned to the categories

ColorPalette['invitae']

Returns: list of colors corresponding to the input

Source code in src/ridgeplot/colors.py
def fit_transform(self, categories: List[str], colors: List[str] = ColorPalette["invitae"]) -> List[str]:
    """
    first map the color to the categories, and then return the
    corresponding color for each category in the input list

    Example:
        ```
        >>> categorical_vector = ["group1", "group2", "group1"]
        >>> colors = ["salmon","gold"]
        >>> ce = ColorEncoder()
        >>> ce.fit_transform(categorical_vector, colors)
        ['salmon', 'gold', 'salmon']
        ```

    Args:
        categories: list of input values (i.e. labels of the samples), can be duplicated
        colors: list of colors to be assigned to the categories
    Returns:
        list of colors corresponding to the input
    """
    self.fit(categories, colors=colors)
    return self.transform(categories)

show_legend(ax, sort=False, **kwargs)

Adding matplotlib legend describing the color encoder to a matplotlib ax object

Parameters:

Name Type Description Default
ax Axes

matplotlib ax object

required
sort bool

sort the legend by the category

False
**kwargs Dict[str, Any]

keyword arguments for matplotlib.pyplot.legend

{}

Returns:

Type Description
Legend

the matplotlib legend object

Source code in src/ridgeplot/colors.py
def show_legend(
    self,
    ax: matplotlib.axes._axes.Axes,
    sort: bool = False,
    **kwargs: Dict[str, Any],
) -> legend.Legend:
    """
    Adding matplotlib legend describing the color encoder to a matplotlib ax object

    Args:
        ax: matplotlib ax object
        sort: sort the legend by the category
        **kwargs: keyword arguments for matplotlib.pyplot.legend

    Returns:
        the matplotlib legend object
    """

    if sort:
        self.encoder = OrderedDict(sorted(self.encoder.items(), key=lambda item: item[0]))
    pat = [mpatches.Patch(color=col, label=lab) for lab, col in self.encoder.items()]
    lgd = ax.legend(handles=pat, **kwargs)
    return lgd

transform(categories)

mapping color to the a list of category in the input list

Example
>>> categorical_vector = ['group a','group b','group c','group a']
>>> colors = ColorPalette["okabeito"]
>>> ce = color_encoder()
>>> ce.fit(categroical_vector, colors)
>>> new_categorical_vector = ["group b", "group c"]
>>> ce.transform(new_categorical_vector)
['#56B4E9', '#009E73']

Parameters:

Name Type Description Default
categories List[str]

list of input values (i.e. labels of the samples), can be duplicated

required

Returns: list of colors for the input list according to the fitted color encoder

Source code in src/ridgeplot/colors.py
def transform(self, categories: List[str]) -> List[str]:
    """
    mapping color to the a list of category in the input list

    Example:
        ```
        >>> categorical_vector = ['group a','group b','group c','group a']
        >>> colors = ColorPalette["okabeito"]
        >>> ce = color_encoder()
        >>> ce.fit(categroical_vector, colors)
        >>> new_categorical_vector = ["group b", "group c"]
        >>> ce.transform(new_categorical_vector)
        ['#56B4E9', '#009E73']
        ```

    Args:
        categories: list of input values (i.e. labels of the samples), can be duplicated
    Returns:
        list of colors for the input list according to the fitted color encoder
    """
    if not self.encoder:
        raise ValueError("Call color_encoder.fit() first!!")

    union_set = set(self.distinct_categories).union(set(categories))
    if len(union_set) != len(self.distinct_categories):
        unseen = union_set - set(self.distinct_categories)
        unseen_str = ", ".join(sorted(list(unseen)))
        raise ValueError(f"Input [categories] contain unseen data!!: {unseen_str}")

    return [self.encoder[category] for category in categories]

check_color_vector_size(categorical_vector, color_vector)

asserting the number of different categories in the input list is less than the given color list

Parameters:

Name Type Description Default
categorical_vector List[str]

list of input values (i.e. labels of the samples), can be duplicated

required
color_vector List[str]

list of colors, intentionally not checked for duplication

required

Returns:

Type Description
List[str]

list of unique categories in the input list

Source code in src/ridgeplot/colors.py
def check_color_vector_size(categorical_vector: List[str], color_vector: List[str]) -> List[str]:
    """
    asserting the number of different categories in the input list is less than the given color list

    Args:
        categorical_vector: list of input values (i.e. labels of the samples), can be duplicated
        color_vector: list of colors, intentionally not checked for duplication

    Returns:
        list of unique categories in the input list
    """
    categories = ordered_set(categorical_vector)

    if len(categories) > len(color_vector):
        raise ValueError(f"Not enough colors!! {len(color_vector)} colors for {len(categories)} categories")
    return categories

get_cmap_color_values(cmap_name)

Get color values for the min and max color in a color map

Parameters:

Name Type Description Default
cmap_name str

color map name (e.g. viridis)

required

Returns:

Type Description
Tuple[str, str]

hex code for the min and max color

Source code in src/ridgeplot/colors.py
def get_cmap_color_values(cmap_name: str) -> Tuple[str, str]:
    """
    Get color values for the min and max color in a color map

    Args:
        cmap_name: color map name (e.g. viridis)

    Returns:
        hex code for the min and max color
    """
    cmap = get_cmap(cmap_name)
    return to_hex(cmap(0.0)), to_hex(cmap(1.0))

ordered_set(xs)

this is a simple function to make a set according to the order of the input list

because python set is unordered, see: https://stackoverflow.com/questions/9792664/converting-a-list-to-a-set-changes-element-order

Parameters:

Name Type Description Default
xs List[str]

list of input values

required

Returns:

Type Description
List[str]

a list of unique input values in the order of how they arranged in the input list

Source code in src/ridgeplot/colors.py
def ordered_set(xs: List[str]) -> List[str]:
    """
    this is a simple function to make a set according to the order of the input list

    because python set is unordered, see:
        https://stackoverflow.com/questions/9792664/converting-a-list-to-a-set-changes-element-order

    Args:
        xs: list of input values

    Returns:
        a list of unique input values in the order of how they arranged in the input list
    """  # noqa: E501
    xs = list(xs)
    return sorted(set(xs), key=xs.index)