@cdc/chart 4.23.2 → 4.23.4

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 (94) hide show
  1. package/dist/cdcchart.js +42292 -40337
  2. package/examples/feature/__data__/area-chart.json +56 -0
  3. package/examples/{planet-example-data.json → feature/__data__/planet-example-data-max-increase.json} +4 -4
  4. package/examples/feature/__data__/planet-example-data.json +68 -0
  5. package/examples/feature/area/area-chart.json +244 -0
  6. package/examples/{example-bar-chart.json → feature/bar/example-bar-chart.json} +4 -1
  7. package/examples/feature/bar/horizontal-chart-max-increase.json +44 -0
  8. package/examples/{horizontal-chart.json → feature/bar/horizontal-chart.json} +10 -4
  9. package/examples/{horizontal-stacked-bar-chart.json → feature/bar/horizontal-stacked-bar-chart.json} +7 -3
  10. package/examples/{planet-chart-horizontal-example-config.json → feature/bar/planet-chart-horizontal-example-config.json} +8 -3
  11. package/examples/feature/bar/planet-example-config.json +156 -0
  12. package/examples/{box-plot.json → feature/boxplot/boxplot.json} +7 -8
  13. package/examples/feature/boxplot/testing.csv +38 -0
  14. package/examples/feature/combo/combochart-categories_are_numbers .json +18 -0
  15. package/examples/{planet-combo-example-config.json → feature/combo/planet-combo-example-config.json} +1 -1
  16. package/examples/feature/deviation/planet-deviation-config.json +168 -0
  17. package/examples/feature/deviation/planet-deviation-data.json +38 -0
  18. package/examples/feature/filters/filter-testing.json +178 -0
  19. package/examples/feature/forecasting/case_date_example.csv +130 -0
  20. package/examples/feature/forecasting/effective_reproduction.json +202 -0
  21. package/examples/feature/forecasting/r_data.csv +130 -0
  22. package/examples/feature/line/line-chart-max-increase.json +32 -0
  23. package/examples/feature/line/line-chart.json +124 -0
  24. package/examples/{paired-bar-example.json → feature/paired-bar/paired-bar-example.json} +10 -4
  25. package/examples/{planet-pie-example-config.json → feature/pie/planet-pie-example-config.json} +2 -2
  26. package/examples/{scatterplot-continuous.csv → feature/scatterplot/scatterplot-continuous.csv} +3 -3
  27. package/examples/{scatterplot.json → feature/scatterplot/scatterplot.json} +3 -3
  28. package/examples/feature/sparkline/example-sparkline.json +76 -0
  29. package/examples/feature/tests-big-small/big-small-test-bar.json +328 -0
  30. package/examples/feature/tests-big-small/big-small-test-line.json +328 -0
  31. package/examples/feature/tests-big-small/big-small-test-negative.json +328 -0
  32. package/examples/{case-rate-example-config.json → feature/tests-case-rate/case-rate-example-config.json} +2 -2
  33. package/examples/{covid-confidence-example-config.json → feature/tests-covid/covid-confidence-example-config.json} +8 -3
  34. package/examples/{covid-example-config.json → feature/tests-covid/covid-example-config.json} +7 -3
  35. package/examples/{cutoff-example-config.json → feature/tests-cutoff/cutoff-example-config.json} +7 -3
  36. package/examples/{date-exclusions-config.json → feature/tests-date-exclusions/date-exclusions-config.json} +2 -2
  37. package/examples/{example-bar-chart-nonnumeric.json → feature/tests-non-numerics/example-bar-chart-nonnumeric.json} +1 -1
  38. package/examples/{line-chart-nonnumeric.json → feature/tests-non-numerics/line-chart-nonnumeric.json} +5 -5
  39. package/examples/{planet-pie-example-config-nonnumeric.json → feature/tests-non-numerics/planet-pie-example-config-nonnumeric.json} +2 -2
  40. package/examples/{sparkline-chart-nonnumeric.json → feature/tests-non-numerics/sparkline-chart-nonnumeric.json} +2 -2
  41. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +31 -172
  42. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +145 -7
  43. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-confidence.json +1 -0
  44. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +96 -14
  45. package/examples/gallery/line/line.json +1 -0
  46. package/examples/gallery/paired-bar/paired-bar-chart.json +1 -0
  47. package/index.html +76 -35
  48. package/package.json +6 -3
  49. package/src/CdcChart.jsx +245 -106
  50. package/src/components/AreaChart.jsx +233 -0
  51. package/src/components/BarChart.jsx +103 -62
  52. package/src/components/BoxPlot.jsx +39 -18
  53. package/src/components/DataTable.jsx +26 -21
  54. package/src/components/DeviationBar.jsx +191 -0
  55. package/src/components/EditorPanel.jsx +662 -298
  56. package/src/components/Legend.jsx +59 -46
  57. package/src/components/LineChart.jsx +12 -36
  58. package/src/components/LinearChart.jsx +163 -64
  59. package/src/components/PairedBarChart.jsx +6 -7
  60. package/src/components/PieChart.jsx +12 -17
  61. package/src/components/ScatterPlot.jsx +19 -16
  62. package/src/components/SparkLine.jsx +84 -118
  63. package/src/components/useIntersectionObserver.jsx +1 -1
  64. package/src/data/initial-state.js +27 -7
  65. package/src/hooks/useColorPalette.js +58 -48
  66. package/src/hooks/useReduceData.js +3 -4
  67. package/src/index.jsx +3 -2
  68. package/src/scss/editor-panel.scss +20 -0
  69. package/src/scss/main.scss +8 -6
  70. package/src/test/CdcChart.test.jsx +6 -0
  71. package/examples/box-plot.csv +0 -5
  72. package/examples/dynamic-legends.json +0 -125
  73. package/examples/line-chart.json +0 -34
  74. package/examples/planet-example-config.json +0 -37
  75. package/examples/temp-example-config.json +0 -64
  76. package/examples/temp-example-data.json +0 -130
  77. package/src/components/Filters.jsx +0 -125
  78. /package/examples/{age-adjusted-rates.json → feature/__data__/age-adjusted-rates.json} +0 -0
  79. /package/examples/{new-data.csv → feature/__data__/new-data.csv} +0 -0
  80. /package/examples/{Barchart_with_negative.json → feature/bar/Barchart_with_negative.json} +0 -0
  81. /package/examples/{stacked-vertical-bar-example-negative.json → feature/bar/stacked-vertical-bar-example-negative.json} +0 -0
  82. /package/examples/{stacked-vertical-bar-example.json → feature/bar/stacked-vertical-bar-example.json} +0 -0
  83. /package/examples/{box-plot-data.json → feature/boxplot/box-plot-data.json} +0 -0
  84. /package/examples/{newdata.json → feature/boxplot/boxplot-data.json} +0 -0
  85. /package/examples/{paired-bar-data.json → feature/paired-bar/paired-bar-data.json} +0 -0
  86. /package/examples/{paired-bar-formatted.json → feature/paired-bar/paired-bar-formatted.json} +0 -0
  87. /package/examples/{case-rate-example-data.json → feature/tests-case-rate/case-rate-example-data.json} +0 -0
  88. /package/examples/{covid-example-data-confidence.json → feature/tests-covid/covid-example-data-confidence.json} +0 -0
  89. /package/examples/{covid-example-data.json → feature/tests-covid/covid-example-data.json} +0 -0
  90. /package/examples/{cutoff-example-data.json → feature/tests-cutoff/cutoff-example-data.json} +0 -0
  91. /package/examples/{date-exclusions-data.json → feature/tests-date-exclusions/date-exclusions-data.json} +0 -0
  92. /package/examples/{example-combo-bar-nonnumeric.json → feature/tests-non-numerics/example-combo-bar-nonnumeric.json} +0 -0
  93. /package/examples/{planet-example-data-nonnumeric.json → feature/tests-non-numerics/planet-example-data-nonnumeric.json} +0 -0
  94. /package/examples/{stacked-vertical-bar-example-nonnumerics.json → feature/tests-non-numerics/stacked-vertical-bar-example-nonnumerics.json} +0 -0
@@ -7,7 +7,7 @@ import LegendCircle from '@cdc/core/components/LegendCircle'
7
7
  import useLegendClasses from './../hooks/useLegendClasses'
8
8
 
9
9
  const Legend = () => {
10
- const { config, legend, colorScale, seriesHighlight, highlight, highlightReset, setSeriesHighlight, dynamicLegendItems, setDynamicLegendItems, transformedData: data, colorPalettes, rawData, setConfig, currentViewport } = useContext(ConfigContext)
10
+ const { config, legend, colorScale, seriesHighlight, highlight, twoColorPalette, highlightReset, setSeriesHighlight, dynamicLegendItems, setDynamicLegendItems, transformedData: data, colorPalettes, rawData, setConfig, currentViewport } = useContext(ConfigContext)
11
11
 
12
12
  const { innerClasses, containerClasses } = useLegendClasses(config)
13
13
 
@@ -25,12 +25,14 @@ const Legend = () => {
25
25
  let tmp = {}
26
26
  colsToKeep.map(col => {
27
27
  tmp[col] = isNaN(dataItem[col]) ? dataItem[col] : dataItem[col]
28
+ return null
28
29
  })
29
30
  return tmp
30
31
  })
31
32
 
32
33
  colsToKeep.map(col => {
33
34
  tmpLabels[col] = col
35
+ return null
34
36
  })
35
37
 
36
38
  if (dynamicLegendItems.length > 0) {
@@ -43,7 +45,7 @@ const Legend = () => {
43
45
  }
44
46
  })
45
47
  }
46
- }, [dynamicLegendItems])
48
+ }, [dynamicLegendItems]) // eslint-disable-line
47
49
 
48
50
  useEffect(() => {
49
51
  if (dynamicLegendItems.length === 0) {
@@ -53,7 +55,9 @@ const Legend = () => {
53
55
  config.runtime.seriesLabelsAll.map(item => {
54
56
  resetSeriesNames.map(col => {
55
57
  tmpLabels[col] = col
58
+ return null
56
59
  })
60
+ return null
57
61
  })
58
62
 
59
63
  setConfig({
@@ -65,7 +69,7 @@ const Legend = () => {
65
69
  }
66
70
  })
67
71
  }
68
- }, [dynamicLegendItems])
72
+ }, [dynamicLegendItems]) // eslint-disable-line
69
73
 
70
74
  const removeDynamicLegendItem = label => {
71
75
  let newLegendItems = dynamicLegendItems.filter(item => item.text !== label.text)
@@ -77,67 +81,75 @@ const Legend = () => {
77
81
  setDynamicLegendItems([...dynamicLegendItems, JSON.parse(e.target.value)])
78
82
  }
79
83
 
80
- const createLegendLabels = (data, defaultLabels) => {
84
+ const createLegendLabels = defaultLabels => {
81
85
  const colorCode = config.legend?.colorCode
82
- if (config.visualizationType !== 'Bar' || config.visualizationSubType !== 'regular' || !colorCode || config.series?.length > 1) {
83
- return defaultLabels
84
- }
85
- let palette = colorPalettes[config.palette]
86
+ if (config.visualizationType === 'Deviation Bar') {
87
+ const [belowColor, aboveColor] = twoColorPalette[config.twoColor.palette]
88
+ const labelBelow = {
89
+ datum: 'X',
90
+ index: 0,
91
+ text: `Below ${config.xAxis.targetLabel}`,
92
+ value: belowColor
93
+ }
94
+ const labelAbove = {
95
+ datum: 'X',
96
+ index: 1,
97
+ text: `Above ${config.xAxis.targetLabel}`,
98
+ value: aboveColor
99
+ }
86
100
 
87
- while (data.length > palette.length) {
88
- palette = palette.concat(palette)
101
+ return [labelBelow, labelAbove]
89
102
  }
90
- palette = palette.slice(0, data.length)
91
- //store uniq values to Set by colorCode
92
- const set = new Set()
93
-
94
- data.forEach(d => set.add(d[colorCode]))
95
-
96
- // create labels with uniq values
97
- const uniqeLabels = Array.from(set).map((val, i) => {
98
- const newLabel = {
99
- datum: val,
100
- index: i,
101
- text: val,
102
- value: palette[i]
103
+ if (config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && colorCode && config.series?.length === 1) {
104
+ let palette = colorPalettes[config.palette]
105
+
106
+ while (data.length > palette.length) {
107
+ palette = palette.concat(palette)
103
108
  }
104
- return newLabel
105
- })
109
+ palette = palette.slice(0, data.length)
110
+ //store uniq values to Set by colorCode
111
+ const set = new Set()
112
+
113
+ data.forEach(d => set.add(d[colorCode]))
114
+
115
+ // create labels with uniq values
116
+ const uniqeLabels = Array.from(set).map((val, i) => {
117
+ const newLabel = {
118
+ datum: val,
119
+ index: i,
120
+ text: val,
121
+ value: palette[i]
122
+ }
123
+ return newLabel
124
+ })
106
125
 
107
- return uniqeLabels
108
- }
109
- // in small screens update config legend position.
110
- useEffect(() => {
111
- if (currentViewport === 'sm' || currentViewport === 'xs' || config.legend.position === 'left') {
112
- setConfig({ ...config, legend: { ...config.legend, position: 'bottom' } })
126
+ return uniqeLabels
113
127
  }
114
- setConfig({ ...config, legend: { ...config.legend, position: 'right' } })
115
- }, [currentViewport])
128
+ return defaultLabels
129
+ }
130
+
131
+ const isBottomOrSmallViewport = config.legend.position === 'bottom' || currentViewport === 'sm' || currentViewport === 'xs' || currentViewport === 'xxs'
132
+ const isHorizontal = config.orientation === 'horizontal'
133
+ const marginTop = isBottomOrSmallViewport && isHorizontal ? `${config.runtime.xAxis.size}px` : '0px'
134
+ const marginBottom = isBottomOrSmallViewport ? '15px' : '0px'
116
135
 
117
- if (!legend) return
136
+ if (!legend) return null
118
137
 
119
138
  if (!legend.dynamicLegend)
120
139
  return config.visualizationType !== 'Box Plot' ? (
121
- <aside
122
- style={{ marginTop: config.legend.position === 'bottom' && config.orientation === 'horizontal' ? `${config.runtime.xAxis.size}px` : '0px', marginBottom: config.legend.position === 'bottom' ? '15px' : '0px' }}
123
- id='legend'
124
- className={containerClasses.join(' ')}
125
- role='region'
126
- aria-label='legend'
127
- tabIndex={0}
128
- >
140
+ <aside style={{ marginTop, marginBottom }} id='legend' className={containerClasses.join(' ')} role='region' aria-label='legend' tabIndex={0}>
129
141
  {legend.label && <h2>{parse(legend.label)}</h2>}
130
142
  {legend.description && <p>{parse(legend.description)}</p>}
131
143
  <LegendOrdinal scale={colorScale} itemDirection='row' labelMargin='0 20px 0 0' shapeMargin='0 10px 0'>
132
144
  {labels => (
133
145
  <div className={innerClasses.join(' ')}>
134
- {createLegendLabels(data, labels).map((label, i) => {
146
+ {createLegendLabels(labels).map((label, i) => {
135
147
  let className = 'legend-item'
136
148
  let itemName = label.datum
137
149
 
138
150
  // Filter excluded data keys from legend
139
151
  if (config.exclusions.active && config.exclusions.keys?.includes(itemName)) {
140
- return
152
+ return null
141
153
  }
142
154
 
143
155
  if (config.runtime.seriesLabels) {
@@ -209,7 +221,7 @@ const Legend = () => {
209
221
 
210
222
  // Filter excluded data keys from legend
211
223
  if (config.exclusions.active && config.exclusions.keys?.includes(itemName)) {
212
- return
224
+ return null
213
225
  }
214
226
 
215
227
  if (config.runtime.seriesLabels) {
@@ -225,6 +237,7 @@ const Legend = () => {
225
237
  if (listItem.text === label.text) {
226
238
  inDynamicList = true
227
239
  }
240
+ return null
228
241
  })
229
242
 
230
243
  if (inDynamicList) return true
@@ -254,7 +267,7 @@ const Legend = () => {
254
267
 
255
268
  // Filter excluded data keys from legend
256
269
  if (config.exclusions.active && config.exclusions.keys?.includes(itemName)) {
257
- return
270
+ return null
258
271
  }
259
272
 
260
273
  if (config.runtime.seriesLabels && !config.legend.dynamicLegend) {
@@ -6,34 +6,18 @@ import { LinePath } from '@visx/shape'
6
6
  import { Text } from '@visx/text'
7
7
 
8
8
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
9
-
10
9
  import ConfigContext from '../ConfigContext'
11
-
12
10
  import useRightAxis from '../hooks/useRightAxis'
11
+ import isNumber from '@cdc/core/helpers/isNumber'
13
12
 
14
13
  export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData, xMax, yMax, seriesStyle = 'Line' }) {
15
- const { colorPalettes, transformedData: data, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, isNumber, cleanData, updateConfig } = useContext(ConfigContext)
16
- // Just do this once up front otherwise we end up
17
- // calling clean several times on same set of data (TT)
18
- const cleanedData = cleanData(data, config.xAxis.dataKey)
19
- const { yScaleRight } = useRightAxis({ config, yMax, data, updateConfig })
14
+ const { colorPalettes, transformedData: data, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, isNumber, updateConfig, handleLineType } = useContext(ConfigContext)
20
15
 
21
- const handleLineType = lineType => {
22
- switch (lineType) {
23
- case 'dashed-sm':
24
- return '5 5'
25
- case 'dashed-md':
26
- return '10 5'
27
- case 'dashed-lg':
28
- return '15 5'
29
- default:
30
- return 0
31
- }
32
- }
16
+ const { yScaleRight } = useRightAxis({ config, yMax, data, updateConfig })
33
17
 
34
18
  const handleAxisFormating = (axis = 'left', label, value) => {
35
19
  // if this is an x axis category/date value return without doing any formatting.
36
- if (label === config.runtime.xAxis.label) return value
20
+ // if (label === config.runtime.xAxis.label) return value
37
21
 
38
22
  axis = String(axis).toLocaleLowerCase()
39
23
  if (label) {
@@ -58,14 +42,13 @@ export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData,
58
42
  opacity={config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(seriesKey) === -1 ? 0.5 : 1}
59
43
  display={config.legend.behavior === 'highlight' || (seriesHighlight.length === 0 && !config.legend.dynamicLegend) || seriesHighlight.indexOf(seriesKey) !== -1 ? 'block' : 'none'}
60
44
  >
61
- {cleanedData.map((d, dataIndex) => {
45
+ {data.map((d, dataIndex) => {
62
46
  // Find the series object from the config.series array that has a dataKey matching the seriesKey variable.
63
47
  const series = config.series.find(({ dataKey }) => dataKey === seriesKey)
64
48
  const { axis } = series
65
49
 
66
50
  const xAxisValue = config.runtime.xAxis.type === 'date' ? formatDate(parseDate(d[config.runtime.xAxis.dataKey])) : d[config.runtime.xAxis.dataKey]
67
51
  const yAxisValue = getYAxisData(d, seriesKey)
68
-
69
52
  const hasMultipleSeries = Object.keys(config.runtime.seriesLabels).length > 1
70
53
  const labeltype = axis === 'Right' ? 'rightLabel' : 'label'
71
54
  let label = config.runtime.yAxis[labeltype]
@@ -85,12 +68,8 @@ export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData,
85
68
  return (
86
69
  d[seriesKey] !== undefined &&
87
70
  d[seriesKey] !== '' &&
88
- d[seriesKey] !== null && (
89
- // isNumber(d[seriesKey]) &&
90
- // isNumber(getYAxisData(d, seriesKey)) &&
91
- // isNumber(getXAxisData(d)) &&
92
- // isNumber(yScaleRight(getXAxisData(d))) &&
93
- // isNumber(yScale(getXAxisData(d))) &&
71
+ d[seriesKey] !== null &&
72
+ isNumber(d[seriesKey]) && (
94
73
  <Group key={`series-${seriesKey}-point-${dataIndex}`}>
95
74
  {/* Render legend */}
96
75
  <Text
@@ -100,7 +79,7 @@ export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData,
100
79
  fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
101
80
  textAnchor='middle'
102
81
  >
103
- {formatNumber(d[seriesKey])}
82
+ {formatNumber(d[seriesKey], 'left')}
104
83
  </Text>
105
84
 
106
85
  <circle
@@ -117,10 +96,9 @@ export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData,
117
96
  )
118
97
  )
119
98
  })}
120
-
121
99
  <LinePath
122
- curve={allCurves.curveLinear}
123
- data={cleanedData}
100
+ curve={allCurves[seriesData[0].lineType]}
101
+ data={data}
124
102
  x={d => xScale(getXAxisData(d))}
125
103
  y={d => (seriesAxis === 'Right' ? yScaleRight(getYAxisData(d, seriesKey)) : yScale(getYAxisData(d, seriesKey)))}
126
104
  stroke={
@@ -134,7 +112,6 @@ export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData,
134
112
  }
135
113
  strokeWidth={2}
136
114
  strokeOpacity={1}
137
- shapeRendering='geometricPrecision'
138
115
  strokeDasharray={lineType ? handleLineType(lineType) : 0}
139
116
  defined={(item, i) => {
140
117
  return item[config.runtime.seriesLabels[seriesKey]] !== '' && item[config.runtime.seriesLabels[seriesKey]] !== null && item[config.runtime.seriesLabels[seriesKey]] !== undefined
@@ -143,8 +120,8 @@ export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData,
143
120
  {config.animate && (
144
121
  <LinePath
145
122
  className='animation'
146
- curve={allCurves.curveLinear}
147
- data={cleanedData}
123
+ curve={seriesData.lineType}
124
+ data={data}
148
125
  x={d => xScale(getXAxisData(d))}
149
126
  y={d => (seriesAxis === 'Right' ? yScaleRight(getYAxisData(d, seriesKey)) : yScale(getYAxisData(d, seriesKey)))}
150
127
  stroke='#fff'
@@ -157,7 +134,6 @@ export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData,
157
134
  }}
158
135
  />
159
136
  )}
160
-
161
137
  {/* Render series labels at end if each line if selected in the editor */}
162
138
  {config.showLineSeriesLabels &&
163
139
  (config.runtime.lineSeriesKeys || config.runtime.seriesKeys).map(seriesKey => {