@cdc/chart 4.26.5 → 4.26.7

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 (128) hide show
  1. package/CONFIG.md +20 -14
  2. package/dist/{cdcchart-DQ00cQCm.es.js → cdcchart-BWVIUcAF.es.js} +5 -55
  3. package/dist/cdcchart.js +36554 -34320
  4. package/examples/feature/heatmap/average-age-categorical.json +1 -1
  5. package/examples/feature/heatmap/calendar-heatmap.json +1 -1
  6. package/examples/feature/heatmap/sparse-aggregation.json +1 -1
  7. package/examples/private/bad-y-axis.json +543 -0
  8. package/examples/private/bar-chart-negative-value.json +455 -0
  9. package/examples/private/flueview.json +22051 -0
  10. package/package.json +3 -11
  11. package/src/CdcChart.tsx +7 -6
  12. package/src/CdcChartComponent.tsx +71 -18
  13. package/src/_stories/Chart.PieLabels.stories.tsx +47 -0
  14. package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +183 -0
  15. package/src/_stories/Chart.YAxisAutoMaxStrategy.stories.tsx +52 -0
  16. package/src/_stories/Chart.YAxisFilterDomain.stories.tsx +90 -0
  17. package/src/_stories/Chart.smoke.stories.tsx +14 -1
  18. package/src/_stories/ChartAnnotation.smoke.stories.tsx +10 -0
  19. package/src/_stories/ChartPrefixSuffix.smoke.stories.tsx +28 -1
  20. package/src/_stories/_mock/annotation_event-line_mock.json +1064 -0
  21. package/src/_stories/_mock/heatmap-average-age-categorical.json +1 -1
  22. package/src/_stories/_mock/heatmap.json +1 -1
  23. package/src/components/Annotations/components/AnnotationDraggable.styles.css +22 -1
  24. package/src/components/Annotations/components/AnnotationDraggable.tsx +219 -119
  25. package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +198 -0
  26. package/src/components/Axis/LeftAxis.tsx +3 -0
  27. package/src/components/Axis/LeftAxisGridlines.tsx +8 -1
  28. package/src/components/Axis/RightAxis.tsx +3 -0
  29. package/src/components/Axis/tests/AxisTickValues.test.tsx +86 -0
  30. package/src/components/BarChart/components/BarChart.Horizontal.tsx +1 -2
  31. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +1 -1
  32. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +1 -1
  33. package/src/components/BarChart/components/BarChart.Vertical.tsx +1 -2
  34. package/src/components/BarChart/helpers/getBarData.ts +28 -28
  35. package/src/components/BarChart/helpers/getBarHeights.ts +2 -2
  36. package/src/components/BarChart/helpers/tests/useBarChart.test.tsx +98 -0
  37. package/src/components/BarChart/helpers/useBarChart.ts +4 -5
  38. package/src/components/BoxPlot/BoxPlot.Horizontal.tsx +7 -6
  39. package/src/components/BoxPlot/BoxPlot.Vertical.tsx +9 -7
  40. package/src/components/BoxPlot/helpers/index.ts +4 -3
  41. package/src/components/Brush/BrushSelector.tsx +1 -1
  42. package/src/components/EditorPanel/EditorPanel.tsx +457 -165
  43. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +101 -52
  44. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +16 -7
  45. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +3 -3
  46. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +19 -4
  47. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.test.tsx +98 -0
  48. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +10 -0
  49. package/src/components/EditorPanel/components/Panels/Panel.Visual.test.tsx +484 -0
  50. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +3 -0
  51. package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +262 -0
  52. package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +32 -0
  53. package/src/components/EditorPanel/components/panels.scss +10 -0
  54. package/src/components/EditorPanel/editor-panel.scss +47 -0
  55. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +6 -2
  56. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +20 -2
  57. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +3 -3
  58. package/src/components/EditorPanel/useEditorPermissions.test.tsx +288 -11
  59. package/src/components/EditorPanel/useEditorPermissions.ts +46 -6
  60. package/src/components/Forecasting/Forecasting.tsx +1 -1
  61. package/src/components/HeatMap/components/HeatMap.tsx +22 -17
  62. package/src/components/HeatMap/components/HeatMapGradientLegend.tsx +29 -15
  63. package/src/components/HeatMap/heatmap.css +15 -1
  64. package/src/components/HeatMap/tests/HeatMap.test.tsx +39 -7
  65. package/src/components/Legend/Legend.Component.tsx +56 -61
  66. package/src/components/Legend/Legend.Suppression.tsx +3 -3
  67. package/src/components/Legend/LegendGroup/LegendGroup.tsx +0 -1
  68. package/src/components/Legend/helpers/createFormatLabels.test.ts +88 -0
  69. package/src/components/Legend/helpers/createFormatLabels.tsx +6 -1
  70. package/src/components/LineChart/helpers.test.ts +230 -1
  71. package/src/components/LineChart/helpers.ts +25 -14
  72. package/src/components/LineChart/index.tsx +23 -7
  73. package/src/components/LinearChart/tests/LinearChart.test.tsx +30 -0
  74. package/src/components/LinearChart.tsx +51 -15
  75. package/src/components/PieChart/PieChart.tsx +117 -10
  76. package/src/components/PieChart/helpers/labelPlacement.test.ts +88 -0
  77. package/src/components/PieChart/helpers/labelPlacement.ts +95 -0
  78. package/src/components/ScatterPlot/ScatterPlot.jsx +5 -13
  79. package/src/components/SmallMultiples/SmallMultipleTile.tsx +3 -0
  80. package/src/components/SmallMultiples/SmallMultiples.tsx +38 -9
  81. package/src/components/SmallMultiples/tests/SmallMultiples.test.tsx +170 -0
  82. package/src/data/initial-state.js +3 -0
  83. package/src/helpers/calculateLeftYAxisWidth.ts +9 -3
  84. package/src/helpers/categoryOrder.ts +60 -0
  85. package/src/helpers/colorAssignmentHelpers.ts +102 -0
  86. package/src/helpers/dataHelpers.ts +11 -1
  87. package/src/helpers/getAxisMaxOverride.ts +16 -0
  88. package/src/helpers/getBoxPlotConfig.ts +19 -12
  89. package/src/helpers/getCleanTopTickMax.ts +64 -0
  90. package/src/helpers/getColorScale.ts +18 -9
  91. package/src/helpers/getComboChartConfig.ts +0 -1
  92. package/src/helpers/getExcludedData.ts +0 -1
  93. package/src/helpers/getHasBoundarySuppression.ts +27 -0
  94. package/src/helpers/getMinMax.ts +25 -22
  95. package/src/helpers/getNewRuntime.ts +0 -2
  96. package/src/helpers/getPiePercent.ts +3 -3
  97. package/src/helpers/getYAxisDomainData.ts +38 -0
  98. package/src/helpers/getYAxisFinalizationEligibility.ts +40 -0
  99. package/src/helpers/hasSpacedInlineLabel.ts +10 -0
  100. package/src/helpers/isConvertLineToBarGraph.ts +2 -2
  101. package/src/helpers/seriesColumnSettings.ts +26 -7
  102. package/src/helpers/sizeHelpers.ts +0 -2
  103. package/src/helpers/smallMultiplesHelpers.ts +5 -0
  104. package/src/helpers/tests/calculateLeftYAxisWidth.test.ts +38 -0
  105. package/src/helpers/tests/categoryOrder.test.ts +57 -0
  106. package/src/helpers/tests/dataHelpers.test.ts +135 -0
  107. package/src/helpers/tests/getAxisMaxOverride.test.ts +36 -0
  108. package/src/helpers/tests/getCleanTopTickMax.test.ts +165 -0
  109. package/src/helpers/tests/getColorScale.test.ts +197 -0
  110. package/src/helpers/tests/getMinMax.test.ts +211 -0
  111. package/src/helpers/tests/getYAxisDomainData.test.ts +119 -0
  112. package/src/helpers/tests/getYAxisFinalizationEligibility.test.ts +185 -0
  113. package/src/helpers/tests/{getYAxisAutoPaddingMode.test.ts → hasSpacedInlineLabel.test.ts} +17 -32
  114. package/src/helpers/tests/seriesColumnSettings.test.ts +76 -2
  115. package/src/helpers/tests/smallMultiplesHelpers.test.ts +99 -0
  116. package/src/hooks/tests/useRightAxis.test.tsx +268 -0
  117. package/src/hooks/tests/useScales.test.tsx +302 -27
  118. package/src/hooks/tests/useTooltip.test.tsx +132 -0
  119. package/src/hooks/useRightAxis.ts +35 -25
  120. package/src/hooks/useScales.ts +45 -28
  121. package/src/hooks/useTooltip.tsx +17 -11
  122. package/src/store/chart.reducer.ts +0 -1
  123. package/src/test/CdcChart.dataTable.test.tsx +216 -0
  124. package/src/types/ChartConfig.ts +6 -1
  125. package/src/types/ChartContext.ts +3 -0
  126. package/src/helpers/getYAxisAutoPadding.ts +0 -55
  127. package/src/helpers/getYAxisAutoPaddingMode.ts +0 -17
  128. package/src/helpers/tests/getYAxisAutoPadding.test.ts +0 -37
@@ -28,6 +28,7 @@ interface LeftAxisProps {
28
28
  xMax: number
29
29
  yAxisWidth: number
30
30
  numTicks: number
31
+ tickValues?: number[]
31
32
  tickLabelFontSize: number
32
33
  axisLabelFontSize: number
33
34
  handleLeftTickFormatting: (tick: any, index: number, ticks: any[]) => string
@@ -45,6 +46,7 @@ const LeftAxis: React.FC<LeftAxisProps> = ({
45
46
  xMax,
46
47
  yAxisWidth,
47
48
  numTicks,
49
+ tickValues,
48
50
  tickLabelFontSize,
49
51
  axisLabelFontSize,
50
52
  handleLeftTickFormatting,
@@ -71,6 +73,7 @@ const LeftAxis: React.FC<LeftAxisProps> = ({
71
73
  stroke='#333'
72
74
  tickFormat={handleLeftTickFormatting}
73
75
  numTicks={numTicks}
76
+ {...(tickValues ? { tickValues } : {})}
74
77
  >
75
78
  {props => {
76
79
  const axisCenter =
@@ -10,6 +10,7 @@ interface LeftAxisGridlinesProps {
10
10
  xMax: number
11
11
  yAxisWidth: number
12
12
  numTicks: number
13
+ tickValues?: number[]
13
14
  axisLabelFontSize: number
14
15
  }
15
16
 
@@ -18,6 +19,7 @@ const LeftAxisGridlines: React.FC<LeftAxisGridlinesProps> = ({
18
19
  xMax,
19
20
  yAxisWidth,
20
21
  numTicks,
22
+ tickValues,
21
23
  axisLabelFontSize
22
24
  }) => {
23
25
  const { config } = useContext(ConfigContext)
@@ -27,7 +29,12 @@ const LeftAxisGridlines: React.FC<LeftAxisGridlinesProps> = ({
27
29
  const showSideTitle = config.yAxis.titlePlacement !== 'top'
28
30
 
29
31
  return (
30
- <AxisLeft scale={yScale} left={yAxisWidth - config.yAxis.axisPadding} numTicks={numTicks}>
32
+ <AxisLeft
33
+ scale={yScale}
34
+ left={yAxisWidth - config.yAxis.axisPadding}
35
+ numTicks={numTicks}
36
+ {...(tickValues ? { tickValues } : {})}
37
+ >
31
38
  {props => {
32
39
  const axisCenter =
33
40
  config.orientation === 'horizontal'
@@ -15,6 +15,7 @@ type RightAxisProps = {
15
15
  yMax: number
16
16
  xMax: number
17
17
  yAxisWidth: number
18
+ tickValues?: number[]
18
19
  tickLabelFontSize: number
19
20
  axisLabelFontSize: number
20
21
  }
@@ -29,6 +30,7 @@ export const RightAxis: React.FC<RightAxisProps> = ({
29
30
  yMax,
30
31
  xMax,
31
32
  yAxisWidth,
33
+ tickValues,
32
34
  tickLabelFontSize,
33
35
  axisLabelFontSize
34
36
  }) => {
@@ -45,6 +47,7 @@ export const RightAxis: React.FC<RightAxisProps> = ({
45
47
  label={config.yAxis.rightLabel}
46
48
  tickFormat={tick => formatNumber(tick, 'right')}
47
49
  numTicks={runtime.yAxis.rightNumTicks || undefined}
50
+ {...(tickValues ? { tickValues } : {})}
48
51
  labelOffset={45}
49
52
  >
50
53
  {props => {
@@ -0,0 +1,86 @@
1
+ import React from 'react'
2
+ import { render, screen } from '@testing-library/react'
3
+ import { describe, expect, it, vi } from 'vitest'
4
+ import ConfigContext from '../../../ConfigContext'
5
+ import { createMockChartContext, createMockConfig } from '../../LinearChart/tests/mockConfigContext'
6
+
7
+ vi.mock('@visx/axis', () => ({
8
+ AxisLeft: ({ tickValues }: { tickValues?: number[] }) => (
9
+ <div data-testid='axis-left' data-tick-values={JSON.stringify(tickValues ?? null)} />
10
+ ),
11
+ AxisRight: ({ tickValues }: { tickValues?: number[] }) => (
12
+ <div data-testid='axis-right' data-tick-values={JSON.stringify(tickValues ?? null)} />
13
+ )
14
+ }))
15
+
16
+ import LeftAxis from '../LeftAxis'
17
+ import LeftAxisGridlines from '../LeftAxisGridlines'
18
+ import RightAxis from '../RightAxis'
19
+
20
+ const tickValues = [0, 5, 10, 15]
21
+
22
+ const renderWithContext = (children: React.ReactNode) => {
23
+ const config = createMockConfig({
24
+ runtime: {
25
+ ...createMockConfig().runtime,
26
+ yAxis: {
27
+ ...createMockConfig().runtime.yAxis,
28
+ rightNumTicks: 4
29
+ }
30
+ } as any
31
+ })
32
+
33
+ return render(<ConfigContext.Provider value={createMockChartContext(config)}>{children}</ConfigContext.Provider>)
34
+ }
35
+
36
+ describe('axis tick values', () => {
37
+ it('passes supplied tick values to the left axis', () => {
38
+ renderWithContext(
39
+ <LeftAxis
40
+ yScale={{}}
41
+ xScale={{}}
42
+ yMax={100}
43
+ xMax={300}
44
+ yAxisWidth={50}
45
+ numTicks={4}
46
+ tickValues={tickValues}
47
+ tickLabelFontSize={16}
48
+ axisLabelFontSize={16}
49
+ handleLeftTickFormatting={tick => String(tick)}
50
+ />
51
+ )
52
+
53
+ expect(JSON.parse(screen.getByTestId('axis-left').dataset.tickValues || 'null')).toEqual(tickValues)
54
+ })
55
+
56
+ it('passes supplied tick values to left-axis gridlines', () => {
57
+ renderWithContext(
58
+ <LeftAxisGridlines
59
+ yScale={{}}
60
+ xMax={300}
61
+ yAxisWidth={50}
62
+ numTicks={4}
63
+ tickValues={tickValues}
64
+ axisLabelFontSize={16}
65
+ />
66
+ )
67
+
68
+ expect(JSON.parse(screen.getByTestId('axis-left').dataset.tickValues || 'null')).toEqual(tickValues)
69
+ })
70
+
71
+ it('passes supplied tick values to the right axis', () => {
72
+ renderWithContext(
73
+ <RightAxis
74
+ yScaleRight={{} as any}
75
+ yMax={100}
76
+ xMax={300}
77
+ yAxisWidth={50}
78
+ tickValues={tickValues}
79
+ tickLabelFontSize={16}
80
+ axisLabelFontSize={16}
81
+ />
82
+ )
83
+
84
+ expect(JSON.parse(screen.getByTestId('axis-right').dataset.tickValues || 'null')).toEqual(tickValues)
85
+ })
86
+ })
@@ -21,7 +21,6 @@ import isNumber from '@cdc/core/helpers/isNumber'
21
21
  // Local context and types
22
22
  import BarChartContext, { BarChartContextValues } from './context'
23
23
  import { ChartContext } from '../../../types/ChartContext'
24
- import _ from 'lodash'
25
24
  import { getBarData } from '../helpers/getBarData'
26
25
  import { getHorizontalBarHeights } from '../helpers/getBarHeights'
27
26
  import { getPatternUrl as getPatternUrlForBar } from '../helpers/getPatternUrl'
@@ -76,7 +75,7 @@ const BarChartHorizontal = () => {
76
75
  <defs>
77
76
  {Object.entries(config.legend.patterns).map(([key, pattern]) => {
78
77
  const patternId = getChartPatternId(key)
79
- const size = pattern.patternSize || 8
78
+ const size = pattern.patternSize || 10
80
79
 
81
80
  switch (pattern.shape) {
82
81
  case 'circles':
@@ -59,7 +59,7 @@ const BarChartStackedHorizontal = () => {
59
59
  <defs>
60
60
  {Object.entries(config.legend.patterns).map(([key, pattern]) => {
61
61
  const patternId = getChartPatternId(key)
62
- const size = pattern.patternSize || 8
62
+ const size = pattern.patternSize || 10
63
63
 
64
64
  switch (pattern.shape) {
65
65
  case 'circles':
@@ -44,7 +44,7 @@ const BarChartStackedVertical = () => {
44
44
  <defs>
45
45
  {Object.entries(config.legend.patterns).map(([key, pattern]) => {
46
46
  const patternId = getChartPatternId(key)
47
- const size = pattern.patternSize || 8
47
+ const size = pattern.patternSize || 10
48
48
 
49
49
  switch (pattern.shape) {
50
50
  case 'circles':
@@ -19,7 +19,6 @@ import createBarElement from '@cdc/core/components/createBarElement'
19
19
  import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
20
20
  // Types
21
21
  import { type ChartContext } from '../../../types/ChartContext'
22
- import _ from 'lodash'
23
22
  import { getBarData } from '../helpers/getBarData'
24
23
  import { getPatternUrl as getPatternUrlForBar } from '../helpers/getPatternUrl'
25
24
  import { getChartPatternId } from '../../../helpers/getChartPatternId'
@@ -90,7 +89,7 @@ const BarChartVertical = () => {
90
89
  <defs>
91
90
  {Object.entries(config.legend.patterns).map(([key, pattern]) => {
92
91
  const patternId = getChartPatternId(key)
93
- const size = pattern.patternSize || 8
92
+ const size = pattern.patternSize || 10
94
93
 
95
94
  switch (pattern.shape) {
96
95
  case 'circles':
@@ -1,28 +1,28 @@
1
- import _ from 'lodash'
2
- import { TransformedData } from '../../../types/ChartContext'
3
- import { ChartConfig } from '../../../types/ChartConfig'
4
-
5
- export const getBarData = (config: ChartConfig, data: TransformedData[], hasConfidenceInterval: boolean) => {
6
- const dynamicSeries = config.series.find(s => s.dynamicCategory)
7
- if (!dynamicSeries) return data
8
- const { dynamicCategory, dataKey } = dynamicSeries
9
- const xAxisKey = config.runtime.originalXAxis.dataKey
10
- const xAxisGroupDataLookup = _.groupBy(data, xAxisKey)
11
- return Object.values(xAxisGroupDataLookup).map(group => {
12
- return group.reduce((acc, datum) => {
13
- const dataValue = datum[dataKey]
14
- const dataCategory = datum[dynamicCategory]
15
- if (hasConfidenceInterval) {
16
- const { lower, upper } = config.confidenceKeys
17
- if (!acc.CI) acc.CI = {}
18
- const lowerValue = datum[lower]
19
- const upperValue = datum[upper]
20
- acc.CI[dataCategory] = { lower: lowerValue, upper: upperValue }
21
- }
22
- acc[dataCategory] = dataValue
23
- acc[xAxisKey] = datum[xAxisKey]
24
- acc.dynamicData = true
25
- return acc
26
- }, {})
27
- })
28
- }
1
+ import groupBy from 'lodash/groupBy'
2
+ import { TransformedData } from '../../../types/ChartContext'
3
+ import { ChartConfig } from '../../../types/ChartConfig'
4
+
5
+ export const getBarData = (config: ChartConfig, data: TransformedData[], hasConfidenceInterval: boolean) => {
6
+ const dynamicSeries = config.series.find(s => s.dynamicCategory)
7
+ if (!dynamicSeries) return data
8
+ const { dynamicCategory, dataKey } = dynamicSeries
9
+ const xAxisKey = config.runtime.originalXAxis.dataKey
10
+ const xAxisGroupDataLookup = groupBy(data, xAxisKey)
11
+ return Object.values(xAxisGroupDataLookup).map(group => {
12
+ return group.reduce((acc, datum) => {
13
+ const dataValue = datum[dataKey]
14
+ const dataCategory = datum[dynamicCategory]
15
+ if (hasConfidenceInterval) {
16
+ const { lower, upper } = config.confidenceKeys
17
+ if (!acc.CI) acc.CI = {}
18
+ const lowerValue = datum[lower]
19
+ const upperValue = datum[upper]
20
+ acc.CI[dataCategory] = { lower: lowerValue, upper: upperValue }
21
+ }
22
+ acc[dataCategory] = dataValue
23
+ acc[xAxisKey] = datum[xAxisKey]
24
+ acc.dynamicData = true
25
+ return acc
26
+ }, {})
27
+ })
28
+ }
@@ -1,5 +1,5 @@
1
1
  import { APP_FONT_SIZE } from '@cdc/core/helpers/constants'
2
- import _ from 'lodash'
2
+ import round from 'lodash/round'
3
3
  import { ChartConfig } from '../../../types/ChartConfig'
4
4
 
5
5
  export const getHorizontalBarHeights = <T>(config: Partial<ChartConfig>, bars: (T & { index })[]) => {
@@ -41,7 +41,7 @@ export const getHorizontalBarHeights = <T>(config: Partial<ChartConfig>, bars: (
41
41
  // return new updated bars/groupes
42
42
  return bars.map((bar, i) => {
43
43
  // set bars Y dynamically to handle space between bars
44
- const y = bar.index === 0 ? 0 : _.round(totalBarHeight * i)
44
+ const y = bar.index === 0 ? 0 : round(totalBarHeight * i)
45
45
  return { ...bar, y, height: barHeight }
46
46
  })
47
47
  }
@@ -0,0 +1,98 @@
1
+ import { renderHook } from '@testing-library/react'
2
+ import { describe, expect, it, vi } from 'vitest'
3
+ import { createMockChartContext, createMockConfig } from '../../../LinearChart/tests/mockConfigContext'
4
+ import { useBarChart } from '../useBarChart'
5
+
6
+ const baseConfig = createMockConfig()
7
+
8
+ const makeConfigContext = (countColumnOverrides: Record<string, unknown> = {}) => {
9
+ const config = createMockConfig({
10
+ visualizationType: 'Bar',
11
+ orientation: 'horizontal',
12
+ barHeight: 25,
13
+ xAxis: {
14
+ ...baseConfig.xAxis,
15
+ type: 'categorical',
16
+ dataKey: 'Cause of death'
17
+ },
18
+ yAxis: {
19
+ ...baseConfig.yAxis,
20
+ labelPlacement: 'Below Bar'
21
+ },
22
+ series: [{ dataKey: 'Percentage', type: 'Bar', axis: 'Left', tooltip: true }] as any,
23
+ columns: {
24
+ Count: {
25
+ name: 'Count',
26
+ label: 'Count',
27
+ prefix: '',
28
+ suffix: '',
29
+ roundToPlace: 0,
30
+ commas: true,
31
+ dataTable: true,
32
+ tooltips: true,
33
+ ...countColumnOverrides
34
+ }
35
+ } as any,
36
+ dataFormat: {
37
+ abbreviated: false,
38
+ bottomAbbreviated: false,
39
+ bottomPrefix: '',
40
+ bottomRoundTo: 0,
41
+ bottomSuffix: '',
42
+ bottomCommas: false,
43
+ commas: false,
44
+ prefix: '',
45
+ preserveOriginalDecimals: false,
46
+ rightPrefix: '',
47
+ rightRoundTo: 0,
48
+ rightSuffix: '',
49
+ roundTo: 1,
50
+ suffix: '%'
51
+ } as any,
52
+ runtime: {
53
+ ...baseConfig.runtime,
54
+ xAxis: {
55
+ ...baseConfig.runtime.xAxis,
56
+ type: 'categorical',
57
+ dataKey: 'Cause of death'
58
+ },
59
+ yAxis: {
60
+ ...baseConfig.runtime.yAxis,
61
+ dataKey: 'Percentage'
62
+ },
63
+ series: [{ dataKey: 'Percentage', type: 'Bar', axis: 'Left', tooltip: true }],
64
+ seriesKeys: ['Percentage'],
65
+ seriesLabels: { Percentage: 'Percentage' },
66
+ seriesLabelsAll: ['Percentage']
67
+ } as any
68
+ })
69
+
70
+ return createMockChartContext(config, {
71
+ tableData: [
72
+ {
73
+ 'Cause of death': 'Cardiovascular conditions',
74
+ Percentage: 22,
75
+ Count: 146
76
+ }
77
+ ],
78
+ updateConfig: vi.fn()
79
+ })
80
+ }
81
+
82
+ describe('useBarChart', () => {
83
+ it('does not apply the left-axis suffix to an additional single-series tooltip column', () => {
84
+ const configContext = makeConfigContext()
85
+ const { result } = renderHook(() => useBarChart(vi.fn(), vi.fn(), configContext))
86
+
87
+ expect(result.current.getAdditionalColumn('Percentage', 'Cardiovascular conditions')).toBe('Count : 146 <br/>')
88
+ })
89
+
90
+ it('applies an additional column suffix when one is configured', () => {
91
+ const configContext = makeConfigContext({ suffix: ' deaths' })
92
+ const { result } = renderHook(() => useBarChart(vi.fn(), vi.fn(), configContext))
93
+
94
+ expect(result.current.getAdditionalColumn('Percentage', 'Cardiovascular conditions')).toBe(
95
+ 'Count : 146 deaths <br/>'
96
+ )
97
+ })
98
+ })
@@ -6,7 +6,7 @@ import { getPaletteColors } from '@cdc/core/helpers/palettes/utils'
6
6
  import { publishAnalyticsEvent } from '@cdc/core/helpers/metrics/helpers'
7
7
  import { getVizSubType, getVizTitle } from '@cdc/core/helpers/metrics/utils'
8
8
  import { isMobileFontViewport } from '@cdc/core/helpers/viewports'
9
- import { getSeriesOwnedColumnNames } from '../../../helpers/seriesColumnSettings'
9
+ import { getSeriesColumnFormattingParams, getSeriesOwnedColumnNames } from '../../../helpers/seriesColumnSettings'
10
10
 
11
11
  export const useBarChart = (handleTooltipMouseOver, handleTooltipMouseOff, configContext) => {
12
12
  const {
@@ -184,10 +184,9 @@ export const useBarChart = (handleTooltipMouseOver, handleTooltipMouseOff, confi
184
184
  if (seriesOwnedColumnNames.includes(colConfig.name || colKeys)) return
185
185
  if (series && colConfig.series && colConfig.series !== series && !colConfig.tooltips) return
186
186
  const formattingParams = {
187
- addColPrefix: config.columns[colKeys].prefix,
188
- addColSuffix: config.columns[colKeys].suffix,
189
- addColRoundTo: config.columns[colKeys].roundToPlace ? config.columns[colKeys].roundToPlace : '',
190
- addColCommas: config.columns[colKeys].commas
187
+ addColPrefix: '',
188
+ addColSuffix: '',
189
+ ...getSeriesColumnFormattingParams(config.columns[colKeys])
191
190
  }
192
191
 
193
192
  const formattedValue = formatColNumber(
@@ -5,7 +5,8 @@ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
5
5
  import ConfigContext from '../../ConfigContext'
6
6
  import { handleTooltip, createPlots } from './helpers/index'
7
7
  import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
8
- import _ from 'lodash'
8
+ import map from 'lodash/map'
9
+ import round from 'lodash/round'
9
10
 
10
11
  const BoxPlotHorizontal = ({ xScale, yScale, seriesScale }) => {
11
12
  const { config, transformedData: data, colorScale, seriesHighlight } = useContext(ConfigContext)
@@ -63,7 +64,7 @@ const BoxPlotHorizontal = ({ xScale, yScale, seriesScale }) => {
63
64
  maxProps={{ stroke: defaultColor, strokeWidth: 1, opacity: fillOpacity }}
64
65
  medianProps={{ stroke: defaultColor, strokeWidth: 1, opacity: fillOpacity }}
65
66
  outliers={
66
- config.boxplot.plotOutlierValues ? _.map(plot.columnOutliers[item.dataKey], item => item) : []
67
+ config.boxplot.plotOutlierValues ? map(plot.columnOutliers[item.dataKey], item => item) : []
67
68
  }
68
69
  outlierProps={{
69
70
  style: {
@@ -78,10 +79,10 @@ const BoxPlotHorizontal = ({ xScale, yScale, seriesScale }) => {
78
79
  config.boxplot,
79
80
  plot.columnCategory,
80
81
  item.dataKey,
81
- _.round(plot.q1[item.dataKey], config.dataFormat.roundTo),
82
- _.round(plot.q3[item.dataKey], config.dataFormat.roundTo),
83
- _.round(plot.median[item.dataKey], config.dataFormat.roundTo),
84
- _.round(plot.iqr[item.dataKey], config.dataFormat.roundTo),
82
+ round(plot.q1[item.dataKey], config.dataFormat.roundTo),
83
+ round(plot.q3[item.dataKey], config.dataFormat.roundTo),
84
+ round(plot.median[item.dataKey], config.dataFormat.roundTo),
85
+ round(plot.iqr[item.dataKey], config.dataFormat.roundTo),
85
86
  config.xAxis.label,
86
87
  defaultColor
87
88
  ),
@@ -7,7 +7,9 @@ import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
7
7
  import { getCurrentPaletteName } from '@cdc/core/helpers/palettes/utils'
8
8
  import { handleTooltip, createPlots } from './helpers/index'
9
9
  import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
10
- import _ from 'lodash'
10
+ import get from 'lodash/get'
11
+ import map from 'lodash/map'
12
+ import round from 'lodash/round'
11
13
 
12
14
  const BoxPlotVertical = ({ xScale, yScale, seriesScale, yAxisWidth }) => {
13
15
  const { config, colorScale, seriesHighlight, transformedData: data } = useContext(ConfigContext)
@@ -19,7 +21,7 @@ const BoxPlotVertical = ({ xScale, yScale, seriesScale, yAxisWidth }) => {
19
21
  const bodyStyles = getComputedStyle(document.body)
20
22
  const defaultColor = APP_FONT_COLOR
21
23
  const constrainedWidth = Math.min(40, boxWidth)
22
- const color_0 = _.get(colorPalettesChart, [getCurrentPaletteName(config), 0], '#000')
24
+ const color_0 = get(colorPalettesChart, [getCurrentPaletteName(config), 0], '#000')
23
25
  const plots = createPlots(data, config)
24
26
  return (
25
27
  <ErrorBoundary component='BoxPlot Vertical'>
@@ -76,7 +78,7 @@ const BoxPlotVertical = ({ xScale, yScale, seriesScale, yAxisWidth }) => {
76
78
  fillOpacity={1}
77
79
  stroke={defaultColor}
78
80
  valueScale={yScale}
79
- outliers={boxplot.plotOutlierValues ? _.map(d.columnOutliers[item.dataKey], item => item) : []}
81
+ outliers={boxplot.plotOutlierValues ? map(d.columnOutliers[item.dataKey], item => item) : []}
80
82
  outlierProps={{
81
83
  style: {
82
84
  fill: defaultColor,
@@ -109,10 +111,10 @@ const BoxPlotVertical = ({ xScale, yScale, seriesScale, yAxisWidth }) => {
109
111
  boxplot,
110
112
  d.columnCategory,
111
113
  item.dataKey,
112
- _.round(d.q1[item.dataKey], config.dataFormat.roundTo),
113
- _.round(d.q3[item.dataKey], config.dataFormat.roundTo),
114
- _.round(d.median[item.dataKey], config.dataFormat.roundTo),
115
- _.round(d.iqr[item.dataKey], config.dataFormat.roundTo),
114
+ round(d.q1[item.dataKey], config.dataFormat.roundTo),
115
+ round(d.q3[item.dataKey], config.dataFormat.roundTo),
116
+ round(d.median[item.dataKey], config.dataFormat.roundTo),
117
+ round(d.iqr[item.dataKey], config.dataFormat.roundTo),
116
118
  config.xAxis.label,
117
119
  defaultColor
118
120
  ),
@@ -1,4 +1,5 @@
1
- import _ from 'lodash'
1
+ import sortBy from 'lodash/sortBy'
2
+ import uniq from 'lodash/uniq'
2
3
  import * as d3 from 'd3-array'
3
4
 
4
5
  interface Plot {
@@ -33,7 +34,7 @@ const calculateBoxPlotStats = (values: number[]) => {
33
34
  if (!values || values.length === 0) return {}
34
35
 
35
36
  // Sort the values
36
- const sortedValues = _.sortBy(values.map(v => Number(v)))
37
+ const sortedValues = sortBy(values.map(v => Number(v)))
37
38
 
38
39
  // Quartiles
39
40
  const firstQuartile = d3.quantile(sortedValues, 0.25) ?? 0
@@ -103,7 +104,7 @@ const calculateNonOutliers = (values: number[], firstQuartile: number, thirdQuar
103
104
  export const createPlots = (data, config) => {
104
105
  const dataKeys = data.map(d => d[config.xAxis.dataKey])
105
106
  const plots: Plot[] = []
106
- const groups: string[] = _.uniq(dataKeys)
107
+ const groups: string[] = uniq(dataKeys)
107
108
 
108
109
  if (groups && groups.length > 0) {
109
110
  groups.forEach(group => {
@@ -128,7 +128,7 @@ const BrushSelector: FC<BrushSelectorProps> = ({ xMax, yMax }) => {
128
128
  <>
129
129
  {Object.entries(config.legend.patterns).map(([key, pattern]) => {
130
130
  const patternId = getChartPatternId(key)
131
- const size = pattern.patternSize || 8
131
+ const size = pattern.patternSize || 10
132
132
 
133
133
  switch (pattern.shape) {
134
134
  case 'circles':