@cdc/chart 4.23.10 → 4.24.1
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 +34606 -32218
- package/examples/feature/bar/additional-column-tooltip.json +446 -0
- package/examples/feature/bar/example-bar-chart.json +1 -46
- package/examples/feature/bar/lollipop.json +156 -0
- package/examples/feature/bar/tall-data.json +98 -0
- package/examples/feature/combo/planet-combo-example-config.json +99 -9
- package/examples/feature/dev-4261.json +399 -0
- package/examples/feature/forest-plot/forest-plot.json +63 -19
- package/examples/feature/forest-plot/{broken.json → linear.json} +77 -23
- package/examples/feature/forest-plot/log.json +26 -0
- package/examples/feature/forest-plot/logarithmic.json +271 -0
- package/examples/feature/line/line-chart-preliminary.json +346 -0
- package/examples/feature/line/line-points.json +340 -0
- package/examples/feature/regions/index.json +462 -0
- package/examples/feature/scatterplot/scatterplot.json +272 -33
- package/examples/gallery/bar-chart-vertical/combo-line-chart.json +181 -48
- package/examples/private/chart-t.json +3740 -0
- package/examples/private/combo.json +369 -0
- package/examples/private/epi-data.csv +13 -0
- package/examples/private/epi-data.json +62 -0
- package/examples/private/epi.json +403 -0
- package/examples/private/occupancy.json +109283 -0
- package/examples/private/prod-line-config.json +401 -0
- package/examples/private/region-data.json +822 -0
- package/examples/private/region-testing.json +312 -0
- package/examples/private/scaling.json +45325 -0
- package/examples/private/testing-data.json +1739 -0
- package/examples/private/testing.json +816 -0
- package/examples/sparkline-multilple.json +846 -0
- package/index.html +12 -8
- package/package.json +3 -3
- package/src/CdcChart.tsx +42 -211
- package/src/ConfigContext.tsx +6 -0
- package/src/_stories/Chart.stories.tsx +188 -0
- package/src/_stories/Chart.tooltip.stories.tsx +305 -0
- package/src/_stories/ChartBrush.stories.tsx +19 -0
- package/src/_stories/ChartEditor.stories.tsx +22 -0
- package/src/_stories/ChartLine.preliminary.tsx +19 -0
- package/src/_stories/ChartSuppress.stories.tsx +19 -0
- package/src/_stories/_mock/brush_mock.json +393 -0
- package/src/_stories/_mock/pie_config.json +191 -0
- package/src/_stories/_mock/pie_data.json +218 -0
- package/src/_stories/_mock/preliminary_mock.json +346 -0
- package/src/_stories/_mock/suppress_mock.json +911 -0
- package/src/components/{AreaChart.Stacked.jsx → AreaChart/components/AreaChart.Stacked.jsx} +6 -7
- package/src/components/{AreaChart.jsx → AreaChart/components/AreaChart.jsx} +7 -36
- package/src/components/AreaChart/index.tsx +4 -0
- package/src/components/{BarChart.Horizontal.jsx → BarChart/components/BarChart.Horizontal.tsx} +111 -34
- package/src/components/{BarChart.StackedHorizontal.jsx → BarChart/components/BarChart.StackedHorizontal.tsx} +55 -20
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +106 -0
- package/src/components/{BarChart.Vertical.jsx → BarChart/components/BarChart.Vertical.tsx} +162 -34
- package/src/components/BarChart/components/BarChart.jsx +39 -0
- package/src/components/{BarChartType.jsx → BarChart/components/BarChartType.jsx} +0 -2
- package/src/components/BarChart/components/context.tsx +13 -0
- package/src/components/BarChart/index.tsx +3 -0
- package/src/components/{BoxPlot.jsx → BoxPlot/BoxPlot.jsx} +1 -1
- package/src/components/BoxPlot/index.tsx +3 -0
- package/src/components/DeviationBar.jsx +4 -3
- package/src/components/{EditorPanel.jsx → EditorPanel/EditorPanel.tsx} +807 -865
- package/src/components/EditorPanel/components/Panel.DateHighlighting.tsx +109 -0
- package/src/components/{ForestPlotSettings.jsx → EditorPanel/components/Panel.ForestPlotSettings.tsx} +190 -220
- package/src/components/EditorPanel/components/Panel.Regions.tsx +168 -0
- package/src/components/{Series.jsx → EditorPanel/components/Panel.Series.tsx} +23 -4
- package/src/components/EditorPanel/components/PanelProps.ts +3 -0
- package/src/components/EditorPanel/components/Panels.tsx +13 -0
- package/src/components/EditorPanel/components/panels.scss +72 -0
- package/src/components/EditorPanel/editor-panel.scss +751 -0
- package/src/components/EditorPanel/index.tsx +3 -0
- package/src/{hooks → components/EditorPanel}/useEditorPermissions.js +50 -5
- package/src/components/{Forecasting.jsx → Forecasting/Forecasting.jsx} +1 -1
- package/src/components/Forecasting/index.tsx +3 -0
- package/src/components/ForestPlot/ForestPlot.tsx +254 -0
- package/src/components/ForestPlot/ForestPlotProps.ts +18 -0
- package/src/components/ForestPlot/index.scss +1 -0
- package/src/components/ForestPlot/index.tsx +3 -0
- package/src/components/Legend/Legend.tsx +347 -0
- package/src/components/Legend/index.tsx +3 -0
- package/src/components/LineChart/LineChartProps.ts +46 -0
- package/src/components/{LineChart.Circle.tsx → LineChart/components/LineChart.Circle.tsx} +36 -30
- package/src/components/LineChart/helpers.ts +45 -0
- package/src/components/LineChart/index.scss +1 -0
- package/src/components/{LineChart.tsx → LineChart/index.tsx} +83 -42
- package/src/components/LinearChart.jsx +125 -82
- package/src/components/PairedBarChart.jsx +2 -2
- package/src/components/{PieChart.jsx → PieChart/PieChart.tsx} +16 -7
- package/src/components/PieChart/index.tsx +3 -0
- package/src/components/Regions/components/Regions.tsx +135 -0
- package/src/components/Regions/index.tsx +3 -0
- package/src/components/{ScatterPlot.jsx → ScatterPlot/ScatterPlot.jsx} +3 -3
- package/src/components/ScatterPlot/index.tsx +3 -0
- package/src/components/{SparkLine.jsx → Sparkline/SparkLine.jsx} +2 -2
- package/src/components/Sparkline/index.tsx +3 -0
- package/src/components/ZoomBrush.tsx +168 -0
- package/src/data/initial-state.js +30 -16
- package/src/helpers/abbreviateNumber.ts +17 -0
- package/src/helpers/computeMarginBottom.ts +55 -0
- package/src/helpers/filterData.ts +18 -0
- package/src/helpers/generateColorsArray.ts +8 -0
- package/src/helpers/getQuartiles.ts +30 -0
- package/src/helpers/handleChartAriaLabels.ts +19 -0
- package/src/helpers/handleLineType.ts +18 -0
- package/src/helpers/lineOptions.ts +18 -0
- package/src/helpers/sort.ts +7 -0
- package/src/helpers/tests/computeMarginBottom.test.ts +20 -0
- package/src/hooks/useBarChart.js +72 -7
- package/src/hooks/useColorScale.ts +50 -0
- package/src/hooks/{useMinMax.js → useMinMax.ts} +75 -23
- package/src/hooks/{useRightAxis.js → useRightAxis.ts} +10 -2
- package/src/hooks/{useScales.js → useScales.ts} +64 -17
- package/src/hooks/{useTooltip.jsx → useTooltip.tsx} +84 -55
- package/src/scss/main.scss +70 -38
- package/src/types/ChartConfig.ts +178 -0
- package/src/types/ChartContext.ts +54 -0
- package/src/types/ForestPlot.ts +53 -0
- package/examples/feature/scatterplot/scatterplot-continuous.csv +0 -17
- package/src/ConfigContext.jsx +0 -5
- package/src/components/BarChart.StackedVertical.jsx +0 -95
- package/src/components/BarChart.jsx +0 -30
- package/src/components/ForestPlot.jsx +0 -191
- package/src/components/Legend.jsx +0 -277
- package/src/scss/LinearChart.scss +0 -0
- package/src/scss/editor-panel.scss +0 -745
- package/src/scss/legend.scss +0 -206
- package/src/scss/mixins.scss +0 -0
- package/src/scss/variables.scss +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { useContext } from 'react'
|
|
2
|
-
import ConfigContext from '
|
|
2
|
+
import ConfigContext from '../../ConfigContext'
|
|
3
3
|
|
|
4
4
|
export const useEditorPermissions = () => {
|
|
5
5
|
const { config } = useContext(ConfigContext)
|
|
6
|
-
const { visualizationType, series, orientation } = config
|
|
6
|
+
const { visualizationType, series, orientation, visualizationSubType } = config
|
|
7
7
|
|
|
8
8
|
// Overall support for the chart types
|
|
9
9
|
// prettier-ignore
|
|
@@ -24,6 +24,12 @@ export const useEditorPermissions = () => {
|
|
|
24
24
|
|
|
25
25
|
const headerColors = ['theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber']
|
|
26
26
|
|
|
27
|
+
const visSupportsDateCategoryAxis = () => {
|
|
28
|
+
const disabledCharts = ['Forest Plot']
|
|
29
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
const visSupportsSuperTitle = () => {
|
|
28
34
|
const disabledCharts = ['Spark Line']
|
|
29
35
|
if (disabledCharts.includes(visualizationType)) return false
|
|
@@ -84,6 +90,15 @@ export const useEditorPermissions = () => {
|
|
|
84
90
|
}
|
|
85
91
|
}
|
|
86
92
|
|
|
93
|
+
const visHasDataSuppression = () => {
|
|
94
|
+
if ((visualizationType === 'Bar' || 'Combo') && visualizationSubType === 'regular') {
|
|
95
|
+
return true
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const visHasBrushChart = () => {
|
|
99
|
+
return ['Line', 'Bar', 'Area Chart', 'Combo'].includes(visualizationType) && orientation === 'vertical'
|
|
100
|
+
}
|
|
101
|
+
|
|
87
102
|
const visHasBarBorders = () => {
|
|
88
103
|
const disabledCharts = ['Box Plot', 'Scatter Plot', 'Pie']
|
|
89
104
|
if (disabledCharts.includes(visualizationType)) return false
|
|
@@ -154,13 +169,13 @@ export const useEditorPermissions = () => {
|
|
|
154
169
|
}
|
|
155
170
|
|
|
156
171
|
const visSupportsDateCategoryTickRotation = () => {
|
|
157
|
-
const disabledCharts = ['
|
|
172
|
+
const disabledCharts = ['Spark Line']
|
|
158
173
|
if (disabledCharts.includes(visualizationType)) return false
|
|
159
174
|
return true
|
|
160
175
|
}
|
|
161
176
|
|
|
162
177
|
const visSupportsDateCategoryNumTicks = () => {
|
|
163
|
-
const disabledCharts = ['
|
|
178
|
+
const disabledCharts = ['Spark Line']
|
|
164
179
|
if (disabledCharts.includes(visualizationType)) return false
|
|
165
180
|
return true
|
|
166
181
|
}
|
|
@@ -177,6 +192,18 @@ export const useEditorPermissions = () => {
|
|
|
177
192
|
return true
|
|
178
193
|
}
|
|
179
194
|
|
|
195
|
+
const visSupportsValueAxisMax = () => {
|
|
196
|
+
const disabledCharts = ['Forest Plot']
|
|
197
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
198
|
+
return true
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const visSupportsValueAxisMin = () => {
|
|
202
|
+
const disabledCharts = ['Forest Plot']
|
|
203
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
204
|
+
return true
|
|
205
|
+
}
|
|
206
|
+
|
|
180
207
|
const visSupportsFilters = () => {
|
|
181
208
|
const disabledCharts = ['Forest Plot']
|
|
182
209
|
if (disabledCharts.includes(visualizationType)) return false
|
|
@@ -192,16 +219,22 @@ export const useEditorPermissions = () => {
|
|
|
192
219
|
|
|
193
220
|
// implement later
|
|
194
221
|
const visSupportsValueAxisTicks = () => {
|
|
222
|
+
const disabledCharts = ['Forest Plot']
|
|
223
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
195
224
|
return true
|
|
196
225
|
}
|
|
197
226
|
|
|
198
227
|
// implement later
|
|
199
228
|
const visSupportsValueAxisLine = () => {
|
|
229
|
+
const disabledCharts = ['Forest Plot']
|
|
230
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
200
231
|
return true
|
|
201
232
|
}
|
|
202
233
|
|
|
203
234
|
// implement later
|
|
204
235
|
const visSupportsValueAxisLabels = () => {
|
|
236
|
+
const disabledCharts = ['Forest Plot']
|
|
237
|
+
if (disabledCharts.includes(visualizationType)) return false
|
|
205
238
|
return true
|
|
206
239
|
}
|
|
207
240
|
|
|
@@ -242,6 +275,12 @@ export const useEditorPermissions = () => {
|
|
|
242
275
|
return true
|
|
243
276
|
}
|
|
244
277
|
|
|
278
|
+
const visSupportsReactTooltip = () => {
|
|
279
|
+
if (['Deviation Bar', 'Box Plot', 'Scatter Plot', 'Paired Bar'].includes(visualizationType) || (visualizationType === 'Bar' && config.tooltips.singleSeries)) {
|
|
280
|
+
return true
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
245
284
|
return {
|
|
246
285
|
enabledChartTypes,
|
|
247
286
|
headerColors,
|
|
@@ -250,11 +289,14 @@ export const useEditorPermissions = () => {
|
|
|
250
289
|
visHasBarBorders,
|
|
251
290
|
visHasDataCutoff,
|
|
252
291
|
visHasLabelOnData,
|
|
292
|
+
visHasDataSuppression,
|
|
253
293
|
visHasLegend,
|
|
294
|
+
visHasBrushChart,
|
|
254
295
|
visHasNumbersOnBars,
|
|
255
296
|
visSupportsBarSpace,
|
|
256
297
|
visSupportsBarThickness,
|
|
257
298
|
visSupportsChartHeight,
|
|
299
|
+
visSupportsDateCategoryAxis,
|
|
258
300
|
visSupportsDateCategoryAxisLabel,
|
|
259
301
|
visSupportsDateCategoryAxisLine,
|
|
260
302
|
visSupportsDateCategoryAxisTicks,
|
|
@@ -276,6 +318,9 @@ export const useEditorPermissions = () => {
|
|
|
276
318
|
visSupportsValueAxisGridLines,
|
|
277
319
|
visSupportsValueAxisLabels,
|
|
278
320
|
visSupportsValueAxisLine,
|
|
279
|
-
visSupportsValueAxisTicks
|
|
321
|
+
visSupportsValueAxisTicks,
|
|
322
|
+
visSupportsReactTooltip,
|
|
323
|
+
visSupportsValueAxisMax,
|
|
324
|
+
visSupportsValueAxisMin
|
|
280
325
|
}
|
|
281
326
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useContext } from 'react'
|
|
2
2
|
|
|
3
3
|
// cdc
|
|
4
|
-
import ConfigContext from '
|
|
4
|
+
import ConfigContext from '../../ConfigContext'
|
|
5
5
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
6
6
|
import { colorPalettesChart, sequentialPalettes } from '@cdc/core/data/colorPalettes'
|
|
7
7
|
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { useContext, useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
// visx
|
|
4
|
+
import { Group } from '@visx/group'
|
|
5
|
+
import { Line, Bar, Circle, LinePath } from '@visx/shape'
|
|
6
|
+
import { Text } from '@visx/text'
|
|
7
|
+
import { scaleLinear } from '@visx/scale'
|
|
8
|
+
import { curveLinearClosed } from '@visx/curve'
|
|
9
|
+
|
|
10
|
+
// types
|
|
11
|
+
import { type ForestPlotProps } from '@cdc/chart/src/components/ForestPlot/ForestPlotProps'
|
|
12
|
+
import { type ChartConfig } from '@cdc/chart/src/types/ChartConfig'
|
|
13
|
+
import { type ChartContext } from '@cdc/chart/src/types/ChartContext'
|
|
14
|
+
|
|
15
|
+
// cdc
|
|
16
|
+
import ConfigContext from '../../ConfigContext'
|
|
17
|
+
import { getFontSize } from '@cdc/core/helpers/cove/number'
|
|
18
|
+
|
|
19
|
+
const ForestPlot = (props: ForestPlotProps) => {
|
|
20
|
+
const { rawData: data, updateConfig } = useContext<ChartContext>(ConfigContext)
|
|
21
|
+
const { xScale, yScale, config, height, width, handleTooltipMouseOff, handleTooltipMouseOver } = props
|
|
22
|
+
const { forestPlot } = config as ChartConfig
|
|
23
|
+
const labelPosition = config.xAxis.tickWidthMax + 10
|
|
24
|
+
const [initialLogTicksSet, setInitialLogTicks] = useState(false)
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
try {
|
|
28
|
+
const defaultColumns = ['estimateField', 'lower', 'upper', 'estimateRadius']
|
|
29
|
+
const newConfig = config
|
|
30
|
+
|
|
31
|
+
// Setting a default number of colums.additionalColumn1, columns.additionalColumn2, etc.
|
|
32
|
+
// to loop through to clean up which columns are being displayed by default for forest plots
|
|
33
|
+
// Set tooltip and data table properties according to the default forestPlot column names above.
|
|
34
|
+
const colsToCheck = 10
|
|
35
|
+
for (let i = 0; i < colsToCheck; i++) {
|
|
36
|
+
defaultColumns.forEach(col => {
|
|
37
|
+
if (config.forestPlot[col] && config.forestPlot[col] !== newConfig.columns[config.forestPlot[`additionalColumn${i}`]]?.name) {
|
|
38
|
+
delete newConfig.columns[`additionalColumn${i}`] // Remove old value if found to prevent duplicates
|
|
39
|
+
newConfig.columns[config.forestPlot[col]] = {}
|
|
40
|
+
newConfig.columns[config.forestPlot[col]].dataKey = newConfig.forestPlot[col]
|
|
41
|
+
newConfig.columns[config.forestPlot[col]].name = newConfig.forestPlot[col]
|
|
42
|
+
newConfig.columns[config.forestPlot[col]].dataTable = true
|
|
43
|
+
newConfig.columns[config.forestPlot[col]].tooltips = true
|
|
44
|
+
newConfig.columns[config.forestPlot[col]].label = newConfig.forestPlot[col]
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Add weight column into tooltip and data table.
|
|
50
|
+
if (config.forestPlot.radius.scalingColumn) {
|
|
51
|
+
newConfig.columns[config.forestPlot.radius.scalingColumn] = {}
|
|
52
|
+
newConfig.columns[config.forestPlot.radius.scalingColumn].dataKey = newConfig.forestPlot.radius.scalingColumn
|
|
53
|
+
newConfig.columns[config.forestPlot.radius.scalingColumn].name = newConfig.forestPlot.radius.scalingColumn
|
|
54
|
+
newConfig.columns[config.forestPlot.radius.scalingColumn].label = newConfig.forestPlot.radius.scalingColumn
|
|
55
|
+
newConfig.columns[config.forestPlot.radius.scalingColumn].dataTable = true
|
|
56
|
+
newConfig.columns[config.forestPlot.radius.scalingColumn].tooltips = true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (newConfig.table.showVertical) {
|
|
60
|
+
newConfig.table.indexLabel = config.xAxis.dataKey
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
updateConfig(newConfig)
|
|
64
|
+
} catch (e) {
|
|
65
|
+
console.log(e.message)
|
|
66
|
+
}
|
|
67
|
+
}, [])
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (!initialLogTicksSet && config.forestPlot.type === 'Logarithmic') {
|
|
71
|
+
updateConfig({
|
|
72
|
+
...config,
|
|
73
|
+
dataFormat: {
|
|
74
|
+
...config.dataFormat,
|
|
75
|
+
roundTo: 2
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
setInitialLogTicks(true)
|
|
79
|
+
}
|
|
80
|
+
}, [config.forestPlot.type])
|
|
81
|
+
|
|
82
|
+
const pooledData = config.data.find(d => d[config.xAxis.dataKey] === config.forestPlot.pooledResult.column)
|
|
83
|
+
|
|
84
|
+
const regressionPoints = pooledData
|
|
85
|
+
? [
|
|
86
|
+
{ x: xScale(pooledData[config.forestPlot.lower]), y: height - Number(config.forestPlot.rowHeight) },
|
|
87
|
+
{ x: xScale(pooledData[config.forestPlot.estimateField]), y: height - forestPlot.pooledResult.diamondHeight - Number(config.forestPlot.rowHeight) },
|
|
88
|
+
{ x: xScale(pooledData[config.forestPlot.upper]), y: height - Number(config.forestPlot.rowHeight) },
|
|
89
|
+
{ x: xScale(pooledData[config.forestPlot.estimateField]), y: height + forestPlot.pooledResult.diamondHeight - Number(config.forestPlot.rowHeight) },
|
|
90
|
+
{ x: xScale(pooledData[config.forestPlot.lower]), y: height - Number(config.forestPlot.rowHeight) }
|
|
91
|
+
]
|
|
92
|
+
: []
|
|
93
|
+
|
|
94
|
+
const topMarginOffset = config.forestPlot.rowHeight
|
|
95
|
+
|
|
96
|
+
const topLine = [
|
|
97
|
+
{ x: 0, y: topMarginOffset },
|
|
98
|
+
{ x: width, y: topMarginOffset }
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
const bottomLine = [
|
|
102
|
+
{ x: 0, y: height },
|
|
103
|
+
{ x: width, y: height }
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
type Columns = {
|
|
107
|
+
forestPlot?: boolean
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const columnsOnChart: Columns[] = Object.entries(config.columns)
|
|
111
|
+
.map(entry => entry[1])
|
|
112
|
+
.filter(entry => entry.forestPlot === true)
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<>
|
|
116
|
+
<Group width={width}>
|
|
117
|
+
{forestPlot.title && (
|
|
118
|
+
<Text className={`forest-plot--title`} x={forestPlot.type === 'Linear' ? xScale(0) : xScale(1)} y={0} textAnchor='middle' verticalAnchor='start' fontSize={getFontSize(config.fontSize)} fill={'black'}>
|
|
119
|
+
{forestPlot.title}
|
|
120
|
+
</Text>
|
|
121
|
+
)}
|
|
122
|
+
|
|
123
|
+
{/* Line of no effect on Continuous Scale. */}
|
|
124
|
+
{forestPlot.lineOfNoEffect.show && forestPlot.type === 'Linear' && <Line from={{ x: xScale(0), y: 0 + topMarginOffset }} to={{ x: xScale(0), y: height }} className='forestplot__line-of-no-effect' stroke={forestPlot.regression.baseLineColor || 'black'} />}
|
|
125
|
+
|
|
126
|
+
{/* Line of no effect on Logarithmic Scale. */}
|
|
127
|
+
{forestPlot.lineOfNoEffect.show && forestPlot.type === 'Logarithmic' && <Line from={{ x: xScale(1), y: 0 + topMarginOffset }} to={{ x: xScale(1), y: height }} className='forestplot__line-of-no-effect' stroke={forestPlot.regression.baseLineColor || 'black'} />}
|
|
128
|
+
|
|
129
|
+
{data.map((d, i) => {
|
|
130
|
+
// calculate both square and circle size based on radius.min and radius.max
|
|
131
|
+
const scaleRadius = scaleLinear({
|
|
132
|
+
domain: data.map(d => d[forestPlot.radius.scalingColumn]),
|
|
133
|
+
range: [forestPlot.radius.min, forestPlot.radius.max]
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
// glyph settings
|
|
137
|
+
const rectSize = forestPlot.radius.scalingColumn !== '' ? scaleRadius(data[i][forestPlot.radius.scalingColumn]) : 4
|
|
138
|
+
const shapeColor = forestPlot.colors.shape ? forestPlot.colors.shape : 'black'
|
|
139
|
+
const lineColor = forestPlot.colors.line ? forestPlot.colors.line : 'black'
|
|
140
|
+
|
|
141
|
+
// ci size
|
|
142
|
+
const ciEndSize = 4
|
|
143
|
+
|
|
144
|
+
// Don't run calculations on the pooled column
|
|
145
|
+
const isTotalColumn = d[config.xAxis.dataKey] === forestPlot.pooledResult.column
|
|
146
|
+
|
|
147
|
+
return !isTotalColumn ? (
|
|
148
|
+
<Group>
|
|
149
|
+
{/* Confidence Interval Paths */}
|
|
150
|
+
<path
|
|
151
|
+
stroke={lineColor}
|
|
152
|
+
strokeWidth={1}
|
|
153
|
+
className='lower-ci'
|
|
154
|
+
d={`
|
|
155
|
+
M${xScale(d[forestPlot.lower])} ${yScale(i) - Number(ciEndSize)}
|
|
156
|
+
L${xScale(d[forestPlot.lower])} ${yScale(i) + Number(ciEndSize)}
|
|
157
|
+
`}
|
|
158
|
+
/>
|
|
159
|
+
|
|
160
|
+
<path
|
|
161
|
+
stroke={lineColor}
|
|
162
|
+
strokeWidth={1}
|
|
163
|
+
className='upper-ci'
|
|
164
|
+
d={`
|
|
165
|
+
M${xScale(d[forestPlot.upper])} ${yScale(i) - Number(ciEndSize)}
|
|
166
|
+
L${xScale(d[forestPlot.upper])} ${yScale(i) + Number(ciEndSize)}
|
|
167
|
+
`}
|
|
168
|
+
/>
|
|
169
|
+
|
|
170
|
+
{/* main line */}
|
|
171
|
+
<line stroke={lineColor} className={`line-${d[config.yAxis.dataKey]}`} key={i} x1={xScale(d[forestPlot.lower])} x2={xScale(d[forestPlot.upper])} y1={yScale(i)} y2={yScale(i)} />
|
|
172
|
+
{forestPlot.shape === 'circle' && (
|
|
173
|
+
<Circle className='forest-plot--circle' cx={xScale(Number(d[forestPlot.estimateField]))} cy={yScale(i)} r={forestPlot.radius.scalingColumn !== '' ? scaleRadius(data[i][forestPlot.radius.scalingColumn]) : 4} fill={shapeColor} style={{ opacity: 1, filter: 'unset' }} />
|
|
174
|
+
)}
|
|
175
|
+
{forestPlot.shape === 'square' && <rect className='forest-plot--square' x={xScale(Number(d[forestPlot.estimateField]))} y={yScale(i) - rectSize / 2} width={rectSize} height={rectSize} fill={shapeColor} style={{ opacity: 1, filter: 'unset' }} />}
|
|
176
|
+
{forestPlot.shape === 'text' && (
|
|
177
|
+
<Text className='forest-plot--text' x={xScale(Number(d[forestPlot.estimateField]))} y={yScale(i)} textAnchor='middle' verticalAnchor='middle' fontSize={getFontSize(config.fontSize)} fill={shapeColor}>
|
|
178
|
+
{d[forestPlot.estimateField]}
|
|
179
|
+
</Text>
|
|
180
|
+
)}
|
|
181
|
+
</Group>
|
|
182
|
+
) : (
|
|
183
|
+
<LinePath data={regressionPoints} x={d => d.x} y={d => d.y - getFontSize(config.fontSize) / 2} stroke='black' strokeWidth={2} fill={'black'} curve={curveLinearClosed} />
|
|
184
|
+
)
|
|
185
|
+
})}
|
|
186
|
+
|
|
187
|
+
{/* regression diamond */}
|
|
188
|
+
{regressionPoints && forestPlot.regression.showDiamond && <LinePath data={regressionPoints} x={d => d.x} y={d => d.y} stroke='black' strokeWidth={2} fill={forestPlot.regression.baseLineColor} curve={curveLinearClosed} />}
|
|
189
|
+
{/* regression text */}
|
|
190
|
+
{forestPlot.regression.description && (
|
|
191
|
+
<Text x={0 - Number(config.xAxis.size)} width={width} y={height - config.forestPlot.rowHeight - Number(forestPlot.rowHeight) / 3} verticalAnchor='start' textAnchor='start' style={{ fontWeight: 'bold', fontSize: 12 }}>
|
|
192
|
+
{forestPlot.regression.description}
|
|
193
|
+
</Text>
|
|
194
|
+
)}
|
|
195
|
+
|
|
196
|
+
<Bar key='forest-plot-tooltip-area' className='forest-plot-tooltip-area' width={width} height={height} fill={false ? 'red' : 'transparent'} fillOpacity={0.5} onMouseMove={e => handleTooltipMouseOver(e, data)} onMouseOut={handleTooltipMouseOff} />
|
|
197
|
+
</Group>
|
|
198
|
+
<Line from={topLine[0]} to={topLine[1]} style={{ stroke: 'black', strokeWidth: 2 }} className='forestplot__top-line' />
|
|
199
|
+
<Line from={bottomLine[0]} to={bottomLine[1]} style={{ stroke: 'black', strokeWidth: 2 }} className='forestplot__bottom-line' />
|
|
200
|
+
|
|
201
|
+
{/* column data */}
|
|
202
|
+
{columnsOnChart.map(column => {
|
|
203
|
+
return data.map((d, i) => {
|
|
204
|
+
return (
|
|
205
|
+
<Text className={`${d[column.name]}`} x={column.forestPlotAlignRight ? width : column.forestPlotStartingPoint} y={yScale(i)} textAnchor={column.forestPlotAlignRight ? 'end' : 'start'} verticalAnchor='middle' fontSize={getFontSize(config.fontSize)} fill={'black'}>
|
|
206
|
+
{d[column.name]}
|
|
207
|
+
</Text>
|
|
208
|
+
)
|
|
209
|
+
})
|
|
210
|
+
})}
|
|
211
|
+
|
|
212
|
+
{/* X Axis DataKey Cols*/}
|
|
213
|
+
{!forestPlot.hideDateCategoryCol &&
|
|
214
|
+
data.map((d, i) => {
|
|
215
|
+
return (
|
|
216
|
+
<Text className={`${d[config.xAxis.dataKey]}`} x={0} y={yScale(i)} textAnchor={'start'} verticalAnchor='middle' fontSize={getFontSize(config.fontSize)} fill={'black'}>
|
|
217
|
+
{d[config.xAxis.dataKey]}
|
|
218
|
+
</Text>
|
|
219
|
+
)
|
|
220
|
+
})}
|
|
221
|
+
|
|
222
|
+
{/* X Axis Datakey Header */}
|
|
223
|
+
{!forestPlot.hideDateCategoryCol && config.xAxis.dataKey && (
|
|
224
|
+
<Text className={config.xAxis.dataKey} x={0} y={0} textAnchor={'start'} verticalAnchor='start' fontSize={getFontSize(config.fontSize)} fill={'black'}>
|
|
225
|
+
{config.xAxis.dataKey}
|
|
226
|
+
</Text>
|
|
227
|
+
)}
|
|
228
|
+
|
|
229
|
+
{/* column headers */}
|
|
230
|
+
{columnsOnChart.map(column => {
|
|
231
|
+
return (
|
|
232
|
+
<Text className={`${column.label}`} x={column.forestPlotAlignRight ? width : column.forestPlotStartingPoint} y={0} textAnchor={column.forestPlotAlignRight ? 'end' : 'start'} verticalAnchor='start' fontSize={getFontSize(config.fontSize)} fill={'black'}>
|
|
233
|
+
{column.label}
|
|
234
|
+
</Text>
|
|
235
|
+
)
|
|
236
|
+
})}
|
|
237
|
+
|
|
238
|
+
{/* left bottom label */}
|
|
239
|
+
{forestPlot.leftLabel && (
|
|
240
|
+
<Text className='forest-plot__left-label' x={forestPlot.type === 'Linear' ? xScale(0) - 25 : xScale(1) - 25} y={height + labelPosition} textAnchor='end' verticalAnchor='start'>
|
|
241
|
+
{forestPlot.leftLabel}
|
|
242
|
+
</Text>
|
|
243
|
+
)}
|
|
244
|
+
|
|
245
|
+
{forestPlot.rightLabel && (
|
|
246
|
+
<Text className='forest-plot__right-label' x={forestPlot.type === 'Linear' ? xScale(0) + 25 : xScale(1) + 25} y={height + labelPosition} textAnchor='start' verticalAnchor='start'>
|
|
247
|
+
{forestPlot.rightLabel}
|
|
248
|
+
</Text>
|
|
249
|
+
)}
|
|
250
|
+
</>
|
|
251
|
+
)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export default ForestPlot
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ChartConfig } from '@cdc/chart/src/types/ChartConfig'
|
|
2
|
+
|
|
3
|
+
export type ForestPlotProps = {
|
|
4
|
+
/** xScale - scaling function for bottom axis */
|
|
5
|
+
xScale: Function
|
|
6
|
+
/** yScale - scaling function for left axis */
|
|
7
|
+
yScale: Function
|
|
8
|
+
/** config - standard chart config */
|
|
9
|
+
config: ChartConfig
|
|
10
|
+
/** height - height of chart */
|
|
11
|
+
height: number
|
|
12
|
+
/** width - width of chart */
|
|
13
|
+
width: number
|
|
14
|
+
/** handleTooltipMouseOff - helper function for hiding tooltip */
|
|
15
|
+
handleTooltipMouseOff: Function
|
|
16
|
+
/** handleTooltipMousOver - helper function for showing tooltip */
|
|
17
|
+
handleTooltipMouseOver: Function
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Forest Plot Styles...
|