ScatterChart
두 변수의 상관관계를 점으로 시각화하는 차트 컨테이너.
개요
ScatterChart는 recharts의 ScatterChart를 얇게 래핑한 컨테이너입니다. XAxis, YAxis를 모두 type="number"로 사용해 데이터 포인트의 분포를 표현합니다.
Scatter시리즈가fill,stroke,data,activeShape,label$토큰 지원ZAxis조합 — 세 번째 차원(버블 크기) 표현으로 버블 차트 구성
언제 사용하나요
- 두 변수의 상관관계 — 팔로워 수 vs 참여율
- 군집 시각화 — 여러 그룹의 분포 비교
- 이상치 탐지 — 분포에서 벗어난 포인트 식별
- 버블 차트 —
ZAxis로 세 번째 지표 추가
Usage
기본 사용법
() => { const data = [ { followers: 12000, engagement: 4.2 }, { followers: 35000, engagement: 3.1 }, { followers: 8000, engagement: 6.8 }, { followers: 120000, engagement: 1.9 }, { followers: 50000, engagement: 2.7 }, { followers: 6000, engagement: 8.5 }, { followers: 200000, engagement: 1.2 }, { followers: 25000, engagement: 4.9 }, ]; return ( <ResponsiveContainer width="100%" height={300}> <ScatterChart margin={{ top: 20, right: 20, bottom: 20, left: 20 }}> <CartesianGrid /> <XAxis dataKey="followers" name="팔로워 수" tickFormatter={(v) => (v / 1000).toFixed(0) + 'K'} /> <YAxis dataKey="engagement" name="참여율" unit="%" /> <Scatter name="인플루언서" data={data} fill="$primary-50" /> <ChartTooltip cursor={{ strokeDasharray: '3 3' }} /> </ScatterChart> </ResponsiveContainer> ); }
버블 차트 (ZAxis)
ZAxis는 re-export된 recharts 컴포넌트입니다. 데이터 포인트의 크기를 세 번째 차원으로 매핑합니다.
() => { const data = [ { followers: 12000, engagement: 4.2, reach: 8500 }, { followers: 35000, engagement: 3.1, reach: 22000 }, { followers: 8000, engagement: 6.8, reach: 5500 }, { followers: 120000, engagement: 1.9, reach: 80000 }, { followers: 50000, engagement: 2.7, reach: 33000 }, ]; return ( <ResponsiveContainer width="100%" height={300}> <ScatterChart margin={{ top: 20, right: 20, bottom: 20, left: 20 }}> <CartesianGrid /> <XAxis dataKey="followers" name="팔로워" tickFormatter={(v) => (v / 1000).toFixed(0) + 'K'} /> <YAxis dataKey="engagement" name="참여율" unit="%" /> <ZAxis dataKey="reach" range={[60, 400]} name="도달" /> <Scatter name="인플루언서" data={data} fill="$primary-50" fillOpacity={0.6} /> <ChartTooltip cursor={{ strokeDasharray: '3 3' }} /> </ScatterChart> </ResponsiveContainer> ); }
다중 그룹
여러 Scatter를 사용해 그룹을 비교합니다.
() => { const groupA = [ { x: 10, y: 5 }, { x: 30, y: 3 }, { x: 70, y: 2 }, { x: 5, y: 7 }, ]; const groupB = [ { x: 18, y: 4 }, { x: 45, y: 2 }, { x: 90, y: 1.5 }, { x: 7, y: 6 }, ]; return ( <ResponsiveContainer width="100%" height={300}> <ScatterChart margin={{ top: 20, right: 20, bottom: 20, left: 20 }}> <CartesianGrid /> <XAxis dataKey="x" type="number" name="X" /> <YAxis dataKey="y" type="number" name="Y" /> <Scatter name="그룹 A" data={groupA} fill="$primary-50" /> <Scatter name="그룹 B" data={groupB} fill="$teal-50" /> <ChartTooltip cursor={{ strokeDasharray: '3 3' }} /> <ChartLegend /> </ScatterChart> </ResponsiveContainer> ); }
$ 토큰 fill
Scatter.fill에 $primary-50, $teal-50 등 토큰을 직접 전달합니다.
() => { const data = [ { followers: 12000, engagement: 4.2 }, { followers: 35000, engagement: 3.1 }, { followers: 8000, engagement: 6.8 }, { followers: 120000, engagement: 1.9 }, { followers: 50000, engagement: 2.7 }, ]; return ( <VStack $css={{ width: '100%', gap: '$spacing-400' }}> <ResponsiveContainer width="100%" height={200}> <ScatterChart margin={{ top: 10, right: 20, bottom: 20, left: 20 }}> <CartesianGrid /> <XAxis dataKey="followers" name="팔로워" tickFormatter={(v) => (v / 1000).toFixed(0) + 'K'} /> <YAxis dataKey="engagement" name="참여율" unit="%" /> <Scatter name="인플루언서" data={data} fill="$primary-50" /> <ChartTooltip /> </ScatterChart> </ResponsiveContainer> <ResponsiveContainer width="100%" height={200}> <ScatterChart margin={{ top: 10, right: 20, bottom: 20, left: 20 }}> <CartesianGrid /> <XAxis dataKey="followers" name="팔로워" tickFormatter={(v) => (v / 1000).toFixed(0) + 'K'} /> <YAxis dataKey="engagement" name="참여율" unit="%" /> <Scatter name="인플루언서" data={data} fill="$teal-50" /> <ChartTooltip /> </ScatterChart> </ResponsiveContainer> </VStack> ); }
Slot 토큰 — activeShape / label
activeShape는 호버 상태 포인트, label은 포인트 라벨. 오브젝트일 때 $ 토큰 해석. label 오브젝트에는 fontSize-200 / font.sans / $text-2 기본 typography가 자동 병합되며, 소비자 명시값이 우선합니다.
() => { const data = [ { followers: 12000, engagement: 4.2 }, { followers: 35000, engagement: 3.1 }, { followers: 8000, engagement: 6.8 }, { followers: 120000, engagement: 1.9 }, { followers: 50000, engagement: 2.7 }, ]; return ( <ResponsiveContainer width="100%" height={280}> <ScatterChart margin={{ top: 20, right: 20, bottom: 20, left: 20 }}> <CartesianGrid /> <XAxis dataKey="followers" name="팔로워" tickFormatter={(v) => (v / 1000).toFixed(0) + 'K'} /> <YAxis dataKey="engagement" name="참여율" unit="%" /> <Scatter name="인플루언서" data={data} fill="$primary-50" activeShape={{ fill: '$teal-40', stroke: '$primary-60' }} label={{ fill: '$text-2', fontSize: 10 }} /> <ChartTooltip cursor={{ strokeDasharray: '3 3' }} /> </ScatterChart> </ResponsiveContainer> ); }
4분면 분석 — ReferenceLine으로 분할
ReferenceLine을 도메인 중앙에 그어 포지셔닝 맵을 만듭니다. 도메인을 데이터 기반으로 정렬해 사분면이 항상 균등 면적을 갖도록 하세요.
() => { const brands = [ { brand: 'A', content: 42, views: 88000, fill: '$indigo-50' }, { brand: 'B', content: 130, views: 360000, fill: '$magenta-50' }, { brand: 'C', content: 165, views: 130000, fill: '$orange-50' }, { brand: 'D', content: 180, views: 290000, fill: '$green-60' }, { brand: 'E', content: 88, views: 95000, fill: '$red-50' }, { brand: 'F', content: 72, views: 410000, fill: '$teal-50' }, ]; const xMax = Math.ceil(Math.max(...brands.map((b) => b.content)) / 200) * 200; const yMax = Math.ceil(Math.max(...brands.map((b) => b.views)) / 500000) * 500000; const xMid = xMax / 2; const yMid = yMax / 2; return ( <ResponsiveContainer width="100%" height={360}> <ScatterChart margin={{ top: 20, right: 30, bottom: 30, left: 50 }}> <CartesianGrid strokeDasharray="3 3" /> <XAxis type="number" dataKey="content" name="콘텐츠 건수" domain={[0, xMax]} /> <YAxis type="number" dataKey="views" name="평균 재생수" domain={[0, yMax]} tickFormatter={(v) => v === 0 ? '0' : (v / 10000).toFixed(0) + '만'} /> <ReferenceLine x={xMid} stroke="$secondary-60" /> <ReferenceLine y={yMid} stroke="$secondary-60" /> {brands.map((b) => ( <Scatter key={b.brand} name={b.brand} data={[b]} fill={b.fill}> <LabelList dataKey="brand" position="bottom" fontSize={11} fill={b.fill} /> </Scatter> ))} <ChartTooltip cursor={{ strokeDasharray: '3 3' }} /> </ScatterChart> </ResponsiveContainer> ); }
인터랙티브 — 선택 가능한 커스텀 shape
Scatter.shape로 점 모양을 커스텀하면 선택 상태에 따라 강조 효과를 줄 수 있습니다. resolveToken은 $토큰 문자열을 <circle fill>처럼 SVG 속성에 직접 넣어야 할 때 사용합니다.
() => { const brands = [ { brand: 'COSRX', content: 42, views: 88000, fill: '$indigo-50' }, { brand: 'Torriden', content: 130, views: 360000, fill: '$magenta-50' }, { brand: 'Anua', content: 165, views: 130000, fill: '$orange-50' }, { brand: 'mixsoon', content: 180, views: 290000, fill: '$green-60' }, { brand: 'Round Lab', content: 105, views: 245000, fill: '$primary-60' }, ]; const [selected, setSelected] = React.useState('Round Lab'); return ( <ResponsiveContainer width="100%" height={320}> <ScatterChart margin={{ top: 20, right: 30, bottom: 30, left: 50 }}> <CartesianGrid strokeDasharray="3 3" /> <XAxis type="number" dataKey="content" name="콘텐츠 건수" /> <YAxis type="number" dataKey="views" name="평균 재생수" tickFormatter={(v) => (v / 10000).toFixed(0) + '만'} /> {brands.map((b) => { const isSelected = b.brand === selected; const resolved = resolveToken(b.fill); return ( <Scatter key={b.brand} name={b.brand} data={[b]} fill={b.fill} isAnimationActive={false} onClick={() => setSelected(b.brand)} shape={(props) => { const { cx = 0, cy = 0 } = props; if (isSelected) { return ( <g style={{ cursor: 'pointer' }}> <circle cx={cx} cy={cy} r={14} fill={resolved} fillOpacity={0.25} /> <circle cx={cx} cy={cy} r={8} fill={resolved} /> </g> ); } return <circle cx={cx} cy={cy} r={5} fill={resolved} style={{ cursor: 'pointer' }} />; }} > <LabelList dataKey="brand" position="bottom" offset={isSelected ? 14 : 6} fontSize={isSelected ? 13 : 11} fontWeight={isSelected ? 700 : 400} fill={b.fill} /> </Scatter> ); })} <ChartTooltip cursor={{ strokeDasharray: '3 3' }} formatter={(v, name) => name === '평균 재생수' ? [(Number(v) / 10000).toFixed(1) + '만', name] : [v, name]} /> </ScatterChart> </ResponsiveContainer> ); }
Props
recharts ScatterChart를 래핑합니다. 여기에 명시되지 않은 props는 recharts ScatterChart API를 참고하세요.
ScatterChart
extends recharts ScatterChart
Prop
Type
Scatter
extends recharts Scatter
Prop
Type
ZAxis
recharts re-export. 래핑되지 않음.
Prop
Type