Merge remote-tracking branch 'origin/colormap-docstrings' into development
This commit is contained in:
commit
99166a7ce2
|
@ -5,6 +5,7 @@ import colorsys
|
|||
from pathlib import Path
|
||||
from typing import Sequence, Union, TextIO
|
||||
|
||||
|
||||
import numpy as np
|
||||
import matplotlib as mpl
|
||||
if os.name == 'posix' and 'DISPLAY' not in os.environ:
|
||||
|
@ -41,6 +42,11 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
|
||||
"""
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
"""Test equality of colormaps."""
|
||||
return len(self.colors) == len(other.colors) \
|
||||
and bool(np.all(self.colors == other.colors))
|
||||
|
||||
def __add__(self, other: 'Colormap') -> 'Colormap':
|
||||
"""Concatenate."""
|
||||
return Colormap(np.vstack((self.colors,other.colors)),
|
||||
|
@ -80,20 +86,20 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
low : numpy.ndarray of shape (3)
|
||||
low : iterable of float (3)
|
||||
Color definition for minimum value.
|
||||
high : numpy.ndarray of shape (3)
|
||||
high : iterable of float (3)
|
||||
Color definition for maximum value.
|
||||
N : int, optional
|
||||
The number of color quantization levels. Defaults to 256.
|
||||
name : str, optional
|
||||
The name of the colormap. Defaults to `DAMASK colormap`.
|
||||
Name of the colormap. Defaults to `DAMASK colormap`.
|
||||
N : int, optional
|
||||
Number of color quantization levels. Defaults to 256.
|
||||
model : {'rgb', 'hsv', 'hsl', 'xyz', 'lab', 'msh'}
|
||||
Colormodel used for input color definitions. Defaults to `rgb`.
|
||||
Color model used for input color definitions. Defaults to `rgb`.
|
||||
The available color models are:
|
||||
- 'rgb': R(ed) G(green) B(lue).
|
||||
- 'hsv': H(ue) S(aturation) V(alue).
|
||||
- 'hsl': H(ue) S(aturation) L(uminance).
|
||||
- 'rgb': Red Green Blue.
|
||||
- 'hsv': Hue Saturation Value.
|
||||
- 'hsl': Hue Saturation Luminance.
|
||||
- 'xyz': CIE Xyz.
|
||||
- 'lab': CIE Lab.
|
||||
- 'msh': Msh (for perceptual uniform interpolation).
|
||||
|
@ -109,41 +115,34 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
>>> damask.Colormap.from_range((0,0,1),(0,0,0),'blue_to_black')
|
||||
|
||||
"""
|
||||
low_high = np.vstack((low,high))
|
||||
if model.lower() == 'rgb':
|
||||
if np.any(low_high<0) or np.any(low_high>1):
|
||||
raise ValueError(f'RGB color {low} | {high} are out of range.')
|
||||
toMsh = dict(
|
||||
rgb=Colormap._rgb2msh,
|
||||
hsv=Colormap._hsv2msh,
|
||||
hsl=Colormap._hsl2msh,
|
||||
xyz=Colormap._xyz2msh,
|
||||
lab=Colormap._lab2msh,
|
||||
msh=lambda x:x,
|
||||
)
|
||||
|
||||
low_,high_ = map(Colormap._rgb2msh,low_high)
|
||||
|
||||
elif model.lower() == 'hsv':
|
||||
if np.any(low_high<0) or np.any(low_high>[360,1,1]):
|
||||
raise ValueError(f'HSV color {low} | {high} are out of range.')
|
||||
|
||||
low_,high_ = map(Colormap._hsv2msh,low_high)
|
||||
|
||||
elif model.lower() == 'hsl':
|
||||
if np.any(low_high<0) or np.any(low_high>[360,1,1]):
|
||||
raise ValueError(f'HSL color {low} | {high} are out of range.')
|
||||
|
||||
low_,high_ = map(Colormap._hsl2msh,low_high)
|
||||
|
||||
elif model.lower() == 'xyz':
|
||||
|
||||
low_,high_ = map(Colormap._xyz2msh,low_high)
|
||||
|
||||
elif model.lower() == 'lab':
|
||||
if np.any(low_high[:,0]<0):
|
||||
raise ValueError(f'CIE Lab color {low} | {high} are out of range.')
|
||||
|
||||
low_,high_ = map(Colormap._lab2msh,low_high)
|
||||
|
||||
elif model.lower() == 'msh':
|
||||
low_,high_ = low_high[0],low_high[1]
|
||||
|
||||
else:
|
||||
if model.lower() not in toMsh:
|
||||
raise ValueError(f'Invalid color model: {model}.')
|
||||
|
||||
low_high = np.vstack((low,high))
|
||||
out_of_bounds = np.bool_(False)
|
||||
|
||||
if model.lower() == 'rgb':
|
||||
out_of_bounds = np.any(low_high<0) or np.any(low_high>1)
|
||||
elif model.lower() == 'hsv':
|
||||
out_of_bounds = np.any(low_high<0) or np.any(low_high>[360,1,1])
|
||||
elif model.lower() == 'hsl':
|
||||
out_of_bounds = np.any(low_high<0) or np.any(low_high>[360,1,1])
|
||||
elif model.lower() == 'lab':
|
||||
out_of_bounds = np.any(low_high[:,0]<0)
|
||||
|
||||
if out_of_bounds:
|
||||
raise ValueError(f'{model.upper()} colors {low} | {high} are out of bounds.')
|
||||
|
||||
low_,high_ = map(toMsh[model.lower()],low_high)
|
||||
msh = map(functools.partial(Colormap._interpolate_msh,low=low_,high=high_),np.linspace(0,1,N))
|
||||
rgb = np.array(list(map(Colormap._msh2rgb,msh)))
|
||||
|
||||
|
@ -155,17 +154,17 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
"""
|
||||
Select from a set of predefined colormaps.
|
||||
|
||||
Predefined colormaps include native matplotlib colormaps
|
||||
and common DAMASK colormaps.
|
||||
Predefined colormaps (Colormap.predefined) include
|
||||
native matplotlib colormaps and common DAMASK colormaps.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
The name of the colormap.
|
||||
Name of the colormap.
|
||||
N : int, optional
|
||||
The number of color quantization levels. Defaults to 256.
|
||||
This parameter is not used for matplotlib colormaps
|
||||
that are of type `ListedColormap`.
|
||||
Number of color quantization levels. Defaults to 256.
|
||||
This parameter is not used for matplotlib colormaps
|
||||
that are of type `ListedColormap`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
@ -178,8 +177,8 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
>>> damask.Colormap.from_predefined('strain')
|
||||
|
||||
"""
|
||||
# matplotlib presets
|
||||
try:
|
||||
# matplotlib presets
|
||||
colormap = cm.__dict__[name]
|
||||
return Colormap(np.array(list(map(colormap,np.linspace(0,1,N)))
|
||||
if isinstance(colormap,mpl.colors.LinearSegmentedColormap) else
|
||||
|
@ -202,8 +201,8 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
----------
|
||||
field : numpy.array of shape (:,:)
|
||||
Data to be shaded.
|
||||
bounds : iterable of len (2), optional
|
||||
Colormap value range (low,high).
|
||||
bounds : iterable of float (2), optional
|
||||
Value range (low,high) spanned by colormap.
|
||||
gap : field.dtype, optional
|
||||
Transparent value. NaN will always be rendered transparent.
|
||||
|
||||
|
@ -242,13 +241,13 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
Parameters
|
||||
----------
|
||||
name : str, optional
|
||||
The name for the reversed colormap.
|
||||
A name of None will be replaced by the name of the parent colormap + "_r".
|
||||
Name of the reversed colormap.
|
||||
If None, parent colormap name + "_r".
|
||||
|
||||
Returns
|
||||
-------
|
||||
damask.Colormap
|
||||
The reversed colormap.
|
||||
Reversed colormap.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
@ -260,16 +259,19 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
return Colormap(np.array(rev.colors),rev.name[:-4] if rev.name.endswith('_r_r') else rev.name)
|
||||
|
||||
|
||||
def _get_file_handle(self, fname: Union[TextIO, str, Path, None], suffix: str) -> TextIO:
|
||||
def _get_file_handle(self,
|
||||
fname: Union[TextIO, str, Path, None],
|
||||
dsuffix: str = '') -> TextIO:
|
||||
"""
|
||||
Provide file handle.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fname : file, str, pathlib.Path, or None
|
||||
Filename or filehandle, will be name of the colormap+extension if None.
|
||||
suffix: str
|
||||
Extension of the filename.
|
||||
Filename or filehandle.
|
||||
If None, colormap name + suffix.
|
||||
suffix: str, optional
|
||||
Extension to use for colormap filename.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
@ -293,10 +295,10 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
----------
|
||||
fname : file, str, or pathlib.Path, optional
|
||||
Filename to store results. If not given, the filename will
|
||||
consist of the name of the colormap and extension '.json'.
|
||||
consist of the name of the colormap with extension '.json'.
|
||||
|
||||
"""
|
||||
colors = []
|
||||
colors: List = []
|
||||
for i,c in enumerate(np.round(self.colors,6).tolist()):
|
||||
colors+=[i]+c
|
||||
|
||||
|
@ -321,7 +323,7 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
----------
|
||||
fname : file, str, or pathlib.Path, optional
|
||||
Filename to store results. If not given, the filename will
|
||||
consist of the name of the colormap and extension '.txt'.
|
||||
consist of the name of the colormap with extension '.txt'.
|
||||
|
||||
"""
|
||||
labels = {'RGBA':4} if self.colors.shape[1] == 4 else {'RGB': 3}
|
||||
|
@ -337,7 +339,7 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
----------
|
||||
fname : file, str, or pathlib.Path, optional
|
||||
Filename to store results. If not given, the filename will
|
||||
consist of the name of the colormap and extension '.legend'.
|
||||
consist of the name of the colormap with extension '.legend'.
|
||||
|
||||
"""
|
||||
# ToDo: test in GOM
|
||||
|
@ -358,7 +360,7 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
----------
|
||||
fname : file, str, or pathlib.Path, optional
|
||||
Filename to store results. If not given, the filename will
|
||||
consist of the name of the colormap and extension '.msh'.
|
||||
consist of the name of the colormap with extension '.msh'.
|
||||
|
||||
"""
|
||||
# ToDo: test in gmsh
|
||||
|
@ -369,7 +371,7 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
|
||||
|
||||
@staticmethod
|
||||
def _interpolate_msh(frac,
|
||||
def _interpolate_msh(frac: float,
|
||||
low: np.ndarray,
|
||||
high: np.ndarray) -> np.ndarray:
|
||||
"""
|
||||
|
@ -449,24 +451,76 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
|
||||
@staticmethod
|
||||
def _hsv2rgb(hsv: np.ndarray) -> np.ndarray:
|
||||
"""H(ue) S(aturation) V(alue) to R(red) G(reen) B(lue)."""
|
||||
"""
|
||||
Hue Saturation Value to Red Green Blue.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
hsv : numpy.ndarray of shape (3)
|
||||
HSV values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
rgb : numpy.ndarray of shape (3)
|
||||
RGB values.
|
||||
|
||||
"""
|
||||
return np.array(colorsys.hsv_to_rgb(hsv[0]/360.,hsv[1],hsv[2]))
|
||||
|
||||
@staticmethod
|
||||
def _rgb2hsv(rgb: np.ndarray) -> np.ndarray:
|
||||
"""R(ed) G(reen) B(lue) to H(ue) S(aturation) V(alue)."""
|
||||
"""
|
||||
Red Green Blue to Hue Saturation Value.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rgb : numpy.ndarray of shape (3)
|
||||
RGB values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
hsv : numpy.ndarray of shape (3)
|
||||
HSV values.
|
||||
|
||||
"""
|
||||
h,s,v = colorsys.rgb_to_hsv(rgb[0],rgb[1],rgb[2])
|
||||
return np.array([h*360,s,v])
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _hsl2rgb(hsl: np.ndarray) -> np.ndarray:
|
||||
"""H(ue) S(aturation) L(uminance) to R(red) G(reen) B(lue)."""
|
||||
"""
|
||||
Hue Saturation Luminance to Red Green Blue.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
hsl : numpy.ndarray of shape (3)
|
||||
HSL values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
rgb : numpy.ndarray of shape (3)
|
||||
RGB values.
|
||||
|
||||
"""
|
||||
return np.array(colorsys.hls_to_rgb(hsl[0]/360.,hsl[2],hsl[1]))
|
||||
|
||||
@staticmethod
|
||||
def _rgb2hsl(rgb: np.ndarray) -> np.ndarray:
|
||||
"""R(ed) G(reen) B(lue) to H(ue) S(aturation) L(uminance)."""
|
||||
"""
|
||||
Red Green Blue to Hue Saturation Luminance.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rgb : numpy.ndarray of shape (3)
|
||||
RGB values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
hsl : numpy.ndarray of shape (3)
|
||||
HSL values.
|
||||
|
||||
"""
|
||||
h,l,s = colorsys.rgb_to_hls(rgb[0],rgb[1],rgb[2])
|
||||
return np.array([h*360,s,l])
|
||||
|
||||
|
@ -474,7 +528,17 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
@staticmethod
|
||||
def _xyz2rgb(xyz: np.ndarray) -> np.ndarray:
|
||||
"""
|
||||
CIE Xyz to R(ed) G(reen) B(lue).
|
||||
CIE Xyz to Red Green Blue.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xyz : numpy.ndarray of shape (3)
|
||||
CIE Xyz values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
rgb : numpy.ndarray of shape (3)
|
||||
RGB values.
|
||||
|
||||
References
|
||||
----------
|
||||
|
@ -494,7 +558,17 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
@staticmethod
|
||||
def _rgb2xyz(rgb: np.ndarray) -> np.ndarray:
|
||||
"""
|
||||
R(ed) G(reen) B(lue) to CIE Xyz.
|
||||
Red Green Blue to CIE Xyz.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rgb : numpy.ndarray of shape (3)
|
||||
RGB values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
xyz : numpy.ndarray of shape (3)
|
||||
CIE Xyz values.
|
||||
|
||||
References
|
||||
----------
|
||||
|
@ -514,6 +588,16 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
"""
|
||||
CIE Lab to CIE Xyz.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lab : numpy.ndarray of shape (3)
|
||||
CIE lab values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
xyz : numpy.ndarray of shape (3)
|
||||
CIE Xyz values.
|
||||
|
||||
References
|
||||
----------
|
||||
http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
|
||||
|
@ -533,6 +617,16 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
"""
|
||||
CIE Xyz to CIE Lab.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xyz : numpy.ndarray of shape (3)
|
||||
CIE Xyz values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
lab : numpy.ndarray of shape (3)
|
||||
CIE lab values.
|
||||
|
||||
References
|
||||
----------
|
||||
http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
|
||||
|
@ -553,6 +647,16 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
"""
|
||||
CIE Lab to Msh.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lab : numpy.ndarray of shape (3)
|
||||
CIE lab values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
msh : numpy.ndarray of shape (3)
|
||||
Msh values.
|
||||
|
||||
References
|
||||
----------
|
||||
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
||||
|
@ -571,6 +675,16 @@ class Colormap(mpl.colors.ListedColormap):
|
|||
"""
|
||||
Msh to CIE Lab.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
msh : numpy.ndarray of shape (3)
|
||||
Msh values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
lab : numpy.ndarray of shape (3)
|
||||
CIE lab values.
|
||||
|
||||
References
|
||||
----------
|
||||
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
|
||||
|
|
|
@ -77,12 +77,15 @@ class TestColormap:
|
|||
# xyz2msh
|
||||
assert np.allclose(Colormap._xyz2msh(xyz),msh,atol=1.e-6,rtol=0)
|
||||
|
||||
def test_eq(self):
|
||||
assert Colormap.from_predefined('strain') == Colormap.from_predefined('strain')
|
||||
assert Colormap.from_predefined('strain') != Colormap.from_predefined('stress')
|
||||
assert Colormap.from_predefined('strain',N=128) != Colormap.from_predefined('strain',N=64)
|
||||
|
||||
@pytest.mark.parametrize('low,high',[((0,0,0),(1,1,1)),
|
||||
([0,0,0],[1,1,1])])
|
||||
def test_from_range_types(self,low,high):
|
||||
a = Colormap.from_range(low,high)
|
||||
b = Colormap.from_range(np.array(low),np.array(high))
|
||||
assert np.all(a.colors == b.colors)
|
||||
assert Colormap.from_range(low,high) == Colormap.from_range(np.array(low),np.array(high))
|
||||
|
||||
@pytest.mark.parametrize('format',['ASCII','paraview','GOM','gmsh'])
|
||||
@pytest.mark.parametrize('model',['rgb','hsv','hsl','xyz','lab','msh'])
|
||||
|
|
Loading…
Reference in New Issue