Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/users/next_whats_new/colormap_get_under_over_bad.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Get under/over/bad colors of Colormap objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

`matplotlib.colors.Colormap` now has methods
`~.colors.Colormap.get_under`, `~.colors.Colormap.get_over`,
`~.colors.Colormap.get_bad` for the colors used for out-of-range and masked
values.
59 changes: 53 additions & 6 deletions lib/matplotlib/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,25 +614,47 @@ def __copy__(self):
cmapobject._global = False
return cmapobject

def get_bad(self):
"""Get the color for masked values."""
if not self._isinit:
self._init()
return self._lut[self._i_bad]

def set_bad(self, color='k', alpha=None):
"""Set the color for masked values."""
_warn_if_global_cmap_modified(self)
self._rgba_bad = to_rgba(color, alpha)
if self._isinit:
self._set_extremes()

def get_under(self):
"""
Get the color for low out-of-range values.
"""
Comment thread
bdice marked this conversation as resolved.
Outdated
if not self._isinit:
self._init()
return self._lut[self._i_under]

def set_under(self, color='k', alpha=None):
"""
Set the color for low out-of-range values when ``norm.clip = False``.
Set the color for low out-of-range values.
Comment thread
bdice marked this conversation as resolved.
Outdated
"""
_warn_if_global_cmap_modified(self)
self._rgba_under = to_rgba(color, alpha)
if self._isinit:
self._set_extremes()

def get_over(self):
"""
Get the color for high out-of-range values.
"""
Comment thread
bdice marked this conversation as resolved.
Outdated
if not self._isinit:
self._init()
return self._lut[self._i_over]

def set_over(self, color='k', alpha=None):
"""
Set the color for high out-of-range values when ``norm.clip = False``.
Set the color for high out-of-range values.
Comment thread
bdice marked this conversation as resolved.
Outdated
"""
_warn_if_global_cmap_modified(self)
self._rgba_over = to_rgba(color, alpha)
Expand All @@ -655,6 +677,7 @@ def _init(self):
raise NotImplementedError("Abstract class only")

def is_gray(self):
"""Return whether the color map is grayscale."""
if not self._isinit:
self._init()
return (np.all(self._lut[:, 0] == self._lut[:, 1]) and
Expand Down Expand Up @@ -703,12 +726,36 @@ def _repr_html_(self):
"""Generate an HTML representation of the Colormap."""
png_bytes = self._repr_png_()
png_base64 = base64.b64encode(png_bytes).decode('ascii')
return ('<strong>' + self.name + '</strong>' +
'<img ' +
def color_block(color):
hex_color = to_hex(color, keep_alpha=True)
return ('<div title="' + hex_color + '" ' +
'style="display: inline-block; ' +
'width: 1em; height: 1em; ' +
'margin: 0; ' +
'vertical-align: middle; ' +
'border: 1px solid #555; ' +
'background-color: ' + hex_color + ';">' +
'</div>')
Comment thread
bdice marked this conversation as resolved.
Outdated

return ('<div style="vertical-align: middle;">' +
Comment thread
bdice marked this conversation as resolved.
Outdated
'<strong>' + self.name + '</strong> ' +
'</div>' +
'<div class="cmap"><img ' +
'alt="' + self.name + ' color map" ' +
'title="' + self.name + '"' +
'title="' + self.name + '" ' +
'style="border: 1px solid #555;" ' +
'src="data:image/png;base64,' + png_base64 + '">')
'src="data:image/png;base64,' + png_base64 + '"></div>' +
'<div style="vertical-align: middle; max-width: 402px; ' +
Comment thread
bdice marked this conversation as resolved.
Outdated
'display: flex; justify-content: space-between;">' +
'<div style="float: left;">' +
color_block(self.get_under()) + ' under' +
'</div>' +
'<div style="margin: 0 auto; display: inline-block;">' +
'bad ' + color_block(self.get_bad()) +
'</div>' +
'<div style="float: right;">' +
'over ' + color_block(self.get_over()) +
'</div>')


class LinearSegmentedColormap(Colormap):
Expand Down
14 changes: 14 additions & 0 deletions lib/matplotlib/tests/test_colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ def test_BoundaryNorm():
cmref.set_under('white')
cmshould = mcolors.ListedColormap(['white', 'blue', 'red', 'black'])

assert mcolors.same_color(cmref.get_over(), 'black')
assert mcolors.same_color(cmref.get_under(), 'white')

refnorm = mcolors.BoundaryNorm(bounds, cmref.N)
mynorm = mcolors.BoundaryNorm(bounds, cmshould.N, extend='both')
assert mynorm.vmin == refnorm.vmin
Expand All @@ -323,6 +326,8 @@ def test_BoundaryNorm():
cmref.set_under('white')
cmshould = mcolors.ListedColormap(['white', 'blue', 'red'])

assert mcolors.same_color(cmref.get_under(), 'white')

assert cmref.N == 2
assert cmshould.N == 3
refnorm = mcolors.BoundaryNorm(bounds, cmref.N)
Expand All @@ -339,6 +344,8 @@ def test_BoundaryNorm():
cmref.set_over('black')
cmshould = mcolors.ListedColormap(['blue', 'red', 'black'])

assert mcolors.same_color(cmref.get_over(), 'black')

assert cmref.N == 2
assert cmshould.N == 3
refnorm = mcolors.BoundaryNorm(bounds, cmref.N)
Expand Down Expand Up @@ -1161,3 +1168,10 @@ def test_repr_html():
html = cmap._repr_html_()
assert len(html) > 0
assert cmap.name in html


def test_get_under_over_bad():
cmap = plt.get_cmap('viridis')
assert_array_equal(cmap.get_under(), cmap(-np.inf))
assert_array_equal(cmap.get_over(), cmap(np.inf))
assert_array_equal(cmap.get_bad(), cmap(np.nan))