Matplotlib 을 통한 인구 이동 그래프(1)

2021. 7. 8. 13:47(Python) Pandas를 이용한 데이터분석

3~4일 가량 판다스와 더불어 오랜만에 사용하는 파이썬과 친해지고 돌아왔다.

오늘은 Pandas에도 기본내장 시각화 도구가 있지만 풍부하진 않다.

 

처음 다룰 라이브러리는 대표적인 시각화 프로그램 Matplotlib이다.

 

선그래프는 연속하는 데이터 값들을 직선 또는 곡선으로 연결하여 데이터 값 사이의

관계를 나타내다. 특히 사계열 데이터와 같이 연속적인 값 변화와 패턴을 파악하는데 적합하다.

 

일단 데이터를 불러오자!

오늘 사용할 데이터는 시도별 전출입 인구수 데이터이다.

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_excel('D:/5674-833_4th/part4/시도별 전출입 인구수.xlsx',engine = 'openpyxl',header =0)
print(df.head())

   전출지별   전입지별      1970      1971  ...      2014      2015      2016      2017
0  전출지별   전입지별  이동자수 (명)  이동자수 (명)  ...  이동자수 (명)  이동자수 (명)  이동자수 (명)  이동자수 (명)
1    전국     전국   4046536   4210164  ...   7629098   7755286   7378430   7154226
2   NaN  서울특별시   1742813   1671705  ...   1573594   1589431   1515602   1472937
3   NaN  부산광역시    448577    389797  ...    485710    507031    459015    439073
4   NaN  대구광역시         -         -  ...    350213    351424    328228    321182

전출지별 칼럼을 위와 같으면 fill 하도록 설정해주고 

서울에서 다른지역으로 이동한 데이터만 추출해서 정리한후

서울에서 경기도로 이동한 인구데이터 값으로 그래프를 그려보자

df = df.fillna(method='ffill') #누락값을 앞 데이터로 채움

#서울에서 다른 지역으로 이동한 데이터만 추출하여 정리
mask = (df['전출지별'] == '서울특별시') & (df['전입지별'] != '서울특별시')
df_seoul = df[mask]
df_seoul = df_seoul.drop(['전출지별'],axis= 1) #전출지별 column 삭제
df_seoul.rename({'전입지별':'전입지'},axis=1,inplace=True) #전입지별 column을 전입지로 바꿔줌
df_seoul.set_index('전입지',inplace = True)

#서울에서 경기도로 이동한 인구데이터 값만 선택
sr_one = df_seoul.loc['경기도']

plt.plot(sr_one.index,sr_one.values) # or plt.plot(sr_one)

여기서 제목과 x,y축을 입력하려니 font 오류가 난다. 

알고보니 한글 폰트 오류였다;;

from matplotlib import font_manager,rc
font_path ="D:/5674-833_4th/part4/malgun.ttf"
font_name = font_manager.FontProperties(fname=font_path).get_name()
rc('font',family = font_name)

그래서 이 구문을 추가하고 

다시 그래프를 그려보니

하지만 밑의 숫자들이 너무 모여있어서 보기가 어렵다.

그래서 그림 사이즈를 늘려주고 x축 라벨을 회전시킨다.

그리고 lengend 함수를 통해 범례도 지정한다.

# 제목정함
plt.title('서울 -> 경기 인구 이동')

# 축이름 추가
plt.xlabel('기간')
plt.ylabel('이동인구수')

#그림 사이즈 지정
plt.figure(figsize=(14,5))
#x 축 눈금 라벨 회전하기
plt.xticks(rotation = 'vertical')

#x 축 y 축 데이터를 plot 함수에 입력
plt.plot(sr_one.index,sr_one.values)

plt.legend(labels=['서울 -> 경기'],loc = 'best')

plt.show()

다음과 같이 깔끔한 그래프가 완성되었다.

 

그리고 스타일을 지정해보면

plt.style.use('ggplot') #ggplot 스타일 지정

#x 축 y 축 데이터를 plot 함수에 입력, 점을 찍어준다
plt.plot(sr_one.index,sr_one.values,marker = 'o',markersize = 10)

ggplot은 R에서는 package가 따로 있었는데 python에서는 스타일로 하나보다 신기하다

 

또 어떤 스타일이 있나 궁금해서 보니

print(plt.style.available)
['Solarize_Light2', '_classic_test_patch', 'bmh', 'classic', 
'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale',
'seaborn', 'seaborn-bright', 'seaborn-colorblind', 'seaborn-dark', 
'seaborn-dark-palette', 'seaborn-darkgrid', 'seaborn-deep', 'seaborn-muted', 
'seaborn-notebook', 'seaborn-paper', 'seaborn-pastel', 'seaborn-poster', 
'seaborn-talk', 'seaborn-ticks', 'seaborn-white', 'seaborn-whitegrid', 'tableau-colorblind10']

엄청나게 많다... 저걸 다 사용할까?? 고수가 되면 사용하겠지??

 

그리고 이제 주석을 달아준다..

#y축 범위지정
plt.ylim(50000,800000)

# #주석표시

plt.annotate('',
             xy= (20,620000), # 화살표의 머리부분(끝점)
             xytext=(2,290000), #화살표의 꼬리부분 (시작점)
             xycoords = 'data', #좌표체계
             arrowprops=dict(arrowstyle = '->',color = 'skyblue',lw = 5),)

plt.annotate('',
             xy = (47,450000),
             xytext=(30,580000),
             xycoords='data',
             arrowprops = dict(arrowstyle = '->',color = 'olive',lw =5),)

#주석표시-텍스트

plt.annotate('인구 이동 증가(1970~1995)', #텍스트입력
             xy = (10,550000), #텍스트 위치 기준점
             rotation = 25, #텍스트 회전 각도
             va = 'baseline', #텍스트 상하 정렬
             ha = 'center', #텍스트 좌우 정렬
             fontsize = 15, #텍스트 크기
             )

plt.annotate('인구 이동 감소(1995~2017)',
             xy = (40,560000),
             rotation = 11,
             va = 'baseline',
             ha = 'center',
             fontsize = 15,
             )

이 작업이 제일 힘든거 같다

...

우리나라 인구의 절반이 산다는 서울특별시와 경기도 간의 인구 이동변화가 화살표 주석과 함께

선 그래프로 표시된다. 1990년대 중반까지 경기도권 5대 신도시(분당,일산 등) 개발로 서울 인구의

대규모 경기도 유입이 있었음을 추정할 수 있다. 이 시기를 정점으로 서울을 벗어나 경기권으로 

이동하는 인구는 현재까지 계속 감소하는 트렌드를 보이고 있다.

 

여기서 화면분할을 한뒤 두개의 그래프를 한 화면에 보여주고 싶다면?

axe 객체를 사용한다.

#그래프 객체 생성(figure에 2개의 서브 플롯 생성)
fig = plt.figure(figsize=(10,10))
ax1 = fig.add_subplot(2,1,1)
ax2 = fig.add_subplot(2,1,2)

#axe객체에 plot함수로 그래프 출력
ax1.plot(sr_one,'o',markersize = 10)
ax2.plot(sr_one,marker = 'o',markerfacecolor='green',markersize =10,
         color = 'olive',linewidth = 2, label = '서울 -> 경기')

ax2.legend(loc = 'best')

#y축 범위 지정(최소값, 최대값)
ax1.set_ylim(50000,800000)
ax2.set_ylim(50000,800000)

#축 눈금 라벨 지정 및 75도 회전
ax1.set_xticklabels(sr_one.index,rotation = 75)
ax2.set_xticklabels(sr_one.index, rotation = 75)

plt.show()

add_subplot의 파라미터는 add_subplot(행의크기,열의크기,서브플롯 순서) 가 있다.

그리고 첫번째 그래프에는 'o' 옵션을 넣어서 선 없이 점만 나타나는 그래프를 그렸고,

두번째 그래프에는 marker = 'o' 라는 옵션을 추가하여 원 모양마커를 가진 선그래프를 그린다.

 

한 화면에 여러개의 그래프를 띄울수도 있다.

서울에서 충청남도, 경상북도, 강원도로 인구이동한 그래프 3개를 화면에 띄워보자

import pandas as pd
import matplotlib.pyplot as plt
#한글 폰트 오류 제거
from matplotlib import font_manager,rc
font_path ="D:/5674-833_4th/part4/malgun.ttf"
font_name = font_manager.FontProperties(fname=font_path).get_name()
rc('font',family = font_name)

df = pd.read_excel('D:/5674-833_4th/part4/시도별 전출입 인구수.xlsx',engine = 'openpyxl',header =0)
df = df.fillna(method='ffill') #누락값을 앞 데이터로 채움

#서울에서 다른 지역으로 이동한 데이터만 추출하여 정리
mask = (df['전출지별'] == '서울특별시') & (df['전입지별'] != '서울특별시')
df_seoul = df[mask]
df_seoul = df_seoul.drop(['전출지별'],axis= 1) #전출지별 column 삭제
df_seoul.rename({'전입지별':'전입지'},axis=1,inplace=True) #전입지별 column을 전입지로 바꿔줌
df_seoul.set_index('전입지',inplace = True)

print(df_seoul)
#서울에서 충청남도 , 경상북도 ,강원도 로 이동한 인구 데이터 값 선택
col_years = list(map(str,range(1970,2018)))
df_3 = df_seoul.loc[['충청남도','경상북도','강원도'],col_years]

#스타일 지정
plt.style.use('ggplot')

#그래프 객체 생성(figure에 1개의 서브 플롯생성)
fig = plt.figure(figsize=(20,5))
ax =fig.add_subplot(1,1,1)

#axe 객체에 plot 함수로 그래프 출력

ax.plot(col_years,df_3.loc['충청남도',:],marker = 'o',markerfacecolor = 'green',
        markersize = 10,color = 'olive',linewidth = 2, label = '서울 -> 충남')
ax.plot(col_years,df_3.loc['경상북도',:],marker = 'o',markerfacecolor = 'blue',
        markersize = 10, color = 'skyblue', linewidth = 2 , label = '서울 -> 경북')
ax.plot(col_years,df_3.loc['강원도',:],marker = 'o',markerfacecolor = 'red',
        markersize =10, color = 'magenta',linewidth = 2, label = '서울 -> 강원')

#범례표시

ax.legend(loc = 'best')

#차트 제목 추가
ax.set_title('서울 -> 충남, 경북 , 강원 인구 이동',size = 20 )

#축 이름 추가
ax.set_xlabel('기간',size =12)
ax.set_ylabel('이동 인구수',size =12)

#축 눈금 라벨 지정 및 90 도 회전
ax.set_xticklabels(col_years,rotation = 90)

#축 눈금 라벨 크기
ax.tick_params(axis = "x", labelsize =10)
ax.tick_params(axis = "y", labelsize= 10)

plt.show()

이번엔 한 화면의 4개의 그래프를 그려보자

4개의 axe객체를 만들어서 화면에 표시한다.

#그래프 객체 생성(figure에 1개의 서브 플롯 생성)
fig = plt.figure(figsize=(20,15))
ax1 = fig.add_subplot(2,2,1)
ax2 = fig.add_subplot(2,2,2)
ax3 = fig.add_subplot(2,2,3)
ax4 = fig.add_subplot(2,2,4)

#axe 객체에 plot 함수로 그래프 출력
ax1.plot(col_years,df_4.loc['충청남도',:], marker ='o',markerfacecolor = 'green',
         markersize = 10, color = 'olive',linewidth = 2, label = '서울 -> 충남')
ax2.plot(col_years,df_4.loc['경상북도',:], marker ='o',markerfacecolor = 'blue',
         markersize = 10, color = 'skyblue',linewidth = 2, label = '서울 -> 경북')
ax3.plot(col_years,df_4.loc['강원도',:], marker ='o',markerfacecolor = 'red',
         markersize = 10, color = 'magenta',linewidth = 2, label = '서울 -> 강원')
ax4.plot(col_years,df_4.loc['전라남도',:], marker ='o',markerfacecolor = 'orange',
         markersize = 10, color = 'yellow',linewidth = 2, label = '서울 -> 전남')