[Folium] JSON 지도 위에 텍스트 넣기
📊 𝗕𝗶𝗴𝗗𝗮𝘁𝗮/Visualization

[Folium] JSON 지도 위에 텍스트 넣기

folium을 이용해서 text 를 띄워보도록 하겠습니다.

여느 marker를 찍듯이 쉽게 사용할 수 있습니다.


 

 folium 설치 

pip install folium

우선 folium 을 설치해줍니다. 

import folium
from folium.features import DivIcon

그리고 import 로 가져와봅시다.

 

 

 

 사용 데이터 

population.csv
0.02MB

기술통계 데이터로 사용할 2022년 전국 인구수 데이터 파일입니다.

TL_SCCO_CTPRVN.json
0.31MB

대한민국 행정구 기준 경계선 geo json 파일 입니다.

 

 

 

 map 만들기 

m = folium.Map(location=[35.8, 128.071503], zoom_start=7,)

우선 folium.Map() 을 만들어서 openstreetmap 을 띄우는 지도맵을 만들어줍니다.

location 에는 위치를 지정해서 넣어줘야 합니다.

보통 위경도 데이터가 있으면 해당 mean() 값을 넣어주지만 지금 위경도 컬럼이 없으므로 대충 어림잡아 넣어주겠습니다.

출력하면 이런식으로 나옵니다.

 

 

 

 JSON 경계파일 지도 위에 매핑하기 

import json

state_geo = '../3주차/data/TL_SCCO_CTPRVN.json'
state_geo

# 시도기준 경계 JSON 파일을 들고 온다.
with open(state_geo, encoding='utf-8') as file:
    sido_map = json.load(file)

파일을 열어 json 으로 로드를 해줍니다.

sido_map['features'][0]['properties']

그리고 해당 json 파일 안에 제대로 행정구역 명이 있는지 확인을 해봅니다.

features.properties.CTP_KOR_NM 으로 되어있네요.

해당 값이랑 우리가 쓸 데이터 파일의 시도명이랑 key 로 잡아서 매핑을 해줄겁니다.

그러니까 둘의 값은 같아야합니다.

경계값의 CTP_KOR_NM 이 강원도라면 강원도의 인구수가 매핑이 되는 것이지요.

 

저희가 사용할 population.csv 파일의 내용은 다음과 같이 생겼습니다.

m = folium.Map(location=[35.8, 128.071503], zoom_start=7,)

ch = folium.Choropleth(
    # geo json 파일로 sido_map 을 사용
    geo_data=sido_map,
    # choropleth 옵션을 쓸 것임
    name='choropleth',
    # data로는 population.csv 파일을 사용 (df로 불러옴)
    data=df,
    # csv 파일에서 사용할 컬럼 값
    columns=['시도명', '인구수'], 
    # 시도명 - CTP_KOR_NM 매핑
    key_on='feature.properties.CTP_KOR_NM',  
    # geo json 색깔 설정
    fill_color='YlGn',
    # 지도 투명하게  
    fill_opacity=0.7,
    # 경계선 투명하게
    line_opacity=1,  
    # 경계선 굵기
    line_weight=1.5,
    # 경계선 색
    line_color='#000',
    # 범례 이름
    legend_name='시도별 인구 수 (명)',  
    #  highlight=True, # 하이라이트 설정
).add_to(m)

m

geo_data 옵션으로 json 파일을 설정해주고 data 에는 실제로 나타낼 데이터를 넣으면 됩니다.

그리고 key_on 을 이용해서 시도명과 CT_KOR_NM 을 매핑해줍니다.

openstreetmap 위에 json 경계 파일 레이어가 하나 더 생긴 것을 확인할 수 있습니다.

서울특별시가 역시나 많네요.

 

 

 

 지도 위에 text 넣기 

# 위도경도 매핑
locs = {
    '경기도': (37.95, 126.95),
    '서울특별시': (37.58, 126.7),
    '부산광역시':(35.198362, 129.053922),
    '경상북도':  (36.63, 128.46),
    '경상남도': (35.5, 128),
    '인천광역시':  (37.5, 125.8),
    '대구광역시': (35.96, 128.32),
    '충청남도': (36.69, 126),
    '전라남도':  (34.819400, 126.893113),
    '전라북도':  (35.86, 126.85),
    '대전광역시':   (36.321655, 127.378953),
    '강원도': (37.88, 128),
    '광주광역시': (35.28, 126.49),
    '울산광역시': (35.8, 129.5),
    '충청북도': (37.19, 127.50),
    '세종특별자치시':    (36.7, 127.07),
    '제주특별자치도':   (33.62, 126.11),
}

locs

folium 에서 여느 marker 를 찍듯이 위경도를 이용해서 찍어줘야합니다.

따라서 적절한 위치에 텍스트를 올리기 위해서 locs 딕셔너리를 만들었습니다.

텍스트의 위치를 조금씩 조정하고 싶다면 해당 딕셔너리의 데이터를 조정하면 됩니다.

https://www.google.co.kr/maps/?hl=ko 

 

Google 지도

Google 지도에서 지역정보를 검색하고 지도를 살펴보거나 운전경로 정보를 검색합니다.

www.google.co.kr

위경도를 가져올때는 google 지도를 이용하세요.

점을 찍고 클릭하면 이런식으로 위도 경도가 뜹니다. 조금 노가다지만.. 어쩔 수 없습니다.

카카오지도api 를 사용하거나 그럴 수도 있지만 어차피 어림잡아서 몇 개만 하면 되니 대충 이렇게 하세요 🫠

 

for key, value in locs.items():
    folium.map.Marker(
        # 위경도 위치
        [value[0], value[1]],  

        # DivIcon 을 사용
        # html 태그를 이용해서 text를 올릴 수 있음
        icon=DivIcon(
            # icon px 사이즈
            icon_size=(0, 0),
            # icon 좌 상단 위치 설정
            icon_anchor=(0, 0),

            # html 형식으로 text 추가
            # div 태그 안에 style 형식 추가
            html='<div\
                    style="\
                        font-size: 0.8rem;\
                        color: black;\
                        background-color:rgba(255, 255, 255, 0.2);\
                        width:85px;\
                        text-align:center;\
                        margin:0px;\
                    "><b>'
            + key + ': ' + str(sido_.loc[key, '인구수'].sum())
            + "<br/><span style='color:red; margin: 0px;'>여성: "
            + str(sido_.loc[(key, '여자'), '인구수']) + '</span>'
            + "<br/><span style='color: blue; margin: 0px;'>남성: "
            + str(sido_.loc[(key, '남자'), '인구수']) + '</span>'
            + '</b></div>',
        )).add_to(m)

folium 의 DivIcon 태그를 사용합니다.

html 태그를 이용해서 지도 위에 텍스트를 쓸 수 있어요.

우선 아까 설정한 locs 딕셔너리를 key, value 로 반복합니다

그러면 key 값에는 시도명이, value 값에는 위경도가 들어갑니다.

이를 이용하여 value[0], value[1] 해서 해당 텍스트 마다의 위치를 찍어줄수 있어요.

sido_ = df.groupby(by=['시도명', '성별']).sum()

그리고 인구수 뿐만이 아니라 성별마다의 인구수를 나타내기 위해서 별도의 데이터 프레임을 만들어 주도록 할게요.

해당 데이터 프레임은 다음과 같이 생겼습니다.

sido_.loc[('부산광역시', '여자'), '인구수']

그러면 이렇게 loc 로 부분 데이터를 뽑아내면 그에 맞는 값이 나오겠죠?

이를 이용해서 텍스트를 나타내주면 됩니다.

 

# html 형식으로 text 추가
            # div 태그 안에 style 형식 추가
            html='<div\
                    style="\
                        font-size: 0.8rem;\
                        color: black;\
                        background-color:rgba(255, 255, 255, 0.2);\
                        width:85px;\
                        text-align:center;\
                        margin:0px;\
                    "><b>'
            + key + ': ' + str(sido_.loc[key, '인구수'].sum())
            + "<br/><span style='color:red; margin: 0px;'>여성: "
            + str(sido_.loc[(key, '여자'), '인구수']) + '</span>'
            + "<br/><span style='color: blue; margin: 0px;'>남성: "
            + str(sido_.loc[(key, '남자'), '인구수']) + '</span>'
            + '</b></div>',

태그 때문에 복잡하게 생겼어도 별거 없습니다.

전체적으로 div 태그로 감싸주고 style 주고 그 안에 <span> 태그 두개가 들어가있습니다.

<br/> 태그를 넣어주는 이유는 한 줄 띄어주려고 그런겁니다.

참고로 숫자 값을 써줄 때는 str() 을 이용하여 문자열로 변경해줘야해요.

그렇지 않으면 다음과 같은 TypeError 가 납니다.

이렇게 태그를 엮어주고 만든 맵을 띄워보면 다음과 같습니다.

짜잔 ✨ 텍스트 태그를 folium 위에 나타낼 수 있게 됐어요.

지도 상에서는 총 인구 수를 그리고 텍스트로는 성별의 인구 수를 나타내어 보았습니다.

텍스트 크기를 크게 하고 싶다면 div 태그의 style 안에 있는 font-size 의 숫자를 크게 잡으면 됩니다.

 

+ 그리고 참고로 folium 은 html 만 저장이 됩니다.

해당 화면을 Png 로 저장하고 싶다면 저의 전 포스팅을 참고해주세요.

2022.05.30 - [📊 𝗕𝗶𝗴𝗗𝗮𝘁𝗮/Visualization] - [Folium] html to png 이미지 파일로 저장하기

 

[Folium] html to png 이미지 파일로 저장하기

 Html to Png Folium 으로 맵을 만들고 나서 보면 html 파일로만 저장을 할 수가 있습니다. 하지만 보고서를 작성할 때 이미지가 필요한데 이때 일일이 캡쳐하기란 지루한 작업입니다. conda install -c cond

yeomss.tistory.com

 

 

 

 코드 파일 

test.ipynb
0.42MB

전체 코드 파일입니다.

 

 

 

 

 

 

 

# folium 텍스트 시각화 문자열 시각화 divIcon 문자 넣기 예제


 

728x90