AI 탐구노트

국가 별 지도 상 위치를 보여주는 코드 생성하기 본문

DIY 테스트

국가 별 지도 상 위치를 보여주는 코드 생성하기

42morrow 2025. 6. 18. 10:50

 

아이와 가끔씩 나라 이름 말하기나 수도 이름 말하기, 국기 맞히기 등의 놀이를 할 때가 있습니다. 대부분의 아이들이 이런 게임을 좋아하고 곧잘 외우죠. 어른들은 아주 예전 학교에서 배웠던 것들을 가지고 얘기하는터라, 아무래도 아이들의 파릇파릇한 기억력을 당해낼 재간이 없을 것 같았습니다. 하지만, 의외로 대부분 아이들이 국기를 보고 나라 이름을 맞히기는 하는데, 그 나라가 대략 어디쯤 있는지를 모르는 경우가 많더군요. 그래서, 아이들 용 컨텐츠로 나라의 위치를 공부하는 것을 하나 만들어 보기로 했습니다. 


 

전체 내용은 대략 다음과 같습니다.

  • ❓️세계지도 정보, MapPuzzle로 안 되었나?
  • 🕵️‍♀️ 세계지도 라이브러리 조사
  • 👨‍💻 Worldmap을 이용한 코드 생성

 

❓️세계지도 정보, MapPuzzle로 안 되었나?

아래의 지난 번 글에서 MapPuzzle이라는 온라인 게임을 소개드린 바 있습니다. MIT 라이선스라 로컬에 내려받고 화면을 그대로 이용해서 영상도 만들 수 있겠다 싶었습니다.

 

 

[추천] MapPuzzle - 지도를 활용한 온라인 퍼즐, 아이들과 꼭 해 보세요!

벡터 방식의 지도 데이터를 이용하고 바이브 코딩을 이용해 온라인으로 퍼즐을 하나 만들 생각이었습니다. 구현하려는 것은 세계 지도를 보여주고 특정 국가명을 보여주면서 그 나라를 지도 상

42morrow.tistory.com

 

그랬는데... 해 보니... 원래가 게임이라 나라 별로 원하는 위치 이미지를 하나씩 추출하는 것은 불가능했습니다. 즉, 하나의 나라에 대한 퍼즐을 채우고 나면 다시 원상 복구는 안 되는 방식이었던거죠. 전체에서 해당 나라만 위치를 표시한 지도들이 필요했던 저였기에 그대로 이용할 수는 없다고 생각했습니다. 

 

그래서 이런 기능을 제공하는 방법을 찾아보기로 했습니다.  

 


🕵️‍♀️ 세계지도 라이브러리 조사

우선 전 세계 지도가 필요했습니다. 지도에서 특정 국가를 선택하면 그 나라의 영토 색깔만 바뀌는 형태면 되었죠. 애초에는 게임으로 만들어볼까 해서 GUI 등도 필요했었지만 MapPuzze 덕분에 그런 것은 잊어도 되게 되었습니다. ^^; 

 

인터넷 검색을 통해 알아본 사용 가능한 지도맵 라이브러리는 아주 다양했습니다. 그것들 가운데 목적에 맞는 가벼운 녀석을 찾아서 사용하는 것으로 방향을 잡았죠. 다음은 조사한 목록입니다. 

 

 

1️⃣ worldmap (Doc, 깃헙)

  • python 패키지 (pypi에서 지원)
  • MIT 라이선스
  • 코드 상으로는 아주 간단함
  • plot 된 것을 svg 파일로 내보내는 것 지원
  • 인터랙티브 모드는 미지원 
  • 대륙 별 표시 기능 미지원 
  • 제약사항 (일부는 개발하면서 알게 됨)
    • 현재는 0.1.7 버전인데 이전 버전과 기능, 컴포넌트, 코드 사용 방식이 전혀 다름
      최신 버전에서는 단순화된 기능만 제공합니다. 예를 들어 plot 기능이 없어지고 파일로 저장하는 것이 기본이 되었습니다. 
    • ISO 국가 코드를 이용하기는 하지만 간혹 잘못된 값이 매칭되는 경우가 있음 (예: 팔레스타인 -> 파키스탄으로 매칭)

 

아래 코드는 제공되는 샘플입니다. 사용 방법은 아주 간단하죠. 나라를 지정하고 적용할 opacity(투명도)와 컬러맵(cmap)을 지정하면 자동으로 생성됩니다.

# Import library
import worldmap as wm

# Coloring of maps
county_names = ['India','china','brazile', 'austrialia']

# Create the SVG
results = wm.plot(
    county_names,                       # 영역을 색칠할 국가명 목록 
    opacity=[10] * len(county_names),   # 투명도 설정
    map_name='world',                   # 사용할 지도 타입 
    cmap='Set1',                        # 컬러맵 선택
    filename='map.svg'                  # 저장할 파일명
)

 

그림 : 코드 실행 결과

 

 

2️⃣ SVG World Map with labels (데모, 깃헙)

  • 색상 레이블 지원
  • html, css, javascript 기반
  • MIT 라이선스
  • UN 193개국 레이블 이용
  • 제약사항) 지원 도법 때문에 약간 찌그러진 상태로  표시됨. 이게 더 자연스러운가?

그림 : SVG World Map을 이용한 예시

 

 

3️⃣ countries-map (깃헙)

  • node 패키지 기반 (typescript, html, scss)
  • v4 (자체 임베딩 맵 이용), v3 (구글 GeoCharts 이용)
  • MIT 라이선스 이용

그림 : countries-map 을 이용한 예시

 

4️⃣ Live Map (링크, 깃헙)

  • node (javascript, css) 기반
  • 제약사항
    • 현재 사용자 위치 (예: 대한민국)에 기본값으로 아이콘이 항상 표시됨
    • 상단에 국가명과 국기가 항상 표시됨 
    • 맵의 배경 색상 변경 필요 -> 다크모드면 회색... 좀 칙칙... 

예시 : Live Map을 이용한 예시

 

 

 

위의 것들 가운데 html, javascript만으로 할 수 있으면 그걸 이용하려고 했는데 별도 서버 모듈(예: node) 같은 것들이 필요하다고 해서 그럴 바에는 손쉬운 python 기반의 worldmap을 이용하기로 했습니다. 코드도 간단하고 후작업을 위한 처리에도 유리할테니까 말이죠.


👨‍💻 Worldmap을 이용한 코드 생성

worldmap 패키지를 이용해 세계지도에서 특정 국가 영역을 색칠하고 결과물은 svg 파일로 저장하는 코드를 작성합니다. 여기에 추가적으로 적용된 요건은 다음과 같습니다.

  • 대륙 별로 영역을 분리해서 처리하도록 처리합니다. 
    • 전세계 지도에 표기하는 것도 필요하지만, 대륙 별 국가 위치 표기도 필요할 것 같았기 때문입니다. 
    • continent_viewboxes라는 변수를 두고 각 대륙 별 좌표 추출을 했습니다. (화면 상에서 내가 생각하는 위치의 박스를 그려서 값만 추출하도록 별도의 코드를 이용했습니다)
    • 이렇게 추출된 좌표 기준으로 크기를 조절하고 crop 하도록 설정합니다. 
  • 아시아국가들의 정보를 담은 json 파일을 미리 생성하고 여기에 포함된 국가들별로 svg 파일을 생성하도록 했습니다. 

1️⃣ 코드

import worldmap as wm
import json
import os
from xml.etree import ElementTree as ET


continent_viewboxes = {
    'asia':          [525, 38, 478, 453],   # x, y, width, height
    'europe':        [399, 166, 205, 196],
    'africa':        [415, 336, 222, 249],
    'north_america': [1, 152, 338, 283],
    'south_america': [216, 414, 176, 243],
    'oceania':       [764, 458, 227, 181],
}

def resize_and_crop_svg(svg_path, viewbox, scale=2.0):
    tree = ET.parse(svg_path)
    root = tree.getroot()
    # viewBox 설정
    viewbox_str = ' '.join(map(str, viewbox))
    root.set('viewBox', viewbox_str)
    # width, height를 2배로
    width, height = int(viewbox[2] * scale), int(viewbox[3] * scale)
    root.set('width', str(width))
    root.set('height', str(height))
    tree.write(svg_path, encoding="utf-8")

with open('아시아국가.json', 'r', encoding='utf-8') as f:
    data = json.load(f)
countries = data['countries']

save_dir = 'asia_svg_files'
os.makedirs(save_dir, exist_ok=True)

viewbox = continent_viewboxes['asia']
scale = 2.0  # 2배

for country in countries:
    eng_name = country['국가명_영어']
    iso_code = country['code']

    svg_filename = os.path.join(save_dir, f'map_{iso_code}.svg')
    result = wm.plot([eng_name], opacity=[100], map_name='world', cmap='tab20', filename=svg_filename)

    svg_path = None
    if isinstance(result, str):
        svg_path = result
    elif isinstance(result, tuple):
        for v in result:
            if isinstance(v, str) and v.endswith('.svg'):
                svg_path = v
                break
    if svg_path is None:
        raise RuntimeError("SVG 파일 경로를 반환값에서 찾지 못했습니다. result={}".format(result))

    # SVG를 2배 크기로 crop (viewBox 및 width/height 조정)
    resize_and_crop_svg(svg_path, viewbox, scale=scale)

    print(f'Saved: {svg_path}')

 

 

2️⃣ 결과물

 

생성된 svg 파일들입니다. 전세계 지도에서 모두 같은 영역 (아시아) 내에서 해당 국가들의 위치가 색칠되어 있습니다. 작은 썸네일이라 소규모 국가들은 제대로 보이지도 않습니다. ^^; 

 


 

이제 이렇게 만들어진 이미지들과 앞서 생성해 둔 국가 별 정보를 담은 json을 이용해 교육 콘텐츠를 제작할 생각입니다. 내용 자체도 어린 아이들 용이라 복잡하지 않고 간단한 내용만 담고 있어야겠죠. 결과물이 나오면 링크를 추가로 공유하도록 하겠습니다. 

 

업데이트) 위의 기법을 이용해서 만든 컨텐츠입니다. 이런 쪽 컨텐츠 좋아하시면 '좋아요', '구독' 부탁드려요! 🤗