- matplotlib에서 custom colormap을 만들고 적용하는 방법입니다.
- 3부로 나누어 1부에 해당하는 본 글에서는 시각적 디자인을, 2~3부에서는 코드 위주로 정리합니다.
Matplotlib Custom Colormap
-
지난 글에는 크게 두 가지 그림이 등장합니다.
- 하나는 value에 따른 컬러맵 명도

- 또 하나는 여러 컬러맵이 적용된 한반도의 풍속 분포 그림입니다.

- 하나는 value에 따른 컬러맵 명도
-
이번 글에서는 이 그림들 중 첫 번째 그림이 그려진 과정을 코드로 살펴보겠습니다.
1. Value vs Lightness
-
이 그림은 기본적으로 공식 홈페이지의 그림들을 모방해서 그렸습니다.
- 원본 그림은 아래와 같습니다.

- 원본 그림은 아래와 같습니다.
-
제가 보기에 조금 아쉬운 부분이 있어서 수정을 했습니다.
- y축 label 위치 : 위로 밀려 붙어있음 → 중앙 고정
- x축 의미 : 컬러맵간 x범위가 겹쳐 혼란함 → 컬러맵 분리
- 일부 색상 불명확 : Lightness가 100에 가까울 때 안보임 → 윤곽선 삽입
1.1. Figure and Axes
- 그림의 틀
Figure와 데이터가 놓일 축공간Axes을 지정합니다. N개의 컬러맵을 동시에 표현할 준비를 합니다.
1 | %matplotlib inline |

- y축 데이터는 맨 왼쪽 그림에만 표기할 준비를 합니다.
sharey=True를 적용해서 축공간들을 동기화합니다.- 두번째 이후 그림에서 y축을 없애고 범위를 통일합니다.
1.2. Data
- 데이터부터 자리를 잡아준 뒤에 거기에 맞게 그림을 꾸밉니다.
- 우리가 얹을 데이터는 특정 컬러맵에서 0~1 범위를 가지는 x가 표현하는 명도의 범위입니다.
- x의 범위를 설정하기 전에 숫자를 명도로 변환하는 함수를 먼저 정의해야 합니다.
- 공식 홈페이지에서 가져온 코드를 한번 자세히 들여다봅시다.
1.2.1 Data to Color, Color to Lightness
-
데이터 형식과 행렬 등으로 다소 지루할 수 있는 구간입니다.
- 읽기 힘들다면 아래 한 줄만 읽고 1.2.2. Plot Lightness of Data로 넘어가도 됩니다.
matplotlib의colormap은numpy.ndarray로 불러낼 수 있다.
-
Blues_r는 짙은 파랑부터 밝은 하늘색까지 변하는 컬러맵입니다.
1 | from matplotlib import cm |
실행결과 : LinearSegmentedColormap 형식입니다.
1 | <class 'matplotlib.colors.LinearSegmentedColormap'> |
- 표현하고자 하는 숫자를
( )에 넣어 붙여주면 색이 출력됩니다.
1 | print(blues_r(0.5)) |
실행결과 : tuple 형식의 RGBA 데이터가 나옵니다.
1 | (0.42274509803921567, 0.684075355632449, 0.8398923490965013, 1.0) |
- 여러 데이터를 List 형식으로 넣어주면 해당 색상이 나열됩니다.
1 | print(blues_r([0, 0.2, 0.4, 0.6, 0.8, 1])) |
실행결과 : numpy.ndarray형식의 RGBA 데이터가 나옵니다.
1 | [[0.03137255 0.18823529 0.41960784 1. ] |
- RGB 색상을 CIELAB으로 변환하기 위해
cspace_converter를 사용합니다. - 그리고 투명도를 담당하는 A(alpha)채널을 제외한 나머지 RGB만 입력합니다.
1 | from colorspacious import cspace_converter |
실행결과 : numpy.ndarray형식의 CIELAB 으로 변환됩니다.
이 중 첫번째 열이 Lightness $$L^*$$에 해당합니다.
1 | [[ 22.18014584 -6.42929944 -23.01729555] |
- 주의 : $$Y = 0.2126R + 0.7152G + 0.0722B$$ 라는 공식이 있습니다.
- 여기서 구하는 $$Y$$는 휘도
Luminance로, 명도Lightness와는 엄밀히 말해 다릅니다. - 지금은 우리 눈이 받아들이는 밝기인 명도를 중심으로 이야기 중입니다.
- 혼동을 방지하기 위해 휘도는 잠시 접어두겠습니다.
- 여기서 구하는 $$Y$$는 휘도
1.2.2. Plot Lightness of Data
- 5가지 colormap에 0부터 1까지의 값을 입력하면서 데이터의 변화를 컬러맵으로 표시해봅시다.
- scatter plot을 두껍게 겹쳐 그리는 방식으로 색상 변화를 표현하겠습니다.
1 | x = np.linspace(0.0, 1.0, 256) # 표현할 data를 0~1까지 256단계로 만듬 |

- 공식 홈페이지의 그림과 비슷하게 출력되었습니다.
1.3. Controlling Figure Aesthetics
- 데이터를 얹었으니 이제 그림을 예쁘게 꾸며봅시다.
- 데이터 시각화에서 예쁘게라는 말은 시각적으로 아름답도록 그리는 것 만을 뜻하지 않습니다.
- 데이터를 인식하기 편하게라는 의미를 함께 가지고 있습니다.
- 축공간
Axes을 먼저 꾸미고, 데이터를 나중에 꾸미겠습니다.
1.3.1. Axes Aesthetics
- 축공간을 어떻게 하면 데이터를 잘 보여줄지 고민해 봤습니다.
- x와 y축의 숫자가 작습니다 → 키웁시다
- 윤곽선이 불필요합니다 → 지웁시다
- 그림의 의미를 모르겠습니다 → y label을 달아줍시다
- 컬러맵간 정량비교가 약합니다 → 눈금을 답시다
1.3.1.1. Larger Ticklabels
ax.scatter()아래에 다음 두 줄을 추가해줍니다.
1 | ax.xaxis.set_tick_params(labelsize=20) # x축 눈금 글꼴 키우기 |
- 실행결과 : 글꼴이 커졌습니다.

1.3.1.2. Needless Spines Removal
1.3.1.3. $$y$$-label Placement
1.3.1.4. Grids On
- 맨 왼쪽 그림은 위
top와 오른쪽right만, 나머지는 왼쪽left까지 지워줍니다. - 첫 번째 축공간에 예외를 지정하기 위해
for ~ enumerate()를 사용합니다.
1 | x = np.linspace(0.0, 1.0, 256) |

- 생각한대로 다 됐는데 생각보다 불편합니다.
- 데이터가 grid 뒤에 있어서 답답합니다.
- 공간이 좁습니다. 빡빡한 느낌이 듭니다.
- 컬러맵 윗부분 색상이 잘 보이지 않습니다.
- 컬러맵 이름을 모르겠습니다.
1.3.1.5. Axes Movement
1.3.1.6. Title Placement
- 남은 불만사항 중 Axes에 해당하는 두번째, 네번째 것을 적용합니다.
1 | x = np.linspace(0.0, 1.0, 256) |

- 전체적인 틀은 한결 나아졌습니다.
1.3.2. Scatter Aesthetics
-
이제 데이터 부분을 수정해 봅시다.
- 데이터를 눈금 앞으로 옮기고 →
zorder사용 - 데이터에 윤곽선을 만들어주면 됩니다. → ???
- 데이터를 눈금 앞으로 옮기고 →
-
scatter plot 전체를 둘러싸는 윤곽선은 트릭이 필요합니다.
- scatter plot을 똑같이 하나 더 만듭니다.
- 새 scatter plot에 두꺼운 윤곽선을 두릅니다.
- 원래 그림의 아래에 깔면 결과적으로 뭉쳐진 알갱이들을 둘러싸는 윤곽선이 그려집니다.
-
파워포인트에도 적용할 수 있는 트릭입니다.

-
재사용을 위해 함수화합니다.
- 컬러맵 리스트와 각 제목을 입력으로 받습니다.
- 제목이 없으면 컬러맵 이름을 제목으로 사용합니다.
- 파일명을 입력받아 파일로 저장합니다.
-
최종 코드와 결과물입니다.
1 | def plot_L(cmaps, titles=None, filename=None): |

- 필요한 그림을 그릴 수 있습니다.
1 | plot_L(["rainbow", "jet", "gnuplot", "brg", "cubehelix"], filename="L_rainbow") |

- 본 글에 사용된 코드는 이 곳에서 다운받을 수 있습니다.