Merge commit 'v3.0.0-alpha5-290-g99267afda'
This commit is contained in:
commit
9d9ee4b979
|
@ -6,6 +6,7 @@ from pathlib import Path
|
||||||
from typing import Sequence, Union, TextIO
|
from typing import Sequence, Union, TextIO
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import scipy.interpolate as interp
|
||||||
import matplotlib as mpl
|
import matplotlib as mpl
|
||||||
if os.name == 'posix' and 'DISPLAY' not in os.environ:
|
if os.name == 'posix' and 'DISPLAY' not in os.environ:
|
||||||
mpl.use('Agg')
|
mpl.use('Agg')
|
||||||
|
@ -41,7 +42,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
https://doi.org/10.1016/j.ijplas.2012.09.012
|
https://doi.org/10.1016/j.ijplas.2012.09.012
|
||||||
|
|
||||||
Matplotlib colormaps overview
|
Matplotlib colormaps overview
|
||||||
https://matplotlib.org/tutorials/colors/colormaps.html
|
https://matplotlib.org/stable/tutorials/colors/colormaps.html
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -191,6 +192,37 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
return Colormap.from_range(definition['low'],definition['high'],name,N)
|
return Colormap.from_range(definition['low'],definition['high'],name,N)
|
||||||
|
|
||||||
|
|
||||||
|
def at(self,
|
||||||
|
fraction : Union[float,Sequence[float]]) -> np.ndarray:
|
||||||
|
"""
|
||||||
|
Interpolate color at fraction.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
fraction : float or sequence of float
|
||||||
|
Fractional coordinate(s) to evaluate Colormap at.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
color : np.ndarray, shape(...,4)
|
||||||
|
RGBA values of interpolated color(s).
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
>>> import damask
|
||||||
|
>>> cmap = damask.Colormap.from_predefined('gray')
|
||||||
|
>>> cmap.at(0.5)
|
||||||
|
array([0.5, 0.5, 0.5, 1. ])
|
||||||
|
>>> 'rgb({},{},{})'.format(*cmap.at(0.5))
|
||||||
|
'rgb(0.5,0.5,0.5)'
|
||||||
|
|
||||||
|
"""
|
||||||
|
return interp.interp1d(np.linspace(0,1,self.N),
|
||||||
|
self.colors,
|
||||||
|
axis=0,
|
||||||
|
assume_sorted=True)(fraction)
|
||||||
|
|
||||||
|
|
||||||
def shade(self,
|
def shade(self,
|
||||||
field: np.ndarray,
|
field: np.ndarray,
|
||||||
bounds: Sequence[float] = None,
|
bounds: Sequence[float] = None,
|
||||||
|
@ -213,7 +245,6 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
RGBA image of shaded data.
|
RGBA image of shaded data.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
N = len(self.colors)
|
|
||||||
mask = np.logical_not(np.isnan(field) if gap is None else \
|
mask = np.logical_not(np.isnan(field) if gap is None else \
|
||||||
np.logical_or (np.isnan(field), field == gap)) # mask NaN (and gap if present)
|
np.logical_or (np.isnan(field), field == gap)) # mask NaN (and gap if present)
|
||||||
|
|
||||||
|
@ -227,7 +258,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
|
|
||||||
return Image.fromarray(
|
return Image.fromarray(
|
||||||
(np.dstack((
|
(np.dstack((
|
||||||
self.colors[(np.round(np.clip((field-lo)/(hi-lo),0.0,1.0)*(N-1))).astype(np.uint16),:3],
|
self.colors[(np.round(np.clip((field-lo)/(hi-lo),0.0,1.0)*(self.N-1))).astype(np.uint16),:3],
|
||||||
mask.astype(float)
|
mask.astype(float)
|
||||||
)
|
)
|
||||||
)*255
|
)*255
|
||||||
|
@ -343,7 +374,7 @@ class Colormap(mpl.colors.ListedColormap):
|
||||||
# ToDo: test in GOM
|
# ToDo: test in GOM
|
||||||
GOM_str = '1 1 {name} 9 {name} '.format(name=self.name.replace(" ","_")) \
|
GOM_str = '1 1 {name} 9 {name} '.format(name=self.name.replace(" ","_")) \
|
||||||
+ '0 1 0 3 0 0 -1 9 \\ 0 0 0 255 255 255 0 0 255 ' \
|
+ '0 1 0 3 0 0 -1 9 \\ 0 0 0 255 255 255 0 0 255 ' \
|
||||||
+ f'30 NO_UNIT 1 1 64 64 64 255 1 0 0 0 0 0 0 3 0 {len(self.colors)}' \
|
+ f'30 NO_UNIT 1 1 64 64 64 255 1 0 0 0 0 0 0 3 0 {self.N}' \
|
||||||
+ ' '.join([f' 0 {c[0]} {c[1]} {c[2]} 255 1' for c in reversed((self.colors*255).astype(int))]) \
|
+ ' '.join([f' 0 {c[0]} {c[1]} {c[2]} 255 1' for c in reversed((self.colors*255).astype(int))]) \
|
||||||
+ '\n'
|
+ '\n'
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,16 @@ class TestColormap:
|
||||||
c += c
|
c += c
|
||||||
assert (np.allclose(c.colors[:len(c.colors)//2],c.colors[len(c.colors)//2:]))
|
assert (np.allclose(c.colors[:len(c.colors)//2],c.colors[len(c.colors)//2:]))
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('N,cmap,at,result',[
|
||||||
|
(8,'gray',0.5,[0.5,0.5,0.5]),
|
||||||
|
(17,'gray',0.5,[0.5,0.5,0.5]),
|
||||||
|
(17,'gray',[0.5,0.75],[[0.5,0.5,0.5],[0.75,0.75,0.75]]),
|
||||||
|
])
|
||||||
|
def test_at_value(self, N, cmap, at, result):
|
||||||
|
assert np.allclose(Colormap.from_predefined(cmap,N=N).at(at)[...,:3],
|
||||||
|
result,
|
||||||
|
rtol=0.005)
|
||||||
|
|
||||||
@pytest.mark.parametrize('bounds',[None,[2,10]])
|
@pytest.mark.parametrize('bounds',[None,[2,10]])
|
||||||
def test_shade(self,ref_path,update,bounds):
|
def test_shade(self,ref_path,update,bounds):
|
||||||
data = np.add(*np.indices((10, 11)))
|
data = np.add(*np.indices((10, 11)))
|
||||||
|
|
Loading…
Reference in New Issue