HeatmapChart
셀마다 하나의 크기를 재는 대신 색으로 나타내는 차트입니다. 같은 아이디어를 두 형태로 그립니다. category 축 두 개와 숫자 하나를 위한 grid, 그리고 pie가 담기에는 조각이 너무 많은 전체와 부분을 위한 treemap입니다.
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이 실제로 있을 때만, 없으면 없는 경계를 만들어 냅니다 |
| midpoint | number | 0 | diverging 스케일이 뒤집히는 지점 |
| min | number | — | 스케일이 시작하는 값. 생략하면 데이터에서 옵니다. 두 차트를 비교하려면 같은 범위를 주어야 합니다 |
| max | number | — | 스케일이 끝나는 값 |
| valueLabels | 'none' | 'all' | 'none' | 각 셀 위에 값을 씁니다. 들어갈 자리가 없는 라벨은 잘리는 대신 생략되고, 잉크는 셀의 단계에 따라 정해집니다 |
| legend | boolean | { 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 | 3 | 0 | 그림자 깊이. 0은 그림자 없음 |
| height | number | string | size | 그림의 높이. 축 라벨도 이 높이 안에 그려집니다 |
| label | string | locale's word | 차트의 접근 가능한 이름. 그림 대신 읽히고, 아래에 숨겨진 데이터 표의 caption이 됩니다. 없으면 locale의 일반 명사가 쓰이지만, 무엇에 대한 차트인지는 여기서만 말할 수 있습니다 |
| format | Intl.NumberFormatOptions | — | 숫자가 나타나는 모든 곳의 표기, 축·tooltip·값 라벨·표. 없으면 만 이상은 축약됩니다(12.4K) |
| locale | string | — | 차트가 스스로 쓰는 말과 날짜의 언어 |
| legend | boolean | NebaChartLegend | series ≥ 2 | series가 둘 이상이면 자동으로 나오고 하나면 나오지 않습니다. 색 하나짜리 범례는 제목을 반복할 뿐입니다 |
| tooltip | boolean | NebaChartTooltip | true | 포인터가 무엇을 드러낼지. tooltip에만 있는 값은 없습니다. 모든 값이 숨겨진 표에도 있습니다 |
| empty | ReactNode | — | 그릴 것이 없을 때 대신 그릴 내용 |
<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}로 끄고, legend의 side로 옮깁니다.
접근성
- 데이터는
label을 caption으로 하는 화면에 보이지 않는 표로도 렌더링됩니다. series 하나가 한 행, category 하나가 한 열입니다. - plot에 focus할 수 있습니다.
←·→로 셀을 옮기고Escape로 tooltip을 해제합니다. - 스케일 범례가 범위의 양 끝을 숫자로 알려 주므로, 램프를 눈으로만 읽어야 하는 경우는 없습니다.