code shortening; list_predefined() --> property "predefined"

This commit is contained in:
Philip Eisenlohr 2020-11-16 10:23:01 -05:00
parent fd8743af5e
commit de20e6b35d
2 changed files with 61 additions and 85 deletions

View File

@ -22,6 +22,16 @@ _ref_white = np.array([.95047, 1.00000, 1.08883])
# - support NaN color (paraview) # - support NaN color (paraview)
class Colormap(mpl.colors.ListedColormap): class Colormap(mpl.colors.ListedColormap):
"""
References
----------
[1] DAMASK colormap theory
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
[2] DAMASK colormaps first use
https://doi.org/10.1016/j.ijplas.2012.09.012
[3] Matplotlib colormaps overview
https://matplotlib.org/tutorials/colors/colormaps.html
"""
def __add__(self,other): def __add__(self,other):
"""Concatenate colormaps.""" """Concatenate colormaps."""
@ -137,40 +147,16 @@ class Colormap(mpl.colors.ListedColormap):
""" """
# matplotlib presets # matplotlib presets
for cat in Colormap._predefined_mpl: try:
for n in cat[1]: colormap = cm.__dict__[name]
if n == name: return Colormap(np.array(list(map(colormap,np.linspace(0,1,N)))
colormap = cm.__dict__[name] if isinstance(colormap,mpl.colors.LinearSegmentedColormap) else
if isinstance(colormap,mpl.colors.LinearSegmentedColormap): colormap.colors),
return Colormap(np.array(list(map(colormap,np.linspace(0,1,N)))),name=name) name=name)
else: except:
return Colormap(np.array(colormap.colors),name=name) # DAMASK presets
definition = Colormap._predefined_DAMASK[name]
# DAMASK presets return Colormap.from_range(definition['low'],definition['high'],name,N)
definition = Colormap._predefined_DAMASK[name]
return Colormap.from_range(definition['low'],definition['high'],name,N)
@staticmethod
def list_predefined():
"""
List predefined colormaps by category.
References
----------
[1] DAMASK colormap theory
https://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf
[2] DAMASK colormaps first use
https://doi.org/10.1016/j.ijplas.2012.09.012
[3] Matplotlib colormaps overview
https://matplotlib.org/tutorials/colors/colormaps.html
"""
print('DAMASK colormaps')
print(' '+', '.join(Colormap._predefined_DAMASK.keys()))
for cat in Colormap._predefined_mpl:
print(f'{cat[0]}')
print(' '+', '.join(cat[1]))
def shade(self,field,bounds=None,gap=None): def shade(self,field,bounds=None,gap=None):
@ -179,9 +165,9 @@ class Colormap(mpl.colors.ListedColormap):
Parameters Parameters
---------- ----------
field : numpy.array of shape(:,:) field : numpy.array of shape (:,:)
Data to be shaded. Data to be shaded.
bounds : iterable of len(2), optional bounds : iterable of len (2), optional
Colormap value range (low,high). Colormap value range (low,high).
gap : field.dtype, optional gap : field.dtype, optional
Transparent value. NaN will always be rendered transparent. Transparent value. NaN will always be rendered transparent.
@ -234,7 +220,6 @@ class Colormap(mpl.colors.ListedColormap):
return Colormap(np.array(rev.colors),rev.name[:-4] if rev.name.endswith('_r_r') else rev.name) return Colormap(np.array(rev.colors),rev.name[:-4] if rev.name.endswith('_r_r') else rev.name)
def save_paraview(self,fname=None): def save_paraview(self,fname=None):
""" """
Write colormap to JSON file for Paraview. Write colormap to JSON file for Paraview.
@ -246,13 +231,13 @@ class Colormap(mpl.colors.ListedColormap):
consist of the name of the colormap and extension '.json'. consist of the name of the colormap and extension '.json'.
""" """
if fname is not None: if fname is None:
fhandle = None
else:
try: try:
fhandle = open(fname,'w') fhandle = open(fname,'w')
except TypeError: except TypeError:
fhandle = fname fhandle = fname
else:
fhandle = None
colors = [] colors = []
for i,c in enumerate(np.round(self.colors,6).tolist()): for i,c in enumerate(np.round(self.colors,6).tolist()):
@ -265,11 +250,9 @@ class Colormap(mpl.colors.ListedColormap):
'DefaultMap':True, 'DefaultMap':True,
'RGBPoints':colors 'RGBPoints':colors
}] }]
if fhandle is None:
with open(self.name.replace(' ','_')+'.json', 'w') as f: with open(self.name.replace(' ','_')+'.json', 'w') if fhandle is None else fhandle as f:
json.dump(out, f,indent=4) json.dump(out, f,indent=4)
else:
json.dump(out,fhandle,indent=4)
def save_ASCII(self,fname=None): def save_ASCII(self,fname=None):
@ -283,22 +266,19 @@ class Colormap(mpl.colors.ListedColormap):
consist of the name of the colormap and extension '.txt'. consist of the name of the colormap and extension '.txt'.
""" """
if fname is not None: if fname is None:
fhandle = None
else:
try: try:
fhandle = open(fname,'w') fhandle = open(fname,'w')
except TypeError: except TypeError:
fhandle = fname fhandle = fname
else:
fhandle = None
labels = {'RGBA':4} if self.colors.shape[1] == 4 else {'RGB': 3} labels = {'RGBA':4} if self.colors.shape[1] == 4 else {'RGB': 3}
t = Table(self.colors,labels,f'Creator: {util.execution_stamp("Colormap")}') t = Table(self.colors,labels,f'Creator: {util.execution_stamp("Colormap")}')
if fhandle is None: with open(self.name.replace(' ','_')+'.txt', 'w') if fhandle is None else fhandle as f:
with open(self.name.replace(' ','_')+'.txt', 'w') as f: t.save(f)
t.save(f)
else:
t.save(fhandle)
def save_GOM(self,fname=None): def save_GOM(self,fname=None):
@ -312,24 +292,21 @@ class Colormap(mpl.colors.ListedColormap):
consist of the name of the colormap and extension '.legend'. consist of the name of the colormap and extension '.legend'.
""" """
if fname is not None: if fname is None:
fhandle = None
else:
try: try:
fhandle = open(fname,'w') fhandle = open(fname,'w')
except TypeError: except TypeError:
fhandle = fname fhandle = fname
else:
fhandle = None
# 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 {len(self.colors)}' \
+ ' '.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'
if fhandle is None: with open(self.name.replace(' ','_')+'.legend', 'w') if fhandle is None else fhandle as f:
with open(self.name.replace(' ','_')+'.legend', 'w') as f: f.write(GOM_str)
f.write(GOM_str)
else:
fhandle.write(GOM_str)
def save_gmsh(self,fname=None): def save_gmsh(self,fname=None):
@ -343,22 +320,19 @@ class Colormap(mpl.colors.ListedColormap):
consist of the name of the colormap and extension '.msh'. consist of the name of the colormap and extension '.msh'.
""" """
if fname is not None: if fname is None:
fhandle = None
else:
try: try:
fhandle = open(fname,'w') fhandle = open(fname,'w')
except TypeError: except TypeError:
fhandle = fname fhandle = fname
else:
fhandle = None
# ToDo: test in gmsh # ToDo: test in gmsh
gmsh_str = 'View.ColorTable = {\n' \ gmsh_str = 'View.ColorTable = {\n' \
+'\n'.join([f'{c[0]},{c[1]},{c[2]},' for c in self.colors[:,:3]*255]) \ +'\n'.join([f'{c[0]},{c[1]},{c[2]},' for c in self.colors[:,:3]*255]) \
+'\n}\n' +'\n}\n'
if fhandle is None: with open(self.name.replace(' ','_')+'.msh', 'w') if fhandle is None else fhandle as f:
with open(self.name.replace(' ','_')+'.msh', 'w') as f: f.write(gmsh_str)
f.write(gmsh_str)
else:
fhandle.write(gmsh_str)
@staticmethod @staticmethod
@ -386,7 +360,6 @@ class Colormap(mpl.colors.ListedColormap):
if msh_sat[2] < - np.pi/3.0: hSpin *= -1.0 if msh_sat[2] < - np.pi/3.0: hSpin *= -1.0
return msh_sat[2] + hSpin return msh_sat[2] + hSpin
lo = np.array(low) lo = np.array(low)
hi = np.array(high) hi = np.array(high)
@ -406,28 +379,28 @@ class Colormap(mpl.colors.ListedColormap):
return (1.0 - frac) * lo + frac * hi return (1.0 - frac) * lo + frac * hi
_predefined_mpl= [('Perceptually Uniform Sequential', [ _predefined_mpl= {'Perceptually Uniform Sequential': [
'viridis', 'plasma', 'inferno', 'magma', 'cividis']), 'viridis', 'plasma', 'inferno', 'magma', 'cividis'],
('Sequential', [ 'Sequential': [
'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', 'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn']), 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn'],
('Sequential (2)', [ 'Sequential (2)': [
'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink', 'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink',
'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia', 'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia',
'hot', 'afmhot', 'gist_heat', 'copper']), 'hot', 'afmhot', 'gist_heat', 'copper'],
('Diverging', [ 'Diverging': [
'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', 'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu',
'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic']), 'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic'],
('Cyclic', ['twilight', 'twilight_shifted', 'hsv']), 'Cyclic': ['twilight', 'twilight_shifted', 'hsv'],
('Qualitative', [ 'Qualitative': [
'Pastel1', 'Pastel2', 'Paired', 'Accent', 'Pastel1', 'Pastel2', 'Paired', 'Accent',
'Dark2', 'Set1', 'Set2', 'Set3', 'Dark2', 'Set1', 'Set2', 'Set3',
'tab10', 'tab20', 'tab20b', 'tab20c']), 'tab10', 'tab20', 'tab20b', 'tab20c'],
('Miscellaneous', [ 'Miscellaneous': [
'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern', 'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern',
'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg', 'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg',
'gist_rainbow', 'rainbow', 'jet', 'nipy_spectral', 'gist_ncar'])] 'gist_rainbow', 'rainbow', 'jet', 'nipy_spectral', 'gist_ncar']}
_predefined_DAMASK = {'orientation': {'low': [0.933334,0.878432,0.878431], _predefined_DAMASK = {'orientation': {'low': [0.933334,0.878432,0.878431],
'high': [0.250980,0.007843,0.000000]}, 'high': [0.250980,0.007843,0.000000]},
@ -436,6 +409,9 @@ class Colormap(mpl.colors.ListedColormap):
'stress': {'low': [0.878432,0.874511,0.949019], 'stress': {'low': [0.878432,0.874511,0.949019],
'high': [0.000002,0.000000,0.286275]}} 'high': [0.000002,0.000000,0.286275]}}
predefined = dict(**{'DAMASK':list(_predefined_DAMASK)},**_predefined_mpl)
@staticmethod @staticmethod
def _hsv2rgb(hsv): def _hsv2rgb(hsv):
""" """

View File

@ -141,8 +141,8 @@ class TestColormap:
diff = ImageChops.difference(img_reference.convert('RGB'),img_current.convert('RGB')) diff = ImageChops.difference(img_reference.convert('RGB'),img_current.convert('RGB'))
assert not diff.getbbox() assert not diff.getbbox()
def test_list(self): def test_predefined(self):
Colormap.list_predefined() assert (isinstance(Colormap.predefined,dict))
@pytest.mark.parametrize('format,ext',[('ASCII','.txt'), @pytest.mark.parametrize('format,ext',[('ASCII','.txt'),
('paraview','.json'), ('paraview','.json'),