본문 바로가기

Python

공공데이터와 Folium(폴리움)으로 제주 오름 지도 안내 서비스 만들기

안녕하세요, 10월에도 제코베 서포터즈 활동을 이어가고 있습니다. 이번에는 제가 들은 강의를 활용해 작은 프로젝트를 진행해보았습니다. 

 

 

제가 이 강의를 고른 이유는 두 가지입니다.

  • 공공데이터에 관심이 있습니다. 
    • 공공데이터 포털은 국가에서 관리하는 자료라 믿고 쓸 수 있는 자료이고
    • 예전 국비과정을 수강할 때 Python과 R을 이용해서 데이터 가공한 경험이 재미있었기 때문인데요.
      수많은 데이터에서 원하는 정보만 쏙 뽑아서 나만의 데이터로 재가공하는 부분이 흥미로웠습니다. 
  • 지도 서비스에 관심이 있습니다.
    • 저는 물론이고 특히 부모님께서 여행을 다니실 때 혹시나 길을 잘 못 찾으시거나 유명한 곳을 가고 싶은데 핸드폰 사용법을 잘 몰라 속상해하시는 일이 없도록 하고 싶었습니다.
    • 지금은 국내이지만 좀 더 실력을 쌓은 후에는 해외 지도 서비스뿐만 아니라 앱에도 도전해보고 싶습니다. 

 

 

자! 그럼 지금부터 강의에는 어떤 것들이 포함되어있는지, 추가적으로 공부한 부분 그리고 공부하면서 얻은 아이디어를 적어보도록 하겠습니다. (데이터 가공은 Google Colab을 이용할 예정입니다.)

 

 

 


 

 

 

처음에 적었듯 공공데이터와 Folium을 활용해 지도 서비스를 만들 텐데요. 여기서 Folium은 무엇일까요?

 

 

Folium이란?

Folium은 지도 위에 데이터를 interactive 하게 표현해 주는 Python의 지도 시각화 라이브러리입니다.

마커를 추가하거나 원으로 범위도 표현할 수 있는데요, 무엇보다 서비스가 안정적일 뿐만 아니라 시각화하여 html로 저장할 수 있다는 점이 큰 장점입니다.

 

 

포스팅에서 소개드리는 것뿐만 아니라 더 다양한 기능들을 알고 싶으시다면  공식문서를 확인해보시면 좋을 것 같습니다.

 

 

 

Folium으로  제주도 오름 지도 만들기

folium을 설치합니다.

!pip3 install folium

 

앞으로 사용할 모듈을 import 합니다.

import pandas as pd
import folium

 

판다스(Pandas)란?
판다스(Pandas) 와 넘파이(Numpy)는 데이터 분석을 위한 필수 패키지입니다.

특히,판다스(Pandas)는  파이썬 데이터 처리를 위한 라이브러리로 pd라는 명칭으로 임포트 하는 것이 관례입니다.

우리가 이번 프로젝트에서 사용할 기능은 [외부 데이터 읽기]로
CSV, 텍스트, Excel, SQL, HTML, JSON 등 다양한 데이터 파일을 읽고 데이터 프레임을 생성할 수 있습니다.

예를 들어 csv 파일을 읽을 때는 pandas.read_csv()를 통해 읽을 수 있습니다. 

 

 

만약 무시해도 괜찮은 warning들이 계속 뜬다면 무시하도록 설정합니다.

import warnings
warnings.filterwarnings(action='ignore')

 

한글 깨짐 해결

!pip3 install git+https://github.com/python-visualization/branca.git@master

 

 

위도와 경도를 이용해서 location설정

location에 위도, 경도 정보를 입력하면 지도를 그릴 수 있습니다.

m = folium.Map(
    location=[33.361936,126.529165]
)

m

💡 원하는 위치의 위도와 경도 찾는 법
1. 구글 지도 접속
2. 찾고 싶은 장소 검색
3. 우클릭 > 이곳이 궁금한가요? 클릭
4. 위도, 경도가 우측 상단에 뜨게 됩니다.

💡 아이디어
위도와 경도만 알면 지도에 그 지역/국가만 표시가 가능하니 
여행 갈 지역을 표시해서 추후에 랜드마크, 추천경로, 맛집 정보를 나오게 하고 싶다는 생각을 했습니다.

 

 

여기까지를 저장해봅시다.

m.save('index.html')

 

 

마커

홈페이지에서 여기저기 장소를 클릭하면 상세정보가 나오거나 마우스 오버 시 문구가 나오는 것을 볼 수 있습니다.

이 또한 간단한 코드로 구현 가능합니다.

  • 기본 좌표 설정 시 zoom_start 정보를 지정하여 (보이는 지도의) 확대 정도를 지정할 수 있습니다.
  • popup: 표기할 팝업 문구 지정 (마우스 클릭 시 표기되는 문구)
  • tooltip: 표기할 툴팁 지정 (마우스 오버 시 표기되는 문구)
  • 마커에 대한 스타일 변경도 가능합니다. 스타일 변경 시 icon 파라미터에 folium.Icon(color=?, icon=?)을 지정합니다.
m = folium.Map(
    location=[33.361936,126.529165],
    zoom_start=10
)

tooltip = 'Click'

folium.Marker (
    [33.361936,126.529165],
    popup='<strong>한라산</strong>',
    tooltip = tooltip,
    icon=folium.Icon(color='#ff0000', icon='info-sign')
).add_to(m)

folium.Marker (
    [33.510449,126.491278],
    popup='<strong>제주국제공항</strong>',
    tooltip = tooltip,
    icon=folium.Icon(color='green', icon='bookmark')
).add_to(m)


folium.Marker (
    [33.461201,126.941985],
    popup='<strong>성산 일출봉</strong>',
    tooltip = tooltip
).add_to(m)


m

 

 

 

 

기본 준비는 마쳤습니다.

이제 공공데이터를 가지고 와서 공공데이터를 어떻게 지도에 이용할 수 있는지 알아보도록 하겠습니다.

 

공공데이터 포털 접속

 

제주 오름을 검색하고, 위도 경도 데이터가 포함된 CSV 파일을 다운합니다.

 

파일명을 읽기 쉽게 o.csv로 바꾼 후 

왼쪽의 파일을 클릭 후 드래그 앤 드롭합니다.

 

드디어 처음에 import 했던 pandas 라이브러리를 사용할 차례입니다.

파일을 읽고 데이터 확인을 위해 맨 앞부분과 끝의 데이터를 확인하였습니다. 

 

 

공공데이터를 가져오는 데 성공하였고 데이터 확인도 끝이 났습니다.

그럼 바로 지도에 가져가면 될까요?

 

여기서 중요한 작업이 하나 남았습니다.

바로 결측치 확인인데요, 결측치가 있다면 어떻게 처리하면 좋을지도 미리 생각해야 합니다.

오름.isnull()
오름.isnull().sum()
읍면동        0
오름명        0
소재지        0
위도         0
경도         0
주차장        0
화장실        0
표고(m)      0
데이터기준일자    0
dtype: int64

 

다행히 결측치가 없음을 확인할 수 있습니다. 휴...

그럼 간단하게 데이터에 어떤 값들이 있는지 확인해보겠습니다.

 

 

최종적으로 어떤 오름을 선택하면 화장실과 주차장이 있는지 없는지 확인 가능하도록 할 것이기에

화장실과 주차장의 Yes, No개수가 궁금해졌습니다.

오름[['화장실']].value_counts()
화장실
N      40
Y      28
dtype: int64
오름[['주차장']].value_counts()
주차장
Y      35
N      33
dtype: int64

 

한 row를 확인해서 어떤 칼럼들이 있는지도 확인해보겠습니다.

오름.iloc[0]
읍면동                             대정읍
오름명                        송악산(절울이)
소재지        제주특별자치도 서귀포시 대정읍 상모리 산 2
위도                        33.199409
경도                        126.29078
주차장                               Y
화장실                               Y
표고(m)                         104.0
데이터기준일자                  2021-05-10
Name: 0, dtype: object

 

여기서 우리가 필요한 데이터는 오름명, 위도, 경도의 데이터이므로

이럴 때는

오름.iloc[0]['오름명']
송악산(절울이)
오름.iloc[0]['위도']
33.1994088
오름.iloc[0]['경도']
126.2907797

 

이렇게 간단하게 뽑아볼 수 있기는 한데, 제가 원하는 건 단 건으로 나오는 게 아닌

 '오름명 위도 경도' 이렇게 한 줄로 나오는 데이터였는데요,

이럴 때 사용할 수 있는 문법은 for 반복문입니다.

for i in range(오름.shape[0]):
  print(오름.iloc[i]['오름명'], 오름.iloc[i]['위도'], 오름.iloc[i]['경도'] )
송악산(절울이) 33.1994088 126.2907797
섯알오름 33.2042537 126.281676
가시오름  33.2533626 126.2490546
녹남봉 33.2798153 126.1954827
물영아리 33.3708091 126.6935196
머체오름 33.342895 126.6494133
이승이 33.342895 126.6494133
사려니오름 33.342895 126.6494133
민오름 33.3508829 126.6980129
운지오름 33.320538 126.7451549
자배봉 33.342895 126.6494133
생길이 33.342895 126.6494133
큰걸세 33.3616666 126.5291666
....

 

여기까지 제가 원하는 데이터를 뽑았으니 이제 지도에 표시해보겠습니다.

m = folium.Map(
    location=[33.361936,126.529165],
    zoom_start=10
)

tooltip = 'Click'

# for문, f-string이용
for i in range(오름.shape[0]):
    folium.Marker(
        [오름.iloc[i]['위도'], 오름.iloc[i]['경도']],
        popup = f'<strong>{오름.iloc[i]["오름명"]}</strong>',
        tooltip = tooltip
    ).add_to(m)

m

위도와 경도의 정보를 통해 오름의 위치표시가 되었고

클릭을 했을 시 오름명이 나오는 것을 확인할 수 있습니다.

 

 

 

우리가 처음에 최종적으로 보고 싶은 정보는

클릭했을 시 오름명과 화장실, 주차장의 유무였습니다. 이 부분도 이어서 해보면

m = folium.Map(
    location=[33.361936,126.529165],
    zoom_start=10
)

tooltip = 'Click'

# for문, f-string이용
# popup = html코드가 들어감
for i in range(오름.shape[0]):
    folium.Marker(
        [오름.iloc[i]['위도'], 오름.iloc[i]['경도']],
        popup = f'<div style="width:100px"><strong>{오름.iloc[i]["오름명"]}</strong><br>\
        주차장: {오름.iloc[i]["주차장"]}<br>\
        화장실: {오름.iloc[i]["화장실"]}<br>\
        </div>',
        tooltip = tooltip
    ).add_to(m)

m

네, 여기까지 제가 원했던 정보들이 지도에 잘 출력됨을 알 수 있습니다.

 

 

 

욕심을 조금 더 내서 기능을 추가해보자면,

1. 기존 데이터에 칼럼을 추가해서 또 다른 데이터 넣기

2. url 삽입해서 다른 페이지로 이동하기

3. 주차장, 화장실 유무 확인이 쉽게 나눠서 볼 수 있는 기능

 

 

첫 번째 기능과 두 번째 기능은 간단하므로 합쳐서 구현해보도록  하겠습니다. 

칼럼 추가 - 이미지 삽입

오름['이미지'] = 오름['오름명']+'.jpg'
오름

# 코드를 깔끔하게, 변수 이용하기
# 이미지 삽입
m = folium.Map(
    location=[33.361936,126.529165],
    zoom_start=10
)

tooltip = 'Click'

# for문, f-string이용
for i in range(오름.shape[0]):
    folium.Marker(
        [오름.iloc[i]['위도'], 오름.iloc[i]['경도']],
        popup = f'<div style="width:100px"><strong>{오름.iloc[i]["오름명"]}</strong><br>\
        주차장 : {오름.iloc[i]["주차장"]}<br>\
        화장실 : {오름.iloc[i]["화장실"]}<br>\
        <img width="80px" src="a.jpg"><br>\
        <a href="https://www.visitjeju.net/kr/search?q=%EC%98%A4%EB%A6%84#">상세페이지 이동</a></div>',
        tooltip = tooltip
    ).add_to(m)

m.save('index.html')

m

 

상세페이지 이동 클릭 시

 

사진으로 오름도 구별할 수 있고 

페이지 이동으로 더 많은 정보를 얻을 수 있으니 토이 플젝을 하게 된다면 이 기능을 꼭 넣어야겠습니다.

 

 

마지막으로  주차장이 있는 그룹과 없는 그룹을 나눠 표시해서 한눈에 파악할 수 있도록 해보겠습니다.

# icon 속성
from folium.features import CustomIcon

m = folium.Map(
    location=[33.361936,126.529165],
    zoom_start = 10
)

tooltip = 'Click'

주차장유 = folium.FeatureGroup(name='주차장유').add_to(m)
주차장무 = folium.FeatureGroup(name='주차장무').add_to(m)

for i in range(오름.shape[0]):

    if 오름.iloc[i]["주차장"] == 'Y':
      folium.Marker(
          [오름.iloc[i]['위도'], 오름.iloc[i]['경도']],
          popup = f'<div style="width:100px"><strong>{오름.iloc[i]["오름명"]}</strong><br>\
          주차장: {오름.iloc[i]["주차장"]}<br>\
          화장실: {오름.iloc[i]["화장실"]}<br>',
          tooltip = tooltip
      ).add_to(주차장유)
    else:
      folium.Marker(
          [오름.iloc[i]['위도'], 오름.iloc[i]['경도']],
          popup = f'<div style="width:100px"><strong>{오름.iloc[i]["오름명"]}</strong><br>\
          주차장: {오름.iloc[i]["주차장"]}<br>\
          화장실: {오름.iloc[i]["화장실"]}<br>',
          tooltip = tooltip
      ).add_to(주차장무)

# 체크박스
folium.LayerControl(collapsed=False).add_to(m)
m

 

주차장 있는 오름만 보고 싶을 경우

 

주차장 없는 오름을 확인하고 싶을 경우

 

 

여기까지 제주 오름 지도 서비스를 간단하게 만들어보았습니다.

기본적인 기능이고 실제로도 간단하게 구현이 가능했지만 필요한 정보들은 확인이 가능했습니다.

 

 

 

 

강의 수강과 실습을 통해 여행을 할 때 도움이 될 만한 저만의 여행 앱을 만들어보고 싶다는 생각을 하게 된 계기가 되었습니다.

앱 개발 아이디어를 얻어가는 것 같아 뿌듯하고 어떤 기능들을 넣을지 어디서 데이터를 모을지 서칭 하면서 작업을 진행했는데요, 저에게 필요하다고 생각하니 즐겁게 찾고 개발했던 것 같습니다. 다음에도 이러한 실습을 하게 된다면 포스팅하도록 하겠습니다. 

 

 

 


 

 

 

 

참고:

제코베

https://teddylee777.github.io/visualization/folium

'Python' 카테고리의 다른 글

Python 엑셀 프로그래밍 - with xlsxwriter  (0) 2022.11.30
Python 내장 함수(Built-in Function)  (0) 2022.09.28
Python 기본 문법 정리  (0) 2022.09.28