3

I am able to plot the RGB components of some Matplotlib's colour maps with this simple Python script:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap

mapa = cm.get_cmap('viridis', 256)

R = []; G = []; B = []

ind = np.linspace(1,256,256)

for item in mapa.colors:
    R.append(item[0])
    G.append(item[1])
    B.append(item[2])
    
plt.figure(1,figsize=(8,8))

plt.plot(ind,R,'r-')
plt.plot(ind,G,'g-')
plt.plot(ind,B,'b-')

plt.xlabel('$Colour \\ index$', fontsize=16, fontname="Times")
plt.ylabel('$RGB \\ component \\ weight$', fontsize=16, fontname="Times")

plt.show()

Some, but not all. It works OK with 'viridis', but not with the notorious 'jet', or 'prism', or 'summer' colour maps. This happens because (it seems) those maps do not have the attribute 'colors':

runfile('F:/Documents/Programs/Python/Colourmap_Plot.py', wdir='F:/Documents/Programs/Python') Traceback (most recent call last):

File "F:\Documents\Programs\Python\Colourmap_Plot.py", line 37, in for item in mapa.colors:

AttributeError: 'LinearSegmentedColormap' object has no attribute 'colors'

I wonder why that happens. Shouldn't all maps be equal with regard to their structure? How could I tell maps that do have the 'colors' attribute from the ones that haven't? And finally, how to plot the components from one of those 'non-conforming' maps?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
  • Works fine for me provided I import `matplotlib` and write `mapa = matplotlib.cm.get_cmap(...` – Andrew Swann Dec 18 '19 at 15:39
  • My bad, I posted a wrong version of the script. The original one has a "from matplotlib import cm" line which I simply deleted for no apparent reason. I'm posting a corrected version. – Fausto Arinos Barbuto Dec 18 '19 at 16:00
  • See also this tutorial: https://matplotlib.org/3.1.1/tutorials/colors/colormap-manipulation.html – Jody Klymak Dec 18 '19 at 16:39
  • @Jody Klymak, that tutorial is exactly from where I started. But I didn't read 'till the end and that perhaps made a difference. I will give it a closer look later. Thanks. – Fausto Arinos Barbuto Dec 18 '19 at 21:26

1 Answers1

4

There are two types of colormaps in matplotlib

  • ListedColormaps
  • LinearSegmentedColormaps

ListedColormaps are basically a list of colors. You get the number of colors via cmap.N and you get the colors themselves via cmap.colors.

LinearSegmentedColormaps are defined by interpolation. They store some sampling points in a dictionary and may interpolate between those, depending on the number of colors needed. The current number of colors is equally accessible via cmap.N.

Shouldn't all maps be equal with regard to their structure?

I guess they should. At least LinearSegmentedColormaps should expose a .colors attribute as well.

How could I tell maps that do have the 'colors' attribute from the ones that haven't?

You can to type or instance comparisson.

if isinstance(cmap, matplotlib.colors.LinearSegmentedColormap):
    # do something
    print("Is a segmented map")
elif isinstance(cmap, matplotlib.colors.ListedColormap):
    # do something else
    print("Is a listed map")

You can also check if the attribute exists,

if hasattr(cmap, "colors"):
    print("Is a listed map")
else:
    print("Is either not a colormap, or is a segmented one.")

And finally, how to plot the components from one of those 'non-conforming' maps?

A possible option to get the colors from a colormap, independent of their type would be to call the colormap with a list/array of integers, effectively indexing all colors up to cmap.N:

colors = cmap(np.arange(0,cmap.N)) 

colors is now a N by 4 shaped array of RGBA colors of the map.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • There is a third kind of map, if I'm not mistaken. tab10 seems to be one of those. The RGB components are list as a tuple of tuples, instead of a list of lists (array). I wonder why. It has the `.colors` attribute, though. – Fausto Arinos Barbuto Dec 18 '19 at 22:41
  • `tab10` should be identical to e.g. `viridis`, namely a `ListedColormap`. Do you have a code that shows any difference between them? – ImportanceOfBeingErnest Dec 18 '19 at 22:43
  • What I verified is that `cm.viridis.colors` shows something like `[[0.267004, 0.004874, 0.329415], ...`, whereas `cm.tab10.colors` shows `((0.12156862745098039, 0.4666666666666667, 0.7058823529411765), ...`. That's obviously a different structure, where tuples replaced the lists. – Fausto Arinos Barbuto Dec 19 '19 at 01:51
  • 1
    Right. There is no type conversion happening, and `.colors` actually stays what it is. I agree that this is undesireable. For now you can always convert to a numpy array yourself, `np.array(cmap.colors)`. – ImportanceOfBeingErnest Dec 19 '19 at 11:42