diff --git a/ui/src/container/models/Details/charts/confusion-matrix-chart/index.jsx b/ui/src/components/charts/confusion-matrix-chart/index.jsx similarity index 100% rename from ui/src/container/models/Details/charts/confusion-matrix-chart/index.jsx rename to ui/src/components/charts/confusion-matrix-chart/index.jsx diff --git a/ui/src/components/charts/confusion-matrix-chart/options.js b/ui/src/components/charts/confusion-matrix-chart/options.js new file mode 100644 index 00000000..ff22373d --- /dev/null +++ b/ui/src/components/charts/confusion-matrix-chart/options.js @@ -0,0 +1,24 @@ +import * as commonChartOptions from '@Helpers/common-chart-options'; + +export default function confusionMatrixOptions(dataset, labelClass, colors) { + let dataMax = 0; + const heatmapData = dataset.toReversed().reduce((accumulator, datas, yIndex) => accumulator.concat(datas.map((data, xIndex) => { + if (data > dataMax) { + dataMax = data; + } + return [xIndex, yIndex, data]; + })), []); + + const options = { + ...commonChartOptions.yAxisOptions.categoryType(labelClass.yAxisLabel), + ...commonChartOptions.xAxisOptions.categoryType(labelClass.xAxisLabel), + ...commonChartOptions.gridOptions.heatmapChart(), + ...commonChartOptions.commonOptions.heatmapChart(), + ...commonChartOptions.visualMapOptions.heatmapChart(dataMax, colors), + series: { + ...commonChartOptions.seriesOptions.heatmapChart(heatmapData), + }, + }; + + return options; +} diff --git a/ui/src/container/models/Details/charts/line-chart/index.jsx b/ui/src/components/charts/line-chart/index.jsx similarity index 100% rename from ui/src/container/models/Details/charts/line-chart/index.jsx rename to ui/src/components/charts/line-chart/index.jsx diff --git a/ui/src/components/charts/line-chart/options.js b/ui/src/components/charts/line-chart/options.js new file mode 100644 index 00000000..ab80f0cc --- /dev/null +++ b/ui/src/components/charts/line-chart/options.js @@ -0,0 +1,37 @@ +import { numberFormatter } from '@Src/constants'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; +import * as commonChartOptions from '@Helpers/common-chart-options'; + +export default function lineChartOptions(title, color, currentDataset, referenceDataset) { + const currentDatasetFormatted = currentDataset.map(({ timestamp, value }) => [timestamp, numberFormatter().format(value)]); + + const series = [ + commonChartOptions.seriesOptions.lineChart(title, CHART_COLOR.LINE_CHART_COLOR, currentDatasetFormatted), + ]; + + if (referenceDataset) { + const referenceDatasetFormatted = referenceDataset.map(({ timestamp, value }) => [timestamp, numberFormatter().format(value)]); + + const referenceLine = { + ...commonChartOptions.seriesOptions.lineChart('Reference', CHART_COLOR.REFERENCE, referenceDatasetFormatted), + endLabel: { + show: true, + color: CHART_COLOR.REFERENCE, + formatter: ({ value }) => `Reference\n${value[1]}`, + }, + color: CHART_COLOR.REFERENCE, + }; + + referenceLine.lineStyle.type = 'dotted'; + series.push(referenceLine); + } + + return { + color: [color], + ...commonChartOptions.tooltipOptions(), + ...commonChartOptions.yAxisOptions.valueType(), + ...commonChartOptions.xAxisOptions.timeType(), + ...commonChartOptions.gridOptions.lineChart(), + series, + }; +} diff --git a/ui/src/container/models/Details/binary-classification/current/data-drift/use-get-filtered-features.js b/ui/src/container/models/Details/binary-classification/current/data-drift/use-get-filtered-features.js index e8d92f1e..e353fac4 100644 --- a/ui/src/container/models/Details/binary-classification/current/data-drift/use-get-filtered-features.js +++ b/ui/src/container/models/Details/binary-classification/current/data-drift/use-get-filtered-features.js @@ -28,8 +28,6 @@ export default () => { const isNumerical = isNumericalSelected && type === DRIFT_TEST_ENUM.KS; const isCategorical = isCategoricalSelected && type === DRIFT_TEST_ENUM.CHI2; - console.debug(type, isNumerical, isCategorical); - return isNumerical || isCategorical; }); }; diff --git a/ui/src/container/models/Details/binary-classification/current/data-quality/data-point-distribution/options.js b/ui/src/container/models/Details/binary-classification/current/data-quality/data-point-distribution/options.js new file mode 100644 index 00000000..eacede83 --- /dev/null +++ b/ui/src/container/models/Details/binary-classification/current/data-quality/data-point-distribution/options.js @@ -0,0 +1,42 @@ +import { CHART_COLOR } from '@Helpers/common-chart-options'; +import { numberFormatter } from '@Src/constants'; +import * as commonChartOptions from '@Helpers/common-chart-options'; + +export default function chartOptions(title, referenceDataset, currentDataset) { + const yAxisLabel = currentDataset.map(({ name }) => name); + + const referenceData = referenceDataset.map(({ count, percentage }) => ({ percentage, count, value: count })); + const currentData = currentDataset.map(({ count, percentage }) => ({ percentage, count, value: count })); + + const options = { + ...commonChartOptions.gridOptions.barChart(), + ...commonChartOptions.xAxisOptions.valueType(), + ...commonChartOptions.yAxisOptions.categoryType(yAxisLabel), + ...commonChartOptions.commonOptions.barChart(), + series: [ + { + ...commonChartOptions.seriesOptions.barChart(title, CHART_COLOR.REFERENCE_LIGHT, referenceData), + color: CHART_COLOR.REFERENCE_LIGHT, + label: { + show: true, + position: 'insideRight', + fontWeight: 'bold', + formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', + }, + }, + { + ...commonChartOptions.seriesOptions.barChart(title, CHART_COLOR.CURRENT_LIGHT_LIGHT, currentData), + color: CHART_COLOR.CURRENT_LIGHT, + label: { + show: true, + position: 'insideRight', + fontWeight: 'bold', + color: CHART_COLOR.CURRENT_DARK, + formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', + }, + }, + ], + }; + + return options; +} diff --git a/ui/src/container/models/Details/binary-classification/current/data-quality/data-point-distribution/options.jsx b/ui/src/container/models/Details/binary-classification/current/data-quality/data-point-distribution/options.jsx deleted file mode 100644 index 5148b9c0..00000000 --- a/ui/src/container/models/Details/binary-classification/current/data-quality/data-point-distribution/options.jsx +++ /dev/null @@ -1,71 +0,0 @@ -import { CHART_COLOR } from '@Container/models/Details/constants'; -import { numberFormatter } from '@Src/constants'; - -export default function chartOptions(title, referenceDataset, currentDataset) { - const yAxisLabel = currentDataset.map(({ name }) => name); - - return { - grid: { - left: 0, - right: 20, - bottom: 0, - top: 0, - containLabel: true, - }, - xAxis: { - type: 'value', - boundaryGap: true, - axisLabel: { - fontSize: 9, - color: '#9b99a1', - }, - }, - yAxis: { - type: 'category', - data: yAxisLabel, - boundaryGap: true, - axisTick: { show: false }, - axisLine: { show: false }, - splitLine: { show: false }, - axisLabel: { - fontSize: 10, - }, - }, - emphasis: { - disabled: true, - }, - barCategoryGap: '21%', - overflow: 'truncate', - lineOverflow: 'truncate', - series: [ - { - name: 'reference', - type: 'bar', - color: CHART_COLOR.REFERENCE_LIGHT, - label: { - show: true, - position: 'insideRight', - fontWeight: 'bold', - color: CHART_COLOR.REFERENCE_DARK, - formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', - - }, - data: referenceDataset.map(({ count, percentage }) => ({ percentage, count, value: count })), - }, - { - name: title, - type: 'bar', - color: CHART_COLOR.CURRENT_LIGHT, - label: { - show: true, - position: 'insideRight', - fontWeight: 'bold', - color: CHART_COLOR.CURRENT_DARK, - formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', - - }, - data: currentDataset.map(({ count, percentage }) => ({ percentage, count, value: count })), - }, - ], - }; -} diff --git a/ui/src/container/models/Details/binary-classification/current/data-quality/data-quality-list/numerical/chart/index.jsx b/ui/src/container/models/Details/binary-classification/current/data-quality/data-quality-list/numerical/chart/index.jsx index a1b8866b..3011c334 100644 --- a/ui/src/container/models/Details/binary-classification/current/data-quality/data-quality-list/numerical/chart/index.jsx +++ b/ui/src/container/models/Details/binary-classification/current/data-quality/data-quality-list/numerical/chart/index.jsx @@ -1,4 +1,4 @@ -import { CHART_COLOR } from '@Container/models/Details/constants'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; import ReactEchartsCore from 'echarts-for-react/lib/core'; import { BarChart } from 'echarts/charts'; import { diff --git a/ui/src/container/models/Details/binary-classification/current/data-quality/data-quality-list/numerical/chart/options.js b/ui/src/container/models/Details/binary-classification/current/data-quality/data-quality-list/numerical/chart/options.js index 1d209d2d..a1db0e4c 100644 --- a/ui/src/container/models/Details/binary-classification/current/data-quality/data-quality-list/numerical/chart/options.js +++ b/ui/src/container/models/Details/binary-classification/current/data-quality/data-quality-list/numerical/chart/options.js @@ -1,49 +1,24 @@ import { numberFormatter } from '@Src/constants'; +import * as commonChartOptions from '@Helpers/common-chart-options'; export default function chartOptions(dataset, referenceColor, currentColor) { - const dataFormatted = dataset.buckets.map((value) => numberFormatter().format(value)); - const lastElementData = dataFormatted.pop(); - const xAxisData = dataFormatted.map((el, idx) => `[${dataFormatted[idx]}${(idx < dataFormatted.length - 1) ? `-${dataFormatted[idx + 1]})` : (idx === dataFormatted.length - 1) ? `-${lastElementData}]` : ''} `); + const { length, [length - 1]: last, ...rest } = dataset.buckets.map((value) => numberFormatter().format(value)); - return { - grid: { - top: 10, - bottom: 0, - left: 25, - right: 5, - containLabel: true, - }, - xAxis: { - type: 'category', - data: xAxisData, - axisTick: { show: false }, - axisLine: { show: false }, - splitLine: { show: false }, - axisLabel: { - fontSize: 12, - interval: 0, - rotate: 20, - color: '#9b99a1', - }, - }, - yAxis: { - type: 'value', - axisLabel: { - fontSize: 9, - color: '#9b99a1', - }, - }, + const values = Object.values(rest); + + const xAxisData = values.map((el, idx) => `[${el}${(idx < values.length - 1) ? `-${values[idx + 1]})` : (idx === values.length - 1) ? `-${last}]` : ''} `); + + const options = { + ...commonChartOptions.gridOptions.barChart(), + ...commonChartOptions.xAxisOptions.categoryType(xAxisData), + ...commonChartOptions.yAxisOptions.valueType(), series: [ - { - data: dataset.referenceValues, - type: 'bar', - itemStyle: { color: referenceColor }, - }, - { - data: dataset.currentValues, - type: 'bar', - itemStyle: { color: currentColor }, - }, + commonChartOptions.seriesOptions.barChart('reference', referenceColor, dataset.referenceValues), + commonChartOptions.seriesOptions.barChart('current', currentColor, dataset.currentValues), ], }; + + options.xAxis.axisLabel.rotate = 20; + + return options; } diff --git a/ui/src/container/models/Details/binary-classification/current/model-quality/charts.jsx b/ui/src/container/models/Details/binary-classification/current/model-quality/charts.jsx index bc71b714..b73b3d94 100644 --- a/ui/src/container/models/Details/binary-classification/current/model-quality/charts.jsx +++ b/ui/src/container/models/Details/binary-classification/current/model-quality/charts.jsx @@ -1,5 +1,6 @@ -import LineChart from '@Container/models/Details/charts/line-chart'; -import { CHART_COLOR, MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; +import LineChart from '@Components/charts/line-chart'; +import { MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; import { useGetCurrentModelQualityQueryWithPolling } from '@Src/store/state/models/polling-hook'; import { modelsApiSlice } from '@State/models/api'; import { useParams } from 'react-router'; diff --git a/ui/src/container/models/Details/binary-classification/current/model-quality/index.jsx b/ui/src/container/models/Details/binary-classification/current/model-quality/index.jsx index b99e4f45..ee0a0614 100644 --- a/ui/src/container/models/Details/binary-classification/current/model-quality/index.jsx +++ b/ui/src/container/models/Details/binary-classification/current/model-quality/index.jsx @@ -1,7 +1,7 @@ import SomethingWentWrong from '@Components/ErrorPage/something-went-wrong'; import JobStatus from '@Components/JobStatus'; -import ConfusionMatrix from '@Container/models/Details/charts/confusion-matrix-chart'; -import { CHART_COLOR, MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; +import ConfusionMatrix from '@Components/charts/confusion-matrix-chart'; +import { MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; import { JOB_STATUS } from '@Src/constants'; import { modelsApiSlice } from '@State/models/api'; import { useGetCurrentModelQualityQueryWithPolling } from '@State/models/polling-hook'; @@ -10,6 +10,7 @@ import { } from '@radicalbit/radicalbit-design-system'; import { memo } from 'react'; import { useParams } from 'react-router'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; import { AccuracyChart, AreaUnderPrChart, diff --git a/ui/src/container/models/Details/binary-classification/reference/data-quality/data-point-distribution/options.js b/ui/src/container/models/Details/binary-classification/reference/data-quality/data-point-distribution/options.js new file mode 100644 index 00000000..b9841ed6 --- /dev/null +++ b/ui/src/container/models/Details/binary-classification/reference/data-quality/data-point-distribution/options.js @@ -0,0 +1,30 @@ +import { CHART_COLOR } from '@Helpers/common-chart-options'; +import { numberFormatter } from '@Src/constants'; +import * as commonChartOptions from '@Helpers/common-chart-options'; + +export default function chartOptions(title, dataset) { + const yAxisLabel = dataset.map(({ name }) => name); + + const referenceData = dataset.map(({ count, percentage }) => ({ percentage, count, value: count })); + + const options = { + ...commonChartOptions.gridOptions.barChart(), + ...commonChartOptions.xAxisOptions.valueType(), + ...commonChartOptions.yAxisOptions.categoryType(yAxisLabel), + ...commonChartOptions.commonOptions.barChart(), + series: [ + { + ...commonChartOptions.seriesOptions.barChart(title, CHART_COLOR.REFERENCE_LIGHT, referenceData), + color: CHART_COLOR.REFERENCE_LIGHT, + label: { + show: true, + position: 'insideRight', + fontWeight: 'bold', + formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', + }, + }, + ], + }; + + return options; +} diff --git a/ui/src/container/models/Details/binary-classification/reference/data-quality/data-point-distribution/options.jsx b/ui/src/container/models/Details/binary-classification/reference/data-quality/data-point-distribution/options.jsx deleted file mode 100644 index d42874d0..00000000 --- a/ui/src/container/models/Details/binary-classification/reference/data-quality/data-point-distribution/options.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import { CHART_COLOR } from '@Container/models/Details/constants'; -import { numberFormatter } from '@Src/constants'; - -export default function chartOptions(title, dataset) { - const yAxisLabel = dataset.map(({ name }) => name); - - return { - grid: { - left: 0, - right: 20, - bottom: 0, - top: 0, - containLabel: true, - }, - xAxis: { - type: 'value', - boundaryGap: true, - axisLabel: { - fontSize: 9, - color: '#9b99a1', - }, - }, - yAxis: { - type: 'category', - data: yAxisLabel, - boundaryGap: true, - axisTick: { show: false }, - axisLine: { show: false }, - splitLine: { show: false }, - axisLabel: { - fontSize: 10, - }, - }, - emphasis: { - disabled: true, - }, - barCategoryGap: '21%', - overflow: 'truncate', - lineOverflow: 'truncate', - series: [ - { - name: title, - type: 'bar', - color: CHART_COLOR.REFERENCE_LIGHT, - emphasis: { - focus: 'series', - }, - label: { - show: true, - position: 'insideRight', - fontWeight: 'bold', - formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', - }, - data: dataset.map(({ count, percentage }) => ({ percentage, count, value: count })), - }, - ], - }; -} diff --git a/ui/src/container/models/Details/binary-classification/reference/data-quality/data-quality-list/numerical/chart/index.jsx b/ui/src/container/models/Details/binary-classification/reference/data-quality/data-quality-list/numerical/chart/index.jsx index ee944f58..64dfbcd9 100644 --- a/ui/src/container/models/Details/binary-classification/reference/data-quality/data-quality-list/numerical/chart/index.jsx +++ b/ui/src/container/models/Details/binary-classification/reference/data-quality/data-quality-list/numerical/chart/index.jsx @@ -1,4 +1,4 @@ -import { CHART_COLOR } from '@Container/models/Details/constants'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; import ReactEchartsCore from 'echarts-for-react/lib/core'; import { BarChart } from 'echarts/charts'; import { diff --git a/ui/src/container/models/Details/binary-classification/reference/data-quality/data-quality-list/numerical/chart/options.js b/ui/src/container/models/Details/binary-classification/reference/data-quality/data-quality-list/numerical/chart/options.js index 8b164a76..ca64e1d0 100644 --- a/ui/src/container/models/Details/binary-classification/reference/data-quality/data-quality-list/numerical/chart/options.js +++ b/ui/src/container/models/Details/binary-classification/reference/data-quality/data-quality-list/numerical/chart/options.js @@ -1,44 +1,23 @@ import { numberFormatter } from '@Src/constants'; +import * as commonChartOptions from '@Helpers/common-chart-options'; export default function chartOptions(dataset, color) { - const dataFormatted = dataset.buckets.map((value) => numberFormatter().format(value)); - const lastElementData = dataFormatted.pop(); - const xAxisData = dataFormatted.map((el, idx) => `[${dataFormatted[idx]}${(idx < dataFormatted.length - 1) ? `-${dataFormatted[idx + 1]})` : (idx === dataFormatted.length - 1) ? `-${lastElementData}]` : ''} `); + const { length, [length - 1]: last, ...rest } = dataset.buckets.map((value) => numberFormatter().format(value)); - return { - grid: { - left: 0, - right: 20, - bottom: 0, - top: 10, - containLabel: true, - }, - xAxis: { - type: 'category', - data: xAxisData, - axisTick: { show: false }, - axisLine: { show: false }, - splitLine: { show: false }, - axisLabel: { - fontSize: 12, - interval: 0, - rotate: 20, - color: '#9b99a1', - }, - }, - yAxis: { - type: 'value', - axisLabel: { - fontSize: 9, - color: '#9b99a1', - }, - }, + const values = Object.values(rest); + + const xAxisData = values.map((el, idx) => `[${el}${(idx < values.length - 1) ? `-${values[idx + 1]})` : (idx === values.length - 1) ? `-${last}]` : ''} `); + + const options = { + ...commonChartOptions.gridOptions.barChart(), + ...commonChartOptions.xAxisOptions.categoryType(xAxisData), + ...commonChartOptions.yAxisOptions.valueType(), series: [ - { - data: dataset.referenceValues, - type: 'bar', - itemStyle: { color }, - }, + commonChartOptions.seriesOptions.barChart('reference', color, dataset.referenceValues), ], }; + + options.xAxis.axisLabel.rotate = 20; + + return options; } diff --git a/ui/src/container/models/Details/binary-classification/reference/model-quality/index.jsx b/ui/src/container/models/Details/binary-classification/reference/model-quality/index.jsx index 41befa04..5fa0b78d 100644 --- a/ui/src/container/models/Details/binary-classification/reference/model-quality/index.jsx +++ b/ui/src/container/models/Details/binary-classification/reference/model-quality/index.jsx @@ -1,12 +1,13 @@ import JobStatus from '@Components/JobStatus'; -import ConfusionMatrix from '@Container/models/Details/charts/confusion-matrix-chart'; -import { CHART_COLOR, MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; +import ConfusionMatrix from '@Components/charts/confusion-matrix-chart'; +import { MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; import { JOB_STATUS } from '@Src/constants'; import { useGetReferenceModelQualityQueryWithPolling } from '@State/models/polling-hook'; import { Board, DataTable, SectionTitle, Spinner, } from '@radicalbit/radicalbit-design-system'; import { memo } from 'react'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; import columns from './columns'; function BinaryClassificationModelQualityMetrics() { diff --git a/ui/src/container/models/Details/charts/confusion-matrix-chart/options.js b/ui/src/container/models/Details/charts/confusion-matrix-chart/options.js deleted file mode 100644 index b0b6479b..00000000 --- a/ui/src/container/models/Details/charts/confusion-matrix-chart/options.js +++ /dev/null @@ -1,58 +0,0 @@ -export default function confusionMatrixOptions(dataset, labelClass, colors) { - let dataMax = 0; - const heatMapData = dataset.toReversed().reduce((accumulator, datas, yIndex) => accumulator.concat(datas.map((data, xIndex) => { - if (data > dataMax) { - dataMax = data; - } - return [xIndex, yIndex, data]; - })), []); - - return { - yAxis: [ - { - type: 'category', - data: labelClass.yAxisLabel, - }, - ], - xAxis: [ - { - type: 'category', - splitLine: { - show: false, - }, - data: labelClass.xAxisLabel, - }, - ], - grid: { - bottom: 80, - top: 0, - left: 64, - right: 0, - }, - visualMap: { - calculable: true, - orient: 'horizontal', - left: 'center', - inRange: { - color: colors, - }, - max: dataMax, - }, - series: [ - { - name: '', - type: 'heatmap', - data: heatMapData, - label: { - show: true, - }, - emphasis: { - itemStyle: { - shadowBlur: 10, - shadowColor: 'rgba(0, 0, 0, 0.5)', - }, - }, - }, - ], - }; -} diff --git a/ui/src/container/models/Details/charts/line-chart/options.js b/ui/src/container/models/Details/charts/line-chart/options.js deleted file mode 100644 index 5b7aea71..00000000 --- a/ui/src/container/models/Details/charts/line-chart/options.js +++ /dev/null @@ -1,75 +0,0 @@ -import { numberFormatter } from '@Src/constants'; -import moment from 'moment'; -import { CHART_COLOR } from '@Container/models/Details/constants'; - -export default function lineChartOptions(title, color, currentDataset, referenceDataset) { - const series = [ - { - name: title, - type: 'line', - lineStyle: { - width: 2, - color: '#73B2E0', - }, - data: currentDataset.map(({ timestamp, value }) => [timestamp, numberFormatter().format(value)]), - symbol: 'none', - }, - ]; - if (referenceDataset) { - series.push({ - name: 'Reference', - type: 'line', - endLabel: { - show: true, - color: CHART_COLOR.REFERENCE, - formatter: ({ value }) => `Reference\n${value[1]}`, - }, - color: CHART_COLOR.REFERENCE, - lineStyle: { - width: 2, - type: 'dotted', - color: CHART_COLOR.REFERENCE, - }, - data: referenceDataset.map(({ timestamp, value }) => [timestamp, numberFormatter().format(value)]), - symbol: 'none', - }); - } - - return { - color: [color], - tooltip: { - trigger: 'axis', - }, - yAxis: [{ - type: 'value', - boundaryGap: true, - axisLabel: { - fontSize: 9, - color: '#9b99a1', - }, - }], - xAxis: [ - { - type: 'time', - axisLabel: { - formatter: (value) => moment(+value).format('DD MMM HH.mm'), - fontSize: 10, - color: '#9b99a1', - }, - axisTick: { show: false }, - axisLine: { show: false }, - splitLine: { show: false }, - - }, - ], - grid: { - bottom: 0, - top: 16, - left: 0, - right: 64, - containLabel: true, - }, - - series, - }; -} diff --git a/ui/src/container/models/Details/constants.js b/ui/src/container/models/Details/constants.js index c7765b95..24530e6a 100644 --- a/ui/src/container/models/Details/constants.js +++ b/ui/src/container/models/Details/constants.js @@ -28,16 +28,6 @@ export const FEATURE_TYPE = { CATEGORICAL: 'categorical', }; -export const CHART_COLOR = { - REFERENCE: '#9B99A1', - REFERENCE_LIGHT: '#DBDBDB', - REFERENCE_DARK: '#667', - CURRENT: '#3695d9', - CURRENT_LIGHT: '#C8E4F9', - CURRENT_DARK: '#0A71BB', - WHITE: '#FFFFFF', -}; - export const MODEL_QUALITY_FIELD = { ACCURACY: 'Accuracy', PRECISION: 'Precision', diff --git a/ui/src/container/models/Details/multi-classification/current/data-drift/use-get-filtered-features.js b/ui/src/container/models/Details/multi-classification/current/data-drift/use-get-filtered-features.js index e8d92f1e..e353fac4 100644 --- a/ui/src/container/models/Details/multi-classification/current/data-drift/use-get-filtered-features.js +++ b/ui/src/container/models/Details/multi-classification/current/data-drift/use-get-filtered-features.js @@ -28,8 +28,6 @@ export default () => { const isNumerical = isNumericalSelected && type === DRIFT_TEST_ENUM.KS; const isCategorical = isCategoricalSelected && type === DRIFT_TEST_ENUM.CHI2; - console.debug(type, isNumerical, isCategorical); - return isNumerical || isCategorical; }); }; diff --git a/ui/src/container/models/Details/multi-classification/current/data-quality/data-point-distribution/options.js b/ui/src/container/models/Details/multi-classification/current/data-quality/data-point-distribution/options.js new file mode 100644 index 00000000..eacede83 --- /dev/null +++ b/ui/src/container/models/Details/multi-classification/current/data-quality/data-point-distribution/options.js @@ -0,0 +1,42 @@ +import { CHART_COLOR } from '@Helpers/common-chart-options'; +import { numberFormatter } from '@Src/constants'; +import * as commonChartOptions from '@Helpers/common-chart-options'; + +export default function chartOptions(title, referenceDataset, currentDataset) { + const yAxisLabel = currentDataset.map(({ name }) => name); + + const referenceData = referenceDataset.map(({ count, percentage }) => ({ percentage, count, value: count })); + const currentData = currentDataset.map(({ count, percentage }) => ({ percentage, count, value: count })); + + const options = { + ...commonChartOptions.gridOptions.barChart(), + ...commonChartOptions.xAxisOptions.valueType(), + ...commonChartOptions.yAxisOptions.categoryType(yAxisLabel), + ...commonChartOptions.commonOptions.barChart(), + series: [ + { + ...commonChartOptions.seriesOptions.barChart(title, CHART_COLOR.REFERENCE_LIGHT, referenceData), + color: CHART_COLOR.REFERENCE_LIGHT, + label: { + show: true, + position: 'insideRight', + fontWeight: 'bold', + formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', + }, + }, + { + ...commonChartOptions.seriesOptions.barChart(title, CHART_COLOR.CURRENT_LIGHT_LIGHT, currentData), + color: CHART_COLOR.CURRENT_LIGHT, + label: { + show: true, + position: 'insideRight', + fontWeight: 'bold', + color: CHART_COLOR.CURRENT_DARK, + formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', + }, + }, + ], + }; + + return options; +} diff --git a/ui/src/container/models/Details/multi-classification/current/data-quality/data-point-distribution/options.jsx b/ui/src/container/models/Details/multi-classification/current/data-quality/data-point-distribution/options.jsx deleted file mode 100644 index 5148b9c0..00000000 --- a/ui/src/container/models/Details/multi-classification/current/data-quality/data-point-distribution/options.jsx +++ /dev/null @@ -1,71 +0,0 @@ -import { CHART_COLOR } from '@Container/models/Details/constants'; -import { numberFormatter } from '@Src/constants'; - -export default function chartOptions(title, referenceDataset, currentDataset) { - const yAxisLabel = currentDataset.map(({ name }) => name); - - return { - grid: { - left: 0, - right: 20, - bottom: 0, - top: 0, - containLabel: true, - }, - xAxis: { - type: 'value', - boundaryGap: true, - axisLabel: { - fontSize: 9, - color: '#9b99a1', - }, - }, - yAxis: { - type: 'category', - data: yAxisLabel, - boundaryGap: true, - axisTick: { show: false }, - axisLine: { show: false }, - splitLine: { show: false }, - axisLabel: { - fontSize: 10, - }, - }, - emphasis: { - disabled: true, - }, - barCategoryGap: '21%', - overflow: 'truncate', - lineOverflow: 'truncate', - series: [ - { - name: 'reference', - type: 'bar', - color: CHART_COLOR.REFERENCE_LIGHT, - label: { - show: true, - position: 'insideRight', - fontWeight: 'bold', - color: CHART_COLOR.REFERENCE_DARK, - formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', - - }, - data: referenceDataset.map(({ count, percentage }) => ({ percentage, count, value: count })), - }, - { - name: title, - type: 'bar', - color: CHART_COLOR.CURRENT_LIGHT, - label: { - show: true, - position: 'insideRight', - fontWeight: 'bold', - color: CHART_COLOR.CURRENT_DARK, - formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', - - }, - data: currentDataset.map(({ count, percentage }) => ({ percentage, count, value: count })), - }, - ], - }; -} diff --git a/ui/src/container/models/Details/multi-classification/current/data-quality/data-quality-list/numerical/chart/index.jsx b/ui/src/container/models/Details/multi-classification/current/data-quality/data-quality-list/numerical/chart/index.jsx index a1b8866b..3011c334 100644 --- a/ui/src/container/models/Details/multi-classification/current/data-quality/data-quality-list/numerical/chart/index.jsx +++ b/ui/src/container/models/Details/multi-classification/current/data-quality/data-quality-list/numerical/chart/index.jsx @@ -1,4 +1,4 @@ -import { CHART_COLOR } from '@Container/models/Details/constants'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; import ReactEchartsCore from 'echarts-for-react/lib/core'; import { BarChart } from 'echarts/charts'; import { diff --git a/ui/src/container/models/Details/multi-classification/current/data-quality/data-quality-list/numerical/chart/options.js b/ui/src/container/models/Details/multi-classification/current/data-quality/data-quality-list/numerical/chart/options.js index 1d209d2d..a1db0e4c 100644 --- a/ui/src/container/models/Details/multi-classification/current/data-quality/data-quality-list/numerical/chart/options.js +++ b/ui/src/container/models/Details/multi-classification/current/data-quality/data-quality-list/numerical/chart/options.js @@ -1,49 +1,24 @@ import { numberFormatter } from '@Src/constants'; +import * as commonChartOptions from '@Helpers/common-chart-options'; export default function chartOptions(dataset, referenceColor, currentColor) { - const dataFormatted = dataset.buckets.map((value) => numberFormatter().format(value)); - const lastElementData = dataFormatted.pop(); - const xAxisData = dataFormatted.map((el, idx) => `[${dataFormatted[idx]}${(idx < dataFormatted.length - 1) ? `-${dataFormatted[idx + 1]})` : (idx === dataFormatted.length - 1) ? `-${lastElementData}]` : ''} `); + const { length, [length - 1]: last, ...rest } = dataset.buckets.map((value) => numberFormatter().format(value)); - return { - grid: { - top: 10, - bottom: 0, - left: 25, - right: 5, - containLabel: true, - }, - xAxis: { - type: 'category', - data: xAxisData, - axisTick: { show: false }, - axisLine: { show: false }, - splitLine: { show: false }, - axisLabel: { - fontSize: 12, - interval: 0, - rotate: 20, - color: '#9b99a1', - }, - }, - yAxis: { - type: 'value', - axisLabel: { - fontSize: 9, - color: '#9b99a1', - }, - }, + const values = Object.values(rest); + + const xAxisData = values.map((el, idx) => `[${el}${(idx < values.length - 1) ? `-${values[idx + 1]})` : (idx === values.length - 1) ? `-${last}]` : ''} `); + + const options = { + ...commonChartOptions.gridOptions.barChart(), + ...commonChartOptions.xAxisOptions.categoryType(xAxisData), + ...commonChartOptions.yAxisOptions.valueType(), series: [ - { - data: dataset.referenceValues, - type: 'bar', - itemStyle: { color: referenceColor }, - }, - { - data: dataset.currentValues, - type: 'bar', - itemStyle: { color: currentColor }, - }, + commonChartOptions.seriesOptions.barChart('reference', referenceColor, dataset.referenceValues), + commonChartOptions.seriesOptions.barChart('current', currentColor, dataset.currentValues), ], }; + + options.xAxis.axisLabel.rotate = 20; + + return options; } diff --git a/ui/src/container/models/Details/multi-classification/current/model-quality/charts.jsx b/ui/src/container/models/Details/multi-classification/current/model-quality/charts.jsx index bc71b714..b73b3d94 100644 --- a/ui/src/container/models/Details/multi-classification/current/model-quality/charts.jsx +++ b/ui/src/container/models/Details/multi-classification/current/model-quality/charts.jsx @@ -1,5 +1,6 @@ -import LineChart from '@Container/models/Details/charts/line-chart'; -import { CHART_COLOR, MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; +import LineChart from '@Components/charts/line-chart'; +import { MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; import { useGetCurrentModelQualityQueryWithPolling } from '@Src/store/state/models/polling-hook'; import { modelsApiSlice } from '@State/models/api'; import { useParams } from 'react-router'; diff --git a/ui/src/container/models/Details/multi-classification/current/model-quality/index.jsx b/ui/src/container/models/Details/multi-classification/current/model-quality/index.jsx index c2bd971e..02c4eb96 100644 --- a/ui/src/container/models/Details/multi-classification/current/model-quality/index.jsx +++ b/ui/src/container/models/Details/multi-classification/current/model-quality/index.jsx @@ -1,7 +1,7 @@ import SomethingWentWrong from '@Components/ErrorPage/something-went-wrong'; import JobStatus from '@Components/JobStatus'; -import ConfusionMatrix from '@Container/models/Details/charts/confusion-matrix-chart'; -import { CHART_COLOR, MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; +import ConfusionMatrix from '@Components/charts/confusion-matrix-chart'; +import { MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; import { JOB_STATUS } from '@Src/constants'; import { modelsApiSlice } from '@State/models/api'; import { useGetCurrentModelQualityQueryWithPolling } from '@State/models/polling-hook'; @@ -10,6 +10,7 @@ import { } from '@radicalbit/radicalbit-design-system'; import { memo } from 'react'; import { useParams } from 'react-router'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; import { AccuracyChart, AreaUnderPrChart, diff --git a/ui/src/container/models/Details/multi-classification/reference/data-quality/data-point-distribution/options.js b/ui/src/container/models/Details/multi-classification/reference/data-quality/data-point-distribution/options.js new file mode 100644 index 00000000..b9841ed6 --- /dev/null +++ b/ui/src/container/models/Details/multi-classification/reference/data-quality/data-point-distribution/options.js @@ -0,0 +1,30 @@ +import { CHART_COLOR } from '@Helpers/common-chart-options'; +import { numberFormatter } from '@Src/constants'; +import * as commonChartOptions from '@Helpers/common-chart-options'; + +export default function chartOptions(title, dataset) { + const yAxisLabel = dataset.map(({ name }) => name); + + const referenceData = dataset.map(({ count, percentage }) => ({ percentage, count, value: count })); + + const options = { + ...commonChartOptions.gridOptions.barChart(), + ...commonChartOptions.xAxisOptions.valueType(), + ...commonChartOptions.yAxisOptions.categoryType(yAxisLabel), + ...commonChartOptions.commonOptions.barChart(), + series: [ + { + ...commonChartOptions.seriesOptions.barChart(title, CHART_COLOR.REFERENCE_LIGHT, referenceData), + color: CHART_COLOR.REFERENCE_LIGHT, + label: { + show: true, + position: 'insideRight', + fontWeight: 'bold', + formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', + }, + }, + ], + }; + + return options; +} diff --git a/ui/src/container/models/Details/multi-classification/reference/data-quality/data-point-distribution/options.jsx b/ui/src/container/models/Details/multi-classification/reference/data-quality/data-point-distribution/options.jsx deleted file mode 100644 index d42874d0..00000000 --- a/ui/src/container/models/Details/multi-classification/reference/data-quality/data-point-distribution/options.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import { CHART_COLOR } from '@Container/models/Details/constants'; -import { numberFormatter } from '@Src/constants'; - -export default function chartOptions(title, dataset) { - const yAxisLabel = dataset.map(({ name }) => name); - - return { - grid: { - left: 0, - right: 20, - bottom: 0, - top: 0, - containLabel: true, - }, - xAxis: { - type: 'value', - boundaryGap: true, - axisLabel: { - fontSize: 9, - color: '#9b99a1', - }, - }, - yAxis: { - type: 'category', - data: yAxisLabel, - boundaryGap: true, - axisTick: { show: false }, - axisLine: { show: false }, - splitLine: { show: false }, - axisLabel: { - fontSize: 10, - }, - }, - emphasis: { - disabled: true, - }, - barCategoryGap: '21%', - overflow: 'truncate', - lineOverflow: 'truncate', - series: [ - { - name: title, - type: 'bar', - color: CHART_COLOR.REFERENCE_LIGHT, - emphasis: { - focus: 'series', - }, - label: { - show: true, - position: 'insideRight', - fontWeight: 'bold', - formatter: (el) => (el.data.count > 0) ? `${el.data.count} (${numberFormatter().format(el.data.percentage)}%)` : '', - }, - data: dataset.map(({ count, percentage }) => ({ percentage, count, value: count })), - }, - ], - }; -} diff --git a/ui/src/container/models/Details/multi-classification/reference/data-quality/data-quality-list/numerical/chart/index.jsx b/ui/src/container/models/Details/multi-classification/reference/data-quality/data-quality-list/numerical/chart/index.jsx index ee944f58..64dfbcd9 100644 --- a/ui/src/container/models/Details/multi-classification/reference/data-quality/data-quality-list/numerical/chart/index.jsx +++ b/ui/src/container/models/Details/multi-classification/reference/data-quality/data-quality-list/numerical/chart/index.jsx @@ -1,4 +1,4 @@ -import { CHART_COLOR } from '@Container/models/Details/constants'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; import ReactEchartsCore from 'echarts-for-react/lib/core'; import { BarChart } from 'echarts/charts'; import { diff --git a/ui/src/container/models/Details/multi-classification/reference/data-quality/data-quality-list/numerical/chart/options.js b/ui/src/container/models/Details/multi-classification/reference/data-quality/data-quality-list/numerical/chart/options.js index 8b164a76..ca64e1d0 100644 --- a/ui/src/container/models/Details/multi-classification/reference/data-quality/data-quality-list/numerical/chart/options.js +++ b/ui/src/container/models/Details/multi-classification/reference/data-quality/data-quality-list/numerical/chart/options.js @@ -1,44 +1,23 @@ import { numberFormatter } from '@Src/constants'; +import * as commonChartOptions from '@Helpers/common-chart-options'; export default function chartOptions(dataset, color) { - const dataFormatted = dataset.buckets.map((value) => numberFormatter().format(value)); - const lastElementData = dataFormatted.pop(); - const xAxisData = dataFormatted.map((el, idx) => `[${dataFormatted[idx]}${(idx < dataFormatted.length - 1) ? `-${dataFormatted[idx + 1]})` : (idx === dataFormatted.length - 1) ? `-${lastElementData}]` : ''} `); + const { length, [length - 1]: last, ...rest } = dataset.buckets.map((value) => numberFormatter().format(value)); - return { - grid: { - left: 0, - right: 20, - bottom: 0, - top: 10, - containLabel: true, - }, - xAxis: { - type: 'category', - data: xAxisData, - axisTick: { show: false }, - axisLine: { show: false }, - splitLine: { show: false }, - axisLabel: { - fontSize: 12, - interval: 0, - rotate: 20, - color: '#9b99a1', - }, - }, - yAxis: { - type: 'value', - axisLabel: { - fontSize: 9, - color: '#9b99a1', - }, - }, + const values = Object.values(rest); + + const xAxisData = values.map((el, idx) => `[${el}${(idx < values.length - 1) ? `-${values[idx + 1]})` : (idx === values.length - 1) ? `-${last}]` : ''} `); + + const options = { + ...commonChartOptions.gridOptions.barChart(), + ...commonChartOptions.xAxisOptions.categoryType(xAxisData), + ...commonChartOptions.yAxisOptions.valueType(), series: [ - { - data: dataset.referenceValues, - type: 'bar', - itemStyle: { color }, - }, + commonChartOptions.seriesOptions.barChart('reference', color, dataset.referenceValues), ], }; + + options.xAxis.axisLabel.rotate = 20; + + return options; } diff --git a/ui/src/container/models/Details/multi-classification/reference/model-quality/index.jsx b/ui/src/container/models/Details/multi-classification/reference/model-quality/index.jsx index e93cf226..756e7850 100644 --- a/ui/src/container/models/Details/multi-classification/reference/model-quality/index.jsx +++ b/ui/src/container/models/Details/multi-classification/reference/model-quality/index.jsx @@ -1,12 +1,13 @@ import JobStatus from '@Components/JobStatus'; -import ConfusionMatrix from '@Container/models/Details/charts/confusion-matrix-chart'; -import { CHART_COLOR, MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; +import ConfusionMatrix from '@Components/charts/confusion-matrix-chart'; +import { MODEL_QUALITY_FIELD } from '@Container/models/Details/constants'; import { JOB_STATUS } from '@Src/constants'; import { useGetReferenceModelQualityQueryWithPolling } from '@State/models/polling-hook'; import { Board, DataTable, SectionTitle, Spinner, } from '@radicalbit/radicalbit-design-system'; import { memo } from 'react'; +import { CHART_COLOR } from '@Helpers/common-chart-options'; import columns from './columns'; function MultiClassificationModelQualityMetrics() { diff --git a/ui/src/helpers/common-chart-options.js b/ui/src/helpers/common-chart-options.js new file mode 100644 index 00000000..db4b5c9c --- /dev/null +++ b/ui/src/helpers/common-chart-options.js @@ -0,0 +1,266 @@ +import moment from 'moment'; + +const dateFormatter = (value) => moment(+value).format('DD MMM HH.mm'); + +const xAxisCategoryType = (xAxisData) => { + const options = { + xAxis: { + type: 'category', + axisTick: { show: false }, + axisLine: { show: false }, + splitLine: { show: false }, + axisLabel: { + fontSize: 12, + interval: 0, + color: '#9b99a1', + }, + }, + }; + if (xAxisData) { + options.xAxis.data = xAxisData; + } + return options; +}; + +const xAxisTimeType = (xAxisData) => { + const options = { + xAxis: { + type: 'time', + axisTick: { show: false }, + axisLine: { show: false }, + splitLine: { show: false }, + axisLabel: { + formatter: dateFormatter, + fontSize: 12, + color: '#9b99a1', + }, + }, + }; + if (xAxisData) { + options.xAxis.data = xAxisData; + } + return options; +}; + +const xAxisValueType = (xAxisData) => { + const options = { + xAxis: { + type: 'value', + boundaryGap: true, + axisLabel: { + fontSize: 9, + color: '#9b99a1', + }, + }, + }; + if (xAxisData) { + options.xAxis.data = xAxisData; + } + return options; +}; + +const yAxisValueType = (yAxisData) => { + const options = { + yAxis: { + type: 'value', + boundaryGap: true, + axisLabel: { + fontSize: 9, + color: '#9b99a1', + }, + }, + }; + if (yAxisData) { + options.yAxis.data = yAxisData; + } + return options; +}; + +const yAxisCategoryType = (yAxisData) => { + const options = { + yAxis: { + type: 'category', + boundaryGap: true, + axisTick: { show: false }, + axisLine: { show: false }, + splitLine: { show: false }, + axisLabel: { + fontSize: 10, + }, + }, + }; + if (yAxisData) { + options.yAxis.data = yAxisData; + } + return options; +}; + +const barGridOptions = () => ({ + grid: { + left: 0, + right: 20, + bottom: 0, + top: 10, + containLabel: true, + }, +}); + +const lineGridOptions = () => ({ + grid: { + bottom: 0, + top: 16, + left: 0, + right: 64, + containLabel: true, + }, +}); + +const heatmapGridOptions = () => ({ + grid: { + bottom: 80, + top: 0, + left: 64, + right: 0, + }, +}); + +const heatmapVisualMapOptions = (dataMax, colors) => { + const options = { + visualMap: { + calculable: true, + orient: 'horizontal', + left: 'center', + }, + }; + + if (dataMax) { + options.visualMap.max = dataMax; + } + + if (colors) { + options.visualMap.inRange = { color: colors }; + } + + return options; +}; + +const tooltipOptions = () => ({ + tooltip: { + trigger: 'axis', + }, +}); + +const barSeriesOptions = (title, color, data) => { + const options = { + title, + type: 'bar', + itemStyle: { color }, + }; + + if (data) { + options.data = data; + } + return options; +}; + +const lineSeriesOptions = (title, color, data) => { + const options = { + name: title, + type: 'line', + lineStyle: { width: 2, color }, + symbol: 'none', + }; + + if (data) { + options.data = data; + } + return options; +}; + +const heatmapSeriesOptions = (data) => { + const options = { + name: '', + type: 'heatmap', + label: { + show: true, + }, + emphasis: { + itemStyle: { + shadowBlur: 10, + shadowColor: 'rgba(0, 0, 0, 0.5)', + }, + }, + }; + + if (data) { + options.data = data; + } + + return options; +}; + +const barChartCommonOptions = () => ({ + emphasis: { disabled: true }, + barCategoryGap: '21%', + overflow: 'truncate', + lineOverflow: 'truncate', +}); + +const heatmapCommonOptions = () => ({ + emphasis: { disabled: true }, +}); + +// Object to simplify usage of common options +const yAxisOptions = { + valueType: yAxisValueType, + categoryType: yAxisCategoryType, +}; + +const xAxisOptions = { + categoryType: xAxisCategoryType, + timeType: xAxisTimeType, + valueType: xAxisValueType, +}; + +const gridOptions = { + barChart: barGridOptions, + lineChart: lineGridOptions, + heatmapChart: heatmapGridOptions, +}; + +const seriesOptions = { + barChart: barSeriesOptions, + lineChart: lineSeriesOptions, + heatmapChart: heatmapSeriesOptions, +}; + +const commonOptions = { + barChart: barChartCommonOptions, + heatmapChart: heatmapCommonOptions, +}; + +const visualMapOptions = { + heatmapChart: heatmapVisualMapOptions, +}; + +const CHART_COLOR = { + REFERENCE: '#9B99A1', + REFERENCE_LIGHT: '#DBDBDB', + REFERENCE_DARK: '#667', + CURRENT: '#3695d9', + CURRENT_LIGHT: '#C8E4F9', + CURRENT_DARK: '#0A71BB', + WHITE: '#FFFFFF', + LINE_CHART_COLOR: '#73B2E0', +}; + +export { + yAxisOptions, + xAxisOptions, + seriesOptions, + gridOptions, + commonOptions, + visualMapOptions, + tooltipOptions, + CHART_COLOR, +};