pbj0812의 코딩 일기

[PYTHON] 자동화 Pie-Donut 차트 만들기 본문

ComputerLanguage_Program/PYTHON

[PYTHON] 자동화 Pie-Donut 차트 만들기

pbj0812 2021. 2. 21. 01:22

0. 목표

 - 자동화 Pie-Donut 차트 만들기

1. 기존의 Pie-Donut 차트 분석

 - 기존 원본 링크

 - 기존에는 숫자, 사이즈, 명암을 사람의 손으로 구해야 되어서 불편함이 많음

2. FlowChart

3. 실습

 1) library 호출

  - 차트에 한글을 넣기 위한 rc 호출(mac)

import pandas as pd
import random
import numpy as np
from matplotlib import rc
rc('font', family='AppleGothic')

 2) 데이터 생성

df = pd.DataFrame({'학년' : ['1학년', '2학년', '3학년', '1학년', '2학년', '1학년', '1학년'], '반' : ['1반', '2반', '3반', '4반', '1반', '1반', '5반'], '명단' : ['민수', '수지', '수영', '찬수', '천재', '미래', '찬호']})

 3) 1차 그룹화(바깥 도넛을 위한)

  - 첫 번째 열을 명단, 마지막 열을 기준 숫자로 지정

df2 = df.groupby(by = [df.columns[0]], as_index = False).count()
group_name = df2[df2.columns[0]]
group_size = df2[df2.columns[2]]

 4) 2차 그룹화(안쪽 도넛을 위한)

  - 두번째 열을 서브 네임, 마지막 열을 서브에 해당하는 숫자로 지정

df3 = df.groupby(by = [df.columns[0], df.columns[1]], as_index = False).count()
subgroup_name = df3[df3.columns[1]]
subgroup_size = df3[df3.columns[2]]
tmp_subgroup_name = df3[df3.columns[0]]

 5) 각 서브의 크기 산정

 - array([3., 2., 1.])

zero_box = np.zeros(len(group_name))
for i in range(len(group_name)):
    for j in tmp_subgroup_name:
        if j == group_name[i]:
            zero_box[i] += 1
        else:
            pass

 6) 기준 색상 제작

  - 랜덤 함수를 통해 제작

color_list = np.zeros([len(group_name), 4])
color_list[:, 3] = 1

for i in range(len(group_name)):
    color_list[i][0] = random.random()
    color_list[i][1] = random.random()
    color_list[i][2] = random.random()

 7) 서브 색상 제작

sub_size = 0
for i in zero_box:
    sub_size += i
    
sub_color_list = np.zeros([int(sub_size), 4])

order = 0 # 리스트
order2 = 0 # 
for i in zero_box:
    if i == 1:
        color_range = 1
        sub_color_list[order][0] = color_list[order2][0]
        sub_color_list[order][1] = color_list[order2][1]
        sub_color_list[order][2] = color_list[order2][2]
        sub_color_list[order][3] = 1
        order+=1
        
    else:
        color_range = np.linspace(0.1, 1, int(i))
        for j in range(int(i)):
            sub_color_list[order][0] = color_list[order2][0]
            sub_color_list[order][1] = color_list[order2][1]
            sub_color_list[order][2] = color_list[order2][2]
            sub_color_list[order][3] = color_range[j]
            order+=1
    order2+=1

 8) 그림 제작 부분

  - 기존 코드에서 크기, 색상을 결정하는 부분을 위에서 만든 변수를 통하여 자동화하도록 구성

fig, ax = plt.subplots()

ax.axis('equal')

pie_outside, _ = ax.pie(group_size, 

                        radius=1.3, 

                        labels=group_name, 

                        labeldistance=0.8,

                        colors=color_list)

plt.setp(pie_outside, 

         width=width_num, 

         edgecolor='white')



# Inside Ring

pie_inside, plt_labels, junk = \
    ax.pie(subgroup_size, 

           radius=(1.3 - width_num), 

           labels=subgroup_name, 

           labeldistance=0.75, 

           autopct='%1.1f%%', 

           colors=sub_color_list)

plt.setp(pie_inside, 

         width=width_num, 

         edgecolor='white')

plt.title('Donut Plot with Subgroups', fontsize=20)

plt.show()

4. 결과

5. 함수 형태

 1) library 호출

import pandas as pd
import random
import numpy as np
from matplotlib import rc
rc('font', family='AppleGothic')

 2) 함수 제작

def donut_pie(df, title):
    df2 = df.groupby(by = [df.columns[0]], as_index = False).count()
    
    group_name = df2[df2.columns[0]]
    group_size = df2[df2.columns[2]]

    df3 = df.groupby(by = [df.columns[0], df.columns[1]], as_index = False).count()
    
    subgroup_name = df3[df3.columns[1]]
    subgroup_size = df3[df3.columns[2]]
    tmp_subgroup_name = df3[df3.columns[0]]
    
    zero_box = np.zeros(len(group_name))
    
    width_num = 0.4
    
    for i in range(len(group_name)):
        for j in tmp_subgroup_name:
            if j == group_name[i]:
                zero_box[i] += 1
            else:
                pass
        
    color_list = np.zeros([len(group_name), 4])
    color_list[:, 3] = 1
    for i in range(len(group_name)):
        color_list[i][0] = random.random()
        color_list[i][1] = random.random()
        color_list[i][2] = random.random()
    
    sub_size = 0
    for i in zero_box:
        sub_size += i
        
    sub_color_list = np.zeros([int(sub_size), 4])
    
    order = 0 # 리스트
    order2 = 0 # 
    for i in zero_box:
        if i == 1:
            color_range = 1
            sub_color_list[order][0] = color_list[order2][0]
            sub_color_list[order][1] = color_list[order2][1]
            sub_color_list[order][2] = color_list[order2][2]
            sub_color_list[order][3] = 1
            order+=1

        else:
            color_range = np.linspace(0.1, 1, int(i))
            for j in range(int(i)):
                sub_color_list[order][0] = color_list[order2][0]
                sub_color_list[order][1] = color_list[order2][1]
                sub_color_list[order][2] = color_list[order2][2]
                sub_color_list[order][3] = color_range[j]
                order+=1
        order2+=1
        
    fig, ax = plt.subplots()

    ax.axis('equal')

    pie_outside, _ = ax.pie(group_size, 

                            radius=1.3, 

                            labels=group_name, 

                            labeldistance=0.8,

                            colors=color_list)

    plt.setp(pie_outside, 

             width=width_num, 

             edgecolor='white')



    # Inside Ring

    pie_inside, plt_labels, junk = \
        ax.pie(subgroup_size, 

               radius=(1.3 - width_num), 

               labels=subgroup_name, 

               labeldistance=0.75, 

               autopct='%1.1f%%', 

               colors=sub_color_list)

    plt.setp(pie_inside, 

             width=width_num, 

             edgecolor='white')

    plt.title(title, fontsize=20)

    plt.show()

 3) 데이터 생성

df = pd.DataFrame({'학년' : ['1학년', '2학년', '3학년', '1학년', '2학년', '1학년', '1학년'], '반' : ['1반', '2반', '3반', '4반', '1반', '1반', '5반'], '명단' : ['민수', '수지', '수영', '찬수', '천재', '미래', '찬호']})

 4) 실행

  - 3) 에서 만든 데이터 프레임 및 차트 명 입력

  - 단점 : 색상의 랜덤화

donut_pie(df, '금일 지각생 비율')

6. 참고

 - [Python] 원 그래프 (Pie Chart), 하위 그룹을 포함한 도넛 그래프 (Donut Chart with Subgroups)
 - 난수 (random)

Comments