Convert color palettes to python matplotlib colormaps

This is a quick post to show you how to import my perceptual color palettes – or any other color palette – into Python and convert them into Matplotlib colormaps. We will use as an example the CIE Lab linear L* palette, which was my adaptation to Matlab of the luminance controlled colormap by Kindlmann et al.

Introduction

You can use the code snippets in here or download the iPython notebook from here (*** please see update ***). You will need NumPy in addition to Matplotlib.

***  UPDATE  ***

Fellow Pythonista Matt Hall of Agile Geoscience extended this work – see comment below to include more flexible import of the data and formatting routines, and code to reverse the colormap. Please use Matt’s expanded iPython notebook.

Preliminaries

First of all, get the color palettes in plain ASCII format rom this page. Download the .odt file for the RGB range 0-1 colors, change the file extension to .zip, and unzip it. Next, open the file Linear_L_0-1, which contains comma separated values, replace commas with tabs, and save as .txt file. That’s it, the rest is in Python.

Code snippets – importing data

Let’s bring in numpy and matplotlib:

%pylab inline
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt

Now we load the data. We get RGB triplets from tabs delimited text file. Values are expected in the 0-1 range, not 0-255 range.

LinL = np.loadtxt('Linear_L_0-1.txt')

A quick QC of the data:

LinL[:3]

gives us:

array
([[ 0.0143,  0.0143,  0.0143],
  [ 0.0404,  0.0125,  0.0325],
  [ 0.0516,  0.0154,  0.0443]])

looking good!

Code snippets – creating colormap

Now we want to go from an array of values for blue in this format:

b1=[0.0000,0.1670,0.3330,0.5000,0.6670,0.8330,1.0000]

to a list that has this format:

[(0.0000,1.0000,1.0000),
(0.1670,1.0000,1.0000),
(0.3330,1.0000,1.0000),
(0.5000,0.0000,0.0000),
(0.6670,0.0000,0.0000),
(0.8330,0.0000,0.0000),
(1.0000,0.0000,0.0000)]

# to a dictionary entry that has this format:

{
'blue': [
(0.0000,1.0000,1.0000),
(0.1670,1.0000,1.0000),
(0.3330,1.0000,1.0000),
(0.5000,0.0000,0.0000),
(0.6670,0.0000,0.0000),
(0.8330,0.0000,0.0000),
(1.0000,0.0000,0.0000)],
...
...
}

which is the format required to make the colormap using matplotlib.colors. Here’s the code:

b3=LinL[:,2] # value of blue at sample n
b2=LinL[:,2] # value of blue at sample n
b1=linspace(0,1,len(b2)) # position of sample n - ranges from 0 to 1

# setting up columns for list
g3=LinL[:,1]
g2=LinL[:,1]
g1=linspace(0,1,len(g2))

r3=LinL[:,0]
r2=LinL[:,0]
r1=linspace(0,1,len(r2))

# creating list
R=zip(r1,r2,r3)
G=zip(g1,g2,g3)
B=zip(b1,b2,b3)

# transposing list
RGB=zip(R,G,B)
rgb=zip(*RGB)
# print rgb

# creating dictionary
k=['red', 'green', 'blue']
LinearL=dict(zip(k,rgb)) # makes a dictionary from 2 lists

Code snippets – testing colormap

That’s it, with the next 3 lines we are done:

my_cmap = matplotlib.colors.LinearSegmentedColormap('my_colormap',LinearL)
pcolor(rand(10,10),cmap=my_cmap)
colorbar()

which gives you this result: LinearL test Notice that if the original file hadn’t had 256 samples, and you wanted a 256 sample color palette, you’d use the line below instead:

my_cmap = matplotlib.colors.LinearSegmentedColormap('my_colormap',LinearL,256)

Have fun!

Related Posts (MyCarta)

The rainbow is dead…long live the rainbow! – Part 5 – CIE Lab linear L* rainbow

Visualize Mt S Helens with Python and a custom color palette

A bunch of links on colors in Python

http://bl.ocks.org/mbostock/5577023

http://matplotlib.org/api/cm_api.html

http://matplotlib.org/api/colors_api.html

http://matplotlib.org/examples/color/colormaps_reference.html

http://matplotlib.org/api/colors_api.html#matplotlib.colors.ListedColormap

http://wiki.scipy.org/Cookbook/Matplotlib/Show_colormaps

http://stackoverflow.com/questions/21094288/convert-list-of-rgb-codes-to-matplotlib-colormap

http://stackoverflow.com/questions/16834861/create-own-colormap-using-matplotlib-and-plot-color-scale

http://stackoverflow.com/questions/11647261/create-a-colormap-with-white-centered-around-zero

16 responses to “Convert color palettes to python matplotlib colormaps

  1. This is brilliant, Matteo! I will definitely be using your famous colourmaps in my stuff. Very cool.

    Check this out. I extended the start of your workflow to do some of the formatting in Python too… and found three ways to reverse a colourmap too. This was a great exercise in getting to know Matplotlib colourmaps better — thanks for the motivation!

    • Hey Matt

      Awesome job, thanks for chipping in, and for giving me some more motivation too! I’m going to sit down tonight and work through your examples. 🙂
      And thanks for loading a Notebook on Github. I have to sign up and get myself in there too.
      By the way, I was going to use part of the the iPython Notebook as an intro to my tutorial article for The Leading Edge, I’m thinking of incorporating some of your additions if that’s OK.

      • Hey, yes, GitHub is great. I honestly don’t think I could live without it anymore. Do join… there is a good number of geoscientists in there and it’s fun to poke around in other people’s stuff.

        Totally fine to do whatever you like with my notebooks etc… I just really appreciate you going over all this. I’ve meant to look at Matplotlib colourmaps for months, but it makes such a difference when someone gets you started!

      • Getting from the arrays to the dictionary gave me a few head scratches particularly because I was learning Python as I went, but wanting to get my palettes in was a motivation. I just added a list at the bottom of the post with a bunch of good links on colormaps in Python.

        I went through the second part of your work again, I like how you made a gen_cmap function, but my favourite is the flipud. Simple, elegant (and perhaps because I used it soo much in Matlab).

  2. Matteo, this is really cool stuff, thanks for sharing!

    To add a bit to Matts code, instead of reading the data from file (raw_data =
    f.read()) and then converting everything from strings, to numbers, to array,
    you could just pass f to numpy.loadtxt and that already gets you an array. You
    can even set the delimeter to ‘;’ so it reads csv directly.

    I’d love to include these as an option (or maybe the default) in Fatiando.
    Would that be ok with you? If so, what is the license for these palettes?

    Also, have you considered putting them on figshare.com? I’d be more than happy
    to cite it if/when I use them in a publication (and put a link in the Fatiando
    docs).

  3. Hi Leonardo

    Thanks for your input. I did originally use the numpy loadtxt but did not think of checking for separator option. I’ll try that. I also like Matt’s idea of getting the file straight off the website. Good to have both options.

    As for the palettes, if you want to include them in Fatiando, go for it, I’d be delighted! My original motivation was to get as many people as possible to drop rainbow/spectrum altogether. The more people, the merrier. I do not have a standard license on the blog stuff (check my Konomark sharing agreement at bottom). You asked, I say use them however you like. If you can include a link to the post, that’s great.

      • One more thing Leonardo: I’m writing this tutorial for The Leading Edge on color palettes. It will be out in August. Same series as your Euler Deconvolution tutorial in Fatiando. As part of that I’m planning to include for sure a version of the improved grayscale from Froner et al. plus either a new grayscale specifically designed for fault interpretation on seismic data, or a new two-color divergent palette. The notebook may have all of them. If you want, when they are ready, I can give you a preview so you can decide if you want to include any of those too.

  4. Pingback: Visualize Mt St Helen with Python and a custom color palette | MyCarta·

  5. Hi Matteo,
    I am novice in matplotlib and you are my only hope for my question: Do you know if it is possible to create a matplotlib colormap from a color palette with values between 0 and 255 (so not only 0-1 values)?
    Thank you very much for your answer and sorry for my english

    • Hello Amy

      If your input palette has values between 0-255, you only need to divide all values by 255 to get them in the range 0-1, then you can use the code in this post. Let me know if you are successful. Matteo

      • Hello,
        thanks four your answer, It works fine now!!! I appreciate your time and
        wish you much success with your projects.
        Amy

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s