티스토리 뷰
목적
우편번호 별로 권역 코드가 매핑되어 있는 데이터를 지도 위에 표현하고자합니다.
권역코드 별로 색상을 다르게하여 권역을 구분하고 우편번호를 지도 위에서 확인하겠습니다.
1. folium을 이용한 시각화
데이터 준비
folium의 경우 utf-8로 인코딩된 csv파일을 이용할 경우 오류가 납니다. euc-kr로 인코딩을 변경해주세요.
저는 mac 환경을 사용하고 있고 아래 명령어로 인코딩을 바꾸었습니다.
iconv -c -f utf-8 -t euc-kr code-bas_id.csv > code-bas_id_euc-kr.csv
file -I code-bas_id.csv, file -I code-bas_id_euc-kr.csv 명령어로 인코딩이 잘 된 것을 확인하였습니다.
colab에서 작업을 하였습니다.
- 지리 데이터 시각화(2)에서 만든 서울시 기초 구역도 geo json파일(TL_KODIS_BAS_W.json)
- 경기도 기초 구역도 geo json파일(TL_KODIS_BAS_W_GG.json)
- 위에서 euc-kr로 인코딩한 권역코드-우편번호 매핑 파일(code-bas_id_euc-kr.csv)을 불러옵니다.
필요한 라이브러리를 import 합니다.
import folium
import pandas as pd
import json
euc-kr로 인코딩된 권역코드-우편번호 매핑 csv 파일의 우편번호를 전처리하고 컬럼명을 변경합니다. ('우편번호*'->'BAS_ID', '권역코드*'->'AREA_CD')
df = pd.read_csv('sample_data/code-bas_id_euc-kr.csv', encoding = 'euc-kr')
df['우편번호*'] = df['우편번호*'].astype('str').str.zfill(5) # 다섯자리 맞춰주기 위해.
df.rename(columns={'우편번호*':'BAS_ID'}, inplace=True)
df.rename(columns={'권역코드*':'AREA_CD'}, inplace=True)
df.head()
서울 geo json 파일과 경기도 geo json 파일을 합쳐 geo_json이라는 변수를 만듭니다.
# 서울 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()
# geo_json.keys() # dict_keys(['type', 'features'])
d['type'] = geo_json['type']
d['features'] = geo_json['features']
d['features'].extend(geo_json2['features'])
# len(d['features'])
geo_json = d
geo_json의 구조는 다음과 같습니다.
2. folium.Choropleth
만약 권역코드(AREA_CD) 가 연속형 변수일 경우 아래와 같이 쉽게 Choropleth 지도를 만들 수 있지만
권역 코드가 명목형 변수이기 때문에 folium.Choropleth를 이용할 수 없고 folium.GeoJson을 이용해야합니다.
m = folium.Map(location=[37.541, 126.986], zoom_start=10)
# Choropleth 레이어를 만들고, 맵 m에 추가.
folium.Choropleth(
geo_data=geo_json,
data=df,
columns=['BAS_ID', 'AREA_CD'],
key_on='feature.properties.BAS_ID', # feature.properties.BAS_ID
fill_color='YlGn',
).add_to(m)
m.save("index.html")
만약 명목형 변수 'AREA_CD'를 그냥 사용했을 경우 아래와 같은 오류가 납니다.
TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
3. folium.GeoJson
geo_json의 properties에 특정 값 추가
(folium.GeoJson은 주어진 json파일로만 그래프를 그립니다. 그래서 df에만 있던 AREA_CD 정보를 geo_json에 추가해주어야합니다.)
geo_json 데이터의 ['properties']에 ['AREA_CD']라는 키를 추가해 해당 우편번호의 권역 코드 값을 채웁니다.
df['BAS_ID']에 해당 우편번호가 없다면 AREA_CD엔 'None'값을 채웁니다.
for i in range(len(geo_json['features'])):
try:
area_cd = df[df['BAS_ID'] == geo_json['features'][i]['properties']['BAS_ID']]['AREA_CD'].tolist()[0]
geo_json['features'][i]['properties']['AREA_CD'] = area_cd
except:
geo_json['features'][i]['properties']['AREA_CD'] = 'None'
AREA_CD 추가 | |
이 데이터를 이용해 서울과 경기도 전체 지도를 대상으로 AREA_CD가 None인 것과 None이 아닌 것에 대해 색상을 다르게 해서 지도를 만들어보겠습니다.
참고: https://nbviewer.org/gist/talbertc-usgs/18f8901fc98f109f2b71156cf3ac81cd
center = [37.541, 126.986]
m = folium.Map(location=center, zoom_start=10)
def style_function(feature):
AREA_CD = feature['properties']['AREA_CD']
return {
'fillOpacity': 0.5,
'weight': 0.5,
'fillColor': 'gray' if AREA_CD == 'None' \
else 'orange'
}
gjson = folium.GeoJson(geo_json,
style_function=style_function
).add_to(m)
m.save("index.html")
위 코드에서 중요한 부분은 gjson = folium.GeoJson() 부분입니다. 그 위에 있는 함수는 스타일을 지정해주는 함수에요.
AREA_CD가 None인 부분은 회색, AREA_CD가 None이 아닌 부분은 주황색, 서울+경기가 아닌 부분은 색이 칠해지지 않은 지도를 생성하였습니다.
다음은 geo_json에서 AREA_CD가 None인 데이터를 제외하고 지도를 생성해보겠습니다.
new_geo_json = dict()
new_geo_json['type'] = geo_json['type']
new_geo_json['features'] = list()
for i in range(len(geo_json['features'])):
if geo_json['features'][i]['properties']['AREA_CD'] == 'None':
continue
else:
new_geo_json['features'].append(geo_json['features'][i])
geo_json = new_geo_json
색상도 조금 다양하게 바꿔보았습니다.
(색상을 조금 더 쉽게 설정하는 방법: 지리 데이터 시각화(6) 의 color 참고)
center = [37.541, 126.986]
m = folium.Map(location=center, zoom_start=10)
def style_function(feature):
AREA_CD = feature['properties']['AREA_CD']
return {
'fillOpacity': 0.5,
'fillColor': 'aliceblue' if AREA_CD[1:] == '00' \
else 'cyan'if AREA_CD[1:] == '01'\
else 'greenyellow'if AREA_CD[1:] == '02'\
else 'dimgray'if AREA_CD == 'S03'\
else 'forestgreen'if AREA_CD[1:] == '03'\
else 'yellow'if AREA_CD == 'S04'\
else 'deeppink'if AREA_CD[1:] == '04'\
else 'deepskyblue'if AREA_CD[1:] == '05'\
else 'black'if AREA_CD[1:] == '06'\
else 'blanchedalmond'if AREA_CD[1:] == '07'\
else 'blue'if AREA_CD[1:] == '08'\
else 'blueviolet'if AREA_CD[1:] == '09'\
else 'brown'if AREA_CD[1:] == '10'\
else 'gray'
}
gjson = folium.GeoJson(geo_json,
style_function=style_function
).add_to(m)
m.save("index.html")
4. folium.features.GeoJsonTooltip
지도위에 권역 별로 표시는 되었지만 해당 구역의 우편번호, 권역코드를 확인할 수 없는 불편함이 있었습니다.
이를 해결하기 위해 tool tip 을 추가해 Interactive choropleth 를 그려보았습니다. (참고: https://vverde.github.io/blob/interactivechoropleth.html)
위에서 만든 코드에 m.save("index.html")줄을 제거하고 아래 내용을 추가해줍니다.
style_function = lambda x: {'fillColor': '#ffffff',
'color':'#000000',
'fillOpacity': 0.1,
'weight': 0.1}
highlight_function = lambda x: {'fillColor': '#000000',
'color':'#000000',
'fillOpacity': 0.50,
'weight': 0.1}
NIL=folium.features.GeoJson(
geo_json,
style_function=style_function,
control=False,
highlight_function=highlight_function,
tooltip=folium.features.GeoJsonTooltip(fields=['BAS_ID','AREA_CD'],
aliases=['ZIP_CD','AREA_CD'],
style=("background-color: white; color: #333333; font-family: arial; font-size: 12px; padding: 10px;"),
sticky=True
)
)
m.add_child(NIL)
m.keep_in_front(NIL)
folium.LayerControl().add_to(m)
# m
m.save("index.html")
이렇게 마우스를 올리면 우편번호와 권역코드를 확인할 수 있는 툴팁이 추가 되었습니다.
'지리데이터시각화(geo)' 카테고리의 다른 글
지리 데이터 시각화 (6) folium을 이용한 경유지&경유 순서 시각화, marker의 icon 안에 숫자 (0) | 2022.03.06 |
---|---|
지리 데이터 시각화(5)- folium의 Choropleth지도 오류 (shape file) (0) | 2022.03.05 |
지리 데이터 시각화(3) - plotly로 choropleth 지도 그리기 (Geo JSON, Geo Data Frame) (0) | 2022.03.05 |
지리 데이터 시각화(2) - 좌표계 변경 (UTM-K -> WGS84), GeoJSON (0) | 2022.03.05 |
지리 데이터 시각화(1) - 한국 기초 구역도 합치기, GeoPandas (0) | 2022.03.05 |
- Total
- Today
- Yesterday