본문 바로가기
Python/Data 처리

[python] GIF 그래프 만들어 보기

by 여비코기 2021. 6. 6.

이번 글에서는 지난 게시글에서 다루었던 OPEN API로부터 받아온 데이터를 이용해 움직이는 그래프(GIF)를 만들어보고자 한다.

 

이 움직이는 그래프를 잘 활용한다면 실시간으로 데이터를 업데이트 해주며  즉각적인 데이터의 변동을 표출해줄 수도 있고, 기존에 취득한 데이터들을 정적인 그래프로 보는 것 보다 훨씬 동적으로 변화량을 확인해 볼 수 있다. 

 

우선 OPEN API로 불러온 자료를 재활용 해볼 것이므로, 데이터를 가져오는 방법은 지난 게시글을 참조하면 좋을 것 같다.

 

[Python] OPEN API 데이터 불러오기 (JSON to Pandas DataFrame)

👽멕북 프로 m1을 구입하게 되어 앞으로 게시글들은 맥 m1 프로세서 기준으로 작성될 것 같습니다 (아직 m1을 제대로 완벽히 지원하지 않아 spyder를 못쓰고 jupyter notebook상에서 진행해야 할 것 같

yobbicorgi.tistory.com

----지난 게시글에서 다루었던 OPEN API 데이터 가져오기 부분 코드----

import warnings
warnings.filterwarnings(action='ignore')

from urllib.request import Request, urlopen
from urllib.parse import urlencode, quote_plus
import pandas as pd
from pandas.io.json import json_normalize
import json

 

rl = 'http://apis.data.go.kr/1360000/AsosHourlyInfoService/getWthrDataList'
service_key='인코딩된 나의 key'
queryParams = '?' + urlencode({quote_plus('ServiceKey') : service_key,
                               quote_plus('pageNo') : '1',
                               quote_plus('numOfRows') : '720',
                               quote_plus('dataType') : 'JSON',
                               quote_plus('dataCd') : 'ASOS', 
                               quote_plus('dateCd') : 'HR', 
                               quote_plus('startDt') : '20210101',
                               quote_plus('startHh') : '01',
                               quote_plus('endDt') : '20210131',
                               quote_plus('endHh') : '01',
                               quote_plus('stnIds') : '108' })

 

response = urlopen(url + queryParams)
json_api = response.read().decode("utf-8")

 

json_file = json.loads(json_api)

 

df=json_normalize(json_file['response']['body']['items']['item'])
df

위와같이 기상청 종관관측 ASOS JSON데이터를 불러와 Pandas DataFrame으로 변환해 주었다.

이 DataFrame에서 몇몇 컬럼을 끄집어 내어 변화를 살펴보고자 한다.

 

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import matplotlib as mpl
from matplotlib import font_manager, rc
import sys

GIF를 만드는데 기본적으로 들어가는 FuncAnimation모듈을 포함한 기타 필요한 모듈들을 import해준다.

plt.style.use('fivethirtyeight')

그림 스타일은 fivethirtyeight 를 적용해주었다.

df.columns

데이터프레임의 컬럼 목록을 보면 다음과 같은 것들이 존재한다

Index(['tm', 'rnum', 'stnId', 'stnNm', 'ta', 'taQcflg', 'rn', 'rnQcflg', 'ws', 'wsQcflg', 'wd', 'wdQcflg', 'hm', 'hmQcflg', 'pv', 'td', 'pa', 'paQcflg', 'ps', 'psQcflg', 'ss', 'ssQcflg', 'icsr', 'dsnw', 'hr3Fhsc', 'dc10Tca', 'dc10LmcsCa', 'clfmAbbrCd', 'lcsCh', 'vs', 'gndSttCd', 'dmstMtphNo', 'ts', 'tsQcflg', 'm005Te', 'm01Te', 'm02Te', 'm03Te'], dtype='object')

 

이 중 대기 온도를 나타내는 'ta', 풍속을 나타내는 'ws', 표면 온도를 나타내는 'ts' 총 세가지 컬럼을 이용하여 그래프를 그려보고자 한다.

첫번째는 단일 데이터만을 가지고 그려보며, 두번째는 위 세가지 데이터를 한번에 표현하는 그래프를 그려보고자 한다.

data =  pd.to_numeric(df['ta'], downcast='float')

fig=plt.figure(figsize=(9,6))

def animate(i):
    x = np.linspace(0,i,i+1)
    y1 = data[:i+1]
    plt.cla()
    plt.plot(x, y1, label='Temp_air', lw=3)
    plt.title('ASOS Data [Temp_air]', fontweight='bold')
    plt.ylabel('Value')
    plt.xlabel('Hour')
    plt.legend(loc='upper left')
    plt.tight_layout()
    
ani = FuncAnimation(plt.gcf(), animate, frames=200, interval=1)
ani.save('./animation_single.gif', fps=20)
print('GIF_make_finish')

FuncAnimate를 활용하여 그래프를 그렸으며

animate함수에는 각 프레임마다 x, y 데이터의 길이를 1씩 추가해주는 방식으로 적용해주었다. 이런 방식을 통해 시간이 지날수록 데이터가 어떻게 변화하는지 볼 수 있다.

 

GIF저장은 총 200프레임, 초당 20프레임으로 적용하여 10초짜리의 GIF파일을 만들었으며 결과는 위와 같다.frames, interval, fps를 조절하여 최종적으로 GIF로 저장했을 때 그래프가 진행되는 속도, 재생 길이 등을 언하는 대로 조절할 수 있다.

data1 = pd.to_numeric(df['ta'], downcast='float')
data2 = pd.to_numeric(df['ws'], downcast='float')
data3 = pd.to_numeric(df['ts'], downcast='float')

fig=plt.figure(figsize=(9,6))

def animate(i):
    x = np.linspace(0,i,i+1)
    y1 = data1[:i+1]
    y2 = data2[:i+1]
    y3 = data3[:i+1]
    
    plt.cla()
    plt.plot(x, y1, label='Temp_air', lw=3)
    plt.plot(x, y2, label='Wind_speed', lw=3)
    plt.plot(x, y3, label='Temp_surface', lw=3)
    plt.title('ASOS Data', fontweight='bold')
    plt.ylabel('Value')
    plt.xlabel('Hour')
    plt.legend(loc='upper left')
    plt.tight_layout()
    
ani = FuncAnimation(plt.gcf(), animate, frames=200, interval=1)
ani.save('./animation_multi.gif', fps=20)
print('GIF_make_finish')

위 단일 데이터와 크게 다를 것 없이 data1, data2, data3에 각 컬럼(ta, ws, ts)를 입력하여 그래프를 그려지게 하였다.

 

결과로 보면 대기 온도와, 표면온도는 같은 경향을 보이며 대기 온도가 조금 더 낮은 값을 보이는 것을 확인 할 수 있다.

 

움직이는 그래프를 표현하는 방법은 매우 다양하다. 지금처럼 과거의 결과가 누적되는 그래프가 아닌 예)24시간, 48시간의 x축을 고정으로 두고 새로 들어오는 데이터들을 새로고침하여 표현해 주는 방법도 있을 것이다.

그래프에 관한 게시글을 또 다루게 된다면 그때 한번 표현해보도록 해보겠다.

댓글