새발블로그

D3로 값 범위(Orders-of-Magnitude)가 큰 시계열을 정확하게 시각화하는 방법 본문

Client/Vue.js

D3로 값 범위(Orders-of-Magnitude)가 큰 시계열을 정확하게 시각화하는 방법

EUG 2025. 11. 10. 22:12

1. 문제 배경

시계열 데이터에서 값의 크기 차이가 수십~수천 배 이상 벌어지는 경우(예: 0.1 ~ 100000), 선형 스케일(linear)만으로는 다음 문제가 발생

  • 작은 값들이 바닥에 평평하게 깔려 보임 → 정보 손실
  • 이상치(outlier) 때문에 전체 분포가 왜곡됨
  • 추세·분포·이상치를 한 번에 보기 어려움

이때 필요한 것이 스케일 보정(Scaling) 이며, D3.js는 이를 정확하고 유연하게 처리할 수 있는 도구를 제공합니다.

2. D3 스케일은 정확히 무엇인가?

D3의 scale() 함수도메인(domain) 값을 픽셀(range) 값으로 변환하는 함수입니다.

value (domain) ---> scale ---> pixel (range)

예시:

const y = d3.scaleLinear()
.domain([0, 100]) // 실제 데이터 범위
.range([300, 0]); // 화면 y축 픽셀

스케일은 그 자체로 수학적 함수이며:

  • scale(value) → 데이터 → 픽셀
  • scale.invert(px) → 픽셀 → 데이터

을 수행

D3의 스케일은 단순 선형뿐 아니라 로그/시간/밴드/파워/퀀타일 등 다양한 공간 변환을 지원합니다.

3. 선형 스케일 vs 로그 스케일

Linear (d3.scaleLinear)

  • 값의 차이가 덧셈적일 때 적합
  • 큰 값 하나 때문에 작은 값이 눌려보이는 문제 발생

Log (d3.scaleLog)

  • 값의 차이가 곱셈적(비율적)일 때 적합
  • 수십~수천 배 차이도 자연스럽게 표현

주의사항:

  • 0 이하 값 불가능 (log 특성)
  • 최소값은 반드시 0보다 큰 값으로 보정해야 함

예:

const y = d3.scaleLog()
.clamp(true)
.domain([
Math.max(0.1, d3.min(data, d => d.y)),
d3.max(data, d => d.y)
])
.range([h, 0]);

 

4. 축(Axis)과 라인(Line) 생성

const x = d3.scaleLinear()
.domain(d3.extent(data, d => d.x))
.range([0, w]);

const y = scaleType === 'log'
? d3.scaleLog().domain([yMin, yMax]).range([h, 0])
: d3.scaleLinear().domain([yMin, yMax]).range([h, 0]);

const line = d3.line()
.x(d => x(d.x))
.y(d => y(d.y))
.curve(d3.curveMonotoneX);
 

5. 비교이미지

위 두 장의 차트에서 보이는 것처럼 Linear 스케일에서는 작은 값이 바닥에 깔려 보이지만, Log 스케일에서는 값의 비율(orders-of-magnitude)을 기반으로 눈금을 배치하기 때문에 작은 값의 패턴과 변동성까지 모두 드러난다.