본문으로 건너뛰기

HeatmapChart

셀마다 하나의 크기를 재는 대신 색으로 나타내는 차트입니다. 같은 아이디어를 두 형태로 그립니다. category 축 두 개와 숫자 하나를 위한 grid, 그리고 pie가 담기에는 조각이 너무 많은 전체와 부분을 위한 treemap입니다.

tsx
import { HeatmapChart } from 'neba';

<HeatmapChart
  label="시간대·요일별 세션"
  categories={['00', '06', '12', '18']}
  series={[
    { name: 'Mon', data: [4, 24, 51, 18] },
    { name: 'Tue', data: [3, 27, 55, 20] }
  ]}
/>;

데이터 형식

series의 형태는 모든 차트가 공유합니다. 전체 정의는 LineChart에 있습니다. 여기서 series 하나는 grid의 또는 treemap의 그룹이고, y가 크기, x가 열 또는 타일의 이름입니다.

null은 결측이고 그 셀은 그리지 않은 채로 둡니다. 스케일의 맨 아래로 칠하지 않습니다. "아무 일도 없었다"와 "가장 적었다"는 서로 다른 읽기이고, 데이터에 있는 것은 둘 중 하나뿐이기 때문입니다.

스케일은 행마다가 아니라 차트 전체의 모든 셀에 걸쳐 한 번 정해집니다. 같은 색은 어디에 있든 같은 숫자를 뜻해야 하고, 그것이 heatmap이 하는 약속의 전부입니다. 비교에 고정된 틀이 필요하면 min·max로 양 끝을 고정하세요.

Props

Prop타입기본값설명
series * NebaChartSeries[]series 하나가 grid의 행 또는 treemap의 그룹입니다. y가 크기, x가 열·타일 이름이고, null은 결측이라 그 셀은 그리지 않습니다
categories(string | number | Date)[]열 이름. 각 점이 x를 직접 들고 있어도 됩니다
shape'grid' | 'treemap''grid'grid는 category 축 둘과 숫자 하나, treemap은 비중대로 크기를 준 타일로 상자를 채웁니다
scale'sequential' | 'diverging''sequential'sequential은 한 hue의 옅음→진함, diverging은 중립 회색을 사이에 둔 두 hue입니다. diverging은 기준이 되는 0이 실제로 있을 때만, 없으면 없는 경계를 만들어 냅니다
midpointnumber0diverging 스케일이 뒤집히는 지점
minnumber스케일이 시작하는 값. 생략하면 데이터에서 옵니다. 두 차트를 비교하려면 같은 범위를 주어야 합니다
maxnumber스케일이 끝나는 값
valueLabels'none' | 'all''none'각 셀 위에 값을 씁니다. 들어갈 자리가 없는 라벨은 잘리는 대신 생략되고, 잉크는 셀의 단계에 따라 정해집니다
legendboolean | { side, align }true양 끝에 값이 붙은 스케일 막대. swatch 목록이 아닙니다. 여기에는 이름을 가진 것이 없고 순서가 곧 의미입니다
variant공통'solid' | 'outline' | 'text''text'표면의 무게. 차트는 시트가 아니라 그림이므로 기본값이 text입니다. Card 안에 넣으면 가장자리가 겹치지 않습니다. 혼자 서는 차트에는 outline을 주세요
size공통'xs' | 'sm' | 'md' | 'lg' | 'xl''md'축 글자·선 두께·마커 크기, 그리고 height를 주지 않았을 때의 높이
color공통'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'시트의 색 계열. series의 색은 여기서 오지 않습니다. 팔레트나 series.color가 정합니다
density공통'default' | 'compact''default'여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통0 | 1 | 2 | 30그림자 깊이. 0은 그림자 없음
heightnumber | stringsize그림의 높이. 축 라벨도 이 높이 안에 그려집니다
labelstringlocale's word차트의 접근 가능한 이름. 그림 대신 읽히고, 아래에 숨겨진 데이터 표의 caption이 됩니다. 없으면 locale의 일반 명사가 쓰이지만, 무엇에 대한 차트인지는 여기서만 말할 수 있습니다
formatIntl.NumberFormatOptions숫자가 나타나는 모든 곳의 표기, 축·tooltip·값 라벨·표. 없으면 만 이상은 축약됩니다(12.4K)
localestring차트가 스스로 쓰는 말과 날짜의 언어
legendboolean | NebaChartLegendseries ≥ 2series가 둘 이상이면 자동으로 나오고 하나면 나오지 않습니다. 색 하나짜리 범례는 제목을 반복할 뿐입니다
tooltipboolean | NebaChartTooltiptrue포인터가 무엇을 드러낼지. tooltip에만 있는 값은 없습니다. 모든 값이 숨겨진 표에도 있습니다
emptyReactNode그릴 것이 없을 때 대신 그릴 내용

<div>의 native 속성과 Box의 모든 prop이 그대로 전달됩니다. 공용 축은 prop 규약을 참고하세요.

예시

shape

grid는 요일 대비 시간대나 주차 대비 코호트처럼 category 축 둘과 숫자 하나를 위한 형태입니다. treemap은 datum마다 타일 하나를 비중에 맞는 크기로 채워 상자를 가득 메웁니다.

treemap은 잘라 나누는 대신 squarify합니다. 타일을 행으로 쌓다가 종횡비가 더 나아지지 않는 순간 그 행을 닫습니다. 그냥 잘라 나누면 값이 스무 개일 때 폭 1px짜리 조각들이 남는데, 그런 조각의 넓이는 아무리 정확해도 읽히지 않습니다.

treemap에는 축이 없고 이름이 타일 안에 직접 적힙니다. 음수는 넓이로 표현할 수 없으므로 표에는 남고 그림에서는 빠집니다.

scale

sequential은 한 hue로 옅은 쪽에서 진한 쪽까지이고, 많을수록 그냥 많다는 뜻일 때 맞습니다. diverging은 중립 회색을 사이에 둔 두 hue로, 목표 대비 초과와 미달, 증가와 감소처럼 중간이 의미를 가지는 값에 씁니다. 그 중간이 어디인지는 midpoint가 정합니다.

diverging은 실제로 기준이 되는 0이 있을 때만 쓰세요. 그냥 크기인 값에 쓰면 데이터에 없는 경계를 만들어 내고, 독자는 차트를 보는 내내 회색에서 무엇이 바뀌었는지를 찾게 됩니다.

두 램프 모두 8슬롯 category 팔레트가 아닙니다. 여기서 색은 정체성이 아니라 크기를 나타내며, hue 여덟 개짜리 heatmap은 셀들이 서로 무관한 여덟 가지라고 말하는 셈입니다.

valueLabels · min · max

valueLabels="all"은 각 값을 셀 위에 씁니다. 글자가 양옆 여백과 함께 들어갈 만큼 셀이 클 때만이고, 들어가지 않는 라벨은 잘리는 대신 생략됩니다. 채워진 셀 안의 라벨은 그 아래 스텝에서 잉크를 고르므로 램프의 양쪽 끝 모두에서 읽힙니다.

min·max는 스케일을 고정합니다. 생략하면 양 끝이 데이터에서 오는데, 그 말은 서로 다른 데이터의 두 차트는 같은 범위를 줄 때까지 비교할 수 없다는 뜻입니다.

legend

범례는 swatch 목록이 아니라 양 끝에 값이 붙은 스케일 막대입니다. 여기에는 이름을 가진 것이 없고, 순서 자체가 의미이기 때문입니다. diverging에서는 막대 가운데 아래에 midpoint를 씁니다. legend={false}로 끄고, legendside로 옮깁니다.

접근성

  • 데이터는 label을 caption으로 하는 화면에 보이지 않는 표로도 렌더링됩니다. series 하나가 한 행, category 하나가 한 열입니다.
  • plot에 focus할 수 있습니다. ·로 셀을 옮기고 Escape로 tooltip을 해제합니다.
  • 스케일 범례가 범위의 양 끝을 숫자로 알려 주므로, 램프를 눈으로만 읽어야 하는 경우는 없습니다.

Released under the MIT License