25

I'm trying to plot log ratios from the range -3 to 3 and want negative ratios to be green and positive to be red, with a log ratio of 0 (center) to be white in color. None of the pre-existing color schemes in matplotlib provide this option, and I haven't been able to figure out how to output a nice gradient manually.

A. Gup
  • 263
  • 1
  • 3
  • 6
  • You could settle for an inverted PiYG colormap (green to pink with white in the middle). – evtoh Jul 07 '16 at 13:31
  • http://matplotlib.org/examples/pylab_examples/custom_cmap.html – user20160 Jul 07 '16 at 13:38
  • 1
    [Beware that](https://matplotlib.org/stable/tutorials/colors/colormaps.html#color-vision-deficiencies) *"the most common form of color vision deficiency involves differentiating between red and green. Thus, avoiding colormaps with both red and green will avoid many problems in general."* – Skippy le Grand Gourou May 03 '21 at 08:14

3 Answers3

46

Using matplotlib.colors.LinearSegmentedColormap's from_list method seems more intuitive than some of the other answers here.

from  matplotlib.colors import LinearSegmentedColormap
cmap=LinearSegmentedColormap.from_list('rg',["r", "w", "g"], N=256) 

enter image description here

Or for more sophisticated tuning:

from  matplotlib.colors import LinearSegmentedColormap
c = ["darkred","red","lightcoral","white", "palegreen","green","darkgreen"]
v = [0,.15,.4,.5,0.6,.9,1.]
l = list(zip(v,c))
cmap=LinearSegmentedColormap.from_list('rg',l, N=256)

enter image description here

yoniLavi
  • 2,624
  • 1
  • 24
  • 30
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • 2
    It feels like this should be the accepted answer! Thank you very much! – Ray Walker Sep 03 '21 at 11:12
  • What command did you use to get this visualization of the colormap ? – kawingkelvin Mar 16 '22 at 22:04
  • 1
    For Ukraine I found the yellow-blue cmap. c2 = ["darkblue","blue","#AAAAFF","white", "#FFFF99", "#FFFF88","yellow"] v2 = [0,.15,.4,.5,0.53,.9,1.] yb = list(zip(v2,c2)) After you create the cmap, you can use cmap.reversed(). For example for a correlation matrix (sns.heatmap(df.corr()) the yellow is above with the first setup not the reversed one. – Arpad Horvath -- Слава Україні Dec 22 '22 at 18:51
8

you can create your own using a LinearSegmentedColormap. I like to set the red and green channels to something less than 1.0 at the upper and lower limits so the colours aren't too bright (here I used 0.8). Adjust that to suit your taste.

See the custom_cmap example on the matplotlib website for further details.

Here's an working example:

import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np

# This dictionary defines the colormap
cdict = {'red':  ((0.0, 0.0, 0.0),   # no red at 0
                  (0.5, 1.0, 1.0),   # all channels set to 1.0 at 0.5 to create white
                  (1.0, 0.8, 0.8)),  # set to 0.8 so its not too bright at 1

        'green': ((0.0, 0.8, 0.8),   # set to 0.8 so its not too bright at 0
                  (0.5, 1.0, 1.0),   # all channels set to 1.0 at 0.5 to create white
                  (1.0, 0.0, 0.0)),  # no green at 1

        'blue':  ((0.0, 0.0, 0.0),   # no blue at 0
                  (0.5, 1.0, 1.0),   # all channels set to 1.0 at 0.5 to create white
                  (1.0, 0.0, 0.0))   # no blue at 1
       }

# Create the colormap using the dictionary
GnRd = colors.LinearSegmentedColormap('GnRd', cdict)

# Make a figure and axes
fig,ax = plt.subplots(1)

# Some fake data in the range -3 to 3
dummydata = np.random.rand(5,5)*6.-3.

# Plot the fake data
p=ax.pcolormesh(dummydata,cmap=GnRd,vmin=-3,vmax=3)

# Make a colorbar
fig.colorbar(p,ax=ax)

plt.show()

enter image description here

tmdavison
  • 64,360
  • 12
  • 187
  • 165
  • 2
    I will add that using a green-red colour map is not a great idea as colourblind folks will not be able to interpret your plot! – tmdavison Mar 08 '18 at 16:42
  • Above comment is great advice, quoting [matplotplib’s colormaps documentation](https://matplotlib.org/stable/tutorials/colors/colormaps.html) : *"The most common form of color vision deficiency involves differentiating between red and green. Thus, avoiding colormaps with both red and green will avoid many problems in general."* – Skippy le Grand Gourou May 03 '21 at 08:12
5

How about the following that uses LinearSegmentedColormap:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap


cmapGR = LinearSegmentedColormap(
    'GreenRed',
    {
        'red':  ((0.0, 0.0, 0.0),
                (0.5, 1.0, 1.0),
                (1.0, 1.0, 1.0)),
        'green':((0.0, 1.0, 1.0),
                (0.5, 1.0, 1.0),
                ( 1.0, 0.0, 0.0)),
        'blue': ((0.0, 0.0, 0.0),
                (0.5, 1.0, 1.0),
                (1.0, 0.0, 0.0))
    },)

plt.imshow(np.array([np.arange(200) for i in range(200)]), cmap=cmapGR)
plt.show()

It produces the following enter image description here

See e.g. http://matplotlib.org/examples/pylab_examples/custom_cmap.html for more uses and other examples.

jmetz
  • 12,144
  • 3
  • 30
  • 41