| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent d28cbf2 commit 1a9dacf
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,8 @@ | |||
| 1 | + Raise or warn on registering a colormap twice | ||
| 2 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 3 | + | ||
| 4 | + When using `matplotlib.cm.register_cmap` to register a user provided | ||
| 5 | + or third-party colormap it will now raise a `ValueError` if trying to | ||
| 6 | + over-write one of the built in colormaps and warn if trying to over | ||
| 7 | + write a user registered colormap. This may raise for user-registered | ||
| 8 | + colormaps in the future. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,6 @@ | |||
| 1 | + | ||
| 2 | + Add ``cm.unregister_cmap`` function | ||
| 3 | + ----------------------------------- | ||
| 4 | + | ||
| 5 | + `.cm.unregister_cmap` allows users to remove a colormap that they | ||
| 6 | + have previously registered. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,6 +24,7 @@ | |||
| 24 | 24 | from matplotlib import _api, colors, cbook | |
| 25 | 25 | from matplotlib._cm import datad | |
| 26 | 26 | from matplotlib._cm_listed import cmaps as cmaps_listed | |
| 27 | + from matplotlib.cbook import _warn_external | ||
| 27 | 28 | ||
| 28 | 29 | ||
| 29 | 30 | LUTSIZE = mpl.rcParams['image.lut'] | |
@@ -95,12 +96,12 @@ def _warn_deprecated(self): | |||
| 95 | 96 | locals().update(_cmap_registry) | |
| 96 | 97 | # This is no longer considered public API | |
| 97 | 98 | cmap_d = _DeprecatedCmapDictWrapper(_cmap_registry) | |
| 98 | - | ||
| 99 | + __builtin_cmaps = tuple(_cmap_registry) | ||
| 99 | 100 | ||
| 100 | 101 | # Continue with definitions ... | |
| 101 | 102 | ||
| 102 | 103 | ||
| 103 | - def register_cmap(name=None, cmap=None): | ||
| 104 | + def register_cmap(name=None, cmap=None, *, override_builtin=False): | ||
| 104 | 105 | """ | |
| 105 | 106 | Add a colormap to the set recognized by :func:`get_cmap`. | |
| 106 | 107 | ||
@@ -121,13 +122,20 @@ def register_cmap(name=None, cmap=None): | |||
| 121 | 122 | Despite being the second argument and having a default value, this | |
| 122 | 123 | is a required argument. | |
| 123 | 124 | ||
| 125 | + override_builtin : bool | ||
| 126 | + | ||
| 127 | + Allow built-in colormaps to be overridden by a user-supplied | ||
| 128 | + colormap. | ||
| 129 | + | ||
| 130 | + Please do not use this unless you are sure you need it. | ||
| 124 | 131 | ||
| 125 | 132 | Notes | |
| 126 | 133 | ----- | |
| 127 | 134 | Registering a colormap stores a reference to the colormap object | |
| 128 | 135 | which can currently be modified and inadvertantly change the global | |
| 129 | 136 | colormap state. This behavior is deprecated and in Matplotlib 3.5 | |
| 130 | 137 | the registered colormap will be immutable. | |
| 138 | + | ||
| 131 | 139 | """ | |
| 132 | 140 | cbook._check_isinstance((str, None), name=name) | |
| 133 | 141 | if name is None: | |
@@ -136,10 +144,18 @@ def register_cmap(name=None, cmap=None): | |||
| 136 | 144 | except AttributeError as err: | |
| 137 | 145 | raise ValueError("Arguments must include a name or a " | |
| 138 | 146 | "Colormap") from err | |
| 147 | + if name in _cmap_registry: | ||
| 148 | + if not override_builtin and name in __builtin_cmaps: | ||
| 149 | + msg = f"Trying to re-register the builtin cmap {name!r}." | ||
| 150 | + raise ValueError(msg) | ||
| 151 | + else: | ||
| 152 | + msg = f"Trying to register the cmap {name!r} which already exists." | ||
| 153 | + _warn_external(msg) | ||
| 139 | 154 | ||
| 140 | 155 | if not isinstance(cmap, colors.Colormap): | |
| 141 | 156 | raise ValueError("You must pass a Colormap instance. " | |
| 142 | 157 | f"You passed {cmap} a {type(cmap)} object.") | |
| 158 | + | ||
| 143 | 159 | cmap._global = True | |
| 144 | 160 | _cmap_registry[name] = cmap | |
| 145 | 161 | return | |
@@ -179,6 +195,47 @@ def get_cmap(name=None, lut=None): | |||
| 179 | 195 | return _cmap_registry[name]._resample(lut) | |
| 180 | 196 | ||
| 181 | 197 | ||
| 198 | + def unregister_cmap(name): | ||
| 199 | + """ | ||
| 200 | + Remove a colormap recognized by :func:`get_cmap`. | ||
| 201 | + | ||
| 202 | + You may not remove built-in colormaps. | ||
| 203 | + | ||
| 204 | + If the named colormap is not registered, returns with no error, raises | ||
| 205 | + if you try to de-register a default colormap. | ||
| 206 | + | ||
| 207 | + .. warning :: | ||
| 208 | + | ||
| 209 | + Colormap names are currently a shared namespace that may be used | ||
| 210 | + by multiple packages. Use `unregister_cmap` only if you know you | ||
| 211 | + have registered that name before. In particular, do not | ||
| 212 | + unregister just in case to clean the name before registering a | ||
| 213 | + new colormap. | ||
| 214 | + | ||
| 215 | + Parameters | ||
| 216 | + ---------- | ||
| 217 | + name : str | ||
| 218 | + The name of the colormap to be un-registered | ||
| 219 | + | ||
| 220 | + Returns | ||
| 221 | + ------- | ||
| 222 | + ColorMap or None | ||
| 223 | + If the colormap was registered, return it if not return `None` | ||
| 224 | + | ||
| 225 | + Raises | ||
| 226 | + ------ | ||
| 227 | + ValueError | ||
| 228 | + If you try to de-register a default built-in colormap. | ||
| 229 | + | ||
| 230 | + """ | ||
| 231 | + if name not in _cmap_registry: | ||
| 232 | + return | ||
| 233 | + if name in __builtin_cmaps: | ||
| 234 | + raise ValueError(f"cannot unregister {name!r} which is a builtin " | ||
| 235 | + "colormap.") | ||
| 236 | + return _cmap_registry.pop(name) | ||
| 237 | + | ||
| 238 | + | ||
| 182 | 239 | class ScalarMappable: | |
| 183 | 240 | """ | |
| 184 | 241 | A mixin class to map scalar data to RGBA. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -64,18 +64,45 @@ def test_resample(): | |||
| 64 | 64 | ||
| 65 | 65 | ||
| 66 | 66 | def test_register_cmap(): | |
| 67 | - new_cm = copy.copy(plt.cm.viridis) | ||
| 68 | - cm.register_cmap('viridis2', new_cm) | ||
| 69 | - assert plt.get_cmap('viridis2') == new_cm | ||
| 67 | + new_cm = copy.copy(cm.get_cmap("viridis")) | ||
| 68 | + target = "viridis2" | ||
| 69 | + cm.register_cmap(target, new_cm) | ||
| 70 | + assert plt.get_cmap(target) == new_cm | ||
| 70 | 71 | ||
| 71 | 72 | with pytest.raises(ValueError, | |
| 72 | - match='Arguments must include a name or a Colormap'): | ||
| 73 | + match="Arguments must include a name or a Colormap"): | ||
| 73 | 74 | cm.register_cmap() | |
| 74 | 75 | ||
| 76 | + with pytest.warns(UserWarning): | ||
| 77 | + cm.register_cmap(target, new_cm) | ||
| 78 | + | ||
| 79 | + cm.unregister_cmap(target) | ||
| 80 | + with pytest.raises(ValueError, | ||
| 81 | + match=f'{target!r} is not a valid value for name;'): | ||
| 82 | + cm.get_cmap(target) | ||
| 83 | + # test that second time is error free | ||
| 84 | + cm.unregister_cmap(target) | ||
| 85 | + | ||
| 75 | 86 | with pytest.raises(ValueError, match="You must pass a Colormap instance."): | |
| 76 | 87 | cm.register_cmap('nome', cmap='not a cmap') | |
| 77 | 88 | ||
| 78 | 89 | ||
| 90 | + def test_double_register_builtin_cmap(): | ||
| 91 | + name = "viridis" | ||
| 92 | + match = f"Trying to re-register the builtin cmap {name!r}." | ||
| 93 | + with pytest.raises(ValueError, match=match): | ||
| 94 | + cm.register_cmap(name, cm.get_cmap(name)) | ||
| 95 | + with pytest.warns(UserWarning): | ||
| 96 | + cm.register_cmap(name, cm.get_cmap(name), override_builtin=True) | ||
| 97 | + | ||
| 98 | + | ||
| 99 | + def test_unregister_builtin_cmap(): | ||
| 100 | + name = "viridis" | ||
| 101 | + match = f'cannot unregister {name!r} which is a builtin colormap.' | ||
| 102 | + with pytest.raises(ValueError, match=match): | ||
| 103 | + cm.unregister_cmap(name) | ||
| 104 | + | ||
| 105 | + | ||
| 79 | 106 | def test_colormap_global_set_warn(): | |
| 80 | 107 | new_cm = plt.get_cmap('viridis') | |
| 81 | 108 | # Store the old value so we don't override the state later on. | |
@@ -97,7 +124,8 @@ def test_colormap_global_set_warn(): | |||
| 97 | 124 | new_cm.set_under('k') | |
| 98 | 125 | ||
| 99 | 126 | # Re-register the original | |
| 100 | - plt.register_cmap(cmap=orig_cmap) | ||
| 127 | + with pytest.warns(UserWarning): | ||
| 128 | + plt.register_cmap(cmap=orig_cmap, override_builtin=True) | ||
| 101 | 129 | ||
| 102 | 130 | ||
| 103 | 131 | def test_colormap_dict_deprecate(): | |
| Back | FazBrowse Home | New Git URL |
0 commit comments