본문 바로가기
데이터 시각화

Python 데이터 시각화, 국내 시.도별 코로나 19 확진 정보 - 공간정보 ( 단계구분도 - plotly choropleth map )

by 맑은안개 2021. 3. 18.

Plotly Choropleth map

국내 코로나19 정보를 Plotly의 공간정보 표현 API인 Choropleth map API를 사용하여 공간정보를 표시해본다. 데이터는 이전 블로그에서 사용한 sorted_df 를 사용할 것이므로 미리 준비하도록 하자.

2021.03.15 - [데이터 시각화] - 국내 시.도별 코로나19 확진자 발생 현황 데이터 시각화( 공공데이터포탈 Open API )

 

다음으로 공간정보의 이해를 위해 아래내용들을 숙지하길 바란다.

1. 지리정보시스템, GIS ( Geographic Information System )

일반 지도와 같은 지형정보와 함께 지하시설물 등 관련 정보를 인공위성으로 수집, 컴퓨터로 작성해 검색, 분석할 수 있도록 한 복합적인 지리정보시스템이다. 국토계획 및 도시계획, 수자원관리, 통신 · 교통망 가설, 토지관리, 지하매설물 설치 등의 분야에서 필요성이 강조되고 있다. 

GIS가 운용되는 분야는 구체적으로 기상항공 정보분석, 상 · 하수도망, 통신망, 전력망, 도시가스망, 도로 등 지상 · 지하 시설물 설치 및 관리, 공장부지, 농작물 재배지역, 산업단지선정 등이다.

출처: 네이버 지식백과

2. Shapefile

shapefile은 GIS를 표현하기 위한 지리정보를 담고 있는 데이터 포맷이다. shapefile 포맷은 지역 위치와 해당 지역의 속성 정보를 담고 있다. .shp .shx .dbf 파일 포맷으로 구성된다. 

출처: 위키백과

3. geoJson

GeoJSON(지오제이슨)은 위치정보를 갖는 점을 기반으로 체계적으로 지형을 표현하기 위해 설계된 개방형 공개 표준 형식이다. 

출처: 위키백과

 

Plotly의 Choropleth map은 geoJson 내용을 사용한다. geoJson은 shapefile로 만들어 지는데 국토교통부의 국가공간정보포털이나 민간 운영 블로그인 GIS DELELOPER 에서 다운로드 받을 수 있다.

shapefile을 geoJson으로 변경하기 위해서는 약간의 노력이 필요하며 본 블로그에서는 다루지 않는다. 구글에서 검색하면 많은 블로그에서 관련 내용을 다루고 있으니 참고바란다.

 

본 블로그에서 사용된 국내 시.도 geoJson파일

 

korea_geojson2.geojson
0.25MB

 

geoJson 파일 구조

{
    "type":"FeatureCollection",
    "bbox":[126.11294936746019,33.23173832249056,129.64960727081376,38.574130814660194],
    "features":[
        {
            "type":"Feature",
            "geometry":{
                "type":"Polygon",
                "coordinates":[
                    [[128.54880989370014,38.301950820518755],
                     [128.60765942875406,38.15215810015938],
                     [128.8786226699225,37.8294251483049],
                     [129.05505018456222,37.675224044111836],
                     .. 생략
                     ,[128.54880989370014,38.301950820518755]]
                ]
            },
            "properties":{
                "CTPRVN_CD":"42",
                "CTP_ENG_NM":"Gangwon-do",
                "CTP_KOR_NM":"강원도"
            }
        },
        .. 이하 16개 시.도 Feature ..
    ]
}

- features에 각 시.도 데이터가 리스트로 담겨있다. 

- plotly는 각 features 데이터에 id 키을 찾아 맵을 지정한다. id가 없으므로 이를 생성해야 하는데 sorted_df의 gubun 값과 위 geoJson의 "properties"에 정의된 "CTP_KOR_NM"을 매핑하여 id를 생성한다. 

- featureidkey로 id 값을 갖는 key값을 지정할 수 있다. 

데이터 로드 및 Map id 생성

with open('geojson/korea_geojson2.geojson', encoding='UTF-8') as f:
    data = json.load(f)
    
for x in data['features']:
    x['id'] = x['properties']['CTP_KOR_NM'] 
    
for idx, _ in enumerate(data['features']):
    print(data['features'][idx]['id'])
    
# OUTPUT
강원도
경기도
경상남도
경상북도
광주광역시
대구광역시
대전광역시
부산광역시
서울특별시
세종특별자치시
울산광역시
인천광역시
전라남도
전라북도
제주특별자치도
충청남도
충청북도

- json으로 로드 후 id 키값에 CTP_KOR_NM 값을 넣었다. 

- 잘 생성되었는지 결과값을 출력해본다.

sorted_df.gubun.unique()

# OUTPUT
array(['경기', '서울', '경남', '인천', '강원', '충북', '충남', '전북', '대구', '부산', '경북',
       '제주', '세종', '대전', '울산', '광주', '전남'], dtype=object)

- sorted_df 의 gubun값은 geoJson의 id 값과 다르다. 매칭 되는 값을 매퍼로 만든 후 sorted_df에 geo_region 컬럼 값으로 데이터를 생성해보자. 

mapper = [
    ('경기', '경기도'),
    ('서울', '서울특별시'),
    ('충북', '충청북도'),
    ('인천', '인천광역시'),
    ('충남', '충청남도'),
    ('광주', '광주광역시'),
    ('부산', '부산광역시'),
    ('강원', '강원도'),
    ('전남', '전라남도'),
    ('대구', '대구광역시'),
    ('전북', '전라북도'),
    ('울산', '울산광역시'),
    ('제주', '제주특별자치도'),
    ('경북', '경상북도'),
    ('세종', '세종특별자치시'),
    ('경남', '경상남도'),
    ('대전', '대전광역시'),
]
get_region = lambda gubun: [x[1] for x in mapper if x[0] == gubun][0]

sorted_df['geo_region'] = sorted_df.gubun.apply(get_region)
sorted_df

# OUTPUT
createdt	deathcnt	defcnt	gubun	incdec	isolclearcnt	isolingcnt	localocccnt	overflowcnt	qurrate	dt	geo_region
9	2021-03-15 09:55:40.205	517	26157	경기	161	23355	2285	161	0	197.41	2021-03-15	경기도
17	2021-03-15 09:55:40.203	407	30061	서울	112	27526	2128	112	0	308.84	2021-03-15	서울특별시
2	2021-03-15 09:55:40.206	14	2438	경남	31	2185	239	31	0	72.53	2021-03-15	경상남도
14	2021-03-15 09:55:40.204	56	4726	인천	18	4423	247	18	0	159.87	2021-03-15	인천광역시
8	2021-03-15 09:55:40.205	42	2033	강원	10	1820	171	10	0	131.97	2021-03-15	강원도
7	2021-03-15 09:55:40.205	60	1978	충북	9	1711	207	9	0	123.67	2021-03-15	충청북도
6	2021-03-15 09:55:40.205	35	2541	충남	6	2400	106	5	1	119.72	2021-03-15	충청남도
5	2021-03-15 09:55:40.205	56	1276	전북	5	1142	78	4	1	70.21	2021-03-15	전라북도
15	2021-03-15 09:55:40.204	215	8726	대구	5	8429	82	4	1	358.14	2021-03-15	대구광역시
16	2021-03-15 09:55:40.203	114	3421	부산	4	3123	184	4	0	100.27	2021-03-15	부산광역시
3	2021-03-15 09:55:40.206	72	3373	경북	3	3191	110	3	0	126.69	2021-03-15	경상북도
1	2021-03-15 09:55:40.206	1	609	제주	3	575	33	3	0	90.79	2021-03-15	제주특별자치도
10	2021-03-15 09:55:40.205	1	246	세종	2	231	14	2	0	71.86	2021-03-15	세종특별자치시
12	2021-03-15 09:55:40.204	15	1205	대전	2	1175	15	2	0	81.74	2021-03-15	대전광역시
11	2021-03-15 09:55:40.204	37	1092	울산	2	970	85	1	1	95.20	2021-03-15	울산광역시
13	2021-03-15 09:55:40.204	21	2175	광주	1	2075	79	1	0	149.31	2021-03-15	광주광역시
4	2021-03-15 09:55:40.206	8	904	전남	1	827	69	0	1	48.48	2021-03-15	전라남도

- DataFrame에 geoJson에 정의된 id와 매핑되는 컬럼을 만들었다. 이제 plotly API를 호출해보자. 

 

plotly choropleth_mapbox

fig = px.choropleth_mapbox(
   sorted_df, 
   geojson=data, 
   locations='geo_region', 
   color='localocccnt',
   color_continuous_scale=px.colors.sequential.Redor,
   # featureidkey="properties.CTP_KOR_NM", # featureidkey를 사용하여 id 값을 갖는 키값 지정
   mapbox_style="carto-positron",
   zoom=5.5, 
   center = {"lat": 35.757981, "lon": 127.661132},
   opacity=0.6,
   labels={'localocccnt':'확진자 수'}
)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()

- geojson 파라미터에 geoJson을 로드한 json파일을 넣는다.

- color 파라미터에 맵에서 표현할 DataFrame의 컬럼을 넣는다. localocccnt는 확진자 수 이다.

- mapbox_style 파라미터로 맵 형태를 다양하게 바꿀 수 있다. 

 

결과

국내 시.도 코로나19 확진자 발생 현황

- 자세히 보면 부산을 비롯하여 몇 군데 색상표현이 누락된 곳이 있다. 이는 geoJson파일의 로케이션 정보에 오류로 인해 발생한 것이다. 

 

mapbox_style

open-street-map, white-bg, carto-positron
carto-darkmatter, stamen-terrain
stamen-toner, stamen-watercolor

 

반응형