From ea42661f6ddae04db68caacd721eb8a83dadeb1c Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Sat, 31 Dec 2016 10:54:17 -0700 Subject: [PATCH 01/17] NF - Add 'truncate' and 'join' methods to colormaps. This is based largely on https://gist.github.com/denis-bz/8052855 Which was based on http://stackoverflow.com/a/18926541/2121597 --- lib/matplotlib/colors.py | 188 +++++++++++++++++- .../test_colorbar/colorbar_join_listed.png | Bin 0 -> 1935 bytes .../colorbar_join_listed_frac.png | Bin 0 -> 1914 bytes .../test_colorbar/colorbar_join_lsc.png | Bin 0 -> 1910 bytes .../test_colorbar/colorbar_join_lsc_frac.png | Bin 0 -> 1881 bytes .../colorbar_truncate_listed.png | Bin 0 -> 1875 bytes .../test_colorbar/colorbar_truncate_lsc.png | Bin 0 -> 1817 bytes lib/matplotlib/tests/test_colorbar.py | 67 +++++++ 8 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_listed.png create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_listed_frac.png create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_lsc.png create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_lsc_frac.png create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate_listed.png create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate_lsc.png diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 80294ec8b2ff..ef1b99593897 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -763,6 +763,99 @@ def func_r(x): return LinearSegmentedColormap(name, data_r, self.N, self._gamma) + def join(self, other, name=None, frac_self=None, N=None): + """ + Join colormap `self` to `other` and return the new colormap. + + Parameters + ---------- + other : cmap + The other colormap to be joined to this one. + name : str, optional + The name for the reversed colormap. If it's None the + name will be ``self.name + '-' + other.name``. + frac_self : float in the interval ``(0.0, 1.0)``, optional + The fraction of the new colormap that should be occupied + by self. By default, this is ``self.N / (self.N + + other.N)``. + + Returns + ------- + LinearSegmentedColormap + The joined colormap. + + Examples + -------- + import matplotlib.pyplat as plt + cmap1 = plt.get_cmap('jet') + cmap2 = plt.get_cmap('plasma_r') + + joined_cmap = cmap1.join(cmap2) + """ + if N is None: + N = self.N + other.N + if frac_self is None: + frac_self = self.N / (other.N + self.N) + if name is None: + name = '{}+{}'.format(self.name, other.name) + assert 0 < frac_self and frac_self < 1, ( + "The parameter ``frac_self`` must be in the interval ``(0.0, 1.0)``." + ) + map0 = self(np.linspace(0, 1, int(N * frac_self))) + map1 = other(np.linspace(0, 1, int(N * (1 - frac_self)))) + # N is set by len of the vstack'd array: + return LinearSegmentedColormap.from_list(name, np.vstack((map0, map1))) + + def truncate(self, minval=0.0, maxval=1.0, N=None): + """ + Truncate a colormap. + + Parameters + ---------- + minval : float in the interval ``(0.0, 1.0)``, optional + The lower fraction of the colormap you want to truncate + (default 0.0). + + maxval : float in the interval ``(0.0, 1.0)``, optional + The upper limit of the colormap you want to keep. i.e. truncate + the section above this value (default 1.0). + + N : int + The number of entries in the map. The default is *None*, + in which case the same color-step density is preserved, + i.e.: N = ceil(N * (maxval - minval)) + + Returns + ------- + LinearSegmentedColormap + The truncated colormap. + + Examples + -------- + import matplotlib.pyplat as plt + cmap = plt.get_cmap('jet') + + # This will return the `jet` colormap with the bottom 20%, + # and top 30% removed: + cmap_trunc = cmap.truncate(0.2, 0.7) + + """ + assert minval < maxval, "``minval`` must be less than ``maxval``" + assert 0 <= minval and minval < 1, ( + "The parameter ``minval`` must be in the interval ``(0.0, 1.0)``.") + assert 0 < maxval and maxval <= 1, ( + "The parameter ``maxval`` must be in the interval ``(0.0, 1.0)``.") + assert minval != 0 or maxval != 1, ( + "This is not a truncation.") + # This was taken largely from + # https://gist.github.com/denis-bz/8052855 + # Which, in turn was from @unutbu's SO answer: + # http://stackoverflow.com/a/18926541/2121597 + if N is None: + N = np.ceil(self.N * (maxval - minval)) + name = "trunc({},{:.2f},{:.2f})".format(self.name, minval, maxval) + return LinearSegmentedColormap.from_list(name, self(np.linspace(minval, maxval, N)), N) + class ListedColormap(Colormap): """Colormap object generated from a list of colors. @@ -853,6 +946,99 @@ def reversed(self, name=None): colors_r = list(reversed(self.colors)) return ListedColormap(colors_r, name=name, N=self.N) + def join(self, other, name=None, frac_self=None, N=None): + """ + Join colormap `self` to `other` and return the new colormap. + + Parameters + ---------- + other : cmap + The other colormap to be joined to this one. + name : str, optional + The name for the reversed colormap. If it's None the + name will be ``self.name + '-' + other.name``. + frac_self : float in the interval ``(0.0, 1.0)``, optional + The fraction of the new colormap that should be occupied + by self. By default, this is ``self.N / (self.N + + other.N)``. + + Returns + ------- + ListedColormap + The joined colormap. + + Examples + -------- + import matplotlib.pyplat as plt + cmap1 = plt.get_cmap('viridis') + cmap2 = plt.get_cmap('plasma_r') + + joined_cmap = cmap1.join(cmap2) + """ + if N is None: + N = self.N + other.N + if frac_self is None: + frac_self = self.N / (other.N + self.N) + if name is None: + name = '{}+{}'.format(self.name, other.name) + assert 0 < frac_self and frac_self < 1, ( + "The parameter ``frac_self`` must be in the interval ``(0.0, 1.0)``." + ) + map0 = self(np.linspace(0, 1, int(N * frac_self))) + map1 = other(np.linspace(0, 1, int(N * (1 - frac_self)))) + # N is set by len of the vstack'd array: + return ListedColormap(np.vstack((map0, map1)), name, ) + + def truncate(self, minval=0.0, maxval=1.0, N=None): + """ + Truncate a colormap. + + Parameters + ---------- + minval : float in the interval ``(0.0, 1.0)``, optional + The lower fraction of the colormap you want to truncate + (default 0.0). + + maxval : float in the interval ``(0.0, 1.0)``, optional + The upper limit of the colormap you want to keep. i.e. truncate + the section above this value (default 1.0). + + N : int + The number of entries in the map. The default is *None*, + in which case the same color-step density is preserved, + i.e.: N = ceil(N * (maxval - minval)) + + Returns + ------- + ListedColormap + The truncated colormap. + + Examples + -------- + import matplotlib.pyplat as plt + cmap = plt.get_cmap('viridis') + + # This will return the `viridis` colormap with the bottom 20%, + # and top 30% removed: + cmap_trunc = cmap.truncate(0.2, 0.7) + + """ + assert minval < maxval, "``minval`` must be less than ``maxval``" + assert 0 <= minval and minval < 1, ( + "The parameter ``minval`` must be in the interval ``(0.0, 1.0)``.") + assert 0 < maxval and maxval <= 1, ( + "The parameter ``maxval`` must be in the interval ``(0.0, 1.0)``.") + assert minval != 0 or maxval != 1, ( + "This is not a truncation.") + # This was taken largely from + # https://gist.github.com/denis-bz/8052855 + # Which, in turn was from @unutbu's SO answer: + # http://stackoverflow.com/a/18926541/2121597 + if N is None: + N = np.ceil(self.N * (maxval - minval)) + name = "trunc({},{:.2f},{:.2f})".format(self.name, minval, maxval) + return ListedColormap(self(np.linspace(minval, maxval, N)), name) + class Normalize(object): """ @@ -1062,7 +1248,7 @@ class SymLogNorm(Normalize): *linthresh* allows the user to specify the size of this range (-*linthresh*, *linthresh*). """ - def __init__(self, linthresh, linscale=1.0, + def __init__(self, linthresh, linscale=1.0, vmin=None, vmax=None, clip=False): """ *linthresh*: diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_listed.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_listed.png new file mode 100644 index 0000000000000000000000000000000000000000..5c39886c7e4abfe747ab6cc5cdc06325da8a4982 GIT binary patch literal 1935 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 HPhb2G99SEj literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_lsc_frac.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_lsc_frac.png new file mode 100644 index 0000000000000000000000000000000000000000..6615c45e7388b13107edfb1d5156c0cd32a0eace GIT binary patch literal 1881 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 f3Xhr5+6VWaW85|#(-k>cb{h~878%M5rXKwp Date: Sat, 31 Dec 2016 11:37:52 -0700 Subject: [PATCH 02/17] Some pep8 fixes. --- lib/matplotlib/colors.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index ef1b99593897..a246f80b049a 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -232,8 +232,8 @@ def to_rgba_array(c, alpha=None): # Special-case inputs that are already arrays, for performance. (If the # array has the wrong kind or shape, raise the error during one-at-a-time # conversion.) - if (isinstance(c, np.ndarray) and c.dtype.kind in "if" - and c.ndim == 2 and c.shape[1] in [3, 4]): + if (isinstance(c, np.ndarray) and c.dtype.kind in "if" and + c.ndim == 2 and c.shape[1] in [3, 4]): if c.shape[1] == 3: result = np.column_stack([c, np.zeros(len(c))]) result[:, -1] = alpha if alpha is not None else 1. @@ -799,7 +799,7 @@ def join(self, other, name=None, frac_self=None, N=None): if name is None: name = '{}+{}'.format(self.name, other.name) assert 0 < frac_self and frac_self < 1, ( - "The parameter ``frac_self`` must be in the interval ``(0.0, 1.0)``." + "The parameter frac_self must be in the interval (0.0, 1.0)." ) map0 = self(np.linspace(0, 1, int(N * frac_self))) map1 = other(np.linspace(0, 1, int(N * (1 - frac_self)))) @@ -840,11 +840,11 @@ def truncate(self, minval=0.0, maxval=1.0, N=None): cmap_trunc = cmap.truncate(0.2, 0.7) """ - assert minval < maxval, "``minval`` must be less than ``maxval``" + assert minval < maxval, "minval must be less than maxval" assert 0 <= minval and minval < 1, ( - "The parameter ``minval`` must be in the interval ``(0.0, 1.0)``.") + "The parameter minval must be in the interval (0.0, 1.0).") assert 0 < maxval and maxval <= 1, ( - "The parameter ``maxval`` must be in the interval ``(0.0, 1.0)``.") + "The parameter maxval must be in the interval (0.0, 1.0).") assert minval != 0 or maxval != 1, ( "This is not a truncation.") # This was taken largely from @@ -854,7 +854,11 @@ def truncate(self, minval=0.0, maxval=1.0, N=None): if N is None: N = np.ceil(self.N * (maxval - minval)) name = "trunc({},{:.2f},{:.2f})".format(self.name, minval, maxval) - return LinearSegmentedColormap.from_list(name, self(np.linspace(minval, maxval, N)), N) + return LinearSegmentedColormap.from_list(name, + self(np.linspace(minval, + maxval, + N)), + N) class ListedColormap(Colormap): @@ -982,7 +986,7 @@ def join(self, other, name=None, frac_self=None, N=None): if name is None: name = '{}+{}'.format(self.name, other.name) assert 0 < frac_self and frac_self < 1, ( - "The parameter ``frac_self`` must be in the interval ``(0.0, 1.0)``." + "The parameter frac_self must be in the interval (0.0, 1.0)." ) map0 = self(np.linspace(0, 1, int(N * frac_self))) map1 = other(np.linspace(0, 1, int(N * (1 - frac_self)))) @@ -1023,11 +1027,11 @@ def truncate(self, minval=0.0, maxval=1.0, N=None): cmap_trunc = cmap.truncate(0.2, 0.7) """ - assert minval < maxval, "``minval`` must be less than ``maxval``" + assert minval < maxval, "minval must be less than maxval" assert 0 <= minval and minval < 1, ( - "The parameter ``minval`` must be in the interval ``(0.0, 1.0)``.") + "The parameter minval must be in the interval (0.0, 1.0).") assert 0 < maxval and maxval <= 1, ( - "The parameter ``maxval`` must be in the interval ``(0.0, 1.0)``.") + "The parameter maxval must be in the interval (0.0, 1.0).") assert minval != 0 or maxval != 1, ( "This is not a truncation.") # This was taken largely from From 42bdcb0f1d9a6d2dcb6fa10ce162b391ccbb0258 Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Sat, 31 Dec 2016 13:08:04 -0700 Subject: [PATCH 03/17] Update .join docstring to include the parameter. --- lib/matplotlib/colors.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index a246f80b049a..0224cf80fb66 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -778,6 +778,10 @@ def join(self, other, name=None, frac_self=None, N=None): The fraction of the new colormap that should be occupied by self. By default, this is ``self.N / (self.N + other.N)``. + N : int + The number of entries in the color map. The default is ``None``, + in which case the number of entries is the sum of the + number of entries in the two colormaps to be joined. Returns ------- @@ -965,6 +969,10 @@ def join(self, other, name=None, frac_self=None, N=None): The fraction of the new colormap that should be occupied by self. By default, this is ``self.N / (self.N + other.N)``. + N : int + The number of entries in the color map. The default is ``None``, + in which case the number of entries is the sum of the + number of entries in the two colormaps to be joined. Returns ------- From 60ebf946086199a334e13e39bc41e9f63ef07dcf Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Sun, 1 Jan 2017 09:15:50 -0700 Subject: [PATCH 04/17] Move methods to `Colorbar`. Note that these methods now always return `ListedColormap`. Also: switch from `assert` to `raise ValueError`. --- lib/matplotlib/colors.py | 299 ++++++------------ .../test_colorbar/colorbar_join_lsc.png | Bin 1910 -> 2010 bytes .../test_colorbar/colorbar_join_lsc_frac.png | Bin 1881 -> 1968 bytes 3 files changed, 101 insertions(+), 198 deletions(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 0224cf80fb66..35a914c2dd8f 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -614,6 +614,107 @@ def reversed(self, name=None): """ raise NotImplementedError() + def join(self, other, name=None, frac_self=None, N=None): + """ + Join colormap `self` to `other` and return the new colormap. + + Parameters + ---------- + other : cmap + The other colormap to be joined to this one. + name : str, optional + The name for the reversed colormap. If it's None the + name will be ``self.name + '-' + other.name``. + frac_self : float in the interval ``(0.0, 1.0)``, optional + The fraction of the new colormap that should be occupied + by self. By default, this is ``self.N / (self.N + + other.N)``. + N : int + The number of entries in the color map. The default is ``None``, + in which case the number of entries is the sum of the + number of entries in the two colormaps to be joined. + + Returns + ------- + ListedColormap + The joined colormap. + + Examples + -------- + import matplotlib.pyplat as plt + cmap1 = plt.get_cmap('viridis', 128) + cmap2 = plt.get_cmap('plasma_r', 64) + + joined_cmap = cmap1.join(cmap2) + + # Note that `joined_cmap` will be 2/3 `cmap1`, and 1/3 `cmap2` + # because of the default behavior of frac_self + # (i.e. proportional to N of each cmap). + """ + if N is None: + N = self.N + other.N + if frac_self is None: + frac_self = self.N / (other.N + self.N) + if name is None: + name = '{}+{}'.format(self.name, other.name) + if not (0 < frac_self and frac_self < 1): + raise ValueError("frac_self must be in the interval (0.0, 1.0)") + map0 = self(np.linspace(0, 1, int(N * frac_self))) + map1 = other(np.linspace(0, 1, int(N * (1 - frac_self)))) + # N is set by len of the vstack'd array: + return ListedColormap(np.vstack((map0, map1)), name, ) + + def truncate(self, minval=0.0, maxval=1.0, N=None): + """ + Truncate a colormap. + + Parameters + ---------- + minval : float in the interval ``(0.0, 1.0)``, optional + The lower fraction of the colormap you want to truncate + (default 0.0). + + maxval : float in the interval ``(0.0, 1.0)``, optional + The upper limit of the colormap you want to keep. i.e. truncate + the section above this value (default 1.0). + + N : int + The number of entries in the map. The default is *None*, + in which case the same color-step density is preserved, + i.e.: N = ceil(N * (maxval - minval)) + + Returns + ------- + ListedColormap + The truncated colormap. + + Examples + -------- + import matplotlib.pyplat as plt + cmap = plt.get_cmap('viridis') + + # This will return the `viridis` colormap with the bottom 20%, + # and top 30% removed: + cmap_trunc = cmap.truncate(0.2, 0.7) + + """ + if minval >= maxval: + raise ValueError("minval must be less than maxval") + if minval < 0 or minval >= 1 or maxval <= 0 or maxval > 1: + raise ValueError( + "minval and maxval must be in the interval (0.0, 1.0)" + ) + if minval == 0 and maxval == 1: + raise ValueError("This is not a truncation") + # This was taken largely from + # https://gist.github.com/denis-bz/8052855 + # Which, in turn was from @unutbu's SO answer: + # http://stackoverflow.com/a/18926541/2121597 + if N is None: + N = np.ceil(self.N * (maxval - minval)) + name = "trunc({},{:.2f},{:.2f})".format(self.name, minval, maxval) + return ListedColormap(self(np.linspace(minval, maxval, N)), name) + class LinearSegmentedColormap(Colormap): """Colormap objects based on lookup tables using linear segments. @@ -763,107 +864,6 @@ def func_r(x): return LinearSegmentedColormap(name, data_r, self.N, self._gamma) - def join(self, other, name=None, frac_self=None, N=None): - """ - Join colormap `self` to `other` and return the new colormap. - - Parameters - ---------- - other : cmap - The other colormap to be joined to this one. - name : str, optional - The name for the reversed colormap. If it's None the - name will be ``self.name + '-' + other.name``. - frac_self : float in the interval ``(0.0, 1.0)``, optional - The fraction of the new colormap that should be occupied - by self. By default, this is ``self.N / (self.N + - other.N)``. - N : int - The number of entries in the color map. The default is ``None``, - in which case the number of entries is the sum of the - number of entries in the two colormaps to be joined. - - Returns - ------- - LinearSegmentedColormap - The joined colormap. - - Examples - -------- - import matplotlib.pyplat as plt - cmap1 = plt.get_cmap('jet') - cmap2 = plt.get_cmap('plasma_r') - - joined_cmap = cmap1.join(cmap2) - """ - if N is None: - N = self.N + other.N - if frac_self is None: - frac_self = self.N / (other.N + self.N) - if name is None: - name = '{}+{}'.format(self.name, other.name) - assert 0 < frac_self and frac_self < 1, ( - "The parameter frac_self must be in the interval (0.0, 1.0)." - ) - map0 = self(np.linspace(0, 1, int(N * frac_self))) - map1 = other(np.linspace(0, 1, int(N * (1 - frac_self)))) - # N is set by len of the vstack'd array: - return LinearSegmentedColormap.from_list(name, np.vstack((map0, map1))) - - def truncate(self, minval=0.0, maxval=1.0, N=None): - """ - Truncate a colormap. - - Parameters - ---------- - minval : float in the interval ``(0.0, 1.0)``, optional - The lower fraction of the colormap you want to truncate - (default 0.0). - - maxval : float in the interval ``(0.0, 1.0)``, optional - The upper limit of the colormap you want to keep. i.e. truncate - the section above this value (default 1.0). - - N : int - The number of entries in the map. The default is *None*, - in which case the same color-step density is preserved, - i.e.: N = ceil(N * (maxval - minval)) - - Returns - ------- - LinearSegmentedColormap - The truncated colormap. - - Examples - -------- - import matplotlib.pyplat as plt - cmap = plt.get_cmap('jet') - - # This will return the `jet` colormap with the bottom 20%, - # and top 30% removed: - cmap_trunc = cmap.truncate(0.2, 0.7) - - """ - assert minval < maxval, "minval must be less than maxval" - assert 0 <= minval and minval < 1, ( - "The parameter minval must be in the interval (0.0, 1.0).") - assert 0 < maxval and maxval <= 1, ( - "The parameter maxval must be in the interval (0.0, 1.0).") - assert minval != 0 or maxval != 1, ( - "This is not a truncation.") - # This was taken largely from - # https://gist.github.com/denis-bz/8052855 - # Which, in turn was from @unutbu's SO answer: - # http://stackoverflow.com/a/18926541/2121597 - if N is None: - N = np.ceil(self.N * (maxval - minval)) - name = "trunc({},{:.2f},{:.2f})".format(self.name, minval, maxval) - return LinearSegmentedColormap.from_list(name, - self(np.linspace(minval, - maxval, - N)), - N) - class ListedColormap(Colormap): """Colormap object generated from a list of colors. @@ -954,103 +954,6 @@ def reversed(self, name=None): colors_r = list(reversed(self.colors)) return ListedColormap(colors_r, name=name, N=self.N) - def join(self, other, name=None, frac_self=None, N=None): - """ - Join colormap `self` to `other` and return the new colormap. - - Parameters - ---------- - other : cmap - The other colormap to be joined to this one. - name : str, optional - The name for the reversed colormap. If it's None the - name will be ``self.name + '-' + other.name``. - frac_self : float in the interval ``(0.0, 1.0)``, optional - The fraction of the new colormap that should be occupied - by self. By default, this is ``self.N / (self.N + - other.N)``. - N : int - The number of entries in the color map. The default is ``None``, - in which case the number of entries is the sum of the - number of entries in the two colormaps to be joined. - - Returns - ------- - ListedColormap - The joined colormap. - - Examples - -------- - import matplotlib.pyplat as plt - cmap1 = plt.get_cmap('viridis') - cmap2 = plt.get_cmap('plasma_r') - - joined_cmap = cmap1.join(cmap2) - """ - if N is None: - N = self.N + other.N - if frac_self is None: - frac_self = self.N / (other.N + self.N) - if name is None: - name = '{}+{}'.format(self.name, other.name) - assert 0 < frac_self and frac_self < 1, ( - "The parameter frac_self must be in the interval (0.0, 1.0)." - ) - map0 = self(np.linspace(0, 1, int(N * frac_self))) - map1 = other(np.linspace(0, 1, int(N * (1 - frac_self)))) - # N is set by len of the vstack'd array: - return ListedColormap(np.vstack((map0, map1)), name, ) - - def truncate(self, minval=0.0, maxval=1.0, N=None): - """ - Truncate a colormap. - - Parameters - ---------- - minval : float in the interval ``(0.0, 1.0)``, optional - The lower fraction of the colormap you want to truncate - (default 0.0). - - maxval : float in the interval ``(0.0, 1.0)``, optional - The upper limit of the colormap you want to keep. i.e. truncate - the section above this value (default 1.0). - - N : int - The number of entries in the map. The default is *None*, - in which case the same color-step density is preserved, - i.e.: N = ceil(N * (maxval - minval)) - - Returns - ------- - ListedColormap - The truncated colormap. - - Examples - -------- - import matplotlib.pyplat as plt - cmap = plt.get_cmap('viridis') - - # This will return the `viridis` colormap with the bottom 20%, - # and top 30% removed: - cmap_trunc = cmap.truncate(0.2, 0.7) - - """ - assert minval < maxval, "minval must be less than maxval" - assert 0 <= minval and minval < 1, ( - "The parameter minval must be in the interval (0.0, 1.0).") - assert 0 < maxval and maxval <= 1, ( - "The parameter maxval must be in the interval (0.0, 1.0).") - assert minval != 0 or maxval != 1, ( - "This is not a truncation.") - # This was taken largely from - # https://gist.github.com/denis-bz/8052855 - # Which, in turn was from @unutbu's SO answer: - # http://stackoverflow.com/a/18926541/2121597 - if N is None: - N = np.ceil(self.N * (maxval - minval)) - name = "trunc({},{:.2f},{:.2f})".format(self.name, minval, maxval) - return ListedColormap(self(np.linspace(minval, maxval, N)), name) - class Normalize(object): """ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_lsc.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_lsc.png index 281f15eca42205ed1de1b810e4cc16a17564894a..3e0d02fd7c9f290485cc481c328447850291d9b5 100644 GIT binary patch delta 1433 zcmY+DeKgYx7{`Cvm`X;Sa?pm{IH%kVSB%7NL*#}+Xtt5OzYH6)jqTp9RIaEUc}uSA zQs%u9+x4=%v?Q){XBV-&&1=NQOxZ4-&bjwK=RAKs&-Z)2=X0KCU40mu?Mw$e$&S8c zPhto;DKI`5hz=yjMiI$T;g|IjgX2lz#29^Zgek%_KFAyqOC*uaQ7CJ~mEc6virL+=WgJVV7zg{z?D^%IJKi* z6<$*pTn_~z{F^jz6<$`3pb4kCny5cqE!!EDcM(rw?}R*z;b=ZiWEOesQNEdRx69As zNSRuR_Vwnzr{5ur>Yv^g-=i+cgyIyqs`XSKTOrKvmc=gR@0Iq8M52&gU>jQr0AMtk z&y|dsT#)W|tI$1g0&hVACd-U;<~lsU7$@K(@mnz|lU>Y~>Nw)sTNcYEfg>b#nGD96 zMAy9K>F|7734$8jh``RCKDp4a9vd{md+>VW8c|V$z;PshiF-53LB8GzB6iy5+Q8nH zQwm-q{GvCXggm?)o#|IS={xNIFzduv+iGvh@)M(Ny?`{gbsVaWdP9q_VKBRYmmX)d zy4U&D>}-Z!hn5@T)Q+8q2D(#_H%7B=6bdQCe#&kHSpstlRA~SW|0c=HJv++U> zsnHFF{ab8jMX(>8bm010=y6N`JY4I^>syR0&K<*l2rnqwjZFD!uD9>xOXuyCWOJ{p zm7QAZr-3u4X~{Yj(u2y`4~<&IQY?piYmlV=NS(s-kAuX;aj~+FQ;Pqx8yWU-p9* zMbnwO4Np@`jnWh4oMOc1KugfB(l<0ftGJ@TWKo_#$5Njt0-qT)zaFRv3WXC#VdO8U zt96exdr$O8X!6GtsE@AU5eDf8+EA8QcbPxkAbplng%xgoI*ZF2cj!2PHdgQaHa%{r zC%W8hKU#FF5?}5D1ZH(6(ZCuaZtf)2Y!Qzm6wnQs46rBNUslD!>QeTEVH!oWymCVf zw63sl#(1r7AZdPaN}?s-Y9P_!A^HIp1`UIRvdcFPNCd!!ci!8e%yrB$b&gVZf>SiL!^T0^tX403WH+!~E{<*vHKzl9`UjrT&%^)# delta 1327 zcmV+~1=J;FF*Eti=ycOR#mNjex=U;{ENLk|N8rzRaJHN`7^z( zF|TzTOPlNTvBuilFC2THoh9wvL(iqPx3^9>(PC;kfRo9j_bY(DPq2Be<5=2UXI{s` z@wo?+0R|nDum=>A5Cs^2H6OsOyF35;UR6l9{{E)(VTPIyAV6Q5{$lj1s=wcPvHo%M zeAUg9?f;|K-kI${FrbHDvc5L(9AnXZ03X+H-+67YwZ#|OHu?Y#X{h)LFC2{kj*zQf zI2r+Dro?wKrM|N)fQ*Lt9_+@g7i#TO{*HETuUA#ockBK<{66sV zxwCs4A7s71>~oW#2PBga1tpVU0SbSt<^#C9wN*Q}*M}Yhny_OG6KEn5Vmc z*Yp3nS7%NwA9F{NbNHO>;2erEkmU&hBk|ur}-< zBhh>S7s*iJtrA~22>~1l@#S%(-d7Yr9-H_shSi(fHMzI{zt!gbdwUzN9{nU<`xpoy z3(fuB*?4rH{obH+%$oqh3ApMVhvq*A2z=a-@f{nJPyry5-~}*$tmXr_^Pl^*dH>GP zV?Yx&@85Ag%+S)%103enx>1*=H)`_Wke_?<7xNhi7>(uwxcXGpWaaRm`_qG8_CL%% zgqL|bbLyFow(bo&$5=EUz}5{F-YW5Bb{@T~ULJIgc@w||CcYfUcc$;vl?U(b`&c*K z`~7NNnBzpl6F^QW#4U$$Im&IOF%m!)imP5`NdV!9#CLoI5Ej5E<9jjeUR__B{~$C# zUz33cLz55%3V&Af0o>TF>b8fT0@~1RJ0E6gY3KnC^SAR~s^4AuTAiJ&e(cYG`jy`d zG!ZZs%?I%G>dODcud3>;zy5fDY4(UOLz%4f^Sr57mCXmRMdHgMy8gyX_12Yd?EBby zx3RZzb&dlyKmZqv_|k`mud+TIc#e4!K#pvv_zEw55gtIA=c<>!2p}9le8)`yp-~6M z_u~BK7_;U-2o2B|lTZO5li&p{f7N^dw>GwGz1tXi3~0i7x8Z!4p{1b*IL!4we!Z^$ z`Me{j32s;UdGUp?Vui>dtpHbQ(EwT~_`(g@%J7%INP%h(AZCZEbxFJmWw zG)a7!2LXgn5Z@dE2n{)Ed@p?KV$YLgX#RuH0DTdY0Ru{Z=>T?JSGBv*?;_jX-mkvR zV;#rR<~s8_7LKj`FGkXn!8)^pFjS*xq7LyrT4 z+t}E9MRe=d@n0ET`oZbi+PZk)^PWEa?8%2)Ku=7k)9KJd01Tn&dw>9a5V>IGA=MK zFmhuuE^u#ibTT+NIWA;nb}%bvF*svmGBRZ>AZT=Sa5^t9ZDDk9Y;SaIX<{yKa%V63 zIrN|a00#3(L_t(|obBDui(Pje$Kg-Rm>O#05Q?SPBrYz9sa+Io5kz-lP{CE!YFGXN zDYzMMCD~?~bqRJGYFGUSy6B=UMH3euXp*ihWE?vQGnwghTuh?WOy^hbx#xS&`*|SD zW$v8&{hTo8#kpq=++*9@+uH>Y=xaj{05BAh;VzSa1si|WbzOB`H}n`Yw=nbod+EBa zF8=l>_3g>&-qu)O-K?srZ=CviZ)?nI9sAPeI(@A1od+-1jT<)(warg||GoNreQVd} z9?$semwr=Mu3UNQ`Q}B_0j#Pz{rt)L`5#{H?e&-M-mj{vGv~h9+ZwZ4$G)_=P9JNm zz46^cZ}TSk`qsY3(%KtqN1SLrH66goWYYT?K;H-0EZ4CwZLTw`ec|w21CxORNq?FT z;QH$3e?M0h(k}$y{hWp@4iqU-~MrZe8lZvz5chU&I3bw{2}XW z1J5xQ%?I#lz5lx(47RrTLfb|kz#$D4U*Uy=5x^00)(ZzCfJ~M6&ZozJSw1=N9J3~X zjE4B`?Vs;FSMUFI_y3~@50|T|>K;eGn&m{p6F``PS;zOn&!&4X;Iq%1dGsjj9z*v5 zlYa#+lh6Srf0_^A=GJ;Wc(^?D7|?_V50@PeQ?xMj0Q>pH7a!Hq=0`O-cJOU}dE$@# z4Frrv^8s8uUNt#!xNY9q_)|Z_>_d3z+q2J{dGzT1pmU5x^8uVELxs0WeBmera3sW+ zr}4k*iido=HRlA7rzXDh;nElH)zyvnc73kf-1&N~A}-HxqTvZ3bItYM={W3l_OTE^ zI09$AT$dS0@FfIqV%rr(H0?1r(*2^>r zARLhRj*kGs9C#wWuMacF*ff75G(caIfdwp+&;cQTR`UT|UD>L;-Nw*kKojnE8;*x5 zS{QnO{k;9JOZE0YmZ~-;U;6$B7cLAm5il0b2e3{rR-K)R~W zu`g||Gpl{!u;$={(eKyJFVESb2Z09k71GQ=HyyyqWKtI|9*57`coNPh7m9mnC%wAW}7h8fz%rVt7fuAp{PUAYlA zmULYyQeE^P(17mD%1w6KRVfJKwp40%LW{0M*QG+Si%U~NK`2R?VMr!3oym2PR;iiJ zuiSIb_n!Cjz>wkIob&yhkn`fqnFDueI-O1nAkZUy4*<{?0h0m)NPjh%OlmTj^gYJh zjrtzoAd|_YzW(aoi5h+_Rcrz+O=!P+UA*; zpRK*^y?x*Ne8!iaeX*`yz53AeEsCZCSXFiU+}Zl>>(&XkfBcQR zGo1(e@fBV;8UY+2SG{mF0?15>?_&D=H_PX1 zx#vmdO8^-R@jckxKR;Tx{;~hR(VgAT=6`9912q*u0AU8^9pCdW&USxiMys>k;ezlS zlQ04+lRyF+lRyFuf2;WbetK`a?(DAjJq9%4&hEPNVTMM14{(@EtMAv9i|^O?>@l`^ z?`Pc&1Pn&=0bKn`9V>oSRc}A@YB$3iLU`%gnbB(BBMeIO0bC?~g||w4;UolbAjFr4 z@xS|u=X#xE-UN_`CccZ|g~#8mSHAh~zVA(L-~aQq`o$b4AL^d~ve4Y`osHw(XCDdy zgcESpI}FV~2MByopYa_UlK}%tlRyFnf2`&Mxc+I?U)60+`6<< z?_GJKHpiz9{CnSd{$F#N2pEdy1Gv2UXgz&M{Hm(ndFxwqnC3yk%RG(G_C3L{G#|j$ z^%dSK@nv>Wf2Vyw zoxaC_Cfu0pI3H$c)b{{~dHe3A`uiuBYjkt%3$MTR#1DI#2pEdy1Ng|wN{ueAJ@EST zH~-qhH1~-weR+C(s+0YuUR5?9z!r%wi|E?ckLoWsf4%Q}yPsUIs;ZakPjj58e*(B* z#FsAY_fu8^0p!T~imxQ_(iH)ud9HftiU7g^#CO;P5E^w*e1BTMnd2nG)%=6d09_H2 z9|Am+Kmrke%?I$_#zyUaaJ}y_pb5JlTz5Xq(5UYL4zvAw)%G8!RZG+Q`oEX@9tQ>~ zHLA@Au$ES;me#7O>f@)Ty^SHhv|w~`?Zn$|{jO^3_g``jO+S16@`-o9klGJmBgB_M zTRM4I7nuMqfWG1@ybPTH@}*q$GIRn+lf;*K5J319KjNE10HGmAj_=RAog+o_4?+WU zMUw#pJd+Ls4S%er12~yXs-_#=E;7A-|Ep{BSjVxnxz4 zb@JgB(9(1|o%THhKp&dE2MEw50R& Date: Sun, 1 Jan 2017 09:20:36 -0700 Subject: [PATCH 05/17] Add the __add__ method, and doc. --- lib/matplotlib/colors.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 35a914c2dd8f..e0f6bae27d7a 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -650,6 +650,11 @@ def join(self, other, name=None, frac_self=None, N=None): # Note that `joined_cmap` will be 2/3 `cmap1`, and 1/3 `cmap2` # because of the default behavior of frac_self # (i.e. proportional to N of each cmap). + + # This is also available as :meth:`Colormap.__add__`, so that + # the following is possible: + + joined_cmap = cmap1 + cmap2 """ if N is None: N = self.N + other.N @@ -664,6 +669,8 @@ def join(self, other, name=None, frac_self=None, N=None): # N is set by len of the vstack'd array: return ListedColormap(np.vstack((map0, map1)), name, ) + __add__ = join + def truncate(self, minval=0.0, maxval=1.0, N=None): """ Truncate a colormap. From 81ddd1cd93f2bccbf4cb6d2308f4d93a651404d7 Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Sun, 1 Jan 2017 09:31:33 -0700 Subject: [PATCH 06/17] Add a `name` parameter to `truncate` reorder `join` inputs (for consistency) +doc fixes/changes --- lib/matplotlib/colors.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index e0f6bae27d7a..1daa790807bb 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -614,7 +614,7 @@ def reversed(self, name=None): """ raise NotImplementedError() - def join(self, other, name=None, frac_self=None, N=None): + def join(self, other, frac_self=None, name=None, N=None): """ Join colormap `self` to `other` and return the new colormap. @@ -622,13 +622,13 @@ def join(self, other, name=None, frac_self=None, N=None): ---------- other : cmap The other colormap to be joined to this one. - name : str, optional - The name for the reversed colormap. If it's None the - name will be ``self.name + '-' + other.name``. frac_self : float in the interval ``(0.0, 1.0)``, optional The fraction of the new colormap that should be occupied by self. By default, this is ``self.N / (self.N + other.N)``. + name : str, optional + The name for the joined colormap. This defaults to + ``self.name + '+' + other.name`` N : int The number of entries in the color map. The default is ``None``, in which case the number of entries is the sum of the @@ -671,7 +671,7 @@ def join(self, other, name=None, frac_self=None, N=None): __add__ = join - def truncate(self, minval=0.0, maxval=1.0, N=None): + def truncate(self, minval=0.0, maxval=1.0, name=None, N=None): """ Truncate a colormap. @@ -680,11 +680,12 @@ def truncate(self, minval=0.0, maxval=1.0, N=None): minval : float in the interval ``(0.0, 1.0)``, optional The lower fraction of the colormap you want to truncate (default 0.0). - maxval : float in the interval ``(0.0, 1.0)``, optional The upper limit of the colormap you want to keep. i.e. truncate the section above this value (default 1.0). - + name : str, optional + The name for the new truncated colormap. This defaults to + ``"trunc({},{:.2f},{:.2f})".format(self.name, minval, maxval)`` N : int The number of entries in the map. The default is *None*, in which case the same color-step density is preserved, @@ -719,7 +720,8 @@ def truncate(self, minval=0.0, maxval=1.0, N=None): # http://stackoverflow.com/a/18926541/2121597 if N is None: N = np.ceil(self.N * (maxval - minval)) - name = "trunc({},{:.2f},{:.2f})".format(self.name, minval, maxval) + if name is None: + name = "trunc({},{:.2f},{:.2f})".format(self.name, minval, maxval) return ListedColormap(self(np.linspace(minval, maxval, N)), name) From 71742d754c1f70d7dca43952ad769181aeed60da Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Sun, 1 Jan 2017 10:13:45 -0700 Subject: [PATCH 07/17] Refactor onto a 'join_colormaps' function --- lib/matplotlib/colors.py | 66 ++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 1daa790807bb..e9099b097f14 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -83,6 +83,60 @@ def __delitem__(self, key): _colors_full_map = _ColorMapping(_colors_full_map) +def join_colormaps(cmaps, fractions=None, name=None, N=None): + """ + Join a series of colormaps into one. + + Parameters + ---------- + cmaps : a sequence of colormaps to be joined (length M) + fractions : a sequence of floats or ints (length M) + The fraction of the new colormap that each colormap should + occupy. These are normalized so they sum to 1. By default, the + fractions are the ``N`` attribute of each cmap. + name : str, optional + The name for the joined colormap. This defaults to + ``cmap[0].name + '+' + cmap[1].name + '+' ...`` + N : int + The number of entries in the color map. This defaults to the + sum of the ``N`` attributes of the cmaps. + + Returns + ------- + ListedColormap + The joined colormap. + + Examples + -------- + import matplotlib.pyplat as plt + cmap1 = plt.get_cmap('viridis', 128) + cmap2 = plt.get_cmap('plasma_r', 64) + cmap3 = plt.get_cmap('jet', 64) + + joined_cmap = join_colormaps((cmap1, cmap2, cmap3)) + + See Also + -------- + + :meth:`Colorbar.join` and :meth:`Colorbar.__add__` : a method + implementation of this functionality + """ + if N is None: + N = np.sum([cm.N for cm in cmaps]) + if fractions is None: + fractions = [cm.N for cm in cmaps] + fractions = np.array(fractions) / np.sum(fractions, dtype='float') + if name is None: + name = "" + for cm in cmaps: + name += cm.name + '+' + name.rstrip('+') + maps = [cm(np.linspace(0, 1, int(N * frac))) + for cm, frac in zip(cmaps, fractions)] + # N is set by len of the vstack'd array: + return ListedColormap(np.vstack(maps), name, ) + + def get_named_colors_mapping(): """Return the global mapping of names to named colors.""" return _colors_full_map @@ -656,18 +710,10 @@ def join(self, other, frac_self=None, name=None, N=None): joined_cmap = cmap1 + cmap2 """ - if N is None: - N = self.N + other.N if frac_self is None: frac_self = self.N / (other.N + self.N) - if name is None: - name = '{}+{}'.format(self.name, other.name) - if not (0 < frac_self and frac_self < 1): - raise ValueError("frac_self must be in the interval (0.0, 1.0)") - map0 = self(np.linspace(0, 1, int(N * frac_self))) - map1 = other(np.linspace(0, 1, int(N * (1 - frac_self)))) - # N is set by len of the vstack'd array: - return ListedColormap(np.vstack((map0, map1)), name, ) + fractions = [frac_self, 1 - frac_self] + return join_colormaps([self, other], fractions, name, N) __add__ = join From fa9f56a2cafd6849ed8d648959b42f5e4c72f257 Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Sun, 1 Jan 2017 12:33:58 -0700 Subject: [PATCH 08/17] Some ideas for a colormap __getitem__ method. --- lib/matplotlib/colors.py | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index e9099b097f14..7815b9d82830 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -770,6 +770,90 @@ def truncate(self, minval=0.0, maxval=1.0, name=None, N=None): name = "trunc({},{:.2f},{:.2f})".format(self.name, minval, maxval) return ListedColormap(self(np.linspace(minval, maxval, N)), name) + def __getitem__(self, item): + """Advanced indexing for colorbars. + + + Examples + -------- + import matplotlib.pyplat as plt + cmap = plt.get_cmap('viridis', 128) + + # ### float indexing + # for float-style indexing, the values must be in [0.0, 1.0] + # Truncate the colormap between 20 and 70% + new_cm = cmap[0.2, 0.7] + # equivalently: + new_cm = cmap[0.2:0.7] + + # Same as above, but specify the number of points + new_cm = cmap[0.2, 0.7, 64] + # equivalently, use `np.mgrid` complex-indexing: + new_cm = cmap[0.2:0.7:1j * 64] + + # ### Int-style indexing + # for int-style indexing, the values must be in [0, self.N] + new_cm = cmap[12:100] + + # Same as above, but 4x fewer points + new_cm = cmap[12:100:4] + + # negative values are supported (same as above) + new_cm = cmap[12:-28:4] + + # And so is `np.mgrid` complex-indexing (same as above) + new_cm = cmap[12:-28:1j * 22] + """ + if isinstance(item, tuple): + if len(item) == 2: + N = self.N + elif len(item) == 3: + N = item[2] + else: + raise IndexError("Invalid colorbar itemization") + return self.truncate(item[0], item[1], N=N) + elif isinstance(item, slice): + name = self.name + '[{:s}]'.format(str(item)) + sss = [item.start, item.stop, item.step] + if any([isinstance(s, int) for s in sss]): + # This is an integer-style itemization + if sss[0] is None: + sss[0] = 0 + elif sss[0] < 0: + sss[0] = sss[0] % self.N + if sss[1] is None: + sss[1] = self.N + elif sss[1] < 0: + sss[1] = sss[1] % self.N + if sss[2] is None: + sss[2] = 1 + sss[0] = sss[0] / self.N + sss[1] = sss[1] / self.N + if not isinstance(sss[2], complex): + sss[2] = sss[2] / self.N + else: + if sss[0] is None: + sss[0] = 0.0 + if sss[1] is None: + sss[1] = 1.0 + if sss[2] is None: + sss[2] = self.N * 1j + if sss[0] < 0 or sss[0] >= 1 or sss[1] <= 0 or sss[1] > 1: + raise IndexError("Invalid colorbar itemization - outside bounds") + points = np.mgrid[slice(*sss)] + elif isinstance(item, (list, np.ndarray)): + name = self.name + '[...]' + if isinstance(item, list): + item = np.array(item) + if item.dtype.kind in ('u', 'i'): + item = item.astype('f') / self.N + points = item + else: + raise IndexError("Invalid colorbar itemization") + if len(points) <= 1: + raise IndexError("Invalid colorbar itemization - too few points") + return ListedColormap(self(points), name=name) + class LinearSegmentedColormap(Colormap): """Colormap objects based on lookup tables using linear segments. From aba18e0a5876c31cf734e5e85dc52caebf1322d0 Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Wed, 18 Jan 2017 15:17:14 -0700 Subject: [PATCH 09/17] Fix some floating-point arithmetic issues for low-N. --- lib/matplotlib/colors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 7815b9d82830..1f9d61ba9038 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -131,7 +131,7 @@ def join_colormaps(cmaps, fractions=None, name=None, N=None): for cm in cmaps: name += cm.name + '+' name.rstrip('+') - maps = [cm(np.linspace(0, 1, int(N * frac))) + maps = [cm(np.linspace(0, 1, int(round(N * frac)))) for cm, frac in zip(cmaps, fractions)] # N is set by len of the vstack'd array: return ListedColormap(np.vstack(maps), name, ) From 652b4cfc64073382c2a139c1f3124872230c18d7 Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Wed, 1 Feb 2017 15:17:13 -0700 Subject: [PATCH 10/17] Simplify getitem. --- lib/matplotlib/colors.py | 73 ++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 1f9d61ba9038..12c3a7ebd132 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -781,15 +781,18 @@ def __getitem__(self, item): # ### float indexing # for float-style indexing, the values must be in [0.0, 1.0] - # Truncate the colormap between 20 and 70% - new_cm = cmap[0.2, 0.7] - # equivalently: - new_cm = cmap[0.2:0.7] + # Truncate the colormap between 20 and 80%. + new_cm = cmap[0.2:0.6] + # `new_cm` will have the color-spacing as `cmap` (in this + # case: 0.6 - 0.2 = 40% of 128 = 51 colors) + + # negative values are supported + # this gives the same result as above + new_cm = cmap[0.2:-0.4] # Same as above, but specify the number of points - new_cm = cmap[0.2, 0.7, 64] - # equivalently, use `np.mgrid` complex-indexing: - new_cm = cmap[0.2:0.7:1j * 64] + # using `np.mgrid` complex-indexing: + new_cm = cmap[0.2:-0.4:1j * 64] # ### Int-style indexing # for int-style indexing, the values must be in [0, self.N] @@ -803,19 +806,35 @@ def __getitem__(self, item): # And so is `np.mgrid` complex-indexing (same as above) new_cm = cmap[12:-28:1j * 22] + + # ### Array/list-style indexing + # In this case, you specify specific points in the colormap + # at which you'd like to create a new colormap. + + # You can index by integers, in which case + # all values must be ints in [-self.N, self.N]: + new_cm = cmap[[5, 10, 25, -38]] + + # Or by floats in the range [-1, 1] + new_cm = cmap[[0.04, 0.08, 0.2, -0.3]] """ - if isinstance(item, tuple): - if len(item) == 2: - N = self.N - elif len(item) == 3: - N = item[2] - else: - raise IndexError("Invalid colorbar itemization") - return self.truncate(item[0], item[1], N=N) - elif isinstance(item, slice): - name = self.name + '[{:s}]'.format(str(item)) + if isinstance(item, slice): sss = [item.start, item.stop, item.step] - if any([isinstance(s, int) for s in sss]): + name = self.name + '[{}:{}:{}]'.format(*sss) + if (all([s is None or abs(s) <= 1 for s in sss[:2]]) and + (sss[2] is None or abs(sss[2]) <= 1 or + isinstance(sss[2], complex))): + if sss[0] is None: + sss[0] = 0 + elif sss[0] < 0: + sss[0] += 1 + if sss[1] is None: + sss[1] = 1.0 + elif sss[1] < 0: + sss[1] += 1 + if sss[2] is None: + sss[2] = self.N * 1j * (sss[1] - sss[0]) + else: # This is an integer-style itemization if sss[0] is None: sss[0] = 0 @@ -831,27 +850,23 @@ def __getitem__(self, item): sss[1] = sss[1] / self.N if not isinstance(sss[2], complex): sss[2] = sss[2] / self.N - else: - if sss[0] is None: - sss[0] = 0.0 - if sss[1] is None: - sss[1] = 1.0 - if sss[2] is None: - sss[2] = self.N * 1j - if sss[0] < 0 or sss[0] >= 1 or sss[1] <= 0 or sss[1] > 1: - raise IndexError("Invalid colorbar itemization - outside bounds") + if sss[0] < 0 or sss[0] >= 1 or sss[1] <= 0 or sss[1] > 1: + raise IndexError("Invalid colorbar itemization - outside bounds") points = np.mgrid[slice(*sss)] elif isinstance(item, (list, np.ndarray)): - name = self.name + '[...]' + name = self.name + '[]' if isinstance(item, list): item = np.array(item) if item.dtype.kind in ('u', 'i'): item = item.astype('f') / self.N + item[item < 0] += 1 + if np.any(item > 1): + raise IndexError("Invalid colorbar itemization - outside bounds") points = item else: raise IndexError("Invalid colorbar itemization") if len(points) <= 1: - raise IndexError("Invalid colorbar itemization - too few points") + raise IndexError("Invalid colorbar itemization - a colorbar must contain >1 color.") return ListedColormap(self(points), name=name) From c2bd7129bcd49308094449f0e6328724a2333ad6 Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Wed, 1 Feb 2017 15:17:21 -0700 Subject: [PATCH 11/17] Add more tests. --- .../test_colorbar/colorbar_join.png | Bin 0 -> 1857 bytes .../test_colorbar/colorbar_join_frac.png | Bin 0 -> 2008 bytes .../test_colorbar/colorbar_join_listed.png | Bin 1935 -> 0 bytes .../colorbar_join_listed_frac.png | Bin 1914 -> 0 bytes .../test_colorbar/colorbar_join_lsc.png | Bin 2010 -> 0 bytes .../test_colorbar/colorbar_join_lsc_frac.png | Bin 1968 -> 0 bytes .../colorbar_trunc-getitem-int-1jN.png | Bin 0 -> 2165 bytes .../colorbar_trunc-getitem-int.png | Bin 0 -> 2794 bytes .../test_colorbar/colorbar_trunc-getitem.png | Bin 0 -> 2157 bytes .../test_colorbar/colorbar_truncate.png | Bin 0 -> 2180 bytes .../colorbar_truncate_listed.png | Bin 1875 -> 0 bytes .../test_colorbar/colorbar_truncate_lsc.png | Bin 1817 -> 0 bytes lib/matplotlib/tests/test_colorbar.py | 63 ++++++++---------- 13 files changed, 28 insertions(+), 35 deletions(-) create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join.png create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_frac.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_listed.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_listed_frac.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_lsc.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_lsc_frac.png create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem-int-1jN.png create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem-int.png create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem.png create mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate_listed.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate_lsc.png diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join.png new file mode 100644 index 0000000000000000000000000000000000000000..5ebad2e5a17724f97403f36a82569dbf75efdcad GIT binary patch literal 1857 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 bi^fR#(tYsxckoZZQyB2xjq|MXAe{LF;*d@S literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_listed.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_listed.png deleted file mode 100644 index 5c39886c7e4abfe747ab6cc5cdc06325da8a4982..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1935 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 diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_lsc_frac.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_lsc_frac.png deleted file mode 100644 index 53cd5faa320c854da05f97e314e763d27f7c376a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1968 zcmb_dX;4#F6n+Vj1PcL*3bIB;&=C@35kgslfJjlGBA^Hag~$>hEMX@acTwExXwU`` zI*LA!Ww5L!Qa~fa5*lSQveqU*42uLv0)#$0?es@&XSAM~yPmmo&o|#W-^uay_E1}` zyBYuhHP78{`v3q&fcDcUWoS+`XOW==k-XD$KMJyJRK$7ctdg+%U@`zGn|v6s0xkPZ z(4`;M{Q%XEa+I2OIEe(r9i}G4QmC=fM=+_Rq~vHyJjN1hfwf2qx5Oq;lBt$#HT$^ zH)d4h!o5CYEcX1vHL;p*X-9m2_V0-aRKT{@u20z9fAm(0N~&H=;4-p)tjOG5OWQE& z`!cf#{clvPZjDoe_Y}R_BMh9Z6J~K2GcfI>N#^1*(?a;HE)xAFoDbP5jWM#TI$*H| zhB%^v(eMIJ9Dt)*z9wL90`N+N#`(>3g4w6Jx>G_@LTn{ERy7t9AZxt746B$oofEf? z5B3}&4wQl*g(=UZklSMn7I^}DTIoza64!f4&ldethtKg9mOPtA?iCtxr6R^LzreEK zj0u^*{Uxjvv|nComCKAmC&hD&sljp(v=XxW`MOm>9QNZnZzFOkYi7WeGAon!usOWf zdSnk~l#`7?V`~I&aXn!O*=N>UiHj?V9FtIY9(c1_ZT92QT9yRsGBG7u)(KJ#~sTUy|S!^$lWyy3w8*#!6(+n4fad@oSWadrjPUg zh;U4CH#ygR7REGnJyY{-_Q)1Qf^iF@c;>0-!ny1Q8zJIqu?c&2gr_~#-F;~xl~%@o zBg=e*@-lfb}Y7p$;k*r_4mT2@whT8g}O3nX~x*r7|<3!(f$baB@ zmmfi|UX9aiZLaFrcx*C69xxD`Sr%YwI=@tB6e?ZJHGw}bk^y&u972WjIYj^Nb2V(| zQ_**fpS1H}=vC-K8BiVnU^*ZN_wu^DItUQvNt1L6*s1rOp2(NVxC6A{MzWRu0~q|p zwc589SY%zh^)C2};KZIbYZZ+CRq5p`K$Cv@Ms~Tn6{pYo_$F%t@w4jlqadMz4}iD| z=?5Diq~Qdu$yB||=e7pvWYU+PESG!D%{$)&cbE|63Zynx)mqa6O5X}^TtI$-!;CmE zen2-Y&tSC8w{x$zOZBe(gd)fX1icf1+b|1*O#MWNk?Y)dApz#qz09o2IEqW1IE!}39}>Kk>UJgjzm z3u7I#K%d4J6$FH=fZ=1;^KpzTiubcoXm}rLhV-fv?bwJxBp9kfbxeATxLPhKWn9xD zyf$XH(}AWHtsxya${Zh+-K+@WGv+C$mB(^ES7iT*ZZEPzR1XG;Gj8}8E{phPJ%6cP zg<$y9FH^mpIBtI-@`SQvEw7zm`#~4?Y2ysbwTVk!=2$G+5v>|eBHaVQ_@Pj|q}t0% zNRAV8v)GfZ*Kzu^T0Av23$n2dz}YT|4T0|TWqL)WLaC|4_hR`Pmn~3t1w7ro-O6@` Go%|i{5g+9M diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem-int-1jN.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem-int-1jN.png new file mode 100644 index 0000000000000000000000000000000000000000..82939b377b1d828080d33283d280a27ff642a78d GIT binary patch literal 2165 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 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem.png new file mode 100644 index 0000000000000000000000000000000000000000..b8ad4b869f9626cdd3bbef8e2a1c40df48fd003f GIT binary patch literal 2157 zcmbVOdpMi-9)A-SsY|8vY|1p!N2@#~Nki)rm#o#Pp3zN3DWxuP8InlSFf5@urp~ZK z&85njt=*C~I5bf?ikjpp%4tpAN^~09grIGRNM)~?wY9%?-skzf_xF4Kd_Lbd?-M_7 zBYksy004}9j(Pb50E7UZFTi2oKH0uC0X*o^5Bmhb!7T$G{S|nX&X(6W|;zg^w z1@^h;$E-^}9yl87HqJN_yR(!bHpC-q7NBmxi6Ya;aTZ8wBheO8q}jYnqRsf_lpu+qtDA#j>^*j?ms`OeV#8_<5+z0oHe4o|Ka`_XSU1! zA4(n;wB^xf?<7zQDlLVdAH;ZiYMR_w8dacnX`qf3jE=e2-M=Dhl$3ZEB3pY9g5!e_ zyB|twPfTE{wTnYHcCj^2W+gK#s?>!327|f|7jlXwm#r9AOV0FGJRh;V9lGLD?CCqf z3<~*423)y(xk+8zQo_Vs@U4n64a=rKQmDjYfibF%yM{y&LSCmyY~AL6-1bFR*b13B zJh~{sm+_g2HRPDL>N7|=56F`njk-oY68Yz=0RF8`!@0Zq#1OlzzZUPh%re_0{ACY! zq>7ij=%+yT3XxE%k;6uTIpI*9xyrSX@mTHg6c}l9|xq4k#cSpAI z`f5RnMCA~2JAXd%q!lHne*2b)^r(xp(=jKiQ``-IyfgcZKGbPWY%_RdrzW|MWAgK= zejyg*up~RlT(#Ncq@sRSJKM?2g%FQ@5mskEsE4Sr2Yb!|Yf+E%b+CzAexS`a+rUC; zJO0iC7`fkYD@X?Cq2ZwU16)?w4w#lWI33-{^3xEhW?nm+2CqU8;0-e7gGi5N zbsSxXleriB$&zQwDR2!bv4{LNfJQSe`rw80yF$@l94IOBgRTBoU3X0_d?(+5@Cwch zQuYH`%KD15uj^pH19cFSg%K6g)|Bxh+V}}Pv0dw`6~_-98MYnNE5a&1y>UpWR!6r| z!b3R5XSH#0OM2g~(e2&XqjLo21xvve%yU?#&4Q`N!jU-D~ouMnQQ{rG&svvar2x4a4Z-^u^F>fzjDw*DK8(bDU(Z`%p0(-^cCz3{1EYS=U!rG z_D>f8sB}TRjP_I~Tm$o4-gGc6aw`bwomU7i+CRr!DCw^8$U5t5ZWIAjC z3PPaL0fgH1t6{Ml^$%1+5~quCD~cw01mV4_k}IXp1iajH$;L&TX78J$?ekG}L?z^r z(7~>AS<$*;vb!B@aUMLI?K)k3&nemUwAw_GyT3$V39OiwiJRT;0q$-*ObwIk`@6SP~QOm}!D`cI6! gj`RN>g7Wb1pZsX^nc2)i@YewFIqK)dJAC&1Z=9{B5C8xG literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate.png new file mode 100644 index 0000000000000000000000000000000000000000..86d85a4d82b11b95c57e64b191d394292d2e1fc2 GIT binary patch literal 2180 zcmb7Gdo)|w9zF?`w6xsOQB+CSteHMWBH|I6)liRVO>tc<^{5HrQT0d=iC2O#tt+|N)Safw19pD-}k{uD)u2sCg_z~ln}ti#Uc)cNQeGs9hB z2L~V>Z>^oNPr{BbL%+CH7sRv0BB6JNC_D$6*MUiO5o8t0D6C4u@1do=(7YSMt8P!d z>U-d)p8?lnofG7JE3yY!h%-hhclmrH{y)n{d~4kHCt6CXU_kHZ5JlhJ2(`07k{cBM z_%lmHHUOsMYz~{|MWCR%R@uF9+vG>5&VP7+t+Ef%)CHCT1No>9S=)vS-3*{2+65 zT~b*}Fp~0@tyAiMs@V6YukRm~vU54Vez;Oy6&cbNOimvqycCWbZ3#J))GPnS(fOX`UVQAP?oA*x`gE4rnzLXQ^Q_Sdh!rs~bYb@vvqo$A|> z=ucsEkr2^=!c#H0;ptdSz3~rH_Vi)k0(xV{%2iMABKlY$#{hqCXwt0T0XY1)RxFwf zp*=6Yl?;vv5*QqLoAzPnYrWA9Sw)$eECj$Sy_I&R%7qT_Nk{xwXDX{wATGI#wP)gL zE8Z*=EBr3cp4PSU*l`NereHx*X>gIKkja5=i}DEEenP{WU~0O{f?ZffNV8Ro3>7TxeBn8Sc|VipE` zDbEAqzgReyno&Dp1BD;XMjkP#>*5x2NS2>JeRh&uI(&Mm>qGJVrQ!V>tFR#vMBUTA zL%EPY(XVnfw7LEMg`TqHs+5P6LSFn*>^`)r0B1k>xzmP3U0DgBkKIZHp#Dp5 z+l5z11yQ(vnbd7(hYk6xU47R&b2G$`6eg!eau7$5|C=$3NOj}SPLq+%+(M;4k*H#H z*Hs5%SybdQ3%Wz8APxQSx;g)yPpzfNd;^@Kf*Msi=FR_xF%!eh-V_eli zoT(FblMfr_z@EaMO5|ONvkq5phxJ;(pN?y2erg&OQp4Plc%h!l{8eSABbyUcwCqwE z#M0^WaY+gNGh4LRV-TtVXwagnLBbNXe|DEftH~>oSIF`A&%AcC5Ifxn+yVYj&SYom z?|d(~Pd>?Z635v!Ppkzpse%#|Z#jn8SU;uESZARRvq*@R9I#4!$rlegOOR+wPcVKL zuv4uqnNSLzqzz!0mp4f_t`U7U+Wx5htJ{}7ySH3n(-2)Gpp8E`ip#VeXe(m=sw29m z3uVg_Te+%*=zY+cU@$^N3s$TkKd5zOXHsuoV8l-EMmX)m)5-IF*!*?{|ADq-bM#==7(~; zR23@FF~VB=kw#tDc5Q@9%{TS0y{EW=Srw{pdPb^MX7PKXcpF0QY@sn!dD$aN)V%Z9~$7=Jg`{a`v-*{|kbz2Bq^xhUeyF$TCJMEdf zQJ7e#tgK^PB#JKPZj=k!dS+&3e|llb6p-!w?F)Mk8BCe=P9$oy|BB;j9`-KERg9Vg z4S!{!i@@y2AY`?*3A4G2zl@J@#&m|}v~Ljey7ER-x`7tykX~1Gyf_z?fz@FwzD*vo zY;O0h`7Krr@G6&TXci&2L;UO2aJz=GWstsr8d$@7i$~xe17K(CXj5h7{r&#{eWSj7 literal 0 HcmV?d00001 diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate_listed.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate_listed.png deleted file mode 100644 index 7415ebbd011eda9a268884c16dec7460d6a56348..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1875 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 f3Xhr5+6VWaW85|#(-k>cb{h~878%M5rXKwp Date: Thu, 2 Feb 2017 10:50:35 -0700 Subject: [PATCH 12/17] pep8 --- lib/matplotlib/colors.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 12c3a7ebd132..48c5aae813d0 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -241,8 +241,8 @@ def _to_rgba_no_colorcycle(c, alpha=None): match = re.match(r"\A#[a-fA-F0-9]{6}\Z", c) if match: return (tuple(int(n, 16) / 255 - for n in [c[1:3], c[3:5], c[5:7]]) - + (alpha if alpha is not None else 1.,)) + for n in [c[1:3], c[3:5], c[5:7]]) + + (alpha if alpha is not None else 1.,)) # hex color with alpha. match = re.match(r"\A#[a-fA-F0-9]{8}\Z", c) if match: @@ -851,7 +851,8 @@ def __getitem__(self, item): if not isinstance(sss[2], complex): sss[2] = sss[2] / self.N if sss[0] < 0 or sss[0] >= 1 or sss[1] <= 0 or sss[1] > 1: - raise IndexError("Invalid colorbar itemization - outside bounds") + raise IndexError("Invalid colorbar itemization - outside " + "bounds") points = np.mgrid[slice(*sss)] elif isinstance(item, (list, np.ndarray)): name = self.name + '[]' @@ -861,12 +862,14 @@ def __getitem__(self, item): item = item.astype('f') / self.N item[item < 0] += 1 if np.any(item > 1): - raise IndexError("Invalid colorbar itemization - outside bounds") + raise IndexError("Invalid colorbar itemization - outside " + "bounds") points = item else: raise IndexError("Invalid colorbar itemization") if len(points) <= 1: - raise IndexError("Invalid colorbar itemization - a colorbar must contain >1 color.") + raise IndexError("Invalid colorbar itemization - a colorbar must " + "contain >1 color.") return ListedColormap(self(points), name=name) From 9de0239b66f761c9813c6aef8b775d225cf9e22a Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Wed, 27 Sep 2017 13:39:35 -0600 Subject: [PATCH 13/17] Add whats_new and update docstring --- doc/users/next_whats_new/colormap_utils.rst | 56 +++++++++++++++++++++ lib/matplotlib/colors.py | 5 +- 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 doc/users/next_whats_new/colormap_utils.rst diff --git a/doc/users/next_whats_new/colormap_utils.rst b/doc/users/next_whats_new/colormap_utils.rst new file mode 100644 index 000000000000..87ed5d6379a7 --- /dev/null +++ b/doc/users/next_whats_new/colormap_utils.rst @@ -0,0 +1,56 @@ +Colormap Utilities +------------------ + +Tools for joining, truncating, and resampling colormaps have been added. This grew out of https://gist.github.com/denis-bz/8052855, and http://stackoverflow.com/a/18926541/2121597. + + +Joining Colormaps +~~~~~~~~~~~~~~~~~ + +This includes the :func:`~matplotlib.colors.join_colormaps` function:: + + import matplotlib.pyplat as plt + from matplotlib.colors import join_colormaps + + viridis = plt.get_cmap('viridis', 128) + plasma = plt.get_cmap('plasma_r', 64) + jet = plt.get_cmap('jet', 64) + + joined_cmap = join_colormaps((viridis, plasma, jet)) + +This functionality has also been incorporated into the :meth:`~matplotlib.colors.colormap.join` and `~matplotlib.colors.colormap.__add__` methods, so that you can do things like:: + + plasma_jet = plasma.join(jet) + + joined_cmap = viridis + plasma + jet # Same as `join_colormaps` function call above + +Truncating and resampling colormaps +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A :meth:`~matplotlib.colors.colormap.truncate` method has also been added:: + + sub_viridis = viridis.truncate(0.3, 0.8) + +This gives a new colormap that goes from 30% to 80% of viridis. This functionality has also been implemented in the `~matplotlib.colors.colormap.__getitem__` method, so that the same colormap can be created by:: + + sub_viridis = viridis[0.3:0.8] + +The `~matplotlib.colors.colormap.__getitem__` method also supports a range of other 'advanced indexing' options, including integer slice indexing:: + + sub_viridis2 = viridis[10:90:2] + +integer list indexing, which may be particularly useful for creating discrete (low-N) colormaps:: + + sub_viridis3 = viridis[[4, 35, 59, 90, 110]] + +and `numpy.mgrid` style complex indexing:: + + sub_viridis4 = viridis[0.2:0.4:64j] + +See the `~matplotlib.colors.colormap.__getitem__` documentation for more details and examples of how to use these advanced indexing options. + +Together, the join and truncate/resample methods allow the user to quickly construct new colormaps from existing ones:: + + new_cm = viridis[0.5:] + plasma[:0.3] + jet[0.2:0.5:64j] + +I doubt this colormap will ever be useful to someone, but hopefully it gives you the idea. diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 48c5aae813d0..1c4464694363 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -773,7 +773,6 @@ def truncate(self, minval=0.0, maxval=1.0, name=None, N=None): def __getitem__(self, item): """Advanced indexing for colorbars. - Examples -------- import matplotlib.pyplat as plt @@ -792,7 +791,7 @@ def __getitem__(self, item): # Same as above, but specify the number of points # using `np.mgrid` complex-indexing: - new_cm = cmap[0.2:-0.4:1j * 64] + new_cm = cmap[0.2:-0.4:64j] # ### Int-style indexing # for int-style indexing, the values must be in [0, self.N] @@ -805,7 +804,7 @@ def __getitem__(self, item): new_cm = cmap[12:-28:4] # And so is `np.mgrid` complex-indexing (same as above) - new_cm = cmap[12:-28:1j * 22] + new_cm = cmap[12:-28:22j] # ### Array/list-style indexing # In this case, you specify specific points in the colormap From 48172c7d19de5c945f2156b4dc6f76f051c62166 Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Fri, 18 May 2018 14:30:43 -0600 Subject: [PATCH 14/17] Compare cmap values in tests (not image comparisons) --- .../test_colorbar/colorbar_join.png | Bin 1857 -> 0 bytes .../test_colorbar/colorbar_join_frac.png | Bin 2008 -> 0 bytes .../colorbar_trunc-getitem-int-1jN.png | Bin 2165 -> 0 bytes .../colorbar_trunc-getitem-int.png | Bin 2794 -> 0 bytes .../test_colorbar/colorbar_trunc-getitem.png | Bin 2157 -> 0 bytes .../test_colorbar/colorbar_truncate.png | Bin 2180 -> 0 bytes lib/matplotlib/tests/test_colorbar.py | 96 +++++++++++------- 7 files changed, 58 insertions(+), 38 deletions(-) delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join_frac.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem-int-1jN.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem-int.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem.png delete mode 100644 lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate.png diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_join.png deleted file mode 100644 index 5ebad2e5a17724f97403f36a82569dbf75efdcad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1857 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*+7b=*vT`50|;t3QaXTq&H|6f zVg?2_H4tW;FKnd@6bvqLjVKAuPb(=;EJ|g_O)M$M$uG&tOj0OIEh^5;&r>kcGte_A zN;c9f$S*E2vamGKOGzy=&`wV?u`skuG1O7WC@Cqh($`05)ypqR*AJ^VnhUh2#nZ(x zq+-t7yXUj#T$MZiF@Nhdw?BeDqE|X%B+R)Uc}?Ulzvz8%X~&~ut=fgl%gVbISa+Aa z|NkI9p34Y)2q1~7i#-c{Ql>=CA-c{2@AWM_tuxx);`&t^5UPR zL&HW6vOHP(x9>t|sQ;hcufC>7ooD)0^lN{2yz%*{sI)twY3$$t3;S-*#Qa!#UzTmN z*&ARmmNhu|zT5ZfWZC6R84GLl04N+Ly`$omNuMSMYb*{kefn z1uLI_J(dJ97ZDL_-o>-ly`Ome)z;~LTj#NTdHUtuq3LI~PMaoCKJ_Le_UL-`Pe#FD zU-#jot5#XX9hW};Bmtxn=)PUWMd_iTZ>Qa7VeC-A5y`vkIsQKU{eKPr`F$6wq%KSi zfBogq^)s8NO_M~o@T>fR)3-yTonJ>f$ZunNohbhm=%I-v^*qb^)`#c%fP$uZD%@ZkfkXlJNS~@xO7ql6!A&e<%Nz`+RN8 z|H_}YXZ?8`@p`30@!|jLLPD=b=iBf7uyy^OAAx%-%U<*E|5ko1HuWxh!QVdVqx|cn zvUQiNGdzzY7KqAESN}#o+W+})ZRy9!$D{q3cWpW|pJR5q?$W<64WY?r*MC7^KrQvx z4-LKQcK2e18vAKJfsRymjw^4!-@jMI<$D9&{?)%3;(q=+9)DiLahLb}xJ`230>3k| zNO*sL&d`6itoV(j>W+C^H|z(cSCnjj_3!Ef^J_N-PS>}&0*d+NuQs=?pP8nnLsM5ef>YZ^!@J5*Dg2gv)S-NwRr7P zRbc3%M(UuN(Sz@hcpN*k#XF{N+Z}+PhVYzM3rH-oLi> z{Oog&H-OR-iaW!;uLtH(Z`d-vpW z|ER>WZ&>we`7PsQt5mk!0( z%j!bP0l+XkKfIV6BAaa$A;k}%cM|qcFbH@T1G1s@Rj+16wy#Z@K=*4?@AB2Hd3M}+2_`Zy?=SVyN7;Knt zkYZEJI&jdRx*JdRCx=rLiE&{-43SESCR3v$Nl02)Tzn)s7U_t#N887RIHD=!c&g)e z7bkRR7|k9P5$?3z!6nqe7I~aXrC{vr7M7yPaS?U_Ovg(A0EK&d?mC!saYQc83XE9O zIzCnt+4eo2osE`UTPuq-^EBbEJyfB0tiGaThjVP%=!NHB7?rWY{Rdhygl~K)F*Lt2 zKAgXNrHkL5m{qwea;X^SOV@%d_8lT&3JPTL#S#5)=rJ3zcDzcldwKKCMMOhlr>rrA$p``NE4s`G1bWc*u)B=<<~ioK+4Xx zF1}QEINUOmt{iWTs^#F$*W?_%!OX6m+dbU7=_XYDL|v!gaccd`l^s`o)H8Cj?dHx0 z*q}F(r-Fp>-|wYmCk{~8h&Y^14xN5?Bv@NKXDww|XG{?g>K;vhclRwOxtw#0k<%sn z5ohe!QQDaRY|Q<&LhE<}6BvfW`_b!Y|~Oz%VW2D5De{ zjJ8SYFOz2=ZWICah=6}&E?4M5`a|rT&BU{(90YGYfU!H%#W#vl4@Q<+W%(06gsW2B zN;s{)S1oCXz}4FH?x(-7a8Zl^P@?{y@CHnki$w1-nKeZvMv!!q#z5a-gtU^Qyel?$ zIgqRalU&L5s^pxgth4gHj@L;_zm(kHAYEslx8(@ncLF+y z(Kn=0W?0Y|?SmLWN#qRSuU*cI;FxY%LDp2g%{{hHV}P?cYN<3-OpA9Ds6+X7HAQEf z#KmMRWcmDRB~u^P)>;+e-=)x=#GsaeaB{gaT?9!rDTePW$2+|bbW!Jye5Ydi%Hi^( z#uO(!WQpo3)r}&tX24g~kuk(;O|6=Jd2ei3oj4h1yC$@eU9f7gE(4|@vifncRgfYU zYd|F?F?z=Bz2s06g00-mKrq3FMol#IfNQVKNDRF#+;vJ+_)d~%j7kuin$})YrFCr)wtF!ze17J-*xlbY`>=L}a{ki>O^AsW}7H&5u zLWfq;exM0Rwo7ydrKm>|hx*~pM?vq@Pq(xm$Y%5FdKyP{VfJ~Wh%^_?qa4Y)9Bc=D z#lUTRtB2Ade1WS4QGZ}qp|)8>*2L7t25M4<94vpy4W0`bS_z9-B*&EDzPOIZs{S)S z4W=ys8)x)wc+h0hW7gHcN_f`$aU6@)-9YE5VEg77;{q)DfGL8hH69CtMJFucDdWu?32dtJw3Qx7q3yWzjO*>pAJ%?ge^j*#6c}=@L z9&>#}*L&_tMTpqSB&>`$TaqCWkHCFEvjZV3|8`F2+&&Y6Yqk-yy03XQcFF>)enQF| zOb4E^`-0`YcBbdU9+Y-phE^mR7k1o#vT@dTcQrd}R2_w3Fo0oR4 zh(C4G>{%LPn5>4w;a6hZyt^P=4!xR2Y8IG{)@<$JMmBBvjb@r7sA@KkcPx^}FJy*M#c7OA{!n2dTm#T7G`Mv8(K}8mGeca2^{tUaIydr1D{lUHb6{ bi^fR#(tYsxckoZZQyB2xjq|MXAe{LF;*d@S diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem-int-1jN.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem-int-1jN.png deleted file mode 100644 index 82939b377b1d828080d33283d280a27ff642a78d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2165 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 diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_trunc-getitem.png deleted file mode 100644 index b8ad4b869f9626cdd3bbef8e2a1c40df48fd003f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2157 zcmbVOdpMi-9)A-SsY|8vY|1p!N2@#~Nki)rm#o#Pp3zN3DWxuP8InlSFf5@urp~ZK z&85njt=*C~I5bf?ikjpp%4tpAN^~09grIGRNM)~?wY9%?-skzf_xF4Kd_Lbd?-M_7 zBYksy004}9j(Pb50E7UZFTi2oKH0uC0X*o^5Bmhb!7T$G{S|nX&X(6W|;zg^w z1@^h;$E-^}9yl87HqJN_yR(!bHpC-q7NBmxi6Ya;aTZ8wBheO8q}jYnqRsf_lpu+qtDA#j>^*j?ms`OeV#8_<5+z0oHe4o|Ka`_XSU1! zA4(n;wB^xf?<7zQDlLVdAH;ZiYMR_w8dacnX`qf3jE=e2-M=Dhl$3ZEB3pY9g5!e_ zyB|twPfTE{wTnYHcCj^2W+gK#s?>!327|f|7jlXwm#r9AOV0FGJRh;V9lGLD?CCqf z3<~*423)y(xk+8zQo_Vs@U4n64a=rKQmDjYfibF%yM{y&LSCmyY~AL6-1bFR*b13B zJh~{sm+_g2HRPDL>N7|=56F`njk-oY68Yz=0RF8`!@0Zq#1OlzzZUPh%re_0{ACY! zq>7ij=%+yT3XxE%k;6uTIpI*9xyrSX@mTHg6c}l9|xq4k#cSpAI z`f5RnMCA~2JAXd%q!lHne*2b)^r(xp(=jKiQ``-IyfgcZKGbPWY%_RdrzW|MWAgK= zejyg*up~RlT(#Ncq@sRSJKM?2g%FQ@5mskEsE4Sr2Yb!|Yf+E%b+CzAexS`a+rUC; zJO0iC7`fkYD@X?Cq2ZwU16)?w4w#lWI33-{^3xEhW?nm+2CqU8;0-e7gGi5N zbsSxXleriB$&zQwDR2!bv4{LNfJQSe`rw80yF$@l94IOBgRTBoU3X0_d?(+5@Cwch zQuYH`%KD15uj^pH19cFSg%K6g)|Bxh+V}}Pv0dw`6~_-98MYnNE5a&1y>UpWR!6r| z!b3R5XSH#0OM2g~(e2&XqjLo21xvve%yU?#&4Q`N!jU-D~ouMnQQ{rG&svvar2x4a4Z-^u^F>fzjDw*DK8(bDU(Z`%p0(-^cCz3{1EYS=U!rG z_D>f8sB}TRjP_I~Tm$o4-gGc6aw`bwomU7i+CRr!DCw^8$U5t5ZWIAjC z3PPaL0fgH1t6{Ml^$%1+5~quCD~cw01mV4_k}IXp1iajH$;L&TX78J$?ekG}L?z^r z(7~>AS<$*;vb!B@aUMLI?K)k3&nemUwAw_GyT3$V39OiwiJRT;0q$-*ObwIk`@6SP~QOm}!D`cI6! gj`RN>g7Wb1pZsX^nc2)i@YewFIqK)dJAC&1Z=9{B5C8xG diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_truncate.png deleted file mode 100644 index 86d85a4d82b11b95c57e64b191d394292d2e1fc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2180 zcmb7Gdo)|w9zF?`w6xsOQB+CSteHMWBH|I6)liRVO>tc<^{5HrQT0d=iC2O#tt+|N)Safw19pD-}k{uD)u2sCg_z~ln}ti#Uc)cNQeGs9hB z2L~V>Z>^oNPr{BbL%+CH7sRv0BB6JNC_D$6*MUiO5o8t0D6C4u@1do=(7YSMt8P!d z>U-d)p8?lnofG7JE3yY!h%-hhclmrH{y)n{d~4kHCt6CXU_kHZ5JlhJ2(`07k{cBM z_%lmHHUOsMYz~{|MWCR%R@uF9+vG>5&VP7+t+Ef%)CHCT1No>9S=)vS-3*{2+65 zT~b*}Fp~0@tyAiMs@V6YukRm~vU54Vez;Oy6&cbNOimvqycCWbZ3#J))GPnS(fOX`UVQAP?oA*x`gE4rnzLXQ^Q_Sdh!rs~bYb@vvqo$A|> z=ucsEkr2^=!c#H0;ptdSz3~rH_Vi)k0(xV{%2iMABKlY$#{hqCXwt0T0XY1)RxFwf zp*=6Yl?;vv5*QqLoAzPnYrWA9Sw)$eECj$Sy_I&R%7qT_Nk{xwXDX{wATGI#wP)gL zE8Z*=EBr3cp4PSU*l`NereHx*X>gIKkja5=i}DEEenP{WU~0O{f?ZffNV8Ro3>7TxeBn8Sc|VipE` zDbEAqzgReyno&Dp1BD;XMjkP#>*5x2NS2>JeRh&uI(&Mm>qGJVrQ!V>tFR#vMBUTA zL%EPY(XVnfw7LEMg`TqHs+5P6LSFn*>^`)r0B1k>xzmP3U0DgBkKIZHp#Dp5 z+l5z11yQ(vnbd7(hYk6xU47R&b2G$`6eg!eau7$5|C=$3NOj}SPLq+%+(M;4k*H#H z*Hs5%SybdQ3%Wz8APxQSx;g)yPpzfNd;^@Kf*Msi=FR_xF%!eh-V_eli zoT(FblMfr_z@EaMO5|ONvkq5phxJ;(pN?y2erg&OQp4Plc%h!l{8eSABbyUcwCqwE z#M0^WaY+gNGh4LRV-TtVXwagnLBbNXe|DEftH~>oSIF`A&%AcC5Ifxn+yVYj&SYom z?|d(~Pd>?Z635v!Ppkzpse%#|Z#jn8SU;uESZARRvq*@R9I#4!$rlegOOR+wPcVKL zuv4uqnNSLzqzz!0mp4f_t`U7U+Wx5htJ{}7ySH3n(-2)Gpp8E`ip#VeXe(m=sw29m z3uVg_Te+%*=zY+cU@$^N3s$TkKd5zOXHsuoV8l-EMmX)m)5-IF*!*?{|ADq-bM#==7(~; zR23@FF~VB=kw#tDc5Q@9%{TS0y{EW=Srw{pdPb^MX7PKXcpF0QY@sn!dD$aN)V%Z9~$7=Jg`{a`v-*{|kbz2Bq^xhUeyF$TCJMEdf zQJ7e#tgK^PB#JKPZj=k!dS+&3e|llb6p-!w?F)Mk8BCe=P9$oy|BB;j9`-KERg9Vg z4S!{!i@@y2AY`?*3A4G2zl@J@#&m|}v~Ljey7ER-x`7tykX~1Gyf_z?fz@FwzD*vo zY;O0h`7Krr@G6&TXci&2L;UO2aJz=GWstsr8d$@7i$~xe17K(CXj5h7{r&#{eWSj7 diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py index df98f6295cd9..d527d46fb3b6 100644 --- a/lib/matplotlib/tests/test_colorbar.py +++ b/lib/matplotlib/tests/test_colorbar.py @@ -188,12 +188,8 @@ def test_gridspec_make_colorbar(): plt.subplots_adjust(top=0.95, right=0.95, bottom=0.2, hspace=0.25) -@image_comparison(baseline_images=['colorbar_join', - 'colorbar_join_frac', ], - extensions=['png'], remove_text=True, - savefig_kwarg={'dpi': 40}) def test_join_colorbar(): - data = np.arange(1200).reshape(30, 40) + test_points = [0.1, 0.3, 0.5, 0.7, 0.9] # Jet is a LinearSegmentedColormap cmap1 = plt.get_cmap('viridis', 5) @@ -201,51 +197,75 @@ def test_join_colorbar(): # This should be a listed colormap. cmap = cmap1.join(cmap2) - - plt.figure() - plt.pcolormesh(data, cmap=cmap) - plt.colorbar(orientation='vertical') + vals = cmap(test_points) + _vals = np.array( + [[0.229739, 0.322361, 0.545706, 1. ], + [0.369214, 0.788888, 0.382914, 1. ], + [0., 0., 0.5, 1. ], + [0.48387097, 1., 0.48387097, 1., ], + [0.5, 0., 0, 1., ]] + ) + assert np.allclose(vals, _vals) # Use the 'frac_self' kwarg for the listed cmap cmap = cmap1.join(cmap2, frac_self=0.7, N=50) - - plt.figure() - plt.pcolormesh(data, cmap=cmap) - plt.colorbar(orientation='vertical') + vals = cmap(test_points) + _vals = np.array( + [[0.267004, 0.004874, 0.329415, 1., ], + [0.127568, 0.566949, 0.550556, 1., ], + [0.369214, 0.788888, 0.382914, 1., ], + [0., 0., 0.5, 1., ], + [1., 0.59259259, 0., 1., ]] + ) + assert np.allclose(vals, _vals) -@image_comparison(baseline_images=['colorbar_truncate', - 'colorbar_trunc-getitem', - 'colorbar_trunc-getitem-int', - 'colorbar_trunc-getitem-int-1jN', ], - extensions=['png'], remove_text=True, - savefig_kwarg={'dpi': 40}) def test_truncate_colorbar(): - data = np.arange(1200).reshape(30, 40) - + test_points = [0.1, 0.3, 0.5, 0.7, 0.9] + cmap = plt.get_cmap('viridis', 32).truncate(0.2, 0.7) - - plt.figure() - plt.pcolormesh(data, cmap=cmap) - plt.colorbar(orientation='vertical') + vals = cmap(test_points) + _vals = np.array( + [[0.243113, 0.292092, 0.538516, 1. ], + [0.19586, 0.395433, 0.555276, 1. ], + [0.144759, 0.519093, 0.556572, 1. ], + [0.12478, 0.640461, 0.527068, 1. ], + [0.226397, 0.728888, 0.462789, 1. ]] + ) + assert np.allclose(vals, _vals) cmap = plt.get_cmap('viridis', 128)[0.2:-0.3:16 * 1j] - - plt.figure() - plt.pcolormesh(data, cmap=cmap) - plt.colorbar(orientation='vertical') + vals = cmap(test_points) + _vals = np.array( + [[0.241237, 0.296485, 0.539709, 1. ], + [0.192357, 0.403199, 0.555836, 1. ], + [0.140536, 0.530132, 0.555659, 1. ], + [0.12138, 0.629492, 0.531973, 1. ], + [0.214, 0.722114, 0.469588, 1. ]] + ) + assert np.allclose(vals, _vals) cmap = plt.get_cmap('viridis', 128)[25:90] - - plt.figure() - plt.pcolormesh(data, cmap=cmap) - plt.colorbar(orientation='vertical') - + vals = cmap(test_points) + _vals = np.array( + [[0.233603, 0.313828, 0.543914, 1. ], + [0.185556, 0.41857, 0.556753, 1. ], + [0.14618, 0.515413, 0.556823, 1. ], + [0.119483, 0.614817, 0.537692, 1. ], + [0.19109, 0.708366, 0.482284, 1. ]] + ) + assert np.allclose(vals, _vals) + cmap = plt.get_cmap('viridis', 128)[25:90:16 * 1j] - - plt.figure() - plt.pcolormesh(data, cmap=cmap) - plt.colorbar(orientation='vertical') + vals = cmap(test_points) + _vals = np.array( + [[0.241237, 0.296485, 0.539709, 1. ], + [0.192357, 0.403199, 0.555836, 1. ], + [0.140536, 0.530132, 0.555659, 1. ], + [0.12138, 0.629492, 0.531973, 1. ], + [0.214, 0.722114, 0.469588, 1. ]] + ) + assert np.allclose(vals, _vals) @image_comparison(baseline_images=['colorbar_single_scatter'], From 8592695b92965260f6d35394c113312b19ea6c76 Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Fri, 18 May 2018 14:54:32 -0600 Subject: [PATCH 15/17] pep8 fixes --- lib/matplotlib/tests/test_colorbar.py | 74 +++++++++++++-------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py index d527d46fb3b6..c3a5a1852282 100644 --- a/lib/matplotlib/tests/test_colorbar.py +++ b/lib/matplotlib/tests/test_colorbar.py @@ -199,11 +199,11 @@ def test_join_colorbar(): cmap = cmap1.join(cmap2) vals = cmap(test_points) _vals = np.array( - [[0.229739, 0.322361, 0.545706, 1. ], - [0.369214, 0.788888, 0.382914, 1. ], - [0., 0., 0.5, 1. ], - [0.48387097, 1., 0.48387097, 1., ], - [0.5, 0., 0, 1., ]] + [[0.229739, 0.322361, 0.545706, 1.], + [0.369214, 0.788888, 0.382914, 1.], + [0., 0., 0.5, 1.], + [0.48387097, 1., 0.48387097, 1.], + [0.5, 0., 0, 1.]] ) assert np.allclose(vals, _vals) @@ -211,60 +211,60 @@ def test_join_colorbar(): cmap = cmap1.join(cmap2, frac_self=0.7, N=50) vals = cmap(test_points) _vals = np.array( - [[0.267004, 0.004874, 0.329415, 1., ], - [0.127568, 0.566949, 0.550556, 1., ], - [0.369214, 0.788888, 0.382914, 1., ], - [0., 0., 0.5, 1., ], - [1., 0.59259259, 0., 1., ]] + [[0.267004, 0.004874, 0.329415, 1.], + [0.127568, 0.566949, 0.550556, 1.], + [0.369214, 0.788888, 0.382914, 1.], + [0., 0., 0.5, 1.], + [1., 0.59259259, 0., 1.]] ) assert np.allclose(vals, _vals) def test_truncate_colorbar(): test_points = [0.1, 0.3, 0.5, 0.7, 0.9] - + cmap = plt.get_cmap('viridis', 32).truncate(0.2, 0.7) vals = cmap(test_points) _vals = np.array( - [[0.243113, 0.292092, 0.538516, 1. ], - [0.19586, 0.395433, 0.555276, 1. ], - [0.144759, 0.519093, 0.556572, 1. ], - [0.12478, 0.640461, 0.527068, 1. ], - [0.226397, 0.728888, 0.462789, 1. ]] + [[0.243113, 0.292092, 0.538516, 1.], + [0.19586, 0.395433, 0.555276, 1.], + [0.144759, 0.519093, 0.556572, 1.], + [0.12478, 0.640461, 0.527068, 1.], + [0.226397, 0.728888, 0.462789, 1.]] ) assert np.allclose(vals, _vals) - cmap = plt.get_cmap('viridis', 128)[0.2:-0.3:16 * 1j] + cmap = plt.get_cmap('viridis', 128)[0.2:-0.3:16j] vals = cmap(test_points) _vals = np.array( - [[0.241237, 0.296485, 0.539709, 1. ], - [0.192357, 0.403199, 0.555836, 1. ], - [0.140536, 0.530132, 0.555659, 1. ], - [0.12138, 0.629492, 0.531973, 1. ], - [0.214, 0.722114, 0.469588, 1. ]] - ) + [[0.241237, 0.296485, 0.539709, 1.], + [0.192357, 0.403199, 0.555836, 1.], + [0.140536, 0.530132, 0.555659, 1.], + [0.12138, 0.629492, 0.531973, 1.], + [0.214, 0.722114, 0.469588, 1.]] + ) assert np.allclose(vals, _vals) cmap = plt.get_cmap('viridis', 128)[25:90] vals = cmap(test_points) _vals = np.array( - [[0.233603, 0.313828, 0.543914, 1. ], - [0.185556, 0.41857, 0.556753, 1. ], - [0.14618, 0.515413, 0.556823, 1. ], - [0.119483, 0.614817, 0.537692, 1. ], - [0.19109, 0.708366, 0.482284, 1. ]] - ) + [[0.233603, 0.313828, 0.543914, 1.], + [0.185556, 0.41857, 0.556753, 1.], + [0.14618, 0.515413, 0.556823, 1.], + [0.119483, 0.614817, 0.537692, 1.], + [0.19109, 0.708366, 0.482284, 1.]] + ) assert np.allclose(vals, _vals) - - cmap = plt.get_cmap('viridis', 128)[25:90:16 * 1j] + + cmap = plt.get_cmap('viridis', 128)[25:90:16j] vals = cmap(test_points) _vals = np.array( - [[0.241237, 0.296485, 0.539709, 1. ], - [0.192357, 0.403199, 0.555836, 1. ], - [0.140536, 0.530132, 0.555659, 1. ], - [0.12138, 0.629492, 0.531973, 1. ], - [0.214, 0.722114, 0.469588, 1. ]] - ) + [[0.241237, 0.296485, 0.539709, 1.], + [0.192357, 0.403199, 0.555836, 1.], + [0.140536, 0.530132, 0.555659, 1.], + [0.12138, 0.629492, 0.531973, 1.], + [0.214, 0.722114, 0.469588, 1.]] + ) assert np.allclose(vals, _vals) From 17e576e97ea1db3815c0e8a7aa378ad2a5c8812d Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Fri, 18 May 2018 20:22:30 -0600 Subject: [PATCH 16/17] Increase coverage. --- lib/matplotlib/colors.py | 4 +- lib/matplotlib/tests/test_colorbar.py | 79 +++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 1c4464694363..d38e7282d87c 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -833,7 +833,7 @@ def __getitem__(self, item): sss[1] += 1 if sss[2] is None: sss[2] = self.N * 1j * (sss[1] - sss[0]) - else: + elif all([s is None or abs(s) > 1 for s in sss[:2]]): # This is an integer-style itemization if sss[0] is None: sss[0] = 0 @@ -852,6 +852,8 @@ def __getitem__(self, item): if sss[0] < 0 or sss[0] >= 1 or sss[1] <= 0 or sss[1] > 1: raise IndexError("Invalid colorbar itemization - outside " "bounds") + else: + raise IndexError("Invalid colorbar itemization") points = np.mgrid[slice(*sss)] elif isinstance(item, (list, np.ndarray)): name = self.name + '[]' diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py index c3a5a1852282..e6fa747e7859 100644 --- a/lib/matplotlib/tests/test_colorbar.py +++ b/lib/matplotlib/tests/test_colorbar.py @@ -4,7 +4,7 @@ from matplotlib import rc_context from matplotlib.testing.decorators import image_comparison import matplotlib.pyplot as plt -from matplotlib.colors import BoundaryNorm, LogNorm +from matplotlib.colors import BoundaryNorm, LogNorm, join_colormaps from matplotlib.cm import get_cmap from matplotlib.colorbar import ColorbarBase @@ -219,11 +219,25 @@ def test_join_colorbar(): ) assert np.allclose(vals, _vals) + # +code-coverage for name kwarg and when fractions is unspecified + cmap = join_colormaps([cmap1, cmap2, cmap1], name='test-map') + vals = cmap(test_points) + _vals = np.array( + [[0.229739, 0.322361, 0.545706, 1., ], + [0.993248, 0.906157, 0.143936, 1., ], + [0.48387097, 1., 0.48387097, 1., ], + [0.267004, 0.004874, 0.329415, 1., ], + [0.369214, 0.788888, 0.382914, 1., ]] + ) + assert np.allclose(vals, _vals) + def test_truncate_colorbar(): test_points = [0.1, 0.3, 0.5, 0.7, 0.9] + vir32 = plt.get_cmap('viridis', 32) + vir128 = plt.get_cmap('viridis', 128) - cmap = plt.get_cmap('viridis', 32).truncate(0.2, 0.7) + cmap = vir32.truncate(0.2, 0.7) vals = cmap(test_points) _vals = np.array( [[0.243113, 0.292092, 0.538516, 1.], @@ -234,7 +248,20 @@ def test_truncate_colorbar(): ) assert np.allclose(vals, _vals) - cmap = plt.get_cmap('viridis', 128)[0.2:-0.3:16j] + # +code-coverage + cmap = vir32.truncate(0.2, 0.7, name='test-map', N=128) + vals = cmap(test_points) + _vals = np.array( + [[0.243113, 0.292092, 0.538516, 1., ], + [0.182256, 0.426184, 0.55712, 1., ], + [0.144759, 0.519093, 0.556572, 1., ], + [0.119423, 0.611141, 0.538982, 1., ], + [0.180653, 0.701402, 0.488189, 1., ]] + ) + assert np.allclose(vals, _vals) + + # Use __getitem__ fractional complex slicing + cmap = vir128[0.2:-0.3:16j] vals = cmap(test_points) _vals = np.array( [[0.241237, 0.296485, 0.539709, 1.], @@ -245,7 +272,8 @@ def test_truncate_colorbar(): ) assert np.allclose(vals, _vals) - cmap = plt.get_cmap('viridis', 128)[25:90] + # Use __getitem__ fractional integer slicing + cmap = vir128[25:90] vals = cmap(test_points) _vals = np.array( [[0.233603, 0.313828, 0.543914, 1.], @@ -256,7 +284,8 @@ def test_truncate_colorbar(): ) assert np.allclose(vals, _vals) - cmap = plt.get_cmap('viridis', 128)[25:90:16j] + # Use __getitem__ integer complex slicing + cmap = vir128[25:90:16j] vals = cmap(test_points) _vals = np.array( [[0.241237, 0.296485, 0.539709, 1.], @@ -267,6 +296,46 @@ def test_truncate_colorbar(): ) assert np.allclose(vals, _vals) + # Use __getitem__ discrete slicing + cmap = vir128[[10, 12, 15, 35, 60, 97]] + vals = cmap(test_points) + _vals = np.array( + [[0.283197, 0.11568, 0.436115, 1., ], + [0.282884, 0.13592, 0.453427, 1., ], + [0.21813, 0.347432, 0.550038, 1., ], + [0.13777, 0.537492, 0.554906, 1., ], + [0.395174, 0.797475, 0.367757, 1., ]] + ) + assert np.allclose(vals, _vals) + + +def test_truncate_colorbar_fail(): + vir128 = plt.get_cmap('viridis', 128) + + with pytest.raises(ValueError, match='less than'): + vir128.truncate(0.7, 0.3) + + with pytest.raises(ValueError, match='not a truncation'): + vir128.truncate(0, 1) + + with pytest.raises(ValueError, match='interval'): + vir128.truncate(0.3, 1.1) + + with pytest.raises(ValueError, match='interval'): + vir128.truncate(-0.1, 0.7) + + with pytest.raises(IndexError, match='must contain >1 color'): + vir128[[3]] + + with pytest.raises(IndexError, match='Invalid colorbar itemization'): + # Tuple indexing of colorbars not allowed. + vir128[3, 5, 9] + + with pytest.raises(IndexError, match='Invalid colorbar itemization'): + # Currently you can't mix-match fractional and int style indexing. + # This could be changed... + vir128[0.3:100] + @image_comparison(baseline_images=['colorbar_single_scatter'], extensions=['png'], remove_text=True, From 9caba24244f4908fa4896d2e2cd010a771d1f47c Mon Sep 17 00:00:00 2001 From: Levi Kilcher Date: Sat, 19 May 2018 20:25:28 -0600 Subject: [PATCH 17/17] Test: 100% coverage! --- lib/matplotlib/colors.py | 2 +- lib/matplotlib/tests/test_colorbar.py | 72 +++++++++++++++------------ 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index d38e7282d87c..2135df32d51a 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -833,7 +833,7 @@ def __getitem__(self, item): sss[1] += 1 if sss[2] is None: sss[2] = self.N * 1j * (sss[1] - sss[0]) - elif all([s is None or abs(s) > 1 for s in sss[:2]]): + elif all([s is None or (s % 1 == 0) for s in sss[:2]]): # This is an integer-style itemization if sss[0] is None: sss[0] = 0 diff --git a/lib/matplotlib/tests/test_colorbar.py b/lib/matplotlib/tests/test_colorbar.py index e6fa747e7859..ee816243d149 100644 --- a/lib/matplotlib/tests/test_colorbar.py +++ b/lib/matplotlib/tests/test_colorbar.py @@ -189,7 +189,7 @@ def test_gridspec_make_colorbar(): def test_join_colorbar(): - test_points = [0.1, 0.3, 0.5, 0.7, 0.9] + test_points = [0.1, 0.3, 0.9] # Jet is a LinearSegmentedColormap cmap1 = plt.get_cmap('viridis', 5) @@ -201,8 +201,6 @@ def test_join_colorbar(): _vals = np.array( [[0.229739, 0.322361, 0.545706, 1.], [0.369214, 0.788888, 0.382914, 1.], - [0., 0., 0.5, 1.], - [0.48387097, 1., 0.48387097, 1.], [0.5, 0., 0, 1.]] ) assert np.allclose(vals, _vals) @@ -213,8 +211,6 @@ def test_join_colorbar(): _vals = np.array( [[0.267004, 0.004874, 0.329415, 1.], [0.127568, 0.566949, 0.550556, 1.], - [0.369214, 0.788888, 0.382914, 1.], - [0., 0., 0.5, 1.], [1., 0.59259259, 0., 1.]] ) assert np.allclose(vals, _vals) @@ -225,15 +221,13 @@ def test_join_colorbar(): _vals = np.array( [[0.229739, 0.322361, 0.545706, 1., ], [0.993248, 0.906157, 0.143936, 1., ], - [0.48387097, 1., 0.48387097, 1., ], - [0.267004, 0.004874, 0.329415, 1., ], [0.369214, 0.788888, 0.382914, 1., ]] ) assert np.allclose(vals, _vals) def test_truncate_colorbar(): - test_points = [0.1, 0.3, 0.5, 0.7, 0.9] + test_points = [0.1, 0.3, 0.9] vir32 = plt.get_cmap('viridis', 32) vir128 = plt.get_cmap('viridis', 128) @@ -242,57 +236,67 @@ def test_truncate_colorbar(): _vals = np.array( [[0.243113, 0.292092, 0.538516, 1.], [0.19586, 0.395433, 0.555276, 1.], - [0.144759, 0.519093, 0.556572, 1.], - [0.12478, 0.640461, 0.527068, 1.], [0.226397, 0.728888, 0.462789, 1.]] ) assert np.allclose(vals, _vals) - # +code-coverage + # +code-coverage: N and name kwargs cmap = vir32.truncate(0.2, 0.7, name='test-map', N=128) vals = cmap(test_points) _vals = np.array( [[0.243113, 0.292092, 0.538516, 1., ], [0.182256, 0.426184, 0.55712, 1., ], - [0.144759, 0.519093, 0.556572, 1., ], - [0.119423, 0.611141, 0.538982, 1., ], [0.180653, 0.701402, 0.488189, 1., ]] ) assert np.allclose(vals, _vals) - # Use __getitem__ fractional complex slicing - cmap = vir128[0.2:-0.3:16j] + # Use __getitem__ fractional complex slicing with start:None + cmap = vir128[:-0.3:16j] + vals = cmap(test_points) + _vals = np.array( + [[0.278791, 0.062145, 0.386592, 1., ], + [0.262138, 0.242286, 0.520837, 1., ], + [0.19109, 0.708366, 0.482284, 1., ]] + ) + assert np.allclose(vals, _vals) + + # Use __getitem__ fractional slicing start:negative, end:None + cmap = vir128[-0.9:] vals = cmap(test_points) _vals = np.array( - [[0.241237, 0.296485, 0.539709, 1.], - [0.192357, 0.403199, 0.555836, 1.], - [0.140536, 0.530132, 0.555659, 1.], - [0.12138, 0.629492, 0.531973, 1.], - [0.214, 0.722114, 0.469588, 1.]] + [[0.262138, 0.242286, 0.520837, 1., ], + [0.175841, 0.44129, 0.557685, 1., ], + [0.772852, 0.877868, 0.131109, 1., ]] ) assert np.allclose(vals, _vals) - # Use __getitem__ fractional integer slicing + # Use __getitem__ integer slicing cmap = vir128[25:90] vals = cmap(test_points) _vals = np.array( [[0.233603, 0.313828, 0.543914, 1.], [0.185556, 0.41857, 0.556753, 1.], - [0.14618, 0.515413, 0.556823, 1.], - [0.119483, 0.614817, 0.537692, 1.], [0.19109, 0.708366, 0.482284, 1.]] ) assert np.allclose(vals, _vals) + # start:None, end:negative, integer jumping + cmap = vir128[:-10:4] + vals = cmap(test_points) + _vals = np.array( + [[0.282884, 0.13592, 0.453427, 1., ], + [0.214298, 0.355619, 0.551184, 1., ], + [0.606045, 0.850733, 0.236712, 1., ]] + ) + assert np.allclose(vals, _vals) + # Use __getitem__ integer complex slicing - cmap = vir128[25:90:16j] + cmap = vir128[-100::16j] vals = cmap(test_points) _vals = np.array( - [[0.241237, 0.296485, 0.539709, 1.], - [0.192357, 0.403199, 0.555836, 1.], - [0.140536, 0.530132, 0.555659, 1.], - [0.12138, 0.629492, 0.531973, 1.], - [0.214, 0.722114, 0.469588, 1.]] + [[0.221989, 0.339161, 0.548752, 1., ], + [0.154815, 0.493313, 0.55784, 1., ], + [0.876168, 0.891125, 0.09525, 1., ]] ) assert np.allclose(vals, _vals) @@ -302,8 +306,6 @@ def test_truncate_colorbar(): _vals = np.array( [[0.283197, 0.11568, 0.436115, 1., ], [0.282884, 0.13592, 0.453427, 1., ], - [0.21813, 0.347432, 0.550038, 1., ], - [0.13777, 0.537492, 0.554906, 1., ], [0.395174, 0.797475, 0.367757, 1., ]] ) assert np.allclose(vals, _vals) @@ -336,6 +338,14 @@ def test_truncate_colorbar_fail(): # This could be changed... vir128[0.3:100] + with pytest.raises(IndexError, match='Invalid colorbar itemization'): + # 150 is beyond the 128-bit colormap. + vir128[[10, 100, 150]] + + with pytest.raises(IndexError, match='Invalid colorbar itemization'): + # The first index can't be the end. + vir128[128:] + @image_comparison(baseline_images=['colorbar_single_scatter'], extensions=['png'], remove_text=True,