본문 바로가기
GIS Tech/GIS Data Process

folium HeatMapWithTime 이용하기

by mpv 2021. 2. 15.

김수빈 인턴 작성

 

Heatmap은 원래 사람의 체온분포를 나타내기 위해 사용되지만, 지리정보를 효과적으로 나타내기 위해 사용해보았다.

참고: https://csds.tistory.com/18

여기서 정제한 ‘seouldata.json’ 파일을 이용한다.

import csv
import pandas as pd
from lxml import etree
import os
import json

array = []
with open('seouldata.json', encoding='utf-8', mode='r') as f:
  array = json.load(f)

df = pd.DataFrame(array)

#None 이 아닌 데이터를 필터링
df = df[(df['x'] == df['x']) & (df['y'] == df['y'])].copy()
df['opnSvcNm'].value_counts().iloc[:20]

데이터를 정제하는 것 까지는 참고 링크의 내용과 같다.
df를 살펴보면 다음과 같다:

 

이 예시에서는 지도 상에 나타내려는 상권을 휴게음식점(카페, 등)으로 두었다.
HeatMapWithTime 은 특정지역의 시간에 따른 변화를 나타내는 역할을 하기 때문에, 공간과 시간, 이렇게 두 가지 축이 필요하다. 이 예시에서 공간은 서울특별시 성동구, 시간은 2000년 1월부터 2020년 12월까지 1달 간격으로 보여주도록 하자.

공간을 지정해줄 때는 df 에 있는 ‘lat’, ‘long’ 축을 이용한다. ‘lat’는 ‘latitude’(위도), ‘lng’는 ‘longitude’(경도) 를 의미한다.

우선 시간축을 담을 리스트를 만들어준다. df 의 날짜 형식이 yyyymmdd 이므로 이에 맞춰준다.

total_date = [[str(i) for i in range(j, j+1200, 100)] for j in range(20000100, 20210100, 10000)]
total_date2 = []
for i in total_date:
    total_date2.extend(i)
total_date2

그 다음 HeatMapWithTime으로 정제된 데이터들을 지도에 보여준다.

우선 원하는 지역의 위도, 경도로 범위를 지정해준다. temp_df 는 df 에서 우리가 보여주고 싶은 공간영역만 추출한 자료이다.

temp_df = df[(df['lng'] < 127.06223) & (df['lng'] > 127.02999)]
temp_df= temp_df[(temp_df['lat'] < 37.55190) & (temp_df['lat'] > 37.53393)]

그 다음 기본 지도를 깔아주고 지도가 처음 시작하는 위치를 지정해준다.

lat = temp_df['lat'].mean()
long = temp_df['lng'].mean()
sm = folium.Map([lat,long],zoom_start=15)

HeatMapWithTime에 넣어줄 heat_data 를 만들어야 한다.

heat_data = [[[row['lat'],row['lng']] for index, row in temp_df[((temp_df['apvPermYmd'] < i) & (temp_df['opnSvcNm'] == '휴게음식점')) & (((temp_df['dcbYmd'] == temp_df['dcbYmd']) & (temp_df['dcbYmd'] > str(int(i) + 100))) | (temp_df['dcbYmd'] != temp_df['dcbYmd']))].iterrows()] for i in total_date2]

이 부분이 조금 헷갈린다. 차근 차근 쪼개서 보자면, 예를 들어 2020년 1월에 성동구에 있는 휴게음식점을 보고자 한다면 세 가지 조건이 있는데,

  1. 휴게음식점이어야 한다
  2. 2020년 1월보다 전에 음식점이 허가를 받았어야 한다
  3. 폐업이 되지 않거나 폐업이 되었더라도 2020년 2월 이후에 되었어야 한다

이를 정제해주는 것이 아래 코드이다.

temp_df[((temp_df['apvPermYmd'] < i) & (temp_df['opnSvcNm'] == '휴게음식점')) & (((temp_df['dcbYmd'] == temp_df['dcbYmd']) & (temp_df['dcbYmd'] > str(int(i) + 100))) | (temp_df['dcbYmd'] != temp_df['dcbYmd']))]

이 부분은 temp_df에서 시간 영역에 맞는 휴게음식점들만 선별하는 과정이다. ‘apvPermYmd’ 는 음식점이 허가를 받은 날짜이고, ‘dcbYmd’ 는 음식점이 폐업한 날짜이다. 주의할 점은 폐업을 아직 하지 않은 음식점들은 ‘dcbYmd’ 가 None으로 되어 있고, 날짜와 비교할 때 에러가 날 수도 있다. 그래서 (temp_df['dcbYmd'] == temp_df['dcbYmd']) 를 통해 temp_df[‘dcbYmd’] 가 None 이 아닌 자료들은 날짜와 비교를 하지 않게끔 한다.

그리고 시간 기준이 되는 ‘i’ 는 미리 만들어준 total_date2 라는 리스트를 iterate하는 값이다.

heat_data를 다 만들어주었으면 그대로 HeatMapWithTime에 넣어주면 된다.

plugins.HeatMapWithTime(heat_data, index = total_date2).add_to(sm)
sm

아래는 전체 코드이다.

 #성동구 전반, 휴게음식점
import folium
from folium import plugins
from folium.plugins import HeatMapWithTime

 #원하는 지역의 위도, 경도로 범위를 지정해준다.
temp_df = df[(df['lng'] < 127.06223) & (df['lng'] > 127.02999)]
temp_df= temp_df[(temp_df['lat'] < 37.55190) & (temp_df['lat'] > 37.53393)]

#지도가 처음 보여지는 기준점을 지정해준다.
lat = temp_df['lat'].mean()
long = temp_df['lng'].mean()
sm = folium.Map([lat,long],zoom_start=15)

heat_data = [[[row['lat'],row['lng']] for index, row in temp_df[((temp_df['apvPermYmd'] < i) & (temp_df['opnSvcNm'] == '휴게음식점')) & (((temp_df['dcbYmd'] == temp_df['dcbYmd']) & (temp_df['dcbYmd'] > str(int(i) + 100))) | (temp_df['dcbYmd'] != temp_df['dcbYmd']))].iterrows()] for i in total_date2]
plugins.HeatMapWithTime(heat_data, index = total_date2).add_to(sm)
sm

'GIS Tech > GIS Data Process' 카테고리의 다른 글

OpenStreetMap에서 POI 크롤링  (0) 2024.06.03
Useful Python GIS Skills 2  (0) 2023.11.02
생활인구 시각화  (0) 2021.01.22
Python (GIS+General) Tip 모음  (5) 2021.01.11
주요 좌표계 활용 방법 (TM, UTM-K, KATEC)  (0) 2021.01.11

댓글