티스토리 뷰

목적

지도 위에 우편 번호를 표시합니다. 

 

folium을 이용한 지도 위 우편번호 표시

데이터 준비 

1. 권역코드-우편번호 csv파일(code-bas_id_euc-kr.csv)

        파일다운로드: 지리 데이터 시각화(4) - folium으로 명목형 choropleth 지도 그리기, tool tip 사용

2. 서울시 기초 구역도 geo json파일(TL_KODIS_BAS_W.json)

        파일다운로드: 지리 데이터 시각화(2) - 좌표계 변경 (UTM-K -> WGS84), GeoJSON

 

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

위에서 만든 두 파일을 불러옵니다. 

필요한 라이브러리를 import 합니다. 

import folium
from folium import plugins
import pandas as pd
import matplotlib.colors as mcolors
import json

첫 번째 파일인 권역코드-우편번호 csv 파일을 읽어 df라는 변수에 대입하고,

우편번호를 전처리(zfill)하고,

컬럼명을 변경('우편번호*'->'BAS_ID', '권역코드*'->'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={'권역코드*':'CD'}, inplace=True)
df.head()

두 번째 파일인 서울 geo json 파일을 가져와 geo_json이라는 변수에 대입합니다. 

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

geo_json 파일은 위와같이 생겼습니다.

geo_json의 properties에 df에 있는 권역코드('CD')정보 추가

이제 geo_json에 df에 있는 정보를 합쳐보도록 하겠습니다.

geo_json 데이터의 ['properties']에 'AREA_CD'라는 키를 추가해 해당 우편번호의 권역 코드('CD') 값을 df에서 가져와 채웁니다. 
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']]['CD'].tolist()[0]
    geo_json['features'][i]['properties']['AREA_CD'] = area_cd
  except:
    geo_json['features'][i]['properties']['AREA_CD'] = 'None'

(try except 구문은 안 쓰는 게 좋긴하지만ㅎㅎㅎ 이 데이터 상에서는 전혀 문제 없으니까 그냥 진행 할게요...ㅎㅎ 좋은 대안 있으신 분은 댓글주세요! 감사합니다.)

 

geo_json에서 AREA_CD가 None인 데이터는 불필요하니 제외하겠습니다. 

new_geo_json = dict()
new_geo_json['type'] = geo_json['type']
new_geo_json['features'] = list()

# geo_json 에서 AREA_CD가 None인 데이터 제외
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

특정 권역('CD')에 해당하는 데이터만 선택하고 싶을 경우 아래와 같은 코드를 추가합니다. (저는 추가했습니다. )

# S12, S14인 데이터만 선택
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'].upper() == 'S12':
    new_geo_json['features'].append(geo_json['features'][i])
  elif geo_json['features'][i]['properties']['AREA_CD'].upper() == 'S14':
    new_geo_json['features'].append(geo_json['features'][i])
  else:
    continue

geo_json = new_geo_json

 

지도 생성 및 색상 지정

저는 S12 권역이든 K12 권역이든 12권역이면 전부 orange색으로 칠하고,

S14든 K14든 14권역이면 전부 blue색으로 칠하려고 AREA_CD[1:]=='12', AREA_CD[1:]=='14' 조건을 넣었습니다. 

(색상을 조금 더 쉽게 설정하는 방법: 지리 데이터 시각화(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,
        'line_color' : 'black',
        'weight': 0.5,
        'fillColor': 'orange' if AREA_CD[1:] == '12' \
            else 'blue'if AREA_CD[1:] == '14'\
            else 'white'
    }

gjson = folium.GeoJson(geo_json, 
                       style_function=style_function,
                      ).add_to(m)

 

우편번호 표시

get_loc 이라는 함수를 만들어 해당 우편번호의 중간 위, 경도를 구해 우편 번호를 중간에 적음. 

(get_loc라는 함수를 만든 이유는 coordinates 값이 [[경도, 위도], [경도, 위도], ..., [경도, 위도]] 이런식으로 해당 우편번호의 경계마다 찍혀 있는데 경도의 평균 (avg_a), 위도의 평균(avg_b)값을 구해 해당 우편번호의 중간 위, 경도를 찾기 위해.)

def get_loc(coor):
  avg_a = 0
  avg_b = 0
  for i in range(len(coor)):
    avg_a += float(coor[i][0])
    avg_b += float(coor[i][1])
  avg_a = avg_a/len(coor)
  avg_b = avg_b/len(coor)
  return avg_b, avg_a


for i in range (len(new_geo_json['features'])):
  folium.Marker(
      location=get_loc(geo_json['features'][i]['geometry']['coordinates'][0]),
      icon=plugins.BeautifyIcon(icon="arrow-down",icon_shape="circle", border_width=0, number=int(geo_json['features'][i]['properties']['BAS_ID']))
      ).add_to(m)

이렇게 지도 위에서 우편번호와 해당 우편번호가 커버하는 지역을 확인할 수 있습니다. 

 

한 가지 아쉬운 점이 있다면 folium.Marker에서 icon에 대한 값을 줄 때 BeautifyIcon이라는 플러그인을 이용해서 줬는데

이 때 마커 위엔 숫자만 넣을 수 있고 텍스트는 못 넣더라구요. 그래서 우편번호 앞에 있던 0이 전부 잘리고 네자리만 보이네요.

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