Source code for clusterking.plots.colors

#!/usr/bin/env python3

# std
import logging
from typing import List, Optional

# 3rd party
import matplotlib.colors
import matplotlib.pyplot as plt
import numpy as np

# ours
from clusterking.util.log import get_logger

# todo: docs
[docs]class ColorScheme(object): """Class holding color scheme. We want to assign a unique color to every cluster and keep it consistent across different plots. Subclass and overwrite color lists to implement different schemes. """
[docs] def __init__( self, clusters: Optional[List[int]] = None, colors: Optional[List[str]] = None, ): """Initialize `ColorScheme` object. Args: clusters: List of cluster names colors: List of colors """ self.log = get_logger("Colors", sh_level=logging.WARNING) self._cluster_colors = None # todo: perhaps use this: self.cluster_colors = [ "xkcd:light red", "xkcd:apple green", "xkcd:bright blue", "xkcd:charcoal grey", "xkcd:orange", "xkcd:purple", "xkcd:brick red", "xkcd:hunter green", "xkcd:marigold", "xkcd:darkish blue", "xkcd:dirt brown", "xkcd:vivid green", "xkcd:periwinkle", ] if colors: self.cluster_colors = colors if not clusters: self.clusters = range(len(self.cluster_colors)) else: self.clusters = list(clusters) if len(self.clusters) > len(self.cluster_colors): self.log.warning( "Not enough colors for all clusters. Some clusters might end up" " with identical colors." )
@property def cluster_colors(self): """List of colors""" return self._cluster_colors @cluster_colors.setter def cluster_colors(self, value): self._cluster_colors = list(map(matplotlib.colors.to_rgba, value))
[docs] def get_cluster_color(self, cluster: int): """Returns base color for cluster. Args: cluster: Name of cluster. Has to be in :attr:`clusters` Returns: Color """ if cluster in self.clusters: index = self.clusters.index(cluster) else: self.log.error( "Cluster {} is not in the list of clusters. ".format(cluster) ) index = 0 return self.cluster_colors[index % len(self.cluster_colors)]
[docs] def to_colormap(self, name="MyColorMap"): """Returns colormap with color for each cluster.""" return matplotlib.colors.LinearSegmentedColormap.from_list( name, list(map(self.get_cluster_color, self.clusters)) )
[docs] def faded_colormap( self, cluster: int, nlines: int, name="MyFadedColorMap", **kwargs ): """Returns colormap for one cluster, including the faded colors. Args: cluster: Name of cluster nlines: Number of shades name: Name of colormap **kwargs: Arguments for :meth:`get_cluster_colors_faded` Returns: Colormap """ colors = self.get_cluster_colors_faded(cluster, nlines, **kwargs) return matplotlib.colors.LinearSegmentedColormap.from_list(name, colors)
[docs] def demo(self): """Plot the colors for all clusters. Returns: figure """ z = np.array(self.clusters).reshape((1, len(self.clusters))) return plt.imshow(z, cmap=self.to_colormap())
[docs] def demo_faded(self, cluster: Optional[int] = None, nlines=10, **kwargs): """Plot the color shades for different lines corresponding to the same cluster Args: cluster: Name of cluster nlines: Number of shades **kwargs: Arguments for :meth:`get_cluster_colors_faded` Returns: figure """ z = np.array(range(nlines)).reshape((1, nlines)) return plt.imshow( z, cmap=self.faded_colormap(cluster, nlines, **kwargs) )
# todo: perhaps this should just be done in a different way, the faded # colors add little value as far as distinguishability is concerned # and make picking color schemes much harder...
[docs] def get_cluster_colors_faded( self, cluster: int, nlines: int, max_alpha=0.7, min_alpha=0.3 ): """Shades of the base color, for cases where we want to draw multiple lines for one cluster Args: cluster: Name of cluster nlines: Number of shades max_alpha: Maximum alpha value min_alpha: Minimum alpha value Returns: List of colors """ base_color = self.get_cluster_color(cluster) alphas = np.linspace(min_alpha, max_alpha, nlines) colors = [ matplotlib.colors.to_rgba(base_color, alpha) for alpha in alphas ] return colors
[docs] def get_err_color(self, cluster: int): """Get color for error shades. Args: cluster: Cluster name Returns: color """ base_color = self.get_cluster_color(cluster) return matplotlib.colors.to_rgba(base_color, 0.3)