유럽 폭염 히트맵 애니메이션 제작기 — 격자 데이터를 지도로 옮기는 일
이 차트의 주제는 유럽 폭염이다. 다만 이 글에서 다루려는 것은 폭염 자체가 아니다. 유럽의 장기 기온 추세, 에어컨 보급률, 2026년 폭염이 만든 인명 피해와 경제적 손실 — 모두 중요한 주제지만 이 글의 범위 밖이다. 이 글은 하나의 질문에서 출발한다. 지도 위에서 히트맵 애니메이션이 과연 시각화로 성립하는가.
기후 분석이 아니라 시각화 실험의 기록이다.
위는 2026년 6월 14일부터 7월 12일까지 유럽의 실제 일 최고기온이다. 아래는 1991년부터 2020년까지 같은 날짜의 평균 일 최고기온이다. 두 지도는 같은 날짜를 같은 속도로 재생한다.
만만하게 봤다
기온 데이터는 공개되어 있다. 지도 템플릿도 있다. 처음에는 그렇게 생각했다. 데이터를 받아서 좌표와 값을 넣으면 지도가 알아서 그려줄 것이라고 봤다. 반나절이면 끝날 작업으로 잡았다.
결과부터 말하면 지금까지 만든 차트 중 난이도가 가장 높았다. 데이터를 구하는 단계가 아니라 그 데이터를 지도 위에서 읽히게 만드는 단계에서 막혔다. 기온 데이터는 지도 시각화가 전제하는 형태와 근본적으로 다르게 생겼기 때문이다.
기온 데이터는 지도가 원하는 모양이 아니다
지도 시각화가 잘 작동하는 데이터는 대개 두 가지 형태다. 하나는 국가나 시도 같은 행정구역 단위 값이다. 지역 코드와 숫자 하나를 짝지으면 코로플레스 지도가 완성된다. 다른 하나는 개별 지점의 사건이다. 사고 발생 위치, 매장 위치처럼 좌표 하나에 점 하나가 대응한다.
기온은 둘 다 아니다. 기온에는 국경이 없다. 프랑스 남부와 스페인 북부의 기온은 국경선에서 끊기지 않고 이어진다. 국가 단위로 평균을 내는 순간 이 연속성이 사라지고, 폭염이 어디서 시작해 어디로 번졌는지가 통째로 지워진다. 이 차트가 보여주려던 것이 바로 그 이동이었으니 코로플레스는 처음부터 선택지가 아니었다.
그렇다고 점 하나에 대응하는 사건도 아니다. 기온은 공간 전체에 깔려 있는 연속면이다. 재분석 데이터가 격자 형태를 취하는 이유도 여기에 있다. 연속면을 유한한 숫자로 저장하려면 공간을 잘게 나누는 수밖에 없다.
격자 해상도가 첫 번째 벽이었다
사용한 데이터는 코페르니쿠스 기후데이터스토어의 ERA5 일 최고기온이다. ERA5는 유럽 전역을 촘촘한 격자로 덮고 각 격자점마다 값을 가진다. 원본 해상도를 그대로 쓰면 유럽 본토 범위만 잘라내도 격자점이 수만 개 단위가 되고, 여기에 29일치를 곱하면 행 수가 감당할 수 없게 불어난다.
브라우저에서 돌아가는 시각화 도구는 이 규모를 받지 못한다. 렌더링이 느려지는 정도가 아니라 아예 멈춘다. 그래서 위도와 경도를 각각 1° 간격으로 리샘플링했다. 지도 범위가 대략 경도 -11°에서 32°, 위도 33°에서 57° 구간이니 하루치가 1,000개 남짓한 격자점으로 정리되고, 29일을 곱해도 3만 행 안팎에서 멈춘다. 이 정도가 브라우저에서 애니메이션이 끊기지 않는 상한선이었다.
여기서 딜레마가 생긴다. 1°는 위도상 약 111km, 유럽 중위도의 경도상으로는 70km 안팎이다. 격자 하나가 서울에서 대전까지의 거리를 하나의 값으로 대표한다는 뜻이다. 산맥과 해안선이 만드는 국지적인 기온 차이는 이 단계에서 대부분 뭉개진다.
더 촘촘하게 가면 지형이 살아나지만 브라우저가 버티지 못하고, 더 성글게 가면 온도 분포가 덩어리로 뭉친다. 여러 간격을 바꿔가며 테스트한 끝에 이 차트는 정확도보다 흐름의 가독성을 택한 지점에서 멈춰 있다. 격자가 커질수록 개별 값의 신뢰도는 떨어지지만, 붉은 영역이 서쪽에서 동쪽으로 밀려가는 큰 움직임은 오히려 선명해진다. 이 차트의 목적이 후자였다.
포인트맵으로는 안 됐다
먼저 시도한 것은 격자점 하나에 원 하나를 찍는 포인트맵이었다. 온도가 높을수록 원을 붉게, 크게 만드는 방식이다. 데이터 구조상 가장 자연스러운 접근이었다.
결과는 실패였다. 화면에 수천 개의 원이 격자 간격대로 규칙적으로 박히면서 기온 분포가 아니라 그물망처럼 보였다. 원 크기를 키우면 서로 겹쳐 뭉개지고, 줄이면 배경 지도에 묻혀 아무것도 안 보였다. 무엇보다 치명적인 것은 격자의 인공적인 배열이 그대로 드러난다는 점이었다. 자연 현상을 보여주는 지도인데 화면에는 사람이 만든 좌표계가 보였다.
기온의 본질은 연속성이다. 점으로 찍는 순간 그 연속성이 끊긴다. 표현 방식이 데이터의 성격을 배반한 경우였다.
히트맵으로 넘어가면서 생긴 문제
히트맵은 이 문제를 해결한다. 각 지점의 값을 주변으로 부드럽게 번지게 만들어 연속면처럼 보이게 한다. 격자의 인공적인 배열이 사라지고, 붉은 덩어리가 지도 위를 이동하는 인상이 만들어진다. 이 차트가 원하던 그림이 여기서 나왔다.
대신 새로운 문제가 따라왔다. 히트맵의 색은 원본 기온값을 그대로 옮긴 색이 아니다. 주변 지점들의 밀도와 가중치가 합산된 시각적 강도다. 같은 40도라도 주변이 함께 뜨거우면 더 짙게, 고립되어 있으면 더 옅게 표현된다.
이 특성 때문에 두 지도를 나란히 놓았을 때 예상 못 한 일이 벌어졌다. 동일한 팔레트를 적용하자 평년 지도가 거의 백지처럼 보인 것이다. 실제로 평년에도 남유럽은 30도를 넘는데, 고온 지점이 흩어져 있다 보니 합산 강도가 낮게 잡혔다. 절대 기온으로는 분명 더운데 화면에서는 시원해 보이는 상태였다.
그래서 두 지도의 팔레트를 다르게 잡았다. 2026년 지도는 짙은 적색까지, 평년 지도는 주황 계열까지 가도록 상한을 조정해 같은 온도대가 비슷한 인상으로 읽히게 맞췄다. 데이터를 손댄 것이 아니라 렌더링 강도 차이를 보정한 것이다. 다만 이 사실은 반드시 밝혀야 한다고 판단했다. 밝히지 않으면 색 차이가 곧 온도 차이로 읽히고, 그건 과장이 된다.
평년 데이터는 직접 만들어야 했다
2026년 데이터는 받으면 끝이지만 비교 대상인 평년 데이터는 그렇지 않았다. 필요한 것은 1991년부터 2020년까지 각 날짜별로 같은 날짜의 평균이다. 6월 14일 값은 30년치 6월 14일의 평균이고, 6월 15일 값은 30년치 6월 15일의 평균이다.
연평균이나 월평균으로는 이 비교가 성립하지 않는다. 6월 중순과 7월 중순은 평년값 자체가 다르기 때문에, 하나의 기준선으로 29일 전체를 비교하면 앞뒤 구간의 대비가 왜곡된다. 날짜 단위로 대응하는 기준선이 있어야 같은 날짜끼리의 비교가 된다.
이 가공 과정이 작업 시간의 상당 부분을 차지했다. 30년치를 격자점별, 날짜별로 정렬하고 평균을 낸 뒤, 2026년 데이터와 동일한 1° 격자 좌표로 다시 맞춰야 했다. 좌표가 조금이라도 어긋나면 두 지도가 서로 다른 지점을 비교하게 된다. 작업 도중 2026년 지도의 동쪽 범위를 넓혔는데, 그때도 확장분을 같은 1° 간격으로 생성해 기존 격자와 이어붙였다. 한쪽만 해상도가 달라지면 그 경계에서 히트맵 강도가 튄다.
시간축을 맞추는 일
마지막 관문은 두 지도의 재생 동기화였다. 상단과 하단이 항상 같은 날짜를 보여줘야 비교가 성립한다. 한쪽이 하루라도 앞서가면 이 차트는 아무 의미가 없어진다.
여기서 날짜 결측 문제가 드러났다. 어느 한쪽에라도 값이 비는 날짜가 있으면 타임슬라이더의 구간 수가 달라지고, 재생 속도가 미세하게 어긋난다. 육안으로 즉시 알아채기 어렵지만 29일이 흐르는 동안 누적되면 확실히 벌어진다. 결국 두 데이터셋의 날짜 목록을 완전히 동일하게 맞추는 작업이 필요했다.
기간을 6월 14일부터 7월 12일까지 29일로 확정한 것도 이 과정에서였다. 5월 폭염 구간까지 넣으면 재생 시간이 길어지면서 후반부의 대비가 상대적으로 묻혔다. 가장 강한 대비가 나타나는 구간만 잘라내는 편이 나았다.
완성했다고 보지 않는다
정확한 기온대 도메인 설정, 편차 표현, 시간에 따른 흐름의 정밀도 — 이 세 가지는 아직 만족스럽지 않다. 특히 색상 구간을 몇 도 단위로 끊을 것인지, 절대 기온이 아니라 평년 대비 편차로 보여줄 것인지는 여전히 열려 있는 문제다.
다만 목표로 삼았던 최소한은 도달했다고 본다. 이 정도 규모구나, 이 정도 범위가 이렇게 움직였구나가 화면에서 읽힌다. 숫자로 40도라고 쓰는 것과, 붉은 영역이 이베리아반도에서 시작해 프랑스와 중부유럽을 지나 동쪽으로 밀려가는 29일을 눈으로 따라가는 것은 다른 경험이다. 이 차트가 하려던 일이 그것이었다.
이 방식으로 열리는 것들
격자 데이터를 히트맵 애니메이션으로 옮기는 방식이 성립한다는 것이 확인됐다면, 같은 구조를 쓸 수 있는 주제가 상당히 많다.
강수량은 기온과 데이터 구조가 거의 동일하다. 같은 ERA5 계열에서 받을 수 있고 격자 형태도 같다. 가뭄 구간과 집중호우 구간을 같은 방식으로 비교할 수 있다.
산불은 발생 지점과 확산 면적이 시간에 따라 변하는 데이터라 히트맵과 잘 맞는다. 다만 기온과 달리 연속면이 아니라 개별 발생 지점이므로 표현 강도를 다르게 잡아야 한다.
감염병 확산은 이 구조가 가장 직관적으로 먹히는 영역이다. 행정구역 단위 집계 데이터를 좌표로 변환하는 단계가 추가로 필요하지만, 확산 경로를 보여주는 목적에는 히트맵이 코로플레스보다 낫다.
인구 이동은 정적인 인구 분포가 아니라 시간에 따른 밀도 변화로 다룰 때 의미가 생긴다. 수도권 집중이나 지방 소멸 같은 주제를 국가 단위 숫자가 아니라 밀도의 이동으로 보여줄 수 있다.
공통점은 하나다. 행정구역 경계로 끊어지지 않고 공간에 연속적으로 퍼져 있으면서, 시간에 따라 이동하는 현상이다. 이 조건에 맞는 데이터라면 같은 방법론을 적용할 수 있다.
이 차트로 읽으면 안 되는 것
몇 가지는 분명히 해둔다.
이 지도의 색으로 정확한 섭씨값을 읽을 수 없다. 히트맵 색은 주변 지점의 밀도가 합산된 시각적 강도이지 온도계 눈금이 아니다.
격자 간격이 1°라는 점도 함께 봐야 한다. 격자 하나가 100km 안팎의 공간을 하나의 값으로 대표하므로, 이 지도에서 특정 도시의 기온을 읽어내는 것은 불가능하다. 도시 단위 정보가 필요하면 각국 기상청 관측 자료를 봐야 한다.
평년 지도는 특정 연도가 아니라 30년 평균이다. 그리고 평년 지도에서 남유럽이 주황색으로 나타나는 것은 정상이다. 원래 여름철 기온이 높은 지역이다. 이 차트가 보여주는 차이는 고온 영역이 얼마나 넓게, 얼마나 북쪽까지 확산됐는가에 있다.
두 지도가 다른 팔레트를 쓴다는 점도 다시 밝혀둔다. 색이 짙다는 사실 자체가 온도 차이의 크기를 뜻하지 않는다.
마지막으로 이 글은 2026년 폭염의 원인을 다루지 않는다. 장기적인 온난화 경향이 폭염 위험을 키운다는 일반적인 맥락은 널리 알려져 있지만, 개별 폭염 사건에 기후변화가 얼마나 기여했는지를 말하려면 별도의 귀속 연구가 필요하다. 이 차트는 두 시기의 기온 분포를 같은 날짜로 나란히 놓은 비교 시각화일 뿐이다.
이 작업에서 가장 크게 남은 것은 격자 간격도 팔레트 값도 아니다. 데이터의 성격과 표현 방식이 어긋나면 아무리 정확한 숫자를 넣어도 화면에서는 읽히지 않는다는 것이다. 포인트맵이 실패한 이유도, 히트맵이 작동한 이유도 결국 같은 자리에 있었다.
출처(외부 링크): 원 데이터와 가공 방식은 아래에서 확인할 수 있다.
- 데이터 Copernicus Climate Data Store — ERA5 daily statistics
- 안내 평년 지도는 위 자료의 1991–2020년 값을 날짜별 평균으로 직접 가공한 결과다. 원 제공자의 공식 산출물이 아니다.
<div class="flourish-embed flourish-map" data-src="visualisation/29742141"><script src="https://public.flourish.studio/resources/embed.js"></script><noscript><img src="https://public.flourish.studio/visualisation/29742141/thumbnail" width="100%" alt="map visualization" /></noscript></div>
<div class="flourish-embed flourish-map" data-src="visualisation/29740293"><script src="https://public.flourish.studio/resources/embed.js"></script><noscript><img src="https://public.flourish.studio/visualisation/29740293/thumbnail" width="100%" alt="map visualization" /></noscript></div>
댓글