Tech Blog

geopandas로 단계구분도 시각화하기 본문

카테고리 없음

geopandas로 단계구분도 시각화하기

agsu 2023. 3. 24. 22:59

 프로젝트에서 지역별 인구수를 나타내는 지도 시각화를 구현해야 하는 일이 있었는데, 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인가구수가 적은 것을 한눈에 확인할 수 있다. 

 

 

 

Comments