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.
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()
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)
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)
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()
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()
See e.g. http://matplotlib.org/examples/pylab_examples/custom_cmap.html for more uses and other examples.
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)
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()
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()
© 2022 - 2025 — McMap. All rights reserved.