@cdc/chart 4.24.11 → 4.24.12-2
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.
- package/dist/cdcchart.js +32134 -32039
- package/examples/feature/sankey/sankey-example-data.json +126 -13
- package/examples/feature/tests-date-exclusions/date-exclusions-config.json +372 -12
- package/examples/private/DEV-8850-2.json +493 -0
- package/examples/private/DEV-9822.json +574 -0
- package/examples/private/DEV-9840.json +553 -0
- package/examples/private/DEV-9850-3.json +461 -0
- package/examples/private/chart.json +1084 -0
- package/examples/private/ci_formatted.json +202 -0
- package/examples/private/ci_issue.json +3016 -0
- package/examples/private/completed.json +634 -0
- package/examples/private/dem-data-long.csv +20 -0
- package/examples/private/dem-data-long.json +36 -0
- package/examples/private/demographic_data.csv +157 -0
- package/examples/private/demographic_data.json +2654 -0
- package/examples/private/demographic_dynamic.json +443 -0
- package/examples/private/demographic_standard.json +560 -0
- package/examples/private/ehdi.json +29939 -0
- package/examples/private/test.json +448 -20047
- package/index.html +9 -6
- package/package.json +2 -2
- package/src/CdcChart.tsx +62 -82
- package/src/_stories/Chart.Anchors.stories.tsx +31 -0
- package/src/_stories/Chart.DynamicSeries.stories.tsx +8 -1
- package/src/_stories/Chart.stories.tsx +32 -0
- package/src/_stories/ChartAxisLabels.stories.tsx +4 -1
- package/{examples/feature/area/area-chart-date-city-temperature.json → src/_stories/_mock/area_chart_stacked.json} +125 -27
- package/src/_stories/_mock/line_chart_dynamic_ci.json +493 -0
- package/src/_stories/_mock/line_chart_non_dynamic_ci.json +522 -0
- package/src/_stories/_mock/short_dates.json +288 -0
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +15 -3
- package/src/components/Axis/Categorical.Axis.tsx +2 -2
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +46 -37
- package/src/components/BarChart/components/BarChart.Vertical.tsx +28 -40
- package/src/components/BarChart/helpers/getBarData.ts +28 -0
- package/src/components/BarChart/helpers/tests/getBarData.test.ts +74 -0
- package/src/components/BoxPlot/BoxPlot.tsx +12 -70
- package/src/components/BoxPlot/helpers/index.ts +54 -0
- package/src/components/BrushChart.tsx +23 -26
- package/src/components/EditorPanel/EditorPanel.tsx +55 -79
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +1 -0
- package/src/components/EditorPanel/useEditorPermissions.ts +5 -1
- package/src/components/Legend/Legend.Component.tsx +2 -2
- package/src/{hooks/useLegendClasses.ts → components/Legend/helpers/getLegendClasses.ts} +5 -5
- package/src/components/Legend/helpers/index.ts +2 -1
- package/src/components/Legend/tests/getLegendClasses.test.ts +115 -0
- package/src/components/LineChart/components/LineChart.Circle.tsx +1 -1
- package/src/components/LineChart/helpers.ts +1 -0
- package/src/components/LineChart/index.tsx +47 -1
- package/src/components/LinearChart.tsx +180 -172
- package/src/components/PieChart/PieChart.tsx +7 -1
- package/src/components/Sankey/components/ColumnList.tsx +19 -0
- package/src/components/Sankey/components/Sankey.tsx +479 -0
- package/src/components/Sankey/helpers/getSankeyTooltip.tsx +33 -0
- package/src/components/Sankey/index.tsx +1 -510
- package/src/components/Sankey/sankey.scss +16 -16
- package/src/components/Sankey/types/index.ts +1 -1
- package/src/data/initial-state.js +4 -3
- package/src/helpers/countNumOfTicks.ts +57 -0
- package/src/helpers/getQuartiles.ts +15 -18
- package/src/hooks/useMinMax.ts +18 -4
- package/src/hooks/useScales.ts +38 -4
- package/src/hooks/useTooltip.tsx +5 -1
- package/src/scss/DataTable.scss +5 -0
- package/src/scss/main.scss +6 -2
|
@@ -4,27 +4,24 @@
|
|
|
4
4
|
* @param {Array} arr - The array of integers or decimals.
|
|
5
5
|
* @returns {Object} An object containing the q1 and q3 values.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
arr.sort((a, b) => a - b)
|
|
7
|
+
import _ from 'lodash'
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
const
|
|
9
|
+
export const getQuartiles = (values: number[]): { q1: number; q3: number } => {
|
|
10
|
+
const sortedData: number[] = _.sortBy(values)
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const quantile = (sortedData: number[], q: number): number => {
|
|
13
|
+
const position: number = (sortedData.length - 1) * q
|
|
14
|
+
const base: number = Math.floor(position)
|
|
15
|
+
const rest: number = position - base
|
|
16
|
+
if (sortedData[base + 1] !== undefined) {
|
|
17
|
+
return sortedData[base] + rest * (sortedData[base + 1] - sortedData[base])
|
|
18
|
+
} else {
|
|
19
|
+
return sortedData[base]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
const q3Array = isEvenLength ? arr.slice(medianIndex) : arr.slice(medianIndex + 1)
|
|
23
|
+
const q1: number = quantile(sortedData, 0.25)
|
|
24
|
+
const q3: number = quantile(sortedData, 0.75)
|
|
19
25
|
|
|
20
|
-
// Calculate the median of the first subarray to get the q1 value
|
|
21
|
-
const q1Index = Math.floor(q1Array.length / 2)
|
|
22
|
-
const q1 = isEvenLength ? (q1Array[q1Index - 1] + q1Array[q1Index]) / 2 : q1Array[q1Index]
|
|
23
|
-
|
|
24
|
-
// Calculate the median of the second subarray to get the q3 value
|
|
25
|
-
const q3Index = Math.floor(q3Array.length / 2)
|
|
26
|
-
const q3 = isEvenLength ? (q3Array[q3Index - 1] + q3Array[q3Index]) / 2 : q3Array[q3Index]
|
|
27
|
-
|
|
28
|
-
// Return an object containing the q1 and q3 values
|
|
29
26
|
return { q1, q3 }
|
|
30
27
|
}
|
package/src/hooks/useMinMax.ts
CHANGED
|
@@ -37,7 +37,7 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
37
37
|
|
|
38
38
|
const { visualizationType, series } = config
|
|
39
39
|
const { max: enteredMaxValue, min: enteredMinValue } = config.runtime.yAxis
|
|
40
|
-
const
|
|
40
|
+
const paddingAddedToAxis = config.yAxis.enablePadding ? 1 + config.yAxis.scalePadding / 100 : 1
|
|
41
41
|
const isLogarithmicAxis = config.yAxis.type === 'logarithmic'
|
|
42
42
|
// do validation bafore applying t0 charts
|
|
43
43
|
const isMaxValid = existPositiveValue ? Number(enteredMaxValue) >= maxValue : Number(enteredMaxValue) >= 0
|
|
@@ -52,8 +52,10 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
52
52
|
|
|
53
53
|
if (lower && upper && config.visualizationType === 'Bar') {
|
|
54
54
|
const buffer = min < 0 ? 1.1 : 0
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
const maxValueWithCI = Math.max(...data.flatMap(d => [d[upper], d[lower]])) * paddingAddedToAxis
|
|
56
|
+
const minValueWithCIPlusBuffer = Math.min(...data.flatMap(d => [d[upper], d[lower]])) * paddingAddedToAxis * buffer
|
|
57
|
+
max = max > maxValueWithCI ? max : maxValueWithCI
|
|
58
|
+
min = min < minValueWithCIPlusBuffer ? min : minValueWithCIPlusBuffer
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
if (config.series.filter(s => s?.type === 'Forecasting')) {
|
|
@@ -185,7 +187,15 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
185
187
|
return valueMatch && (index === 0 || index === tableData.length - 1)
|
|
186
188
|
})
|
|
187
189
|
})
|
|
188
|
-
|
|
190
|
+
let isCategoricalAxis = config.yAxis.type === 'categorical'
|
|
191
|
+
min =
|
|
192
|
+
enteredMinValue !== '' && isMinValid
|
|
193
|
+
? Number(enteredMinValue)
|
|
194
|
+
: suppressedMinValue
|
|
195
|
+
? 0
|
|
196
|
+
: isCategoricalAxis
|
|
197
|
+
? 0
|
|
198
|
+
: minValue
|
|
189
199
|
}
|
|
190
200
|
//If data value max wasn't provided, calculate it
|
|
191
201
|
if (max === Number.MIN_VALUE) {
|
|
@@ -226,6 +236,10 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
226
236
|
}
|
|
227
237
|
}
|
|
228
238
|
|
|
239
|
+
if (config.visualizationType === 'Area Chart' && config.visualizationSubType === 'stacked') {
|
|
240
|
+
min = 0
|
|
241
|
+
}
|
|
242
|
+
|
|
229
243
|
return { min, max, leftMax, rightMax }
|
|
230
244
|
}
|
|
231
245
|
export default useMinMax
|
package/src/hooks/useScales.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
LinearScaleConfig,
|
|
3
|
+
LogScaleConfig,
|
|
4
|
+
scaleBand,
|
|
5
|
+
scaleLinear,
|
|
6
|
+
scaleLog,
|
|
7
|
+
scalePoint,
|
|
8
|
+
scaleTime,
|
|
9
|
+
getTicks
|
|
10
|
+
} from '@visx/scale'
|
|
2
11
|
import { useContext } from 'react'
|
|
3
12
|
import ConfigContext from '../ConfigContext'
|
|
4
13
|
import { ChartConfig } from '../types/ChartConfig'
|
|
5
14
|
import { ChartContext } from '../types/ChartContext'
|
|
15
|
+
import _ from 'lodash'
|
|
6
16
|
|
|
7
17
|
const scaleTypes = {
|
|
8
18
|
TIME: 'time',
|
|
@@ -154,6 +164,9 @@ const useScales = (properties: useScaleProps) => {
|
|
|
154
164
|
|
|
155
165
|
// Set Scales
|
|
156
166
|
|
|
167
|
+
const categories = _.uniq(data.map(d => d[config.xAxis.dataKey]))
|
|
168
|
+
const range = [0, config.barThickness * 100 || 1]
|
|
169
|
+
const domain = _.map(config.series, 'dataKey')
|
|
157
170
|
yScale = scaleLinear({
|
|
158
171
|
range: [yMax, 0],
|
|
159
172
|
round: true,
|
|
@@ -161,11 +174,10 @@ const useScales = (properties: useScaleProps) => {
|
|
|
161
174
|
})
|
|
162
175
|
xScale = scaleBand({
|
|
163
176
|
range: [0, xMax],
|
|
164
|
-
domain:
|
|
177
|
+
domain: categories
|
|
165
178
|
})
|
|
166
179
|
xScale.type = scaleTypes.BAND
|
|
167
|
-
|
|
168
|
-
seriesScale = composeScalePoint(seriesDomain, [0, yMax])
|
|
180
|
+
seriesScale = composeScaleBand(domain, range)
|
|
169
181
|
}
|
|
170
182
|
|
|
171
183
|
// handle Paired bar
|
|
@@ -327,6 +339,28 @@ export const getTickValues = (xAxisDataMapped, xScale, num, config) => {
|
|
|
327
339
|
}
|
|
328
340
|
}
|
|
329
341
|
|
|
342
|
+
// Ensure that the last tick is shown for charts with a "Date (Linear Scale)" scale
|
|
343
|
+
export const filterAndShiftLinearDateTicks = (config, axisProps, xAxisDataMapped, formatDate) => {
|
|
344
|
+
let ticks = axisProps.ticks
|
|
345
|
+
const filteredTickValues = getTicks(axisProps.scale, axisProps.numTicks)
|
|
346
|
+
if (filteredTickValues.length < xAxisDataMapped.length) {
|
|
347
|
+
let shift = 0
|
|
348
|
+
const lastIdx = xAxisDataMapped.indexOf(filteredTickValues[filteredTickValues.length - 1])
|
|
349
|
+
if (lastIdx < xAxisDataMapped.length - 1) {
|
|
350
|
+
shift = !config.xAxis.sortByRecentDate
|
|
351
|
+
? xAxisDataMapped.length - 1 - lastIdx
|
|
352
|
+
: xAxisDataMapped.indexOf(filteredTickValues[0]) * -1
|
|
353
|
+
}
|
|
354
|
+
ticks = filteredTickValues.map(value => {
|
|
355
|
+
return axisProps.ticks[axisProps.ticks.findIndex(tick => tick.value === value) + shift]
|
|
356
|
+
})
|
|
357
|
+
}
|
|
358
|
+
ticks.forEach((tick, i) => {
|
|
359
|
+
tick.formattedValue = formatDate(tick.value, i, ticks)
|
|
360
|
+
})
|
|
361
|
+
return ticks
|
|
362
|
+
}
|
|
363
|
+
|
|
330
364
|
/// helper functions
|
|
331
365
|
const composeXScale = ({ min, max, xMax, config }) => {
|
|
332
366
|
// Adjust min value if using logarithmic scale
|
package/src/hooks/useTooltip.tsx
CHANGED
|
@@ -553,9 +553,13 @@ export const useTooltip = props => {
|
|
|
553
553
|
(!pd.column || key === pd.column)
|
|
554
554
|
)) ||
|
|
555
555
|
{}
|
|
556
|
-
|
|
556
|
+
let newValue = label || value
|
|
557
557
|
const style = displayGray ? { color: '#8b8b8a' } : {}
|
|
558
558
|
|
|
559
|
+
if (index == 1 && config.dataFormat.onlyShowTopPrefixSuffix) {
|
|
560
|
+
newValue = `${config.dataFormat.prefix}${newValue}${config.dataFormat.suffix}`
|
|
561
|
+
}
|
|
562
|
+
|
|
559
563
|
return <li style={style} className='tooltip-body'>{`${getSeriesNameFromLabel(key)}: ${newValue}`}</li>
|
|
560
564
|
}
|
|
561
565
|
|
package/src/scss/DataTable.scss
CHANGED
package/src/scss/main.scss
CHANGED
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
.subtext--responsive-ticks,
|
|
141
141
|
.section-subtext {
|
|
142
142
|
&--brush-active {
|
|
143
|
-
margin-top:
|
|
143
|
+
margin-top: 3em !important;
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
border: 1px solid var(--lightGray);
|
|
160
160
|
position: relative;
|
|
161
161
|
|
|
162
|
-
&.
|
|
162
|
+
&.border-0 {
|
|
163
163
|
border: 1px solid transparent;
|
|
164
164
|
padding: 0;
|
|
165
165
|
}
|
|
@@ -261,6 +261,10 @@
|
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
.legend-container__inner.flex-column-reverse div.legend-item:last-child {
|
|
265
|
+
margin-bottom: 0.2rem !important;
|
|
266
|
+
}
|
|
267
|
+
|
|
264
268
|
.dynamic-legend-list {
|
|
265
269
|
// overide traditional legend item that uses !important
|
|
266
270
|
.legend-item {
|