How to create a heat map in python that ranges from green to red?
Asked Answered
O

5

30

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.

Obstipation answered 7/7, 2016 at 13:19 Comment(3)
You could settle for an inverted PiYG colormap (green to pink with white in the middle).Postmortem
matplotlib.org/examples/pylab_examples/custom_cmap.htmlNostalgia
Beware that "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."Odeen
E
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

Equinox answered 7/7, 2016 at 13:38 Comment(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!Equinox
Above comment is great advice, quoting matplotplib’s colormaps documentation : "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."Odeen
U
51

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

Undersurface answered 18/12, 2017 at 16:10 Comment(3)
It feels like this should be the accepted answer! Thank you very much!Milliken
What command did you use to get this visualization of the colormap ?Oleic
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.Brunt
E
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

Equinox answered 7/7, 2016 at 13:38 Comment(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!Equinox
Above comment is great advice, quoting matplotplib’s colormaps documentation : "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."Odeen
D
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.

Downcome answered 7/7, 2016 at 13:34 Comment(0)
C
5

Not exactly red to green, but there's a diverging colormap: RdYlGn, red-yellow-green.

plot = sns.heatmap(df.corr().round(2),cmap='RdYlGn',annot=True)
Carleencarlen answered 26/9, 2023 at 8:46 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Lactiferous
L
0

I don't want to use g or r because these are different than the default Greens and Reds Colormaps https://matplotlib.org/stable/users/explain/colors/colormaps.html

So I concatenate Greens and Reds.

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

sample = 15
colors = np.vstack(
    (
        # Default is White -> Green but I want Green -> White -> Red so reverse the order
        plt.get_cmap("Greens", sample)(np.linspace(0, 1, sample))[::-1],
        # np.ones((1, 4)),  # Explicit White optional
        plt.get_cmap("Reds", sample)(np.linspace(0, 1, sample)),
    )
)
cmap = LinearSegmentedColormap.from_list("green_to_red", colors)
fig, ax = plt.subplots(figsize=(5, 1), tight_layout=True)
ax.imshow(np.array([np.arange(256) for i in range(256)]), cmap="Greens", aspect="auto")
fig.show()

enter image description here

And a Scatter Plot

fig, ax = plt.subplots(figsize=(6, 3), tight_layout=True)
x = np.linspace(-7, 7, 1000)
map = ax.scatter(x, np.cos(x), c=y, cmap=cmap)
fig.colorbar(mappable=map, ax=ax)
fig.show()

enter image description here

Luminescent answered 6/3, 2024 at 14:13 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.