@cdc/chart 4.23.6 → 4.23.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/cdcchart.js +29981 -29995
  2. package/examples/feature/__data__/area-chart-date-apple.json +5122 -0
  3. package/examples/feature/__data__/city-temperature.json +2198 -0
  4. package/examples/feature/__data__/planet-example-data.json +1 -1
  5. package/examples/feature/area/area-chart-category.json +45 -45
  6. package/examples/feature/area/area-chart-date-apple.json +10376 -0
  7. package/examples/feature/area/area-chart-date-city-temperature.json +4528 -0
  8. package/examples/feature/area/area-chart-date.json +111 -3
  9. package/examples/feature/combo/right-issues.json +1 -1
  10. package/examples/feature/forecasting/combo-forecasting.json +72 -46
  11. package/examples/feature/forecasting/effective_reproduction.json +57 -8
  12. package/examples/feature/forecasting/forecasting.json +12 -3
  13. package/examples/feature/forest-plot/broken.json +700 -0
  14. package/examples/feature/forest-plot/data.csv +24 -0
  15. package/examples/feature/forest-plot/forest-plot.json +717 -0
  16. package/examples/feature/line/line-chart.json +11 -11
  17. package/examples/feature/pie/planet-pie-example-config.json +1 -1
  18. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +167 -20
  19. package/examples/private/confidence_interval_test.json +248 -0
  20. package/examples/private/tooltip-issue.json +45275 -0
  21. package/index.html +13 -11
  22. package/package.json +4 -3
  23. package/src/CdcChart.jsx +78 -27
  24. package/src/components/AreaChart.jsx +65 -151
  25. package/src/components/BarChart.Horizontal.jsx +251 -0
  26. package/src/components/BarChart.StackedHorizontal.jsx +118 -0
  27. package/src/components/BarChart.StackedVertical.jsx +93 -0
  28. package/src/components/BarChart.Vertical.jsx +204 -0
  29. package/src/components/BarChart.jsx +17 -667
  30. package/src/components/BarChartType.jsx +15 -0
  31. package/src/components/BrushHandle.jsx +17 -0
  32. package/src/components/DataTable.jsx +67 -22
  33. package/src/components/EditorPanel.jsx +426 -358
  34. package/src/components/Forecasting.jsx +23 -86
  35. package/src/components/ForestPlot.jsx +191 -0
  36. package/src/components/ForestPlotSettings.jsx +508 -0
  37. package/src/components/Legend.jsx +10 -8
  38. package/src/components/LineChart.jsx +31 -6
  39. package/src/components/LinearChart.jsx +317 -230
  40. package/src/components/Series.jsx +40 -4
  41. package/src/data/initial-state.js +50 -3
  42. package/src/hooks/useBarChart.js +186 -0
  43. package/src/hooks/useEditorPermissions.js +218 -0
  44. package/src/hooks/useMinMax.js +18 -5
  45. package/src/hooks/useRightAxis.js +2 -1
  46. package/src/hooks/useScales.js +45 -2
  47. package/src/hooks/useTooltip.jsx +407 -0
  48. package/src/scss/main.scss +11 -17
@@ -248,7 +248,7 @@ const SeriesDropdownConfidenceInterval = props => {
248
248
 
249
249
  return (
250
250
  <div className='edit-block'>
251
- <h3>Confidence Interval Groups</h3>
251
+ <span className='edit-label column-heading'>Confidence Interval Groups</span>
252
252
  <fieldset>
253
253
  <Accordion allowZeroExpanded>
254
254
  {series?.confidenceIntervals?.map((ciGroup, ciIndex) => {
@@ -290,7 +290,7 @@ const SeriesDropdownConfidenceInterval = props => {
290
290
  </>
291
291
  </AccordionItemHeading>
292
292
  <AccordionItemPanel>
293
- <div className='input-group'>
293
+ {/* <div className='input-group'>
294
294
  <label htmlFor='showInTooltip'>Show In Tooltip</label>
295
295
  <div className={'cove-input__checkbox--small'} onClick={e => updateShowInTooltip(e, index, ciIndex)}>
296
296
  <div className={`cove-input__checkbox-box${'blue' ? ' custom-color' : ''}`} style={{ backgroundColor: '' }}>
@@ -298,7 +298,7 @@ const SeriesDropdownConfidenceInterval = props => {
298
298
  </div>
299
299
  <input className='cove-input--hidden' type='checkbox' name={'showInTooltip'} checked={showInTooltip ? showInTooltip : false} readOnly />
300
300
  </div>
301
- </div>
301
+ </div> */}
302
302
 
303
303
  <InputSelect
304
304
  initial='Select an option'
@@ -400,6 +400,38 @@ const SeriesInputName = props => {
400
400
  )
401
401
  }
402
402
 
403
+ const SeriesDisplayInTooltip = props => {
404
+ const { series, index } = props
405
+ const { config, updateConfig } = useContext(ConfigContext)
406
+
407
+ const toggleTooltip = seriesIndex => {
408
+ let copiedSeries = [...config.series]
409
+
410
+ const showInTooltip = copiedSeries[seriesIndex].tooltip ? copiedSeries[seriesIndex].tooltip : false
411
+
412
+ copiedSeries[seriesIndex].tooltip = !copiedSeries[seriesIndex].tooltip
413
+
414
+ updateConfig({
415
+ ...config,
416
+ series: copiedSeries
417
+ })
418
+ }
419
+
420
+ return (
421
+ <>
422
+ <div className='input-group'>
423
+ <label htmlFor={`series-tooltip--${index}`}>Show In Tooltip</label>
424
+ <div className={'cove-input__checkbox--small'} onClick={e => toggleTooltip(index)}>
425
+ <div className={`cove-input__checkbox-box${'blue' ? ' custom-color' : ''}`} style={{ backgroundColor: '' }}>
426
+ {series.tooltip && <Check className='' style={{ fill: '#025eaa' }} />}
427
+ </div>
428
+ <input className='cove-input--hidden' type='checkbox' name={`series-tooltip--${index}`} checked={series.tooltip ? series.tooltip : false} readOnly />
429
+ </div>
430
+ </div>
431
+ </>
432
+ )
433
+ }
434
+
403
435
  const SeriesButtonRemove = props => {
404
436
  const { config, updateConfig } = useContext(ConfigContext)
405
437
  const { series, index } = props
@@ -474,9 +506,10 @@ const SeriesItem = props => {
474
506
  <Series.Dropdown.SeriesType series={series} index={i} />
475
507
  <Series.Dropdown.AxisPosition series={series} index={i} />
476
508
  <Series.Dropdown.LineType series={series} index={i} />
477
- <Series.Dropdown.ForecastingStage series={series} index={i} />
509
+ {/* <Series.Dropdown.ForecastingStage series={series} index={i} /> */}
478
510
  <Series.Dropdown.ForecastingColor series={series} index={i} />
479
511
  <Series.Dropdown.ConfidenceInterval series={series} index={i} />
512
+ <Series.Checkbox.DisplayInTooltip series={series} index={i} />
480
513
  </AccordionItemPanel>
481
514
  )}
482
515
  </AccordionItem>
@@ -508,6 +541,9 @@ const Series = {
508
541
  Input: {
509
542
  Name: SeriesInputName
510
543
  },
544
+ Checkbox: {
545
+ DisplayInTooltip: SeriesDisplayInTooltip
546
+ },
511
547
  Button: {
512
548
  Remove: SeriesButtonRemove
513
549
  },
@@ -1,8 +1,10 @@
1
1
  export default {
2
2
  type: 'chart',
3
+ debugSvg: false,
3
4
  title: '',
4
5
  showTitle: true,
5
6
  showDownloadMediaButton: false,
7
+ showChartBrush: false,
6
8
  theme: 'theme-blue',
7
9
  animate: false,
8
10
  fontSize: 'medium',
@@ -15,6 +17,7 @@ export default {
15
17
  barStyle: '',
16
18
  roundingStyle: 'standard',
17
19
  tipRounding: 'top',
20
+ isResponsiveTicks: false,
18
21
  general: {
19
22
  showDownloadButton: false
20
23
  },
@@ -36,7 +39,7 @@ export default {
36
39
  tickLabelColor: '#333',
37
40
  tickColor: '#333',
38
41
  rightHideAxis: true,
39
- rightAxisSize: 50,
42
+ rightAxisSize: 0,
40
43
  rightLabel: '',
41
44
  rightLabelOffsetSize: 0,
42
45
  rightAxisLabelColor: '#333',
@@ -107,7 +110,7 @@ export default {
107
110
  labelOffset: 65,
108
111
  axisPadding: 0,
109
112
  target: 0,
110
- anchors: []
113
+ maxTickRotation: 0
111
114
  },
112
115
  table: {
113
116
  label: 'Data Table',
@@ -169,5 +172,49 @@ export default {
169
172
  useLogScale: false,
170
173
  filterBehavior: 'Filter Change',
171
174
  highlightedBarValues: [],
172
- series: []
175
+ series: [],
176
+ tooltips: {
177
+ opacity: 90
178
+ },
179
+ forestPlot: {
180
+ startAt: 0,
181
+ width: 'auto',
182
+ colors: {
183
+ line: '',
184
+ shape: ''
185
+ },
186
+ estimateField: '',
187
+ estimateRadius: '',
188
+ lowerCiField: '',
189
+ upperCiField: '',
190
+ shape: '',
191
+ rowHeight: 20,
192
+ showZeroLine: false,
193
+ description: {
194
+ show: true,
195
+ text: 'description',
196
+ location: 0
197
+ },
198
+ result: {
199
+ show: true,
200
+ text: 'result',
201
+ location: 100
202
+ },
203
+ radius: {
204
+ min: 1,
205
+ max: 8,
206
+ scalingColumn: ''
207
+ },
208
+ regression: {
209
+ lower: 0,
210
+ upper: 0,
211
+ estimateField: 0
212
+ },
213
+ leftWidthOffset: 0,
214
+ rightWidthOffset: 0
215
+ },
216
+ brush: {
217
+ pattern_id: 'brush_pattern',
218
+ accent_color: '#ddd'
219
+ }
173
220
  }
@@ -0,0 +1,186 @@
1
+ import React, { useContext, useEffect } from 'react'
2
+ import ConfigContext from '../ConfigContext'
3
+
4
+ export const useBarChart = () => {
5
+ const { config, colorPalettes, tableData, updateConfig, parseDate, formatDate } = useContext(ConfigContext)
6
+ const { orientation } = config
7
+
8
+ const isHorizontal = orientation === 'horizontal'
9
+ const barBorderWidth = 1
10
+ const lollipopBarWidth = config.lollipopSize === 'large' ? 7 : config.lollipopSize === 'medium' ? 6 : 5
11
+ const lollipopShapeSize = config.lollipopSize === 'large' ? 14 : config.lollipopSize === 'medium' ? 12 : 10
12
+ const isLabelBelowBar = config.yAxis.labelPlacement === 'Below Bar'
13
+ const displayNumbersOnBar = config.yAxis.displayNumbersOnBar
14
+ const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
15
+
16
+ const isRounded = config.barStyle === 'rounded'
17
+ const isStacked = config.visualizationSubType === 'stacked'
18
+ const tipRounding = config.tipRounding
19
+ const radius = config.roundingStyle === 'standard' ? '8px' : config.roundingStyle === 'shallow' ? '5px' : config.roundingStyle === 'finger' ? '15px' : '0px'
20
+ const stackCount = config.runtime.seriesKeys.length
21
+ const fontSize = { small: 16, medium: 18, large: 20 }
22
+ const hasMultipleSeries = Object.keys(config.runtime.seriesLabels).length > 1
23
+
24
+ useEffect(() => {
25
+ if (orientation === 'horizontal' && !config.yAxis.labelPlacement) {
26
+ updateConfig({
27
+ ...config,
28
+ yAxis: {
29
+ ...config,
30
+ labelPlacement: 'Below Bar'
31
+ }
32
+ })
33
+ }
34
+ }, [config, updateConfig]) // eslint-disable-line
35
+
36
+ useEffect(() => {
37
+ if (config.isLollipopChart === false && config.barHeight < 25) {
38
+ updateConfig({ ...config, barHeight: 25 })
39
+ }
40
+ }, [config.isLollipopChart]) // eslint-disable-line
41
+
42
+ useEffect(() => {
43
+ if (config.visualizationSubType === 'horizontal') {
44
+ updateConfig({
45
+ ...config,
46
+ orientation: 'horizontal'
47
+ })
48
+ }
49
+ }, []) // eslint-disable-line
50
+
51
+ useEffect(() => {
52
+ if (config.barStyle === 'lollipop' && !config.isLollipopChart) {
53
+ updateConfig({ ...config, isLollipopChart: true })
54
+ }
55
+ if (isRounded || config.barStyle === 'flat') {
56
+ updateConfig({ ...config, isLollipopChart: false })
57
+ }
58
+ }, [config.barStyle]) // eslint-disable-line
59
+
60
+ const applyRadius = index => {
61
+ if (index === undefined || index === null || !isRounded) return {}
62
+ let style = {}
63
+
64
+ if ((isStacked && index + 1 === stackCount) || !isStacked) {
65
+ style = isHorizontal ? { borderRadius: `0 ${radius} ${radius} 0` } : { borderRadius: `${radius} ${radius} 0 0` }
66
+ }
67
+ if (!isStacked && index === -1) {
68
+ style = isHorizontal ? { borderRadius: `${radius} 0 0 ${radius} ` } : { borderRadius: ` 0 0 ${radius} ${radius}` }
69
+ }
70
+ if (tipRounding === 'full' && isStacked && index === 0 && stackCount > 1) {
71
+ style = isHorizontal ? { borderRadius: `${radius} 0 0 ${radius}` } : { borderRadius: `0 0 ${radius} ${radius}` }
72
+ }
73
+ if (tipRounding === 'full' && ((isStacked && index === 0 && stackCount === 1) || !isStacked)) {
74
+ style = { borderRadius: radius }
75
+ }
76
+ return style
77
+ }
78
+
79
+ const assignColorsToValues = (barsCount, barIndex, currentBarColor) => {
80
+ if (!config.legend.colorCode && config.series.length > 1) {
81
+ return currentBarColor
82
+ }
83
+ const palettesArr = colorPalettes[config.palette]
84
+ const values = tableData.map(d => {
85
+ return d[config.legend.colorCode]
86
+ })
87
+ // Map to hold unique values and their colors
88
+ let colorMap = new Map()
89
+ // Resultant array to hold colors to the values
90
+ let palette = []
91
+
92
+ for (let i = 0; i < values.length; i++) {
93
+ // If value not in map, add it and assign a color
94
+ if (!colorMap.has(values[i])) {
95
+ colorMap.set(values[i], palettesArr[colorMap.size % palettesArr.length])
96
+ }
97
+ // push the color to the result array
98
+ palette.push(colorMap.get(values[i]))
99
+ }
100
+
101
+ // loop throghy existing colors and extend if needed
102
+ while (palette.length < barsCount) {
103
+ palette = palette.concat(palette)
104
+ }
105
+ const barColor = palette[barIndex]
106
+ return barColor
107
+ }
108
+ const updateBars = defaultBars => {
109
+ // function updates stacked && regular && lollipop horizontal bars
110
+ if (config.visualizationType !== 'Bar' && !isHorizontal) return defaultBars
111
+
112
+ const barsArr = [...defaultBars]
113
+ let barHeight
114
+
115
+ const heights = {
116
+ stacked: config.barHeight,
117
+ lollipop: lollipopBarWidth
118
+ }
119
+
120
+ if (!isStacked) {
121
+ barHeight = heights[config.isLollipopChart ? 'lollipop' : 'stacked'] * stackCount
122
+ } else {
123
+ barHeight = heights.stacked
124
+ }
125
+
126
+ const labelHeight = isLabelBelowBar ? fontSize[config.fontSize] * 1.2 : 0
127
+ let barSpace = Number(config.barSpace)
128
+
129
+ // calculate height of container based height, space and fontSize of labels
130
+ let totalHeight = barsArr.length * (barHeight + labelHeight + barSpace)
131
+
132
+ if (isHorizontal) {
133
+ config.heights.horizontal = totalHeight
134
+ }
135
+
136
+ // return new updated bars/groupes
137
+ return barsArr.map((bar, i) => {
138
+ // set bars Y dynamically to handle space between bars
139
+ let y = 0
140
+ bar.index !== 0 && (y = (barHeight + barSpace + labelHeight) * i)
141
+
142
+ return { ...bar, y: y, height: barHeight }
143
+ })
144
+ }
145
+
146
+ const getHighlightedBarColorByValue = value => {
147
+ const match = config?.highlightedBarValues.filter(item => {
148
+ if (!item.value) return
149
+ return config.xAxis.type === 'date' ? formatDate(parseDate(item.value)) === value : item.value === value
150
+ })[0]
151
+
152
+ if (!match?.color) return `rgba(255, 102, 1)`
153
+ return match.color
154
+ }
155
+ const getHighlightedBarByValue = value => {
156
+ const match = config?.highlightedBarValues.filter(item => {
157
+ if (!item.value) return
158
+ return config.xAxis.type === 'date' ? formatDate(parseDate(item.value)) === value : item.value === value
159
+ })[0]
160
+
161
+ if (!match?.color) return false
162
+ return match
163
+ }
164
+
165
+ return {
166
+ isHorizontal,
167
+ barBorderWidth,
168
+ lollipopBarWidth,
169
+ lollipopShapeSize,
170
+ isLabelBelowBar,
171
+ displayNumbersOnBar,
172
+ section,
173
+ isRounded,
174
+ isStacked,
175
+ tipRounding,
176
+ radius,
177
+ stackCount,
178
+ fontSize,
179
+ hasMultipleSeries,
180
+ applyRadius,
181
+ updateBars,
182
+ assignColorsToValues,
183
+ getHighlightedBarColorByValue,
184
+ getHighlightedBarByValue
185
+ }
186
+ }
@@ -0,0 +1,218 @@
1
+ import React, { useContext } from 'react'
2
+ import ConfigContext from '../ConfigContext'
3
+
4
+ export const useEditorPermissions = () => {
5
+ const { config } = useContext(ConfigContext)
6
+ const { visualizationType, series, orientation } = config
7
+
8
+ // Overall support for the chart types
9
+ // prettier-ignore
10
+ const enabledChartTypes = [
11
+ 'Area Chart',
12
+ 'Bar',
13
+ 'Box Plot',
14
+ 'Combo',
15
+ 'Deviation Bar',
16
+ 'Forecasting',
17
+ // 'Forest Plot',
18
+ 'Line',
19
+ 'Paired Bar',
20
+ 'Pie',
21
+ 'Scatter Plot',
22
+ 'Spark Line'
23
+ ]
24
+
25
+ const visHasLabelOnData = () => {
26
+ const disabledCharts = ['Area Chart', 'Box Plot', 'Pie', 'Scatter Plot', 'Forest Plot']
27
+ if (disabledCharts.includes(visualizationType)) return false
28
+ return true
29
+ }
30
+
31
+ const visCanAnimate = () => {
32
+ const disabledCharts = ['Area Chart', 'Scatter Plot', 'Box Plot', 'Forest Plot']
33
+ if (disabledCharts.includes(visualizationType)) return false
34
+ return true
35
+ }
36
+
37
+ const visHasLegend = () => {
38
+ switch (visualizationType) {
39
+ case 'Box Plot':
40
+ return false
41
+ case 'Forest Plot':
42
+ return false
43
+ default:
44
+ return true
45
+ }
46
+ }
47
+
48
+ const visHasNumbersOnBars = () => {
49
+ if (visualizationType === 'Forest Plot') return false
50
+ if (config.orientation === 'horizontal' && (config.yAxis.labelPlacement === 'Below Bar' || config.yAxis.labelPlacement === 'On Date/Category Axis' || config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar')) return true
51
+ return false
52
+ }
53
+
54
+ const visHasAnchors = () => {
55
+ switch (visualizationType) {
56
+ case 'Area Chart':
57
+ return true
58
+ case 'Combo':
59
+ return true
60
+ case 'Line':
61
+ return true
62
+ case 'Bar':
63
+ return true
64
+ case 'Scatter Plot':
65
+ return true
66
+ default:
67
+ return false
68
+ }
69
+ }
70
+
71
+ const visHasBarBorders = () => {
72
+ const disabledCharts = ['Box Plot', 'Scatter Plot', 'Pie']
73
+ if (disabledCharts.includes(visualizationType)) return false
74
+ return series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar' || series.type === 'Deviation Bar')
75
+ }
76
+
77
+ const visHasDataCutoff = () => {
78
+ switch (visualizationType) {
79
+ case 'Forest Plot':
80
+ return false
81
+ case 'Box Plot':
82
+ return false
83
+ case 'Pie':
84
+ return false
85
+ default:
86
+ return true
87
+ }
88
+ }
89
+
90
+ const visSupportsTooltipLines = () => {
91
+ const enabledCharts = ['Combo', 'Forecasting', 'Area Chart', 'Line', 'Bar']
92
+ if (enabledCharts.includes(visualizationType)) return true
93
+ return false
94
+ }
95
+
96
+ const visSupportsSequentialPallete = () => {
97
+ const disabledCharts = ['Paired Bar', 'Deviation Bar', 'Forest Plot']
98
+ if (disabledCharts.includes(visualizationType)) return false
99
+ return true
100
+ }
101
+
102
+ const visSupportsNonSequentialPallete = () => {
103
+ const disabledCharts = ['Paired Bar', 'Deviation Bar', 'Forest Plot']
104
+ if (disabledCharts.includes(visualizationType)) return false
105
+ return true
106
+ }
107
+
108
+ const visSupportsReverseColorPalette = () => {
109
+ const disabledCharts = ['Forest Plot', 'Paired Bar', 'Deviation Bar']
110
+ if (disabledCharts.includes(visualizationType)) return false
111
+ return true
112
+ }
113
+
114
+ const visSupportsDateCategoryAxisLabel = () => {
115
+ const disabledCharts = ['Forest Plot']
116
+ if (disabledCharts.includes(visualizationType)) return false
117
+ return true
118
+ }
119
+
120
+ const visSupportsDateCategoryAxisLine = () => {
121
+ const disabledCharts = ['Forest Plot']
122
+ if (disabledCharts.includes(visualizationType)) return false
123
+ return true
124
+ }
125
+
126
+ const visSupportsDateCategoryAxisTicks = () => {
127
+ const disabledCharts = ['Forest Plot']
128
+ if (disabledCharts.includes(visualizationType)) return false
129
+ return true
130
+ }
131
+
132
+ const visSupportsDateCategoryTickRotation = () => {
133
+ const disabledCharts = ['Forest Plot']
134
+ if (disabledCharts.includes(visualizationType)) return false
135
+ return true
136
+ }
137
+
138
+ const visSupportsDateCategoryNumTicks = () => {
139
+ const disabledCharts = ['Forest Plot']
140
+ if (disabledCharts.includes(visualizationType)) return false
141
+ return true
142
+ }
143
+
144
+ const visSupportsRegions = () => {
145
+ const disabledCharts = ['Forest Plot', 'Pie', 'Paired Bar']
146
+ if (disabledCharts.includes(visualizationType)) return false
147
+ return true
148
+ }
149
+
150
+ const visSupportsFilters = () => {
151
+ const disabledCharts = ['Forest Plot']
152
+ if (disabledCharts.includes(visualizationType)) return false
153
+ return true
154
+ }
155
+
156
+ const visSupportsValueAxisGridLines = () => {
157
+ const disabledCharts = ['Forest Plot']
158
+ if (orientation === 'horizontal') return false
159
+ if (disabledCharts.includes(visualizationType)) return false
160
+ return true
161
+ }
162
+
163
+ // implement later
164
+ const visSupportsValueAxisTicks = () => {
165
+ return true
166
+ }
167
+
168
+ // implement later
169
+ const visSupportsValueAxisLine = () => {
170
+ return true
171
+ }
172
+
173
+ // implement later
174
+ const visSupportsValueAxisLabels = () => {
175
+ return true
176
+ }
177
+
178
+ const visSupportsBarSpace = () => {
179
+ const disabledCharts = ['Forest Plot']
180
+ if (disabledCharts.includes(visualizationType)) return false
181
+ if (orientation === 'horizontal' || visualizationType === 'Paired Bar') return true
182
+ return false
183
+ }
184
+
185
+ const visSupportsBarThickness = () => {
186
+ const disabledCharts = ['Forest Plot']
187
+ if (disabledCharts.includes(visualizationType)) return false
188
+ return true
189
+ }
190
+
191
+ return {
192
+ enabledChartTypes,
193
+ visHasLabelOnData,
194
+ visHasNumbersOnBars,
195
+ visHasAnchors,
196
+ visHasBarBorders,
197
+ visHasDataCutoff,
198
+ visCanAnimate,
199
+ visHasLegend,
200
+ visSupportsTooltipLines,
201
+ visSupportsNonSequentialPallete,
202
+ visSupportsSequentialPallete,
203
+ visSupportsReverseColorPalette,
204
+ visSupportsDateCategoryAxisLabel,
205
+ visSupportsDateCategoryAxisLine,
206
+ visSupportsDateCategoryAxisTicks,
207
+ visSupportsDateCategoryTickRotation,
208
+ visSupportsDateCategoryNumTicks,
209
+ visSupportsRegions,
210
+ visSupportsFilters,
211
+ visSupportsValueAxisGridLines,
212
+ visSupportsValueAxisTicks,
213
+ visSupportsValueAxisLine,
214
+ visSupportsValueAxisLabels,
215
+ visSupportsBarSpace,
216
+ visSupportsBarThickness
217
+ }
218
+ }
@@ -7,7 +7,8 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
7
7
  }
8
8
 
9
9
  const { max: enteredMaxValue, min: enteredMinValue } = config.runtime.yAxis
10
-
10
+ const minRequiredCIPadding = 1.15 // regardless of Editor if CI data, there must be 10% padding added
11
+
11
12
  // do validation bafore applying t0 charts
12
13
  const isMaxValid = existPositiveValue ? enteredMaxValue >= maxValue : enteredMaxValue >= 0
13
14
  const isMinValid = config.useLogScale ? enteredMinValue >= 0 : (enteredMinValue <= 0 && minValue >= 0) || (enteredMinValue <= minValue && minValue < 0)
@@ -15,6 +16,7 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
15
16
  min = enteredMinValue && isMinValid ? enteredMinValue : minValue
16
17
  max = enteredMaxValue && isMaxValid ? enteredMaxValue : Number.MIN_VALUE
17
18
 
19
+ let ciYMin = 0
18
20
  if (config.visualizationType === 'Bar' || config.visualizationType === 'Combo' || config.visualizationType === 'Deviation Bar') {
19
21
  let ciYMax = 0
20
22
  if (config.hasOwnProperty('confidenceKeys')) {
@@ -22,7 +24,15 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
22
24
  return d[config.confidenceKeys.upper]
23
25
  })
24
26
  ciYMax = Math.max.apply(Math, upperCIValues)
25
- if (ciYMax > max) max = ciYMax // bump up the max
27
+ if (ciYMax > max) max = ciYMax * minRequiredCIPadding // bump up the max plus some padding always
28
+
29
+ // check the min if lower confidence
30
+ let lowerCIValues = data.map(function (d) {
31
+ // if no lower CI then we need lowerCIValues to have nothing in it
32
+ return d[config.confidenceKeys.lower] !== undefined ? d[config.confidenceKeys.lower] : ''
33
+ })
34
+ ciYMin = Math.min.apply(Math, lowerCIValues)
35
+ if (ciYMin < min) min = ciYMin * minRequiredCIPadding // adjust the min + 10% padding for negative numbers to separate from axis
26
36
  }
27
37
  }
28
38
 
@@ -47,11 +57,12 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
47
57
  const highCIGroup = Math.max.apply(
48
58
  null,
49
59
  result.map(item => item[0])
50
- ) // Extract ages from result
60
+ )
61
+
51
62
  const lowCIGroup = Math.min.apply(
52
63
  null,
53
64
  result.map(item => item[1])
54
- ) // Extract ages from result
65
+ )
55
66
 
56
67
  if (highCIGroup > max) {
57
68
  max = highCIGroup
@@ -62,9 +73,11 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
62
73
  }
63
74
  }
64
75
 
65
- if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && min > 0) {
76
+ // this should not apply to bar charts if there is negative CI data
77
+ if (((config.visualizationType === 'Bar' && ciYMin >= 0) || (config.visualizationType === 'Combo' && !isAllLine)) && min > 0) {
66
78
  min = 0
67
79
  }
80
+
68
81
  if (config.visualizationType === 'Combo' && isAllLine) {
69
82
  if ((enteredMinValue === undefined || enteredMinValue === null || enteredMinValue === '') && min > 0) {
70
83
  min = 0
@@ -19,8 +19,9 @@ export default function useRightAxis({ config, yMax = 0, data = [], updateConfig
19
19
 
20
20
  // if there is a bar series & the right axis doesn't include a negative number, default to zero
21
21
  const hasBarSeries = config.runtime?.barSeriesKeys?.length > 0
22
+ const hasLineSeries = config.runtime?.lineSeriesKeys?.length > 0
22
23
 
23
- if (hasBarSeries && minValue > 0) {
24
+ if ((hasBarSeries || hasLineSeries) && minValue > 0) {
24
25
  minValue = 0
25
26
  }
26
27