@hitachivantara/uikit-react-viz 6.1.6 → 6.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,79 +1,64 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { forwardRef, useMemo } from "react";
3
- import { HeatmapChart } from "echarts/charts";
4
- import { VisualMapComponent, GridComponent, TooltipComponent } from "echarts/components";
5
- import * as echarts from "echarts/core";
1
+ import { HvBaseChart } from "../BaseChart/BaseChart.js";
6
2
  import { getGroupKey } from "../utils/index.js";
7
- import { useClasses } from "./ConfusionMatrix.styles.js";
8
- import { useColorScale, useSeries, useGridLayout } from "./utils.js";
9
- import { useVisualMap } from "../hooks/useVisualMap.js";
10
- import { useData } from "../hooks/useData.js";
11
- import { useTooltip } from "../hooks/tooltip/useTooltip.js";
12
- import { useYAxis } from "../hooks/useYAxis.js";
13
3
  import { useXAxis } from "../hooks/useXAxis.js";
4
+ import { useYAxis } from "../hooks/useYAxis.js";
14
5
  import { useGrid } from "../hooks/useGrid.js";
6
+ import { useData } from "../hooks/useData.js";
7
+ import { useVisualMap } from "../hooks/useVisualMap.js";
8
+ import { useTooltip } from "../hooks/tooltip/useTooltip.js";
15
9
  import { useOption } from "../hooks/useOption.js";
16
- import { HvBaseChart } from "../BaseChart/BaseChart.js";
10
+ import { useClasses } from "./ConfusionMatrix.styles.js";
11
+ import { useColorScale, useGridLayout, useSeries } from "./utils.js";
12
+ import { forwardRef, useMemo } from "react";
13
+ import { GridComponent, TooltipComponent, VisualMapComponent } from "echarts/components";
14
+ import * as echarts from "echarts/core";
15
+ import { jsx } from "react/jsx-runtime";
16
+ import { HeatmapChart } from "echarts/charts";
17
+ //#region src/ConfusionMatrix/ConfusionMatrix.tsx
17
18
  echarts.use([
18
- HeatmapChart,
19
- VisualMapComponent,
20
- GridComponent,
21
- TooltipComponent
19
+ HeatmapChart,
20
+ VisualMapComponent,
21
+ GridComponent,
22
+ TooltipComponent
22
23
  ]);
23
- const HvConfusionMatrix = forwardRef(function HvConfusionMatrix2(props, ref) {
24
- const {
25
- legend,
26
- groupBy,
27
- measure,
28
- sortBy,
29
- splitBy,
30
- filters,
31
- grid,
32
- data: dataProp,
33
- tooltip,
34
- xAxis,
35
- yAxis,
36
- colorScale: colorScaleProp,
37
- delta,
38
- valuesProps,
39
- width,
40
- height,
41
- format = "square",
42
- classes: classesProp,
43
- onOptionChange,
44
- ...others
45
- } = props;
46
- const { classes } = useClasses(classesProp);
47
- const groupByKey = getGroupKey(groupBy);
48
- const { data: chartData } = useData({
49
- data: dataProp,
50
- groupBy,
51
- measures: [measure],
52
- sortBy: sortBy ?? groupBy,
53
- // automatically orders x axis to create the confusion matrix
54
- splitBy,
55
- filters,
56
- delta: typeof delta === "string" ? delta : void 0
57
- });
58
- const colorScale = useColorScale({
59
- delta: !!delta,
60
- data: chartData,
61
- custom: colorScaleProp,
62
- filterKey: groupByKey
63
- });
64
- const chartVisualMap = useVisualMap({
65
- show: colorScale?.pieces != null,
66
- type: colorScale?.pieces != null ? "piecewise" : "continuous",
67
- ...colorScale,
68
- ...legend
69
- });
70
- const chartTooltip = useTooltip({
71
- component: (params) => {
72
- const value = params?.series?.[0].value;
73
- const fmtValue = typeof measure !== "string" && measure.valueFormatter ? measure.valueFormatter(value) : tooltip?.valueFormatter ? tooltip?.valueFormatter(value) : value;
74
- const ftmTitle = tooltip?.titleFormatter ? tooltip.titleFormatter(params?.title) : params?.title;
75
- const content = `${ftmTitle} - ${params?.series?.[0].name}: ${fmtValue}`;
76
- return `
24
+ /**
25
+ * A Confusion Matrix is a table used to evaluate the performance of a predictive model.
26
+ * Rows represent the actual classes, and columns show the predicted classes.
27
+ *
28
+ * - The diagonal cells show correct predictions and off-diagonal cells represent misclassifications.
29
+ *
30
+ */
31
+ var HvConfusionMatrix = forwardRef(function HvConfusionMatrix(props, ref) {
32
+ const { legend, groupBy, measure, sortBy, splitBy, filters, grid, data: dataProp, tooltip, xAxis, yAxis, colorScale: colorScaleProp, delta, valuesProps, width, height, format = "square", classes: classesProp, onOptionChange, ...others } = props;
33
+ const { classes } = useClasses(classesProp);
34
+ const groupByKey = getGroupKey(groupBy);
35
+ const { data: chartData } = useData({
36
+ data: dataProp,
37
+ groupBy,
38
+ measures: [measure],
39
+ sortBy: sortBy ?? groupBy,
40
+ splitBy,
41
+ filters,
42
+ delta: typeof delta === "string" ? delta : void 0
43
+ });
44
+ const colorScale = useColorScale({
45
+ delta: !!delta,
46
+ data: chartData,
47
+ custom: colorScaleProp,
48
+ filterKey: groupByKey
49
+ });
50
+ const chartVisualMap = useVisualMap({
51
+ show: colorScale?.pieces != null,
52
+ type: colorScale?.pieces != null ? "piecewise" : "continuous",
53
+ ...colorScale,
54
+ ...legend
55
+ });
56
+ const chartTooltip = useTooltip({
57
+ component: (params) => {
58
+ const value = params?.series?.[0].value;
59
+ const fmtValue = typeof measure !== "string" && measure.valueFormatter ? measure.valueFormatter(value) : tooltip?.valueFormatter ? tooltip?.valueFormatter(value) : value;
60
+ const content = `${tooltip?.titleFormatter ? tooltip.titleFormatter(params?.title) : params?.title} - ${params?.series?.[0].name}: ${fmtValue}`;
61
+ return `
77
62
  <div class="${classes.tooltipRoot}">
78
63
  <div class="${classes.tooltipContainer}">
79
64
  <div>
@@ -81,84 +66,100 @@ const HvConfusionMatrix = forwardRef(function HvConfusionMatrix2(props, ref) {
81
66
  </div>
82
67
  </div>
83
68
  </div>`;
84
- },
85
- ...tooltip
86
- });
87
- const chartYAxis = useYAxis({
88
- axes: [
89
- {
90
- type: "categorical",
91
- name: "True Label",
92
- position: "left",
93
- ...yAxis,
94
- nameProps: {
95
- location: "center",
96
- padding: yAxis?.nameProps?.location == null || yAxis?.nameProps?.location === "center" ? yAxis?.position === "right" ? [50, 0, 0, 0] : [0, 0, 50, 0] : void 0,
97
- ...yAxis?.nameProps
98
- },
99
- data: chartData.columnNames().filter((p) => p !== groupByKey).toReversed()
100
- }
101
- ]
102
- });
103
- const chartXAxis = useXAxis({
104
- name: "Predicted Value",
105
- position: "top",
106
- ...xAxis,
107
- nameProps: {
108
- location: "center",
109
- padding: xAxis?.nameProps?.location == null || xAxis?.nameProps?.location === "center" ? xAxis?.position === "bottom" ? [30, 0, 0, 0] : [0, 0, 30, 0] : void 0,
110
- ...xAxis?.nameProps
111
- },
112
- data: chartData.array(groupByKey)
113
- });
114
- const chartSeries = useSeries({
115
- data: chartData,
116
- filterKey: groupByKey,
117
- valuesProps,
118
- delta: !!(delta && colorScale == null)
119
- });
120
- const chartGridLayout = useGridLayout({
121
- data: chartData,
122
- format,
123
- filterKey: groupByKey,
124
- visualMapVisible: chartVisualMap.visualMap.show,
125
- visualMapYPosition: chartVisualMap.visualMap.top,
126
- xAxisPosition: chartXAxis.xAxis.position
127
- });
128
- const chartGrid = useGrid({
129
- // If sizes are provided, the grid size should automatically adapt to the values provided
130
- width: width != null ? void 0 : chartGridLayout.size.width,
131
- height: height != null ? void 0 : chartGridLayout.size.height,
132
- ...chartGridLayout.padding,
133
- ...grid
134
- });
135
- const size = useMemo(() => {
136
- return {
137
- width,
138
- // Echarts has a problem were the height is always set to 300px
139
- // Thus, we need to update the height to make sure the chart is not cut out
140
- height: height ?? chartGridLayout.size.height + chartGridLayout.padding.bottom + chartGridLayout.padding.top
141
- };
142
- }, [
143
- chartGridLayout.padding.bottom,
144
- chartGridLayout.padding.top,
145
- chartGridLayout.size.height,
146
- height,
147
- width
148
- ]);
149
- const option = useOption({
150
- option: {
151
- ...chartVisualMap,
152
- ...chartTooltip,
153
- ...chartGrid,
154
- ...chartXAxis,
155
- ...chartYAxis,
156
- ...chartSeries
157
- },
158
- onOptionChange
159
- });
160
- return /* @__PURE__ */ jsx(HvBaseChart, { ref, option, ...size, ...others });
69
+ },
70
+ ...tooltip
71
+ });
72
+ const chartYAxis = useYAxis({ axes: [{
73
+ type: "categorical",
74
+ name: "True Label",
75
+ position: "left",
76
+ ...yAxis,
77
+ nameProps: {
78
+ location: "center",
79
+ padding: yAxis?.nameProps?.location == null || yAxis?.nameProps?.location === "center" ? yAxis?.position === "right" ? [
80
+ 50,
81
+ 0,
82
+ 0,
83
+ 0
84
+ ] : [
85
+ 0,
86
+ 0,
87
+ 50,
88
+ 0
89
+ ] : void 0,
90
+ ...yAxis?.nameProps
91
+ },
92
+ data: chartData.columnNames().filter((p) => p !== groupByKey).toReversed()
93
+ }] });
94
+ const chartXAxis = useXAxis({
95
+ name: "Predicted Value",
96
+ position: "top",
97
+ ...xAxis,
98
+ nameProps: {
99
+ location: "center",
100
+ padding: xAxis?.nameProps?.location == null || xAxis?.nameProps?.location === "center" ? xAxis?.position === "bottom" ? [
101
+ 30,
102
+ 0,
103
+ 0,
104
+ 0
105
+ ] : [
106
+ 0,
107
+ 0,
108
+ 30,
109
+ 0
110
+ ] : void 0,
111
+ ...xAxis?.nameProps
112
+ },
113
+ data: chartData.array(groupByKey)
114
+ });
115
+ const chartSeries = useSeries({
116
+ data: chartData,
117
+ filterKey: groupByKey,
118
+ valuesProps,
119
+ delta: !!(delta && colorScale == null)
120
+ });
121
+ const chartGridLayout = useGridLayout({
122
+ data: chartData,
123
+ format,
124
+ filterKey: groupByKey,
125
+ visualMapVisible: chartVisualMap.visualMap.show,
126
+ visualMapYPosition: chartVisualMap.visualMap.top,
127
+ xAxisPosition: chartXAxis.xAxis.position
128
+ });
129
+ const chartGrid = useGrid({
130
+ width: width != null ? void 0 : chartGridLayout.size.width,
131
+ height: height != null ? void 0 : chartGridLayout.size.height,
132
+ ...chartGridLayout.padding,
133
+ ...grid
134
+ });
135
+ const size = useMemo(() => {
136
+ return {
137
+ width,
138
+ height: height ?? chartGridLayout.size.height + chartGridLayout.padding.bottom + chartGridLayout.padding.top
139
+ };
140
+ }, [
141
+ chartGridLayout.padding.bottom,
142
+ chartGridLayout.padding.top,
143
+ chartGridLayout.size.height,
144
+ height,
145
+ width
146
+ ]);
147
+ return /* @__PURE__ */ jsx(HvBaseChart, {
148
+ ref,
149
+ option: useOption({
150
+ option: {
151
+ ...chartVisualMap,
152
+ ...chartTooltip,
153
+ ...chartGrid,
154
+ ...chartXAxis,
155
+ ...chartYAxis,
156
+ ...chartSeries
157
+ },
158
+ onOptionChange
159
+ }),
160
+ ...size,
161
+ ...others
162
+ });
161
163
  });
162
- export {
163
- HvConfusionMatrix
164
- };
164
+ //#endregion
165
+ export { HvConfusionMatrix };
@@ -1,29 +1,25 @@
1
1
  import { createClasses } from "@hitachivantara/uikit-react-utils";
2
2
  import { theme } from "@hitachivantara/uikit-styles";
3
- const { useClasses, staticClasses } = createClasses(
4
- "HvConfusionMatrix",
5
- {
6
- tooltipRoot: {
7
- backgroundColor: theme.colors.bgContainer,
8
- width: "fit-content",
9
- minWidth: 150,
10
- boxShadow: theme.colors.shadow,
11
- zIndex: theme.zIndices.sticky
12
- },
13
- tooltipContainer: {
14
- padding: theme.spacing("15px", "sm"),
15
- display: "flex",
16
- flexDirection: "column"
17
- },
18
- tooltipText: {
19
- fontFamily: theme.fontFamily.body,
20
- fontWeight: theme.fontWeights.normal,
21
- fontSize: theme.fontSizes.sm,
22
- color: theme.colors.text
23
- }
24
- }
25
- );
26
- export {
27
- staticClasses,
28
- useClasses
29
- };
3
+ //#region src/ConfusionMatrix/ConfusionMatrix.styles.tsx
4
+ var { useClasses, staticClasses } = createClasses("HvConfusionMatrix", {
5
+ tooltipRoot: {
6
+ backgroundColor: theme.colors.bgContainer,
7
+ width: "fit-content",
8
+ minWidth: 150,
9
+ boxShadow: theme.colors.shadow,
10
+ zIndex: theme.zIndices.sticky
11
+ },
12
+ tooltipContainer: {
13
+ padding: theme.spacing("15px", "sm"),
14
+ display: "flex",
15
+ flexDirection: "column"
16
+ },
17
+ tooltipText: {
18
+ fontFamily: theme.fontFamily.body,
19
+ fontWeight: theme.fontWeights.normal,
20
+ fontSize: theme.fontSizes.sm,
21
+ color: theme.colors.text
22
+ }
23
+ });
24
+ //#endregion
25
+ export { useClasses };
@@ -1,142 +1,109 @@
1
- import { useMemo, useCallback } from "react";
1
+ import { useCallback, useMemo } from "react";
2
2
  import { useTheme } from "@hitachivantara/uikit-react-utils";
3
- const useColorScale = ({
4
- data,
5
- delta,
6
- custom,
7
- filterKey
8
- }) => {
9
- const { colors } = useTheme();
10
- const colorScale = useMemo(() => {
11
- if (custom == null && delta) {
12
- return;
13
- }
14
- if (custom && typeof custom[0] === "object") {
15
- return {
16
- pieces: custom.reduce((acc, curr) => {
17
- acc.push({
18
- ...curr,
19
- color: colors?.[curr.color] || curr.color
20
- });
21
- return acc;
22
- }, [])
23
- };
24
- }
25
- const flatData = data.columnNames().filter((p) => p !== filterKey).reduce((acc, c) => {
26
- acc.push(...data.array(c));
27
- return acc;
28
- }, []);
29
- const max = Math.max(...flatData);
30
- const min = Math.min(...flatData);
31
- const parsedColors = custom?.map(
32
- (c) => typeof c === "string" ? colors?.[c] || c : c.color
33
- );
34
- return {
35
- colorScale: parsedColors || [colors?.textLight || "", colors?.cat3 || ""],
36
- max,
37
- min
38
- };
39
- }, [colors, custom, data, filterKey, delta]);
40
- return colorScale;
3
+ //#region src/ConfusionMatrix/utils.ts
4
+ var useColorScale = ({ data, delta, custom, filterKey }) => {
5
+ const { colors } = useTheme();
6
+ return useMemo(() => {
7
+ if (custom == null && delta) return;
8
+ if (custom && typeof custom[0] === "object") return { pieces: custom.reduce((acc, curr) => {
9
+ acc.push({
10
+ ...curr,
11
+ color: colors?.[curr.color] || curr.color
12
+ });
13
+ return acc;
14
+ }, []) };
15
+ const flatData = data.columnNames().filter((p) => p !== filterKey).reduce((acc, c) => {
16
+ acc.push(...data.array(c));
17
+ return acc;
18
+ }, []);
19
+ const max = Math.max(...flatData);
20
+ const min = Math.min(...flatData);
21
+ return {
22
+ colorScale: custom?.map((c) => typeof c === "string" ? colors?.[c] || c : c.color) || [colors?.textLight || "", colors?.cat3 || ""],
23
+ max,
24
+ min
25
+ };
26
+ }, [
27
+ colors,
28
+ custom,
29
+ data,
30
+ filterKey,
31
+ delta
32
+ ]);
41
33
  };
42
- const useSeries = ({
43
- data,
44
- filterKey,
45
- delta,
46
- valuesProps
47
- }) => {
48
- const { colors } = useTheme();
49
- const getDeltaColor = useCallback(
50
- (value, diagonal) => {
51
- if (diagonal && value > 0 || !diagonal && value < 0) {
52
- return colors?.positive;
53
- }
54
- if (diagonal && value < 0 || !diagonal && value > 0) {
55
- return colors?.negative;
56
- }
57
- return colors?.textLight;
58
- },
59
- [colors]
60
- );
61
- const chartSeries = useMemo(() => {
62
- return {
63
- series: {
64
- id: `series~${filterKey}`,
65
- type: "heatmap",
66
- label: {
67
- show: true,
68
- ...valuesProps,
69
- ...valuesProps?.color && {
70
- color: colors?.[valuesProps.color] || valuesProps.color
71
- }
72
- },
73
- emphasis: {
74
- disabled: true
75
- },
76
- data: data.columnNames().filter((p) => p !== filterKey).reduce((acc, c, j) => {
77
- const row = data.array(c).reduce((racc, rv, i) => {
78
- racc.push({
79
- value: [data.array(filterKey)[i], c, rv != null ? rv : "-"],
80
- ...delta && {
81
- visualMap: false,
82
- itemStyle: {
83
- color: getDeltaColor(rv, i === j)
84
- }
85
- }
86
- });
87
- return racc;
88
- }, []);
89
- acc.push(...row);
90
- return acc;
91
- }, [])
92
- }
93
- };
94
- }, [colors, data, delta, filterKey, getDeltaColor, valuesProps]);
95
- return chartSeries;
34
+ var useSeries = ({ data, filterKey, delta, valuesProps }) => {
35
+ const { colors } = useTheme();
36
+ const getDeltaColor = useCallback((value, diagonal) => {
37
+ if (diagonal && value > 0 || !diagonal && value < 0) return colors?.positive;
38
+ if (diagonal && value < 0 || !diagonal && value > 0) return colors?.negative;
39
+ return colors?.textLight;
40
+ }, [colors]);
41
+ return useMemo(() => {
42
+ return { series: {
43
+ id: `series~${filterKey}`,
44
+ type: "heatmap",
45
+ label: {
46
+ show: true,
47
+ ...valuesProps,
48
+ ...valuesProps?.color && { color: colors?.[valuesProps.color] || valuesProps.color }
49
+ },
50
+ emphasis: { disabled: true },
51
+ data: data.columnNames().filter((p) => p !== filterKey).reduce((acc, c, j) => {
52
+ const row = data.array(c).reduce((racc, rv, i) => {
53
+ racc.push({
54
+ value: [
55
+ data.array(filterKey)[i],
56
+ c,
57
+ rv != null ? rv : "-"
58
+ ],
59
+ ...delta && {
60
+ visualMap: false,
61
+ itemStyle: { color: getDeltaColor(rv, i === j) }
62
+ }
63
+ });
64
+ return racc;
65
+ }, []);
66
+ acc.push(...row);
67
+ return acc;
68
+ }, [])
69
+ } };
70
+ }, [
71
+ colors,
72
+ data,
73
+ delta,
74
+ filterKey,
75
+ getDeltaColor,
76
+ valuesProps
77
+ ]);
96
78
  };
97
- const SQUARE_SIZE = 52;
98
- const useGridLayout = ({
99
- data,
100
- filterKey,
101
- format,
102
- xAxisPosition,
103
- visualMapVisible,
104
- visualMapYPosition
105
- }) => {
106
- const size = useMemo(() => {
107
- const nCols = data.array(filterKey).length;
108
- const nRows = data.columnNames().filter((p) => p !== filterKey).length;
109
- const itemHeight = format === "square" ? SQUARE_SIZE : SQUARE_SIZE / 2;
110
- return {
111
- padding: {
112
- bottom: xAxisPosition === "bottom" || visualMapVisible && visualMapYPosition === "bottom" ? 60 : 20,
113
- top: xAxisPosition === "top" || visualMapVisible && visualMapYPosition === "top" ? 60 : 20,
114
- ...visualMapVisible && visualMapYPosition === "bottom" && xAxisPosition === "bottom" && {
115
- bottom: 100
116
- },
117
- ...visualMapVisible && visualMapYPosition === "top" && xAxisPosition === "top" && {
118
- top: 100
119
- },
120
- left: 80,
121
- right: 80
122
- },
123
- size: {
124
- height: Math.max(itemHeight * nRows, itemHeight * 8),
125
- width: Math.max(SQUARE_SIZE * nCols, SQUARE_SIZE * 8)
126
- }
127
- };
128
- }, [
129
- data,
130
- filterKey,
131
- format,
132
- visualMapVisible,
133
- visualMapYPosition,
134
- xAxisPosition
135
- ]);
136
- return size;
137
- };
138
- export {
139
- useColorScale,
140
- useGridLayout,
141
- useSeries
79
+ var SQUARE_SIZE = 52;
80
+ var useGridLayout = ({ data, filterKey, format, xAxisPosition, visualMapVisible, visualMapYPosition }) => {
81
+ return useMemo(() => {
82
+ const nCols = data.array(filterKey).length;
83
+ const nRows = data.columnNames().filter((p) => p !== filterKey).length;
84
+ const itemHeight = format === "square" ? SQUARE_SIZE : SQUARE_SIZE / 2;
85
+ return {
86
+ padding: {
87
+ bottom: xAxisPosition === "bottom" || visualMapVisible && visualMapYPosition === "bottom" ? 60 : 20,
88
+ top: xAxisPosition === "top" || visualMapVisible && visualMapYPosition === "top" ? 60 : 20,
89
+ ...visualMapVisible && visualMapYPosition === "bottom" && xAxisPosition === "bottom" && { bottom: 100 },
90
+ ...visualMapVisible && visualMapYPosition === "top" && xAxisPosition === "top" && { top: 100 },
91
+ left: 80,
92
+ right: 80
93
+ },
94
+ size: {
95
+ height: Math.max(itemHeight * nRows, itemHeight * 8),
96
+ width: Math.max(SQUARE_SIZE * nCols, SQUARE_SIZE * 8)
97
+ }
98
+ };
99
+ }, [
100
+ data,
101
+ filterKey,
102
+ format,
103
+ visualMapVisible,
104
+ visualMapYPosition,
105
+ xAxisPosition
106
+ ]);
142
107
  };
108
+ //#endregion
109
+ export { useColorScale, useGridLayout, useSeries };