Heatmap

Data Visualization

visx 기반 매트릭스 히트맵.

Usage

두 범주 조합의 수치를 격자 색 농도로 비교하고 패턴을 찾을 때 사용한다.

import

import

import { Heatmap } from '@mildang/design-system/Chart';

예제를 복사해 쓸 때 필요한 준비

@mildang/styled-system 은 이 저장소에서 Panda 가 생성하는 산출물이다. 저장소 안에서는 turbo run ship 이후 쓸 수 있고, 패키지 소비자는 자기 Panda 산출물이나 다른 레이아웃 수단으로 바꿔야 한다.

API Reference

Heatmap Props

Prop

Type

Default

data
필수

TDatum[]

지정 안 함

valueKey
필수

string

지정 안 함

xKey
필수

string

지정 안 함

yKey
필수

string

지정 안 함

cellGap

number

2

cellRadius

number

4

className

string

지정 안 함

colorRange

[string, string]

[ | token('colors.brand.surface.low'), | token('colors.brand.surface.highest'), | ]

formatValue

(value: number) => string

(value: number) => value.toLocaleString()

legendPosition

"bottom" | "left" | "right" | "top"

bottom

margin

Partial<ChartMargin>

지정 안 함

showLegend

boolean

false

showTooltip

boolean

false

showValues

boolean

false

showXAxis

boolean

true

showYAxis

boolean

true

valueLabel

string

지정 안 함

예제

기본

import { Heatmap } from '@mildang/design-system/Chart';

// 반별 × 단원별 정답률(%)
const accuracyData = [
  { unit: '1단원', classroom: '1반', accuracy: 92 },
  { unit: '1단원', classroom: '2반', accuracy: 85 },
  { unit: '1단원', classroom: '3반', accuracy: 78 },
  { unit: '1단원', classroom: '4반', accuracy: 88 },
  { unit: '2단원', classroom: '1반', accuracy: 84 },
  { unit: '2단원', classroom: '2반', accuracy: 76 },
  { unit: '2단원', classroom: '3반', accuracy: 69 },
  { unit: '2단원', classroom: '4반', accuracy: 81 },
  { unit: '3단원', classroom: '1반', accuracy: 71 },
  { unit: '3단원', classroom: '2반', accuracy: 64 },
  { unit: '3단원', classroom: '3반', accuracy: 58 },
  { unit: '3단원', classroom: '4반', accuracy: 66 },
  { unit: '4단원', classroom: '1반', accuracy: 88 },
  { unit: '4단원', classroom: '2반', accuracy: 79 },
  { unit: '4단원', classroom: '3반', accuracy: 72 },
  { unit: '4단원', classroom: '4반', accuracy: 83 },
  { unit: '5단원', classroom: '1반', accuracy: 95 },
  { unit: '5단원', classroom: '2반', accuracy: 87 },
  { unit: '5단원', classroom: '3반', accuracy: 74 },
  { unit: '5단원', classroom: '4반', accuracy: 90 },
  { unit: '6단원', classroom: '1반', accuracy: 62 },
  { unit: '6단원', classroom: '2반', accuracy: 55 },
  { unit: '6단원', classroom: '3반', accuracy: 51 },
  { unit: '6단원', classroom: '4반', accuracy: 59 },
];

const HeatmapDefaultExample = () => (
    <Heatmap data={accuracyData} xKey="unit" yKey="classroom" valueKey="accuracy" showLegend />
  );

export default HeatmapDefaultExample;

값 표시

import { Heatmap } from '@mildang/design-system/Chart';

// 반별 × 단원별 정답률(%)
const accuracyData = [
  { unit: '1단원', classroom: '1반', accuracy: 92 },
  { unit: '1단원', classroom: '2반', accuracy: 85 },
  { unit: '1단원', classroom: '3반', accuracy: 78 },
  { unit: '1단원', classroom: '4반', accuracy: 88 },
  { unit: '2단원', classroom: '1반', accuracy: 84 },
  { unit: '2단원', classroom: '2반', accuracy: 76 },
  { unit: '2단원', classroom: '3반', accuracy: 69 },
  { unit: '2단원', classroom: '4반', accuracy: 81 },
  { unit: '3단원', classroom: '1반', accuracy: 71 },
  { unit: '3단원', classroom: '2반', accuracy: 64 },
  { unit: '3단원', classroom: '3반', accuracy: 58 },
  { unit: '3단원', classroom: '4반', accuracy: 66 },
  { unit: '4단원', classroom: '1반', accuracy: 88 },
  { unit: '4단원', classroom: '2반', accuracy: 79 },
  { unit: '4단원', classroom: '3반', accuracy: 72 },
  { unit: '4단원', classroom: '4반', accuracy: 83 },
  { unit: '5단원', classroom: '1반', accuracy: 95 },
  { unit: '5단원', classroom: '2반', accuracy: 87 },
  { unit: '5단원', classroom: '3반', accuracy: 74 },
  { unit: '5단원', classroom: '4반', accuracy: 90 },
  { unit: '6단원', classroom: '1반', accuracy: 62 },
  { unit: '6단원', classroom: '2반', accuracy: 55 },
  { unit: '6단원', classroom: '3반', accuracy: 51 },
  { unit: '6단원', classroom: '4반', accuracy: 59 },
];

const HeatmapWithValuesExample = () => (
    <Heatmap
      data={accuracyData}
      xKey="unit"
      yKey="classroom"
      valueKey="accuracy"
      showValues
      formatValue={(v) => `${v}%`}
    />
  );

export default HeatmapWithValuesExample;

Hover Tooltip

import { Heatmap } from '@mildang/design-system/Chart';

// 반별 × 단원별 정답률(%)
const accuracyData = [
  { unit: '1단원', classroom: '1반', accuracy: 92 },
  { unit: '1단원', classroom: '2반', accuracy: 85 },
  { unit: '1단원', classroom: '3반', accuracy: 78 },
  { unit: '1단원', classroom: '4반', accuracy: 88 },
  { unit: '2단원', classroom: '1반', accuracy: 84 },
  { unit: '2단원', classroom: '2반', accuracy: 76 },
  { unit: '2단원', classroom: '3반', accuracy: 69 },
  { unit: '2단원', classroom: '4반', accuracy: 81 },
  { unit: '3단원', classroom: '1반', accuracy: 71 },
  { unit: '3단원', classroom: '2반', accuracy: 64 },
  { unit: '3단원', classroom: '3반', accuracy: 58 },
  { unit: '3단원', classroom: '4반', accuracy: 66 },
  { unit: '4단원', classroom: '1반', accuracy: 88 },
  { unit: '4단원', classroom: '2반', accuracy: 79 },
  { unit: '4단원', classroom: '3반', accuracy: 72 },
  { unit: '4단원', classroom: '4반', accuracy: 83 },
  { unit: '5단원', classroom: '1반', accuracy: 95 },
  { unit: '5단원', classroom: '2반', accuracy: 87 },
  { unit: '5단원', classroom: '3반', accuracy: 74 },
  { unit: '5단원', classroom: '4반', accuracy: 90 },
  { unit: '6단원', classroom: '1반', accuracy: 62 },
  { unit: '6단원', classroom: '2반', accuracy: 55 },
  { unit: '6단원', classroom: '3반', accuracy: 51 },
  { unit: '6단원', classroom: '4반', accuracy: 59 },
];

const HeatmapHoverTooltipExample = () => (
    <Heatmap
      data={accuracyData}
      xKey="unit"
      yKey="classroom"
      valueKey="accuracy"
      valueLabel="정답률"
      formatValue={(v) => `${v}%`}
      showTooltip
    />
  );

export default HeatmapHoverTooltipExample;

커스텀 색상·셀 스타일

import { Heatmap } from '@mildang/design-system/Chart';
import { token } from '@mildang/styled-system/tokens';

// 반별 × 단원별 정답률(%)
const accuracyData = [
  { unit: '1단원', classroom: '1반', accuracy: 92 },
  { unit: '1단원', classroom: '2반', accuracy: 85 },
  { unit: '1단원', classroom: '3반', accuracy: 78 },
  { unit: '1단원', classroom: '4반', accuracy: 88 },
  { unit: '2단원', classroom: '1반', accuracy: 84 },
  { unit: '2단원', classroom: '2반', accuracy: 76 },
  { unit: '2단원', classroom: '3반', accuracy: 69 },
  { unit: '2단원', classroom: '4반', accuracy: 81 },
  { unit: '3단원', classroom: '1반', accuracy: 71 },
  { unit: '3단원', classroom: '2반', accuracy: 64 },
  { unit: '3단원', classroom: '3반', accuracy: 58 },
  { unit: '3단원', classroom: '4반', accuracy: 66 },
  { unit: '4단원', classroom: '1반', accuracy: 88 },
  { unit: '4단원', classroom: '2반', accuracy: 79 },
  { unit: '4단원', classroom: '3반', accuracy: 72 },
  { unit: '4단원', classroom: '4반', accuracy: 83 },
  { unit: '5단원', classroom: '1반', accuracy: 95 },
  { unit: '5단원', classroom: '2반', accuracy: 87 },
  { unit: '5단원', classroom: '3반', accuracy: 74 },
  { unit: '5단원', classroom: '4반', accuracy: 90 },
  { unit: '6단원', classroom: '1반', accuracy: 62 },
  { unit: '6단원', classroom: '2반', accuracy: 55 },
  { unit: '6단원', classroom: '3반', accuracy: 51 },
  { unit: '6단원', classroom: '4반', accuracy: 59 },
];

const HeatmapCustomStyleExample = () => (
    <Heatmap
      data={accuracyData}
      xKey="unit"
      yKey="classroom"
      valueKey="accuracy"
      colorRange={[token('colors.orange.light.100'), token('colors.red.light.400')]}
      cellGap={6}
      cellRadius={10}
      showLegend
    />
  );

export default HeatmapCustomStyleExample;

값이 0인 경우

import { Heatmap } from '@mildang/design-system/Chart';

// 학습 시간(분) — 0값 포함 엣지 케이스
const studyTimeData = [
  { day: '월', student: '김민준', minutes: 45 },
  { day: '화', student: '김민준', minutes: 0 },
  { day: '수', student: '김민준', minutes: 62 },
  { day: '월', student: '이서연', minutes: 30 },
  { day: '화', student: '이서연', minutes: 88 },
  { day: '수', student: '이서연', minutes: 0 },
];

const HeatmapWithZeroValuesExample = () => (
    <Heatmap data={studyTimeData} xKey="day" yKey="student" valueKey="minutes" showValues showLegend />
  );

export default HeatmapWithZeroValuesExample;

데이터 1개

import { Heatmap } from '@mildang/design-system/Chart';

const HeatmapSingleDatumExample = () => (
    <Heatmap
      data={[{ unit: '1단원', classroom: '1반', accuracy: 92 }]}
      xKey="unit"
      yKey="classroom"
      valueKey="accuracy"
      showValues
    />
  );

export default HeatmapSingleDatumExample;

빈 데이터

import { Heatmap } from '@mildang/design-system/Chart';

const HeatmapEmptyExample = () => <Heatmap data={[]} xKey="unit" yKey="classroom" valueKey="accuracy" showLegend />;

export default HeatmapEmptyExample;

반응형 (너비 자동 조정)

import { Heatmap } from '@mildang/design-system/Chart';

// 반별 × 단원별 정답률(%)
const accuracyData = [
  { unit: '1단원', classroom: '1반', accuracy: 92 },
  { unit: '1단원', classroom: '2반', accuracy: 85 },
  { unit: '1단원', classroom: '3반', accuracy: 78 },
  { unit: '1단원', classroom: '4반', accuracy: 88 },
  { unit: '2단원', classroom: '1반', accuracy: 84 },
  { unit: '2단원', classroom: '2반', accuracy: 76 },
  { unit: '2단원', classroom: '3반', accuracy: 69 },
  { unit: '2단원', classroom: '4반', accuracy: 81 },
  { unit: '3단원', classroom: '1반', accuracy: 71 },
  { unit: '3단원', classroom: '2반', accuracy: 64 },
  { unit: '3단원', classroom: '3반', accuracy: 58 },
  { unit: '3단원', classroom: '4반', accuracy: 66 },
  { unit: '4단원', classroom: '1반', accuracy: 88 },
  { unit: '4단원', classroom: '2반', accuracy: 79 },
  { unit: '4단원', classroom: '3반', accuracy: 72 },
  { unit: '4단원', classroom: '4반', accuracy: 83 },
  { unit: '5단원', classroom: '1반', accuracy: 95 },
  { unit: '5단원', classroom: '2반', accuracy: 87 },
  { unit: '5단원', classroom: '3반', accuracy: 74 },
  { unit: '5단원', classroom: '4반', accuracy: 90 },
  { unit: '6단원', classroom: '1반', accuracy: 62 },
  { unit: '6단원', classroom: '2반', accuracy: 55 },
  { unit: '6단원', classroom: '3반', accuracy: 51 },
  { unit: '6단원', classroom: '4반', accuracy: 59 },
];

const HeatmapResponsiveExample = () => (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 32, width: '100%' }}>
      {([280, 480, 720] as const).map((w) => (
        <div key={w} style={{ width: w }}>
          <div style={{ marginBottom: 4, fontSize: 11, color: '#888' }}>{w}px</div>
          <div style={{ width: w, height: 240 }}>
            <Heatmap data={accuracyData} xKey="unit" yKey="classroom" valueKey="accuracy" />
          </div>
        </div>
      ))}
    </div>
  );

export default HeatmapResponsiveExample;