#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-тест для фильтрации некоторых значений.