@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.
- package/dist/cdcchart.js +42292 -40337
- package/examples/feature/__data__/area-chart.json +56 -0
- package/examples/{planet-example-data.json → feature/__data__/planet-example-data-max-increase.json} +4 -4
- package/examples/feature/__data__/planet-example-data.json +68 -0
- package/examples/feature/area/area-chart.json +244 -0
- package/examples/{example-bar-chart.json → feature/bar/example-bar-chart.json} +4 -1
- package/examples/feature/bar/horizontal-chart-max-increase.json +44 -0
- package/examples/{horizontal-chart.json → feature/bar/horizontal-chart.json} +10 -4
- package/examples/{horizontal-stacked-bar-chart.json → feature/bar/horizontal-stacked-bar-chart.json} +7 -3
- package/examples/{planet-chart-horizontal-example-config.json → feature/bar/planet-chart-horizontal-example-config.json} +8 -3
- package/examples/feature/bar/planet-example-config.json +156 -0
- package/examples/{box-plot.json → feature/boxplot/boxplot.json} +7 -8
- package/examples/feature/boxplot/testing.csv +38 -0
- package/examples/feature/combo/combochart-categories_are_numbers .json +18 -0
- package/examples/{planet-combo-example-config.json → feature/combo/planet-combo-example-config.json} +1 -1
- package/examples/feature/deviation/planet-deviation-config.json +168 -0
- package/examples/feature/deviation/planet-deviation-data.json +38 -0
- package/examples/feature/filters/filter-testing.json +178 -0
- package/examples/feature/forecasting/case_date_example.csv +130 -0
- package/examples/feature/forecasting/effective_reproduction.json +202 -0
- package/examples/feature/forecasting/r_data.csv +130 -0
- package/examples/feature/line/line-chart-max-increase.json +32 -0
- package/examples/feature/line/line-chart.json +124 -0
- package/examples/{paired-bar-example.json → feature/paired-bar/paired-bar-example.json} +10 -4
- package/examples/{planet-pie-example-config.json → feature/pie/planet-pie-example-config.json} +2 -2
- package/examples/{scatterplot-continuous.csv → feature/scatterplot/scatterplot-continuous.csv} +3 -3
- package/examples/{scatterplot.json → feature/scatterplot/scatterplot.json} +3 -3
- package/examples/feature/sparkline/example-sparkline.json +76 -0
- package/examples/feature/tests-big-small/big-small-test-bar.json +328 -0
- package/examples/feature/tests-big-small/big-small-test-line.json +328 -0
- package/examples/feature/tests-big-small/big-small-test-negative.json +328 -0
- package/examples/{case-rate-example-config.json → feature/tests-case-rate/case-rate-example-config.json} +2 -2
- package/examples/{covid-confidence-example-config.json → feature/tests-covid/covid-confidence-example-config.json} +8 -3
- package/examples/{covid-example-config.json → feature/tests-covid/covid-example-config.json} +7 -3
- package/examples/{cutoff-example-config.json → feature/tests-cutoff/cutoff-example-config.json} +7 -3
- package/examples/{date-exclusions-config.json → feature/tests-date-exclusions/date-exclusions-config.json} +2 -2
- package/examples/{example-bar-chart-nonnumeric.json → feature/tests-non-numerics/example-bar-chart-nonnumeric.json} +1 -1
- package/examples/{line-chart-nonnumeric.json → feature/tests-non-numerics/line-chart-nonnumeric.json} +5 -5
- package/examples/{planet-pie-example-config-nonnumeric.json → feature/tests-non-numerics/planet-pie-example-config-nonnumeric.json} +2 -2
- package/examples/{sparkline-chart-nonnumeric.json → feature/tests-non-numerics/sparkline-chart-nonnumeric.json} +2 -2
- package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +31 -172
- package/examples/gallery/bar-chart-vertical/combo-line-chart.json +145 -7
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-confidence.json +1 -0
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +96 -14
- package/examples/gallery/line/line.json +1 -0
- package/examples/gallery/paired-bar/paired-bar-chart.json +1 -0
- package/index.html +76 -35
- package/package.json +6 -3
- package/src/CdcChart.jsx +245 -106
- package/src/components/AreaChart.jsx +233 -0
- package/src/components/BarChart.jsx +103 -62
- package/src/components/BoxPlot.jsx +39 -18
- package/src/components/DataTable.jsx +26 -21
- package/src/components/DeviationBar.jsx +191 -0
- package/src/components/EditorPanel.jsx +662 -298
- package/src/components/Legend.jsx +59 -46
- package/src/components/LineChart.jsx +12 -36
- package/src/components/LinearChart.jsx +163 -64
- package/src/components/PairedBarChart.jsx +6 -7
- package/src/components/PieChart.jsx +12 -17
- package/src/components/ScatterPlot.jsx +19 -16
- package/src/components/SparkLine.jsx +84 -118
- package/src/components/useIntersectionObserver.jsx +1 -1
- package/src/data/initial-state.js +27 -7
- package/src/hooks/useColorPalette.js +58 -48
- package/src/hooks/useReduceData.js +3 -4
- package/src/index.jsx +3 -2
- package/src/scss/editor-panel.scss +20 -0
- package/src/scss/main.scss +8 -6
- package/src/test/CdcChart.test.jsx +6 -0
- package/examples/box-plot.csv +0 -5
- package/examples/dynamic-legends.json +0 -125
- package/examples/line-chart.json +0 -34
- package/examples/planet-example-config.json +0 -37
- package/examples/temp-example-config.json +0 -64
- package/examples/temp-example-data.json +0 -130
- package/src/components/Filters.jsx +0 -125
- /package/examples/{age-adjusted-rates.json → feature/__data__/age-adjusted-rates.json} +0 -0
- /package/examples/{new-data.csv → feature/__data__/new-data.csv} +0 -0
- /package/examples/{Barchart_with_negative.json → feature/bar/Barchart_with_negative.json} +0 -0
- /package/examples/{stacked-vertical-bar-example-negative.json → feature/bar/stacked-vertical-bar-example-negative.json} +0 -0
- /package/examples/{stacked-vertical-bar-example.json → feature/bar/stacked-vertical-bar-example.json} +0 -0
- /package/examples/{box-plot-data.json → feature/boxplot/box-plot-data.json} +0 -0
- /package/examples/{newdata.json → feature/boxplot/boxplot-data.json} +0 -0
- /package/examples/{paired-bar-data.json → feature/paired-bar/paired-bar-data.json} +0 -0
- /package/examples/{paired-bar-formatted.json → feature/paired-bar/paired-bar-formatted.json} +0 -0
- /package/examples/{case-rate-example-data.json → feature/tests-case-rate/case-rate-example-data.json} +0 -0
- /package/examples/{covid-example-data-confidence.json → feature/tests-covid/covid-example-data-confidence.json} +0 -0
- /package/examples/{covid-example-data.json → feature/tests-covid/covid-example-data.json} +0 -0
- /package/examples/{cutoff-example-data.json → feature/tests-cutoff/cutoff-example-data.json} +0 -0
- /package/examples/{date-exclusions-data.json → feature/tests-date-exclusions/date-exclusions-data.json} +0 -0
- /package/examples/{example-combo-bar-nonnumeric.json → feature/tests-non-numerics/example-combo-bar-nonnumeric.json} +0 -0
- /package/examples/{planet-example-data-nonnumeric.json → feature/tests-non-numerics/planet-example-data-nonnumeric.json} +0 -0
- /package/examples/{stacked-vertical-bar-example-nonnumerics.json → feature/tests-non-numerics/stacked-vertical-bar-example-nonnumerics.json} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useContext
|
|
1
|
+
import React, { useContext } from 'react'
|
|
2
2
|
|
|
3
3
|
import * as allCurves from '@visx/curve'
|
|
4
4
|
import { Group } from '@visx/group'
|
|
@@ -15,7 +15,7 @@ import useReduceData from '../hooks/useReduceData'
|
|
|
15
15
|
import ConfigContext from '../ConfigContext'
|
|
16
16
|
|
|
17
17
|
export default function SparkLine({ width: parentWidth, height: parentHeight }) {
|
|
18
|
-
const { transformedData: data,
|
|
18
|
+
const { transformedData: data, config, parseDate, formatDate, seriesHighlight, formatNumber, colorScale, handleChartAriaLabels } = useContext(ConfigContext)
|
|
19
19
|
let width = parentWidth
|
|
20
20
|
const { minValue, maxValue } = useReduceData(config, data, ConfigContext)
|
|
21
21
|
|
|
@@ -35,44 +35,7 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
|
|
|
35
35
|
const isMaxValid = Number(enteredMaxValue) >= Number(maxValue)
|
|
36
36
|
const isMinValid = Number(enteredMinValue) <= Number(minValue)
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
// REMOVE bad data points from the data set
|
|
40
|
-
// Examples: NA, N/A, "1,234", "anystring"
|
|
41
|
-
// - if you dont call this on data into LineGroup below, for example
|
|
42
|
-
// then entire data series are removed because of the defined statement
|
|
43
|
-
// i.e. if a series has any bad data points the entire series wont plot
|
|
44
|
-
const cleanData = (data, testing = false) => {
|
|
45
|
-
let cleanedup = []
|
|
46
|
-
if (testing) console.log('## Data to clean=', data)
|
|
47
|
-
data.forEach(function (d, i) {
|
|
48
|
-
let cleanedSeries = {}
|
|
49
|
-
Object.keys(d).forEach(function (key) {
|
|
50
|
-
if (key === 'Date') {
|
|
51
|
-
// pass thru the dates
|
|
52
|
-
cleanedSeries[key] = d[key]
|
|
53
|
-
} else {
|
|
54
|
-
// remove comma and dollar signs
|
|
55
|
-
let tmp = d[key] != null && d[key] != '' ? d[key].replace(/[,\$]/g, '') : ''
|
|
56
|
-
if (testing) console.log("tmp no comma or $", tmp)
|
|
57
|
-
if ((tmp !== '' && tmp !== null && !isNaN(tmp)) || (tmp !== '' && tmp !== null && /\d+\.?\d*/.test(tmp))) {
|
|
58
|
-
cleanedSeries[key] = tmp
|
|
59
|
-
} else {
|
|
60
|
-
// return nothing to skip bad data point
|
|
61
|
-
cleanedSeries[key] = '' // returning blank fixes broken chart draw
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
})
|
|
65
|
-
cleanedup.push(cleanedSeries)
|
|
66
|
-
})
|
|
67
|
-
if (testing) console.log('## cleanedData =', cleanedup)
|
|
68
|
-
return cleanedup
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Just do this once up front otherwise we end up
|
|
72
|
-
// calling clean several times on same set of data (TT)
|
|
73
|
-
const cleanedData = cleanData(data, config.xAxis.dataKey);
|
|
74
|
-
|
|
75
|
-
if (cleanedData) {
|
|
38
|
+
if (data) {
|
|
76
39
|
let min = enteredMinValue && isMinValid ? enteredMinValue : minValue
|
|
77
40
|
let max = enteredMaxValue && isMaxValid ? enteredMaxValue : Number.MIN_VALUE
|
|
78
41
|
|
|
@@ -87,7 +50,7 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
|
|
|
87
50
|
max += paddingValue
|
|
88
51
|
}
|
|
89
52
|
|
|
90
|
-
let xAxisDataMapped =
|
|
53
|
+
let xAxisDataMapped = data.map(d => getXAxisData(d))
|
|
91
54
|
|
|
92
55
|
if (config.runtime.horizontal) {
|
|
93
56
|
xScale = scaleLinear({
|
|
@@ -116,6 +79,7 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
|
|
|
116
79
|
range: [margin.left, width - margin.right]
|
|
117
80
|
})
|
|
118
81
|
|
|
82
|
+
// eslint-disable-next-line
|
|
119
83
|
seriesScale = scalePoint({
|
|
120
84
|
domain: config.runtime.barSeriesKeys || config.runtime.seriesKeys,
|
|
121
85
|
range: [0, xMax]
|
|
@@ -128,88 +92,90 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
|
|
|
128
92
|
return (
|
|
129
93
|
<ErrorBoundary component='SparkLine'>
|
|
130
94
|
<svg role='img' aria-label={handleChartAriaLabels(config)} width={width} height={height} className={'sparkline'} tabIndex={0}>
|
|
131
|
-
{
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
95
|
+
{config.runtime.lineSeriesKeys?.length > 0
|
|
96
|
+
? config.runtime.lineSeriesKeys
|
|
97
|
+
: config.runtime.seriesKeys.map((seriesKey, index) => (
|
|
98
|
+
<>
|
|
99
|
+
<Group
|
|
100
|
+
className='sparkline-group'
|
|
101
|
+
height={parentHeight}
|
|
102
|
+
style={{ height: parentHeight }}
|
|
103
|
+
top={margin.top}
|
|
104
|
+
key={`series-${seriesKey}`}
|
|
105
|
+
opacity={config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(seriesKey) === -1 ? 0.5 : 1}
|
|
106
|
+
display={config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(seriesKey) !== -1 ? 'block' : 'none'}
|
|
107
|
+
>
|
|
108
|
+
{data.map((d, dataIndex) => {
|
|
109
|
+
let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${formatNumber(getYAxisData(d, seriesKey))}` : formatNumber(getYAxisData(d, seriesKey))
|
|
110
|
+
let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${d[config.runtime.xAxis.dataKey]}` : d[config.runtime.xAxis.dataKey]
|
|
111
|
+
|
|
112
|
+
const tooltip = `<div>
|
|
147
113
|
${yAxisTooltip}<br />
|
|
148
114
|
${xAxisTooltip}<br />
|
|
149
115
|
${config.seriesLabel ? `${config.seriesLabel}: ${seriesKey}` : ''}
|
|
150
116
|
</div>`
|
|
151
117
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
118
|
+
let circleRadii = 4.5
|
|
119
|
+
return (
|
|
120
|
+
<Group key={`series-${seriesKey}-point-${dataIndex}`}>
|
|
121
|
+
<Text display={config.labels ? 'block' : 'none'} x={xScale(getXAxisData(d))} y={yScale(getYAxisData(d, seriesKey))} fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'} textAnchor='middle'>
|
|
122
|
+
{formatNumber(d[seriesKey])}
|
|
123
|
+
</Text>
|
|
124
|
+
|
|
125
|
+
{dataIndex + 1 !== data.length && (config.lineDatapointStyle === 'always show' || config.lineDatapointStyle === 'hover') && (
|
|
126
|
+
<circle
|
|
127
|
+
key={`${seriesKey}-${dataIndex}`}
|
|
128
|
+
r={circleRadii}
|
|
129
|
+
cx={xScale(getXAxisData(d))}
|
|
130
|
+
cy={yScale(getYAxisData(d, seriesKey))}
|
|
131
|
+
fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
|
|
132
|
+
style={{ fill: colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000' }}
|
|
133
|
+
data-tooltip-html={tooltip}
|
|
134
|
+
data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
|
|
135
|
+
/>
|
|
136
|
+
)}
|
|
137
|
+
</Group>
|
|
138
|
+
)
|
|
139
|
+
})}
|
|
140
|
+
<LinePath
|
|
141
|
+
curve={allCurves.curveLinear}
|
|
142
|
+
data={data}
|
|
143
|
+
x={d => xScale(getXAxisData(d))}
|
|
144
|
+
y={d => yScale(getYAxisData(d, seriesKey))}
|
|
145
|
+
stroke={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
|
|
146
|
+
strokeWidth={2}
|
|
147
|
+
strokeOpacity={1}
|
|
148
|
+
shapeRendering='geometricPrecision'
|
|
149
|
+
markerEnd={`url(#${'arrow'}--${index})`}
|
|
150
|
+
/>
|
|
151
|
+
<MarkerArrow
|
|
152
|
+
id={`arrow--${index}`}
|
|
153
|
+
refX={2}
|
|
154
|
+
size={6}
|
|
155
|
+
markerEnd={`url(#${'arrow'}--${index})`}
|
|
156
|
+
strokeOpacity={1}
|
|
157
|
+
fillOpacity={1}
|
|
158
|
+
// stroke={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
|
|
159
|
+
fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
|
|
160
|
+
/>
|
|
161
|
+
</Group>
|
|
162
|
+
<AxisBottom
|
|
163
|
+
top={yMax + margin.top}
|
|
164
|
+
hideAxisLine
|
|
165
|
+
hideTicks
|
|
166
|
+
scale={xScale}
|
|
167
|
+
tickValues={handleSparkLineTicks}
|
|
168
|
+
tickFormat={tick => (config.xAxis.type === 'date' ? formatDate(tick) : null)}
|
|
169
|
+
stroke={'black'}
|
|
170
|
+
tickStroke={'black'}
|
|
171
|
+
tickLabelProps={() => ({
|
|
172
|
+
fill: 'black',
|
|
173
|
+
fontSize: 11,
|
|
174
|
+
textAnchor: 'middle'
|
|
175
|
+
})}
|
|
176
|
+
/>
|
|
177
|
+
</>
|
|
178
|
+
))}
|
|
213
179
|
</svg>
|
|
214
180
|
</ErrorBoundary>
|
|
215
181
|
)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
type: 'chart',
|
|
3
3
|
title: '',
|
|
4
|
+
showTitle: true,
|
|
4
5
|
theme: 'theme-blue',
|
|
5
6
|
animate: false,
|
|
6
7
|
fontSize: 'medium',
|
|
@@ -24,6 +25,7 @@ export default {
|
|
|
24
25
|
hideTicks: false,
|
|
25
26
|
size: 50,
|
|
26
27
|
gridLines: false,
|
|
28
|
+
enablePadding: false,
|
|
27
29
|
min: '',
|
|
28
30
|
max: '',
|
|
29
31
|
labelColor: '#333',
|
|
@@ -63,9 +65,11 @@ export default {
|
|
|
63
65
|
median: 'Median',
|
|
64
66
|
sd: 'Standard Deviation',
|
|
65
67
|
iqr: 'Interquartile Range',
|
|
66
|
-
|
|
68
|
+
total: 'Total',
|
|
67
69
|
outliers: 'Outliers',
|
|
68
|
-
values: 'Values'
|
|
70
|
+
values: 'Values',
|
|
71
|
+
lowerBounds: 'Lower Bounds',
|
|
72
|
+
upperBounds: 'Upper Bounds'
|
|
69
73
|
}
|
|
70
74
|
},
|
|
71
75
|
topAxis: {
|
|
@@ -81,6 +85,8 @@ export default {
|
|
|
81
85
|
},
|
|
82
86
|
xAxis: {
|
|
83
87
|
type: 'categorical',
|
|
88
|
+
showTargetLabel: true,
|
|
89
|
+
targetLabel: 'Target',
|
|
84
90
|
hideAxis: false,
|
|
85
91
|
hideLabel: false,
|
|
86
92
|
hideTicks: false,
|
|
@@ -93,7 +99,8 @@ export default {
|
|
|
93
99
|
tickColor: '#333',
|
|
94
100
|
numTicks: '',
|
|
95
101
|
labelOffset: 65,
|
|
96
|
-
axisPadding: 0
|
|
102
|
+
axisPadding: 0,
|
|
103
|
+
target: 0
|
|
97
104
|
},
|
|
98
105
|
table: {
|
|
99
106
|
label: 'Data Table',
|
|
@@ -101,12 +108,12 @@ export default {
|
|
|
101
108
|
limitHeight: false,
|
|
102
109
|
height: '',
|
|
103
110
|
caption: '',
|
|
104
|
-
showDownloadUrl: false
|
|
111
|
+
showDownloadUrl: false,
|
|
112
|
+
showDataTableLink: true
|
|
105
113
|
},
|
|
106
114
|
orientation: 'vertical',
|
|
107
115
|
legend: {
|
|
108
116
|
behavior: 'isolate',
|
|
109
|
-
position: 'right',
|
|
110
117
|
singleRow: false,
|
|
111
118
|
colorCode: '',
|
|
112
119
|
reverseLabelOrder: false,
|
|
@@ -123,12 +130,25 @@ export default {
|
|
|
123
130
|
},
|
|
124
131
|
palette: 'qualitative-bold',
|
|
125
132
|
isPaletteReversed: false,
|
|
133
|
+
twoColor: {
|
|
134
|
+
palette: 'monochrome-1',
|
|
135
|
+
isPaletteReversed: false
|
|
136
|
+
},
|
|
126
137
|
labels: false,
|
|
127
|
-
dataFormat: {
|
|
138
|
+
dataFormat: {
|
|
139
|
+
commas: false,
|
|
140
|
+
prefix: '',
|
|
141
|
+
suffix: '',
|
|
142
|
+
abbreviated: false,
|
|
143
|
+
bottomSuffix: '',
|
|
144
|
+
bottomPrefix: '',
|
|
145
|
+
bottomAbbreviated: false
|
|
146
|
+
},
|
|
128
147
|
confidenceKeys: {},
|
|
129
148
|
visual: {
|
|
130
149
|
border: true,
|
|
131
150
|
accent: true,
|
|
132
151
|
background: true
|
|
133
|
-
}
|
|
152
|
+
},
|
|
153
|
+
filterBehavior: 'Filter Change'
|
|
134
154
|
}
|
|
@@ -1,58 +1,68 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
// constants
|
|
4
|
-
const SEQUENTIAL = 'SEQUENTIAL'
|
|
5
|
-
const SEQUENTIAL_REVERSE = 'SEQUENTIAL_REVERSE'
|
|
6
|
-
export const GET_PALETTE = 'GET_PALETTE'
|
|
7
|
-
|
|
8
|
-
// create initial state
|
|
9
|
-
const initialState = {
|
|
10
|
-
filteredPallets: [],
|
|
11
|
-
isPaletteReversed: false,
|
|
12
|
-
filteredQualitative: [],
|
|
13
|
-
paletteName: undefined
|
|
14
|
-
}
|
|
1
|
+
import { colorPalettesChart, twoColorPalette } from '@cdc/core/data/colorPalettes'
|
|
2
|
+
import { useEffect } from 'react'
|
|
15
3
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let
|
|
19
|
-
|
|
20
|
-
case GET_PALETTE:
|
|
21
|
-
return { ...state, paletteName: action.paletteName }
|
|
22
|
-
case SEQUENTIAL:
|
|
23
|
-
paletteName = state.paletteName && state.paletteName.endsWith('reverse') ? String(state.paletteName).substring(0, state.paletteName.length - 7) : String(state.paletteName)
|
|
24
|
-
const qualitative = palletNamesArr.filter((name) => String(name).startsWith('qualitative') && !String(name).endsWith('reverse'))
|
|
25
|
-
const sequential = palletNamesArr.filter((name) => String(name).startsWith('sequential') && !String(name).endsWith('reverse'))
|
|
26
|
-
return { ...state, filteredPallets: sequential, filteredQualitative: qualitative, paletteName: paletteName, isPaletteReversed: false }
|
|
27
|
-
|
|
28
|
-
case SEQUENTIAL_REVERSE:
|
|
29
|
-
paletteName = palletNamesArr.find((name) => name === String(state.paletteName).concat('reverse') || name === String(state.paletteName).concat('-reverse'))
|
|
30
|
-
const qualitativeReverse = palletNamesArr.filter((name) => String(name).startsWith('qualitative') && String(name).endsWith('reverse'))
|
|
31
|
-
const sequentialReverse = palletNamesArr.filter((name) => String(name).startsWith('sequential') && String(name).endsWith('reverse'))
|
|
32
|
-
return { ...state, filteredQualitative: qualitativeReverse, filteredPallets: sequentialReverse, paletteName: paletteName, isPaletteReversed: true }
|
|
33
|
-
default:
|
|
34
|
-
return state
|
|
35
|
-
}
|
|
36
|
-
}
|
|
4
|
+
export const useColorPalette = (config, updateConfig) => {
|
|
5
|
+
let twoColorPalettes = []
|
|
6
|
+
let sequential = []
|
|
7
|
+
let nonSequential = []
|
|
37
8
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
9
|
+
// Get two color palettes if visualization type is Paired Bar
|
|
10
|
+
if (config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') {
|
|
11
|
+
const isReversed = config.twoColor.isPaletteReversed
|
|
12
|
+
twoColorPalettes = Object.keys(twoColorPalette).filter(name => (isReversed ? name.endsWith('reverse') : !name.endsWith('reverse')))
|
|
13
|
+
} else {
|
|
14
|
+
// Get sequential and non-sequential palettes for other visualization types
|
|
15
|
+
const seqPalettes = []
|
|
16
|
+
const nonSeqPalettes = []
|
|
17
|
+
|
|
18
|
+
for (const paletteName in colorPalettesChart) {
|
|
19
|
+
const isSequential = paletteName.startsWith('sequential')
|
|
20
|
+
const isQualitative = paletteName.startsWith('qualitative')
|
|
21
|
+
const isReversed = paletteName.endsWith('reverse')
|
|
41
22
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
23
|
+
if (isSequential && ((!config.isPaletteReversed && !isReversed) || (config.isPaletteReversed && isReversed))) {
|
|
24
|
+
seqPalettes.push(paletteName)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isQualitative && ((!config.isPaletteReversed && !isReversed) || (config.isPaletteReversed && isReversed))) {
|
|
28
|
+
nonSeqPalettes.push(paletteName)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
sequential = seqPalettes
|
|
33
|
+
nonSequential = nonSeqPalettes
|
|
34
|
+
}
|
|
45
35
|
|
|
36
|
+
// Update pairedBar.palette based on isPaletteReversed
|
|
46
37
|
useEffect(() => {
|
|
47
|
-
|
|
48
|
-
}, [])
|
|
38
|
+
let palette = ''
|
|
49
39
|
|
|
40
|
+
if (config.twoColor.isPaletteReversed && !config.twoColor.palette.endsWith('reverse')) {
|
|
41
|
+
palette = config.twoColor.palette + 'reverse'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!config.twoColor.isPaletteReversed && config.twoColor.palette.endsWith('reverse')) {
|
|
45
|
+
palette = config.twoColor.palette.slice(0, -7)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
updateConfig({ ...config, twoColor: { ...config.twoColor, palette: palette } })
|
|
49
|
+
}, [config.twoColor.isPaletteReversed])
|
|
50
|
+
|
|
51
|
+
// Update palette based on isPaletteReversed
|
|
50
52
|
useEffect(() => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
let palette = ''
|
|
54
|
+
|
|
55
|
+
if (config.isPaletteReversed && !config.palette.endsWith('reverse')) {
|
|
56
|
+
palette = config.palette + 'reverse'
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!config.isPaletteReversed && config.palette.endsWith('reverse')) {
|
|
60
|
+
palette = config.palette.slice(0, -7)
|
|
54
61
|
}
|
|
55
|
-
}, [configState.isPaletteReversed, dispatch, colorPalettes])
|
|
56
62
|
|
|
57
|
-
|
|
63
|
+
updateConfig({ ...config, palette: palette })
|
|
64
|
+
}, [config.isPaletteReversed])
|
|
65
|
+
|
|
66
|
+
// Return all palettes
|
|
67
|
+
return { twoColorPalettes, sequential, nonSequential }
|
|
58
68
|
}
|
|
@@ -9,7 +9,7 @@ function useReduceData(config, data) {
|
|
|
9
9
|
// remove comma and $ signs
|
|
10
10
|
let tmp
|
|
11
11
|
if (typeof value === 'string') {
|
|
12
|
-
tmp = value !== null && value !== '' ? value.replace(/[
|
|
12
|
+
tmp = value !== null && value !== '' ? value.replace(/[,$]/g, '') : ''
|
|
13
13
|
} else {
|
|
14
14
|
tmp = value !== null && value !== '' ? value : ''
|
|
15
15
|
}
|
|
@@ -18,7 +18,6 @@ function useReduceData(config, data) {
|
|
|
18
18
|
const getMaxValueFromData = () => {
|
|
19
19
|
let max // will hold max number from data.
|
|
20
20
|
if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && isBar)) && config.visualizationSubType === 'stacked') {
|
|
21
|
-
|
|
22
21
|
const yTotals = data.reduce((allTotals, xValue) => {
|
|
23
22
|
const totalYValues = config.runtime.seriesKeys.reduce((yTotal, k) => {
|
|
24
23
|
yTotal += Number(xValue[k])
|
|
@@ -33,7 +32,7 @@ function useReduceData(config, data) {
|
|
|
33
32
|
}, [])
|
|
34
33
|
|
|
35
34
|
max = Math.max(...yTotals)
|
|
36
|
-
} else if (config.visualizationType === 'Bar' && config.series && config.series.dataKey) {
|
|
35
|
+
} else if ((config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.series && config.series.dataKey) {
|
|
37
36
|
max = Math.max(...data.map(d => (isNumber(d[config.series.dataKey]) ? Number(cleanChars(d[config.series.dataKey])) : 0)))
|
|
38
37
|
//max = Math.max(...data.map(d => Number(d[config.series.dataKey])))
|
|
39
38
|
} else if (config.visualizationType === 'Combo' && config.visualizationSubType === 'stacked' && !isBar) {
|
|
@@ -46,7 +45,7 @@ function useReduceData(config, data) {
|
|
|
46
45
|
yTotal += Number(d[k])
|
|
47
46
|
return yTotal
|
|
48
47
|
}, 0)
|
|
49
|
-
total.push(totalYValues)
|
|
48
|
+
return total.push(totalYValues)
|
|
50
49
|
})
|
|
51
50
|
// get lineSeries largest values
|
|
52
51
|
const lineMax = Math.max(...data.map(d => Math.max(...config.runtime.lineSeriesKeys.map(key => Number(cleanChars(d[key]))))))
|
package/src/index.jsx
CHANGED
|
@@ -6,11 +6,12 @@ import CdcChart from './CdcChart'
|
|
|
6
6
|
import 'react-tooltip/dist/react-tooltip.css'
|
|
7
7
|
|
|
8
8
|
let isEditor = window.location.href.includes('editor=true')
|
|
9
|
+
let isDebug = window.location.href.includes('debug=true')
|
|
9
10
|
|
|
10
11
|
let domContainer = document.getElementsByClassName('react-container')[0]
|
|
11
12
|
|
|
12
13
|
ReactDOM.createRoot(domContainer).render(
|
|
13
14
|
<React.StrictMode>
|
|
14
|
-
<CdcChart configUrl={domContainer.attributes['data-config'].value} isEditor={isEditor} />
|
|
15
|
-
</React.StrictMode
|
|
15
|
+
<CdcChart configUrl={domContainer.attributes['data-config'].value} isEditor={isEditor} isDebug={isDebug} />
|
|
16
|
+
</React.StrictMode>
|
|
16
17
|
)
|
|
@@ -75,11 +75,16 @@
|
|
|
75
75
|
align-items: center;
|
|
76
76
|
justify-content: space-between;
|
|
77
77
|
font-size: 0.9em;
|
|
78
|
+
position: relative;
|
|
78
79
|
|
|
79
80
|
&:hover {
|
|
80
81
|
background-color: $lightestGray;
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
div {
|
|
85
|
+
width: 100%;
|
|
86
|
+
}
|
|
87
|
+
|
|
83
88
|
.series-list__name {
|
|
84
89
|
position: relative;
|
|
85
90
|
user-select: none;
|
|
@@ -132,7 +137,13 @@
|
|
|
132
137
|
}
|
|
133
138
|
|
|
134
139
|
.series-list__dropdown {
|
|
140
|
+
width: 100%;
|
|
141
|
+
display: block;
|
|
135
142
|
font-size: 0.8em;
|
|
143
|
+
margin-bottom: 10px;
|
|
144
|
+
select {
|
|
145
|
+
width: 100%;
|
|
146
|
+
}
|
|
136
147
|
}
|
|
137
148
|
|
|
138
149
|
.series-list__remove {
|
|
@@ -140,6 +151,9 @@
|
|
|
140
151
|
font-size: 1.125rem;
|
|
141
152
|
color: #f00;
|
|
142
153
|
cursor: pointer;
|
|
154
|
+
position: absolute;
|
|
155
|
+
top: 5px;
|
|
156
|
+
right: 5px;
|
|
143
157
|
}
|
|
144
158
|
|
|
145
159
|
+ li {
|
|
@@ -150,6 +164,7 @@
|
|
|
150
164
|
|
|
151
165
|
.series-list__name-text {
|
|
152
166
|
max-width: 150px;
|
|
167
|
+
margin-bottom: 10px;
|
|
153
168
|
white-space: nowrap;
|
|
154
169
|
text-overflow: ellipsis;
|
|
155
170
|
overflow: hidden;
|
|
@@ -419,6 +434,11 @@
|
|
|
419
434
|
width: 33.3%;
|
|
420
435
|
height: 100%;
|
|
421
436
|
}
|
|
437
|
+
|
|
438
|
+
span.two-color {
|
|
439
|
+
width: 50%;
|
|
440
|
+
height: 100%;
|
|
441
|
+
}
|
|
422
442
|
}
|
|
423
443
|
}
|
|
424
444
|
|
package/src/scss/main.scss
CHANGED
|
@@ -231,9 +231,13 @@
|
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
+
.visx-tooltip {
|
|
235
|
+
z-index: 100000;
|
|
236
|
+
}
|
|
237
|
+
|
|
234
238
|
.tooltip {
|
|
235
|
-
border: rgba(0,0,0
|
|
236
|
-
box-shadow: rgba(0,0,0
|
|
239
|
+
border: rgba(0, 0, 0, 0.3) 1px solid;
|
|
240
|
+
box-shadow: rgba(0, 0, 0, 0.1) 3px 3px 7px;
|
|
237
241
|
opacity: 1;
|
|
238
242
|
line-height: 1.4em;
|
|
239
243
|
font-size: 1em;
|
|
@@ -242,8 +246,8 @@
|
|
|
242
246
|
z-index: 1;
|
|
243
247
|
|
|
244
248
|
.react-tooltip-arrow {
|
|
245
|
-
border-bottom: rgba(0,0,0
|
|
246
|
-
border-right: rgba(0,0,0
|
|
249
|
+
border-bottom: rgba(0, 0, 0, 0.3) 1px solid;
|
|
250
|
+
border-right: rgba(0, 0, 0, 0.3) 1px solid;
|
|
247
251
|
backface-visibility: hidden;
|
|
248
252
|
}
|
|
249
253
|
}
|
|
@@ -337,8 +341,6 @@
|
|
|
337
341
|
}
|
|
338
342
|
|
|
339
343
|
&__wrapper {
|
|
340
|
-
margin-bottom: 40px;
|
|
341
|
-
|
|
342
344
|
hr {
|
|
343
345
|
margin-bottom: 20px;
|
|
344
346
|
}
|
package/examples/box-plot.csv
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
x,min,firstQuartile,median,thirdQuartile,max,outliers
|
|
2
|
-
Group 1,-3.529439249291613,2.498913996933074,6,6.517816161082865,12.546169407307552,-4.222649440089676,-3.7995254226812145,12.669680018702707,,,,,,,,,,,,
|
|
3
|
-
Group 2,-2.961278855962981,3.1553763355078277,5.31642875968012,7.233146463155033,13.349801654625843,-4.5962772985737645,14.42798091207488,14.832072412460995,,,,,,,,,,,,
|
|
4
|
-
Group 3,-0.784362943544294,5.600233888319485,7.606034555385235,9.85663177622867,16.24122860809245,-2.0568265981730285,-2.036299998010181,-1.634595257757523,-0.9751707921193091,-0.9256799494292718,-0.813852054679872,16.255225428689318,19.221712546396496,,,,,,,
|
|
5
|
-
Group 4,-3.4976011611041598,2.362493132101971,4.364242960871863,6.269222660906058,12.129316954112188,-5.912277243480174,-4.535668956980487,-4.255719319016919,-4.175200716132927,-4.1021204775116455,-3.7913796362224352,-3.6909919981778567,-3.6261129831962697,12.169135739844744,12.1724073804239,12.191268834215071,12.236896118210165,12.34513716605812,12.826785108558722,13.048968511771164
|