@cdc/chart 4.23.4 → 4.23.5

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 (31) hide show
  1. package/dist/cdcchart.js +52384 -50875
  2. package/examples/feature/__data__/planet-example-data.json +2 -19
  3. package/examples/feature/__data__/planet-logaritmic-data.json +56 -0
  4. package/examples/feature/area/area-chart-category.json +240 -0
  5. package/examples/feature/bar/example-bar-chart.json +544 -22
  6. package/examples/feature/bar/planet-chart-logaritmic-config.json +170 -0
  7. package/examples/feature/boxplot/valid-boxplot.csv +17 -0
  8. package/examples/feature/filters/filter-testing.json +37 -3
  9. package/examples/feature/forecasting/random_data.csv +366 -0
  10. package/examples/feature/line/line-chart.json +2 -2
  11. package/examples/feature/test-highlight/test-highlight-2.json +789 -0
  12. package/examples/feature/test-highlight/test-highlight-vertical.json +561 -0
  13. package/examples/feature/test-highlight/test-highlight.json +100 -0
  14. package/examples/feature/tests-non-numerics/stacked-vertical-bar-example-nonnumerics.json +1 -2
  15. package/examples/gallery/bar-chart-horizontal/horizontal-highlight.json +345 -0
  16. package/index.html +8 -8
  17. package/package.json +2 -2
  18. package/src/CdcChart.jsx +294 -14
  19. package/src/components/AreaChart.jsx +27 -20
  20. package/src/components/BarChart.jsx +85 -25
  21. package/src/components/DeviationBar.jsx +32 -32
  22. package/src/components/EditorPanel.jsx +1105 -184
  23. package/src/components/Legend.jsx +39 -3
  24. package/src/components/LineChart.jsx +1 -8
  25. package/src/components/LinearChart.jsx +121 -270
  26. package/src/data/initial-state.js +18 -3
  27. package/src/hooks/useHighlightedBars.js +154 -0
  28. package/src/hooks/useMinMax.js +92 -0
  29. package/src/hooks/useReduceData.js +31 -57
  30. package/src/hooks/useScales.js +202 -0
  31. /package/examples/feature/area/{area-chart.json → area-chart-date.json} +0 -0
@@ -0,0 +1,154 @@
1
+ import React, { useContext } from 'react'
2
+ import ConfigContext from '../ConfigContext'
3
+
4
+ export const useHighlightedBars = (config, updateConfig) => {
5
+ const { formatDate, parseDate } = useContext(ConfigContext)
6
+
7
+ let highlightedSeries = [] // only allow single series for highlights
8
+ let highlightedSeriesKey = ''
9
+ let highlightedBarValues = []
10
+ let highlightedSeriesValues = []
11
+
12
+ if (config.series?.length > 0 && config.data) {
13
+ highlightedSeries = config.series[0] // only allow single series for highlights
14
+ highlightedSeriesKey = config.series[0].dataKey
15
+ highlightedBarValues = config.highlightedBarValues
16
+ highlightedSeriesValues = config.data.map(item => item[config.xAxis.dataKey])
17
+ } else {
18
+ highlightedSeries = [] // only allow single series for highlights
19
+ highlightedSeriesKey = ''
20
+ highlightedBarValues = []
21
+ highlightedSeriesValues = []
22
+ }
23
+
24
+ const handleUpdateHighlightedBorderWidth = (e, index) => {
25
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
26
+ copyOfHighlightedBarValues[index].borderWidth = e.target.value
27
+
28
+ updateConfig({
29
+ ...config,
30
+ highlightedBarValues: copyOfHighlightedBarValues
31
+ })
32
+ }
33
+
34
+ const handleUpdateHighlightedBar = (e, index) => {
35
+ e.preventDefault()
36
+
37
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
38
+
39
+ copyOfHighlightedBarValues[index].value = e.target.value
40
+ copyOfHighlightedBarValues[index].dataKey = highlightedSeriesKey
41
+
42
+ updateConfig({
43
+ ...config,
44
+ highlightedBarValues: copyOfHighlightedBarValues
45
+ })
46
+ }
47
+
48
+ const handleAddNewHighlightedBar = (e, index) => {
49
+ e.preventDefault()
50
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
51
+ copyOfHighlightedBarValues.push({ dataKey: highlightedSeriesKey })
52
+
53
+ updateConfig({
54
+ ...config,
55
+ highlightedBarValues: copyOfHighlightedBarValues
56
+ })
57
+ }
58
+
59
+ const handleRemoveHighlightedBar = (e, index) => {
60
+ e.preventDefault()
61
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
62
+ copyOfHighlightedBarValues.splice(index, 1)
63
+ updateConfig({
64
+ ...config,
65
+ highlightedBarValues: copyOfHighlightedBarValues
66
+ })
67
+ }
68
+
69
+ const handleUpdateHighlightedBarColor = (e, index) => {
70
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
71
+ copyOfHighlightedBarValues[index].color = e.target.value
72
+
73
+ updateConfig({
74
+ ...config
75
+ })
76
+ }
77
+
78
+ const handleHighlightedBarLegendLabel = (e, index) => {
79
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
80
+ copyOfHighlightedBarValues[index].legendLabel = e.target.value
81
+
82
+ updateConfig({
83
+ ...config,
84
+ copyOfHighlightedBarValues
85
+ })
86
+ }
87
+
88
+ const HighLightedBarUtils = () => {}
89
+
90
+ /**
91
+ * @param {string} formattedValue - The value to check for.
92
+ * @param {Array<string>} highlightedBarValuesIn - An array of highlighted bar values.
93
+ * @param {string} labelColor - The default label color.
94
+ * @returns {string} - Returns the font color for the given value.
95
+ */
96
+ HighLightedBarUtils.checkFontColor = (formattedValue, highlightedBarValuesIn, labelColor) => {
97
+ if (config.xAxis.type === 'date') {
98
+ if (HighLightedBarUtils.formatDates(highlightedBarValuesIn).includes(formattedValue)) {
99
+ return '#000'
100
+ }
101
+ } else {
102
+ if (highlightedBarValuesIn.includes(formattedValue)) {
103
+ return '#000'
104
+ }
105
+ }
106
+ return labelColor
107
+ }
108
+
109
+ /**
110
+ * Formats an array of date values using the formatDate and parseDate functions.
111
+ *
112
+ * @param {string[]} highlightedBarValues - An array of date values to format.
113
+ * @returns {?Date[]} - An array of formatted date objects, or null if invalid input is provided.
114
+ */
115
+ HighLightedBarUtils.formatDates = highlightedBarValues => {
116
+ return highlightedBarValues.map(dateItem => {
117
+ if (!dateItem) return false
118
+ return formatDate(parseDate(dateItem))
119
+ })
120
+ }
121
+
122
+ /**
123
+ * Finds duplicate objects in an array based on the legendLabel property.
124
+ *
125
+ * @param {Array} arr - The array of objects to be checked.
126
+ * @return {Array} - An array of arrays, each containing objects that have the same legendLabel property.
127
+ */
128
+ HighLightedBarUtils.findDuplicates = arr => {
129
+ const duplicates = {}
130
+ const result = arr.filter(obj => {
131
+ const { legendLabel } = obj
132
+ if (!duplicates[legendLabel]) {
133
+ duplicates[legendLabel] = true
134
+ return true
135
+ }
136
+ return false
137
+ })
138
+ return result
139
+ }
140
+
141
+ return {
142
+ HighLightedBarUtils,
143
+ highlightedSeries,
144
+ highlightedSeriesKey,
145
+ highlightedBarValues,
146
+ highlightedSeriesValues,
147
+ handleUpdateHighlightedBar,
148
+ handleAddNewHighlightedBar,
149
+ handleRemoveHighlightedBar,
150
+ handleUpdateHighlightedBarColor,
151
+ handleHighlightedBarLegendLabel,
152
+ handleUpdateHighlightedBorderWidth
153
+ }
154
+ }
@@ -0,0 +1,92 @@
1
+ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAllLine }) => {
2
+ let min = 0
3
+ let max = 0
4
+
5
+ if (!data) {
6
+ return { min, max }
7
+ }
8
+
9
+ const { max: enteredMaxValue, min: enteredMinValue } = config.runtime.yAxis
10
+
11
+ // do validation bafore applying t0 charts
12
+ const isMaxValid = existPositiveValue ? enteredMaxValue >= maxValue : enteredMaxValue >= 0
13
+ const isMinValid = config.useLogScale ? enteredMinValue >= 0 : (enteredMinValue <= 0 && minValue >= 0) || (enteredMinValue <= minValue && minValue < 0)
14
+
15
+ min = enteredMinValue && isMinValid ? enteredMinValue : minValue
16
+ max = enteredMaxValue && isMaxValid ? enteredMaxValue : Number.MIN_VALUE
17
+
18
+ if (config.visualizationType === 'Bar' || config.visualizationType === 'Combo' || config.visualizationType === 'Deviation Bar') {
19
+ let ciYMax = 0
20
+ if (config.hasOwnProperty('confidenceKeys')) {
21
+ let upperCIValues = data.map(function (d) {
22
+ return d[config.confidenceKeys.upper]
23
+ })
24
+ ciYMax = Math.max.apply(Math, upperCIValues)
25
+ if (ciYMax > max) max = ciYMax // bump up the max
26
+ }
27
+ }
28
+
29
+ if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && min > 0) {
30
+ min = 0
31
+ }
32
+ if (config.visualizationType === 'Combo' && isAllLine) {
33
+ if ((enteredMinValue === undefined || enteredMinValue === null || enteredMinValue === '') && min > 0) {
34
+ min = 0
35
+ }
36
+ if (enteredMinValue) {
37
+ const isMinValid = config.useLogScale ? enteredMinValue >= 0 && enteredMinValue < minValue : enteredMinValue < minValue
38
+ min = enteredMinValue && isMinValid ? enteredMinValue : minValue
39
+ }
40
+ }
41
+
42
+ if (config.visualizationType === 'Deviation Bar' && min > 0) {
43
+ const isMinValid = Number(enteredMinValue) < Math.min(minValue, Number(config.xAxis.target))
44
+ min = enteredMinValue && isMinValid ? enteredMinValue : 0
45
+ }
46
+
47
+ if (config.visualizationType === 'Line') {
48
+ const isMinValid = config.useLogScale ? enteredMinValue >= 0 && enteredMinValue < minValue : enteredMinValue < minValue
49
+ min = enteredMinValue && isMinValid ? enteredMinValue : minValue
50
+ }
51
+ //If data value max wasn't provided, calculate it
52
+ if (max === Number.MIN_VALUE) {
53
+ // if all values in data are negative set max = 0
54
+ max = existPositiveValue ? maxValue : 0
55
+ }
56
+
57
+ //Adds Y Axis data padding if applicable
58
+ if (config.runtime.yAxis.paddingPercent) {
59
+ let paddingValue = (max - min) * config.runtime.yAxis.paddingPercent
60
+ min -= paddingValue
61
+ max += paddingValue
62
+ }
63
+
64
+ if (config.isLollipopChart && config.yAxis.displayNumbersOnBar) {
65
+ const dataKey = data.map(item => item[config.series[0].dataKey])
66
+ const maxDataVal = Math.max(...dataKey).toString().length
67
+
68
+ switch (true) {
69
+ case maxDataVal > 8 && maxDataVal <= 12:
70
+ max = max * 1.3
71
+ break
72
+ case maxDataVal > 4 && maxDataVal <= 7:
73
+ max = max * 1.1
74
+ break
75
+ default:
76
+ break
77
+ }
78
+ }
79
+
80
+ if (config.yAxis.enablePadding) {
81
+ if (min < 0) {
82
+ // sets with negative data need more padding on the max
83
+ max *= 1.2
84
+ min *= 1.2
85
+ } else {
86
+ max *= 1.1
87
+ }
88
+ }
89
+
90
+ return { min, max }
91
+ }
92
+ export default useMinMax
@@ -1,81 +1,55 @@
1
1
  import isNumber from '@cdc/core/helpers/isNumber'
2
2
 
3
3
  function useReduceData(config, data) {
4
- // for combo charts check if all Data Series selected to Bar;
5
- const isBar = config?.series?.every(element => element?.type === 'Bar')
6
- // for combo charts check if all Data series selected Line or dashed-md/sm/lg.
7
- const isAllLine = config?.series?.every(el => el.type === 'Line' || el.type === 'dashed-sm' || el.type === 'dashed-md' || el.type === 'dashed-lg')
8
- const cleanChars = value => {
9
- // remove comma and $ signs
10
- let tmp
11
- if (typeof value === 'string') {
12
- tmp = value !== null && value !== '' ? value.replace(/[,$]/g, '') : ''
13
- } else {
14
- tmp = value !== null && value !== '' ? value : ''
15
- }
16
- return tmp
17
- }
4
+ const isBar = config.series.every(({ type }) => type === 'Bar')
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) => yTotal + Number(xValue[k]), 0)
7
+
18
8
  const getMaxValueFromData = () => {
19
- let max // will hold max number from data.
20
- if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && isBar)) && config.visualizationSubType === 'stacked') {
21
- const yTotals = data.reduce((allTotals, xValue) => {
22
- const totalYValues = config.runtime.seriesKeys.reduce((yTotal, k) => {
23
- yTotal += Number(xValue[k])
24
- return yTotal
25
- }, 0)
26
-
27
- allTotals.push(totalYValues)
28
- if (totalYValues > max) {
29
- max = totalYValues
30
- }
31
- return allTotals
32
- }, [])
9
+ let max = Math.max(...data.map(d => Math.max(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : 0)))))
33
10
 
11
+ if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && isBar)) && config.visualizationSubType === 'stacked') {
12
+ const yTotals = data.map(sumYValues(config.runtime.seriesKeys))
34
13
  max = Math.max(...yTotals)
35
- } else if ((config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.series && config.series.dataKey) {
14
+ }
15
+
16
+ if ((config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.series && config.series.dataKey) {
36
17
  max = Math.max(...data.map(d => (isNumber(d[config.series.dataKey]) ? Number(cleanChars(d[config.series.dataKey])) : 0)))
37
- //max = Math.max(...data.map(d => Number(d[config.series.dataKey])))
38
- } else if (config.visualizationType === 'Combo' && config.visualizationSubType === 'stacked' && !isBar) {
39
- let total = []
18
+ }
40
19
 
20
+ if (config.visualizationType === 'Combo' && config.visualizationSubType === 'stacked' && !isBar) {
41
21
  if (config.runtime.barSeriesKeys && config.runtime.lineSeriesKeys) {
42
- // get barSeries max Values added to each other
43
- data.map(function (d, index) {
44
- const totalYValues = config.runtime.barSeriesKeys.reduce((yTotal, k) => {
45
- yTotal += Number(d[k])
46
- return yTotal
47
- }, 0)
48
- return total.push(totalYValues)
49
- })
50
- // get lineSeries largest values
51
- const lineMax = Math.max(...data.map(d => Math.max(...config.runtime.lineSeriesKeys.map(key => Number(cleanChars(d[key]))))))
22
+ const yTotals = data.map(sumYValues(config.runtime.barSeriesKeys))
52
23
 
53
- const barMax = Math.max(...total)
24
+ const lineMax = Math.max(...data.map(d => Math.max(...config.runtime.lineSeriesKeys.map(key => Number(cleanChars(d[key]))))))
25
+ const barMax = Math.max(...yTotals)
54
26
 
55
- max = Number(barMax) > Number(lineMax) ? barMax : lineMax
27
+ max = Math.max(barMax, lineMax)
56
28
  }
57
- } else {
58
- max = Math.max(...data.map(d => Math.max(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : 0)))))
59
29
  }
30
+
60
31
  return max
61
32
  }
62
33
 
63
34
  const getMinValueFromData = () => {
64
- let min
65
- const minNumberFromData = Math.min(...data.map(d => Math.min(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : 1000000000)))))
66
- min = String(minNumberFromData)
67
- return min
35
+ const minNumberFromData = Math.min(...data.map(d => Math.min(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : Infinity)))))
36
+
37
+ return String(minNumberFromData)
68
38
  }
69
39
 
70
40
  const findPositiveNum = () => {
71
- // loop throught provided data to find positve number in arr based on series keys.
72
- let existPositiveValue = false
73
- if (config.runtime.seriesKeys) {
74
- for (let i = 0; i < config.runtime.seriesKeys.length; i++) {
75
- existPositiveValue = data.some(d => d[config.runtime.seriesKeys[i]] >= 0)
76
- }
41
+ if (!config.runtime.seriesKeys) {
42
+ return false
77
43
  }
78
- return existPositiveValue
44
+ return config.runtime.seriesKeys.some(key => data.some(d => d[key] >= 0))
45
+ }
46
+
47
+ const cleanChars = value => {
48
+ if (value === null || value === '') {
49
+ return ''
50
+ }
51
+
52
+ return typeof value === 'string' ? value.replace(/[,$]/g, '') : value
79
53
  }
80
54
 
81
55
  const maxValue = Number(getMaxValueFromData())
@@ -0,0 +1,202 @@
1
+ import { scaleBand, scaleLinear, scaleLog, scalePoint, scaleTime } from '@visx/scale'
2
+
3
+ const useScales = properties => {
4
+ let { xAxisDataMapped, xMax, yMax, min, max, config, data } = properties
5
+ const seriesDomain = config.runtime.barSeriesKeys || config.runtime.seriesKeys
6
+ const xAxisType = config.runtime.xAxis.type
7
+ const isHorizontal = config.orientation === 'horizontal'
8
+
9
+ // define scxales
10
+ let xScale = null
11
+ let yScale = null
12
+ let g2xScale = null
13
+ let g1xScale = null
14
+ let seriesScale = null
15
+
16
+ const scaleTypes = {
17
+ TIME: 'time',
18
+ LOG: 'log',
19
+ POINT: 'point',
20
+ LINEAR: 'linear',
21
+ BAND: 'band'
22
+ }
23
+
24
+ // handle Horizontal bars
25
+ if (isHorizontal) {
26
+ xScale = composeXScale({ min: min * 1.03, ...properties })
27
+ xScale.type = config.useLogScale ? scaleTypes.LOG : scaleTypes.LINEAR
28
+ yScale = getYScaleFunction(xAxisType, xAxisDataMapped)
29
+ yScale.rangeRound([0, yMax])
30
+ seriesScale = composeScalePoint(seriesDomain, [0, yMax])
31
+ }
32
+
33
+ // handle Vertical bars
34
+ if (!isHorizontal) {
35
+ xScale = composeScalePoint(xAxisDataMapped, [0, xMax], 0.5)
36
+ xScale.type = scaleTypes.POINT
37
+
38
+ // if (config.visualizationType === 'Bar') {
39
+ // xScale = scaleBand({
40
+ // domain: xAxisDataMapped,
41
+ // range: [0, xMax],
42
+ // padding: 0.4
43
+ // })
44
+ // xScale.type = scaleTypes.BAND
45
+ // }
46
+ yScale = composeYScale(properties)
47
+ seriesScale = composeScalePoint(seriesDomain, [0, xMax])
48
+ }
49
+
50
+ // handle Area chart
51
+ if (config.visualizationType === 'Area Chart' && config.xAxis.type === 'date') {
52
+ xScale = scaleTime({
53
+ domain: [Math.min(...xAxisDataMapped), Math.max(...xAxisDataMapped)],
54
+ range: [0, xMax]
55
+ })
56
+ xScale.type = scaleTypes.TIME
57
+ }
58
+
59
+ // handle Deviation bar
60
+ if (config.visualizationType === 'Deviation Bar') {
61
+ const leftOffset = config.isLollipopChart ? 1.05 : 1.03
62
+ yScale = scaleBand({
63
+ domain: xAxisDataMapped,
64
+ range: [0, yMax]
65
+ })
66
+ xScale = scaleLinear({
67
+ domain: [min * leftOffset, Math.max(Number(config.xAxis.target), max)],
68
+ range: [0, xMax],
69
+ round: true,
70
+ nice: true
71
+ })
72
+ xScale.type = scaleTypes.LINEAR
73
+ }
74
+
75
+ // handle Scatter plot
76
+ if (config.visualizationType === 'Scatter Plot') {
77
+ if (config.xAxis.type === 'continuous') {
78
+ xScale = scaleLinear({
79
+ domain: [0, Math.max.apply(null, xScale.domain())],
80
+ range: [0, xMax]
81
+ })
82
+ xScale.type = scaleTypes.LINEAR
83
+ }
84
+ }
85
+
86
+ // handle Box plot
87
+ if (config.visualizationType === 'Box Plot') {
88
+ const allOutliers = []
89
+ const hasOutliers = config.boxplot.plots.map(b => b.columnOutliers.map(outlier => allOutliers.push(outlier))) && !config.boxplot.hideOutliers
90
+
91
+ // check if outliers are lower
92
+ if (hasOutliers) {
93
+ let outlierMin = Math.min(...allOutliers)
94
+ let outlierMax = Math.max(...allOutliers)
95
+
96
+ // check if outliers exceed standard bounds
97
+ if (outlierMin < min) min = outlierMin
98
+ if (outlierMax > max) max = outlierMax
99
+ }
100
+
101
+ // check fences for max/min
102
+ let lowestFence = Math.min(...config.boxplot.plots.map(item => item.columnLowerBounds))
103
+ let highestFence = Math.max(...config.boxplot.plots.map(item => item.columnUpperBounds))
104
+
105
+ if (lowestFence < min) min = lowestFence
106
+ if (highestFence > max) max = highestFence
107
+
108
+ // Set Scales
109
+ yScale = scaleLinear({
110
+ range: [yMax, 0],
111
+ round: true,
112
+ domain: [min, max]
113
+ })
114
+
115
+ xScale = scaleBand({
116
+ range: [0, xMax],
117
+ round: true,
118
+ domain: config.boxplot.categories,
119
+ padding: 0.4
120
+ })
121
+ xScale.type = scaleTypes.BAND
122
+ }
123
+
124
+ // handle Paired bar
125
+ if (config.visualizationType === 'Paired Bar') {
126
+ const offset = 1.02 // Offset of the ticks/values from the Axis
127
+ let groupOneMax = Math.max.apply(
128
+ Math,
129
+ data.map(d => d[config.series[0].dataKey])
130
+ )
131
+ let groupTwoMax = Math.max.apply(
132
+ Math,
133
+ data.map(d => d[config.series[1].dataKey])
134
+ )
135
+
136
+ // group one
137
+ g1xScale = scaleLinear({
138
+ domain: [0, Math.max(groupOneMax, groupTwoMax) * offset],
139
+ range: [xMax / 2, 0]
140
+ })
141
+
142
+ // group 2
143
+ g2xScale = scaleLinear({
144
+ domain: g1xScale.domain(),
145
+ range: [xMax / 2, xMax],
146
+ nice: true
147
+ })
148
+ }
149
+
150
+ return { xScale, yScale, seriesScale, g1xScale, g2xScale }
151
+ }
152
+
153
+ export default useScales
154
+
155
+ /// helper functions
156
+ const composeXScale = ({ min, max, xMax, config }) => {
157
+ // Adjust min value if using logarithmic scale
158
+ min = config.useLogScale && min >= 0 && min < 1 ? min + 0.1 : min
159
+ // Select the appropriate scale function
160
+ const scaleFunc = config.useLogScale ? scaleLog : scaleLinear
161
+ // Return the configured scale function
162
+ return scaleFunc({
163
+ domain: [min, max],
164
+ range: [0, xMax],
165
+ nice: config.useLogScale,
166
+ zero: config.useLogScale,
167
+ type: config.useLogScale ? 'log' : 'linear'
168
+ })
169
+ }
170
+
171
+ const composeYScale = ({ min, max, yMax, config }) => {
172
+ // Adjust min value if using logarithmic scale
173
+ min = config.useLogScale && min >= 0 && min < 1 ? min + 0.1 : min
174
+ // Select the appropriate scale function
175
+ const scaleFunc = config.useLogScale ? scaleLog : scaleLinear
176
+ // Return the configured scale function
177
+ return scaleFunc({
178
+ domain: [min, max],
179
+ range: [yMax, 0],
180
+ nice: config.useLogScale,
181
+ zero: config.useLogScale
182
+ })
183
+ }
184
+
185
+ const getYScaleFunction = (xAxisType, xAxisDataMapped) => {
186
+ if (xAxisType === 'date') {
187
+ return scaleLinear({
188
+ domain: [Math.min(...xAxisDataMapped), Math.max(...xAxisDataMapped)]
189
+ })
190
+ } else {
191
+ return scalePoint({ domain: xAxisDataMapped, padding: 0.5 })
192
+ }
193
+ }
194
+
195
+ const composeScalePoint = (domain, range, padding = 0) => {
196
+ return scalePoint({
197
+ domain: domain,
198
+ range: range,
199
+ padding: padding,
200
+ type: 'point'
201
+ })
202
+ }