@cdc/chart 4.25.6-2 → 4.25.7
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 +52634 -30848
- package/package.json +3 -2
- package/src/CdcChartComponent.tsx +13 -9
- package/src/_stories/Chart.BoxPlot.stories.tsx +35 -0
- package/src/_stories/Chart.stories.tsx +0 -7
- package/src/_stories/Chart.tooltip.stories.tsx +35 -275
- package/src/_stories/_mock/bar-chart-suppressed.json +2 -80
- package/src/_stories/_mock/boxplot_multiseries.json +252 -166
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +1 -1
- package/src/components/AreaChart/components/AreaChart.jsx +4 -8
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +34 -2
- package/src/components/BarChart/components/BarChart.Vertical.tsx +15 -0
- package/src/components/BoxPlot/BoxPlot.Horizontal.tsx +131 -0
- package/src/components/BoxPlot/{BoxPlot.tsx → BoxPlot.Vertical.tsx} +4 -4
- package/src/components/BoxPlot/helpers/index.ts +32 -12
- package/src/components/BrushChart.tsx +1 -1
- package/src/components/EditorPanel/EditorPanel.tsx +3 -3
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +2 -2
- package/src/components/Forecasting/{Forecasting.jsx → Forecasting.tsx} +32 -12
- package/src/components/Legend/LegendGroup/LegendGroup.tsx +1 -0
- package/src/components/Legend/helpers/index.ts +2 -2
- package/src/components/LinearChart.tsx +63 -15
- package/src/data/initial-state.js +1 -5
- package/src/helpers/filterAndShiftLinearDateTicks.ts +58 -0
- package/src/helpers/getBridgedData.ts +13 -0
- package/src/helpers/tests/getBridgedData.test.ts +64 -0
- package/src/hooks/useScales.ts +42 -42
- package/src/hooks/useTooltip.tsx +3 -2
- package/src/scss/main.scss +2 -8
- package/src/store/chart.actions.ts +2 -2
- package/src/store/chart.reducer.ts +4 -12
- package/src/types/ChartConfig.ts +0 -5
- package/examples/private/0527.json +0 -1
- package/examples/private/DEV-8850-2.json +0 -493
- package/examples/private/DEV-9822.json +0 -574
- package/examples/private/DEV-9840.json +0 -553
- package/examples/private/DEV-9850-3.json +0 -461
- package/examples/private/chart.json +0 -1084
- package/examples/private/ci_formatted.json +0 -202
- package/examples/private/ci_issue.json +0 -3016
- package/examples/private/completed.json +0 -634
- package/examples/private/dem-data-long.csv +0 -20
- package/examples/private/dem-data-long.json +0 -36
- package/examples/private/demographic_data.csv +0 -157
- package/examples/private/demographic_data.json +0 -2654
- package/examples/private/demographic_dynamic.json +0 -443
- package/examples/private/demographic_standard.json +0 -560
- package/examples/private/ehdi.json +0 -29939
- package/examples/private/line-issue.json +0 -497
- package/examples/private/not-loading.json +0 -360
- package/examples/private/test.json +0 -493
- package/examples/private/testing-pie.json +0 -436
- package/src/components/BoxPlot/index.tsx +0 -3
- /package/src/components/Brush/{BrushController..tsx → BrushController.tsx} +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Ensure that the last tick is shown for charts with a "Date (Linear Scale)" scale
|
|
2
|
+
import { ChartConfig } from '../types/ChartConfig'
|
|
3
|
+
import { getTicks } from '@visx/scale'
|
|
4
|
+
export const filterAndShiftLinearDateTicks = (
|
|
5
|
+
config: ChartConfig,
|
|
6
|
+
axisProps: { scale: any; numTicks: number; ticks: { value: any; formattedValue?: string }[] },
|
|
7
|
+
xAxisDataMapped: any[],
|
|
8
|
+
formatDate: (value: any, index: number, all: any[]) => string
|
|
9
|
+
) => {
|
|
10
|
+
// Guard #1: must have a scale & ticks array
|
|
11
|
+
if (!axisProps?.scale || !Array.isArray(axisProps.ticks)) {
|
|
12
|
+
return []
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Guard #2: if no domain data, just format what we have
|
|
16
|
+
if (!Array.isArray(xAxisDataMapped) || xAxisDataMapped.length === 0) {
|
|
17
|
+
axisProps.ticks.forEach((t, i) => {
|
|
18
|
+
t.formattedValue = formatDate(t.value, i, axisProps.ticks)
|
|
19
|
+
})
|
|
20
|
+
return axisProps.ticks
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// get our filtered tick *values*
|
|
24
|
+
const filteredTickValues = getTicks(axisProps.scale, axisProps.numTicks) || []
|
|
25
|
+
|
|
26
|
+
let ticks = axisProps.ticks
|
|
27
|
+
|
|
28
|
+
if (filteredTickValues.length > 0 && filteredTickValues.length < xAxisDataMapped.length) {
|
|
29
|
+
const lastFiltered = filteredTickValues[filteredTickValues.length - 1]
|
|
30
|
+
const lastIdx = xAxisDataMapped.indexOf(lastFiltered)
|
|
31
|
+
|
|
32
|
+
let shift = 0
|
|
33
|
+
if (lastIdx >= 0 && lastIdx < xAxisDataMapped.length - 1) {
|
|
34
|
+
shift = config.xAxis.sortByRecentDate
|
|
35
|
+
? -xAxisDataMapped.indexOf(filteredTickValues[0])
|
|
36
|
+
: xAxisDataMapped.length - 1 - lastIdx
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
ticks = filteredTickValues.map(value => {
|
|
40
|
+
const baseIndex = axisProps.ticks.findIndex(t => t.value === value)
|
|
41
|
+
const targetIndex = baseIndex + shift
|
|
42
|
+
|
|
43
|
+
// Guard #3: if shifting would go out of bounds, clamp
|
|
44
|
+
const safeIndex = Math.max(0, Math.min(axisProps.ticks.length - 1, targetIndex))
|
|
45
|
+
return axisProps.ticks[safeIndex]
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Finally, format all ticks
|
|
50
|
+
ticks.forEach((tick, i) => {
|
|
51
|
+
// Guard #4: only format if we actually have a value
|
|
52
|
+
if (tick && tick.value != null) {
|
|
53
|
+
tick.formattedValue = formatDate(tick.value, i, ticks)
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
return ticks
|
|
58
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const getBridgedData = (stageKey: string, stageColumn: string, data: Record<string, any>[]) => {
|
|
2
|
+
const allStages: string[] = Array.from(new Set(data.map(d => d?.[stageColumn]).filter(Boolean)))
|
|
3
|
+
|
|
4
|
+
const stageIndex: number = allStages.indexOf(stageKey)
|
|
5
|
+
if (stageIndex === -1) return []
|
|
6
|
+
const currentStage = data.filter(d => d?.[stageColumn] === stageKey)
|
|
7
|
+
const nextKey = allStages[stageIndex + 1]
|
|
8
|
+
if (nextKey) {
|
|
9
|
+
const nextSlice = data.filter(d => d[stageColumn] === nextKey)
|
|
10
|
+
return [...currentStage, nextSlice[0]]
|
|
11
|
+
}
|
|
12
|
+
return currentStage
|
|
13
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { getBridgedData } from '../getBridgedData'
|
|
3
|
+
|
|
4
|
+
describe('getBridgedData', () => {
|
|
5
|
+
const sampleData = [
|
|
6
|
+
{ Month: 'Jan', value: 1 },
|
|
7
|
+
{ Month: 'Jan', value: 2 },
|
|
8
|
+
{ Month: 'Feb', value: 3 },
|
|
9
|
+
{ Month: 'Feb', value: 4 },
|
|
10
|
+
{ Month: 'Mar', value: 5 }
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
it('returns correct slice for stageKey with next stage', () => {
|
|
14
|
+
const result = getBridgedData('Jan', 'Month', sampleData)
|
|
15
|
+
|
|
16
|
+
expect(result).toEqual([
|
|
17
|
+
{ Month: 'Jan', value: 1 },
|
|
18
|
+
{ Month: 'Jan', value: 2 },
|
|
19
|
+
{ Month: 'Feb', value: 3 } // only first item from next stage
|
|
20
|
+
])
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('returns correct slice for stageKey with no next stage', () => {
|
|
24
|
+
const result = getBridgedData('Mar', 'Month', sampleData)
|
|
25
|
+
|
|
26
|
+
expect(result).toEqual([{ Month: 'Mar', value: 5 }])
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('returns empty if stageKey not found', () => {
|
|
30
|
+
const result = getBridgedData('Dec', 'Month', sampleData)
|
|
31
|
+
|
|
32
|
+
expect(result).toEqual([])
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('handles unordered input data and preserves stage order by first appearance', () => {
|
|
36
|
+
const unorderedData = [
|
|
37
|
+
{ step: 'B', val: 1 },
|
|
38
|
+
{ step: 'A', val: 2 },
|
|
39
|
+
{ step: 'C', val: 3 },
|
|
40
|
+
{ step: 'A', val: 4 },
|
|
41
|
+
{ step: 'B', val: 5 }
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
const result = getBridgedData('A', 'step', unorderedData)
|
|
45
|
+
|
|
46
|
+
expect(result).toEqual([
|
|
47
|
+
{ step: 'A', val: 2 },
|
|
48
|
+
{ step: 'A', val: 4 },
|
|
49
|
+
{ step: 'C', val: 3 }
|
|
50
|
+
])
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('returns only items matching current stage if next stage has no data', () => {
|
|
54
|
+
const dataWithEmptyStage = [
|
|
55
|
+
{ stage: '1', x: 10 },
|
|
56
|
+
{ stage: '2', x: 20 },
|
|
57
|
+
{ stage: '3', x: 30 }
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
const result = getBridgedData('3', 'stage', dataWithEmptyStage)
|
|
61
|
+
|
|
62
|
+
expect(result).toEqual([{ stage: '3', x: 30 }])
|
|
63
|
+
})
|
|
64
|
+
})
|
package/src/hooks/useScales.ts
CHANGED
|
@@ -44,7 +44,7 @@ const useScales = (properties: useScaleProps) => {
|
|
|
44
44
|
const xAxisType = config.runtime.xAxis.type
|
|
45
45
|
const isHorizontal = config.orientation === 'horizontal'
|
|
46
46
|
const { visualizationType, xAxis, forestPlot } = config
|
|
47
|
-
|
|
47
|
+
const paddingRange = ['Area Chart', 'Forecasting'].includes(config.visualizationType) ? 1 : 1 - config.barThickness
|
|
48
48
|
// define scales
|
|
49
49
|
let xScale = null
|
|
50
50
|
let yScale = null
|
|
@@ -68,22 +68,16 @@ const useScales = (properties: useScaleProps) => {
|
|
|
68
68
|
|
|
69
69
|
// handle Vertical bars
|
|
70
70
|
if (!isHorizontal) {
|
|
71
|
-
xScale = composeScaleBand(xAxisDataMapped, [0, xMax],
|
|
71
|
+
xScale = composeScaleBand(xAxisDataMapped, [0, xMax], paddingRange)
|
|
72
72
|
yScale = composeYScale(properties)
|
|
73
73
|
seriesScale = composeScaleBand(seriesDomain, [0, xScale.bandwidth()], 0)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// handle Linear scaled viz
|
|
77
|
-
if (config.xAxis.type === 'date' && !isHorizontal) {
|
|
78
|
-
const xAxisDataMappedSorted = sortXAxisData(xAxisDataMapped, config.xAxis.sortByRecentDate)
|
|
79
|
-
xScale = composeScaleBand(xAxisDataMappedSorted, [0, xMax], 1 - config.barThickness)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
76
|
// handle Linear scaled viz
|
|
83
77
|
if (config.xAxis.type === 'date' && !isHorizontal) {
|
|
84
78
|
const sorted = sortXAxisData(xAxisDataMapped, config.xAxis.sortByRecentDate)
|
|
85
79
|
|
|
86
|
-
xScale = composeScaleBand(sorted, [0, xMax],
|
|
80
|
+
xScale = composeScaleBand(sorted, [0, xMax], paddingRange)
|
|
87
81
|
xScale.type = scaleTypes.BAND
|
|
88
82
|
}
|
|
89
83
|
|
|
@@ -153,44 +147,50 @@ const useScales = (properties: useScaleProps) => {
|
|
|
153
147
|
|
|
154
148
|
// handle Box plot
|
|
155
149
|
if (visualizationType === 'Box Plot') {
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
150
|
+
const {
|
|
151
|
+
boxplot: { plots, hideOutliers },
|
|
152
|
+
xAxis: { dataKey },
|
|
153
|
+
orientation,
|
|
154
|
+
runtime: { seriesKeys },
|
|
155
|
+
series,
|
|
156
|
+
barThickness
|
|
157
|
+
} = config
|
|
158
|
+
|
|
159
|
+
// 1) merge outliers + fences
|
|
160
|
+
let lo = min,
|
|
161
|
+
hi = max
|
|
162
|
+
for (const { columnOutliers = [], columnLowerBounds: lb, columnUpperBounds: ub } of plots) {
|
|
163
|
+
if (!hideOutliers && columnOutliers.length) {
|
|
164
|
+
lo = Math.min(lo, ...columnOutliers)
|
|
165
|
+
hi = Math.max(hi, ...columnOutliers)
|
|
166
|
+
}
|
|
167
|
+
lo = Math.min(lo, lb)
|
|
168
|
+
hi = Math.max(hi, ub)
|
|
169
169
|
}
|
|
170
|
+
;[min, max] = [lo, hi]
|
|
170
171
|
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
let highestFence = Math.max(...config.boxplot.plots.map(item => item.columnUpperBounds))
|
|
172
|
+
// 2) unique categories
|
|
173
|
+
const cats = Array.from(new Set(data.map(d => d[dataKey])))
|
|
174
174
|
|
|
175
|
-
if (
|
|
176
|
-
|
|
175
|
+
if (orientation === 'horizontal') {
|
|
176
|
+
xScale = composeXScale({ min, max, xMax, config })
|
|
177
|
+
xScale.type = scaleTypes.LINEAR
|
|
177
178
|
|
|
178
|
-
|
|
179
|
+
yScale = composeScaleBand(cats, [0, yMax], 0.4)
|
|
180
|
+
seriesScale = composeScaleBand(seriesKeys, [0, yScale.bandwidth()], 0.3)
|
|
181
|
+
} else {
|
|
182
|
+
xScale = composeScaleBand(cats, [0, xMax], 1 - barThickness)
|
|
183
|
+
xScale.type = scaleTypes.BAND
|
|
179
184
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
range: [0, xMax],
|
|
190
|
-
domain: categories
|
|
191
|
-
})
|
|
192
|
-
xScale.type = scaleTypes.BAND
|
|
193
|
-
seriesScale = composeScaleBand(domain, range)
|
|
185
|
+
// numeric → Y
|
|
186
|
+
yScale = composeYScale({ min, max, yMax, config, leftMax: 0 })
|
|
187
|
+
|
|
188
|
+
seriesScale = composeScaleBand(
|
|
189
|
+
series.map(s => s.dataKey),
|
|
190
|
+
[0, xScale.bandwidth()],
|
|
191
|
+
0
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
// handle Paired bar
|
package/src/hooks/useTooltip.tsx
CHANGED
|
@@ -286,10 +286,11 @@ export const useTooltip = props => {
|
|
|
286
286
|
let minDistance = Number.MAX_VALUE
|
|
287
287
|
let offset = x
|
|
288
288
|
|
|
289
|
+
const barThicknessOffset = config.xAxis.type === 'date' ? xScale.bandwidth() / 2 : 0
|
|
289
290
|
data.forEach(d => {
|
|
290
291
|
const xPosition = isDateScale(xAxis) ? xScale(parseDate(d[xAxis.dataKey])) : xScale(d[xAxis.dataKey])
|
|
291
292
|
let bwOffset = config.barHeight
|
|
292
|
-
const distance = Math.abs(Number(xPosition - offset + (isClick ? bwOffset * 2 : 0)))
|
|
293
|
+
const distance = Math.abs(Number(xPosition + barThicknessOffset - offset + (isClick ? bwOffset * 2 : 0)))
|
|
293
294
|
|
|
294
295
|
if (distance <= minDistance) {
|
|
295
296
|
minDistance = distance
|
|
@@ -593,7 +594,7 @@ export const useTooltip = props => {
|
|
|
593
594
|
|
|
594
595
|
return (
|
|
595
596
|
<li style={style} className='tooltip-body mb-1'>
|
|
596
|
-
{displayText}
|
|
597
|
+
{parse(displayText)}
|
|
597
598
|
</li>
|
|
598
599
|
)
|
|
599
600
|
}
|
package/src/scss/main.scss
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@import '@cdc/core/styles/accessibility';
|
|
2
|
+
|
|
1
3
|
@mixin breakpoint($class) {
|
|
2
4
|
@if $class == xs {
|
|
3
5
|
@media (max-width: 767px) {
|
|
@@ -739,11 +741,3 @@
|
|
|
739
741
|
.cdc-open-viz-module .debug {
|
|
740
742
|
border: 2px solid red;
|
|
741
743
|
}
|
|
742
|
-
|
|
743
|
-
// Only frontend styles are applied in WCMS/TP
|
|
744
|
-
// This helps match those styles when viewing in the editor
|
|
745
|
-
.modal.cdc-cove-editor *:focus-visible,
|
|
746
|
-
.cdc-open-viz-module *:focus-visible {
|
|
747
|
-
outline: dashed 2px rgba(255, 102, 1, 0.9) !important;
|
|
748
|
-
outline-offset: 3px !important;
|
|
749
|
-
}
|
|
@@ -16,7 +16,7 @@ type SET_DIMENSIONS = Action<'SET_DIMENSIONS', DimensionsType>
|
|
|
16
16
|
type SET_CONTAINER = Action<'SET_CONTAINER', object>
|
|
17
17
|
type SET_LOADED_EVENT = Action<'SET_LOADED_EVENT', boolean>
|
|
18
18
|
type SET_DRAG_ANNOTATIONS = Action<'SET_DRAG_ANNOTATIONS', boolean>
|
|
19
|
-
type
|
|
19
|
+
type SET_BRUSH_DATA = Action<'SET_BRUSH_DATA', object[]>
|
|
20
20
|
type ChartActions =
|
|
21
21
|
| SET_CONFIG
|
|
22
22
|
| UPDATE_CONFIG
|
|
@@ -31,6 +31,6 @@ type ChartActions =
|
|
|
31
31
|
| SET_LOADED_EVENT
|
|
32
32
|
| SET_DRAG_ANNOTATIONS
|
|
33
33
|
| SET_LOADING
|
|
34
|
-
|
|
|
34
|
+
| SET_BRUSH_DATA
|
|
35
35
|
|
|
36
36
|
export default ChartActions
|
|
@@ -18,11 +18,7 @@ type ChartState = {
|
|
|
18
18
|
coveLoadedEventRan: boolean
|
|
19
19
|
isDraggingAnnotation: boolean
|
|
20
20
|
imageId: string
|
|
21
|
-
|
|
22
|
-
data: object[]
|
|
23
|
-
isActive: boolean
|
|
24
|
-
isBrushing: boolean
|
|
25
|
-
}
|
|
21
|
+
brushData: object[] | []
|
|
26
22
|
}
|
|
27
23
|
|
|
28
24
|
export const getInitialState = (configObj: ChartConfig): ChartState => {
|
|
@@ -41,11 +37,7 @@ export const getInitialState = (configObj: ChartConfig): ChartState => {
|
|
|
41
37
|
coveLoadedEventRan: false,
|
|
42
38
|
isDraggingAnnotation: false,
|
|
43
39
|
imageId: `cove-${Math.random().toString(16).slice(-4)}`,
|
|
44
|
-
|
|
45
|
-
data: [],
|
|
46
|
-
isActive: false,
|
|
47
|
-
isBrushing: false
|
|
48
|
-
}
|
|
40
|
+
brushData: []
|
|
49
41
|
}
|
|
50
42
|
}
|
|
51
43
|
|
|
@@ -77,7 +69,7 @@ export const reducer = (state: ChartState, action: ChartActions): ChartState =>
|
|
|
77
69
|
return { ...state, coveLoadedEventRan: action.payload }
|
|
78
70
|
case 'SET_DRAG_ANNOTATIONS':
|
|
79
71
|
return { ...state, isDraggingAnnotation: action.payload }
|
|
80
|
-
case '
|
|
81
|
-
return { ...state,
|
|
72
|
+
case 'SET_BRUSH_DATA':
|
|
73
|
+
return { ...state, brushData: action.payload }
|
|
82
74
|
}
|
|
83
75
|
}
|
package/src/types/ChartConfig.ts
CHANGED
|
@@ -120,11 +120,6 @@ export type AllChartsConfig = {
|
|
|
120
120
|
barStyle: 'lollipop' | 'rounded' | 'flat'
|
|
121
121
|
barThickness: number
|
|
122
122
|
boxplot: BoxPlot
|
|
123
|
-
brush: {
|
|
124
|
-
active: boolean
|
|
125
|
-
data: object[]
|
|
126
|
-
isBrushing: boolean
|
|
127
|
-
}
|
|
128
123
|
chartMessage: { noData?: string }
|
|
129
124
|
color: string
|
|
130
125
|
colorMatchLineSeriesLabels: boolean
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"type":"chart","visualizationType":"Bar","id":1,"category":"Charts","label":"Bar","subType":"Bar","orientation":"horizontal","barThickness":"0.37","visualizationSubType":"regular","xAxis":{"sortDates":false,"anchors":[{"value":"95","color":"red","lineStyle":"Dashed Small"},{"value":"84.7","color":"black","lineStyle":"Dashed Small"}],"type":"categorical","showTargetLabel":true,"targetLabel":"Target","hideAxis":false,"hideLabel":false,"hideTicks":false,"size":"350","tickRotation":0,"min":"","max":"","labelColor":"#333","tickLabelColor":"#333","tickColor":"#333","numTicks":"","labelOffset":0,"axisPadding":200,"target":0,"maxTickRotation":45,"padding":5,"showYearsOnce":false,"sortByRecentDate":false,"dataKey":"State/cities","tickWidthMax":29,"axisBBox":29.860000610351562},"icon":{"key":null,"ref":null,"props":{},"_owner":null},"content":"Use bars to show comparisons between data categories.","datasets":{},"activeVizButtonID":1,"data":[{"State/cities":"Vermont","Completed cases":"2","Total cases":"2","Percentage who completed therapy":"100","Cases category":"1 to 52 TB cases"},{"State/cities":"Nevada","Completed cases":"44","Total cases":"44","Percentage who completed therapy":"100","Cases category":"1 to 52 TB cases"},{"State/cities":"Mississippi","Completed cases":"34","Total cases":"35","Percentage who completed therapy":"97","Cases category":"1 to 52 TB cases"},{"State/cities":"New Mexico","Completed cases":"15","Total cases":"16","Percentage who completed therapy":"94","Cases category":"1 to 52 TB cases"},{"State/cities":"Kansas","Completed cases":"27","Total cases":"29","Percentage who completed therapy":"93","Cases category":"1 to 52 TB cases"},{"State/cities":"Utah","Completed cases":"22","Total cases":"24","Percentage who completed therapy":"92","Cases category":"1 to 52 TB cases"},{"State/cities":"Delaware","Completed cases":"12","Total cases":"13","Percentage who completed therapy":"92","Cases category":"1 to 52 TB cases"},{"State/cities":"Wisconsin","Completed cases":"21","Total cases":"23","Percentage who completed therapy":"91","Cases category":"1 to 52 TB cases"},{"State/cities":"Colorado","Completed cases":"36","Total cases":"40","Percentage who completed therapy":"90","Cases category":"1 to 52 TB cases"},{"State/cities":"New Hampshire","Completed cases":"8","Total cases":"9","Percentage who completed therapy":"89","Cases category":"1 to 52 TB cases"},{"State/cities":"Chicago, IL","Completed cases":"47","Total cases":"53","Percentage who completed therapy":"89","Cases category":"1 to 52 TB cases"},{"State/cities":"Iowa","Completed cases":"28","Total cases":"32","Percentage who completed therapy":"88","Cases category":"1 to 52 TB cases"},{"State/cities":"Idaho","Completed cases":"6","Total cases":"7","Percentage who completed therapy":"86","Cases category":"1 to 52 TB cases"},{"State/cities":"District of Columbia","Completed cases":"12","Total cases":"14","Percentage who completed therapy":"86","Cases category":"1 to 52 TB cases"},{"State/cities":"Arkansas","Completed cases":"38","Total cases":"44","Percentage who completed therapy":"86","Cases category":"1 to 52 TB cases"},{"State/cities":"Alaska","Completed cases":"42","Total cases":"49","Percentage who completed therapy":"86","Cases category":"1 to 52 TB cases"},{"State/cities":"West Virginia","Completed cases":"11","Total cases":"13","Percentage who completed therapy":"85","Cases category":"1 to 52 TB cases"},{"State/cities":"Connecticut","Completed cases":"34","Total cases":"40","Percentage who completed therapy":"85","Cases category":"1 to 52 TB cases"},{"State/cities":"Oklahoma","Completed cases":"40","Total cases":"48","Percentage who completed therapy":"83","Cases category":"1 to 52 TB cases"},{"State/cities":"Maine","Completed cases":"11","Total cases":"14","Percentage who completed therapy":"79","Cases category":"1 to 52 TB cases"},{"State/cities":"South Dakota","Completed cases":"10","Total cases":"13","Percentage who completed therapy":"77","Cases category":"1 to 52 TB cases"},{"State/cities":"Rhode Island","Completed cases":"3","Total cases":"4","Percentage who completed therapy":"75","Cases category":"1 to 52 TB cases"},{"State/cities":"Baltimore, MD","Completed cases":"6","Total cases":"12","Percentage who completed therapy":"50","Cases category":"1 to 52 TB cases"},{"State/cities":"Montana","Completed cases":"1","Total cases":"3","Percentage who completed therapy":"33","Cases category":"1 to 52 TB cases"},{"State/cities":"Oregon","Completed cases":"54","Total cases":"57","Percentage who completed therapy":"95","Cases category":"53 to 130 TB cases"},{"State/cities":"South Carolina","Completed cases":"50","Total cases":"53","Percentage who completed therapy":"94","Cases category":"53 to 130 TB cases"},{"State/cities":"Indiana","Completed cases":"67","Total cases":"71","Percentage who completed therapy":"94","Cases category":"53 to 130 TB cases"},{"State/cities":"Philadelphia, PA","Completed cases":"42","Total cases":"45","Percentage who completed therapy":"93","Cases category":"53 to 130 TB cases"},{"State/cities":"San Francisco, CA","Completed cases":"44","Total cases":"48","Percentage who completed therapy":"92","Cases category":"53 to 130 TB cases"},{"State/cities":"New York [excluding New York City]","Completed cases":"315","Total cases":"346","Percentage who completed therapy":"91","Cases category":"53 to 130 TB cases"},{"State/cities":"San Diego, CA","Completed cases":"159","Total cases":"175","Percentage who completed therapy":"91","Cases category":"53 to 130 TB cases"},{"State/cities":"Pennsylvania [excluding Philadelphia]","Completed cases":"70","Total cases":"78","Percentage who completed therapy":"90","Cases category":"53 to 130 TB cases"},{"State/cities":"Minnesota","Completed cases":"85","Total cases":"93","Percentage who completed therapy":"91","Cases category":"53 to 130 TB cases"},{"State/cities":"North Dakota","Completed cases":"9","Total cases":"10","Percentage who completed therapy":"90","Cases category":"53 to 130 TB cases"},{"State/cities":"North Carolina","Completed cases":"116","Total cases":"129","Percentage who completed therapy":"90","Cases category":"53 to 130 TB cases"},{"State/cities":"Michigan","Completed cases":"75","Total cases":"83","Percentage who completed therapy":"90","Cases category":"53 to 130 TB cases"},{"State/cities":"Hawaii","Completed cases":"66","Total cases":"73","Percentage who completed therapy":"90","Cases category":"53 to 130 TB cases"},{"State/cities":"Arizona","Completed cases":"101","Total cases":"112","Percentage who completed therapy":"90","Cases category":"53 to 130 TB cases"},{"State/cities":"Kentucky","Completed cases":"47","Total cases":"53","Percentage who completed therapy":"89","Cases category":"53 to 130 TB cases"},{"State/cities":"Massachusetts","Completed cases":"102","Total cases":"116","Percentage who completed therapy":"88","Cases category":"53 to 130 TB cases"},{"State/cities":"Ohio","Completed cases":"99","Total cases":"115","Percentage who completed therapy":"86","Cases category":"53 to 130 TB cases"},{"State/cities":"Houston, TX","Completed cases":"97","Total cases":"113","Percentage who completed therapy":"86","Cases category":"53 to 130 TB cases"},{"State/cities":"Alabama","Completed cases":"49","Total cases":"58","Percentage who completed therapy":"84","Cases category":"53 to 130 TB cases"},{"State/cities":"Maryland [excluding Baltimore]","Completed cases":"93","Total cases":"112","Percentage who completed therapy":"83","Cases category":"53 to 130 TB cases"},{"State/cities":"Texas [excluding Houston]","Completed cases":"502","Total cases":"604","Percentage who completed therapy":"83","Cases category":"53 to 130 TB cases"},{"State/cities":"Tennessee","Completed cases":"78","Total cases":"95","Percentage who completed therapy":"82","Cases category":"53 to 130 TB cases"},{"State/cities":"Missouri","Completed cases":"47","Total cases":"59","Percentage who completed therapy":"80","Cases category":"53 to 130 TB cases"},{"State/cities":"Louisiana","Completed cases":"66","Total cases":"84","Percentage who completed therapy":"79","Cases category":"53 to 130 TB cases"},{"State/cities":"Nebraska","Completed cases":"11","Total cases":"26","Percentage who completed therapy":"42","Cases category":"53 to 130 TB cases"},{"State/cities":"Illinois [excluding Chicago]","Completed cases":"101","Total cases":"103","Percentage who completed therapy":"98","Cases category":"131 or more TB cases"},{"State/cities":"Washington","Completed cases":"128","Total cases":"134","Percentage who completed therapy":"96","Cases category":"131 or more TB cases"},{"State/cities":"Florida","Completed cases":"324","Total cases":"339","Percentage who completed therapy":"96","Cases category":"131 or more TB cases"},{"State/cities":"New York, NY ","Completed cases":"126","Total cases":"136","Percentage who completed therapy":"93","Cases category":"131 or more TB cases"},{"State/cities":"Los Angeles, CA","Completed cases":"321","Total cases":"345","Percentage who completed therapy":"93","Cases category":"131 or more TB cases"},{"State/cities":"Virginia","Completed cases":"133","Total cases":"144","Percentage who completed therapy":"92","Cases category":"131 or more TB cases"},{"State/cities":"New Jersey","Completed cases":"177","Total cases":"192","Percentage who completed therapy":"92","Cases category":"131 or more TB cases"},{"State/cities":"Georgia","Completed cases":"158","Total cases":"173","Percentage who completed therapy":"91","Cases category":"131 or more TB cases"},{"State/cities":"California [excluding LA, SD, SF]","Completed cases":"703","Total cases":"790","Percentage who completed therapy":"89","Cases category":"131 or more TB cases"}],"dataFileName":"COT-12Months-v2.csv","dataFileSourceType":"file","annotations":[{"text":"National average 84.7%","snapToNearestPoint":false,"fontSize":16,"bezier":10,"show":{"desktop":true,"tablet":true,"mobile":true},"connectorType":"line","colors":{"label":"black","connector":"black","marker":"black"},"selected":true,"anchor":{"vertical":false,"horizontal":false},"marker":"circle","edit":{"subject":true,"label":true},"seriesKey":"","x":76.75190558150972,"y":216.92999267578125,"xKey":"1/15/2016","yKey":"","dx":20,"dy":-20,"opacity":"87","savedDimensions":[null,null],"connectionType":"select"},{"text":"2025 target: 95%","snapToNearestPoint":false,"fontSize":16,"bezier":10,"show":{"desktop":true,"tablet":true,"mobile":true},"connectorType":"line","colors":{"label":"black","connector":"black","marker":"black"},"selected":true,"anchor":{"vertical":false,"horizontal":false},"marker":"circle","edit":{"subject":true,"label":true},"seriesKey":"","x":89.14433243176788,"y":105.92999267578125,"xKey":"1/15/2016","yKey":"","dx":20,"dy":-20,"opacity":"100","savedDimensions":[null,null],"connectionType":"select"}],"debugSvg":false,"chartMessage":{"noData":"No Data Available"},"title":"","showTitle":true,"showDownloadMediaButton":false,"theme":"theme-blue","animate":false,"lineDatapointStyle":"hover","lineDatapointColor":"Same as Line","barHasBorder":"true","isLollipopChart":false,"lollipopShape":"circle","lollipopColorStyle":"two-tone","barStyle":"","roundingStyle":"standard","tipRounding":"top","isResponsiveTicks":false,"general":{"annotationDropdownText":"Annotations","showMissingDataLabel":true,"showSuppressedSymbol":true,"showZeroValueData":true,"hideNullValue":true,"showDownloadButton":false,"showAnnotationDropdown":false},"padding":{"left":5,"right":5},"preliminaryData":[],"yAxis":{"hideAxis":false,"displayNumbersOnBar":false,"hideLabel":false,"hideTicks":false,"size":50,"gridLines":false,"enablePadding":false,"min":"","max":"","labelColor":"#333","tickLabelColor":"#333","tickColor":"#333","rightHideAxis":false,"rightAxisSize":0,"rightLabel":"","rightLabelOffsetSize":0,"rightAxisLabelColor":"#333","rightAxisTickLabelColor":"#333","rightAxisTickColor":"#333","numTicks":"","axisPadding":0,"scalePadding":"30","tickRotation":0,"anchors":[],"shoMissingDataLabel":true,"showMissingDataLine":true,"categories":[],"labelPlacement":"On Date/Category Axis","type":"linear","labelOffset":"-1"},"boxplot":{"plots":[],"borders":"true","plotOutlierValues":false,"plotNonOutlierValues":true,"labels":{"q1":"Lower Quartile","q2":"q2","q3":"Upper Quartile","q4":"q4","minimum":"Minimum","maximum":"Maximum","mean":"Mean","median":"Median","sd":"Standard Deviation","iqr":"Interquartile Range","count":"Count","outliers":"Outliers","values":"Values","lowerBounds":"Lower Bounds","upperBounds":"Upper Bounds"}},"topAxis":{"hasLine":false},"isLegendValue":false,"barHeight":25,"barSpace":"5","heights":{"vertical":300,"horizontal":1740},"table":{"label":"Data Table","expanded":true,"limitHeight":false,"height":"","caption":"","showDownloadUrl":false,"showDataTableLink":true,"showDownloadLinkBelow":true,"indexLabel":"","download":true,"showVertical":false,"dateDisplayFormat":"","showMissingDataLabel":true,"showSuppressedSymbol":true,"show":false},"color":"pinkpurple","columns":{"Percentage who completed therapy":{"label":"Percentage who completed therapy","dataTable":true,"tooltips":true,"prefix":"","suffix":"%","forestPlot":false,"startingPoint":"0","forestPlotAlignRight":false,"roundToPlace":0,"commas":false,"showInViz":false,"forestPlotStartingPoint":0,"name":"Percentage who completed therapy","series":""},"Completed cases":{"label":"Completed cases","dataTable":true,"tooltips":true,"prefix":"","suffix":"","forestPlot":false,"startingPoint":"0","forestPlotAlignRight":false,"roundToPlace":0,"commas":false,"showInViz":false,"forestPlotStartingPoint":0,"name":"Completed cases"},"Total cases":{"label":"Total cases","dataTable":true,"tooltips":true,"prefix":"","suffix":"","forestPlot":false,"startingPoint":"0","forestPlotAlignRight":false,"roundToPlace":0,"commas":false,"showInViz":false,"forestPlotStartingPoint":0,"name":"Total cases"}},"legend":{"hide":false,"behavior":"isolate","axisAlign":true,"singleRow":true,"colorCode":"Cases category","reverseLabelOrder":false,"description":"","dynamicLegend":false,"dynamicLegendDefaultText":"Show All","dynamicLegendItemLimit":5,"dynamicLegendItemLimitMessage":"Dynamic Legend Item Limit Hit.","dynamicLegendChartMessage":"Select Options from the Legend","label":"Completion of therapy by U.S. states and cities","lineMode":false,"verticalSorted":false,"highlightOnHover":false,"hideSuppressedLabels":false,"hideSuppressionLink":false,"seriesHighlight":[],"style":"boxes","subStyle":"linear blocks","groupBy":"Cases category","shape":"circle","tickRotation":"","hideBorder":{"side":false,"topBottom":true},"position":"bottom","unified":true},"brush":{"height":45,"active":false},"exclusions":{"active":false,"keys":[]},"palette":"sequential-blue","isPaletteReversed":false,"twoColor":{"palette":"monochrome-1","isPaletteReversed":false},"labels":false,"dataFormat":{"commas":false,"prefix":"","suffix":"","abbreviated":false,"bottomSuffix":"","bottomPrefix":"","bottomAbbreviated":false},"filters":[],"confidenceKeys":{},"visual":{"border":true,"accent":true,"background":true,"verticalHoverLine":false,"horizontalHoverLine":false,"lineDatapointSymbol":"none","maximumShapeAmount":7},"useLogScale":false,"filterBehavior":"Filter Change","highlightedBarValues":[],"series":[{"dataKey":"Percentage who completed therapy","type":"Bar","axis":"Left","tooltip":false,"name":"Percentage who completed therapy"}],"tooltips":{"opacity":90,"singleSeries":false,"dateDisplayFormat":""},"forestPlot":{"startAt":0,"colors":{"line":"","shape":""},"lineOfNoEffect":{"show":true},"type":"","pooledResult":{"diamondHeight":5,"column":""},"estimateField":"","estimateRadius":"","shape":"square","rowHeight":20,"description":{"show":true,"text":"description","location":0},"result":{"show":true,"text":"result","location":100},"radius":{"min":2,"max":10,"scalingColumn":""},"regression":{"lower":0,"upper":0,"estimateField":0},"leftWidthOffset":0,"rightWidthOffset":0,"showZeroLine":false,"leftLabel":"","rightLabel":""},"area":{"isStacked":false},"sankey":{"title":{"defaultColor":"black"},"iterations":1,"rxValue":0.9,"overallSize":{"width":900,"height":700},"margin":{"margin_y":25,"margin_x":0},"nodeSize":{"nodeWidth":26,"nodeHeight":40},"nodePadding":55,"nodeFontColor":"black","nodeColor":{"default":"#ff8500","inactive":"#808080"},"linkColor":{"default":"#ffc900","inactive":"#D3D3D3"},"opacity":{"nodeOpacityDefault":1,"nodeOpacityInactive":0.1,"LinkOpacityDefault":1,"LinkOpacityInactive":0.1},"storyNodeFontColor":"#006778","storyNodeText":[],"nodeValueStyle":{"textBefore":"(","textAfter":")"},"data":[]},"version":"4.25.1","migrations":{"addColorMigration":true},"dynamicMarginTop":0}
|