# Copyright (c) 2015-2023 Patricio Cubillos and contributors.
# mc3 is open-source software under the MIT license (see LICENSE).
__all__ = [
'alphatize',
'rainbow_text',
'Theme',
'THEMES',
]
import numpy as np
from matplotlib.colors import (
is_color_like,
same_color,
to_rgb,
to_rgba,
ListedColormap,
)
from matplotlib.transforms import Affine2D, offset_copy
[docs]def alphatize(colors, alpha, background='w'):
"""
Get RGB representation of a color as if it had the specified alpha.
Parameters
----------
colors: color or iterable of colors
The color to alphatize.
alpha: Float
Alpha value to apply.
background: color
Background color.
Returns
-------
rgb: RGB or list of RGB color arrays
The RGB representation of the alphatized color (or list of colors).
Examples
--------
>>> import mc3.plots as mp
>>> # As string:
>>> color = 'red'
>>> alpha = 0.5
>>> mp.alphatize(color, alpha)
array([1. , 0.5, 0.5])
>>> # As RGB tuple:
>>> color = (1.0, 0.0, 0.0)
>>> mp.alphatize(color, alpha)
array([1. , 0.5, 0.5])
>>> # Specify 'background':
>>> color1 = 'red'
>>> color2 = 'blue'
>>> mp.alphatize(color1, alpha, color2)
array([0.5, 0. , 0.5])
>>> # Input a list of colors:
>>> mp.alphatize(['r', 'b'], alpha=0.8)
[array([1. , 0.2, 0.2]), array([0.2, 0.2, 1. ])]
"""
flatten = False
if is_color_like(colors):
colors = [colors]
flatten = True
colors = [np.array(to_rgb(color)) for color in colors]
background = np.array(to_rgb(background))
# https://matplotlib.org/tutorials/colors/colors.html
rgb = [(1.0-alpha) * background + alpha*c for c in colors]
if flatten:
return rgb[0]
return rgb
[docs]def rainbow_text(ax, texts, fontsize, colors=None, loc='above'):
"""
Plot lines of text on top of each other (above an axis),
each line with a specified color.
Parameters
----------
texts: 1D iterable of strings
Text to plot.
colors: 1D interable of colors
Color for each text.
ax: A matplotlib axis instance
Axis where to plot the text.
fontsize: Float
Text font size.
loc: String
Location of the first text. Select: 'above' or 'inside'.
Returns
-------
printed_texts: 1D list of strings
The text objects.
"""
if colors is None:
colors = ['black' for _ in texts]
fig = ax.get_figure()
t = ax.transAxes
x = 0.02
if loc == 'above':
y = 1.02
verticalalignment = 'bottom'
bbox = None
elif loc == 'inside':
y = 0.97
verticalalignment = 'top'
bbox = {'facecolor':'white', 'alpha':0.5, 'pad':0.0, 'edgecolor':'none'}
printed_texts = []
for string, col in zip(texts, colors):
text = ax.text(
x, y, string, color=col, transform=t,
ha='left', va=verticalalignment,
size=fontsize,
bbox=bbox,
)
printed_texts.append(text)
text.draw(fig.canvas.get_renderer())
ex = text.get_window_extent()
# Convert window extent from pixels to inches
# to avoid issues displaying at different dpi
ex = fig.dpi_scale_trans.inverted().transform_bbox(ex)
t = text.get_transform() + offset_copy(Affine2D(), fig=fig, y=ex.height)
return printed_texts
[docs]class Theme():
"""A monochromatic color theme from given color"""
def __init__(self, color, alpha_light=0.15, alpha_dark=0.7):
"""
Parameters
----------
color: color or iterable of colors
The color to alphatize.
alpha_light: Float
Alpha color value to merge with white to make self.light_color.
alpha_dark: Float
Alpha color value to merge with black.
Examples
--------
>>> import mc3.plots.colors as colors
>>> theme = colors.Theme('xkcd:blue')
>>> theme = colors.Theme([0.0, 0.2, 0.8])
"""
whites = [
alphatize(color, alpha, 'white')
for alpha in np.linspace(alpha_light, 1.0, 162)
]
darks = [
alphatize(color, alpha, 'black')
for alpha in np.linspace(1.0, alpha_dark, 95)
]
colormap = ListedColormap(whites + darks[1:])
colormap.set_under(color='white')
colormap.set_bad(color='white')
self.light_color = alphatize(color, 0.75, 'white')
self.color = color
self.dark_color = alphatize(color, alpha_dark, 'black')
self.colormap = colormap
def __repr__(self):
return f"Theme({repr(self.color)})"
def __eq__(self, other):
return (
same_color(self.color, other.color) and
same_color(self.light_color, other.light_color) and
same_color(self.dark_color, other.dark_color) and
self.colormap == other.colormap
)
# Setup for THEMES:
yellow = alphatize('gold', 0.7, 'orange')
yellow_theme = Theme(yellow, alpha_light=0.2, alpha_dark=0.6)
yellow_theme.color = 'orange'
yellow_theme.light_color = 'gold'
yellow_theme.dark_color = 'darkgoldenrod'
THEMES = {
'red': Theme('xkcd:tomato'),
'orange': Theme('darkorange'),
'yellow': yellow_theme,
'green': Theme('xkcd:green'),
'lightblue': Theme('dodgerblue'),
'blue': Theme('xkcd:blue'),
'purple': Theme('xkcd:violet'),
'indigo': Theme('xkcd:indigo'),
'black': Theme('0.3'),
}