Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Small utility to create a discrete matplotlib colormap
# By Jake VanderPlas
# License: BSD-style
import matplotlib.pyplot as plt
import numpy as np
def discrete_cmap(N, base_cmap=None):
"""Create an N-bin discrete colormap from the specified input map"""
# Note that if base_cmap is a string or None, you can simply do
# return plt.cm.get_cmap(base_cmap, N)
# The following works for string, None, or a colormap instance:
base = plt.cm.get_cmap(base_cmap)
color_list = base(np.linspace(0, 1, N))
cmap_name = base.name + str(N)
return base.from_list(cmap_name, color_list, N)
if __name__ == '__main__':
N = 5
x = np.random.randn(40)
y = np.random.randn(40)
c = np.random.randint(N, size=40)
# Edit: don't use the default ('jet') because it makes @mwaskom mad...
plt.scatter(x, y, c=c, s=50, cmap=discrete_cmap(N, 'cubehelix'))
plt.colorbar(ticks=range(N))
plt.clim(-0.5, N - 0.5)
plt.show()
@zafarali

This comment has been minimized.

Copy link

@zafarali zafarali commented Jun 17, 2015

This piece of code has literally saved me so much time, thank you very much for sharing!

@paulaceccon

This comment has been minimized.

Copy link

@paulaceccon paulaceccon commented Jun 25, 2015

Really nice example!

@jameswinegar

This comment has been minimized.

Copy link

@jameswinegar jameswinegar commented Aug 14, 2015

Very useful for several projects I am working on.

@pkaf

This comment has been minimized.

Copy link

@pkaf pkaf commented Oct 29, 2015

fantabulous !

@TomCMM

This comment has been minimized.

Copy link

@TomCMM TomCMM commented Nov 14, 2015

Thanks it helps :)

@arganish

This comment has been minimized.

Copy link

@arganish arganish commented Jan 27, 2016

this is awesome, thank you!

@celiacintas

This comment has been minimized.

Copy link

@celiacintas celiacintas commented May 31, 2016

awesome!!!

@Zsailer

This comment has been minimized.

Copy link

@Zsailer Zsailer commented Aug 18, 2016

Super useful. Thanks!

Minor bug -- if you leave the base_cmap keyword argument as None, it raises this error:

AttributeError: 'ListedColormap' object has no attribute 'from_list'

Edit: Just realized that you mentioned this in the commented line. Sorry!

@spthm

This comment has been minimized.

Copy link

@spthm spthm commented Nov 26, 2016

Thanks, this is great! I did however notice that it doesn't work for the perceptually uniform colormaps (at least, not in 1.5.1) because they are ListedColormap instances.

Replacing return base.from_list(cmap_name, color_list, N) with return LinearSegmentedColormap.from_list(cmap_name, color_list, N) is sufficient (LinearSegmentedColormap is in matplotlib.colors).

@paramoreta

This comment has been minimized.

Copy link

@paramoreta paramoreta commented Mar 19, 2018

This is brilliant. Thanks a lot for the time saved. :)

@trontrytel

This comment has been minimized.

Copy link

@trontrytel trontrytel commented Apr 4, 2018

Thank you for sharing this! This is great and simple. A function like this should be part of matplotlib.

@smba

This comment has been minimized.

Copy link

@smba smba commented Aug 3, 2018

This is exactly what I was looking for, glad you shared your ideas! Thanks a lot!

@MaraMuchow

This comment has been minimized.

Copy link

@MaraMuchow MaraMuchow commented Mar 7, 2019

Thanks a lot for this guide. But I have a question. How to handle the guide when you want your colorbar from 3 to 6 as an example? Because in your code it always starts with 0.

@egpbos

This comment has been minimized.

Copy link

@egpbos egpbos commented Aug 27, 2019

Not sure why, but it doesn't actually work for me. I had to replace the final line in the function with return ListedColormap(color_list, name=cmap_name).

@chagaz

This comment has been minimized.

Copy link

@chagaz chagaz commented Mar 3, 2021

Thanks!

I received a ValueError complaining that cmap_name was not a valid value for name; supported values are (followed by the list of predefined color map names).
To fix it, I had to register the colormap. Specifically, I replaced return base.from_list(cmap_name, color_list, N) with

custom_cmap = base.from_list(cmap_name, color_list, N)
plt.cm.register_cmap(name=cmap_name, cmap=custom_cmap)
return custom_cmap
@cvanelteren

This comment has been minimized.

Copy link

@cvanelteren cvanelteren commented Apr 6, 2021

This worked for me

def discrete_cmap(N, base_cmap=None):
    """Create an N-bin discrete colormap from the specified input map"""

    # Note that if base_cmap is a string or None, you can simply do
    #    return plt.cm.get_cmap(base_cmap, N)
    # The following works for string, None, or a colormap instance:

    base = plt.cm.get_cmap(base_cmap)
    color_list = base(np.linspace(0, 1, N, 0))
    cmap_name = base.name + str(N)
    return plt.cm.colors.ListedColormap(color_list, color_list, N)
@fraclad

This comment has been minimized.

Copy link

@fraclad fraclad commented May 3, 2021

Exactly what I need! Thank you so much for sharing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment