본문 바로가기
데이터 분석/시각화

[바 차트(Bar chart)] 3. Matplotlib 바 차트 번외 - 막대에 그라데이션 적용하기

by 부자 꽁냥이 2020. 6. 14.

안녕하세요~ '꽁냥이'입니다.

 

꽁냥이는 다음과 같이 5편에 걸쳐 바 차트에 관한 내용을 포스팅합니다.

 


1. Matplotlib을 이용하여 바 차트, 수평 바 차트 그리기

2. Matplotlib을 이용하여 바 차트 꾸미기

3. Matplotlib 바 차트 번외 - 막대에 그라데이션 적용하기

4. Matplotlib을 이용하여 그룹 바 차트(Grouped bar chart) 그리기

5. Matplotlib을 이용하여 스택 바 차트(Stacked bar chart) 그리기


이번 포스팅에서는 바 차트(Bar chart) 번외 편으로 막대에 그라데이션을 적용하는 방법을 소개합니다. 사실 이 내용을 이전 포스팅([바 차트(Bar chart)] 2. Matplotlib을 이용하여 바 차트 꾸미기)에서 다루려고 했지만 그라데이션을 적용하는 문제는 기존의 바 차트 꾸미는 방법과 조금 다르기 때문에 따로 포스팅을 만들어서 소개하려고 해요. 

 

보통 바 차트를 생성하거나 꾸밀 때 bar 메서드를 이용했다는 것은 지난 포스팅을 통해서 아셨을 거예요. 하지만 bar 메서드에는 그라데이션을 직접 적용할 수 있는 방법이 없는 거 같더라고요(문서랑 인터넷 검색해봤는데 못 찾았어요. 아시는 분은 알려주시면 감사하겠습니다). 그래서 다른 방법을 사용해야 하는데요. 그럼 그 방법을 살펴볼게요.

 

여기서 다루는 내용은 아래와 같아요.

 

1. 그라데이션 적용 원리

2. 전체 코드

3. 코드 설명

 

이번 포스팅은 아래 사이트를 참고하였습니다.

 

Matplotlib - Bar chart with gradients :

https://matplotlib.org/3.2.0/gallery/lines_bars_and_markers/gradient_bar.html

LIST

   1. 그라데이션 적용 원리

먼저 그라데이션을 적용하는 과정을 알아보겠습니다. 아래 그림을 보시죠~

 

위 그림은 그라데이션을 적용하는 과정을 설명한 그림인데요. 먼저 1) 막대기를 생성하고요. 그런 다음에 2) 막대기의 색을 비워주고 3) 막대기의 꼭지점 좌표를 계산하여 그라데이션을 적용할 범위를 정해줍니다. 마지막으로 4) 범위안에 그라데이션을 덧칠해주면 됩니다~


   2. 전체 코드

자! 방법은 알았으니 코드로 구현해볼까요? 바 차트로 그릴 데이터는 이전 포스팅과 동일하게 연령별 방문 환자수로 정했습니다.

 

전체 코드는 다음과 같습니다.

import numpy as np
import matplotlib.pyplot as plt

## 데이터
age_category = ['10대 이하', '20대', '30대', '40대', '50대', '60대 이상'] ## 연령 카테고리, x축 눈금에 표시될 라벨
num_patient = [3,3,5,7,8,9] ## 방문환자수

## 시각화
tick_size = 13 ## 눈금 폰트 사이즈
axis_label_size = 15 ## x축, y축 폰트 사이즈

plt.figure(figsize=(10,10)) ## Figure 생성 사이즈는 10 by 10
xtick_label_position = list(range(len(age_category))) ## x축 눈금 라벨이 표시될 x좌표
plt.xticks(xtick_label_position, age_category) ## x축 눈금 라벨 출력

bar = plt.bar(xtick_label_position, num_patient) ## 바차트 출력
cmap = plt.get_cmap('Greens') ## 그라데이션 색상

plt.title('지난달 연령별 방문환자 수',fontsize=20) ## 타이틀 출력
plt.xlabel('연령',fontsize=axis_label_size) ## x축 라벨 출력
plt.ylabel('방문환자수',fontsize=axis_label_size) ## y축 라벨 출력

def gradientbars(bars,cmap):
    '''
    막대기의 그라데이션을 적용시켜주는 함수
    '''
    grad = np.expand_dims(np.linspace(0,1,256),0).T ## 그라데이션을 적용할 컬러 값
    ax = bars[0].axes ## 막대기가 그려진 axes를 가져온다. 이 axes위에 그라데이션을 그린다.
    lim = ax.get_xlim()+ax.get_ylim() ## 처음 바 차트가 그려진 x좌표와 y좌표를 저장
    for bar in bars:
        bar.set_facecolor("none") ## 막대기의 색상을 비워준다.
        x,y = bar.get_xy() ## 막대기의 좌측 하단 x, y좌표
        w, h = bar.get_width(), bar.get_height() ## 막대기의 폭과 높이
        ax.imshow(grad, extent=[x,x+w,y+h,y], cmap = cmap, aspect="auto",\
                   vmin=-0.5, vmax=2) ## 막대기안에 그라데이션을 그려준다.
    ax.axis(lim) ## 처음에 그린 바차트의 x좌표 한계값과 y좌표 한계값을 적용한다.

gradientbars(bar,cmap)
plt.show() 
반응형

   3. 코드 설명

핵심적인 부분만 설명할게요. 설명하지 않는 부분은 주석을 참고하시면 됩니다~

 

우선 바 차트를 생성하구요(16번째 줄). -> 한글 설정 부분과 바 차트를 그리는 기본적인 방법은 아래 포스팅을 참고하세요.

 

Matplotlib 한글 폰트 설정 : https://zephyrus1111.tistory.com/7

Matplotlib을 이용하여 바 차트 그리기 : https://zephyrus1111.tistory.com/8

 

plt.get_cmap을 이용하여 그라데이션을 적용할 색상을 정해줍니다(17번째 줄). 적용 가능한 색상은 아래 사이트를 참고하세요.

 

색상 종류 : https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html

 

다음은 이번 포스팅의 핵심인 gradientbars 함수입니다. 하나씩 살펴볼까요?

먼저 그라데이션을 적용할 컬러 값을 지정합니다(27번째 줄). 이 값은 2차원 배열로 지정해줘야 하는데요. 아래 코드를 실행해보세요.

grad = np.expand_dims(np.linspace(0,1,256),0).T
print(grad.shape)

실행 결과

위와 같이 컬러 값을 (256, 1)인 2차원 배열로 지정해야해요. 먼저 np.linspace를 이용하여 0부터 1까지의 값을 동일한 간격으로 255(256-1)등분으로 나누어주고요. np.linspace는 1차원 배열이므로 2차원 배열로 확장하기 위해서 np.expand_dims를 사용합니다. 그리고 세로 방향으로 그라데이션의 변화를 주기 위해서 반드시 transpose를 해주셔야 합니다(이를 생략하면 그라데이션의 변화가 가로로 적용됩니다).

 

위에서 256이라는 숫자를 주목해주세요. 이 값은 그라데이션의 연속성을 결정하는 값이에요. 이 값이 커야 연속적인 색상의 변화를 표현할 수 있어요. 이해가 안 되신다고요? 꽁냥이가 여러분의 이해를 돕기 위해서 앞의 숫자에 따른 그라데이션의 변화를 간단하게 구현해봤습니다. 아래 코드를 실행해보세요(코드 설명은 주석을 참고하세요).

 

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(10,10))
bars = plt.bar([1,2,3],[10,10,10]) ## 바 차트 출력

## 3가지 컬러 2차원 배열
grad1 = np.expand_dims(np.linspace(0,1,5),0).T
grad2 = np.expand_dims(np.linspace(0,1,10),0).T
grad3 = np.expand_dims(np.linspace(0,1,256),0).T
grad = [grad1,grad2,grad3]

cmap = plt.get_cmap('Greens') ## 그라데이션 색상

ax = bars[0].axes ## 막대기가 그려진 axes를 가져온다. 이 axes위에 그라데이션을 그린다.
lim = ax.get_xlim()+ax.get_ylim() ## 처음 바 차트가 그려진 x좌표와 y좌표를 저장
text = ['5', '10', '256'] ## 출력할 텍스트 값
for i, bar in enumerate(bars):
    bar.set_facecolor("none") ## 막대기의 색상을 비워준다.
    x,y = bar.get_xy() ## 막대기의 좌측 하단 x, y좌표
    w, h = bar.get_width(), bar.get_height() ## 막대기의 폭과 높이
    ax.text(x+w*(1/2),y+h+0.2, \
            text[i],ha='center',fontsize=13) ## 텍스트 생성
    ax.imshow(grad[i], extent=[x,x+w,y+h,y], cmap = cmap, \
              aspect="auto", vmin=-0.5, vmax=2) ## 막대기안에 그라데이션을 그려준다.

ax.axis(lim) ## 처음에 그린 바차트의 x좌표 한계값과 y좌표 한계값을 적용한다.
plt.show()

 

실행 결과

위 그림을 보시면 알겠지만 첫 번째 숫자의 값이 작아 질수록 연속적이 아닌 띄엄띄엄 그라데이션이 그려지게 됩니다. 따라서 최대한 값을 크게 지정해줘야 연속적인 그라데이션이 그려지게 된다는 거 잊지 마세요~!!

다음으로 기존 막대기가 그려진 그림 뼈대위에 그라데이션을 덧칠하기 위해서 Axes 객체를 불러옵니다(28번째 줄). 여기서는 막대기가 6개가 생성되지만 6개 모두 같은 그림 뼈대를 가지고 있으므로 첫 번째 막대기의 Axes 객체를 불러오면 됩니다.

 

그라데이션을 계속 적용하다 보면 처음에 그려진 것과 다르게 테두리 여백이 없어지고 시작 방향이 다르게 됩니다(시작 방향이 다른 것은 그라데이션을 높이가 올라갈수록 색상을 진하게 적용시키는 것 때문이라는 것이라고 알고 계시면 됩니다).

따라서 처음 그려진 그림의 범위를 반드시 저장해야합니다(29번째 줄).

 

아래의 그림을 보시면 이해할 수 있어요(저장한 경우와 저장하지 않은 경우, 테두리 여백이 달라졌음을 확인하세요).

이제 각 막대기에 대해서 색상을 비워주고요(31번째 줄). 막대기 좌측 하단의 x, y좌표와 막대기의 폭, 높이를 가져옵니다(32~33번째 줄).

 

34번째 줄은 ax.imshow 메서드를 사용하여 실제로 그라데이션을 그리는 부분입니다. 그라데이션을 그리기 위한 ax.imshow의 기본 사용법은 다음과 같습니다.

 

ax.imshow(컬러 값, 적용 범위, 적용 색상 , . . . )

 

먼저 grad에 저장했던 컬러값을 첫 번째 인자로 주고, 적용범위를 extent라는 인자에 넣어주었습니다. 그리고 17번째 줄의 적용 색상도 넣어주었어요. 추가적으로 x축 눈금에 대한 y축 눈금 길이의 비를 지정할 수 있는 aspect인자에는 "auto"를 넣었고요. 색상 범위를 조절할 수 있는 vmin과 vmax값을 각각 -0.5, 2로 지정해줬습니다. 유의할 점은 이름에서 알 수 있듯이 vmin값은 vmax보다 작아야 한다는 것입니다(안 그러면 에러가 발생합니다). vmin과 vmax인자에 대한 효과는 아래의 코드를 실행하고 그 결과를 먼저 보겠습니다(코드 설명은 주석을 참고하세요).

## vmin, vmax값에 따른 그라데이션 변화
import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(10,10))
bars = plt.bar([1,2,3,4],[10,10,10,10])

cmap = plt.get_cmap('Greens') ## 그라데이션 색상
grad = np.expand_dims(np.linspace(0,1,256),0).T ## 그라데이션을 적용할 컬러 값 

ax = bars[0].axes ## 막대기가 그려진 axes를 가져온다. 이 axes위에 그라데이션을 그린다.
lim = ax.get_xlim()+ax.get_ylim() ## 처음 바 차트가 그려진 x좌표와 y좌표를 저장
v_value = [(1,0), (0.8,0.2), (2,0), (1,-0.5)] ## vmin, vmax에 적용할 값
text = ['vmax=1, vmin=0', 'vmax=0.8, vmin=0.2', \
        'vmax=2, vmin=0', 'vmax=1, vmin=-0.5'] ## 출력할 텍스트
for i, bar in enumerate(bars):
    bar.set_facecolor("none") ## 막대기의 색상을 비워준다.
    x,y = bar.get_xy() ## 막대기의 좌측 하단 x, y좌표
    w, h = bar.get_width(), bar.get_height() ## 막대기의 폭과 높이
    ax.text(x+w*(1/2),y+h+0.2, \
            text[i],ha='center',fontsize=13) ## 텍스트 생성
    ax.imshow(grad, extent=[x,x+w,y+h,y], aspect="auto",cmap = cmap, \
              vmin=v_value[i][1], vmax=v_value[i][0]) ## 막대기안에 그라데이션을 그려준다.

ax.axis(lim) ## 처음에 그린 바차트의 x좌표 한계값과 y좌표 한계값을 적용한다.
plt.show()

 

vmin, vmax값에 따른 그라데이션 변화

가장 왼쪽에 있는 것이 기본 설정일 때를 나타낸 거고요(vmax=1,vmin=0 또는 vmax=None, vmin=None).

 

두 번째를 보시면 vmin값이 0.2인데 막대기 아래쪽(가장 밝은 색)이 전체길이의 20%로 만큼 차지하고 vmax값은 0.8인데 1-0.8=0.2이므로 막대기 위쪽(가장 진한 색)이 전체 길이의 20%로 만큼 차지하는 거에요.

 

세 번째는 vmin은 0으로 vmax는 1보다큰 2로 설정하였는데 1보다 커지면 막대기 위쪽의 색이 달라짐을 확인할 수 있습니다. 기본 설정과 비교했을 때 막대기 아래쪽은 동일하지만 막대기 위쪽의 색깔이 더 연해졌어요.

 

마지막으로 vmax는 기존 값인 1로 설정하고 vmin값을 0보다 작은 값인 -0.5로 설정하였습니다. 이 경우에는 막대기 아래쪽의 색이 변했습니다. 기본 설정과 비교했을 때 막대기 위쪽은 동일지만 막대기 아래쪽이 더 진하게 변했습니다. 

 

이렇듯 vmin과 vmax는 색상의 출발점과 도착점을 지정해주는 값이라고 생각하시면 되고요. 위 코드에서 vmin과 vmax를 변화시켜가면서 맘에 드는 것을 찾으시면 되겠습니다~ 

 

vmin과 vmax에 대한 효과는 꽁냥이도 여러 가지 값을 대입해봐서 경험적으로 알게 된 거예요. 문서를 찾아봐도, 인터넷을 검색해봐도 vmin, vmax인자를 이용한 색상범위 계산식과 구체적인 설명을 찾지 못했거든요 ㅠ.ㅠ. 나중에라도 정확하게 알게 된다면 내용 추가하겠습니당~

 

이제 처음에 설정한 그림 범위로 다시 설정해주시고(36번째 줄) 그리고 우리가 만든 함수를 이용해서 막대기에 그라데이션을 넣어줍니다(38번째 줄).

 

그럼 전체 코드를 실행해볼까요?

그라데이션이 잘 적용되었습니다. 짝짝!!

 

근데 테두리가 없어서 좀 허전해 보이네요. 그라데이션 색상이 초록색이므로 테두리도 초록색으로 설정해줍시다. 16번째 줄을 다음과 같이 바꿔주세요.

bar = plt.bar(xtick_label_position, num_patient, edgecolor='green')

이제 다시 실행해볼게요~

 

어때요? 그라데이션을 넣어주니까 뭔가 있어보이지 않나요?!

 

지금까지 바 차트에서 막대기에 그라데이션을 적용하는 방법에 대해서 알아봤습니다. 여러분도 자신이 좋아하는 색상을 이용해서 그라데이션을 적용시켜보세요~

 

궁금하신 내용이나 잘못된 내용, 그 밖에 하고 싶은 말은 댓글로 남겨주시면 감사하겠습니다.

 

다음 포스팅에서는 그룹 바 차트(Grouped bar chart)를 그려보는 방법을 소개하겠습니다. 다음 포스팅도 기대해주세요.

 

지금까지 '꽁냥이의 글' 읽어 주셔서 감사합니다. 안녕히 계세요~~>0< 


댓글


맨 위로