Reputation: 99
When using LinearSegmentedColormap, Matplotlib documentation mentions regarding the argument colors that
colors: array-like of colors or array-like of (value, color). If only colors are given, they are equidistantly mapped from the range [0,1]; i.e. 0 maps to colors[0] and 1 maps to colors[-1]. If (value, color) pairs are given, the mapping is from value to color. This can be used to divide the range unevenly.
I have the following colors ['crimson', 'brown', 'lime', 'brown', 'crimson'] and I want to divide the range unevenly in this way:
(-1, -0.5) : 'crimson'
(-0.5, -0.15) : 'brown'
(-0.15, 0.15) : 'lime'
(0.15, 0.5) : 'brown'
(0.5, 1) : 'crimson'
I tried passing the colors argument in the format: [(-1, 'crimson'), (-0.5, 'brown), (-0.15, 'lime'), (0.15, 'brown), (0.5, 'crimson')] but got an error. Am I missing something?
Upvotes: 1
Views: 812
Reputation: 80329
To achieve the described color segmentation, you could combine LinearSegmentedColormap.from_list('', colors, len(colors))
with a BoundaryNorm
. Note that you need 6 boundaries for 5 colors.
Working with (value, color)
pairs for LinearSegmentedColormap
seems a bit cumbersome, as the values need to normalized to go strictly from 0 to 1. This would be more suited if case you need a continuous range of colors and want to set a specific color at a specific position (not at a specific range).
from matplotlib import pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, BoundaryNorm
import numpy as np
bounds = [-1, -0.5, -0.15, 0.15, 0.5, 1]
colors = ['crimson', 'brown', 'lime', 'brown', 'crimson']
cmap = LinearSegmentedColormap.from_list('', colors, N=len(colors))
norm = BoundaryNorm(bounds, ncolors=len(colors), )
x = np.random.uniform(0, 1, 100)
y = np.random.uniform(-1, 1, 100)
plt.scatter(x, y, c=y, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()
Note that you can use plt.colorbar(spacing='proportional')
to display larger chunks of color for the larger ranges. The default is spacing='uniform'
with equal space for each color.
PS: About the new question, a custom smooth colormap could be created with the (value, color)
list for LinearSegmentedColormap
and setting extra boundaries.
from matplotlib import pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np
bounds = [-1, -0.5, -0.499, -0.15, -0.149, 0.0, 0.149, 0.15, 0.499, 0.5, 1]
colors = ['crimson', 'crimson', 'brown', 'brown', 'limegreen', 'lime', 'limegreen', 'brown', 'brown', 'crimson', 'crimson']
norm = plt.Normalize(bounds[0], bounds[-1])
cmap = LinearSegmentedColormap.from_list('', [(norm(b), c) for b, c in zip(bounds, colors)], N=256)
x = np.random.uniform(0, 1, 100)
y = np.random.uniform(-1, 1, 100)
plt.scatter(x, y, c=y, cmap=cmap, norm=norm)
plt.colorbar()
plt.show()
Upvotes: 1