Development./Data Visualization

[Data Visualization] python 데이터 시각화 - Folium

Chuuu_DevCamp:) 2022. 3. 15. 00:22
반응형

Folium은 파이썬에서 leaflet.js를 이용해 지리 데이터를 효과적으로 시각화 할 수 있는 라이브러리입니다.

지도와 좌표값을 이용해서, 각 주제에 맞는 html 파일을 생성 또는 저장할 수 있도록 도와주는 역할을 합니다.

 

API Reference: https://python-visualization.github.io/folium/

 

라이브러리 설치

pip install folium

라이브러리 설치가 완료 되었다면, 지도에 데이터를 시각화 하기 위한 라이브러리를 import 해줍니다.

추후 지도상에 마커와 아이콘을 띄우기 위해, Marker, Icon을 함께 import 하였습니다.

#지도 시각화에 필요한 라이브러리 import 하기
import folium
from folium import Marker, Icon
# Pandas는 쉽고 직관적인 관계형 또는 분류된 데이터로 작업 할 수 있도록 설계된, 빠르고 유연하며 표현이 풍부한 데이터 구조를 제공하는 Python 패키지이다.
import pandas as pd
import csv, time

 

이후, 실습을 위한 예제 데이터인 한국 공항공사 공항 위치 정보를 불러와 실습을 진행하였다.

#데이터 불러오기 (data 출처 : 공공데이터포털 / 한국공항공사_공항 위치정보)
#https://www.data.go.kr/data/15002851/fileData.do
df = pd.read_csv('C:/Users/ischoo/PycharmProjects/Jupyter_Test/한국공항공사_공항 위치정보_20210906.csv', encoding = 'cp949')
df

한국 공항 위치 정보

Map

위 코드로 불러온 공항 위치 정보를 지도에 표시하기 위해서, 가장 기본이 되는 지도 표시 코드를 작성하였습니다.

여러 배경의 지도 제공이 가능하며, folium API reference페이지에서는 다음과 같은 맵 제공이 가능 한 것으로 설명합니다.

  • "OpenStreetMap"
  • "Stamen Terrain"
  • "Stamen Toner"
  • "Stament Watercolor"
  • "CartoDB positron"
  • "CartoDB dark_matter"
# folium.Map을 통해 초기 지도를 세팅
marker_map = folium.Map(location=[36.344362, 127.948878] # Default location = 36.344362, 127.948878
                        , zoom_start=6) # zoom start level = 6 (숫자가 커질 수록 축척이 커짐)

# Add tiles
folium.TileLayer('OpenStreetMap').add_to(marker_map)
folium.TileLayer('Stamen Terrain').add_to(marker_map)
folium.TileLayer('Stamen Toner').add_to(marker_map)
folium.TileLayer('Stamen Watercolor').add_to(marker_map)
folium.TileLayer('CartoDB positron').add_to(marker_map)
folium.TileLayer('CartoDB dark_matter').add_to(marker_map)

# Add the option to switch tiles
folium.LayerControl().add_to(marker_map)

marker_map

Marker

이후 공항 정보를 icon으로 표시하기 위한 코드를 작성하여 공항 위치에 marker가 표시되도록 해보았습니다.

이 때, icon의 색깔과 모양을 모두 커스터마이징 가능합니다. 또한, 아이콘 클릭시 뜨는 popup html형식으로 구성되어 있어 팝업 창 내 동영상을 추가하거나 web site link를 첨부하거나, json text를 삽입하는 등 다양한 방법으로 무수히 많은 정보를 제공할 수 있어 유용합니다.

import json
import requests

for i in df.index:
    sub_lat = df.loc[i, '위도']
    sub_long = df.loc[i, '경도']
    title = df.loc[i, '공항명']
    if title.__eq__('김포'):
        folium.Marker([sub_lat, sub_long] # 좌표 추가
                      , tooltip=title # 툴팁 지정 (마우스 커서를 아이콘 위치에 올릴 경우 표시되는 문구)
                      , icon=folium.Icon('red', icon='star') # 아이콘 정보
                      , popup='<iframe width="560" height="315" src="https://www.youtube.com/embed/mArvXzzvBMs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>').add_to(marker_map) # 마우스 클릭 시 표기되는 문구
    elif title.__eq__('김해'):
        folium.Marker([sub_lat, sub_long]
                      , tooltip=title
                      , icon=folium.Icon('green', icon='star') # icon colors = {'purple', 'darkblue', 'blue', 'cadetblue', 'black', 'darkgreen', 'orange', 'darkred', 'lightgreen', 'pink', 'white', 'red', 'lightred', 'green', 'gray', 'beige', 'lightblue', 'darkpurple', 'lightgray'}
                      , popup='<a href=https://ko.wikipedia.org/wiki/%EA%B9%80%ED%95%B4%EA%B5%AD%EC%A0%9C%EA%B3%B5%ED%95%AD>Gimhae Internaltional Airport</a>').add_to(marker_map)
    else:
        if i % 2 == 0:
			# 짝수 번째 index의 공항은 popup에 임의의 json 데이터를 표시 하도록 구현
            f = open('sample_hydra.json', encoding='utf-8')
            jsonData = f.read()
            folium.Marker([sub_lat, sub_long]
                      , tooltip=title
                      , popup=jsonData).add_to(marker_map)
        else:
			# 홀수 번째 index의 공항은 popup에 임의의 차트를 표시하도록 구현
			# 차트는 json 데이터를 활용해서 표시한다.
            url = ("https://raw.githubusercontent.com/python-visualization/folium/master/examples/data")
            data = json.loads(requests.get(f"{url}/vis1.json").text)
            folium.Marker([sub_lat, sub_long]
                         , tooltip=title
                         , popup=folium.Popup(max_width=450).add_child(
                             folium.Vega(data, width=450, height=250))).add_to(marker_map)
        
marker_map

김포 marker를 클릭할 경우 popup에 표시되는 동영상 정보
김해 marker를 클릭할 경우 popup에 표시되는 링크 정보
김해 marker를 클릭할 경우 팝업에 표시되는 링크 클릭 시 동작

 

짝수 번째 index marker클릭 시 생성되는 팝업에 json 데이터를 표시
홀수 번째 index marker 클릭 시 json 기반 차트 표시

MarkerCluster

만약 방대한 양의 marker 데이터가 포함 되어 있을 경우, 지도에 모두 표시되면 지도가 매우 정갈하지 못하고, 사용하기 불편할 것입니다. 따라서, folium 플러그인 중 MarkerCluster를 이용하여 marker 클러스터를 형성하여 데이터를 보기좋게 정리 및 시각화 하였습니다.

실습을 위해 부산에 있는 7개 해수욕장의 음식점 정보 공공데이터를 사용하였습니다.

#데이터 불러오기 (data 출처 : 공공데이터포털 / 부산관광공사_7 BEACH 음식점 기본정보)
#https://www.data.go.kr/data/15096697/fileData.do
from folium.plugins import MarkerCluster

df = pd.read_csv('''C:/Users/ischoo/PycharmProjects/Jupyter_Test/부산관광공사_7 BEACH 음식점 기본정보_20220101.csv''', encoding='utf-8')
df

위 음식점 데이터를 MarkerCluster로 표현하기 위해 다음과 같이 설계해봤습니다.

  1. 식당 위치에 따라 그룹을 지어 지도에 표시되도록 하고, 영업인허가명에 따라 다른 색깔의 icon이 표시되도록 한다
  2. 식당 icon에 마우스 커서를 올릴 경우 식당명이 표시되도록 한다.
  3. 식당 icon을 클릭할 경우 음식점 소개 내용이 표시되도록 한다.
cluster_map = folium.Map(location=[35.1607928, 129.0472984], zoom_start=11)
marker_cluster = MarkerCluster().add_to(cluster_map)

for i in df.index:
    restaurant_type = df.loc[i,'영업인허가명']
    
    iconColor = 'purple'
    if restaurant_type.__eq__('일반음식점'):
        iconColor = 'lightgreen'
    elif restaurant_type.__eq__('제과점영업'):
        iconColor = 'lightblue'
    
    folium.Marker([df.loc[i, '식당위도'], df.loc[i, '식당경도']] # 식당 위도,경도 위치에 icon 표시
                  , icon=folium.Icon(color=iconColor) # 영업인허가명에 따라 icon 색상 설정
                  , tooltip=df.loc[i, '식당명'] # 마우스 커서를 icon위에 올릴 경우 표시될 text - 식당명
                  , popup=df.loc[i, '음식점소개내용'] # Marker를 클릭할 경우 표시되는 내용 - 음식점 소개 내용
                  , encoding='utf-8').add_to(marker_cluster)

cluster_map

GeoJson

맵에 geoJson 데이터를 표시하기 위한 클래스이며, json 형태로 작성된 파일이나 스트링, 딕셔너리 데이터를 전달할 경우 polygon을 맵에 표시합니다. json 형태로 어떻게 데이터를 작성하는지 찾아보던 중 GeoJson 데이터를 생성해 주는 툴을 찾아 사용 해 볼 수 있었습니다.

툴을 사용하여 임의의 위치에 해당 하는 polygon json 데이터를 생성하여 사용 해 보았습니다.

생성 한 임의의 geoJson 파일

{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[123.22265625000001,32.58384932565662],[132.42919921875,32.58384932565662],[132.42919921875,43.46886761482925],[123.22265625000001,43.46886761482925],[123.22265625000001,32.58384932565662]]]}}]}
polygon_map = folium.Map(location=[38.279707, 127.290699], zoom_start=5)

folium.GeoJson(
    "Korea.geojson", # 임시로 생성한 Korea.geojson 파일을 data 파라미터로 전달
    name='Korea'
).add_to(polygon_map)

polygon_map

위에서 욕심을 내 좀더 보기 좋은 샘플을 찾아 추가 구현 해 보았습니다.

https://raw.githubusercontent.com/southkorea/seoul-maps/master/kostat/2013/json/seoul_municipalities_geo_simple.json data request하여 서울 행정구역 지역구별 polygon json을 받아오고, 해당 polygon 데이터를 지도에 표시하도록 구현 해보았습니다.

import requests
import json

# 서울 행정구역 json raw파일(githubcontent)을 받아 seoul_geo변수에 json 데이터를 딕셔너리 형태로 저장
req_data = requests.get('https://raw.githubusercontent.com/southkorea/seoul-maps/master/kostat/2013/json/seoul_municipalities_geo_simple.json')
data_content = req_data.content
seoul_geo = json.loads(data_content)

# 맵 생성
m = folium.Map(
    location=[37.559819, 126.963895],
    zoom_start=11, 
)

# 지역구 별로 그룹화 된 json 데이터에 따라 polygon을 맵에 그리도록 설정
folium.GeoJson(
    seoul_geo,
    name='지역구'
).add_to(m)

m