본문 바로가기
Computer/python

[Folium] Choropleth 지도 전부 검은색으로 뜰 때 해결법 + 미국 zip code별 GeoJSON 자료

by injeolmialmond 2021. 9. 21.

Folium은 파이썬에서 지도를 이용한 데이터 시각화를 해야 할 때 쓸 수 있는 가장 유용한 툴입니다.

그 중에서도 choropleth의 경우 지도 위에 수치형 데이터를 표현할 수 있기 때문에 많이 사용되는데요,

간혹 데이터프레임의 데이터를 가져다 choropleth map을 구현하려는데, 밑의 캡쳐처럼  모든 지역이 검은색으로 뜨는 현상이 일어날 수 있습니다. (제가 그랬읍니다,,)

구글에 'folium choropleth all black'이라고 치면 나오는 이미지들
나혼자만의 싸움..

하지만 프로그래밍을 하면서 겪는 대부분의 오류들이 그렇듯, 모든 지역이 검은 색으로 나타나는 것은 정해진 규칙들을 지키지 않았기 떄문에 발생합니다.

 

가장 먼저 왜 지역들이 검은 색으로 나오는지를 확인해야 하는데요, folium 공식 문서에 의하면 choropleth 객체에 주게 되는 인자들 중 nan_fill_color는 디폴트로 검은색이 적용된다고 합니다.

http://python-visualization.github.io/folium/modules.html

  • nan_fill_color (string, default 'black') – Area fill color for nan or missing values. Can pass a hex code, color name.

 

따라서 nan_fill_color를 설정하지 않았는데 검은 색으로 뜬다는 것은, 지역들이 모두 NaN 으로 인식된다는 것입니다. 또한 GeoJSON의 데이터는 똑바로 적용되었기에 지역의 경계선에 맞추어 검은 색으로 칠해졌겠죠? 그렇다면 문제는 GeoJSON이 아닌, 데이터프레임에 있다는 뜻입니다.

 

folium 문서를 읽으면 column 인자에 주게 되는 리스트/튜플/딕셔너리 속 첫번째 요소, 그리고 key_on 인자에 주는 GeoJSON의 경로 상 데이터를 매칭시킨다는 것을 알 수 있습니다. 따라서 두 개 데이터의 자료형이 동일해야 합니다!

 

GeoJSON에 매칭하려 했던 데이터프레임의 모양

저는 밑의 링크에서 제공하는 GeoJSON을 사용했는데, 파일에서 제공하는 zip code가 문자열 형태인 것을 모르고, 데이터프레임의 integer 형태였던 zip_code와 대응시키려 했습니다. 따라서 zip_code 역시 문자열 형태로 바꾸어준 뒤 매칭시키니 예쁘게 choropleth map이 그려졌습니다!

코드는 다음과 같습니다.

import json
import urllib.request
import folium
from folium.plugins import MarkerCluster # for clustering the markers

# 유니크한 zip_code들로 이루어진 리스트 만들기
ziplist = list(df_zip['zip_code'].unique())
ints = [int(item) for item in ziplist]

# 내 데이터프레임의 zip_code 변수 문자열로 바꾸기
df_zip['zip_code'] = df_zip['zip_code'].astype(str)

# GeoJSON 파일 갖고오기
url = 'https://github.com/OpenDataDE/State-zip-code-GeoJSON/raw/master/ny_new_york_zip_codes_geo.min.json'
data = urllib.request.urlopen(url).read()
tmp = json.loads(data)

# remove ZIP codes not in our dataset
geozips = []
for i in range(len(tmp['features'])):
    if int(tmp['features'][i]['properties']['ZCTA5CE10']) in ints: # zip_code가 str이니 int로 바꿔 매칭합니다
        geozips.append(tmp['features'][i])

# creating new JSON object
new_json = dict.fromkeys(['type','features'])
new_json['type'] = 'FeatureCollection'
new_json['features'] = geozips

# save JSON object as updated-file
open("updated-file.json", "w").write(
    json.dumps(new_json, sort_keys=True, indent=4, separators=(',', ': '))
)


# 데이터프레임의 연속형 변수를 5분위로 나누어줍니다.
myscale = (df_zip['cnt'].quantile((0, 0.2, 0.4, 0.6, 0.8, 1))).tolist()

# 지도 만들기
map = folium.Map(location=[40.693943, -73.985880], default_zoom_start=12)
map.choropleth(geo_data="updated-file.json",
             data=df_zip, # my dataset
             columns=['zip_code', 'cnt'], # zip code is here for matching the geojson zipcode, sales price is the column that changes the color of zipcode areas
             key_on='feature.properties.ZCTA5CE10', # this path contains zipcodes in str type, this zipcodes should match with our ZIP CODE column
             nan_fill_color='black',
             threshold_scale=myscale,
             fill_color='BuPu', fill_opacity=0.7, line_opacity=0.3,
             legend_name='taxi call num')

# Marker 만들기
marker_cluster = MarkerCluster().add_to(map) # create marker clusters

for i in range(df_zip.shape[0]):
    location = [df_zip['lat'][i],df_zip['lng'][i]]
    tooltip = "zipcode:{}<br> calls: {}<br>".format(df_zip["zip_code"][i], df_zip['cnt'][i])
    
    folium.Marker(location, # adding more details to the popup screen using HTML
                  tooltip=tooltip).add_to(marker_cluster)
                  
map

 

미국 zipcode 별 GeoJSON 파일은 다음 링크에서 구할 수 있습니다.

OpenDataDE/State-zip-code-GeoJSON: Zip code boundaries for each of the 50 states (github.com)

 

GitHub - OpenDataDE/State-zip-code-GeoJSON: Zip code boundaries for each of the 50 states

Zip code boundaries for each of the 50 states. Contribute to OpenDataDE/State-zip-code-GeoJSON development by creating an account on GitHub.

github.com

 

 

 

참고자료)

 

1. 기본적인 choropleth map 만들기

Interactive Map visualization with Folium in Python | by Saidakbar P | Medium

 

Interactive Map visualization with Folium in Python

When working with datasets, more often than not, we encounter property sales, rental or housing-related datasets. At first glance, we…

medium.com

 

2. GeoJSON 중 내 데이터프레임에 있는 자료만 가져오기

Visualizing Data at the ZIP Code Level with Folium | by Finn Qiao | Towards Data Science

 

Visualizing Data at the ZIP Code Level with Folium

Python EDA of LA Restaurant and Market Inspections with regex and GeoJSONs

towardsdatascience.com

 

댓글