Tech Blog
geopandas로 단계구분도 시각화하기 본문
프로젝트에서 지역별 인구수를 나타내는 지도 시각화를 구현해야 하는 일이 있었는데, folium은 너무 인터랙티브하고 실제적인 지도의 느낌이라서, 보다 평면적이고, 직관적인 지도를 그릴 수 있는 라이브러리를 찾아보았다. 그렇게 해서 선택한 라이브러리는 geopadas였고, 전달하고자 하는 정보를 더 효과적으로 시각화 할 수 있었다. 앞으로도 지도 시각화를 할 때 종종 유용하게 쓰일 것 같은데 , 구글링 하다가 정보가 너무 없어서 시각화 했던 과정을 기록해두려고 한다.
라이브러리 설치
!pip install geopandas
!pip install fiona
라이브러리 import
import geopandas as gpd
from fiona.crs import from_epsg
먼저, 사용할 라이브러리를 설치하고 import 한다.
1. 사용 데이터셋 & 시각화를 위한 전처리
1) 서울시 1인가구 데이터
시각화에는 서울시 1인가구(연령별) 통계 데이터를 사용하였고, 분석을 위하여 전처리 한 데이터셋은 다음과 같다.
df_melt.head()
2) 서울시 행정구역 시군구 경계 데이터
국가공간정보포털 에서 서울의 행정구역시군구_경계 데이터를 받을 수 있다.
gdf_admin_gu_pg = gpd.read_file('data/LARD_ADM_SECT_SGG_11.shp', encoding='cp949')
gdf_admin_gu_pg.head()
shp 파일은 read_file로 불러올 수 있고, encoding은 cp949로 해주었다.
3) gdf 전처리
gdf_admin_gu_pg2 = gdf_admin_gu_pg.to_crs(epsg=3857)
좌표계를 3857로 변환한다.
gp = df_melt.groupby("자치구")['1인가구수'].sum().astype("int") # gp: 지역별 1인 가구수
gdf_admin_gu_pg3 = gdf_admin_gu_pg2.rename(columns={"SGG_NM": "자치구"}) # gdf_admin_gu_pg2: gp와 컬럼명 동일하게 변경
gdf_gu = pd.concat([gdf_admin_gu_pg3.set_index("자치구"), gp], axis=1).reset_index() # gp와 gdf_admin_gu_pg2 합치기
gdf_gu.head()
자치구별 1인가구수 시리즈를 생성하고, 컬럼명을 맞춰준 뒤, 자치구를 기준으로 concat 하였다.
columns = ["자치구", "1인가구수"]
gdf_gu2 = gpd.GeoDataFrame(gdf_gu[columns], geometry=gdf_gu.geometry, crs=from_epsg(3857))
gdf_gu2["center"] = gdf_gu2.geometry.centroid
gdf_gu2.head()
시각화에 사용할 컬럼들만 남겨주고, 좌표 설정을 한다. gdf_gu2.geometry.centroid는 밑에서 글자를 넣기 위해 경계의 중점 좌표를 구한 것이다.
2. 기본 지도 시각화
fig = plt.figure(figsize=(18, 13))
ax = fig.subplots(1, 1)
gdf_gu2.plot(color='gray', ax=ax)
ax.set_axis_off()
plt.show()
plot 함수를 사용하여 기본적으로 지도 시각화를 수행한 결과이다.
3. 단계구분도 시각화
fig = plt.figure(figsize=(18, 13))
ax = fig.subplots(1, 1)
# 범례
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.1)
# 단계구분도
gdf_gu2.plot("1인가구수", ax=ax, legend=True, cax=cax, cmap='Reds')
ax.set_title("서울시 자치구 별 1인 가구 수", fontsize=25, pad=20)
단계구분도는 gdf_gu2에서 색깔로 수를 표현하고싶은 데이터의 컬럼명을 plot함수의 인자로 넣어준다.
단계구분도가 잘 적용된 것을 볼 수 있다. 이 시각화의 목적은 자치구 별 1인 가구수의 정보를 전달하는 것이므로, 자치구명을 지도에 넣어주어야 목적에 부합하는 시각화가 완성된다.
4. text 추가 & 최종 결과
# 지역명 추가
for idx in range(len(gdf_gu2)):
lat = gdf_gu2.center.iloc[idx].xy[0][0]
long = gdf_gu2.center.iloc[idx].xy[1][0]
if gdf_gu2["1인가구수"].iloc[idx] >= 400000:
c = "white"
else:
c = 'black'
ax.text(lat-1500, long-300, gdf_gu2["자치구"].iloc[idx], fontsize=13, color=c, fontweight='bold')
ax.set_axis_off()
plt.show()
자치구명을 추가해주기 위해 위의 코드를 추가하였다. 자치구명 글자를 넣기 위해 삽질을 꽤 오래했다. 일반적으로 쓰는 위도, 경도 값과 좌표계가 달랐기 때문이었다. 그래서 해결한 방법은 경계 데이터의 중점에 접근하는 것이었고, 중점의 좌표는 앞서 보았듯이, gdf_gu2.geometry.centroid로 구할 수 있다. 중점의 x좌표는 gdf_gu2.center.iloc[idx].xy[0][0], y좌표는 gdf_gu2.center.iloc[idx].xy[1][0] 과 같이 접근 할 수 있다. 이렇게 좌표를 얻어내서, ax.text를 사용하여 자치구 글자를 넣어주었다. 그 위에 한가지 추가한 조건문은, 색깔이 진한 구역은 검정색 글씨가 잘 안 보여서 인구수가 400000 이상인 구역의 색깔을 흰색으로 변경해준 것이다.
최종 결과물이다. 관악구와 강서구에 1인가구수가 가장 많고, 종로구, 중구에는 1인가구수가 적은 것을 한눈에 확인할 수 있다.