holoviz / colorcet

A set of useful perceptually uniform colormaps for plotting scientific data
http://colorcet.holoviz.org
Other
673 stars 52 forks source link

ValueError: A colormap named "cet_gray" is already registered #96

Closed yannikschaelte closed 1 year ago

yannikschaelte commented 1 year ago

ALL software version info

colorcet 3.0.1 arviz 0.12.1 python 3.10/8 matplotlib 3.6.0/1 afaik introduced with recent colorcet/matplotlib release

Description of expected behavior and the observed behavior

When multiple libraries use mpl.colormaps.register(cmap, name=cmap_name) with the same cmap_name, a ValueError: A colormap named "cet_gray" is already registered. is raised. This happens e.g. for colorcet + arviz, both of which define cet_gray (see here for arviz).

What is the desired behavior -- does colorcet want to assume control of that color name, preventing others from accidentally overriding it (in which case arviz, which intends to duplicate the colorcet color, would be responsible)? Or should simultaneous overriding of the global variable be allowed.

Complete, minimal, self-contained example code that reproduces the issue

import arviz
import colorcet

or

import colorcet
import arviz

This prohibits the use of both simultaneously.

Stack traceback and/or browser JavaScript console output

 Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/yannik/env/env/lib/python3.10/site-packages/arviz/__init__.py", line 320, in <module>
    _mpl_cm("gray", _linear_grey_10_95_c0)
  File "/home/yannik/env/env/lib/python3.10/site-packages/arviz/__init__.py", line 317, in _mpl_cm
    register_cmap("cet_" + name, cmap=cmap)
  File "/home/yannik/env/env/lib/python3.10/site-packages/matplotlib/_api/deprecation.py", line 200, in wrapper
    return func(*args, **kwargs)
  File "/home/yannik/env/env/lib/python3.10/site-packages/matplotlib/cm.py", line 248, in register_cmap
    _colormaps.register(cmap, name=name, force=override_builtin)
  File "/home/yannik/env/env/lib/python3.10/site-packages/matplotlib/cm.py", line 149, in register
    raise ValueError(
ValueError: A colormap named "cet_gray" is already registered.
yannikschaelte commented 1 year ago

Maybe solved in arviz side --> https://github.com/arviz-devs/arviz/issues/2135

hoxbro commented 1 year ago

Awesome. I would also like to handle this on our site, so please don't close the issue. :slightly_smiling_face:

ColCarroll commented 1 year ago

👋 from arviz -- does it make sense to just catch ValueErrors and either re-emit them as a warning or silently skip? I guess a "better" answer would be to ask matplotlib to emit a more specific warning...

hoxbro commented 1 year ago

I would probably do something like the following. 1) Check if colormap exists 2) If colormap exists, check if the cmap is identical. 3) If not identical, give a warning and replace. I assume this is how it worked before.

jbednar commented 1 year ago

It looks like this conflict occurs because arviz has borrowed the cet_gray colormap definition from colorcet and registered that using the same name as in colorcet. That approach makes sense if arviz relies on that particular map but does not want to add a colorcet dependency. If that indeed that is the goal, what I would suggest is that arviz should try/except attempt to import colorcet, and then only register its internal version of cet_gray if colorcet cannot be imported. The advantage of this approach over alternatives is that (a) it avoids depending on import order, and (b) there is never any ambiguity about where the colormap came from, in the obscure case that somehow colorcet were to update the definition in a new release, and (c) the actual colormap Python list object will be the same for any code running in that process.

If instead either arviz or colorcet avoids the error by first checking if the map was previously registered, then where the map actually comes from will depend on the import order, and it may or may not be the same Python object if accessed via colorcet, arviz, or matplotlib, which mostly won't matter but could cause some weird UI bugs.

If arviz wanted to add an additional check that the colormap is identical, that's reasonable, but I don't think colorcet should be checking that or looking for conflicts, because this is a map that fundamentally comes from colorcet, and I think colorcet should be able to simply define it as it always does.

alexdesiqueira commented 1 year ago

Hey everyone, when trying to import itkwidgets I get a related error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In [55], line 2
      1 import itk
----> 2 from itkwidgets import view

File ~/mambaforge/envs/dataumbrella_skimage/lib/python3.8/site-packages/itkwidgets/__init__.py:13
      1 __all__ = ['version_info', '__version__',
      2            'Viewer', 'view',
      3            'checkerboard',
   (...)
      8            'lut',
      9            '_jupyter_nbextension_paths']
     11 from ._version import version_info, __version__
---> 13 from .widget_viewer import Viewer, view
     14 from .widget_compare import compare
     15 from .widget_checkerboard import checkerboard

File ~/mambaforge/envs/dataumbrella_skimage/lib/python3.8/site-packages/itkwidgets/widget_viewer.py:8
      1 """Viewer class
      2 
      3 Visualization of an image.
      4 
      5 In the future, will add optional segmentation mesh overlay.
      6 """
----> 8 import colorcet
      9 import matplotlib
     10 import collections

File ~/mambaforge/envs/dataumbrella_skimage/lib/python3.8/site-packages/colorcet/__init__.py:335
     76 cyclic_grey_15_85_c0 = [\
     77 [0.46877, 0.46888, 0.46885],
     78 [0.47381, 0.47391, 0.47389],
   (...)
    332 [0.46374, 0.46385, 0.46382],
    333 ]
    334 b_cyclic_grey_15_85_c0 = bokeh_palette('cyclic_grey_15_85_c0',cyclic_grey_15_85_c0)
--> 335 m_cyclic_grey_15_85_c0 = mpl_cm('cyclic_grey_15_85_c0',cyclic_grey_15_85_c0)
    336 m_cyclic_grey_15_85_c0_r = mpl_cm('cyclic_grey_15_85_c0_r',list(reversed(cyclic_grey_15_85_c0)))
    341 cyclic_grey_15_85_c0_s25 = [\
    342 [0.17676, 0.17681, 0.1768],
    343 [0.1775, 0.17755, 0.17754],
   (...)
    597 [0.17656, 0.1766, 0.17659],
    598 ]

File ~/mambaforge/envs/dataumbrella_skimage/lib/python3.8/site-packages/colorcet/__init__.py:67, in mpl_cm(name, colorlist)
     65 def mpl_cm(name,colorlist):
     66     cm[name]      = LinearSegmentedColormap.from_list(name, colorlist, N=len(colorlist))
---> 67     register_cmap("cet_"+name, cmap=cm[name])
     68     return cm[name]

File ~/mambaforge/envs/dataumbrella_skimage/lib/python3.8/site-packages/matplotlib/_api/deprecation.py:200, in deprecated.<locals>.deprecate.<locals>.wrapper(*args, **kwargs)
    198 def wrapper(*args, **kwargs):
    199     emit_warning()
--> 200     return func(*args, **kwargs)

File ~/mambaforge/envs/dataumbrella_skimage/lib/python3.8/site-packages/matplotlib/cm.py:274, in register_cmap(name, cmap, override_builtin)
    270 # override_builtin is allowed here for backward compatibility
    271 # this is just a shim to enable that to work privately in
    272 # the global ColormapRegistry
    273 _colormaps._allow_override_builtin = override_builtin
--> 274 _colormaps.register(cmap, name=name, force=override_builtin)
    275 _colormaps._allow_override_builtin = False

File ~/mambaforge/envs/dataumbrella_skimage/lib/python3.8/site-packages/matplotlib/cm.py:143, in ColormapRegistry.register(self, cmap, name, force)
    139 if name in self:
    140     if not force:
    141         # don't allow registering an already existing cmap
    142         # unless explicitly asked to
--> 143         raise ValueError(
    144             f'A colormap named "{name}" is already registered.')
    145     elif (name in self._builtin_cmaps
    146             and not self._allow_override_builtin):
    147         # We don't allow overriding a builtin unless privately
    148         # coming from register_cmap()
    149         raise ValueError("Re-registering the builtin cmap "
    150                          f"{name!r} is not allowed.")

ValueError: A colormap named "cet_cyclic_grey_15_85_c0" is already registered.

It looks like some colormaps will clash with matplotlib ones, too.

jbednar commented 1 year ago

@alexdesiqueira , I cannot reproduce an issue from that example:

image

If you are still having issues, please open a new issue with a reproducible example, but I'll close this one as the underlying issue has been fixed in arviz.