@@ -675,16 +675,7 @@ def _create_lookup_table(N, data, gamma=1.0):
675
675
return np .clip (lut , 0.0 , 1.0 )
676
676
677
677
678
- class ColormapBase :
679
- """
680
- Base class for all colormaps, both scalar, bivariate and multivariate.
681
-
682
- This class is used for type checking, and cannot be initialized.
683
- """
684
- ...
685
-
686
-
687
- class Colormap (ColormapBase ):
678
+ class Colormap :
688
679
"""
689
680
Baseclass for all scalar to RGBA mappings.
690
681
@@ -721,7 +712,7 @@ def __init__(self, name, N=256):
721
712
#: `matplotlib.colorbar.Colorbar` constructor.
722
713
self .colorbar_extend = False
723
714
724
- def __call__ (self , X , alpha = None , bytes = False , return_mask_bad = False ):
715
+ def __call__ (self , X , alpha = None , bytes = False ):
725
716
r"""
726
717
Parameters
727
718
----------
@@ -737,15 +728,40 @@ def __call__(self, X, alpha=None, bytes=False, return_mask_bad=False):
737
728
bytes : bool
738
729
If False (default), the returned RGBA values will be floats in the
739
730
interval ``[0, 1]`` otherwise they will be `numpy.uint8`\s in the
740
- interval ``[0, 255]``.
741
- return_mask_bad : bool
742
- If true, also return a mask of bad values.
731
+ interval ``[0, 255]``
743
732
744
733
Returns
745
734
-------
746
735
Tuple of RGBA values if X is scalar, otherwise an array of
747
736
RGBA values with a shape of ``X.shape + (4, )``.
748
737
"""
738
+ rgba , mask = self ._get_rgba_and_mask (X , alpha = alpha , bytes = bytes )
739
+ return rgba
740
+
741
+ def _get_rgba_and_mask (self , X , alpha = None , bytes = False ):
742
+ r"""
743
+ Parameters
744
+ ----------
745
+ X : float or int, `~numpy.ndarray` or scalar
746
+ The data value(s) to convert to RGBA.
747
+ For floats, *X* should be in the interval ``[0.0, 1.0]`` to
748
+ return the RGBA values ``X*100`` percent along the Colormap line.
749
+ For integers, *X* should be in the interval ``[0, Colormap.N)`` to
750
+ return RGBA values *indexed* from the Colormap with index ``X``.
751
+ alpha : float or array-like or None
752
+ Alpha must be a scalar between 0 and 1, a sequence of such
753
+ floats with shape matching X, or None.
754
+ bytes : bool
755
+ If False (default), the returned RGBA values will be floats in the
756
+ interval ``[0, 1]`` otherwise they will be `numpy.uint8`\s in the
757
+ interval ``[0, 255]``.
758
+
759
+ Returns
760
+ -------
761
+ (colors, mask), where color is a tuple of RGBA values if X is scalar,
762
+ otherwise an array of RGBA values with a shape of ``X.shape + (4, )``,
763
+ and mask is a boolean array.
764
+ """
749
765
if not self ._isinit :
750
766
self ._init ()
751
767
@@ -791,9 +807,7 @@ def __call__(self, X, alpha=None, bytes=False, return_mask_bad=False):
791
807
792
808
if not np .iterable (X ):
793
809
rgba = tuple (rgba )
794
- if return_mask_bad :
795
- return rgba , mask_bad
796
- return rgba
810
+ return rgba , mask_bad
797
811
798
812
def __copy__ (self ):
799
813
cls = self .__class__
@@ -1240,13 +1254,10 @@ def reversed(self, name=None):
1240
1254
return new_cmap
1241
1255
1242
1256
1243
- class MultivarColormap ( ColormapBase ) :
1257
+ class MultivarColormap :
1244
1258
"""
1245
1259
Class for holding multiple `~matplotlib.colors.Colormap` for use in a
1246
1260
`~matplotlib.cm.VectorMappable` object
1247
-
1248
- MultivarColormap does not support alpha in the constituent
1249
- look up tables (ignored).
1250
1261
"""
1251
1262
def __init__ (self , name , colormaps , combination_mode ):
1252
1263
"""
@@ -1258,20 +1269,26 @@ def __init__(self, name, colormaps, combination_mode):
1258
1269
The individual colormaps that are combined
1259
1270
combination_mode: str, 'Add' or 'Sub'
1260
1271
Describe how colormaps are combined in sRGB space
1261
-
1272
+
1262
1273
- If 'Add' -> Mixing produces brighter colors
1263
1274
`sRGB = cmap[0][X[0]] + cmap[1][x[1]] + ... + cmap[n-1][x[n-1]]`
1264
1275
- If 'Sub' -> Mixing produces darker colors
1265
1276
`sRGB = cmap[0][X[0]] + cmap[1][x[1]] + ... + cmap[n-1][x[n-1]] - n + 1`
1266
1277
"""
1267
1278
self .name = name
1268
1279
1269
- if not np .iterable (colormaps ) or len (colormaps ) == 1 :
1280
+ if not np .iterable (colormaps ) \
1281
+ or len (colormaps ) == 1 \
1282
+ or isinstance (colormaps , str ):
1270
1283
raise ValueError ("A MultivarColormap must have more than one colormap." )
1271
- for cmap in colormaps :
1284
+ colormaps = list (colormaps ) # ensure cmaps is a list, i.e. not a tuple
1285
+ for i , cmap in enumerate (colormaps ):
1272
1286
if not issubclass (type (cmap ), Colormap ):
1273
- raise ValueError ("colormaps must be a list of objects that subclass"
1274
- " Colormap, not strings or list of strings" )
1287
+ if isinstance (cmap , str ):
1288
+ colormaps [i ] = mpl .colormaps [cmap ]
1289
+ else :
1290
+ raise ValueError ("colormaps must be a list of objects that subclass"
1291
+ " Colormap or valid strings." )
1275
1292
1276
1293
self .colormaps = colormaps
1277
1294
self .combination_mode = combination_mode
@@ -1309,10 +1326,10 @@ def __call__(self, X, alpha=None, bytes=False):
1309
1326
raise ValueError (
1310
1327
f'For the selected colormap the data must have a first dimension '
1311
1328
f'{ len (self )} , not { len (X )} ' )
1312
- rgba , mask_bad = self [0 ](X [0 ], bytes = False , return_mask_bad = True )
1329
+ rgba , mask_bad = self [0 ]. _get_rgba_and_mask (X [0 ], bytes = False )
1313
1330
rgba = np .asarray (rgba )
1314
1331
for c , xx in zip (self [1 :], X [1 :]):
1315
- sub_rgba , sub_mask_bad = c (xx , bytes = False , return_mask_bad = True )
1332
+ sub_rgba , sub_mask_bad = c . _get_rgba_and_mask (xx , bytes = False )
1316
1333
sub_rgba = np .asarray (sub_rgba )
1317
1334
rgba [..., :3 ] += sub_rgba [..., :3 ] # add colors
1318
1335
rgba [..., 3 ] *= sub_rgba [..., 3 ] # multiply alpha
@@ -1400,16 +1417,30 @@ def combination_mode(self, mode):
1400
1417
self ._combination_mode = mode
1401
1418
1402
1419
def _repr_png_ (self ):
1403
- raise NotImplementedError ("no png representation of MultivarColormap"
1404
- " but you may access png repreesntations of the"
1405
- " individual colorbars." )
1420
+ """Generate a PNG representation of the Colormap."""
1421
+ X = np .tile (np .linspace (0 , 1 , _REPR_PNG_SIZE [0 ]),
1422
+ (_REPR_PNG_SIZE [1 ], 1 ))
1423
+ pixels = np .zeros ((_REPR_PNG_SIZE [1 ]* len (self ), _REPR_PNG_SIZE [0 ], 4 ),
1424
+ dtype = np .uint8 )
1425
+ for i , c in enumerate (self ):
1426
+ pixels [i * _REPR_PNG_SIZE [1 ]:(i + 1 )* _REPR_PNG_SIZE [1 ], :] = c (X , bytes = True )
1427
+ png_bytes = io .BytesIO ()
1428
+ title = self .name + ' multivariate colormap'
1429
+ author = f'Matplotlib v{ mpl .__version__ } , https://matplotlib.org'
1430
+ pnginfo = PngInfo ()
1431
+ pnginfo .add_text ('Title' , title )
1432
+ pnginfo .add_text ('Description' , title )
1433
+ pnginfo .add_text ('Author' , author )
1434
+ pnginfo .add_text ('Software' , author )
1435
+ Image .fromarray (pixels ).save (png_bytes , format = 'png' , pnginfo = pnginfo )
1436
+ return png_bytes .getvalue ()
1406
1437
1407
1438
def _repr_html_ (self ):
1408
1439
"""Generate an HTML representation of the MultivarColormap."""
1409
1440
return '' .join ([c ._repr_html_ () for c in self .colormaps ])
1410
1441
1411
1442
1412
- class BivarColormap ( ColormapBase ) :
1443
+ class BivarColormap :
1413
1444
"""
1414
1445
Baseclass for all bivarate to RGBA mappings.
1415
1446
0 commit comments