2020-07-16 01:28:24 +05:30
|
|
|
|
import os
|
2020-06-27 19:31:16 +05:30
|
|
|
|
import json
|
|
|
|
|
import functools
|
2021-08-28 21:19:44 +05:30
|
|
|
|
import colorsys
|
2021-11-23 21:04:50 +05:30
|
|
|
|
from pathlib import Path
|
2021-11-25 01:42:13 +05:30
|
|
|
|
from typing import Sequence, Union, TextIO
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
import matplotlib as mpl
|
2020-07-16 00:49:09 +05:30
|
|
|
|
if os.name == 'posix' and 'DISPLAY' not in os.environ:
|
|
|
|
|
mpl.use('Agg')
|
2020-06-27 19:31:16 +05:30
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
from matplotlib import cm
|
2020-08-04 22:22:04 +05:30
|
|
|
|
from PIL import Image
|
|
|
|
|
|
2020-08-24 13:25:41 +05:30
|
|
|
|
from . import util
|
2020-06-28 15:10:19 +05:30
|
|
|
|
from . import Table
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2021-11-25 16:22:52 +05:30
|
|
|
|
_EPS = 216./24389.
|
|
|
|
|
_KAPPA = 24389./27.
|
|
|
|
|
_REF_WHITE = np.array([.95047, 1.00000, 1.08883]) # Observer = 2, Illuminant = D65
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2020-06-28 13:02:10 +05:30
|
|
|
|
# ToDo (if needed)
|
|
|
|
|
# - support alpha channel (paraview/ASCII/input)
|
|
|
|
|
# - support NaN color (paraview)
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
class Colormap(mpl.colors.ListedColormap):
|
2020-11-16 20:53:01 +05:30
|
|
|
|
"""
|
2020-11-16 21:09:43 +05:30
|
|
|
|
Enhance matplotlib colormap functionality to be used within DAMASK.
|
|
|
|
|
|
2021-12-03 17:03:27 +05:30
|
|
|
|
Colors are internally stored as R(ed) G(green) B(lue) values.
|
2021-12-03 21:37:12 +05:30
|
|
|
|
The colormap can be used in matplotlib, seaborn, etc., or can
|
2021-12-03 17:03:27 +05:30
|
|
|
|
exported to file for external use.
|
|
|
|
|
|
2020-11-16 20:53:01 +05:30
|
|
|
|
References
|
|
|
|
|
----------
|
2021-03-17 15:55:21 +05:30
|
|
|
|
K. Moreland, Proceedings of the 5th International Symposium on Advances in Visual Computing, 2009
|
2021-03-26 00:03:08 +05:30
|
|
|
|
https://doi.org/10.1007/978-3-642-10520-3_9
|
2021-03-17 15:55:21 +05:30
|
|
|
|
|
|
|
|
|
P. Eisenlohr et al., International Journal of Plasticity 46:37–53, 2013
|
|
|
|
|
https://doi.org/10.1016/j.ijplas.2012.09.012
|
|
|
|
|
|
|
|
|
|
Matplotlib colormaps overview
|
|
|
|
|
https://matplotlib.org/tutorials/colors/colormaps.html
|
2020-11-16 21:09:43 +05:30
|
|
|
|
|
2020-11-16 20:53:01 +05:30
|
|
|
|
"""
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2021-12-03 17:03:27 +05:30
|
|
|
|
def __eq__(self, other: object) -> bool:
|
2021-11-24 04:16:38 +05:30
|
|
|
|
"""Test equality of colormaps."""
|
2021-12-03 17:03:27 +05:30
|
|
|
|
if not isinstance(other, Colormap):
|
|
|
|
|
return NotImplemented
|
2021-11-24 04:16:38 +05:30
|
|
|
|
return len(self.colors) == len(other.colors) \
|
|
|
|
|
and bool(np.all(self.colors == other.colors))
|
|
|
|
|
|
2021-12-01 19:43:46 +05:30
|
|
|
|
def __add__(self, other: 'Colormap') -> 'Colormap':
|
2021-03-27 14:40:35 +05:30
|
|
|
|
"""Concatenate."""
|
2020-06-30 07:28:41 +05:30
|
|
|
|
return Colormap(np.vstack((self.colors,other.colors)),
|
|
|
|
|
f'{self.name}+{other.name}')
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2021-12-01 19:43:46 +05:30
|
|
|
|
def __iadd__(self, other: 'Colormap') -> 'Colormap':
|
2021-03-27 14:40:35 +05:30
|
|
|
|
"""Concatenate (in-place)."""
|
2020-07-02 19:56:04 +05:30
|
|
|
|
return self.__add__(other)
|
2020-07-02 19:55:04 +05:30
|
|
|
|
|
2021-12-01 19:43:46 +05:30
|
|
|
|
def __invert__(self) -> 'Colormap':
|
2021-03-27 14:40:35 +05:30
|
|
|
|
"""Reverse."""
|
2020-07-02 19:43:47 +05:30
|
|
|
|
return self.reversed()
|
|
|
|
|
|
2021-11-23 22:29:56 +05:30
|
|
|
|
def __repr__(self) -> str:
|
2021-03-27 14:40:35 +05:30
|
|
|
|
"""Show as matplotlib figure."""
|
2020-11-16 21:55:13 +05:30
|
|
|
|
fig = plt.figure(self.name,figsize=(5,.5))
|
2020-11-15 16:30:26 +05:30
|
|
|
|
ax1 = fig.add_axes([0, 0, 1, 1])
|
|
|
|
|
ax1.set_axis_off()
|
|
|
|
|
ax1.imshow(np.linspace(0,1,self.N).reshape(1,-1),
|
|
|
|
|
aspect='auto', cmap=self, interpolation='nearest')
|
2021-12-03 21:37:12 +05:30
|
|
|
|
plt.show(block=False)
|
|
|
|
|
return f'Colormap: {self.name}'
|
2020-11-15 16:30:26 +05:30
|
|
|
|
|
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def from_range(low: Sequence[float],
|
|
|
|
|
high: Sequence[float],
|
|
|
|
|
name: str = 'DAMASK colormap',
|
|
|
|
|
N: int = 256,
|
2021-12-01 19:43:46 +05:30
|
|
|
|
model: str = 'rgb') -> 'Colormap':
|
2020-06-27 19:31:16 +05:30
|
|
|
|
"""
|
2020-06-30 07:28:41 +05:30
|
|
|
|
Create a perceptually uniform colormap between given (inclusive) bounds.
|
2020-06-28 13:02:10 +05:30
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
low : sequence of float, len (3)
|
2020-06-28 13:02:10 +05:30
|
|
|
|
Color definition for minimum value.
|
2021-12-03 21:37:12 +05:30
|
|
|
|
high : sequence of float, len (3)
|
2020-06-28 13:02:10 +05:30
|
|
|
|
Color definition for maximum value.
|
2020-06-27 23:13:35 +05:30
|
|
|
|
name : str, optional
|
2021-12-03 17:03:27 +05:30
|
|
|
|
Name of the colormap. Defaults to 'DAMASK colormap'.
|
2021-11-24 03:50:07 +05:30
|
|
|
|
N : int, optional
|
|
|
|
|
Number of color quantization levels. Defaults to 256.
|
2020-06-28 13:02:10 +05:30
|
|
|
|
model : {'rgb', 'hsv', 'hsl', 'xyz', 'lab', 'msh'}
|
2021-12-03 21:37:12 +05:30
|
|
|
|
Color model used for input color definitions. Defaults to 'rgb'.
|
2020-06-28 13:02:10 +05:30
|
|
|
|
The available color models are:
|
2021-11-24 03:50:07 +05:30
|
|
|
|
- 'rgb': Red Green Blue.
|
|
|
|
|
- 'hsv': Hue Saturation Value.
|
|
|
|
|
- 'hsl': Hue Saturation Luminance.
|
2020-06-28 13:02:10 +05:30
|
|
|
|
- 'xyz': CIE Xyz.
|
|
|
|
|
- 'lab': CIE Lab.
|
|
|
|
|
- 'msh': Msh (for perceptual uniform interpolation).
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2021-04-23 22:45:11 +05:30
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
new : damask.Colormap
|
|
|
|
|
Colormap within given bounds.
|
|
|
|
|
|
2021-04-24 21:30:57 +05:30
|
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
>>> import damask
|
|
|
|
|
>>> damask.Colormap.from_range((0,0,1),(0,0,0),'blue_to_black')
|
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
"""
|
2021-11-24 03:50:07 +05:30
|
|
|
|
toMsh = dict(
|
|
|
|
|
rgb=Colormap._rgb2msh,
|
|
|
|
|
hsv=Colormap._hsv2msh,
|
|
|
|
|
hsl=Colormap._hsl2msh,
|
|
|
|
|
xyz=Colormap._xyz2msh,
|
|
|
|
|
lab=Colormap._lab2msh,
|
|
|
|
|
msh=lambda x:x,
|
|
|
|
|
)
|
2020-06-27 23:13:35 +05:30
|
|
|
|
|
2021-11-24 03:50:07 +05:30
|
|
|
|
if model.lower() not in toMsh:
|
|
|
|
|
raise ValueError(f'Invalid color model: {model}.')
|
2020-06-27 23:13:35 +05:30
|
|
|
|
|
2021-11-24 03:50:07 +05:30
|
|
|
|
low_high = np.vstack((low,high))
|
2021-11-26 01:52:52 +05:30
|
|
|
|
out_of_bounds = np.bool_(False)
|
2020-06-27 23:13:35 +05:30
|
|
|
|
|
2021-11-24 03:50:07 +05:30
|
|
|
|
if model.lower() == 'rgb':
|
2021-11-26 01:52:52 +05:30
|
|
|
|
out_of_bounds = np.any(low_high<0) or np.any(low_high>1)
|
2020-06-27 19:31:16 +05:30
|
|
|
|
elif model.lower() == 'hsv':
|
2021-11-26 01:52:52 +05:30
|
|
|
|
out_of_bounds = np.any(low_high<0) or np.any(low_high>[360,1,1])
|
2020-06-27 19:31:16 +05:30
|
|
|
|
elif model.lower() == 'hsl':
|
2021-11-26 01:52:52 +05:30
|
|
|
|
out_of_bounds = np.any(low_high<0) or np.any(low_high>[360,1,1])
|
2020-06-27 19:31:16 +05:30
|
|
|
|
elif model.lower() == 'lab':
|
2021-11-26 01:52:52 +05:30
|
|
|
|
out_of_bounds = np.any(low_high[:,0]<0)
|
2020-06-27 23:13:35 +05:30
|
|
|
|
|
2021-11-26 01:52:52 +05:30
|
|
|
|
if out_of_bounds:
|
2021-11-24 03:50:07 +05:30
|
|
|
|
raise ValueError(f'{model.upper()} colors {low} | {high} are out of bounds.')
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2021-11-24 03:50:07 +05:30
|
|
|
|
low_,high_ = map(toMsh[model.lower()],low_high)
|
2020-06-30 10:46:49 +05:30
|
|
|
|
msh = map(functools.partial(Colormap._interpolate_msh,low=low_,high=high_),np.linspace(0,1,N))
|
2020-06-27 19:31:16 +05:30
|
|
|
|
rgb = np.array(list(map(Colormap._msh2rgb,msh)))
|
|
|
|
|
|
|
|
|
|
return Colormap(rgb,name=name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-12-01 19:43:46 +05:30
|
|
|
|
def from_predefined(name: str, N: int = 256) -> 'Colormap':
|
2020-06-27 19:31:16 +05:30
|
|
|
|
"""
|
2020-06-28 13:02:10 +05:30
|
|
|
|
Select from a set of predefined colormaps.
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2021-11-25 23:44:34 +05:30
|
|
|
|
Predefined colormaps (Colormap.predefined) include
|
|
|
|
|
native matplotlib colormaps and common DAMASK colormaps.
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
name : str
|
2021-11-24 03:50:07 +05:30
|
|
|
|
Name of the colormap.
|
2020-06-27 19:31:16 +05:30
|
|
|
|
N : int, optional
|
2021-11-26 01:52:52 +05:30
|
|
|
|
Number of color quantization levels. Defaults to 256.
|
|
|
|
|
This parameter is not used for matplotlib colormaps
|
|
|
|
|
that are of type `ListedColormap`.
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2021-04-23 22:45:11 +05:30
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
new : damask.Colormap
|
|
|
|
|
Predefined colormap.
|
|
|
|
|
|
2021-04-24 21:30:57 +05:30
|
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
>>> import damask
|
|
|
|
|
>>> damask.Colormap.from_predefined('strain')
|
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
"""
|
2020-11-16 20:53:01 +05:30
|
|
|
|
try:
|
2021-11-24 03:50:07 +05:30
|
|
|
|
# matplotlib presets
|
2020-11-16 20:53:01 +05:30
|
|
|
|
colormap = cm.__dict__[name]
|
|
|
|
|
return Colormap(np.array(list(map(colormap,np.linspace(0,1,N)))
|
|
|
|
|
if isinstance(colormap,mpl.colors.LinearSegmentedColormap) else
|
|
|
|
|
colormap.colors),
|
|
|
|
|
name=name)
|
2020-11-16 21:09:43 +05:30
|
|
|
|
except KeyError:
|
2020-11-16 20:53:01 +05:30
|
|
|
|
# DAMASK presets
|
|
|
|
|
definition = Colormap._predefined_DAMASK[name]
|
|
|
|
|
return Colormap.from_range(definition['low'],definition['high'],name,N)
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def shade(self,
|
|
|
|
|
field: np.ndarray,
|
2021-11-23 22:29:56 +05:30
|
|
|
|
bounds: Sequence[float] = None,
|
|
|
|
|
gap: float = None) -> Image:
|
2020-08-04 22:22:04 +05:30
|
|
|
|
"""
|
|
|
|
|
Generate PIL image of 2D field using colormap.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
field : numpy.array, shape (:,:)
|
2020-08-04 22:22:04 +05:30
|
|
|
|
Data to be shaded.
|
2021-12-03 21:37:12 +05:30
|
|
|
|
bounds : sequence of float, len (2), optional
|
2021-11-25 23:44:34 +05:30
|
|
|
|
Value range (low,high) spanned by colormap.
|
2020-08-04 23:44:04 +05:30
|
|
|
|
gap : field.dtype, optional
|
2020-08-04 22:22:04 +05:30
|
|
|
|
Transparent value. NaN will always be rendered transparent.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
PIL.Image
|
|
|
|
|
RGBA image of shaded data.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
N = len(self.colors)
|
|
|
|
|
mask = np.logical_not(np.isnan(field) if gap is None else \
|
2020-08-04 23:59:27 +05:30
|
|
|
|
np.logical_or (np.isnan(field), field == gap)) # mask NaN (and gap if present)
|
|
|
|
|
|
|
|
|
|
lo,hi = (field[mask].min(),field[mask].max()) if bounds is None else \
|
|
|
|
|
(min(bounds[:2]),max(bounds[:2]))
|
2020-08-04 22:22:04 +05:30
|
|
|
|
|
|
|
|
|
delta,avg = hi-lo,0.5*(hi+lo)
|
|
|
|
|
|
2020-08-04 23:59:27 +05:30
|
|
|
|
if delta * 1e8 <= avg: # delta is similar to numerical noise
|
2020-08-04 23:44:04 +05:30
|
|
|
|
hi,lo = hi+0.5*avg,lo-0.5*avg # extend range to have actual data centered within
|
2020-08-04 22:22:04 +05:30
|
|
|
|
|
2020-08-05 19:38:48 +05:30
|
|
|
|
return Image.fromarray(
|
|
|
|
|
(np.dstack((
|
2020-08-05 20:14:10 +05:30
|
|
|
|
self.colors[(np.round(np.clip((field-lo)/(hi-lo),0.0,1.0)*(N-1))).astype(np.uint16),:3],
|
2020-08-05 19:38:48 +05:30
|
|
|
|
mask.astype(float)
|
|
|
|
|
)
|
|
|
|
|
)*255
|
|
|
|
|
).astype(np.uint8),
|
|
|
|
|
mode='RGBA')
|
2020-08-04 22:22:04 +05:30
|
|
|
|
|
|
|
|
|
|
2021-12-01 19:43:46 +05:30
|
|
|
|
def reversed(self, name: str = None) -> 'Colormap':
|
2020-06-27 23:13:35 +05:30
|
|
|
|
"""
|
2021-03-27 14:40:35 +05:30
|
|
|
|
Reverse.
|
2020-06-27 23:13:35 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
name : str, optional
|
2021-11-25 23:44:34 +05:30
|
|
|
|
Name of the reversed colormap.
|
2021-12-03 17:03:27 +05:30
|
|
|
|
Defaults to parent colormap name + '_r'.
|
2020-06-27 23:13:35 +05:30
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
damask.Colormap
|
2021-11-24 03:50:07 +05:30
|
|
|
|
Reversed colormap.
|
2020-06-27 23:13:35 +05:30
|
|
|
|
|
2021-04-24 21:30:57 +05:30
|
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
>>> import damask
|
|
|
|
|
>>> damask.Colormap.from_predefined('stress').reversed()
|
|
|
|
|
|
2020-06-27 23:13:35 +05:30
|
|
|
|
"""
|
|
|
|
|
rev = super(Colormap,self).reversed(name)
|
2020-06-30 07:28:41 +05:30
|
|
|
|
return Colormap(np.array(rev.colors),rev.name[:-4] if rev.name.endswith('_r_r') else rev.name)
|
2020-06-27 23:13:35 +05:30
|
|
|
|
|
|
|
|
|
|
2021-11-25 23:44:34 +05:30
|
|
|
|
def _get_file_handle(self,
|
2021-12-03 21:37:12 +05:30
|
|
|
|
fname: Union[TextIO, str, Path, None],
|
|
|
|
|
suffix: str = '') -> TextIO:
|
2020-06-28 13:02:10 +05:30
|
|
|
|
"""
|
2021-02-10 23:05:13 +05:30
|
|
|
|
Provide file handle.
|
2020-06-28 13:02:10 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-02-10 23:05:13 +05:30
|
|
|
|
fname : file, str, pathlib.Path, or None
|
2021-12-03 21:37:12 +05:30
|
|
|
|
Name or handle of file.
|
2021-11-25 23:44:34 +05:30
|
|
|
|
If None, colormap name + suffix.
|
2021-11-26 22:04:43 +05:30
|
|
|
|
suffix: str, optional
|
2021-12-03 21:37:12 +05:30
|
|
|
|
Extension to use for colormap file.
|
2021-02-10 23:05:13 +05:30
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-04-23 22:45:11 +05:30
|
|
|
|
f : file object
|
|
|
|
|
File handle with write access.
|
2020-06-28 13:02:10 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-11-16 20:53:01 +05:30
|
|
|
|
if fname is None:
|
2021-11-24 21:56:58 +05:30
|
|
|
|
return open(self.name.replace(' ','_')+suffix, 'w', newline='\n')
|
2021-11-23 22:29:56 +05:30
|
|
|
|
elif isinstance(fname, (str, Path)):
|
2021-11-22 21:45:22 +05:30
|
|
|
|
return open(fname, 'w', newline='\n')
|
2020-11-16 20:53:01 +05:30
|
|
|
|
else:
|
2021-11-22 21:45:22 +05:30
|
|
|
|
return fname
|
2021-02-10 23:05:13 +05:30
|
|
|
|
|
|
|
|
|
|
2021-11-23 22:29:56 +05:30
|
|
|
|
def save_paraview(self, fname: Union[TextIO, str, Path] = None):
|
2021-02-10 23:05:13 +05:30
|
|
|
|
"""
|
|
|
|
|
Save as JSON file for use in Paraview.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
fname : file, str, or pathlib.Path, optional
|
2021-12-03 21:37:12 +05:30
|
|
|
|
File to store results. Defaults to colormap name + '.json'.
|
2021-02-10 23:05:13 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2021-12-03 17:03:27 +05:30
|
|
|
|
colors = []
|
2020-09-15 10:28:06 +05:30
|
|
|
|
for i,c in enumerate(np.round(self.colors,6).tolist()):
|
2020-06-27 19:31:16 +05:30
|
|
|
|
colors+=[i]+c
|
|
|
|
|
|
|
|
|
|
out = [{
|
2020-08-25 00:20:40 +05:30
|
|
|
|
'Creator':util.execution_stamp('Colormap'),
|
2020-06-27 19:31:16 +05:30
|
|
|
|
'ColorSpace':'RGB',
|
2020-09-15 10:28:06 +05:30
|
|
|
|
'Name':self.name,
|
2020-06-27 19:31:16 +05:30
|
|
|
|
'DefaultMap':True,
|
|
|
|
|
'RGBPoints':colors
|
|
|
|
|
}]
|
2020-11-16 20:53:01 +05:30
|
|
|
|
|
2021-12-01 19:43:46 +05:30
|
|
|
|
fhandle = self._get_file_handle(fname,'.json')
|
2021-11-30 15:34:41 +05:30
|
|
|
|
json.dump(out,fhandle,indent=4)
|
|
|
|
|
fhandle.write('\n')
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2020-09-15 10:28:06 +05:30
|
|
|
|
|
2021-11-23 22:29:56 +05:30
|
|
|
|
def save_ASCII(self, fname: Union[TextIO, str, Path] = None):
|
2020-09-15 10:28:06 +05:30
|
|
|
|
"""
|
2020-12-04 02:28:24 +05:30
|
|
|
|
Save as ASCII file.
|
2020-09-15 10:28:06 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-02-10 23:05:13 +05:30
|
|
|
|
fname : file, str, or pathlib.Path, optional
|
2021-12-03 21:37:12 +05:30
|
|
|
|
File to store results. Defaults to colormap name + '.txt'.
|
2020-09-15 10:28:06 +05:30
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
labels = {'RGBA':4} if self.colors.shape[1] == 4 else {'RGB': 3}
|
|
|
|
|
t = Table(self.colors,labels,f'Creator: {util.execution_stamp("Colormap")}')
|
2021-11-24 21:56:58 +05:30
|
|
|
|
t.save(self._get_file_handle(fname,'.txt'))
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2020-09-15 10:28:06 +05:30
|
|
|
|
|
2021-11-23 22:29:56 +05:30
|
|
|
|
def save_GOM(self, fname: Union[TextIO, str, Path] = None):
|
2020-09-15 10:28:06 +05:30
|
|
|
|
"""
|
2020-12-04 02:28:24 +05:30
|
|
|
|
Save as ASCII file for use in GOM Aramis.
|
2020-09-15 10:28:06 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-02-10 23:05:13 +05:30
|
|
|
|
fname : file, str, or pathlib.Path, optional
|
2021-12-03 21:37:12 +05:30
|
|
|
|
File to store results. Defaults to colormap name + '.legend'.
|
2020-09-15 10:28:06 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-06-28 00:56:25 +05:30
|
|
|
|
# ToDo: test in GOM
|
2020-09-15 10:28:06 +05:30
|
|
|
|
GOM_str = '1 1 {name} 9 {name} '.format(name=self.name.replace(" ","_")) \
|
2020-06-28 00:56:25 +05:30
|
|
|
|
+ '0 1 0 3 0 0 -1 9 \\ 0 0 0 255 255 255 0 0 255 ' \
|
2020-09-15 10:28:06 +05:30
|
|
|
|
+ f'30 NO_UNIT 1 1 64 64 64 255 1 0 0 0 0 0 0 3 0 {len(self.colors)}' \
|
|
|
|
|
+ ' '.join([f' 0 {c[0]} {c[1]} {c[2]} 255 1' for c in reversed((self.colors*255).astype(int))]) \
|
2020-06-28 00:56:25 +05:30
|
|
|
|
+ '\n'
|
2021-02-10 23:05:13 +05:30
|
|
|
|
|
2021-11-24 21:56:58 +05:30
|
|
|
|
self._get_file_handle(fname,'.legend').write(GOM_str)
|
2020-06-28 00:56:25 +05:30
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2021-11-23 22:29:56 +05:30
|
|
|
|
def save_gmsh(self, fname: Union[TextIO, str, Path] = None):
|
2020-09-15 10:28:06 +05:30
|
|
|
|
"""
|
2020-12-04 02:28:24 +05:30
|
|
|
|
Save as ASCII file for use in gmsh.
|
2020-09-15 10:28:06 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-02-10 23:05:13 +05:30
|
|
|
|
fname : file, str, or pathlib.Path, optional
|
2021-12-03 21:37:12 +05:30
|
|
|
|
File to store results. Defaults to colormap name + '.msh'.
|
2020-09-15 10:28:06 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-06-28 00:56:25 +05:30
|
|
|
|
# ToDo: test in gmsh
|
|
|
|
|
gmsh_str = 'View.ColorTable = {\n' \
|
2020-09-15 10:28:06 +05:30
|
|
|
|
+'\n'.join([f'{c[0]},{c[1]},{c[2]},' for c in self.colors[:,:3]*255]) \
|
2020-06-28 00:56:25 +05:30
|
|
|
|
+'\n}\n'
|
2021-11-24 21:56:58 +05:30
|
|
|
|
self._get_file_handle(fname,'.msh').write(gmsh_str)
|
2020-06-28 00:06:18 +05:30
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-26 01:52:52 +05:30
|
|
|
|
def _interpolate_msh(frac: float,
|
2021-11-23 22:29:56 +05:30
|
|
|
|
low: np.ndarray,
|
|
|
|
|
high: np.ndarray) -> np.ndarray:
|
2020-06-28 13:02:10 +05:30
|
|
|
|
"""
|
|
|
|
|
Interpolate in Msh color space.
|
|
|
|
|
|
|
|
|
|
This interpolation gives a perceptually uniform colormap.
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2020-06-28 13:02:10 +05:30
|
|
|
|
References
|
|
|
|
|
----------
|
|
|
|
|
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
|
|
|
|
https://www.kennethmoreland.com/color-maps/diverging_map.py
|
|
|
|
|
|
|
|
|
|
"""
|
2020-06-27 19:31:16 +05:30
|
|
|
|
def rad_diff(a,b):
|
|
|
|
|
return abs(a[2]-b[2])
|
|
|
|
|
|
|
|
|
|
def adjust_hue(msh_sat, msh_unsat):
|
|
|
|
|
"""If saturation of one of the two colors is much less than the other, hue of the less."""
|
|
|
|
|
if msh_sat[0] >= msh_unsat[0]:
|
|
|
|
|
return msh_sat[2]
|
|
|
|
|
else:
|
|
|
|
|
hSpin = msh_sat[1]/np.sin(msh_sat[1])*np.sqrt(msh_unsat[0]**2.0-msh_sat[0]**2)/msh_sat[0]
|
|
|
|
|
if msh_sat[2] < - np.pi/3.0: hSpin *= -1.0
|
|
|
|
|
return msh_sat[2] + hSpin
|
|
|
|
|
|
|
|
|
|
lo = np.array(low)
|
|
|
|
|
hi = np.array(high)
|
|
|
|
|
|
|
|
|
|
if (lo[1] > 0.05 and hi[1] > 0.05 and rad_diff(lo,hi) > np.pi/3.0):
|
|
|
|
|
M_mid = max(lo[0],hi[0],88.0)
|
|
|
|
|
if frac < 0.5:
|
|
|
|
|
hi = np.array([M_mid,0.0,0.0])
|
|
|
|
|
frac *= 2.0
|
|
|
|
|
else:
|
|
|
|
|
lo = np.array([M_mid,0.0,0.0])
|
|
|
|
|
frac = 2.0*frac - 1.0
|
|
|
|
|
if lo[1] < 0.05 and hi[1] > 0.05:
|
|
|
|
|
lo[2] = adjust_hue(hi,lo)
|
|
|
|
|
elif lo[1] > 0.05 and hi[1] < 0.05:
|
|
|
|
|
hi[2] = adjust_hue(lo,hi)
|
|
|
|
|
|
|
|
|
|
return (1.0 - frac) * lo + frac * hi
|
|
|
|
|
|
|
|
|
|
|
2020-11-16 20:53:01 +05:30
|
|
|
|
_predefined_mpl= {'Perceptually Uniform Sequential': [
|
|
|
|
|
'viridis', 'plasma', 'inferno', 'magma', 'cividis'],
|
|
|
|
|
'Sequential': [
|
2020-06-27 19:31:16 +05:30
|
|
|
|
'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
|
|
|
|
|
'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
|
2020-11-16 20:53:01 +05:30
|
|
|
|
'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn'],
|
|
|
|
|
'Sequential (2)': [
|
2020-06-27 19:31:16 +05:30
|
|
|
|
'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink',
|
|
|
|
|
'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia',
|
2020-11-16 20:53:01 +05:30
|
|
|
|
'hot', 'afmhot', 'gist_heat', 'copper'],
|
|
|
|
|
'Diverging': [
|
2020-06-27 19:31:16 +05:30
|
|
|
|
'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu',
|
2020-11-16 20:53:01 +05:30
|
|
|
|
'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic'],
|
|
|
|
|
'Cyclic': ['twilight', 'twilight_shifted', 'hsv'],
|
|
|
|
|
'Qualitative': [
|
2020-06-27 19:31:16 +05:30
|
|
|
|
'Pastel1', 'Pastel2', 'Paired', 'Accent',
|
|
|
|
|
'Dark2', 'Set1', 'Set2', 'Set3',
|
2020-11-16 20:53:01 +05:30
|
|
|
|
'tab10', 'tab20', 'tab20b', 'tab20c'],
|
|
|
|
|
'Miscellaneous': [
|
2020-06-27 19:31:16 +05:30
|
|
|
|
'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern',
|
|
|
|
|
'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg',
|
2020-11-16 20:53:01 +05:30
|
|
|
|
'gist_rainbow', 'rainbow', 'jet', 'nipy_spectral', 'gist_ncar']}
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2020-06-27 23:47:48 +05:30
|
|
|
|
_predefined_DAMASK = {'orientation': {'low': [0.933334,0.878432,0.878431],
|
|
|
|
|
'high': [0.250980,0.007843,0.000000]},
|
|
|
|
|
'strain': {'low': [0.941177,0.941177,0.870588],
|
|
|
|
|
'high': [0.266667,0.266667,0.000000]},
|
|
|
|
|
'stress': {'low': [0.878432,0.874511,0.949019],
|
|
|
|
|
'high': [0.000002,0.000000,0.286275]}}
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2020-11-16 20:53:01 +05:30
|
|
|
|
predefined = dict(**{'DAMASK':list(_predefined_DAMASK)},**_predefined_mpl)
|
|
|
|
|
|
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
@staticmethod
|
2021-11-23 22:29:56 +05:30
|
|
|
|
def _hsv2rgb(hsv: np.ndarray) -> np.ndarray:
|
2021-11-26 01:52:52 +05:30
|
|
|
|
"""
|
|
|
|
|
Hue Saturation Value to Red Green Blue.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
hsv : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
HSV values.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
rgb : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
RGB values.
|
|
|
|
|
|
|
|
|
|
"""
|
2021-08-28 21:19:44 +05:30
|
|
|
|
return np.array(colorsys.hsv_to_rgb(hsv[0]/360.,hsv[1],hsv[2]))
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-23 22:29:56 +05:30
|
|
|
|
def _rgb2hsv(rgb: np.ndarray) -> np.ndarray:
|
2021-11-26 01:52:52 +05:30
|
|
|
|
"""
|
|
|
|
|
Red Green Blue to Hue Saturation Value.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
rgb : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
RGB values.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
hsv : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
HSV values.
|
|
|
|
|
|
|
|
|
|
"""
|
2021-08-28 21:19:44 +05:30
|
|
|
|
h,s,v = colorsys.rgb_to_hsv(rgb[0],rgb[1],rgb[2])
|
|
|
|
|
return np.array([h*360,s,v])
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-23 22:29:56 +05:30
|
|
|
|
def _hsl2rgb(hsl: np.ndarray) -> np.ndarray:
|
2021-11-26 01:52:52 +05:30
|
|
|
|
"""
|
|
|
|
|
Hue Saturation Luminance to Red Green Blue.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
hsl : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
HSL values.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
rgb : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
RGB values.
|
|
|
|
|
|
|
|
|
|
"""
|
2021-08-28 21:19:44 +05:30
|
|
|
|
return np.array(colorsys.hls_to_rgb(hsl[0]/360.,hsl[2],hsl[1]))
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-23 22:29:56 +05:30
|
|
|
|
def _rgb2hsl(rgb: np.ndarray) -> np.ndarray:
|
2021-11-26 01:52:52 +05:30
|
|
|
|
"""
|
|
|
|
|
Red Green Blue to Hue Saturation Luminance.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
rgb : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
RGB values.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
hsl : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
HSL values.
|
|
|
|
|
|
|
|
|
|
"""
|
2021-08-28 21:19:44 +05:30
|
|
|
|
h,l,s = colorsys.rgb_to_hls(rgb[0],rgb[1],rgb[2])
|
|
|
|
|
return np.array([h*360,s,l])
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _xyz2rgb(xyz: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
"""
|
2021-11-24 03:50:07 +05:30
|
|
|
|
CIE Xyz to Red Green Blue.
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2021-11-26 01:52:52 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
xyz : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
CIE Xyz values.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
rgb : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
RGB values.
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
----------
|
2021-03-20 19:04:14 +05:30
|
|
|
|
https://www.easyrgb.com/en/math.php
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
rgb_lin = np.dot(np.array([
|
|
|
|
|
[ 3.240969942,-1.537383178,-0.498610760],
|
|
|
|
|
[-0.969243636, 1.875967502, 0.041555057],
|
|
|
|
|
[ 0.055630080,-0.203976959, 1.056971514]
|
|
|
|
|
]),xyz)
|
|
|
|
|
with np.errstate(invalid='ignore'):
|
|
|
|
|
rgb = np.where(rgb_lin>0.0031308,rgb_lin**(1.0/2.4)*1.0555-0.0555,rgb_lin*12.92)
|
|
|
|
|
|
|
|
|
|
return np.clip(rgb,0.,1.)
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _rgb2xyz(rgb: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
"""
|
2021-11-24 03:50:07 +05:30
|
|
|
|
Red Green Blue to CIE Xyz.
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
2021-11-26 01:52:52 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
rgb : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
RGB values.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
xyz : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
CIE Xyz values.
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
----------
|
2021-03-20 19:04:14 +05:30
|
|
|
|
https://www.easyrgb.com/en/math.php
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
rgb_lin = np.where(rgb>0.04045,((rgb+0.0555)/1.0555)**2.4,rgb/12.92)
|
|
|
|
|
return np.dot(np.array([
|
|
|
|
|
[0.412390799,0.357584339,0.180480788],
|
|
|
|
|
[0.212639006,0.715168679,0.072192315],
|
|
|
|
|
[0.019330819,0.119194780,0.950532152]
|
|
|
|
|
]),rgb_lin)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _lab2xyz(lab: np.ndarray, ref_white: np.ndarray = None) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
"""
|
|
|
|
|
CIE Lab to CIE Xyz.
|
|
|
|
|
|
2021-11-26 01:52:52 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
lab : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
CIE lab values.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
xyz : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
CIE Xyz values.
|
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
References
|
|
|
|
|
----------
|
|
|
|
|
http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
f_x = (lab[0]+16.)/116. + lab[1]/500.
|
|
|
|
|
f_z = (lab[0]+16.)/116. - lab[2]/200.
|
|
|
|
|
|
|
|
|
|
return np.array([
|
2021-11-25 16:22:52 +05:30
|
|
|
|
f_x**3. if f_x**3. > _EPS else (116.*f_x-16.)/_KAPPA,
|
|
|
|
|
((lab[0]+16.)/116.)**3 if lab[0]>_KAPPA*_EPS else lab[0]/_KAPPA,
|
|
|
|
|
f_z**3. if f_z**3. > _EPS else (116.*f_z-16.)/_KAPPA
|
|
|
|
|
])*(ref_white if ref_white is not None else _REF_WHITE)
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-23 22:29:56 +05:30
|
|
|
|
def _xyz2lab(xyz: np.ndarray, ref_white: np.ndarray = None) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
"""
|
|
|
|
|
CIE Xyz to CIE Lab.
|
|
|
|
|
|
2021-11-26 01:52:52 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
xyz : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
CIE Xyz values.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
lab : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
CIE lab values.
|
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
References
|
|
|
|
|
----------
|
|
|
|
|
http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
|
|
|
|
|
|
|
|
|
|
"""
|
2021-11-25 16:22:52 +05:30
|
|
|
|
ref_white = ref_white if ref_white is not None else _REF_WHITE
|
|
|
|
|
f = np.where(xyz/ref_white > _EPS,(xyz/ref_white)**(1./3.),(_KAPPA*xyz/ref_white+16.)/116.)
|
2020-06-27 19:31:16 +05:30
|
|
|
|
|
|
|
|
|
return np.array([
|
|
|
|
|
116.0 * f[1] - 16.0,
|
|
|
|
|
500.0 * (f[0] - f[1]),
|
|
|
|
|
200.0 * (f[1] - f[2])
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _lab2msh(lab: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
"""
|
|
|
|
|
CIE Lab to Msh.
|
|
|
|
|
|
2021-11-26 01:52:52 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
lab : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
CIE lab values.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
msh : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
Msh values.
|
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
References
|
|
|
|
|
----------
|
|
|
|
|
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
|
|
|
|
https://www.kennethmoreland.com/color-maps/diverging_map.py
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
M = np.linalg.norm(lab)
|
|
|
|
|
return np.array([
|
|
|
|
|
M,
|
|
|
|
|
np.arccos(lab[0]/M) if M>1e-8 else 0.,
|
|
|
|
|
np.arctan2(lab[2],lab[1]) if M>1e-8 else 0.,
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _msh2lab(msh: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
"""
|
|
|
|
|
Msh to CIE Lab.
|
|
|
|
|
|
2021-11-26 01:52:52 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
msh : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
Msh values.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2021-12-03 21:37:12 +05:30
|
|
|
|
lab : numpy.ndarray, shape (3)
|
2021-11-26 01:52:52 +05:30
|
|
|
|
CIE lab values.
|
|
|
|
|
|
2020-06-27 19:31:16 +05:30
|
|
|
|
References
|
|
|
|
|
----------
|
|
|
|
|
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
|
|
|
|
https://www.kennethmoreland.com/color-maps/diverging_map.py
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
return np.array([
|
|
|
|
|
msh[0] * np.cos(msh[1]),
|
|
|
|
|
msh[0] * np.sin(msh[1]) * np.cos(msh[2]),
|
|
|
|
|
msh[0] * np.sin(msh[1]) * np.sin(msh[2])
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _lab2rgb(lab: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
return Colormap._xyz2rgb(Colormap._lab2xyz(lab))
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _rgb2lab(rgb: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
return Colormap._xyz2lab(Colormap._rgb2xyz(rgb))
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _msh2rgb(msh: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
return Colormap._lab2rgb(Colormap._msh2lab(msh))
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _rgb2msh(rgb: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
return Colormap._lab2msh(Colormap._rgb2lab(rgb))
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _hsv2msh(hsv: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
return Colormap._rgb2msh(Colormap._hsv2rgb(hsv))
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _hsl2msh(hsl: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
return Colormap._rgb2msh(Colormap._hsl2rgb(hsl))
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2021-11-22 21:45:22 +05:30
|
|
|
|
def _xyz2msh(xyz: np.ndarray) -> np.ndarray:
|
2020-06-27 19:31:16 +05:30
|
|
|
|
return Colormap._lab2msh(Colormap._xyz2lab(xyz))
|