Я столкнулся с проблемой, когда цветовая карта по умолчанию, SymLogNorm
импортированная из matplotlib.colors
, на самом деле не является симметричной для моих данных. Среднее значение и медиана моих данных выше нуля, но я хочу, чтобы нулевые значения отображались как белый цвет. SymLogNorm
возвращает цветовую карту с центральным значением чуть выше нуля — незаметно, но определенно заметно.
Есть ли решение этой проблемы?
Вот мое исправление — оно по существу использует ручную линейную шкалу для областей, близких к центру, и использует логарифмическую шкалу для областей, расположенных дальше от центра. Вы указываете lin_thres и другие аргументы так же, как и для SymLogNorm.
class MidpointLogNorm(colors.SymLogNorm):
"""
Normalise the colorbar so that diverging bars work there way either side from a prescribed midpoint value)
e.g. im=ax1.imshow(array, norm=MidpointNormalize(midpoint=0.,vmin=-100, vmax=100))
All arguments are the same as SymLogNorm, except for midpoint
"""
def __init__(self, lin_thres, lin_scale, midpoint=None, vmin=None, vmax=None):
self.midpoint = midpoint
self.lin_thres = lin_thres
self.lin_scale = lin_scale
#fraction of the cmap that the linear component occupies
self.linear_proportion = (lin_scale / (lin_scale + 1)) * 0.5
print(self.linear_proportion)
colors.SymLogNorm.__init__(self, lin_thres, lin_scale, vmin, vmax)
def __get_value__(self, v, log_val, clip=None):
if v < -self.lin_thres or v > self.lin_thres:
return log_val
x = [-self.lin_thres, self.midpoint, self.lin_thres]
y = [0.5 - self.linear_proportion, 0.5, 0.5 + self.linear_proportion]
interpol = np.interp(v, x, y)
return interpol
def __call__(self, value, clip=None):
log_val = colors.SymLogNorm.__call__(self, value)
out = [0] * len(value)
for i, v in enumerate(value):
out[i] = self.__get_value__(v, log_val[i])
return np.ma.masked_array(out)
Я черпал вдохновение вокруг середины отсюда: http://chris35wills.github.io/matplotlib_diverging_colorbar/
Ваш предыдущий ответ на самом деле не сработал для меня, так как средняя точка была «далеко» от исходной средней точки. Проблема в том, что в ваших лагорифмических значениях не учитывается средняя точка.
Я немного изменил ваш код и исправил эту проблему, создав 2 SymLogNorm. Оба центрированы посередине. Один начинается с vmin, а другой заканчивается на vmax (экстремумы заполняются по средней точке).
Если я беру значение v, я назначаю координаты цветовой полосы следующим образом:
vmin < v < midpoint — lin_thresh, поэтому используйте SymLogNorm, который начинается с vmin
midpoint - lin_thresh < v < midpoint + lin_thresh, поэтому используйте интерполяцию
midpoint + lin_thresh < v < vmax, поэтому используйте SymLogNorm, который заканчивается на vmax
class MidpointLogNorm(colors.SymLogNorm):
def __init__(self, lin_thres, lin_scale, midpoint=None, vmin=None, vmax=None):
self.midpoint = midpoint
self.lin_thres = lin_thres
self.lin_scale = lin_scale
#fraction of the cmap that the linear component occupies
self.linear_proportion = (lin_scale / (lin_scale + 1)) * 0.5
print(self.linear_proportion)
# Create norm with vmin at 0 and midpoint at 0.5
self.SymLogNorm1 = colors.SymLogNorm(lin_thres, lin_scale, vmin, 2*self.midpoint + np.abs(vmin))
# Create norm with midpoint at 0.5 and vmax at 1
self.SymLogNorm2 = colors.SymLogNorm(lin_thres, lin_scale, 2*self.midpoint - vmax, vmax)
colors.SymLogNorm.__init__(self, lin_thres, lin_scale, vmin, vmax)
def __get_value__(self, v, log_val1_i, log_val2_i, clip=None):
v = np.array(v)
x = [self.vmin, self.midpoint, self.vmax]
y = [0., 0.5, 1.]
interpol = np.interp(v, x, y)
out = np.where(np.abs(v) < self.lin_thres, interpol, v)
out = np.where(out > self.lin_thres, log_val2_i, out)
out = np.where(out < self.lin_thres, log_val1_i, out)
return np.ma.masked_array(out)
def __call__(self, value, clip=None):
log_val1 = self.SymLogNorm1(value)
log_val2 = self.SymLogNorm2(value)
out = [0] * len(value)
for i, v in enumerate(value):
out[i] = self.__get_value__(v, log_val1[i], log_val2[i])
return np.ma.masked_array(out)
Это не самые лучшие вопросы и ответы, но этого достаточно, чтобы +1 компенсировал -1. Я думаю, вы могли бы предоставить более подробную информацию в своем вопросе с данными и изображениями, как в блоге Криса Уиллиса.