Are there any colormaps or is there a simple way to transform a matplotlib colormap to provide a much bigger color range near 0.5 and a smaller one at the extremes? I am cre
Your link provides quite a good solution for the colormap. I edited a bit, but it contained al the necessary. You need to pick some sensible levels for your nonlinear colormap. I used two ranges centered around the mean values, between +- 4
the standard deviation of your sample. by changing that to another number you obtain a different local gradient in the color around the two mean values.
For the colorbar, you
The second allows greater resolution when looking at the data, looks nicer and is implemented below:
import numpy as np
import matplotlib.pyplot as plt
x = y = np.linspace(1, 10, 10)
t1mean, t2mean = 2, 9
sigma1, sigma2 = .3, .01
t1 = np.random.normal(t1mean, sigma1, 10)
t2 = np.random.normal(t2mean, sigma2, 10)
class nlcmap(object):
def __init__(self, cmap, levels):
self.cmap = cmap
self.N = cmap.N
self.monochrome = self.cmap.monochrome
self.levels = np.asarray(levels, dtype='float64')
self._x = self.levels
self.levmax = self.levels.max()
self.transformed_levels = np.linspace(0.0, self.levmax,
len(self.levels))
def __call__(self, xi, alpha=1.0, **kw):
yi = np.interp(xi, self._x, self.transformed_levels)
return self.cmap(yi / self.levmax, alpha)
tmax = max(t1.max(), t2.max())
#the choice of the levels depends on the data:
levels = np.concatenate((
[0, tmax],
np.linspace(t1mean - 4 * sigma1, t1mean + 4 * sigma1, 5),
np.linspace(t2mean - 4 * sigma2, t2mean + 4 * sigma2, 5),
))
levels = levels[levels <= tmax]
levels.sort()
cmap_nonlin = nlcmap(plt.cm.jet, levels)
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.scatter(x, y, edgecolors=cmap_nonlin(t1), s=15, linewidths=4)
ax2.scatter(x, y, edgecolors=cmap_nonlin(t2), s=15, linewidths=4)
fig.subplots_adjust(left=.25)
cbar_ax = fig.add_axes([0.10, 0.15, 0.05, 0.7])
#for the colorbar we map the original colormap, not the nonlinear one:
sm = plt.cm.ScalarMappable(cmap=plt.cm.jet,
norm=plt.Normalize(vmin=0, vmax=tmax))
sm._A = []
cbar = fig.colorbar(sm, cax=cbar_ax)
#here we are relabel the linear colorbar ticks to match the nonlinear ticks
cbar.set_ticks(cmap_nonlin.transformed_levels)
cbar.set_ticklabels(["%.2f" % lev for lev in levels])
plt.show()
In the result, notice that the ticks of the colorbar are NOT equispaced:
You could use LinearSegmentedColormap:
With this, you need to set up a color lookup table within a dictionary e.g. 'cdict' below.
cdict = {'red': [(0.0, 0.0, 0.0),
(0.15, 0.01, 0.01),
(0.35, 1.0, 1.0),
(1.0, 1.0, 1.0)],
'green': [(0.0, 0.0, 0.0),
(1.0, 0.0, 1.0)],
'blue': [(0.0, 0.0, 1.0),
(0.9, 0.01, 0.01),
(1.0, 0.0, 1.0)]}
This shows the transistions between values. I have set red to vary a lot around the values of t1/t2_max
(0.15 to 0.35) and blue to vary a lot around the values of t2/t2_max
(0.9 to 1.0). Green does nothing. I'd recommend reading the docs to see how this works. (Note this could be automated to automatically vary around your values). I then tweaked your code to show the graph:
import matplotlib.colors as col
my_cmap = col.LinearSegmentedColormap('my_colormap', cdict)
plt.figure(figsize=(22.0, 15.50))
p = plt.subplot(1,2,1)
colors = my_cmap(t1/t2_max)
p.scatter(x, y, edgecolors=colors, s=15, linewidths=4)
p = plt.subplot(1,2,2)
colors = my_cmap(t2/t2_max)
p.scatter(x, y, edgecolors=colors, s=15, linewidths=4)
plt.subplots_adjust(left=0.2)
cbar_ax = plt.axes([0.10, 0.15, 0.05, 0.7])
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.Normalize(vmin=0, vmax=t2_max))
sm._A = []
cbar = plt.colorbar(sm,cax=cbar_ax)
plt.show()