6. 시각 분석 — 히트맵과 데이터바
집계가 끝난 raw 숫자의 크기를 색과 막대로 표시합니다. 시각화를 켜도 getPivotData, footer, detail의 값과 원본은 바뀌지 않습니다. 숫자 표시 문자열을 다시 숫자로 해석하지 않습니다.
6.1 기존 히트맵과 Value별 설정
기존 useHeatmap, setHeatmapColors, changeHeatmapColors 동작은 그대로입니다. 신규 setVisualAnalytics는 Value별로 heatmap/dataBar를 설정합니다. dataField+operation이 실제 Value와 맞아야 적용되며 아직 배치하지 않은 Value 선언도 보관할 수 있습니다.
// 먼저 값 차원에 매출과 계산된 이익을 배치합니다.
AUIPivot.setValueFields(pid, [
{dataField: "TOTAL", operation: "SUM", formatString: "#,##0"},
{dataField: "PROFIT", operation: "SUM", formatString: "#,##0"}
]);
// PROFIT은 source 필드 또는 setDerivedFields로 등록한 계산필드여야 합니다.
AUIPivot.setVisualAnalytics(pid, [
{dataField: "TOTAL", operation: "SUM", heatmap: {scope: "ROW"}},
{dataField: "PROFIT", operation: "SUM", dataBar: {scope: "COLUMN"}}
]);
AUIPivot.updatePivot(pid);
setVisualAnalytics는 선언을 저장하고 updatePivot/setGridData에서 반영합니다. []로 해제합니다. 명시한 heatmap 또는 false만 해당 Value의 기존 히트맵을 대체하며 dataBar만 지정하면 기존 히트맵과 함께 표시할 수 있습니다.
2.8.0부터 집계 후 수식에는 표시명 대신 수식 정의의 ID와 calculation을 지정합니다. 일반 집계와 사용자 집계는 기존 operation을 유지합니다. 수식에도 GLOBAL, ROW, COLUMN과 요약 행, 요약 칼럼, 푸터 옵션이 동일하게 적용됩니다. 오류와 원본 없는 셀은 제외합니다.
// 등록한 Rate 수식에 히트맵과 데이터바를 함께 표시합니다.
AUIPivot.setVisualAnalytics(pid, [{
dataField: "Rate", calculation: {kind: "formula"},
heatmap: {scope: "ROW"}, dataBar: {scope: "COLUMN"},
summaryColumns: true, summaryRows: true, footer: true
}]);
AUIPivot.updatePivot(pid);
기존 히트맵도 Value별 범위를 사용하지만, 집계 과정에서 수집한 범위와 기존 소계 표시 규칙을 유지합니다. 일부 RATIO/ROW_RATIO 범위는 비율 변환 전 합계에 기반합니다. 아래의 새 GLOBAL은 완성된 숫자와 말단 셀 기준을 명시적으로 선택하는 설정이므로 과거 히트맵과 색상이 항상 같은 것은 아닙니다.
6.2 GLOBAL, ROW, COLUMN
| scope | 비교 집합 |
|---|---|
| GLOBAL (기본) | 같은 Value의 전체 논리 말단 셀 |
| ROW | 같은 논리 말단 행 안에서 같은 Value의 열들 |
| COLUMN | 같은 최종 논리 말단 열 안에서 같은 Value의 행들 |
히트맵은 (value−min)/(max−min)으로 정규화합니다. 서울 10, 20, 30, 부산 1000, 2000, 3000이면 ROW에서 두 행 모두 0, 0.5, 1 패턴입니다. GLOBAL은 절대 크기를 비교하므로 같은 색이 아닙니다.
dataField+operation별 범위를 분리하므로 매출과 비율이 섞이지 않습니다. Value first/last, 다단계 연도/월, 정렬, 접기/펼치기와 무관하게 논리 Pivot 범위를 사용합니다. COLUMN은 2025/1월과 2026/1월을 서로 다른 말단 열로 비교합니다.
null, undefined, 빈 문자열, NaN, Infinity는 제외하고 실제 숫자 0은 포함합니다. sparse 공백은 자동으로 0이 되지 않습니다. min=max인 히트맵은 최대 강도를 사용하며 NaN 스타일을 만들지 않습니다.
6.3 데이터바와 0축
min0=min(0,min), max0=max(0,max)로 범위를 확장합니다. 0축 위치는 (0−min0)/(max0−min0), 값 위치는 (value−min0)/(max0−min0)입니다. 두 위치 사이를 막대로 표시합니다.
- 모두 양수: 축은 왼쪽, 큰 양수일수록 길어집니다.
- 모두 음수: 축은 오른쪽, 절댓값이 큰 음수일수록 왼쪽으로 길어집니다.
- 양음수 혼합: 0축을 중심으로 음수는 왼쪽, 양수는 오른쪽입니다.
- 모두 0: 길이 0. 동일한 양수/음수: 동일 길이. 표시 계산의 범위가 0이어도 NaN/Infinity CSS를 만들지 않습니다.
-100, -50, 0, 50, 100이면 축은 50%이며 양끝 값은 셀 너비의 절반씩 차지합니다. 색은 기본 양수 #4374D9, 음수 #C85050, 불투명도 28%입니다. 35.2%는 raw 0.352로 비교하며 formatter는 기존 문자열을 유지합니다.
6.4 요약 칼럼, 요약 행, 푸터를 선택적으로 켜기
// 일반 셀은 행별, 합계는 별도 집합에서 비교합니다.
AUIPivot.setVisualAnalytics(pid, [{
dataField: "TOTAL", operation: "SUM",
heatmap: {scope: "ROW"}, dataBar: {scope: "COLUMN"},
summaryColumns: true, summaryRows: true, footer: true
}]);
AUIPivot.updatePivot(pid);
세 옵션은 값 필드별로 지정하며 기본값은 false입니다. 요약 칼럼은 같은 칼럼의 일반 행끼리, 요약 행은 같은 행의 같은 값 필드끼리 비교합니다. 요약 행과 요약 칼럼이 만나는 셀은 두 옵션을 모두 켜야 표시됩니다.
요약 행과 푸터에서는 월별 합계, 연도별 합계처럼 열의 집계 수준을 나누어 비교합니다. 일반 셀의 scope와 별개이며 일반 값과 합계를 섞지 않습니다. 푸터의 전체 총계 한 셀은 제외합니다.
접힌 연도의 요약 칼럼도 설정에 따라 시각화됩니다. 세 옵션은 해당 heatmap/dataBar에 함께 적용하며 합계만 켜는 독립 시각화 모드는 아닙니다.
6.5 색상, formatter, 스타일 충돌
heatmap은 defaultHeatmapColors를 사용하며 colors에 2~16개의 #RRGGBB를 지정할 수 있습니다. dataBar는 color, negativeColor를 지정합니다. CSS 배경색 위에 막대를 함께 표시할 수 있고 숫자 텍스트, 셀 크기, 접근성 값은 유지합니다.
명시적인 사용자 열 style, 비어 있지 않은 셀 styleFunction 또는 우선 행 스타일이 있으면 새 시각화를 적용하지 않습니다. 사용자 배경을 덮어쓰지 않습니다. 추가 formatter 호출이나 셀별 추가 DOM 없이 표현하며 raw 집계값은 양자화하지 않습니다.
필터, source, 축, Value, 파생 정의 변경과 rebuild에서 범위를 재생성합니다. 정렬은 값 범위를 바꾸지 않고 collapse는 전체 논리 범위를 유지합니다. 가상 스크롤에서 셀을 재사용할 때 이전 스타일을 해제합니다.
6.6 저장, 내보내기와 실행 예제
시각화는 화면 전용입니다. CSV/XLSX/PDF의 색상, 막대, Excel 조건부 서식 저장은 제공하지 않습니다. 숫자, 서식은 기존 export 경로를 따릅니다. 시각화 선언은 Report Definition에 포함되지 않으므로 별도로 저장하세요.
// 보고서 정의와 화면 시각화 선언을 별도의 JSON 값으로 저장합니다.
const saved = JSON.stringify({
report: AUIPivot.getReportDefinition(pid),
visuals: AUIPivot.getVisualAnalytics(pid)
});
// 사용자 집계가 있다면 대상 인스턴스에 먼저 등록한 뒤 복원합니다.
const restored = JSON.parse(saved);
AUIPivot.setReportDefinition(otherPid, restored.report);
AUIPivot.setVisualAnalytics(otherPid, restored.visuals);
AUIPivot.updatePivot(otherPid);
자동차 매출, 이익 시각 분석, setVisualAnalytics, getVisualAnalytics, 기존 useHeatmap