Repository: vispy/vispy

Issue:
Some colormaps in the `get_colormaps` dictionary are not Colormap instances
If I recall correctly this was added by @larsoner. In `vispy/color/colormap.py` there is a `_colormaps` dictionary that can be accessed via the public `get_colormaps()`. However, as a user, I expect this dictionary to map colormap names to colormap instances, some of these values though are colormap classes or functions. For example, `cubehelix -> CubeHelixColormap` and `single_hue -> _SingleHue`. This is "worked around" by having the `get_colormap` function create these colormaps with optional kwargs passed to the class.

I'm not a huge fan of this so unless someone can argue for this behavior I would like to propose that we replace these non-instance colormaps with basic instances or remove them from the colormap dictionary returned from `get_colormaps`.


Discussion:
fine by me
@djhoese I can have a look early next week. 
Here is a copy of the raw dictionary:

<details>

```
_colormaps = dict(
    # Some colormap presets
    autumn=Colormap([(1., 0., 0., 1.), (1., 1., 0., 1.)]),
    blues=Colormap([(1., 1., 1., 1.), (0., 0., 1., 1.)]),
    cool=Colormap([(0., 1., 1., 1.), (1., 0., 1., 1.)]),
    greens=Colormap([(1., 1., 1., 1.), (0., 1., 0., 1.)]),
    reds=Colormap([(1., 1., 1., 1.), (1., 0., 0., 1.)]),
    spring=Colormap([(1., 0., 1., 1.), (1., 1., 0., 1.)]),
    summer=Colormap([(0., .5, .4, 1.), (1., 1., .4, 1.)]),
    fire=_Fire(),
    grays=_Grays(),
    hot=_Hot(),
    ice=_Ice(),
    winter=_Winter(),
    light_blues=_SingleHue(),
    orange=_SingleHue(hue=35),
    viridis=Colormap(ColorArray(_viridis_data)),
    # Diverging presets
    coolwarm=Colormap(ColorArray(
        [
            (226, 0.59, 0.92), (222, 0.44, 0.99), (218, 0.26, 0.97),
            (30, 0.01, 0.87),
            (20, 0.3, 0.96), (15, 0.5, 0.95), (8, 0.66, 0.86)
        ],
        color_space="hsv"
    )),
    PuGr=_Diverging(145, 280, 0.85, 0.30),
    GrBu=_Diverging(255, 133, 0.75, 0.6),
    GrBu_d=_Diverging(255, 133, 0.75, 0.6, "dark"),
    RdBu=_Diverging(220, 20, 0.75, 0.5),

    # Configurable colormaps
    cubehelix=CubeHelixColormap,
    single_hue=_SingleHue,
    hsl=_HSL,
    husl=_HUSL,
    diverging=_Diverging,
    RdYeBuCy=_RedYellowBlueCyan,
)
```

</details>


And visuals like `ImageVisual` typically run `get_colormap(cmap)` when a user does `my_img.cmap = 'cubehelix'` which will automatically generate the *instance* of the colormap.
I've a suggestion. If the colormap is not in the `_colormaps` dictionary and if matplotlib is installed, it might be interesting to build the colormap with Matplotlib? Something like :

```python
if (cmap not in _colormaps) and has_mpl:
    from matplotlib import cm
    # Get the list of implemented colormaps in Matplotlib :
    full_mpl_cmaps = list(cm.datad.keys()) + list(cm.cmaps_listed.keys())
    if cmap not in full_mpl_cmaps:
        raise ValueError("%s colormap not in matplotlib" % cmap)
    
    sc = cm.ScalarMappable(cmap=cmap)
    x = np.arange(256)
    cmap_vec = np.array(sc.to_rgba(x, alpha=1.))
    return Colormap(cmap_vec)
```
@EtienneCmb Now that vispy supports texture-based colormaps this should be a lot easier. If you want to make a pull request for this I'd be ok with that. If mpl colormaps need more than 256 colors we can do that too (ex. viridis).

Resolving patch:
diff --git a/vispy/color/colormap.py b/vispy/color/colormap.py
--- a/vispy/color/colormap.py
+++ b/vispy/color/colormap.py
@@ -3,7 +3,6 @@
 # Distributed under the (new) BSD License. See LICENSE.txt for more info.
 
 from __future__ import division  # just to be safe...
-import inspect
 import warnings
 
 import numpy as np
@@ -607,7 +606,7 @@ def map(self, t):
                            np.sqrt(t))
 
 
-class _SingleHue(Colormap):
+class SingleHue(Colormap):
     """A colormap which is solely defined by the given hue and value.
 
     Given the color hue and value, this color map increases the saturation
@@ -643,10 +642,10 @@ def __init__(self, hue=200, saturation_range=[0.1, 0.8], value=1.0):
             (hue, saturation_range[0], value),
             (hue, saturation_range[1], value)
         ], color_space='hsv')
-        super(_SingleHue, self).__init__(colors)
+        super(SingleHue, self).__init__(colors)
 
 
-class _HSL(Colormap):
+class HSL(Colormap):
     """A colormap which is defined by n evenly spaced points in a circular color space.
 
     This means that we change the hue value while keeping the
@@ -685,11 +684,11 @@ def __init__(self, ncolors=6, hue_start=0, saturation=1.0, value=1.0,
         colors = ColorArray([(hue, saturation, value) for hue in hues],
                             color_space='hsv')
 
-        super(_HSL, self).__init__(colors, controls=controls,
-                                   interpolation=interpolation)
+        super(HSL, self).__init__(colors, controls=controls,
+                                  interpolation=interpolation)
 
 
-class _HSLuv(Colormap):
+class HSLuv(Colormap):
     """A colormap which is defined by n evenly spaced points in the HSLuv space.
 
     Parameters
@@ -733,19 +732,19 @@ def __init__(self, ncolors=6, hue_start=0, saturation=1.0, value=0.7,
             [hsluv_to_rgb([hue, saturation, value]) for hue in hues],
         )
 
-        super(_HSLuv, self).__init__(colors, controls=controls,
-                                     interpolation=interpolation)
+        super(HSLuv, self).__init__(colors, controls=controls,
+                                    interpolation=interpolation)
 
 
-class _HUSL(_HSLuv):
+class _HUSL(HSLuv):
     """Deprecated."""
 
     def __init__(self, *args, **kwargs):
-        warnings.warn("_HUSL Colormap is deprecated. Please use '_HSLuv' instead.")
+        warnings.warn("_HUSL Colormap is deprecated. Please use 'HSLuv' instead.")
         super().__init__(*args, **kwargs)
 
 
-class _Diverging(Colormap):
+class Diverging(Colormap):
 
     def __init__(self, h_pos=20, h_neg=250, saturation=1.0, value=0.7,
                  center="light"):
@@ -759,11 +758,11 @@ def __init__(self, h_pos=20, h_neg=250, saturation=1.0, value=0.7,
 
         colors = ColorArray([start, mid, end])
 
-        super(_Diverging, self).__init__(colors)
+        super(Diverging, self).__init__(colors)
 
 
-class _RedYellowBlueCyan(Colormap):
-    """A colormap which is goes red-yellow positive and blue-cyan negative
+class RedYellowBlueCyan(Colormap):
+    """A colormap which goes red-yellow positive and blue-cyan negative
 
     Parameters
     ---------
@@ -783,7 +782,7 @@ def __init__(self, limits=(0.33, 0.66, 1.0)):
         colors = [(0., 1., 1., 1.), (0., 0., 1., 1.), (0., 0., 1., 0.),
                   (1., 0., 0., 0.), (1., 0., 0., 1.), (1., 1., 0., 1.)]
         colors = ColorArray(colors)
-        super(_RedYellowBlueCyan, self).__init__(
+        super(RedYellowBlueCyan, self).__init__(
             colors, controls=controls, interpolation='linear')
 
 
@@ -1068,8 +1067,8 @@ def __init__(self, limits=(0.33, 0.66, 1.0)):
     hot=_Hot(),
     ice=_Ice(),
     winter=_Winter(),
-    light_blues=_SingleHue(),
-    orange=_SingleHue(hue=35),
+    light_blues=SingleHue(),
+    orange=SingleHue(hue=35),
     viridis=Colormap(ColorArray(_viridis_data)),
     # Diverging presets
     coolwarm=Colormap(ColorArray(
@@ -1080,53 +1079,70 @@ def __init__(self, limits=(0.33, 0.66, 1.0)):
         ],
         color_space="hsv"
     )),
-    PuGr=_Diverging(145, 280, 0.85, 0.30),
-    GrBu=_Diverging(255, 133, 0.75, 0.6),
-    GrBu_d=_Diverging(255, 133, 0.75, 0.6, "dark"),
-    RdBu=_Diverging(220, 20, 0.75, 0.5),
-
-    # Configurable colormaps
-    cubehelix=CubeHelixColormap,
-    single_hue=_SingleHue,
-    hsl=_HSL,
-    husl=_HUSL,
-    hsluv=_HSLuv,
-    diverging=_Diverging,
-    RdYeBuCy=_RedYellowBlueCyan,
+    PuGr=Diverging(145, 280, 0.85, 0.30),
+    GrBu=Diverging(255, 133, 0.75, 0.6),
+    GrBu_d=Diverging(255, 133, 0.75, 0.6, "dark"),
+    RdBu=Diverging(220, 20, 0.75, 0.5),
+
+    cubehelix=CubeHelixColormap(),
+    single_hue=SingleHue(),
+    hsl=HSL(),
+    husl=HSLuv(),
+    diverging=Diverging(),
+    RdYeBuCy=RedYellowBlueCyan(),
 )
 
 
 def get_colormap(name, *args, **kwargs):
-    """Obtain a colormap
-    Some colormaps can have additional configuration parameters. Refer to
-    their corresponding documentation for more information.
+    """Obtain a colormap.
+
     Parameters
     ----------
     name : str | Colormap
         Colormap name. Can also be a Colormap for pass-through.
+    *args:
+        Deprecated.
+    **kwargs
+        Deprecated.
+
     Examples
     --------
         >>> get_colormap('autumn')
-        >>> get_colormap('single_hue', hue=10)
+        >>> get_colormap('single_hue')
+
+    .. versionchanged: 0.7
+
+        Additional args/kwargs are no longer accepted. Colormap classes are
+        no longer created on the fly. To create a ``cubehelix``
+        (``CubeHelixColormap``), ``single_hue`` (``SingleHue``), ``hsl``
+        (``HSL``), ``husl`` (``HSLuv``), ``diverging`` (``Diverging``), or
+        ``RdYeBuCy`` (``RedYellowBlueCyan``) colormap you must import and
+        instantiate it directly from the ``vispy.color.colormap`` module.
+
     """
+    if args or kwargs:
+        warnings.warn("Creating a Colormap instance with 'get_colormap' is "
+                      "no longer supported. No additional arguments or "
+                      "keyword arguments should be passed.", DeprecationWarning)
     if isinstance(name, BaseColormap):
-        cmap = name
-    else:
-        if not isinstance(name, str):
-            raise TypeError('colormap must be a Colormap or string name')
-        if name in _colormaps:  # vispy cmap
-            cmap = _colormaps[name]
-        elif has_matplotlib():  # matplotlib cmap
-            try:
-                cmap = MatplotlibColormap(name)
-            except ValueError:
-                raise KeyError('colormap name %s not found' % name)
-        else:
+        return name
+
+    if not isinstance(name, str):
+        raise TypeError('colormap must be a Colormap or string name')
+    if name in _colormaps:  # vispy cmap
+        cmap = _colormaps[name]
+        if name in ("cubehelix", "single_hue", "hsl", "husl", "diverging", "RdYeBuCy"):
+            warnings.warn(f"Colormap '{name}' has been deprecated. "
+                          f"Please import and create 'vispy.color.colormap.{cmap.__class__.__name__}' "
+                          "directly instead.", DeprecationWarning)
+
+    elif has_matplotlib():  # matplotlib cmap
+        try:
+            cmap = MatplotlibColormap(name)
+        except ValueError:
             raise KeyError('colormap name %s not found' % name)
-
-        if inspect.isclass(cmap):
-            cmap = cmap(*args, **kwargs)
-
+    else:
+        raise KeyError('colormap name %s not found' % name)
     return cmap
 
 


Test patch:
diff --git a/vispy/visuals/tests/test_colormap.py b/vispy/visuals/tests/test_colormap.py
--- a/vispy/visuals/tests/test_colormap.py
+++ b/vispy/visuals/tests/test_colormap.py
@@ -11,7 +11,7 @@
 from vispy.testing import (requires_application, TestingCanvas,
                            run_tests_if_main)
 from vispy.testing.image_tester import assert_image_approved
-from vispy.color import (get_colormap, Colormap)
+from vispy.color import Colormap
 
 size = (100, 100)
 
@@ -58,10 +58,12 @@ def test_colormap_discrete_nu():
 @requires_application()
 def test_colormap_single_hue():
     """Test colormap support using a single hue()"""
+    from vispy.color.colormap import SingleHue
     with TestingCanvas(size=size, bgcolor='w') as c:
         idata = np.linspace(255, 0, size[0]*size[1]).astype(np.ubyte)
         data = idata.reshape((size[0], size[1]))
-        image = Image(cmap=get_colormap('single_hue', 255),
+        cmap = SingleHue(255)
+        image = Image(cmap=cmap,
                       clim='auto', parent=c.scene)
         image.set_data(data)
         assert_image_approved(c.render(), "visuals/colormap_hue.png")
@@ -81,10 +83,12 @@ def test_colormap_coolwarm():
 @requires_application()
 def test_colormap_CubeHelix():
     """Test colormap support using cubehelix colormap in only blues"""
+    from vispy.color.colormap import CubeHelixColormap
     with TestingCanvas(size=size, bgcolor='w') as c:
         idata = np.linspace(255, 0, size[0]*size[1]).astype(np.ubyte)
         data = idata.reshape((size[0], size[1]))
-        image = Image(cmap=get_colormap('cubehelix', rot=0, start=0),
+        cmap = CubeHelixColormap(rot=0, start=0)
+        image = Image(cmap=cmap,
                       clim='auto', parent=c.scene)
         image.set_data(data)
         assert_image_approved(c.render(), "visuals/colormap_cubehelix.png")