added Colormap.at(fraction) to interpolate

This commit is contained in:
Eureka Pai 2021-12-10 11:31:26 -05:00
parent 63c76abed8
commit 947bf946e1
2 changed files with 32 additions and 3 deletions

View File

@ -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')
@ -191,6 +192,28 @@ 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 : float) -> np.ndarray:
"""
Interpolate color at fraction.
Parameters
----------
fraction : float
Fractional coordinate to evaluate Colormap at.
Returns
-------
color : np.ndarray, shape(3)
RGB values of interpolated color.
"""
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 +236,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 +249,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 +365,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'

View File

@ -139,6 +139,13 @@ 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',[
(8,'gray'),
(17,'gray'),
])
def test_at(self, N, cmap):
assert np.allclose(Colormap.from_predefined(cmap,N=N).at(0.5)[:3],0.5,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)))