티스토리 뷰

먼저 말씀드리면 저는 plotly로 만든 html 파일이 너무 늦게 열리거나 안 열리는 문제로 folium을 사용하고 있습니다.

folium 사용법을 원하시는 분들은 다음 글을 참고해주세요! ^_^

 

목적

우편번호 별로 권역 코드가 매핑되어 있는 데이터를 지도 위에 표현하고자합니다. 

권역코드 별로 색상 다르게하여 권역을 구분하고 우편번호를 지도 위에서 확인하겠습니다. 

Choropleth map (등치 지도)

등치 지도는 미리 정의된 영역집계 요약을 나타내는 통계 변수(인구 밀도 또는 1인당 소득 등)에 비례해 색이 지정되거나 패턴화된 주제 지도 유형입니다.

변수가 지리적 영역에 따라 어떻게 변하는지 시각화하거나 지역 내 변동성 수준을 표시하는 쉬운 방법을 제공합니다.

 

Plotly를 이용한 시각화

데이터 준비

colab에서 작업을 하였습니다.

 

필요한 라이브러리를 불러옵니다. 

import json
import pandas as pd
import plotly.express as px

권역코드-우편번호 매핑 정보를 가져온 뒤 컬럼명을 변경합니다. ('우편번호*'->'BAS_ID', '권역코드*'->'AREA_CD')

# 권역 - 우편번호 매핑 정보 가져오기
df = pd.read_csv('sample_data/code-bas_id.csv')
df['우편번호*'] = df['우편번호*'].astype('str').str.zfill(5)  # 다섯자리 맞춰주기 위해.
df.rename(columns={'우편번호*':'BAS_ID'}, inplace=True)
df.rename(columns={'권역코드*':'AREA_CD'}, inplace=True)
df = df.reindex(columns=['BAS_ID', 'AREA_CD'])

총 row 수: 1,000

지리 데이터 시각화 (2)에서 만든 서울 기초 구역도 GeoJSON 파일을 json 형태로 load 합니다. 

# 서울 geo json 가져오기
with open('sample_data/TL_KODIS_BAS_W.json') as response:
    geo_json = json.load(response)

 

json 데이터는 아래와 같이 확인할 수 있습니다. 

geo_json.keys()  # dict_keys(['type', 'features'])
geo_json['features'][0].keys()  # dict_keys(['type', 'geometry', 'properties'])
geo_json['features'][0]['type']  # Feature
geo_json['features'][0]['geometry']  # {'coordinates': [[[126.96788111379844, 37.582215153329535], ... 
geo_json['features'][0]['properties']

 

GeoJSON 데이터 합치는 법

서울 GeoJSON 과 경기도 GeoJSON파일을 합치는 방법입니다. 

 

  1. 서울 GeoJSON 파일을 불러온 상태에서 경기도 GeoJSON 파일(TL_KODIS_BAS_W_GG.json) 을 불러옵니다.
  2. 그 후 서울 GeoJSON 파일 변수인 geo_json에 경기도 GeoJSON 파일 변수인 geo_json2를 extend 합니다. 
# 서울 geo json 가져오기
# with open('sample_data/TL_KODIS_BAS_W.json') as response:
#     geo_json = json.load(response)

# 경기도 geo json 가져오기
with open('sample_data/TL_KODIS_BAS_W_GG.json') as response:
    geo_json2 = json.load(response)

# 서울 geo json과 경기도 geo json 합치기.
d = dict()
d['type'] = geo_json['type']
d['features'] = geo_json['features']
d['features'].extend(geo_json2['features'])
geo_json = d

 

1. Plotly

다음은 본격적으로 지도를 만드는 과정입니다. Plotly 는 다양한 그래프 라이브러리 맵을 제공합니다. 

choropleth_mapbox 사용법은 아래 두 사이트를 참고했습니다. 

2. GeoJSON 사용

df 전체 (총 1,000개의 행)를 이용하면 time out error 가 나기 때문에 상위 50개의 데이터만 사용했습니다.

df = df[:50]
fig = px.choropleth_mapbox(data_frame=df, geojson=geo_json,
                           featureidkey="properties.BAS_ID",
                           locations=df['BAS_ID'], color="AREA_CD",
                           opacity=0.5, zoom=9,
                           center={"lat": 37.541, "lon": 126.986},
                           mapbox_style="carto-positron"
                           )
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
# fig.show()
fig.write_html("index.html")

 

choropleth_mapbox 파라미터 설명

  • data_frame: 지도 위에 표시될 정보가 담긴 data frame.
  • geojson: geo json 파일을 그대로 사용.
  • SQL의 merge 처럼 featureidkey, locations에 적힌 값으로 data frame과 geo json 데이터가 연결됨.
    • featureidkey: locations에서 사용할 값과 일치하는 GeoJSON의 key. ex) properties.BAS_ID라고 적어주면 됨.
    • locations: featureidkey와 연결 될 키(df의 컬럼명). 
  • color: 색상을 지정하는데 사용할 df의 컬럼명.
  • opacity: 불투명도 설정. 0과 1사이의 값.
  • zoom: 지도의 확대/축소 수준 설정.
  • center: 지도의 중심점 설정.
  • mapbox_style: 지도 기본 스타일

결과 화면은 아래와 같습니다.

해당 지역에 마우스를 올릴 경우 AREA_CD, BAS_ID 정보를 얻을 수 있습니다. 

 

3. Geo Data Frame 사용 (GeoJSON -> GeoDataFrame)

저는 서울, 경기 GeoJSON 데이터 중 일부분만 사용하는데 사용하지 않는 부분까지 전부 choropleth_mapbox에서 활용하기 때문에 속도가 느린 것 같아 Geo Data Frame을 통해 해결해 보았습니다. 

import geopandas as gpd

Geo JSON을 Geo Data Frame으로 바꾸는 방법입니다. 

geo_json의 'features'부분을 dataframe으로 만들고 우편번호-권역 매핑 정보가 있는 변수 df와 'BAS_ID'를 이용해 merge 합니다. 

geo_df = gpd.GeoDataFrame.from_features(geo_json['features']).merge(df, on='BAS_ID').set_index('BAS_ID')

조금 더 자세히 살펴보면 geo_df = gpd.GeoDataFrame.from_features(geo_json['features])를 통해 아래 json 형식에서 

아래 Data Frame 형식으로 변경이 됩니다. (총 row수: 5,665)

그리고 .merge(df, on='BAS_ID').set_index('BAS_ID') 를 통해 'BAS_ID'를 기준으로 변수 df와 merge를 하고 BAS_ID를 index로 세팅합니다. (총 row수: 440개) 

fig = px.choropleth_mapbox(data_frame=geo_df, geojson=geo_df.geometry,
                           locations=geo_df.index, color='AREA_CD',
                           opacity=0.5, zoom=9,
                           center={"lat": 37.541, "lon": 126.986},
                           mapbox_style="carto-positron")
# fig.show()
fig.write_html("index.html")

Geo JSON 을 사용했을 때와 비교했을 때 data_frame, geojson, locations 부분이 달라지고 featureidkey 부분이 없어졌습니다. 

필요 없는 데이터를 삭제하니 속도도 빨라진 것을 확인할 수 있었습니다. 

 

하지만 그럼에도 더 많은 데이터를 처리할 경우 html페이지가 열리지 않는 경우가 많아 이를 해결하기 위해 folium을 사용했습니다. 

댓글
Total
Today
Yesterday
공지사항
최근에 올라온 글
글 보관함