Matplotlib에서 컬러맵 만들기 #

Matplotlib에는 matplotlib.colormaps. 추가 컬러 맵이 많은 palettable 과 같은 외부 라이브러리도 있습니다 .

그러나 우리는 종종 Matplotlib에서 컬러맵을 생성하거나 조작하기를 원합니다. 이것은 클래스 ListedColormap또는 를 사용하여 수행할 수 있습니다 LinearSegmentedColormap. 외부에서 볼 때 두 컬러맵 클래스는 0과 1 사이의 값을 여러 색상에 매핑합니다. 그러나 약간의 차이가 있으며 그 중 일부는 다음과 같습니다.

컬러맵을 수동으로 생성하거나 조작하기 전에 먼저 기존 컬러맵 클래스에서 컬러맵과 해당 색상을 얻는 방법을 살펴보겠습니다.

색상표 가져오기 및 해당 값에 액세스 #

먼저 이름이 지정된 컬러맵을 가져오는데 대부분이 Matplotlib에서 컬러맵 선택 에 나열되어 있으며 컬러 matplotlib.colormaps맵 객체를 반환하는 를 사용하여 수행할 수 있습니다 . 컬러맵을 정의하기 위해 내부적으로 사용되는 색상 목록의 길이는 를 통해 조정할 수 있습니다 Colormap.resampled. 아래에서는 적당한 값인 8을 사용하므로 살펴볼 값이 많지 않습니다.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.colors import ListedColormap, LinearSegmentedColormap

viridis = mpl.colormaps['viridis'].resampled(8)

객체 viridis는 콜러블이며 0과 1 사이의 부동 소수점을 전달하면 색상표에서 RGBA 값을 반환합니다.

print(viridis(0.56))
(0.122312, 0.633153, 0.530398, 1.0)

ListedColormap #

ListedColormaps는 색상 값을 .colors속성에 저장합니다. 컬러맵을 구성하는 색상 목록은 속성을 사용하여 직접 액세스하거나 컬러맵 의 길이와 일치하는 값 배열을 colors호출하여 간접적으로 액세스할 수 있습니다 . viridis반환된 목록은 RGBA Nx4 배열 형식이며 여기서 N은 컬러맵의 길이입니다.

print('viridis.colors', viridis.colors)
print('viridis(range(8))', viridis(range(8)))
print('viridis(np.linspace(0, 1, 8))', viridis(np.linspace(0, 1, 8)))
viridis.colors [[0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]
viridis(range(8)) [[0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]
viridis(np.linspace(0, 1, 8)) [[0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]

컬러맵은 조회 테이블이므로 컬러맵을 "오버샘플링"하면 가장 가까운 이웃 보간법이 반환됩니다(아래 목록에서 반복되는 색상 참고).

print('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12)))
viridis(np.linspace(0, 1, 12)) [[0.267004 0.004874 0.329415 1.      ]
 [0.267004 0.004874 0.329415 1.      ]
 [0.275191 0.194905 0.496005 1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.212395 0.359683 0.55171  1.      ]
 [0.153364 0.497    0.557724 1.      ]
 [0.122312 0.633153 0.530398 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.288921 0.758394 0.428426 1.      ]
 [0.626579 0.854645 0.223353 1.      ]
 [0.993248 0.906157 0.143936 1.      ]
 [0.993248 0.906157 0.143936 1.      ]]

LinearSegmentedColormap #

LinearSegmentedColormaps에는 .colors속성이 없습니다. 그러나 여전히 정수 배열 또는 0과 1 사이의 부동 소수점 배열을 사용하여 컬러맵을 호출할 수 있습니다.

copper = mpl.colormaps['copper'].resampled(8)

print('copper(range(8))', copper(range(8)))
print('copper(np.linspace(0, 1, 8))', copper(np.linspace(0, 1, 8)))
copper(range(8)) [[0.         0.         0.         1.        ]
 [0.17647055 0.1116     0.07107143 1.        ]
 [0.35294109 0.2232     0.14214286 1.        ]
 [0.52941164 0.3348     0.21321429 1.        ]
 [0.70588219 0.4464     0.28428571 1.        ]
 [0.88235273 0.558      0.35535714 1.        ]
 [1.         0.6696     0.42642857 1.        ]
 [1.         0.7812     0.4975     1.        ]]
copper(np.linspace(0, 1, 8)) [[0.         0.         0.         1.        ]
 [0.17647055 0.1116     0.07107143 1.        ]
 [0.35294109 0.2232     0.14214286 1.        ]
 [0.52941164 0.3348     0.21321429 1.        ]
 [0.70588219 0.4464     0.28428571 1.        ]
 [0.88235273 0.558      0.35535714 1.        ]
 [1.         0.6696     0.42642857 1.        ]
 [1.         0.7812     0.4975     1.        ]]

나열된 컬러맵 만들기 #

컬러맵을 생성하는 것은 본질적으로 새로운 컬러맵을 생성하기 위해 색상 사양의 목록 또는 배열을 제공하는 위 작업의 반대 작업입니다 ListedColormap.

자습서를 계속하기 전에 하나 이상의 컬러맵을 입력으로 사용하고 임의의 데이터를 생성한 다음 컬러맵을 해당 데이터 집합의 이미지 플롯에 적용하는 도우미 함수를 정의해 보겠습니다.

def plot_examples(colormaps):
    """
    Helper function to plot data with associated colormap.
    """
    np.random.seed(19680801)
    data = np.random.randn(30, 30)
    n = len(colormaps)
    fig, axs = plt.subplots(1, n, figsize=(n * 2 + 2, 3),
                            constrained_layout=True, squeeze=False)
    for [ax, cmap] in zip(axs.flat, colormaps):
        psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4)
        fig.colorbar(psm, ax=ax)
    plt.show()

가장 간단한 경우에는 색상 이름 목록을 입력하여 색상표를 만들 수 있습니다.

cmap = ListedColormap(["darkorange", "gold", "lawngreen", "lightseagreen"])
plot_examples([cmap])
컬러맵 조작

실제로 이 목록에는 유효한 Matplotlib 색상 사양 이 포함될 수 있습니다 . 사용자 정의 컬러맵을 생성하는 데 특히 유용한 것은 Nx4 numpy 배열입니다. 이러한 배열에서 수행할 수 있는 다양한 numpy 작업을 통해 기존 컬러맵에서 새 컬러맵을 만드는 작업이 매우 간단해집니다.

예를 들어 어떤 이유로 256 길이의 "viridis" 컬러맵의 처음 25개 항목을 분홍색으로 만들고 싶다고 가정합니다.

viridis = mpl.colormaps['viridis'].resampled(256)
newcolors = viridis(np.linspace(0, 1, 256))
pink = np.array([248/256, 24/256, 148/256, 1])
newcolors[:25, :] = pink
newcmp = ListedColormap(newcolors)

plot_examples([viridis, newcmp])
컬러맵 조작

컬러맵의 동적 범위를 줄일 수 있습니다. 여기서 우리는 컬러맵의 중간 절반을 선택합니다. 그러나 viridis는 나열된 컬러맵이기 때문에 원래 컬러맵에 있던 256개의 값 대신 128개의 불연속 값으로 끝납니다. 이 방법은 새 색상을 추가하기 위해 색상 공간에서 보간하지 않습니다.

viridis_big = mpl.colormaps['viridis']
newcmp = ListedColormap(viridis_big(np.linspace(0.25, 0.75, 128)))
plot_examples([viridis, newcmp])
컬러맵 조작

두 개의 컬러맵을 쉽게 연결할 수 있습니다.

top = mpl.colormaps['Oranges_r'].resampled(128)
bottom = mpl.colormaps['Blues'].resampled(128)

newcolors = np.vstack((top(np.linspace(0, 1, 128)),
                       bottom(np.linspace(0, 1, 128))))
newcmp = ListedColormap(newcolors, name='OrangeBlue')
plot_examples([viridis, newcmp])
컬러맵 조작

물론 명명된 컬러맵에서 시작할 필요는 없으며 에 전달할 Nx4 배열을 생성하기만 하면 됩니다 ListedColormap. 여기에서는 갈색(RGB: 90, 40, 40)에서 흰색(RGB: 255, 255, 255)으로 가는 컬러맵을 만듭니다.

N = 256
vals = np.ones((N, 4))
vals[:, 0] = np.linspace(90/256, 1, N)
vals[:, 1] = np.linspace(40/256, 1, N)
vals[:, 2] = np.linspace(40/256, 1, N)
newcmp = ListedColormap(vals)
plot_examples([viridis, newcmp])
컬러맵 조작

선형 세그먼트 컬러맵 만들기 #

LinearSegmentedColormap클래스는 RGB(A) 값이 보간되는 앵커 포인트를 사용하여 컬러맵을 지정합니다.

이러한 컬러맵을 지정하는 형식은 앵커 포인트에서 불연속성을 허용합니다. 각 앵커 포인트는 형식의 행렬에서 행으로 지정됩니다. 여기서 는 앵커이고 는 앵커 포인트 양쪽의 색상 값입니다.[x[i] yleft[i] yright[i]]x[i]yleft[i]yright[i]

불연속성이 없으면 다음 과 같습니다.yleft[i] == yright[i]

cdict = {'red':   [[0.0,  0.0, 0.0],
                   [0.5,  1.0, 1.0],
                   [1.0,  1.0, 1.0]],
         'green': [[0.0,  0.0, 0.0],
                   [0.25, 0.0, 0.0],
                   [0.75, 1.0, 1.0],
                   [1.0,  1.0, 1.0]],
         'blue':  [[0.0,  0.0, 0.0],
                   [0.5,  0.0, 0.0],
                   [1.0,  1.0, 1.0]]}


def plot_linearmap(cdict):
    newcmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256)
    rgba = newcmp(np.linspace(0, 1, 256))
    fig, ax = plt.subplots(figsize=(4, 3), constrained_layout=True)
    col = ['r', 'g', 'b']
    for xx in [0.25, 0.5, 0.75]:
        ax.axvline(xx, color='0.7', linestyle='--')
    for i in range(3):
        ax.plot(np.arange(256)/256, rgba[:, i], color=col[i])
    ax.set_xlabel('index')
    ax.set_ylabel('RGB')
    plt.show()

plot_linearmap(cdict)
컬러맵 조작

앵커 포인트에서 불연속성을 만들기 위해 세 번째 열은 두 번째 열과 다릅니다. 각각의 "빨간색", "녹색", "파란색" 및 선택적으로 "알파"에 대한 행렬은 다음과 같이 설정됩니다.

cdict['red'] = [...
                [x[i]      yleft[i]     yright[i]],
                [x[i+1]    yleft[i+1]   yright[i+1]],
               ...]

x[i]및 사이의 컬러맵에 전달된 값 x[i+1]의 경우 보간은 yright[i]및 사이 yleft[i+1]입니다.

아래 예에서는 0.5에서 빨간색 불연속성이 있습니다. 0과 0.5 사이의 보간은 0.3에서 1로 이동하고 0.5와 1 사이에서는 0.9에서 1로 이동합니다. ( 즉 , )가 0의 왼쪽에 있는 값이고 ( 즉, )는 색상 매핑 도메인 외부에 있는 1의 오른쪽에 있는 값입니다.red[0, 1]red[2, 2]red[0, 1]yleft[0]red[2, 2]yright[2]

cdict['red'] = [[0.0,  0.0, 0.3],
                [0.5,  1.0, 0.9],
                [1.0,  1.0, 1.0]]
plot_linearmap(cdict)
컬러맵 조작

목록에서 분할된 컬러맵 직접 생성 #

위에서 설명한 접근 방식은 매우 다양하지만 구현하기 다소 번거롭습니다. 일부 기본적인 경우에는 사용이 LinearSegmentedColormap.from_list더 쉬울 수 있습니다. 이렇게 하면 제공된 색상 목록에서 동일한 간격으로 분할된 색상표가 생성됩니다.

colors = ["darkorange", "gold", "lawngreen", "lightseagreen"]
cmap1 = LinearSegmentedColormap.from_list("mycmap", colors)

원하는 경우 컬러맵의 노드를 0과 1 사이의 숫자로 지정할 수 있습니다. 예를 들어 빨간색 부분이 컬러맵에서 더 많은 공간을 차지하도록 할 수 있습니다.

nodes = [0.0, 0.4, 0.8, 1.0]
cmap2 = LinearSegmentedColormap.from_list("mycmap", list(zip(nodes, colors)))

plot_examples([cmap1, cmap2])
컬러맵 조작

스크립트의 총 실행 시간: (0분 4.802초)

Sphinx-Gallery에서 생성한 갤러리