@cdc/chart 4.24.12 → 4.25.2-25
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 +79900 -78999
- package/examples/feature/boxplot/boxplot.json +2 -157
- package/examples/feature/boxplot/testing.csv +23 -38
- package/examples/feature/tests-non-numerics/example-combo-bar-nonnumeric.json +579 -49
- package/examples/private/ehdi.json +29939 -0
- package/examples/private/line-issue.json +497 -0
- package/examples/private/not-loading.json +360 -0
- package/index.html +11 -15
- package/package.json +2 -2
- package/src/CdcChart.tsx +92 -1512
- package/src/CdcChartComponent.tsx +1113 -0
- package/src/ConfigContext.tsx +6 -1
- package/src/_stories/Chart.Anchors.stories.tsx +1 -1
- package/src/_stories/Chart.CustomColors.stories.tsx +1 -1
- package/src/_stories/Chart.DynamicSeries.stories.tsx +17 -2
- package/src/_stories/Chart.Filters.stories.tsx +19 -0
- package/src/_stories/Chart.Legend.Gradient.stories.tsx +2 -2
- package/src/_stories/Chart.ScatterPlot.stories.tsx +19 -0
- package/src/_stories/Chart.tooltip.stories.tsx +1 -2
- package/src/_stories/ChartAnnotation.stories.tsx +1 -1
- package/src/_stories/ChartAxisLabels.stories.tsx +1 -1
- package/src/_stories/ChartAxisTitles.stories.tsx +1 -1
- package/src/_stories/ChartEditor.stories.tsx +1 -1
- package/src/_stories/ChartLine.Suppression.stories.tsx +1 -1
- package/src/_stories/ChartLine.Symbols.stories.tsx +18 -0
- package/src/_stories/ChartPrefixSuffix.stories.tsx +1 -1
- package/src/_stories/_mock/line_chart_symbols.json +437 -0
- package/src/_stories/_mock/scatterplot-image-download.json +1244 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +3 -11
- package/src/components/Annotations/components/AnnotationDropdown.tsx +3 -3
- package/src/components/Axis/Categorical.Axis.tsx +3 -4
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +14 -5
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +10 -4
- package/src/components/BarChart/components/BarChart.Vertical.tsx +5 -7
- package/src/components/BarChart/components/BarChart.jsx +24 -4
- package/src/components/BarChart/components/context.tsx +1 -0
- package/src/components/BoxPlot/BoxPlot.tsx +34 -32
- package/src/components/BoxPlot/helpers/index.ts +108 -18
- package/src/components/BrushChart.tsx +44 -24
- package/src/components/DeviationBar.jsx +2 -6
- package/src/components/EditorPanel/EditorPanel.tsx +64 -8
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +4 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +3 -1
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +44 -7
- package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +6 -1
- package/src/components/ForestPlot/ForestPlot.tsx +176 -26
- package/src/components/Legend/Legend.Component.tsx +29 -38
- package/src/components/Legend/Legend.Suppression.tsx +3 -5
- package/src/components/Legend/Legend.tsx +2 -2
- package/src/components/Legend/LegendLine.Shape.tsx +51 -0
- package/src/components/Legend/helpers/createFormatLabels.tsx +29 -26
- package/src/components/Legend/helpers/getLegendClasses.ts +20 -38
- package/src/components/Legend/helpers/index.ts +22 -9
- package/src/components/Legend/tests/getLegendClasses.test.ts +3 -20
- package/src/components/LineChart/components/LineChart.Circle.tsx +104 -94
- package/src/components/LineChart/index.tsx +6 -2
- package/src/components/LinearChart.tsx +77 -43
- package/src/components/PairedBarChart.jsx +2 -9
- package/src/components/ZoomBrush.tsx +5 -7
- package/src/data/initial-state.js +6 -3
- package/src/helpers/getBoxPlotConfig.ts +68 -0
- package/src/helpers/getColorScale.ts +24 -0
- package/src/helpers/getComboChartConfig.ts +42 -0
- package/src/helpers/getExcludedData.ts +37 -0
- package/src/helpers/getTopAxis.ts +7 -0
- package/src/helpers/isConvertLineToBarGraph.ts +10 -3
- package/src/hooks/useBarChart.ts +40 -13
- package/src/hooks/{useHighlightedBars.js → useHighlightedBars.ts} +2 -1
- package/src/hooks/useIntersectionObserver.ts +37 -0
- package/src/hooks/useMinMax.ts +11 -8
- package/src/hooks/useReduceData.ts +1 -1
- package/src/hooks/useScales.ts +10 -0
- package/src/hooks/useTooltip.tsx +21 -2
- package/src/index.jsx +1 -0
- package/src/scss/DataTable.scss +0 -5
- package/src/scss/main.scss +31 -116
- package/src/store/chart.actions.ts +40 -0
- package/src/store/chart.reducer.ts +83 -0
- package/src/types/ChartConfig.ts +6 -3
- package/src/types/ChartContext.ts +1 -3
- package/src/helpers/getQuartiles.ts +0 -27
- package/src/hooks/useColorScale.ts +0 -50
- package/src/hooks/useIntersectionObserver.jsx +0 -29
- package/src/hooks/useTopAxis.js +0 -6
|
@@ -26,8 +26,7 @@ import Regions from './Regions'
|
|
|
26
26
|
import CategoricalYAxis from './Axis/Categorical.Axis'
|
|
27
27
|
|
|
28
28
|
// Helpers
|
|
29
|
-
import {
|
|
30
|
-
import { isLegendWrapViewport } from '@cdc/core/helpers/viewports'
|
|
29
|
+
import { isLegendWrapViewport, isMobileHeightViewport } from '@cdc/core/helpers/viewports'
|
|
31
30
|
import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
|
|
32
31
|
import { calcInitialHeight } from '../helpers/sizeHelpers'
|
|
33
32
|
|
|
@@ -36,13 +35,13 @@ import useMinMax from '../hooks/useMinMax'
|
|
|
36
35
|
import useReduceData from '../hooks/useReduceData'
|
|
37
36
|
import useRightAxis from '../hooks/useRightAxis'
|
|
38
37
|
import useScales, { getTickValues, filterAndShiftLinearDateTicks } from '../hooks/useScales'
|
|
39
|
-
import
|
|
38
|
+
import getTopAxis from '../helpers/getTopAxis'
|
|
40
39
|
import { useTooltip as useCoveTooltip } from '../hooks/useTooltip'
|
|
41
40
|
import { useEditorPermissions } from './EditorPanel/useEditorPermissions'
|
|
42
41
|
import Annotation from './Annotations'
|
|
43
42
|
import { BlurStrokeText } from '@cdc/core/components/BlurStrokeText'
|
|
44
|
-
import { fontSizes } from '@cdc/core/helpers/cove/fontSettings'
|
|
45
43
|
import { countNumOfTicks } from '../helpers/countNumOfTicks'
|
|
44
|
+
import _ from 'lodash'
|
|
46
45
|
|
|
47
46
|
type LinearChartProps = {
|
|
48
47
|
parentWidth: number
|
|
@@ -50,9 +49,14 @@ type LinearChartProps = {
|
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
const BOTTOM_LABEL_PADDING = 9
|
|
53
|
-
const X_TICK_LABEL_PADDING =
|
|
52
|
+
const X_TICK_LABEL_PADDING = 4.5
|
|
54
53
|
const DEFAULT_TICK_LENGTH = 8
|
|
55
54
|
const MONTH_AS_MS = 1000 * 60 * 60 * 24 * 30
|
|
55
|
+
const TICK_LABEL_FONT_SIZE = 16
|
|
56
|
+
const TICK_LABEL_FONT_SIZE_SMALL = 13
|
|
57
|
+
const AXIS_LABEL_FONT_SIZE = 18
|
|
58
|
+
const AXIS_LABEL_FONT_SIZE_SMALL = 14
|
|
59
|
+
const TICK_LABEL_MARGIN_RIGHT = 4.5
|
|
56
60
|
|
|
57
61
|
const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, parentWidth }, svgRef) => {
|
|
58
62
|
// prettier-ignore
|
|
@@ -60,6 +64,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
60
64
|
brushConfig,
|
|
61
65
|
colorScale,
|
|
62
66
|
config,
|
|
67
|
+
convertLineToBarGraph,
|
|
63
68
|
currentViewport,
|
|
64
69
|
dimensions,
|
|
65
70
|
formatDate,
|
|
@@ -99,7 +104,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
99
104
|
// HOOKS % STATES
|
|
100
105
|
const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, data)
|
|
101
106
|
const { visSupportsReactTooltip } = useEditorPermissions()
|
|
102
|
-
const { hasTopAxis } =
|
|
107
|
+
const { hasTopAxis } = getTopAxis(config)
|
|
103
108
|
const [animatedChart, setAnimatedChart] = useState(false)
|
|
104
109
|
const [point, setPoint] = useState({ x: 0, y: 0 })
|
|
105
110
|
const [suffixWidth, setSuffixWidth] = useState(0)
|
|
@@ -129,6 +134,9 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
129
134
|
const labelsOverflow = onlyShowTopPrefixSuffix && !suffixHasNoSpace
|
|
130
135
|
const padding = orientation === 'horizontal' ? Number(config.xAxis.size) : Number(config.yAxis.size)
|
|
131
136
|
const yLabelOffset = isNaN(parseInt(`${runtime.yAxis.labelOffset}`)) ? 0 : parseInt(`${runtime.yAxis.labelOffset}`)
|
|
137
|
+
const tickLabelFontSize = isMobileHeightViewport(currentViewport) ? TICK_LABEL_FONT_SIZE_SMALL : TICK_LABEL_FONT_SIZE
|
|
138
|
+
const axisLabelFontSize = isMobileHeightViewport(currentViewport) ? AXIS_LABEL_FONT_SIZE_SMALL : AXIS_LABEL_FONT_SIZE
|
|
139
|
+
const GET_TEXT_WIDTH_FONT = `normal ${tickLabelFontSize}px Nunito, sans-serif`
|
|
132
140
|
|
|
133
141
|
// zero if not forest plot
|
|
134
142
|
const forestRowsHeight = isForestPlot ? config.data.length * config.forestPlot.rowHeight : 0
|
|
@@ -249,10 +257,6 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
249
257
|
const useDateSpanMonths = isDateTime && dateSpanMonths > xTickCount
|
|
250
258
|
|
|
251
259
|
// GETTERS & FUNCTIONS
|
|
252
|
-
const checkLineToBarGraph = () => {
|
|
253
|
-
return isConvertLineToBarGraph(config.visualizationType, data, config.allowLineToBarGraph)
|
|
254
|
-
}
|
|
255
|
-
|
|
256
260
|
const handleLeftTickFormatting = (tick, index, ticks) => {
|
|
257
261
|
if (isLogarithmicAxis && tick === 0.1) {
|
|
258
262
|
//when logarithmic scale applied change value of first tick
|
|
@@ -377,7 +381,8 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
377
381
|
const topLabelOnGridline = topYLabelRef.current && yAxis.labelsAboveGridlines
|
|
378
382
|
|
|
379
383
|
// Heights to add
|
|
380
|
-
|
|
384
|
+
|
|
385
|
+
const brushHeight = brush?.active ? brush?.height + brush?.height : 0
|
|
381
386
|
const forestRowsHeight = isForestPlot ? config.data.length * forestPlot.rowHeight : 0
|
|
382
387
|
const topLabelOnGridlineHeight = topLabelOnGridline ? topYLabelRef.current.getBBox().height : 0
|
|
383
388
|
const additionalHeight = axisBottomHeight + brushHeight + forestRowsHeight + topLabelOnGridlineHeight
|
|
@@ -410,21 +415,37 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
410
415
|
useEffect(() => {
|
|
411
416
|
if (lastMaxValue.current === maxValue) return
|
|
412
417
|
lastMaxValue.current = maxValue
|
|
418
|
+
|
|
413
419
|
if (!yAxisAutoPadding) return
|
|
414
420
|
setYAxisAutoPadding(0)
|
|
415
421
|
}, [maxValue])
|
|
422
|
+
|
|
416
423
|
useEffect(() => {
|
|
417
424
|
if (orientation === 'horizontal') return
|
|
425
|
+
if (!labelsOverflow) return
|
|
426
|
+
|
|
427
|
+
// minimum percentage of the max value that the distance should be from the top grid line
|
|
428
|
+
const MINIMUM_DISTANCE_PERCENTAGE = 0.025
|
|
418
429
|
|
|
419
|
-
const
|
|
430
|
+
const topGridLine = Math.max(...yScale.ticks(handleNumTicks))
|
|
431
|
+
const needsPaddingThreshold = topGridLine - maxValue * MINIMUM_DISTANCE_PERCENTAGE
|
|
432
|
+
const maxValueIsGreaterThanThreshold = maxValue > needsPaddingThreshold
|
|
420
433
|
|
|
421
|
-
if (!
|
|
434
|
+
if (!maxValueIsGreaterThanThreshold) return
|
|
422
435
|
|
|
423
|
-
const
|
|
436
|
+
const ticks = yScale.ticks(handleNumTicks)
|
|
437
|
+
const tickGap = ticks.length === 1 ? ticks[0] : ticks[1] - ticks[0]
|
|
424
438
|
const nextTick = Math.max(...yScale.ticks(handleNumTicks)) + tickGap
|
|
425
|
-
const
|
|
439
|
+
const divideBy = minValue < 0 ? maxValue / 2 : maxValue
|
|
440
|
+
const calculatedPadding = (nextTick - maxValue) / divideBy
|
|
441
|
+
|
|
442
|
+
// if auto padding is too close to next tick, add one more ticks worth of padding
|
|
443
|
+
const newPadding =
|
|
444
|
+
calculatedPadding > MINIMUM_DISTANCE_PERCENTAGE ? calculatedPadding : calculatedPadding + tickGap / divideBy
|
|
426
445
|
|
|
427
|
-
|
|
446
|
+
/* sometimes even though the padding is getting to the next tick exactly,
|
|
447
|
+
d3 still doesn't show the tick. we add 0.1 to ensure to tip it over the edge */
|
|
448
|
+
setYAxisAutoPadding(newPadding * 100 + 0.1)
|
|
428
449
|
}, [maxValue, labelsOverflow, yScale, handleNumTicks])
|
|
429
450
|
|
|
430
451
|
// Render Functions
|
|
@@ -433,12 +454,12 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
433
454
|
|
|
434
455
|
const getTickPositions = (ticks, xScale) => {
|
|
435
456
|
if (!ticks.length) return false
|
|
436
|
-
//
|
|
457
|
+
// filter out first index
|
|
437
458
|
const filteredTicks = ticks.filter(tick => tick.index !== 0)
|
|
438
459
|
const numberOfTicks = filteredTicks?.length
|
|
439
460
|
const xMaxHalf = xScale.range()[0] || xMax / 2
|
|
440
461
|
const tickWidthAll = filteredTicks.map(tick =>
|
|
441
|
-
getTextWidth(formatNumber(tick.value, 'left'),
|
|
462
|
+
getTextWidth(formatNumber(tick.value, 'left'), GET_TEXT_WIDTH_FONT)
|
|
442
463
|
)
|
|
443
464
|
const accumulator = 100
|
|
444
465
|
const sumOfTickWidth = tickWidthAll.reduce((a, b) => a + b, accumulator)
|
|
@@ -475,10 +496,6 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
475
496
|
return (
|
|
476
497
|
<Group className='bottom-axis'>
|
|
477
498
|
{props.ticks.map((tick, i) => {
|
|
478
|
-
const textWidth = getTextWidth(
|
|
479
|
-
formatNumber(tick.value, 'left'),
|
|
480
|
-
`normal ${fontSizes[config.fontSize]}px sans-serif`
|
|
481
|
-
)
|
|
482
499
|
const isTicksOverlapping = getTickPositions(props.ticks, g1xScale)
|
|
483
500
|
const maxTickRotation = Number(config.xAxis.maxTickRotation) || 90
|
|
484
501
|
const isResponsiveTicks = config.isResponsiveTicks && isTicksOverlapping
|
|
@@ -497,6 +514,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
497
514
|
angle={-angle}
|
|
498
515
|
verticalAnchor={angle ? 'middle' : 'start'}
|
|
499
516
|
textAnchor={textAnchor}
|
|
517
|
+
fontSize={tickLabelFontSize}
|
|
500
518
|
>
|
|
501
519
|
{formatNumber(tick.value, 'left')}
|
|
502
520
|
</Text>
|
|
@@ -527,10 +545,6 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
527
545
|
<>
|
|
528
546
|
<Group className='bottom-axis'>
|
|
529
547
|
{props.ticks.map((tick, i) => {
|
|
530
|
-
const textWidth = getTextWidth(
|
|
531
|
-
formatNumber(tick.value, 'left'),
|
|
532
|
-
`normal ${fontSizes[config.fontSize]}px sans-serif`
|
|
533
|
-
)
|
|
534
548
|
const isTicksOverlapping = getTickPositions(props.ticks, g2xScale)
|
|
535
549
|
const maxTickRotation = Number(config.xAxis.maxTickRotation) || 90
|
|
536
550
|
const isResponsiveTicks = config.isResponsiveTicks && isTicksOverlapping
|
|
@@ -548,6 +562,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
548
562
|
angle={-angle}
|
|
549
563
|
verticalAnchor={angle ? 'middle' : 'start'}
|
|
550
564
|
textAnchor={textAnchor}
|
|
565
|
+
fontSize={tickLabelFontSize}
|
|
551
566
|
>
|
|
552
567
|
{formatNumber(tick.value, 'left')}
|
|
553
568
|
</Text>
|
|
@@ -565,6 +580,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
565
580
|
stroke='#333'
|
|
566
581
|
textAnchor={'middle'}
|
|
567
582
|
verticalAnchor='start'
|
|
583
|
+
fontSize={axisLabelFontSize}
|
|
568
584
|
>
|
|
569
585
|
{runtime.xAxis.label}
|
|
570
586
|
</Text>
|
|
@@ -641,6 +657,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
641
657
|
transform={`translate(${-1 * runtime.yAxis.size + yLabelOffset}, ${axisCenter}) rotate(-90)`}
|
|
642
658
|
fontWeight='bold'
|
|
643
659
|
fill={config.yAxis.labelColor}
|
|
660
|
+
fontSize={axisLabelFontSize}
|
|
644
661
|
>
|
|
645
662
|
{props.label}
|
|
646
663
|
</Text>
|
|
@@ -712,7 +729,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
712
729
|
showTooltip={showTooltip}
|
|
713
730
|
/>
|
|
714
731
|
)}
|
|
715
|
-
{(visualizationType === 'Bar' || visualizationType === 'Combo' ||
|
|
732
|
+
{(visualizationType === 'Bar' || visualizationType === 'Combo' || convertLineToBarGraph) && (
|
|
716
733
|
<BarChart
|
|
717
734
|
xScale={xScale}
|
|
718
735
|
yScale={yScale}
|
|
@@ -731,7 +748,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
731
748
|
chartRef={svgRef}
|
|
732
749
|
/>
|
|
733
750
|
)}
|
|
734
|
-
{((visualizationType === 'Line' && !
|
|
751
|
+
{((visualizationType === 'Line' && !convertLineToBarGraph) ||
|
|
735
752
|
visualizationType === 'Combo' ||
|
|
736
753
|
visualizationType === 'Bump Chart') && (
|
|
737
754
|
<LineChart
|
|
@@ -795,7 +812,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
795
812
|
{!['Paired Bar', 'Box Plot', 'Area Chart', 'Scatter Plot', 'Deviation Bar', 'Forecasting', 'Bar'].includes(
|
|
796
813
|
visualizationType
|
|
797
814
|
) &&
|
|
798
|
-
!
|
|
815
|
+
!convertLineToBarGraph && (
|
|
799
816
|
<>
|
|
800
817
|
<LineChart
|
|
801
818
|
xScale={xScale}
|
|
@@ -928,7 +945,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
928
945
|
{config.chartMessage.noData}
|
|
929
946
|
</Text>
|
|
930
947
|
)}
|
|
931
|
-
{(config.visualizationType === 'Bar' ||
|
|
948
|
+
{(config.visualizationType === 'Bar' || convertLineToBarGraph) &&
|
|
932
949
|
config.tooltips.singleSeries &&
|
|
933
950
|
config.visual.horizontalHoverLine && (
|
|
934
951
|
<Group
|
|
@@ -947,7 +964,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
947
964
|
/>
|
|
948
965
|
</Group>
|
|
949
966
|
)}
|
|
950
|
-
{(config.visualizationType === 'Bar' ||
|
|
967
|
+
{(config.visualizationType === 'Bar' || convertLineToBarGraph) &&
|
|
951
968
|
config.tooltips.singleSeries &&
|
|
952
969
|
config.visual.verticalHoverLine && (
|
|
953
970
|
<Group key='tooltipLine-vertical' className='vertical-tooltip-line'>
|
|
@@ -1034,7 +1051,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1034
1051
|
const lastTick = props.ticks.length - 1 === i
|
|
1035
1052
|
const hideTopTick = lastTick && onlyShowTopPrefixSuffix && suffix && !suffixHasNoSpace
|
|
1036
1053
|
const valueOnLinePadding = hideAxis ? -8 : -12
|
|
1037
|
-
const labelXPadding = labelsAboveGridlines ? valueOnLinePadding :
|
|
1054
|
+
const labelXPadding = labelsAboveGridlines ? valueOnLinePadding : TICK_LABEL_MARGIN_RIGHT
|
|
1038
1055
|
const labelYPadding = labelsAboveGridlines ? 4 : 0
|
|
1039
1056
|
const labelX = tick.to.x - labelXPadding
|
|
1040
1057
|
const labelY = tick.to.y - labelYPadding
|
|
@@ -1051,6 +1068,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1051
1068
|
to={isLogarithmicAxis ? to : tick.to}
|
|
1052
1069
|
stroke={config.yAxis.tickColor}
|
|
1053
1070
|
display={orientation === 'horizontal' ? 'none' : 'block'}
|
|
1071
|
+
fontSize={tickLabelFontSize}
|
|
1054
1072
|
/>
|
|
1055
1073
|
)}
|
|
1056
1074
|
|
|
@@ -1068,6 +1086,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1068
1086
|
}) rotate(-${config.runtime.horizontal ? config.runtime.yAxis.tickRotation || 0 : 0})`}
|
|
1069
1087
|
verticalAnchor={'start'}
|
|
1070
1088
|
textAnchor={'end'}
|
|
1089
|
+
fontSize={tickLabelFontSize}
|
|
1071
1090
|
>
|
|
1072
1091
|
{tick.formattedValue}
|
|
1073
1092
|
</Text>
|
|
@@ -1083,6 +1102,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1083
1102
|
}) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
|
|
1084
1103
|
verticalAnchor={'start'}
|
|
1085
1104
|
textAnchor={'end'}
|
|
1105
|
+
fontSize={tickLabelFontSize}
|
|
1086
1106
|
>
|
|
1087
1107
|
{tick.formattedValue}
|
|
1088
1108
|
</Text>
|
|
@@ -1097,6 +1117,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1097
1117
|
}) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
|
|
1098
1118
|
textAnchor={'end'}
|
|
1099
1119
|
verticalAnchor='middle'
|
|
1120
|
+
fontSize={tickLabelFontSize}
|
|
1100
1121
|
>
|
|
1101
1122
|
{tick.formattedValue}
|
|
1102
1123
|
</Text>
|
|
@@ -1112,6 +1133,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1112
1133
|
}) rotate(-${runtime.horizontal ? runtime.yAxis.tickRotation : 0})`}
|
|
1113
1134
|
textAnchor={'end'}
|
|
1114
1135
|
verticalAnchor='middle'
|
|
1136
|
+
fontSize={tickLabelFontSize}
|
|
1115
1137
|
>
|
|
1116
1138
|
{tick.formattedValue}
|
|
1117
1139
|
</Text>
|
|
@@ -1130,6 +1152,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1130
1152
|
verticalAnchor={config.runtime.horizontal ? 'start' : 'middle'}
|
|
1131
1153
|
textAnchor={config.runtime.horizontal ? 'start' : 'end'}
|
|
1132
1154
|
fill={config.yAxis.tickLabelColor}
|
|
1155
|
+
fontSize={tickLabelFontSize}
|
|
1133
1156
|
>
|
|
1134
1157
|
{config.runtime.seriesLabelsAll[tick.formattedValue - 1]}
|
|
1135
1158
|
</Text>
|
|
@@ -1172,6 +1195,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1172
1195
|
paintOrder={'stroke'} // keeps stroke under fill
|
|
1173
1196
|
strokeLinejoin='round'
|
|
1174
1197
|
style={{ whiteSpace: 'pre-wrap' }} // prevents leading spaces from being trimmed
|
|
1198
|
+
fontSize={tickLabelFontSize}
|
|
1175
1199
|
>
|
|
1176
1200
|
{suffix}
|
|
1177
1201
|
</BlurStrokeText>
|
|
@@ -1193,6 +1217,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1193
1217
|
strokeLinejoin='round'
|
|
1194
1218
|
paintOrder={'stroke'} // keeps stroke under fill
|
|
1195
1219
|
style={{ whiteSpace: 'pre-wrap' }} // prevents leading spaces from being trimmed
|
|
1220
|
+
fontSize={tickLabelFontSize}
|
|
1196
1221
|
>
|
|
1197
1222
|
{`${tick.formattedValue}${combineDomSuffixWithValue ? suffix : ''}`}
|
|
1198
1223
|
</BlurStrokeText>
|
|
@@ -1208,6 +1233,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1208
1233
|
transform={`translate(${-1 * runtime.yAxis.size + yLabelOffset}, ${axisCenter}) rotate(-90)`}
|
|
1209
1234
|
fontWeight='bold'
|
|
1210
1235
|
fill={config.yAxis.labelColor}
|
|
1236
|
+
fontSize={axisLabelFontSize}
|
|
1211
1237
|
>
|
|
1212
1238
|
{props.label}
|
|
1213
1239
|
</Text>
|
|
@@ -1270,6 +1296,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1270
1296
|
verticalAnchor={runtime.horizontal ? 'start' : 'middle'}
|
|
1271
1297
|
textAnchor={'start'}
|
|
1272
1298
|
fill={config.yAxis.rightAxisTickLabelColor}
|
|
1299
|
+
fontSize={tickLabelFontSize}
|
|
1273
1300
|
>
|
|
1274
1301
|
{tick.formattedValue}
|
|
1275
1302
|
</Text>
|
|
@@ -1289,6 +1316,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1289
1316
|
}, ${axisCenter}) rotate(-90)`}
|
|
1290
1317
|
fontWeight='bold'
|
|
1291
1318
|
fill={config.yAxis.rightAxisLabelColor}
|
|
1319
|
+
fontSize={axisLabelFontSize}
|
|
1292
1320
|
>
|
|
1293
1321
|
{props.label}
|
|
1294
1322
|
</Text>
|
|
@@ -1328,17 +1356,18 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1328
1356
|
numTicks={useDateSpanMonths ? dateSpanMonths : xTickCount}
|
|
1329
1357
|
tickStroke='#333'
|
|
1330
1358
|
tickValues={
|
|
1331
|
-
config.xAxis.manual
|
|
1359
|
+
config.runtime.xAxis.manual
|
|
1332
1360
|
? getTickValues(xAxisDataMapped, xScale, isDateTime ? xTickCount : getManualStep(), config)
|
|
1333
|
-
: config.xAxis.type === 'date'
|
|
1361
|
+
: config.runtime.xAxis.type === 'date'
|
|
1334
1362
|
? xAxisDataMapped
|
|
1335
1363
|
: undefined
|
|
1336
1364
|
}
|
|
1337
1365
|
>
|
|
1338
1366
|
{props => {
|
|
1367
|
+
const hasDynamicCategory = config.series.some(s => s.dynamicCategory)
|
|
1339
1368
|
// For these charts, we generated all ticks in tickValues above, and now need to filter/shift them
|
|
1340
1369
|
// so the last tick is always labeled
|
|
1341
|
-
if (config.xAxis.type === 'date' && !config.xAxis.manual) {
|
|
1370
|
+
if (config.runtime.xAxis.type === 'date' && !config.runtime.xAxis.manual && !hasDynamicCategory) {
|
|
1342
1371
|
props.ticks = filterAndShiftLinearDateTicks(config, props, xAxisDataMapped, formatDate)
|
|
1343
1372
|
}
|
|
1344
1373
|
|
|
@@ -1346,7 +1375,11 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1346
1375
|
useDateSpanMonths &&
|
|
1347
1376
|
xScale
|
|
1348
1377
|
.ticks(xTickCount)
|
|
1349
|
-
.map(t =>
|
|
1378
|
+
.map(t =>
|
|
1379
|
+
props.ticks.findIndex(
|
|
1380
|
+
tick => (typeof tick.value === 'number' ? tick.value : tick.value.getTime()) === t.getTime()
|
|
1381
|
+
)
|
|
1382
|
+
)
|
|
1350
1383
|
.slice(0, 2)
|
|
1351
1384
|
.reduce((acc, curr) => curr - acc)
|
|
1352
1385
|
|
|
@@ -1370,16 +1403,12 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1370
1403
|
|
|
1371
1404
|
// Calculate sumOfTickWidth here, before map function
|
|
1372
1405
|
const tickWidthMax = Math.max(
|
|
1373
|
-
...filteredTicks.map(tick =>
|
|
1374
|
-
getTextWidth(tick.formattedValue, `normal ${fontSizes[config.fontSize]}px sans-serif`)
|
|
1375
|
-
)
|
|
1406
|
+
...filteredTicks.map(tick => getTextWidth(tick.formattedValue, GET_TEXT_WIDTH_FONT))
|
|
1376
1407
|
)
|
|
1377
1408
|
// const marginTop = 20 // moved to top bc need for yMax calcs
|
|
1378
1409
|
const accumulator = ismultiLabel ? 180 : 100
|
|
1379
1410
|
|
|
1380
|
-
const textWidths = filteredTicks.map(tick =>
|
|
1381
|
-
getTextWidth(tick.formattedValue, `normal ${fontSizes[config.fontSize]}px sans-serif`)
|
|
1382
|
-
)
|
|
1411
|
+
const textWidths = filteredTicks.map(tick => getTextWidth(tick.formattedValue, GET_TEXT_WIDTH_FONT))
|
|
1383
1412
|
const sumOfTickWidth = textWidths.reduce((a, b) => a + b, accumulator)
|
|
1384
1413
|
const spaceBetweenEachTick = (xMax - sumOfTickWidth) / (filteredTicks.length - 1)
|
|
1385
1414
|
|
|
@@ -1471,6 +1500,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1471
1500
|
: undefined
|
|
1472
1501
|
}
|
|
1473
1502
|
fill={config.xAxis.tickLabelColor}
|
|
1503
|
+
fontSize={tickLabelFontSize}
|
|
1474
1504
|
>
|
|
1475
1505
|
{tick.formattedValue}
|
|
1476
1506
|
</Text>
|
|
@@ -1488,6 +1518,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1488
1518
|
verticalAnchor='start'
|
|
1489
1519
|
fontWeight='bold'
|
|
1490
1520
|
fill={config.xAxis.labelColor}
|
|
1521
|
+
fontSize={axisLabelFontSize}
|
|
1491
1522
|
>
|
|
1492
1523
|
{props.label}
|
|
1493
1524
|
</Text>
|
|
@@ -1502,6 +1533,7 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1502
1533
|
Object.entries(tooltipData.data).length > 0 &&
|
|
1503
1534
|
tooltipOpen &&
|
|
1504
1535
|
showTooltip &&
|
|
1536
|
+
!tooltipData?.data?.some(subArray => subArray.some(item => item === undefined)) &&
|
|
1505
1537
|
tooltipData.dataYPosition &&
|
|
1506
1538
|
tooltipData.dataXPosition && (
|
|
1507
1539
|
<>
|
|
@@ -1517,7 +1549,9 @@ const LinearChart = forwardRef<SVGAElement, LinearChartProps>(({ parentHeight, p
|
|
|
1517
1549
|
>
|
|
1518
1550
|
<ul>
|
|
1519
1551
|
{typeof tooltipData === 'object' &&
|
|
1520
|
-
Object.entries(tooltipData.data)
|
|
1552
|
+
Object.entries(tooltipData.data)
|
|
1553
|
+
.filter(([_, values]) => Array.isArray(values) && !values.includes(undefined))
|
|
1554
|
+
.map((item, index) => <TooltipListItem item={item} key={index} />)}
|
|
1521
1555
|
</ul>
|
|
1522
1556
|
</TooltipWithBounds>
|
|
1523
1557
|
</>
|
|
@@ -15,7 +15,6 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
15
15
|
|
|
16
16
|
const borderWidth = config.barHasBorder === 'true' ? 1 : 0
|
|
17
17
|
const halfWidth = width / 2
|
|
18
|
-
const fontSize = { small: 16, medium: 18, large: 20 }
|
|
19
18
|
const offset = 1.02 // Offset of the left bar from the Axis
|
|
20
19
|
|
|
21
20
|
const groupOne = {
|
|
@@ -109,10 +108,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
109
108
|
const totalheight = (Number(config.barSpace) + barHeight + borderWidth) * data.length
|
|
110
109
|
config.heights.horizontal = totalheight
|
|
111
110
|
// check if text fits inside of the bar including suffix/prefix,comma,fontSize ..etc
|
|
112
|
-
const textWidth = getTextWidth(
|
|
113
|
-
formatNumber(d[groupOne.dataKey], 'left'),
|
|
114
|
-
`normal ${fontSize[config.fontSize]}px sans-serif`
|
|
115
|
-
)
|
|
111
|
+
const textWidth = getTextWidth(formatNumber(d[groupOne.dataKey], 'left'))
|
|
116
112
|
const textFits = textWidth < barWidth - 5 // minus padding dx(5)
|
|
117
113
|
|
|
118
114
|
return (
|
|
@@ -170,10 +166,7 @@ const PairedBarChart = ({ width, height, originalWidth }) => {
|
|
|
170
166
|
const totalheight = (Number(config.barSpace) + barHeight + borderWidth) * data.length
|
|
171
167
|
config.heights.horizontal = totalheight
|
|
172
168
|
// check if text fits inside of the bar including suffix/prefix,comma,fontSize ..etc
|
|
173
|
-
const textWidth = getTextWidth(
|
|
174
|
-
formatNumber(d[groupTwo.dataKey], 'left'),
|
|
175
|
-
`normal ${fontSize[config.fontSize]}px sans-serif`
|
|
176
|
-
)
|
|
169
|
+
const textWidth = getTextWidth(formatNumber(d[groupTwo.dataKey], 'left'))
|
|
177
170
|
const isTextFits = textWidth < barWidth - 5 // minus padding dx(5)
|
|
178
171
|
|
|
179
172
|
return (
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Brush } from '@visx/brush'
|
|
2
2
|
import { Group } from '@visx/group'
|
|
3
3
|
import { Text } from '@visx/text'
|
|
4
|
-
import { useBarChart } from '../hooks/useBarChart'
|
|
5
4
|
import { FC, useContext, useEffect, useRef, useState } from 'react'
|
|
6
5
|
import ConfigContext from '../ConfigContext'
|
|
7
6
|
import { ScaleLinear, ScaleBand } from 'd3-scale'
|
|
8
7
|
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
9
8
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
10
9
|
import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
|
|
10
|
+
import { appFontSize } from '@cdc/core/helpers/cove/fontSettings'
|
|
11
11
|
|
|
12
12
|
interface Props {
|
|
13
13
|
xScaleBrush: ScaleLinear<number, number>
|
|
@@ -19,7 +19,6 @@ const ZoomBrush: FC<Props> = props => {
|
|
|
19
19
|
const { tableData, config, parseDate, formatDate, setBrushConfig, dashboardConfig } = useContext(ConfigContext)
|
|
20
20
|
const sharedFilters = dashboardConfig?.dashboard?.sharedFilters ?? []
|
|
21
21
|
const isDashboardFilters = sharedFilters?.length > 0
|
|
22
|
-
const { fontSize } = useBarChart()
|
|
23
22
|
const [showTooltip, setShowTooltip] = useState(false)
|
|
24
23
|
const [brushKey, setBrushKey] = useState(0)
|
|
25
24
|
const brushRef = useRef(null)
|
|
@@ -178,7 +177,6 @@ const ZoomBrush: FC<Props> = props => {
|
|
|
178
177
|
showTooltip={showTooltip}
|
|
179
178
|
pixelDistance={textProps.endPosition - textProps.startPosition}
|
|
180
179
|
textProps={textProps}
|
|
181
|
-
fontSize={fontSize[config.fontSize]}
|
|
182
180
|
{...props}
|
|
183
181
|
isBrushing={brushRef.current?.state.isBrushing}
|
|
184
182
|
/>
|
|
@@ -202,7 +200,7 @@ const ZoomBrush: FC<Props> = props => {
|
|
|
202
200
|
}
|
|
203
201
|
|
|
204
202
|
const BrushHandle = props => {
|
|
205
|
-
const { x, isBrushActive, isBrushing, className, textProps,
|
|
203
|
+
const { x, isBrushActive, isBrushing, className, textProps, showTooltip, left } = props
|
|
206
204
|
const pathWidth = 8
|
|
207
205
|
if (!isBrushActive) {
|
|
208
206
|
return null
|
|
@@ -212,7 +210,7 @@ const BrushHandle = props => {
|
|
|
212
210
|
const transform = isLeft ? 'scale(-1, 1)' : 'translate(0,0)'
|
|
213
211
|
const textAnchor = isLeft ? 'end' : 'start'
|
|
214
212
|
const tooltipText = isLeft ? ` Drag edges to focus on a specific segment ` : ''
|
|
215
|
-
const textWidth = getTextWidth(tooltipText,
|
|
213
|
+
const textWidth = getTextWidth(tooltipText, `${appFontSize / 1.1}px`)
|
|
216
214
|
|
|
217
215
|
return (
|
|
218
216
|
<>
|
|
@@ -221,7 +219,7 @@ const BrushHandle = props => {
|
|
|
221
219
|
x={(Number(textProps.xMax) - textWidth) / 2}
|
|
222
220
|
dy={-12}
|
|
223
221
|
pointerEvents='visiblePainted'
|
|
224
|
-
fontSize={
|
|
222
|
+
fontSize={appFontSize / 1.1}
|
|
225
223
|
>
|
|
226
224
|
{tooltipText}
|
|
227
225
|
</Text>
|
|
@@ -234,7 +232,7 @@ const BrushHandle = props => {
|
|
|
234
232
|
y={25}
|
|
235
233
|
verticalAnchor='start'
|
|
236
234
|
textAnchor={textAnchor}
|
|
237
|
-
fontSize={
|
|
235
|
+
fontSize={appFontSize / 1.4}
|
|
238
236
|
>
|
|
239
237
|
{isLeft ? textProps.startValue : textProps.endValue}
|
|
240
238
|
</Text>
|
|
@@ -11,10 +11,9 @@ export default {
|
|
|
11
11
|
showDownloadMediaButton: false,
|
|
12
12
|
theme: 'theme-blue',
|
|
13
13
|
animate: false,
|
|
14
|
-
fontSize: 'medium',
|
|
15
14
|
lineDatapointStyle: 'hover',
|
|
16
15
|
lineDatapointColor: 'Same as Line',
|
|
17
|
-
barHasBorder: '
|
|
16
|
+
barHasBorder: 'true',
|
|
18
17
|
isLollipopChart: false,
|
|
19
18
|
lollipopShape: 'circle',
|
|
20
19
|
lollipopColorStyle: 'two-tone',
|
|
@@ -167,6 +166,7 @@ export default {
|
|
|
167
166
|
seriesHighlight: [],
|
|
168
167
|
style: 'circles',
|
|
169
168
|
subStyle: 'linear blocks',
|
|
169
|
+
shape: 'circle',
|
|
170
170
|
tickRotation: '',
|
|
171
171
|
hideBorder: {
|
|
172
172
|
side: false,
|
|
@@ -198,13 +198,16 @@ export default {
|
|
|
198
198
|
bottomPrefix: '',
|
|
199
199
|
bottomAbbreviated: false
|
|
200
200
|
},
|
|
201
|
+
filters: [],
|
|
201
202
|
confidenceKeys: {},
|
|
202
203
|
visual: {
|
|
203
204
|
border: true,
|
|
204
205
|
accent: true,
|
|
205
206
|
background: true,
|
|
206
207
|
verticalHoverLine: false,
|
|
207
|
-
horizontalHoverLine: false
|
|
208
|
+
horizontalHoverLine: false,
|
|
209
|
+
lineDatapointSymbol: 'none',
|
|
210
|
+
maximumShapeAmount: 7
|
|
208
211
|
},
|
|
209
212
|
useLogScale: false,
|
|
210
213
|
filterBehavior: 'Filter Change',
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
import { ChartConfig } from '../types/ChartConfig'
|
|
3
|
+
import * as d3 from 'd3-array'
|
|
4
|
+
|
|
5
|
+
export const getBoxPlotConfig = (newConfig: ChartConfig, data: object[]) => {
|
|
6
|
+
const combinedData = data
|
|
7
|
+
const groups = _.uniq(_.map(combinedData, newConfig.xAxis.dataKey))
|
|
8
|
+
const seriesKeys = _.map(newConfig.series, 'dataKey')
|
|
9
|
+
const plots: any[] = []
|
|
10
|
+
|
|
11
|
+
groups.forEach(g => {
|
|
12
|
+
seriesKeys.forEach(seriesKey => {
|
|
13
|
+
try {
|
|
14
|
+
if (!g) throw new Error('No groups resolved in box plots')
|
|
15
|
+
|
|
16
|
+
// Start handle operations on combinedData
|
|
17
|
+
const { count, sortedData } = _.chain(combinedData)
|
|
18
|
+
// Filter by xAxis data key
|
|
19
|
+
.filter(item => item[newConfig.xAxis.dataKey] === g)
|
|
20
|
+
// perform multiple operations on the filtered data
|
|
21
|
+
.thru(filteredData => ({
|
|
22
|
+
count: filteredData.length,
|
|
23
|
+
sortedData: _.map(filteredData, item => Number(item[seriesKey])).sort()
|
|
24
|
+
}))
|
|
25
|
+
// get the results from the chain
|
|
26
|
+
.value()
|
|
27
|
+
|
|
28
|
+
if (!sortedData) throw new Error('boxplots dont have data yet')
|
|
29
|
+
if (!plots) throw new Error('boxplots dont have plots yet')
|
|
30
|
+
|
|
31
|
+
const q1 = d3.quantile(sortedData, 0.25)
|
|
32
|
+
const q3 = d3.quantile(sortedData, 0.75)
|
|
33
|
+
|
|
34
|
+
const iqr = q3 - q1
|
|
35
|
+
const lowerBounds = q1 - 1.5 * iqr
|
|
36
|
+
const upperBounds = q3 + 1.5 * iqr
|
|
37
|
+
const nonOutliers = sortedData.filter(value => value >= lowerBounds && value <= upperBounds)
|
|
38
|
+
plots.push({
|
|
39
|
+
columnCategory: g,
|
|
40
|
+
columnMax: d3.max(nonOutliers),
|
|
41
|
+
columnThirdQuartile: _.round(q3, newConfig.dataFormat.roundTo),
|
|
42
|
+
columnMedian: Number(d3.median(sortedData)).toFixed(newConfig.dataFormat.roundTo),
|
|
43
|
+
columnFirstQuartile: _.round(q1, newConfig.dataFormat.roundTo),
|
|
44
|
+
columnMin: _.min(nonOutliers),
|
|
45
|
+
columnCount: count,
|
|
46
|
+
columnSd: Number(d3.deviation(sortedData)).toFixed(newConfig.dataFormat.roundTo),
|
|
47
|
+
columnMean: Number(d3.mean(sortedData)).toFixed(newConfig.dataFormat.roundTo),
|
|
48
|
+
columnIqr: _.round(iqr, newConfig.dataFormat.roundTo),
|
|
49
|
+
values: sortedData,
|
|
50
|
+
columnLowerBounds: lowerBounds,
|
|
51
|
+
columnUpperBounds: upperBounds,
|
|
52
|
+
columnOutliers: _.filter(sortedData, value => value < lowerBounds || value > upperBounds),
|
|
53
|
+
columnNonOutliers: _.filter(sortedData, value => value >= lowerBounds && value <= upperBounds)
|
|
54
|
+
})
|
|
55
|
+
} catch (e) {
|
|
56
|
+
console.error('COVE: ', e.message) // eslint-disable-line
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// Generate a flat list of categories based on seriesKeys and groups
|
|
62
|
+
const categories =
|
|
63
|
+
seriesKeys.length > 1
|
|
64
|
+
? _.flatMap(groups, value => _.map(seriesKeys, key => `${_.capitalize(key)} - ${_.capitalize(value)}`))
|
|
65
|
+
: groups
|
|
66
|
+
|
|
67
|
+
return [plots, categories]
|
|
68
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { colorPalettesChart as colorPalettes, twoColorPalette } from '@cdc/core/data/colorPalettes'
|
|
2
|
+
import { scaleOrdinal } from '@visx/scale'
|
|
3
|
+
import { ChartConfig } from '../types/ChartConfig'
|
|
4
|
+
|
|
5
|
+
export const getColorScale = (config: ChartConfig): ((value: string) => string) => {
|
|
6
|
+
const configPalette = ['Paired Bar', 'Deviation Bar'].includes(config.visualizationType)
|
|
7
|
+
? config.twoColor.palette
|
|
8
|
+
: config.palette
|
|
9
|
+
const allPalettes: Record<string, string[]> = { ...colorPalettes, ...twoColorPalette }
|
|
10
|
+
let palette = config.customColors || allPalettes[configPalette]
|
|
11
|
+
let numberOfKeys = config.runtime.seriesKeys.length
|
|
12
|
+
|
|
13
|
+
while (numberOfKeys > palette.length) {
|
|
14
|
+
palette = palette.concat(palette)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
palette = palette.slice(0, numberOfKeys)
|
|
18
|
+
|
|
19
|
+
return scaleOrdinal({
|
|
20
|
+
domain: config.runtime.seriesLabelsAll,
|
|
21
|
+
range: palette,
|
|
22
|
+
unknown: null
|
|
23
|
+
})
|
|
24
|
+
}
|