Извлечение местоположений границ сегментированной цветовой карты

#matplotlib

#matplotlib

Вопрос:

Я работаю над созданием пользовательской цветовой карты в Matplotlib.

Я понимаю, что с цветовой полосой у нас есть непрерывный диапазон значений, сопоставленный со «спектром» цветов, которые определены в цветовой карте. Я создаю пользовательскую сегментированную цветовую карту, чтобы охватить дискретный диапазон значений.

Мой код:

 colors = ['#FBE9BD', '#F2C370', '#E58B48', '#C35D30', '#A12F29']
cmap1 = LinearSegmentedColormap.from_list("mycmap", colors, N=5)
  

Данные, которые я раскрашиваю, варьируются в значениях от [50, 450]. Насколько я понимаю, эта цветовая панель затем разделит этот диапазон (max — min) на пять равномерно расположенных подразделов и присвоит ему значение цвета на основе приведенного выше массива. Мой вопрос в том, есть ли какой-либо простой способ извлечь граничные диапазоны из этой цветовой карты? Я хотел бы сопоставить значения каждого диапазона ячеек (т. Е. 50-120, 121-175) с легендой, которая отображается рядом с соответствующим цветом.

Второй вопрос — допустим, мы увеличиваем значение от N = 5 до N = 10. Без предоставления каких-либо дополнительных цветов в массиве цветов. Теперь у нас было бы больше подкатегорий, чем разных значений цвета. Что здесь происходит, некоторые ячейки имеют одинаковое назначение цвета?

Любые ссылки на информацию или примеры будут высоко оценены.

Ответ №1:

Следующий код и график пытаются проиллюстрировать, что происходит.

LinearSegmentedColormap.from_list("", colors) внутренне создает гладкую цветовую карту с в данном случае 5 цветами со значениями 0, 0.25, 0.5, 0.75 и 1 (т. Е. Диапазон 0-1 равномерно распределен на 5-1 = 4 равных интервала. Промежуточные позиции интерполируются плавно. При установке N , N области помещаются в диапазон 0-1. Например, с N=10 задается 10 областей (с использованием 11 границ). Значение цвета каждой области получается путем деления плавного цветового диапазона между 0-1 на N (таким образом, не N 1) равных позиций.

Теперь для сопоставления внешних значений 50-450 с внутренними значениями 0-1 используется norm . По умолчанию используются минимальные и максимальные значения данных. vmin и / или vmax можно задать явные минимальные и максимальные значения. (Помимо этого, также может быть назначена явная функция нормы.)

Чтобы вычислить границы для внешних значений, диапазон 50-450 необходимо разрезать на N равных областей, так что N 1 границ. np.linspace(50, 450, N 1) это функция numpy, которая создает эти граничные значения в массив.

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

colors = ['#FBE9BD', '#F2C370', '#E58B48', '#C35D30', '#A12F29']
cmap1 = LinearSegmentedColormap.from_list("mycmap1", colors, N=10)

minval = 50
maxval = 450
bounds = np.linspace(minval, maxval, cmap1.N   1)
x = np.random.uniform(size=1000)
y = np.random.uniform(minval, maxval, size=x.size)
plt.scatter(x, y, c=y, vmin=minval, vmax=maxval, cmap=cmap1)

cbar = plt.colorbar(ScalarMappable(cmap=LinearSegmentedColormap.from_list("mycmap1", colors, N=256)),
                    label='Complete colormap', ticks=np.linspace(0, 1, len(colors)))
cbar.ax.set_yticklabels(colors)
plt.colorbar(ticks=bounds, label=f'LinearSegmentedColormap N={cmap1.N}')
plt.show()
  

Слева N=5 , справа N=10 .

иллюстрирующий график

На следующем графике показана та же ситуация, но с более различимыми цветами. Жирные метки на гладкой цветовой панели показывают, откуда берутся точные цвета для сегментированной цветовой панели.

более разнообразные цвета

PS: Для создания легенды аналогичным образом:

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

colors = ['#FBE9BD', '#F2C370', '#E58B48', '#C35D30', '#A12F29']

cmap1 = LinearSegmentedColormap.from_list("mycmap1", colors, N=10)

minval = 50
maxval = 450
bounds = np.linspace(minval, maxval, cmap1.N   1)
x = np.random.uniform(size=1000)
y = np.random.uniform(minval, maxval, size=x.size)
plt.scatter(x, y, c=y, vmin=minval, vmax=maxval, cmap=cmap1)

handles = [Line2D([], [], color=cmap1(i / (cmap1.N - 1)),
                  marker='o', ls='', label=f'{bounds[i]:.0f}-{bounds[i 1]:.0f}')
           for i in range(cmap1.N) if i < 6 or i == cmap1.N-1]
plt.legend(handles=handles, bbox_to_anchor=[1.02, 1.02], loc='upper left')
plt.tight_layout()
plt.show()
  

пример легенды

Комментарии:

1. Спасибо за этот очень подробный ответ! Можно ли также использовать этот метод для сопоставления значений (цветов / меток) с объектом легенды вместо цветовой панели?

2. Я обновил код для одновременного создания дескрипторов легенды и меток и добавил if-тест для фильтрации некоторых значений.