@cdc/chart 4.24.9 → 4.24.11

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.
Files changed (95) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcchart.js +45911 -41739
  3. package/examples/feature/boxplot/boxplot-data.json +88 -22
  4. package/examples/feature/boxplot/boxplot.json +540 -16
  5. package/examples/feature/boxplot/testing.csv +7 -7
  6. package/examples/feature/sankey/sankey-example-data.json +0 -1
  7. package/examples/private/test.json +20092 -0
  8. package/index.html +4 -4
  9. package/package.json +2 -2
  10. package/src/CdcChart.tsx +209 -188
  11. package/src/_stories/Chart.CustomColors.stories.tsx +19 -0
  12. package/src/_stories/Chart.DynamicSeries.stories.tsx +27 -0
  13. package/src/_stories/Chart.Legend.Gradient.stories.tsx +74 -0
  14. package/src/_stories/Chart.stories.tsx +30 -3
  15. package/src/_stories/ChartAxisLabels.stories.tsx +20 -0
  16. package/src/_stories/ChartAxisTitles.stories.tsx +53 -0
  17. package/src/_stories/ChartEditor.stories.tsx +27 -0
  18. package/src/_stories/ChartLine.Suppression.stories.tsx +25 -0
  19. package/src/_stories/ChartPrefixSuffix.stories.tsx +159 -0
  20. package/src/_stories/_mock/boxplot_multiseries.json +647 -0
  21. package/src/_stories/_mock/dynamic_series_bar_config.json +723 -0
  22. package/src/_stories/_mock/dynamic_series_config.json +979 -0
  23. package/src/_stories/_mock/horizontal_bar.json +257 -0
  24. package/src/_stories/_mock/large_x_axis_labels.json +261 -0
  25. package/src/_stories/_mock/paired-bar.json +262 -0
  26. package/src/_stories/_mock/pie_with_data.json +255 -0
  27. package/{examples/feature/scatterplot/scatterplot.json → src/_stories/_mock/scatterplot_mock.json} +62 -92
  28. package/src/_stories/_mock/simplified_line.json +1510 -0
  29. package/src/_stories/_mock/suppression_mock.json +1549 -0
  30. package/src/components/Annotations/components/AnnotationDraggable.tsx +0 -3
  31. package/src/components/Annotations/components/AnnotationDropdown.tsx +1 -1
  32. package/src/components/Axis/Categorical.Axis.tsx +22 -4
  33. package/src/components/BarChart/components/BarChart.Horizontal.tsx +95 -16
  34. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +41 -17
  35. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +43 -9
  36. package/src/components/BarChart/components/BarChart.Vertical.tsx +123 -47
  37. package/src/components/BarChart/helpers/index.ts +23 -5
  38. package/src/components/BoxPlot/BoxPlot.tsx +189 -0
  39. package/src/components/BrushChart.tsx +3 -2
  40. package/src/components/DeviationBar.jsx +58 -8
  41. package/src/components/EditorPanel/EditorPanel.tsx +127 -102
  42. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +11 -28
  43. package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +51 -6
  44. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +21 -4
  45. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +40 -9
  46. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +3 -3
  47. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +121 -56
  48. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +296 -35
  49. package/src/components/EditorPanel/components/panels.scss +4 -6
  50. package/src/components/EditorPanel/editor-panel.scss +0 -8
  51. package/src/components/EditorPanel/helpers/tests/updateFieldRankByValue.test.ts +38 -0
  52. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +42 -0
  53. package/src/components/EditorPanel/useEditorPermissions.ts +16 -1
  54. package/src/components/ForestPlot/ForestPlot.tsx +2 -3
  55. package/src/components/ForestPlot/ForestPlotProps.ts +2 -0
  56. package/src/components/Legend/Legend.Component.tsx +23 -24
  57. package/src/components/Legend/Legend.Suppression.tsx +25 -20
  58. package/src/components/Legend/Legend.tsx +16 -18
  59. package/src/components/Legend/helpers/index.ts +16 -19
  60. package/src/components/LegendWrapper.tsx +3 -1
  61. package/src/components/LineChart/components/LineChart.Circle.tsx +10 -0
  62. package/src/components/LineChart/helpers.ts +48 -43
  63. package/src/components/LineChart/index.tsx +88 -82
  64. package/src/components/LinearChart.tsx +747 -562
  65. package/src/components/PairedBarChart.jsx +50 -10
  66. package/src/components/PieChart/PieChart.tsx +1 -6
  67. package/src/components/Regions/components/Regions.tsx +33 -19
  68. package/src/components/Sankey/index.tsx +50 -32
  69. package/src/components/Sankey/sankey.scss +6 -5
  70. package/src/components/Sankey/useSankeyAlert.tsx +60 -0
  71. package/src/components/ScatterPlot/ScatterPlot.jsx +20 -4
  72. package/src/components/ZoomBrush.tsx +25 -6
  73. package/src/coreStyles_chart.scss +3 -0
  74. package/src/data/initial-state.js +8 -10
  75. package/src/helpers/configHelpers.ts +28 -0
  76. package/src/helpers/handleRankByValue.ts +15 -0
  77. package/src/helpers/sizeHelpers.ts +25 -0
  78. package/src/helpers/tests/handleRankByValue.test.ts +37 -0
  79. package/src/helpers/tests/sizeHelpers.test.ts +80 -0
  80. package/src/hooks/useColorPalette.js +10 -2
  81. package/src/hooks/useLegendClasses.ts +13 -22
  82. package/src/hooks/useMinMax.ts +27 -13
  83. package/src/hooks/useReduceData.ts +43 -10
  84. package/src/hooks/useScales.ts +87 -38
  85. package/src/hooks/useTooltip.tsx +62 -53
  86. package/src/index.jsx +1 -0
  87. package/src/scss/DataTable.scss +5 -4
  88. package/src/scss/main.scss +57 -70
  89. package/src/types/ChartConfig.ts +43 -34
  90. package/src/types/ChartContext.ts +22 -15
  91. package/src/types/ForestPlot.ts +8 -0
  92. package/src/_stories/Chart.Legend.Gradient.tsx +0 -19
  93. package/src/_stories/ChartBrush.stories.tsx +0 -19
  94. package/src/components/BoxPlot/BoxPlot.jsx +0 -111
  95. package/src/components/LinearChart.jsx +0 -817
@@ -0,0 +1,28 @@
1
+ import { cloneDeep } from 'lodash'
2
+ import { ChartConfig } from '../types/ChartConfig'
3
+
4
+ /* editConfigKeys
5
+ * Add edit or update config keys
6
+ * keyUpdates: { path: string[], value: any }[]
7
+ * path is the array of keys needed to reach the value to be updated
8
+ * value is the new value to be set
9
+ * if the key does not exist, it will be created
10
+ */
11
+ export function editConfigKeys(config: ChartConfig, keyUpdates: { path: string[]; value: any }[]): ChartConfig {
12
+ const configDeepCopy = cloneDeep(config)
13
+
14
+ const newConfig = keyUpdates.reduce((acc, { path, value }) => {
15
+ const pathCopy = [...path]
16
+ const lastKey = pathCopy.pop()
17
+ const target = pathCopy.reduce((target, key) => {
18
+ if (!target[key]) {
19
+ target[key] = {}
20
+ }
21
+ return target[key]
22
+ }, acc)
23
+ target[lastKey] = value
24
+ return acc
25
+ }, configDeepCopy)
26
+
27
+ return newConfig
28
+ }
@@ -0,0 +1,15 @@
1
+ import { ChartConfig } from '../types/ChartConfig'
2
+
3
+ const getNumericValue = number => {
4
+ if (typeof number === 'string') return parseFloat(number.replace(/,/g, ''))
5
+ return Number(number)
6
+ }
7
+
8
+ export const handleRankByValue = (data, passedConfig: ChartConfig) => {
9
+ if (passedConfig.rankByValue) {
10
+ const series = passedConfig.series[0].dataKey
11
+ const sorted = data.sort((a, b) => getNumericValue(a[series]) - getNumericValue(b[series]))
12
+ return passedConfig.rankByValue === 'asc' ? sorted : sorted.reverse()
13
+ }
14
+ return data
15
+ }
@@ -0,0 +1,25 @@
1
+ import { isMobileHeightViewport } from '@cdc/core/helpers/viewports'
2
+ import { ChartConfig, ViewportSize } from '../types/ChartConfig'
3
+
4
+ export function getOrientation(
5
+ { orientation, heights, visualizationType }: Pick<ChartConfig, 'orientation' | 'heights' | 'visualizationType'>,
6
+ currentViewport: ViewportSize
7
+ ): 'vertical' | 'horizontal' | 'mobileVertical' {
8
+ const isForestPlot = visualizationType === 'Forest Plot'
9
+ const useVertical = orientation === 'vertical' || isForestPlot
10
+ const useMobileVertical = heights?.mobileVertical && isMobileHeightViewport(currentViewport)
11
+ const responsiveVertical = useMobileVertical ? 'mobileVertical' : 'vertical'
12
+
13
+ return useVertical ? responsiveVertical : 'horizontal'
14
+ }
15
+ export function calcInitialHeight(
16
+ { heights, orientation, visualizationType }: Pick<ChartConfig, 'heights' | 'orientation' | 'visualizationType'>,
17
+ currentViewport: ViewportSize
18
+ ): number {
19
+ // if no heights are provided assume config has not been loaded
20
+ if (!heights) return 0
21
+
22
+ const renderedOrientation = getOrientation({ orientation, heights, visualizationType }, currentViewport)
23
+ const height = Number(heights?.[renderedOrientation])
24
+ return isNaN(height) ? 0 : height
25
+ }
@@ -0,0 +1,37 @@
1
+ import { handleRankByValue } from '../handleRankByValue'
2
+ import { ChartConfig } from '../../types/ChartConfig'
3
+
4
+ describe('handleRankByValue', () => {
5
+ it('should sort the data in ascending order when rankByValue is "asc"', () => {
6
+ const data = [{ value: 3 }, { value: 1 }, { value: 2 }]
7
+ const config: ChartConfig = {
8
+ rankByValue: 'asc',
9
+ series: [{ dataKey: 'value' }]
10
+ }
11
+
12
+ const result = handleRankByValue(data, config)
13
+ expect(result).toEqual([{ value: 1 }, { value: 2 }, { value: 3 }])
14
+ })
15
+
16
+ it('should sort the data in descending order when rankByValue is "desc"', () => {
17
+ const data = [{ value: 3 }, { value: 1 }, { value: 2 }]
18
+ const config: ChartConfig = {
19
+ rankByValue: 'desc',
20
+ series: [{ dataKey: 'value' }]
21
+ }
22
+
23
+ const result = handleRankByValue(data, config)
24
+ expect(result).toEqual([{ value: 3 }, { value: 2 }, { value: 1 }])
25
+ })
26
+
27
+ it('should handle numeric strings correctly', () => {
28
+ const data = [{ value: '3' }, { value: '1' }, { value: '2' }]
29
+ const config: ChartConfig = {
30
+ rankByValue: 'asc',
31
+ series: [{ dataKey: 'value' }]
32
+ }
33
+
34
+ const result = handleRankByValue(data, config)
35
+ expect(result).toEqual([{ value: '1' }, { value: '2' }, { value: '3' }])
36
+ })
37
+ })
@@ -0,0 +1,80 @@
1
+ import { calcInitialHeight, getOrientation } from '../sizeHelpers'
2
+ import { describe, expect, it } from 'vitest'
3
+ import { ChartOrientation, VisualizationType } from '../../types/ChartConfig'
4
+
5
+ describe('sizeHelpers', () => {
6
+ describe('getOrientation', () => {
7
+ it("should return 'vertical' when orientation is vertical", () => {
8
+ const config = {
9
+ orientation: 'vertical' as ChartOrientation,
10
+ heights: { mobileVertical: 0, vertical: 0, horizontal: 0 },
11
+ visualizationType: 'Bar' as VisualizationType
12
+ }
13
+ expect(getOrientation(config, 'md')).toBe('vertical')
14
+ })
15
+
16
+ it("should return 'horizontal' when orientation is horizontal", () => {
17
+ const config = {
18
+ orientation: 'horizontal' as ChartOrientation,
19
+ heights: { mobileVertical: 0, vertical: 0, horizontal: 0 },
20
+ visualizationType: 'Bar' as VisualizationType
21
+ }
22
+ expect(getOrientation(config, 'md')).toBe('horizontal')
23
+ })
24
+ it("should return 'vertical' when orientation is horizontal but visualizationType is 'Forest Plot'", () => {
25
+ const config = {
26
+ orientation: 'horizontal' as ChartOrientation,
27
+ heights: { mobileVertical: 0, vertical: 0, horizontal: 0 },
28
+ visualizationType: 'Forest Plot' as VisualizationType
29
+ }
30
+ expect(getOrientation(config, 'md')).toBe('vertical')
31
+ })
32
+
33
+ it('should return mobileVertical when viewport is mobile height', () => {
34
+ const config = {
35
+ orientation: 'vertical' as ChartOrientation,
36
+ heights: { mobileVertical: 100, vertical: 0, horizontal: 0 },
37
+ visualizationType: 'Bar' as VisualizationType
38
+ }
39
+ expect(getOrientation(config, 'xxs')).toBe('mobileVertical')
40
+ })
41
+ })
42
+ })
43
+
44
+ describe('calcInitialHeight', () => {
45
+ it('should return 0 when no heights are provided', () => {
46
+ const config = {
47
+ heights: undefined,
48
+ orientation: 'vertical' as ChartOrientation,
49
+ visualizationType: 'Bar' as VisualizationType
50
+ }
51
+ expect(calcInitialHeight(config, 'md')).toBe(0)
52
+ })
53
+
54
+ it('should return vertical height when orientation is vertical', () => {
55
+ const config = {
56
+ orientation: 'vertical' as ChartOrientation,
57
+ heights: { mobileVertical: 0, vertical: 100, horizontal: 0 },
58
+ visualizationType: 'Bar' as VisualizationType
59
+ }
60
+ expect(calcInitialHeight(config, 'md')).toBe(100)
61
+ })
62
+
63
+ it('should return horizontal height when orientation is horizontal', () => {
64
+ const config = {
65
+ orientation: 'horizontal' as ChartOrientation,
66
+ heights: { mobileVertical: 0, vertical: 0, horizontal: 100 },
67
+ visualizationType: 'Bar' as VisualizationType
68
+ }
69
+ expect(calcInitialHeight(config, 'md')).toBe(100)
70
+ })
71
+
72
+ it('should return mobileVertical height when viewport is mobile height', () => {
73
+ const config = {
74
+ heights: { mobileVertical: 100, vertical: 0, horizontal: 0 },
75
+ orientation: 'vertical' as ChartOrientation,
76
+ visualizationType: 'Bar' as VisualizationType
77
+ }
78
+ expect(calcInitialHeight(config, 'xxs')).toBe(100)
79
+ })
80
+ })
@@ -5,11 +5,14 @@ export const useColorPalette = (config, updateConfig) => {
5
5
  let twoColorPalettes = []
6
6
  let sequential = []
7
7
  let nonSequential = []
8
+ const accessibleColors = []
8
9
 
9
10
  // Get two color palettes if visualization type is Paired Bar
10
11
  if (config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') {
11
12
  const isReversed = config.twoColor.isPaletteReversed
12
- twoColorPalettes = Object.keys(twoColorPalette).filter(name => (isReversed ? name.endsWith('reverse') : !name.endsWith('reverse')))
13
+ twoColorPalettes = Object.keys(twoColorPalette).filter(name =>
14
+ isReversed ? name.endsWith('reverse') : !name.endsWith('reverse')
15
+ )
13
16
  } else {
14
17
  // Get sequential and non-sequential palettes for other visualization types
15
18
  const seqPalettes = []
@@ -18,6 +21,7 @@ export const useColorPalette = (config, updateConfig) => {
18
21
  for (const paletteName in colorPalettesChart) {
19
22
  const isSequential = paletteName.startsWith('sequential')
20
23
  const isQualitative = paletteName.startsWith('qualitative')
24
+ const colorblindsafe = paletteName.startsWith('colorblindsafe')
21
25
  const isReversed = paletteName.endsWith('reverse')
22
26
 
23
27
  if (isSequential && ((!config.isPaletteReversed && !isReversed) || (config.isPaletteReversed && isReversed))) {
@@ -27,6 +31,9 @@ export const useColorPalette = (config, updateConfig) => {
27
31
  if (isQualitative && ((!config.isPaletteReversed && !isReversed) || (config.isPaletteReversed && isReversed))) {
28
32
  nonSeqPalettes.push(paletteName)
29
33
  }
34
+ if (colorblindsafe && ((!config.isPaletteReversed && !isReversed) || (config.isPaletteReversed && isReversed))) {
35
+ accessibleColors.push(paletteName)
36
+ }
30
37
  }
31
38
 
32
39
  sequential = seqPalettes
@@ -64,5 +71,6 @@ export const useColorPalette = (config, updateConfig) => {
64
71
  }, [config.isPaletteReversed])
65
72
 
66
73
  // Return all palettes
67
- return { twoColorPalettes, sequential, nonSequential }
74
+
75
+ return { twoColorPalettes, sequential, nonSequential, accessibleColors }
68
76
  }
@@ -1,22 +1,12 @@
1
- type ConfigType = {
2
- legend: {
3
- position: 'left' | 'bottom' | 'top' | 'right'
4
- singleRow?: boolean
5
- reverseLabelOrder?: boolean
6
- verticalSorted?: boolean
7
- hideBorder: {
8
- side?: boolean
9
- topBottom?: boolean
10
- }
11
- }
12
- }
1
+ import { ChartConfig } from '../types/ChartConfig'
13
2
 
14
- const useLegendClasses = (config: ConfigType) => {
3
+ const useLegendClasses = (config: ChartConfig) => {
4
+ const { position, singleRow, reverseLabelOrder, verticalSorted, hideBorder } = config.legend
15
5
  const containerClasses = ['legend-container']
16
6
  const innerClasses = ['legend-container__inner']
17
7
 
18
8
  // Handle legend positioning
19
- switch (config.legend.position) {
9
+ switch (position) {
20
10
  case 'left':
21
11
  containerClasses.push('left')
22
12
  break
@@ -34,32 +24,33 @@ const useLegendClasses = (config: ConfigType) => {
34
24
  }
35
25
 
36
26
  // Handle single row configuration for 'bottom' and 'top' positions
37
- if (['bottom', 'top'].includes(config.legend.position) && config.legend.singleRow) {
27
+ if (['bottom', 'top'].includes(position) && singleRow) {
38
28
  innerClasses.push('single-row')
39
29
  }
40
30
 
41
31
  // Reverse label order
42
- if (config.legend.reverseLabelOrder) {
32
+ if (reverseLabelOrder) {
43
33
  innerClasses.push('d-flex', 'flex-column-reverse')
44
34
  }
45
35
 
46
36
  // Vertical sorting for 'bottom' and 'top' positions
47
- if (['bottom', 'top'].includes(config.legend.position) && config.legend.verticalSorted) {
37
+ if (['bottom', 'top'].includes(position) && verticalSorted) {
48
38
  innerClasses.push('vertical-sorted')
49
39
  }
50
40
 
51
41
  // Configure border classes
52
- if (
53
- config.legend.hideBorder.side &&
54
- (['right', 'left'].includes(config.legend.position) || !config.legend.position)
55
- ) {
42
+ if (hideBorder.side && (['right', 'left'].includes(position) || !position)) {
56
43
  containerClasses.push('no-border')
57
44
  }
58
45
 
59
- if (config.legend.hideBorder.topBottom && ['top', 'bottom'].includes(config.legend.position)) {
46
+ if (hideBorder.topBottom && ['top', 'bottom'].includes(position)) {
60
47
  containerClasses.push('no-border')
61
48
  }
62
49
 
50
+ if (hideBorder.topBottom && ['top'].includes(position)) {
51
+ containerClasses.push('p-0')
52
+ }
53
+
63
54
  return {
64
55
  containerClasses,
65
56
  innerClasses
@@ -40,11 +40,13 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
40
40
  const minRequiredCIPadding = 1.15 // regardless of Editor if CI data, there must be 10% padding added
41
41
  const isLogarithmicAxis = config.yAxis.type === 'logarithmic'
42
42
  // do validation bafore applying t0 charts
43
- const isMaxValid = existPositiveValue ? enteredMaxValue >= maxValue : enteredMaxValue >= 0
44
- const isMinValid = isLogarithmicAxis ? enteredMinValue >= 0 : (enteredMinValue <= 0 && minValue >= 0) || (enteredMinValue <= minValue && minValue < 0)
43
+ const isMaxValid = existPositiveValue ? Number(enteredMaxValue) >= maxValue : Number(enteredMaxValue) >= 0
44
+ const isMinValid = isLogarithmicAxis
45
+ ? Number(enteredMinValue) >= 0
46
+ : (Number(enteredMinValue) <= 0 && minValue >= 0) || (Number(enteredMinValue) <= minValue && minValue < 0)
45
47
 
46
- min = enteredMinValue && isMinValid ? enteredMinValue : minValue
47
- max = enteredMaxValue && isMaxValid ? enteredMaxValue : Number.MIN_VALUE
48
+ min = enteredMinValue && isMinValid ? Number(enteredMinValue) : minValue
49
+ max = enteredMaxValue && isMaxValid ? Number(enteredMaxValue) : Number.MIN_VALUE
48
50
 
49
51
  const { lower, upper } = config?.confidenceKeys || {}
50
52
 
@@ -122,8 +124,8 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
122
124
  leftMax = findMaxFromSeriesKeys(data, leftAxisSeriesItems, leftMax, 'left')
123
125
  rightMax = findMaxFromSeriesKeys(data, rightAxisSeriesItems, rightMax, 'right')
124
126
 
125
- if (leftMax < enteredMaxValue) {
126
- leftMax = enteredMaxValue
127
+ if (leftMax < Number(enteredMaxValue)) {
128
+ leftMax = Number(enteredMaxValue)
127
129
  }
128
130
  } catch (e) {
129
131
  console.error(e.message)
@@ -131,10 +133,18 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
131
133
  }
132
134
 
133
135
  // this should not apply to bar charts if there is negative CI data
134
- if ((visualizationType === 'Bar' || checkLineToBarGraph() || (visualizationType === 'Combo' && !isAllLine)) && min > 0) {
136
+ if (
137
+ (visualizationType === 'Bar' || checkLineToBarGraph() || (visualizationType === 'Combo' && !isAllLine)) &&
138
+ min > 0
139
+ ) {
135
140
  min = 0
136
141
  }
137
- if ((config.visualizationType === 'Bar' || checkLineToBarGraph() || (config.visualizationType === 'Combo' && !isAllLine)) && min < 0) {
142
+ if (
143
+ (config.visualizationType === 'Bar' ||
144
+ checkLineToBarGraph() ||
145
+ (config.visualizationType === 'Combo' && !isAllLine)) &&
146
+ min < 0
147
+ ) {
138
148
  min = min * 1.1
139
149
  }
140
150
 
@@ -143,18 +153,22 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
143
153
  min = 0
144
154
  }
145
155
  if (enteredMinValue) {
146
- const isMinValid = isLogarithmicAxis ? enteredMinValue >= 0 && enteredMinValue < minValue : enteredMinValue < minValue
147
- min = enteredMinValue && isMinValid ? enteredMinValue : minValue
156
+ const isMinValid = isLogarithmicAxis
157
+ ? Number(enteredMinValue) >= 0 && Number(enteredMinValue) < minValue
158
+ : Number(enteredMinValue) < minValue
159
+ min = Number(enteredMinValue) && isMinValid ? Number(enteredMinValue) : minValue
148
160
  }
149
161
  }
150
162
 
151
163
  if (config.visualizationType === 'Deviation Bar' && min > 0) {
152
164
  const isMinValid = Number(enteredMinValue) < Math.min(minValue, Number(config.xAxis.target))
153
- min = enteredMinValue && isMinValid ? enteredMinValue : 0
165
+ min = Number(enteredMinValue) && isMinValid ? Number(enteredMinValue) : 0
154
166
  }
155
167
 
156
168
  if (config.visualizationType === 'Line' && !checkLineToBarGraph()) {
157
- const isMinValid = isLogarithmicAxis ? enteredMinValue >= 0 && enteredMinValue < minValue : enteredMinValue < minValue
169
+ const isMinValid = isLogarithmicAxis
170
+ ? Number(enteredMinValue) >= 0 && Number(enteredMinValue) < minValue
171
+ : Number(enteredMinValue) < minValue
158
172
  // update minValue for (0) Suppression points
159
173
  const suppressedMinValue = tableData?.some((dataItem, index) => {
160
174
  return config.preliminaryData?.some(pd => {
@@ -171,7 +185,7 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
171
185
  return valueMatch && (index === 0 || index === tableData.length - 1)
172
186
  })
173
187
  })
174
- min = enteredMinValue && isMinValid ? enteredMinValue : suppressedMinValue ? 0 : minValue
188
+ min = Number(enteredMinValue) && isMinValid ? Number(enteredMinValue) : suppressedMinValue ? 0 : minValue
175
189
  }
176
190
  //If data value max wasn't provided, calculate it
177
191
  if (max === Number.MIN_VALUE) {
@@ -3,12 +3,28 @@ import isNumber from '@cdc/core/helpers/isNumber'
3
3
  function useReduceData(config, data) {
4
4
  const isBar = config.series.every(({ type }) => type === 'Bar')
5
5
  const isAllLine = config.series.every(({ type }) => ['Line', 'dashed-sm', 'dashed-md', 'dashed-lg'].includes(type))
6
- const sumYValues = seriesKeys => xValue => seriesKeys.reduce((yTotal, k) => (isNaN(Number(xValue[k])) ? yTotal : yTotal + Number(xValue[k])), 0)
7
-
6
+ const sumYValues = seriesKeys => xValue =>
7
+ seriesKeys.reduce((yTotal, k) => (isNaN(Number(xValue[k])) ? yTotal : yTotal + Number(xValue[k])), 0)
8
+ const getSeriesKey = seriesKey => {
9
+ const series = config.runtime.series.find(item => item.dataKey === seriesKey)
10
+ return series?.dynamicCategory ? series.originalDataKey : seriesKey
11
+ }
8
12
  const getMaxValueFromData = () => {
9
- let max = Math.max(...data.map(d => Math.max(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : 0)))))
10
-
11
- if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && isBar)) && config.visualizationSubType === 'stacked') {
13
+ let max = Math.max(
14
+ ...data.map(d =>
15
+ Math.max(
16
+ ...config.runtime.seriesKeys.map(key => {
17
+ const seriesKey = getSeriesKey(key)
18
+ return isNumber(d[seriesKey]) ? Number(cleanChars(d[seriesKey])) : 0
19
+ })
20
+ )
21
+ )
22
+ )
23
+
24
+ if (
25
+ (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && isBar)) &&
26
+ config.visualizationSubType === 'stacked'
27
+ ) {
12
28
  const yTotals = data.map(sumYValues(config.runtime.seriesKeys)).filter(num => !isNaN(num))
13
29
  max = Math.max(...yTotals)
14
30
  }
@@ -18,15 +34,23 @@ function useReduceData(config, data) {
18
34
  max = Math.max(...yTotals)
19
35
  }
20
36
 
21
- if ((config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.series && config.series.dataKey) {
22
- max = Math.max(...data.map(d => (isNumber(d[config.series.dataKey]) ? Number(cleanChars(d[config.series.dataKey])) : 0)))
37
+ if (
38
+ (config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') &&
39
+ config.series &&
40
+ config.series.dataKey
41
+ ) {
42
+ max = Math.max(
43
+ ...data.map(d => (isNumber(d[config.series.dataKey]) ? Number(cleanChars(d[config.series.dataKey])) : 0))
44
+ )
23
45
  }
24
46
 
25
47
  if (config.visualizationType === 'Combo' && config.visualizationSubType === 'stacked' && !isBar) {
26
48
  if (config.runtime.barSeriesKeys && config.runtime.lineSeriesKeys) {
27
49
  const yTotals = data.map(sumYValues(config.runtime.barSeriesKeys))
28
50
 
29
- const lineMax = Math.max(...data.map(d => Math.max(...config.runtime.lineSeriesKeys.map(key => Number(cleanChars(d[key]))))))
51
+ const lineMax = Math.max(
52
+ ...data.map(d => Math.max(...config.runtime.lineSeriesKeys.map(key => Number(cleanChars(d[key])))))
53
+ )
30
54
  const barMax = Math.max(...yTotals)
31
55
 
32
56
  max = Math.max(barMax, lineMax)
@@ -37,7 +61,16 @@ function useReduceData(config, data) {
37
61
  }
38
62
 
39
63
  const getMinValueFromData = () => {
40
- const minNumberFromData = Math.min(...data.map(d => Math.min(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : Infinity)))))
64
+ const minNumberFromData = Math.min(
65
+ ...data.map(d =>
66
+ Math.min(
67
+ ...config.runtime.seriesKeys.map(key => {
68
+ const seriesKey = getSeriesKey(key)
69
+ return isNumber(d[seriesKey]) ? Number(cleanChars(d[seriesKey])) : Infinity
70
+ })
71
+ )
72
+ )
73
+ )
41
74
 
42
75
  return String(minNumberFromData)
43
76
  }
@@ -46,7 +79,7 @@ function useReduceData(config, data) {
46
79
  if (!config.runtime.seriesKeys) {
47
80
  return false
48
81
  }
49
- return config.runtime.seriesKeys.some(key => data.some(d => d[key] >= 0))
82
+ return config.runtime.seriesKeys.some(key => data.some(d => d[getSeriesKey(key)] >= 0))
50
83
  }
51
84
 
52
85
  const cleanChars = value => {