@cdc/chart 4.26.7 → 4.26.10

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.
Files changed (255) hide show
  1. package/CONFIG.md +502 -368
  2. package/dist/cdcchart-CYc-Kayd.es.js +22488 -0
  3. package/dist/cdcchart-DCKn8NmI.es.js +20695 -0
  4. package/dist/cdcchart-Dyui9nk_.es.js +45828 -0
  5. package/dist/cdcchart.js +4 -97406
  6. package/examples/__data__/vega-remote-data.json +6 -0
  7. package/examples/dendrogram.json +18 -0
  8. package/examples/feature/bar/bar-chart-race-annual-change.json +68 -0
  9. package/examples/feature/heatmap/average-age-categorical.json +2 -2
  10. package/examples/feature/heatmap/calendar-heatmap.json +2 -2
  11. package/examples/feature/heatmap/cell-values-bottom-axis.json +2 -2
  12. package/examples/feature/heatmap/sparse-aggregation.json +2 -2
  13. package/examples/feature/line/line-chart-race.json +50 -0
  14. package/examples/feature/sankey/sankey-example-data.json +40 -1441
  15. package/examples/feature/sankey/sankey_chart_data.csv +9 -20
  16. package/examples/network.json +31 -0
  17. package/examples/private/box-plot.json +573 -0
  18. package/examples/private/custom-color-issue.json +625 -0
  19. package/examples/private/custom-colors.json +522 -0
  20. package/examples/private/cutoff.json +10750 -0
  21. package/examples/private/overlay-legend.json +485 -0
  22. package/examples/private/pie-test.json +469 -0
  23. package/examples/vega-remote.json +22 -0
  24. package/package.json +11 -5
  25. package/src/CdcChartComponent.tsx +405 -208
  26. package/src/_stories/Chart.BarRace.stories.tsx +443 -0
  27. package/src/_stories/Chart.BoxPlotNumericSort.stories.tsx +189 -0
  28. package/src/_stories/Chart.BoxPlotStatsParity.stories.tsx +207 -0
  29. package/src/_stories/Chart.ColorDistribution.stories.tsx +299 -0
  30. package/src/_stories/Chart.DataCutoff.stories.tsx +147 -0
  31. package/src/_stories/Chart.DataTableDownloadFilename.stories.tsx +60 -0
  32. package/src/_stories/Chart.Dendrogram.stories.tsx +373 -0
  33. package/src/_stories/Chart.Forecast.CILegend.stories.tsx +236 -0
  34. package/src/_stories/Chart.HeatMap.stories.tsx +170 -4
  35. package/src/_stories/Chart.Legend.AxisAlign.stories.tsx +119 -0
  36. package/src/_stories/Chart.LineRace.stories.tsx +149 -0
  37. package/src/_stories/Chart.Network.stories.tsx +432 -0
  38. package/src/_stories/Chart.PaletteConversion.Editor.stories.tsx +208 -0
  39. package/src/_stories/Chart.Patterns.smoke.stories.tsx +31 -0
  40. package/src/_stories/Chart.PercentageValue.stories.tsx +311 -0
  41. package/src/_stories/Chart.PieLabels.stories.tsx +4 -2
  42. package/src/_stories/Chart.RankByValueMutation.stories.tsx +206 -0
  43. package/src/_stories/Chart.RequiredFields.stories.tsx +681 -0
  44. package/src/_stories/Chart.Sankey.stories.tsx +417 -0
  45. package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +47 -0
  46. package/src/_stories/Chart.SmallMultiplesNumericTileOrder.stories.tsx +137 -0
  47. package/src/_stories/Chart.TooltipSeriesLabels.stories.tsx +43 -0
  48. package/src/_stories/Chart.VegaRemoteData.stories.tsx +31 -0
  49. package/src/_stories/ChartAnnotation.Editor.stories.tsx +78 -0
  50. package/src/_stories/ChartAxisTitles.smoke.stories.tsx +48 -0
  51. package/src/_stories/ChartBar.Editor.stories.tsx +499 -57
  52. package/src/_stories/ChartBrush.Editor.stories.tsx +46 -67
  53. package/src/_stories/ChartBrush.Regression.stories.tsx +135 -0
  54. package/src/_stories/ChartEditor.Editor.stories.tsx +33 -3
  55. package/src/_stories/ChartLine.EffectCompatibility.stories.tsx +120 -0
  56. package/src/_stories/_mock/annotation_event-line_mock.json +2 -2
  57. package/src/_stories/_mock/editor-test-configs.json +20 -10
  58. package/src/_stories/_mock/editor-test-datasets.json +38 -42
  59. package/src/_stories/_mock/heatmap-average-age-categorical.json +2 -2
  60. package/src/_stories/_mock/heatmap.json +2 -2
  61. package/src/_stories/_mock/legend-axis-align-stacked-bar.json +125 -0
  62. package/src/_stories/_mock/sankey_mock.json +23 -27
  63. package/src/components/Annotations/components/AnnotationDraggable.styles.css +52 -0
  64. package/src/components/Annotations/components/AnnotationDraggable.tsx +639 -139
  65. package/src/components/Annotations/components/AnnotationDropdown.styles.css +44 -4
  66. package/src/components/Annotations/components/AnnotationDropdown.tsx +10 -32
  67. package/src/components/Annotations/helpers/resolveAnnotationLayout.ts +212 -0
  68. package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +612 -19
  69. package/src/components/Annotations/tests/AnnotationDropdown.test.tsx +50 -0
  70. package/src/components/Annotations/tests/resolveAnnotationLayout.test.ts +203 -0
  71. package/src/components/Axis/BottomAxis.tsx +1 -1
  72. package/src/components/Axis/Categorical.Axis.tsx +3 -3
  73. package/src/components/Axis/RightAxis.tsx +21 -13
  74. package/src/components/BarChart/components/BarChart.Horizontal.tsx +38 -6
  75. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +12 -3
  76. package/src/components/BarChart/components/BarChart.StackedVertical.test.ts +28 -0
  77. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +29 -25
  78. package/src/components/BarChart/components/BarChart.Vertical.tsx +37 -26
  79. package/src/components/BarChart/components/PortionPatternOverlay.tsx +61 -0
  80. package/src/components/BarChart/components/context.tsx +6 -0
  81. package/src/components/BarChart/helpers/getPatternUrl.ts +2 -5
  82. package/src/components/BarChart/helpers/index.ts +8 -0
  83. package/src/components/BarChart/helpers/portionPattern.ts +243 -0
  84. package/src/components/BarChart/helpers/tests/addMinimumBarHeights.test.ts +42 -0
  85. package/src/components/BarChart/helpers/tests/getPatternUrl.test.ts +13 -0
  86. package/src/components/BarChart/helpers/tests/portionPattern.test.ts +280 -0
  87. package/src/components/BarChart/helpers/tests/useBarChart.test.tsx +104 -0
  88. package/src/components/BarChart/helpers/useBarChart.ts +60 -59
  89. package/src/components/BarChartRace/BarChartRace.test.tsx +199 -0
  90. package/src/components/BarChartRace/BarChartRace.tsx +230 -0
  91. package/src/components/BarChartRace/BarChartRaceFallback.test.tsx +61 -0
  92. package/src/components/BarChartRace/BarChartRaceFallback.tsx +48 -0
  93. package/src/components/BarChartRace/bar-chart-race.css +160 -0
  94. package/src/components/BarChartRace/helpers.test.ts +114 -0
  95. package/src/components/BarChartRace/helpers.ts +185 -0
  96. package/src/components/BarChartRace/index.ts +3 -0
  97. package/src/components/BoxPlot/helpers/index.ts +11 -82
  98. package/src/components/Brush/BrushSelector.tsx +9 -23
  99. package/src/components/Brush/MiniChartPreview.tsx +33 -1
  100. package/src/components/Dendrogram/components/Dendrogram.tsx +374 -0
  101. package/src/components/Dendrogram/dendrogram.css +113 -0
  102. package/src/components/Dendrogram/helpers/layoutDendrogram.test.ts +95 -0
  103. package/src/components/Dendrogram/helpers/layoutDendrogram.ts +56 -0
  104. package/src/components/Dendrogram/helpers/prepareDendrogramData.test.ts +135 -0
  105. package/src/components/Dendrogram/helpers/prepareDendrogramData.ts +166 -0
  106. package/src/components/Dendrogram/helpers/resolveDendrogramLabels.test.ts +196 -0
  107. package/src/components/Dendrogram/helpers/resolveDendrogramLabels.ts +418 -0
  108. package/src/components/Dendrogram/index.tsx +1 -0
  109. package/src/components/Dendrogram/types/index.ts +66 -0
  110. package/src/components/EditorPanel/EditorPanel.tsx +1005 -760
  111. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +50 -5
  112. package/src/components/EditorPanel/components/Panels/Panel.Dendrogram.css +10 -0
  113. package/src/components/EditorPanel/components/Panels/Panel.Dendrogram.tsx +211 -0
  114. package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +19 -8
  115. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +88 -54
  116. package/src/components/EditorPanel/components/Panels/Panel.Network.css +9 -0
  117. package/src/components/EditorPanel/components/Panels/Panel.Network.tsx +202 -0
  118. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +233 -33
  119. package/src/components/EditorPanel/components/Panels/Panel.Radar.tsx +6 -1
  120. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +89 -105
  121. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +2 -2
  122. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +1 -1
  123. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +8 -66
  124. package/src/components/EditorPanel/components/Panels/RacingControls.test.tsx +131 -0
  125. package/src/components/EditorPanel/components/Panels/RacingControls.tsx +185 -0
  126. package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +2 -2
  127. package/src/components/EditorPanel/components/Panels/index.tsx +4 -0
  128. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +20 -7
  129. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +25 -2
  130. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +2 -1
  131. package/src/components/EditorPanel/useEditorPermissions.test.tsx +62 -0
  132. package/src/components/EditorPanel/useEditorPermissions.ts +70 -24
  133. package/src/components/Forecasting/Forecasting.tsx +15 -6
  134. package/src/components/HeatMap/components/HeatMap.tsx +511 -178
  135. package/src/components/HeatMap/heatmap.constants.ts +7 -3
  136. package/src/components/HeatMap/heatmap.css +101 -2
  137. package/src/components/HeatMap/helpers/layout.ts +80 -0
  138. package/src/components/HeatMap/tests/HeatMap.test.tsx +339 -16
  139. package/src/components/HeatMap/tests/helpers.test.ts +79 -0
  140. package/src/components/Legend/Legend.Component.tsx +110 -90
  141. package/src/components/Legend/LegendGroup/LegendGroup.styles.css +7 -0
  142. package/src/components/Legend/LegendGroup/LegendGroup.tsx +47 -34
  143. package/src/components/Legend/helpers/createFormatLabels.test.ts +226 -0
  144. package/src/components/Legend/helpers/createFormatLabels.tsx +45 -51
  145. package/src/components/LineChart/components/LineChart.Circle.tsx +3 -3
  146. package/src/components/LineChart/helpers.test.ts +126 -38
  147. package/src/components/LineChart/helpers.ts +9 -4
  148. package/src/components/LineChart/index.tsx +69 -24
  149. package/src/components/LineChart/tests/LineChart.test.tsx +630 -0
  150. package/src/components/LineChartRace/LineChartRace.test.tsx +275 -0
  151. package/src/components/LineChartRace/LineChartRace.tsx +134 -0
  152. package/src/components/LineChartRace/LineChartRaceFallback.tsx +28 -0
  153. package/src/components/LineChartRace/helpers.test.ts +88 -0
  154. package/src/components/LineChartRace/helpers.ts +157 -0
  155. package/src/components/LineChartRace/index.ts +3 -0
  156. package/src/components/LineChartRace/line-chart-race.css +16 -0
  157. package/src/components/LinearChart/ValueAxisAnchors.tsx +58 -0
  158. package/src/components/LinearChart/VisualizationRenderer.tsx +18 -23
  159. package/src/components/LinearChart/tests/LinearChart.test.tsx +412 -13
  160. package/src/components/LinearChart/tests/VisualizationRenderer.test.tsx +141 -0
  161. package/src/components/LinearChart/tests/mockConfigContext.ts +2 -1
  162. package/src/components/LinearChart.tsx +81 -51
  163. package/src/components/Network/components/Network.tsx +372 -0
  164. package/src/components/Network/helpers/layoutNetwork.test.ts +68 -0
  165. package/src/components/Network/helpers/layoutNetwork.ts +87 -0
  166. package/src/components/Network/helpers/prepareNetworkData.test.ts +116 -0
  167. package/src/components/Network/helpers/prepareNetworkData.ts +101 -0
  168. package/src/components/Network/helpers/resolveNetworkLabels.test.ts +112 -0
  169. package/src/components/Network/helpers/resolveNetworkLabels.ts +206 -0
  170. package/src/components/Network/index.tsx +3 -0
  171. package/src/components/Network/network.css +107 -0
  172. package/src/components/Network/types/index.ts +56 -0
  173. package/src/components/PairedBarChart.jsx +5 -10
  174. package/src/components/PairedBarChart.test.tsx +71 -0
  175. package/src/components/PieChart/PieChart.tsx +9 -8
  176. package/src/components/RacingChartRenderer.tsx +44 -0
  177. package/src/components/Regions/components/Regions.test.tsx +179 -0
  178. package/src/components/Regions/components/Regions.tsx +104 -69
  179. package/src/components/Regions/index.tsx +2 -3
  180. package/src/components/Sankey/components/Sankey.tsx +264 -437
  181. package/src/components/Sankey/helpers/getSankeyTooltip.ts +12 -0
  182. package/src/components/Sankey/helpers/prepareSankeyData.test.ts +71 -0
  183. package/src/components/Sankey/helpers/prepareSankeyData.ts +90 -0
  184. package/src/components/Sankey/sankey.scss +57 -116
  185. package/src/components/Sankey/types/index.ts +41 -4
  186. package/src/components/ScatterPlot/ScatterPlot.jsx +28 -4
  187. package/src/components/ScatterPlot/ScatterPlot.test.tsx +60 -0
  188. package/src/components/SmallMultiples/SmallMultiples.tsx +12 -12
  189. package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +7 -5
  190. package/src/components/raceTiming.ts +18 -0
  191. package/src/data/initial-state.js +77 -31
  192. package/src/helpers/applyChartTypeContract.ts +71 -0
  193. package/src/helpers/axisLabelFontSize.ts +2 -2
  194. package/src/helpers/boxPlotStats.ts +60 -0
  195. package/src/helpers/bumpChartTooltip.ts +2 -1
  196. package/src/helpers/calculateHorizontalBarCategoryLabelWidth.test.ts +37 -0
  197. package/src/helpers/calculateHorizontalBarCategoryLabelWidth.ts +3 -2
  198. package/src/helpers/calculateRightYAxisWidth.ts +60 -0
  199. package/src/helpers/colorAssignmentHelpers.ts +2 -2
  200. package/src/helpers/createNewChartConfig.ts +56 -0
  201. package/src/helpers/dataDrivenYAxisCategories.ts +18 -0
  202. package/src/helpers/forecastLegend.ts +88 -0
  203. package/src/helpers/getBoxPlotConfig.ts +18 -37
  204. package/src/helpers/getChartTypeDefaultPalette.ts +29 -0
  205. package/src/helpers/getColorCodeCategoryColorMap.ts +26 -0
  206. package/src/helpers/getColorScale.ts +31 -22
  207. package/src/helpers/getDynamicYAxisCategories.ts +69 -0
  208. package/src/helpers/getMinMax.ts +9 -7
  209. package/src/helpers/getNewRuntime.ts +5 -2
  210. package/src/helpers/getStackedSeriesMax.ts +51 -0
  211. package/src/helpers/getV21ChartDistributionColors.ts +57 -0
  212. package/src/helpers/handleRankByValue.ts +15 -15
  213. package/src/helpers/seriesColumnSettings.ts +10 -0
  214. package/src/helpers/sizeHelpers.ts +4 -3
  215. package/src/helpers/smallMultiplesHelpers.ts +10 -13
  216. package/src/helpers/tests/applyChartTypeContract.test.ts +37 -0
  217. package/src/helpers/tests/boxPlotStats.test.ts +31 -0
  218. package/src/helpers/tests/bumpChartTooltip.test.ts +29 -0
  219. package/src/helpers/tests/calculateRightYAxisWidth.test.ts +105 -0
  220. package/src/helpers/tests/countNumOfTicks.test.ts +11 -0
  221. package/src/helpers/tests/createNewChartConfig.test.ts +182 -0
  222. package/src/helpers/tests/getBoxPlotConfig.test.ts +70 -0
  223. package/src/helpers/tests/getColorCodeCategoryColorMap.test.ts +113 -0
  224. package/src/helpers/tests/getColorScale.test.ts +226 -1
  225. package/src/helpers/tests/getDynamicYAxisCategories.test.ts +61 -0
  226. package/src/helpers/tests/getMinMax.test.ts +41 -0
  227. package/src/helpers/tests/getStackedSeriesMax.test.ts +26 -0
  228. package/src/helpers/tests/handleRankByValue.test.ts +55 -37
  229. package/src/helpers/tests/seriesColumnSettings.test.ts +23 -0
  230. package/src/helpers/tests/smallMultiplesHelpers.test.ts +37 -1
  231. package/src/helpers/tests/tooltipHelpers.test.ts +80 -0
  232. package/src/helpers/tooltipHelpers.ts +16 -0
  233. package/src/hooks/tests/useTooltip.test.tsx +353 -1
  234. package/src/hooks/usePrefersReducedMotion.ts +22 -0
  235. package/src/hooks/useReduceData.ts +4 -36
  236. package/src/hooks/useScales.ts +15 -0
  237. package/src/hooks/useTooltip.tsx +95 -64
  238. package/src/scss/main.scss +74 -2
  239. package/src/store/chart.reducer.ts +4 -3
  240. package/src/test/CdcChart.dataTable.test.tsx +490 -16
  241. package/src/test/CdcChart.dendrogram.test.tsx +277 -0
  242. package/src/test/CdcChart.finalization.test.tsx +143 -0
  243. package/src/test/CdcChart.network.test.tsx +271 -0
  244. package/src/types/ChartConfig.ts +91 -54
  245. package/src/types/ChartContext.ts +5 -0
  246. package/src/types/Horizon.ts +1 -1
  247. package/LICENSE +0 -201
  248. package/dist/cdcchart-BWVIUcAF.es.js +0 -4802
  249. package/src/_stories/Chart.Sankey.smoke.stories.tsx +0 -62
  250. package/src/components/Sankey/components/ColumnList.tsx +0 -19
  251. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +0 -34
  252. package/src/components/Sankey/useSankeyAlert.tsx +0 -60
  253. package/src/data/legacy-defaults.ts +0 -18
  254. package/src/helpers/ensureSpecialChartAxisTypes.ts +0 -11
  255. package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +0 -30
@@ -13,6 +13,7 @@ import {
13
13
  // @cdc/core
14
14
  import { EditorPanel as BaseEditorPanel } from '@cdc/core/components/EditorPanel/EditorPanel'
15
15
  import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
16
+ import ModernStylesAction from '@cdc/core/components/EditorPanel/ModernStylesAction'
16
17
  import Icon from '@cdc/core/components/ui/Icon'
17
18
  import ColumnsEditor from '@cdc/core/components/EditorPanel/ColumnsEditor'
18
19
  import CustomSortOrder from '@cdc/core/components/EditorPanel/CustomSortOrder'
@@ -30,7 +31,7 @@ import { useDataColumns } from '@cdc/core/hooks/useDataColumns'
30
31
 
31
32
  // chart components
32
33
  import Panels from './components/Panels'
33
- import PaletteConversionModal from '@cdc/core/components/PaletteConversionModal'
34
+ import PaletteConversionModal, { V21_PALETTE_CONVERSION_MESSAGE } from '@cdc/core/components/PaletteConversionModal'
34
35
 
35
36
  // cdc additional
36
37
  import { useEditorPermissions } from './useEditorPermissions'
@@ -64,7 +65,9 @@ import { getSeriesOwnedColumnNames } from '../../helpers/seriesColumnSettings'
64
65
  import { getOrderedCategoryValues } from '../../helpers/categoryOrder'
65
66
  import {
66
67
  HEATMAP_CONFIG_DEFAULTS,
68
+ MAX_HEATMAP_COLUMN_WIDTH,
67
69
  MAX_HEATMAP_COLOR_BUCKETS,
70
+ MIN_HEATMAP_COLUMN_WIDTH,
68
71
  MIN_HEATMAP_COLOR_BUCKETS
69
72
  } from '../HeatMap/heatmap.constants'
70
73
 
@@ -129,6 +132,7 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
129
132
  let preliminaryData = config.preliminaryData ? [...config.preliminaryData] : []
130
133
  const defaultValues = {
131
134
  type: defaultType,
135
+ lineEffectScope: 'outgoing',
132
136
  seriesKeys: [],
133
137
  label: 'Suppressed',
134
138
  column: '',
@@ -157,7 +161,10 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
157
161
  preliminaryData = [...config.preliminaryData]
158
162
  }
159
163
 
160
- preliminaryData[i][fieldName] = value
164
+ preliminaryData[i] = { ...preliminaryData[i], [fieldName]: value }
165
+ if (fieldName === 'lineEffectScope' && value === '') {
166
+ delete preliminaryData[i].lineEffectScope
167
+ }
161
168
  if (fieldName === 'symbol') {
162
169
  preliminaryData[i]['iconCode'] = symbolCodes[value]
163
170
  }
@@ -200,6 +207,7 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
200
207
  value,
201
208
  hideBarSymbol,
202
209
  hideLineStyle,
210
+ lineEffectScope,
203
211
  weight
204
212
  },
205
213
  i
@@ -509,6 +517,34 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
509
517
  updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
510
518
  />
511
519
  )}
520
+ {style && !style.includes('Circles') && (
521
+ <Select
522
+ display={config.visualizationType === 'Line' || hasComboLineSeries}
523
+ id={`line-effect-scope-${i}`}
524
+ value={lineEffectScope === 'outgoing' ? 'outgoing' : ''}
525
+ fieldName='lineEffectScope'
526
+ label='Apply style to'
527
+ aria-label='Apply style to'
528
+ tooltip={
529
+ <Tooltip style={{ textTransform: 'none' }}>
530
+ <Tooltip.Target>
531
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
532
+ </Tooltip.Target>
533
+ <Tooltip.Content>
534
+ <p>
535
+ A matching data point styles either the segment after it or both segments before
536
+ and after it.
537
+ </p>
538
+ </Tooltip.Content>
539
+ </Tooltip>
540
+ }
541
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
542
+ options={[
543
+ { label: 'Segment after point', value: 'outgoing' },
544
+ { label: 'Both adjacent segments', value: '' }
545
+ ]}
546
+ />
547
+ )}
512
548
  {style && !style.includes('Circles') && (
513
549
  <TextField
514
550
  type='number'
@@ -559,20 +595,27 @@ interface CategoricalAxisProps {
559
595
 
560
596
  type AxisAnchorEditorProps = {
561
597
  axisKey: 'xAxis' | 'yAxis'
598
+ anchorField?: 'anchors' | 'rightAnchors'
562
599
  config: ChartConfig
563
600
  lineOptions: { value: string; label?: string }[]
564
601
  updateConfig: Function
565
602
  }
566
603
 
567
- const AxisAnchorEditor: React.FC<AxisAnchorEditorProps> = ({ axisKey, config, lineOptions, updateConfig }) => {
568
- const anchors = config[axisKey]?.anchors || []
604
+ const AxisAnchorEditor: React.FC<AxisAnchorEditorProps> = ({
605
+ axisKey,
606
+ anchorField = 'anchors',
607
+ config,
608
+ lineOptions,
609
+ updateConfig
610
+ }) => {
611
+ const anchors = config[axisKey]?.[anchorField] || []
569
612
 
570
613
  const updateAnchors = (nextAnchors: Anchor[]) => {
571
614
  updateConfig({
572
615
  ...config,
573
616
  [axisKey]: {
574
617
  ...config[axisKey],
575
- anchors: nextAnchors
618
+ [anchorField]: nextAnchors
576
619
  }
577
620
  })
578
621
  }
@@ -608,13 +651,17 @@ const AxisAnchorEditor: React.FC<AxisAnchorEditorProps> = ({ axisKey, config, li
608
651
  <GroupedList
609
652
  items={anchors}
610
653
  label='Anchors'
611
- droppableId={`${axisKey}-anchors-order`}
654
+ droppableId={`${axisKey}-${anchorField}-order`}
612
655
  onDragEnd={({ source, destination }) => {
613
656
  if (!destination || source.index === destination.index) return
614
657
  reorderAnchors(source.index, destination.index)
615
658
  }}
616
659
  renderItem={(anchor, index) => (
617
- <Draggable key={`${axisKey}-anchor-${index}`} draggableId={`${axisKey}-anchor-${index}`} index={index}>
660
+ <Draggable
661
+ key={`${axisKey}-${anchorField}-anchor-${index}`}
662
+ draggableId={`${axisKey}-${anchorField}-anchor-${index}`}
663
+ index={index}
664
+ >
618
665
  {(provided, snapshot) => (
619
666
  <div
620
667
  ref={provided.innerRef}
@@ -710,6 +757,38 @@ const AxisAnchorEditor: React.FC<AxisAnchorEditorProps> = ({ axisKey, config, li
710
757
  }
711
758
 
712
759
  const CategoricalAxis: React.FC<CategoricalAxisProps> = ({ config, updateConfig, display }) => {
760
+ const dataDrivenCategories = config.yAxis.dataDrivenCategories
761
+ const isDataDriven =
762
+ config.yAxis.categoryMode === 'data-driven' || (config.yAxis.categoryMode === undefined && !!dataDrivenCategories)
763
+
764
+ const updateDynamicCategories = (updates: Record<string, any>) => {
765
+ updateConfig({
766
+ ...config,
767
+ yAxis: {
768
+ ...config.yAxis,
769
+ dataDrivenCategories: { ...dataDrivenCategories, ...updates }
770
+ }
771
+ })
772
+ }
773
+
774
+ const updateDynamicCategory = (index: number, fieldName: string, value: string) => {
775
+ const categories = [...(dataDrivenCategories?.categories || [])]
776
+ categories[index] = { ...categories[index], [fieldName]: value }
777
+ updateDynamicCategories({ categories })
778
+ }
779
+
780
+ const addDynamicCategory = () => {
781
+ const categories = [...(dataDrivenCategories?.categories || [])]
782
+ categories.push({ label: `Category ${categories.length + 1}`, upperBoundKey: '', color: '#c9c9c9' })
783
+ updateDynamicCategories({ categories })
784
+ }
785
+
786
+ const removeDynamicCategory = (index: number) => {
787
+ const categories = [...(dataDrivenCategories?.categories || [])]
788
+ categories.splice(index, 1)
789
+ updateDynamicCategories({ categories })
790
+ }
791
+
713
792
  const maxHeight = config?.yAxis?.maxValue
714
793
 
715
794
  const totalEnteredHeight =
@@ -763,6 +842,44 @@ const CategoricalAxis: React.FC<CategoricalAxisProps> = ({ config, updateConfig,
763
842
  return <></>
764
843
  }
765
844
 
845
+ if (isDataDriven && dataDrivenCategories) {
846
+ return (
847
+ <div className='edit-block'>
848
+ <p>Data-Driven Category Axis</p>
849
+ <p>Thresholds are read from the current filtered data. The last category defines the axis maximum.</p>
850
+ {dataDrivenCategories.categories?.map((category, index) => (
851
+ <div key={category.upperBoundKey || category.label || 'unnamed-category'} className='edit-block'>
852
+ <p>Data-Driven Category {index + 1}</p>
853
+ <Button type='button' className='btn btn-danger' onClick={() => removeDynamicCategory(index)}>
854
+ Remove
855
+ </Button>
856
+ <TextField
857
+ value={category.label}
858
+ fieldName='label'
859
+ label='Category Label'
860
+ updateField={(_, __, fieldName, value) => updateDynamicCategory(index, fieldName, value)}
861
+ />
862
+ <TextField
863
+ value={category.upperBoundKey}
864
+ fieldName='upperBoundKey'
865
+ label='Upper-Bound Column'
866
+ updateField={(_, __, fieldName, value) => updateDynamicCategory(index, fieldName, value)}
867
+ />
868
+ <TextField
869
+ value={category.color}
870
+ fieldName='color'
871
+ label='Color'
872
+ updateField={(_, __, fieldName, value) => updateDynamicCategory(index, fieldName, value)}
873
+ />
874
+ </div>
875
+ ))}
876
+ <Button type='button' variant='editor-primary' onClick={addDynamicCategory}>
877
+ Add Data-Driven Category
878
+ </Button>
879
+ </div>
880
+ )
881
+ }
882
+
766
883
  return (
767
884
  <>
768
885
  {config.yAxis.type === 'categorical' &&
@@ -859,7 +976,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
859
976
  handleShowAll,
860
977
  dimensions
861
978
  } = useContext<ChartContext>(ConfigContext)
862
-
979
+ const isBarRace = config.visualizationType === 'Bar' && config.visualizationSubType === 'racing'
863
980
  const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
864
981
  const properties = {
865
982
  data,
@@ -921,7 +1038,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
921
1038
  ...series,
922
1039
  type:
923
1040
  config.visualizationType === 'Combo' ? 'Bar' : config.visualizationType ? config.visualizationType : 'Bar',
924
- axis: 'Left'
1041
+ axis: 'Left',
1042
+ tooltip: series.tooltip ?? true
925
1043
  }
926
1044
  })
927
1045
  }
@@ -985,13 +1103,19 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
985
1103
  if (isDateScale(updatedConfig.xAxis) && !updatedConfig.xAxis.padding) {
986
1104
  updatedConfig.xAxis.padding = 0
987
1105
  }
1106
+ if (isDateScale(updatedConfig.xAxis) && updatedConfig.xAxis.dataKey && !updatedConfig.table.defaultSort?.column) {
1107
+ updatedConfig.table.defaultSort = {
1108
+ column: updatedConfig.xAxis.dataKey,
1109
+ sortDirection: 'desc'
1110
+ }
1111
+ }
988
1112
  // Default Radar charts to a taller height
989
1113
  if (updatedConfig.visualizationType === 'Radar' && updatedConfig.heights?.vertical <= 400) {
990
1114
  updatedConfig.heights.vertical = 400
991
1115
  }
992
1116
  // DEV-8008 - Remove Bar styling when Line is converted to Bar
993
1117
  if (updatedConfig.visualizationType === 'Line') {
994
- updatedConfig.visualizationSubType = 'regular'
1118
+ if (updatedConfig.visualizationSubType !== 'racing') updatedConfig.visualizationSubType = 'regular'
995
1119
  updatedConfig.barStyle = 'flat'
996
1120
  updatedConfig.isLollipopChart = false
997
1121
  }
@@ -1143,7 +1267,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1143
1267
  }
1144
1268
 
1145
1269
  const addNewExclusion = exclusionKey => {
1146
- let newExclusion = [...config.exclusions.keys]
1270
+ let newExclusion = [...(config.exclusions?.keys ?? [])]
1147
1271
  newExclusion.push(exclusionKey)
1148
1272
 
1149
1273
  let payload = { ...config.exclusions, keys: newExclusion }
@@ -1152,7 +1276,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1152
1276
 
1153
1277
  const removeExclusion = excludeValue => {
1154
1278
  let exclusionsIndex = -1
1155
- let exclusions = [...config.exclusions.keys]
1279
+ let exclusions = [...(config.exclusions?.keys ?? [])]
1156
1280
 
1157
1281
  for (let i = 0; i < exclusions.length; i++) {
1158
1282
  if (exclusions[i] === excludeValue) {
@@ -1167,10 +1291,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1167
1291
  let newExclusions = { ...config.exclusions, keys: exclusions }
1168
1292
  let newExclusionsPayload = { ...config, exclusions: newExclusions }
1169
1293
 
1170
- if (exclusions.length === 0) {
1171
- delete newExclusionsPayload.exclusions.keys
1172
- }
1173
-
1174
1294
  updateConfig(newExclusionsPayload)
1175
1295
  }
1176
1296
  }
@@ -1355,34 +1475,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1355
1475
  handleUpdateHighlightedBorderWidth
1356
1476
  } = useHighlightedBars(config, updateConfig)
1357
1477
 
1358
- // when the orientation changes, swap x and y axis anchors
1359
- useEffect(() => {
1360
- const prevXAnchors = config.xAxis.anchors.length > 0 ? config.xAxis.anchors : []
1361
- const prevYAnchors = config.yAxis.anchors.length > 0 ? config.yAxis.anchors : []
1362
-
1363
- updateConfig({
1364
- ...config,
1365
- xAxis: {
1366
- ...config.xAxis,
1367
- anchors: prevYAnchors
1368
- },
1369
- yAxis: {
1370
- ...config.yAxis,
1371
- anchors: prevXAnchors
1372
- }
1373
- })
1374
- }, [config.orientation])
1375
-
1376
- // Set paired bars to be horizontal, even though that option doesn't display
1377
- useEffect(() => {
1378
- if (config.visualizationType === 'Paired Bar') {
1379
- updateConfig({
1380
- ...config,
1381
- orientation: 'horizontal'
1382
- })
1383
- }
1384
- }, []) // eslint-disable-line
1385
-
1386
1478
  useEffect(() => {
1387
1479
  if (config.orientation === 'horizontal') {
1388
1480
  updateConfig({
@@ -1392,15 +1484,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1392
1484
  }
1393
1485
  }, [config.isLollipopChart, config.lollipopShape]) // eslint-disable-line
1394
1486
 
1395
- /// temporary force orientation untill we support Vartical deviaton bar
1396
- useEffect(() => {
1397
- if (config.visualizationType === 'Deviation Bar') {
1398
- updateConfig({ ...config, orientation: 'horizontal' })
1399
- }
1400
- }, [config.visualizationType])
1401
-
1402
1487
  const ExclusionsList = useCallback(() => {
1403
- const exclusions = [...config.exclusions.keys]
1488
+ const exclusions = [...(config.exclusions?.keys ?? [])]
1404
1489
  return (
1405
1490
  <ul className='series-list'>
1406
1491
  {exclusions.map((exclusion, index) => {
@@ -1463,6 +1548,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1463
1548
 
1464
1549
  // Check if it's a v1 palette configuration
1465
1550
  const isV1PaletteConfig = isV1Palette(config)
1551
+ const shouldUpgradePalette = USE_V2_MIGRATION && (isV1PaletteConfig || config.general?.palette?.version === '2.0')
1466
1552
 
1467
1553
  const executeSelection = () => {
1468
1554
  const _newConfig = cloneConfig(config)
@@ -1478,14 +1564,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1478
1564
  // V2 migration logic
1479
1565
  const migratedName = palette ? migratePaletteWithMap(palette, paletteMigrationMap, false) : undefined
1480
1566
  _newConfig.general.palette.name = migratedName
1481
- if (isV1PaletteConfig) {
1482
- _newConfig.general.palette.version = '2.0'
1567
+ if (shouldUpgradePalette) {
1568
+ _newConfig.general.palette.version = '2.1'
1483
1569
  }
1484
1570
  }
1485
1571
  updateConfig(_newConfig)
1486
1572
  }
1487
1573
 
1488
- if (isV1PaletteConfig) {
1574
+ if (shouldUpgradePalette) {
1489
1575
  setPendingPaletteSelection({ palette, action: executeSelection, type: 'general' })
1490
1576
  setShowConversionModal(true)
1491
1577
  } else {
@@ -1539,7 +1625,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1539
1625
  if (!_newConfig.general.palette) {
1540
1626
  _newConfig.general.palette = {}
1541
1627
  }
1542
- _newConfig.general.palette.version = '2.0'
1628
+ _newConfig.general.palette.version = '2.1'
1543
1629
 
1544
1630
  // Create backup for rollback functionality (consistent with standard format)
1545
1631
  if (!_newConfig.general.palette.backups) {
@@ -1595,7 +1681,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1595
1681
  if (!_newConfig.general.palette) {
1596
1682
  _newConfig.general.palette = {}
1597
1683
  }
1598
- _newConfig.general.palette.version = '2.0'
1684
+ _newConfig.general.palette.version = '2.1'
1599
1685
 
1600
1686
  // Forecast-specific migration map for v1 → v2 palette names (all lowercase-hyphen format)
1601
1687
  const forecastPaletteMigrationMap: Record<string, string> = {
@@ -1720,15 +1806,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1720
1806
  _newConfig.general.palette.name = palette
1721
1807
  }
1722
1808
 
1723
- // Set version to V1
1809
+ // Keep the current palette version
1724
1810
  if (!_newConfig.general) {
1725
1811
  _newConfig.general = {}
1726
1812
  }
1727
1813
  if (!_newConfig.general.palette) {
1728
1814
  _newConfig.general.palette = {}
1729
1815
  }
1730
- _newConfig.general.palette.version = '1.0'
1731
-
1816
+ _newConfig.general.palette.version = config.general?.palette?.version || '1.0'
1732
1817
  updateConfig(_newConfig)
1733
1818
  }
1734
1819
  setShowConversionModal(false)
@@ -2048,6 +2133,25 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2048
2133
  label='Show Cell Values'
2049
2134
  updateField={updateFieldDeprecated}
2050
2135
  />
2136
+ <CheckBox
2137
+ value={Boolean(config.heatmap?.horizontalScroll ?? HEATMAP_CONFIG_DEFAULTS.horizontalScroll)}
2138
+ section='heatmap'
2139
+ fieldName='horizontalScroll'
2140
+ label='Enable Horizontal Scrolling'
2141
+ updateField={updateFieldDeprecated}
2142
+ />
2143
+ {Boolean(config.heatmap?.horizontalScroll ?? HEATMAP_CONFIG_DEFAULTS.horizontalScroll) && (
2144
+ <TextField
2145
+ value={config.heatmap?.minColumnWidth ?? HEATMAP_CONFIG_DEFAULTS.minColumnWidth}
2146
+ type='number'
2147
+ min={MIN_HEATMAP_COLUMN_WIDTH}
2148
+ max={MAX_HEATMAP_COLUMN_WIDTH}
2149
+ section='heatmap'
2150
+ fieldName='minColumnWidth'
2151
+ label='Minimum Column Width'
2152
+ updateField={updateFieldDeprecated}
2153
+ />
2154
+ )}
2051
2155
  <TextField
2052
2156
  value={config.heatmap?.cellPadding ?? HEATMAP_CONFIG_DEFAULTS.cellPadding}
2053
2157
  type='number'
@@ -2056,6 +2160,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2056
2160
  fieldName='cellPadding'
2057
2161
  label='Cell Padding'
2058
2162
  updateField={updateFieldDeprecated}
2163
+ tooltip={
2164
+ <Tooltip style={{ textTransform: 'none' }}>
2165
+ <Tooltip.Target>
2166
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2167
+ </Tooltip.Target>
2168
+ <Tooltip.Content>To adjust cell height, use Chart Height in the General panel.</Tooltip.Content>
2169
+ </Tooltip>
2170
+ }
2059
2171
  />
2060
2172
  <TextField
2061
2173
  value={config.heatmap?.rowLabelGap ?? HEATMAP_CONFIG_DEFAULTS.rowLabelGap}
@@ -2121,16 +2233,21 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2121
2233
  <Panels.General name='General' />
2122
2234
  <Panels.ForestPlot name='Forest Plot Settings' />
2123
2235
  <Panels.Sankey name='Sankey' />
2236
+ <Panels.Network name='Network' />
2237
+ <Panels.Dendrogram name='Dendrogram' />
2124
2238
  {config.visualizationType !== 'Pie' &&
2125
2239
  config.visualizationType !== 'Forest Plot' &&
2126
- config.visualizationType !== 'Sankey' && (
2240
+ !['Sankey', 'Network', 'Dendrogram'].includes(config.visualizationType) && (
2127
2241
  <AccordionItem>
2128
2242
  <AccordionItemHeading>
2129
- <AccordionItemButton>
2243
+ <AccordionItemButton data-required-field-section='data-series'>
2130
2244
  Data Series{' '}
2131
2245
  {(!config.series ||
2132
2246
  config.series.length === 0 ||
2133
- (config.visualizationType === 'Paired Bar' && config.series.length < 2)) &&
2247
+ (config.isLollipopChart && config.series.length !== 1) ||
2248
+ (config.visualizationType === 'Radar' && config.series.length < 3) ||
2249
+ (config.visualizationType === 'Deviation Bar' && config.series.length !== 1) ||
2250
+ (config.visualizationType === 'Paired Bar' && config.series.length !== 2)) &&
2134
2251
  !config.dynamicSeries &&
2135
2252
  config.visualizationType !== 'HeatMap' && (
2136
2253
  <WarningImage width='25' className='warning-icon' />
@@ -2180,25 +2297,31 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2180
2297
  {(!config.series || config.series.length === 0) &&
2181
2298
  !config.dynamicSeries &&
2182
2299
  config.visualizationType !== 'Paired Bar' &&
2183
- config.visualizationType !== 'HeatMap' && (
2184
- <p className='warning'>At least one series is required</p>
2185
- )}
2300
+ config.visualizationType !== 'Deviation Bar' &&
2301
+ config.visualizationType !== 'HeatMap' &&
2302
+ !config.isLollipopChart && <p className='warning'>At least one series is required</p>}
2303
+ {config.isLollipopChart && config.series?.length !== 1 && (
2304
+ <p className='warning'>Select exactly one data series for a lollipop chart.</p>
2305
+ )}
2306
+ {config.visualizationType === 'Deviation Bar' && config.series?.length !== 1 && (
2307
+ <p className='warning'>Select exactly one data series for a deviation bar chart.</p>
2308
+ )}
2186
2309
  {(!config.series || config.series.length === 0) &&
2187
2310
  !config.dynamicSeries &&
2188
2311
  config.visualizationType === 'HeatMap' && (
2189
2312
  <p className='warning'>At least one series is required</p>
2190
2313
  )}
2191
- {(!config.series || config.series.length === 0 || config.series.length < 2) &&
2192
- config.visualizationType === 'Paired Bar' && (
2193
- <p className='warning'>
2194
- Select two data series for paired bar chart (e.g., Male and Female).
2195
- </p>
2196
- )}
2314
+ {config.series?.length !== 2 && config.visualizationType === 'Paired Bar' && (
2315
+ <p className='warning'>
2316
+ Select two data series for paired bar chart (e.g., Male and Female).
2317
+ </p>
2318
+ )}
2197
2319
  <>
2198
2320
  <Select
2199
2321
  fieldName='visualizationType'
2200
2322
  label='Add Data Series'
2201
2323
  aria-label='Add Data Series'
2324
+ data-required-field-control='data-series'
2202
2325
  initial='Select'
2203
2326
  onChange={e => {
2204
2327
  if (e.target.value !== '' && e.target.value !== 'Select') {
@@ -2305,7 +2428,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2305
2428
  {visSupportsLeftValueAxis() && (
2306
2429
  <AccordionItem>
2307
2430
  <AccordionItemHeading>
2308
- <AccordionItemButton>
2431
+ <AccordionItemButton
2432
+ data-required-field-section={config.visualizationType === 'Pie' ? 'pie-data-column' : undefined}
2433
+ >
2309
2434
  {config.visualizationType === 'Pie'
2310
2435
  ? 'Data Format'
2311
2436
  : config.orientation === 'vertical'
@@ -2324,6 +2449,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2324
2449
  section='yAxis'
2325
2450
  fieldName='dataKey'
2326
2451
  label='Data Column'
2452
+ data-required-field-control='pie-data-column'
2327
2453
  initial='Select'
2328
2454
  required={true}
2329
2455
  updateField={updateFieldDeprecated}
@@ -2440,29 +2566,57 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2440
2566
  />
2441
2567
  </>
2442
2568
  )}
2443
- {config.visualizationType !== 'Pie' && config.visualizationType !== 'HeatMap' && (
2569
+ {!isBarRace && config.visualizationType !== 'Pie' && config.visualizationType !== 'HeatMap' && (
2444
2570
  <>
2445
2571
  <Select
2446
2572
  label='Axis Type'
2447
- value={config.yAxis.type}
2573
+ value={
2574
+ config.yAxis.type === 'categorical' &&
2575
+ (config.yAxis.categoryMode === 'data-driven' ||
2576
+ (config.yAxis.categoryMode === undefined && config.yAxis.dataDrivenCategories))
2577
+ ? 'categorical-data-driven'
2578
+ : config.yAxis.type
2579
+ }
2448
2580
  options={[
2449
2581
  { value: 'linear', label: 'Numeric (Linear Scale)' },
2450
2582
  ...(config.visualizationSubType !== 'stacked'
2451
2583
  ? [{ value: 'logarithmic', label: 'Numeric (Logarithmic Scale)' }]
2452
2584
  : []),
2453
2585
  ...(config.orientation !== 'horizontal'
2454
- ? [{ value: 'categorical', label: 'Categorical' }]
2586
+ ? [
2587
+ { value: 'categorical', label: 'Categorical' },
2588
+ { value: 'categorical-data-driven', label: 'Categorical (Data-Driven)' }
2589
+ ]
2455
2590
  : [])
2456
2591
  ]}
2457
2592
  section='yAxis'
2458
2593
  fieldName='type'
2459
2594
  updateField={(_section, _subsection, _fieldName, value) => {
2595
+ const isDataDriven = value === 'categorical-data-driven'
2596
+ const isCategorical = value === 'categorical' || isDataDriven
2597
+ const nextYAxis = {
2598
+ ...config.yAxis,
2599
+ type: isCategorical ? 'categorical' : value
2600
+ }
2601
+
2602
+ if (isDataDriven) {
2603
+ nextYAxis.categoryMode = 'data-driven'
2604
+ nextYAxis.dataDrivenCategories = config.yAxis.dataDrivenCategories || {
2605
+ categories: [],
2606
+ manualCategories: config.yAxis.categories || []
2607
+ }
2608
+ nextYAxis.categories = []
2609
+ } else if (isCategorical) {
2610
+ nextYAxis.categoryMode = 'manual'
2611
+ nextYAxis.categories =
2612
+ config.yAxis.dataDrivenCategories?.manualCategories || config.yAxis.categories || []
2613
+ } else {
2614
+ delete nextYAxis.categoryMode
2615
+ }
2616
+
2460
2617
  updateConfig({
2461
2618
  ...config,
2462
- yAxis: {
2463
- ...config.yAxis,
2464
- type: value
2465
- }
2619
+ yAxis: nextYAxis
2466
2620
  })
2467
2621
  }}
2468
2622
  tooltip={
@@ -2471,8 +2625,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2471
2625
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2472
2626
  </Tooltip.Target>
2473
2627
  <Tooltip.Content>
2474
- Select 'Numeric (Linear Scale)' for uniform scaling, 'Numeric (Logarithmic Scale)' for
2475
- exponential data, or 'Categorical' for discrete categories.
2628
+ Select a numeric scale, 'Categorical' for manually sized categories, or 'Categorical
2629
+ (Data-Driven)' to size categories from threshold columns in the current data.
2476
2630
  </Tooltip.Content>
2477
2631
  </Tooltip>
2478
2632
  }
@@ -2491,20 +2645,28 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2491
2645
  fieldName='label'
2492
2646
  label='Label'
2493
2647
  updateField={updateFieldDeprecated}
2494
- maxLength={config.yAxis.titlePlacement === 'side' ? 35 : undefined}
2648
+ maxLength={
2649
+ config.orientation === 'horizontal' || config.yAxis.titlePlacement === 'side'
2650
+ ? 35
2651
+ : undefined
2652
+ }
2495
2653
  tooltip={
2496
2654
  <Tooltip style={{ textTransform: 'none' }}>
2497
2655
  <Tooltip.Target>
2498
2656
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2499
2657
  </Tooltip.Target>
2500
2658
  <Tooltip.Content>
2501
- <p>35 character limit when Label Placement is Side</p>
2659
+ <p>
2660
+ {config.orientation === 'horizontal'
2661
+ ? '35 character limit'
2662
+ : '35 character limit when Label Placement is Side'}
2663
+ </p>
2502
2664
  </Tooltip.Content>
2503
2665
  </Tooltip>
2504
2666
  }
2505
2667
  />
2506
2668
  <Select
2507
- display={!visHasCategoricalAxis()}
2669
+ display={config.orientation !== 'horizontal' && !visHasCategoricalAxis()}
2508
2670
  value={config.yAxis.titlePlacement}
2509
2671
  section='yAxis'
2510
2672
  fieldName='titlePlacement'
@@ -2667,7 +2829,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2667
2829
  }
2668
2830
  />
2669
2831
  <CheckBox
2670
- display={!visHasCategoricalAxis()}
2832
+ display={!isBarRace && !visHasCategoricalAxis()}
2671
2833
  value={config.dataFormat.abbreviated}
2672
2834
  section='dataFormat'
2673
2835
  fieldName='abbreviated'
@@ -2795,255 +2957,82 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2795
2957
  }
2796
2958
  />
2797
2959
  </div>
2798
- {config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
2799
- <>
2800
- {visSupportsValueAxisLine() && (
2801
- <CheckBox
2802
- value={config.xAxis.hideAxis}
2803
- section='xAxis'
2804
- fieldName='hideAxis'
2805
- label='Hide Axis'
2806
- updateField={updateFieldDeprecated}
2807
- />
2808
- )}
2809
- {visSupportsValueAxisLabels() && (
2810
- <CheckBox
2811
- value={config.xAxis.hideLabel}
2812
- section='xAxis'
2813
- fieldName='hideLabel'
2814
- label='Hide Tick Labels'
2815
- updateField={updateFieldDeprecated}
2816
- />
2817
- )}
2818
- {visSupportsValueAxisTicks() && (
2819
- <CheckBox
2820
- value={config.xAxis.hideTicks}
2821
- section='xAxis'
2822
- fieldName='hideTicks'
2823
- label='Hide Ticks'
2824
- updateField={updateFieldDeprecated}
2825
- />
2826
- )}
2827
- <div className='axis-domain-group'>
2828
- <span className='axis-domain-group__title'>Value Axis Domain</span>
2829
- <div className='axis-domain-group__row'>
2830
- {visSupportsValueAxisMax() && (
2831
- <div className='axis-domain-group__field'>
2832
- <TextField
2833
- value={config.xAxis.max}
2834
- section='xAxis'
2835
- fieldName='max'
2836
- label='axis max value'
2837
- type='number'
2838
- placeholder='Auto'
2839
- className='axis-domain-number'
2840
- updateField={updateFieldDeprecated}
2841
- />
2842
- <span className='axis-domain-warning'>{warningMsg.maxMsg}</span>
2843
- </div>
2844
- )}
2845
- {visSupportsValueAxisMin() && (
2846
- <div className='axis-domain-group__field'>
2847
- <TextField
2848
- value={config.xAxis.min}
2849
- section='xAxis'
2850
- fieldName='min'
2851
- type='number'
2852
- label='axis min value'
2853
- placeholder='Auto'
2854
- className='axis-domain-number'
2855
- updateField={updateFieldDeprecated}
2856
- />
2857
- <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
2858
- </div>
2859
- )}
2860
- </div>
2861
- {config.visualizationType === 'Deviation Bar' && (
2862
- <TextField
2863
- value={config.xAxis.target}
2960
+ {!isBarRace &&
2961
+ (config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
2962
+ <>
2963
+ {visSupportsValueAxisLine() && (
2964
+ <CheckBox
2965
+ value={config.xAxis.hideAxis}
2864
2966
  section='xAxis'
2865
- fieldName='target'
2866
- type='number'
2867
- label='Deviation point'
2868
- placeholder='Auto'
2869
- className='axis-domain-number'
2870
- updateField={updateFieldDeprecated}
2871
- />
2872
- )}
2873
- <TextField
2874
- value={config.yAxis.smallestLeftAxisMax}
2875
- section='yAxis'
2876
- fieldName='smallestLeftAxisMax'
2877
- type='number'
2878
- label='Smallest axis maximum'
2879
- placeholder='Auto'
2880
- className='axis-domain-number'
2881
- tooltip={
2882
- <Tooltip style={{ textTransform: 'none' }}>
2883
- <Tooltip.Target>
2884
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2885
- </Tooltip.Target>
2886
- <Tooltip.Content>
2887
- <p>
2888
- Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
2889
- 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
2890
- </p>
2891
- </Tooltip.Content>
2892
- </Tooltip>
2893
- }
2894
- updateField={updateFieldDeprecated}
2895
- />
2896
- {visSupportsAutoMaxStrategy() && (
2897
- <Select
2898
- value={config.yAxis.autoMaxStrategy || 'default'}
2899
- section='yAxis'
2900
- fieldName='autoMaxStrategy'
2901
- label='Automatic max strategy'
2902
- updateField={updateFieldDeprecated}
2903
- options={[
2904
- { value: 'default', label: 'Default' },
2905
- { value: 'clean-top-tick', label: 'Clean top tick' }
2906
- ]}
2907
- tooltip={
2908
- <Tooltip style={{ textTransform: 'none' }}>
2909
- <Tooltip.Target>
2910
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2911
- </Tooltip.Target>
2912
- <Tooltip.Content>
2913
- {config.visualizationType === 'Combo' ? (
2914
- <p>
2915
- Clean top tick rounds automatic left and right axis maximums up to cleaner
2916
- tick steps before axis padding is applied.
2917
- </p>
2918
- ) : (
2919
- <p>
2920
- Clean top tick rounds the automatic value axis maximum up to a cleaner tick
2921
- step before axis padding is applied.
2922
- </p>
2923
- )}
2924
- </Tooltip.Content>
2925
- </Tooltip>
2926
- }
2927
- />
2928
- )}
2929
- {visSupportsFilterDomainBehavior() && (
2930
- <Select
2931
- value={config.yAxis.filterDomainBehavior || 'dynamic'}
2932
- section='yAxis'
2933
- fieldName='filterDomainBehavior'
2934
- label='Filter Domain Behavior'
2967
+ fieldName='hideAxis'
2968
+ label='Hide Axis'
2935
2969
  updateField={updateFieldDeprecated}
2936
- options={[
2937
- { value: 'dynamic', label: 'Dynamic' },
2938
- { value: 'stable', label: 'Stable' }
2939
- ]}
2940
- tooltip={
2941
- <Tooltip style={{ textTransform: 'none' }}>
2942
- <Tooltip.Target>
2943
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2944
- </Tooltip.Target>
2945
- <Tooltip.Content>
2946
- {config.visualizationType === 'Combo' ? (
2947
- <p>
2948
- Dynamic rescales the value axes to the currently filtered data. Stable keeps
2949
- the left and right axes based on the full eligible dataset while still
2950
- rendering filtered rows.
2951
- </p>
2952
- ) : (
2953
- <p>
2954
- Dynamic rescales the value axis to the currently filtered data. Stable keeps
2955
- the value axis based on the full eligible dataset while still rendering
2956
- filtered rows.
2957
- </p>
2958
- )}
2959
- </Tooltip.Content>
2960
- </Tooltip>
2961
- }
2962
2970
  />
2963
2971
  )}
2964
- </div>
2965
- {config.visualizationType === 'Deviation Bar' && (
2966
- <>
2967
- <TextField
2968
- value={config.xAxis.targetLabel || 'Target'}
2972
+ {visSupportsValueAxisLabels() && (
2973
+ <CheckBox
2974
+ value={config.xAxis.hideLabel}
2969
2975
  section='xAxis'
2970
- fieldName='targetLabel'
2971
- type='text'
2972
- label='Deviation point Label'
2976
+ fieldName='hideLabel'
2977
+ label='Hide Tick Labels'
2973
2978
  updateField={updateFieldDeprecated}
2974
2979
  />
2980
+ )}
2981
+ {visSupportsValueAxisTicks() && (
2975
2982
  <CheckBox
2976
- value={config.xAxis.showTargetLabel}
2983
+ value={config.xAxis.hideTicks}
2977
2984
  section='xAxis'
2978
- fieldName='showTargetLabel'
2979
- label='Show Deviation point label'
2985
+ fieldName='hideTicks'
2986
+ label='Hide Ticks'
2980
2987
  updateField={updateFieldDeprecated}
2981
2988
  />
2982
- </>
2983
- )}
2984
- </>
2985
- ) : (
2986
- config.visualizationType !== 'Pie' &&
2987
- config.visualizationType !== 'HeatMap' && (
2988
- <>
2989
- <CheckBox
2990
- display={!visHasCategoricalAxis()}
2991
- value={config.yAxis.hideAxis}
2992
- section='yAxis'
2993
- fieldName='hideAxis'
2994
- label='Hide Axis'
2995
- updateField={updateFieldDeprecated}
2996
- />
2997
- <CheckBox
2998
- display={!visHasCategoricalAxis()}
2999
- value={config.yAxis.hideLabel}
3000
- section='yAxis'
3001
- fieldName='hideLabel'
3002
- label='Hide Tick Labels'
3003
- updateField={updateFieldDeprecated}
3004
- />
3005
- <CheckBox
3006
- display={!visHasCategoricalAxis()}
3007
- value={config.yAxis.hideTicks}
3008
- section='yAxis'
3009
- fieldName='hideTicks'
3010
- label='Hide Ticks'
3011
- updateField={updateFieldDeprecated}
3012
- />
3013
-
2989
+ )}
3014
2990
  <div className='axis-domain-group'>
3015
2991
  <span className='axis-domain-group__title'>Value Axis Domain</span>
3016
2992
  <div className='axis-domain-group__row'>
3017
- <div className='axis-domain-group__field'>
3018
- <TextField
3019
- value={config.yAxis.max}
3020
- section='yAxis'
3021
- fieldName='max'
3022
- type='number'
3023
- label='axis max value'
3024
- placeholder='Auto'
3025
- className='axis-domain-number'
3026
- updateField={updateFieldDeprecated}
3027
- />
3028
- <span className='axis-domain-warning'>{warningMsg.maxMsg}</span>
3029
- </div>
3030
- {config.visualizationType !== 'Area Chart' &&
3031
- config.visualizationSubType !== 'stacked' && (
3032
- <div className='axis-domain-group__field'>
3033
- <TextField
3034
- value={config.yAxis.min}
3035
- section='yAxis'
3036
- fieldName='min'
3037
- type='number'
3038
- label='axis min value'
3039
- placeholder='Auto'
3040
- className='axis-domain-number'
3041
- updateField={updateFieldDeprecated}
3042
- />
3043
- <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
3044
- </div>
3045
- )}
2993
+ {visSupportsValueAxisMax() && (
2994
+ <div className='axis-domain-group__field'>
2995
+ <TextField
2996
+ value={config.xAxis.max}
2997
+ section='xAxis'
2998
+ fieldName='max'
2999
+ label='axis max value'
3000
+ type='number'
3001
+ placeholder='Auto'
3002
+ className='axis-domain-number'
3003
+ updateField={updateFieldDeprecated}
3004
+ />
3005
+ <span className='axis-domain-warning'>{warningMsg.maxMsg}</span>
3006
+ </div>
3007
+ )}
3008
+ {visSupportsValueAxisMin() && (
3009
+ <div className='axis-domain-group__field'>
3010
+ <TextField
3011
+ value={config.xAxis.min}
3012
+ section='xAxis'
3013
+ fieldName='min'
3014
+ type='number'
3015
+ label='axis min value'
3016
+ placeholder='Auto'
3017
+ className='axis-domain-number'
3018
+ updateField={updateFieldDeprecated}
3019
+ />
3020
+ <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
3021
+ </div>
3022
+ )}
3046
3023
  </div>
3024
+ {config.visualizationType === 'Deviation Bar' && (
3025
+ <TextField
3026
+ value={config.xAxis.target}
3027
+ section='xAxis'
3028
+ fieldName='target'
3029
+ type='number'
3030
+ label='Deviation point'
3031
+ placeholder='Auto'
3032
+ className='axis-domain-number'
3033
+ updateField={updateFieldDeprecated}
3034
+ />
3035
+ )}
3047
3036
  <TextField
3048
3037
  value={config.yAxis.smallestLeftAxisMax}
3049
3038
  section='yAxis'
@@ -3135,30 +3124,203 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3135
3124
  }
3136
3125
  />
3137
3126
  )}
3138
- {visSupportsYPadding() && (
3139
- <CheckBox
3140
- value={config.yAxis.enablePadding}
3141
- section='yAxis'
3142
- fieldName='enablePadding'
3143
- label='Add Padding to Value Axis Scale'
3144
- updateField={updateFieldDeprecated}
3145
- />
3146
- )}
3147
- {config.yAxis.enablePadding && visSupportsYPadding() && (
3127
+ </div>
3128
+ {config.visualizationType === 'Deviation Bar' && (
3129
+ <>
3148
3130
  <TextField
3149
- type='number'
3131
+ value={config.xAxis.targetLabel || 'Target'}
3132
+ section='xAxis'
3133
+ fieldName='targetLabel'
3134
+ type='text'
3135
+ label='Deviation point Label'
3136
+ updateField={updateFieldDeprecated}
3137
+ />
3138
+ <CheckBox
3139
+ value={config.xAxis.showTargetLabel}
3140
+ section='xAxis'
3141
+ fieldName='showTargetLabel'
3142
+ label='Show Deviation point label'
3143
+ updateField={updateFieldDeprecated}
3144
+ />
3145
+ </>
3146
+ )}
3147
+ </>
3148
+ ) : (
3149
+ config.visualizationType !== 'Pie' &&
3150
+ config.visualizationType !== 'HeatMap' && (
3151
+ <>
3152
+ <CheckBox
3153
+ value={config.yAxis.hideAxis}
3154
+ section='yAxis'
3155
+ fieldName='hideAxis'
3156
+ label='Hide Axis'
3157
+ updateField={updateFieldDeprecated}
3158
+ />
3159
+ <CheckBox
3160
+ display={!visHasCategoricalAxis()}
3161
+ value={config.yAxis.hideLabel}
3162
+ section='yAxis'
3163
+ fieldName='hideLabel'
3164
+ label='Hide Tick Labels'
3165
+ updateField={updateFieldDeprecated}
3166
+ />
3167
+ <CheckBox
3168
+ display={!visHasCategoricalAxis()}
3169
+ value={config.yAxis.hideTicks}
3170
+ section='yAxis'
3171
+ fieldName='hideTicks'
3172
+ label='Hide Ticks'
3173
+ updateField={updateFieldDeprecated}
3174
+ />
3175
+
3176
+ <div className='axis-domain-group'>
3177
+ <span className='axis-domain-group__title'>Value Axis Domain</span>
3178
+ <div className='axis-domain-group__row'>
3179
+ <div className='axis-domain-group__field'>
3180
+ <TextField
3181
+ value={config.yAxis.max}
3182
+ section='yAxis'
3183
+ fieldName='max'
3184
+ type='number'
3185
+ label='axis max value'
3186
+ placeholder='Auto'
3187
+ className='axis-domain-number'
3188
+ updateField={updateFieldDeprecated}
3189
+ />
3190
+ <span className='axis-domain-warning'>{warningMsg.maxMsg}</span>
3191
+ </div>
3192
+ {config.visualizationType !== 'Area Chart' &&
3193
+ config.visualizationSubType !== 'stacked' && (
3194
+ <div className='axis-domain-group__field'>
3195
+ <TextField
3196
+ value={config.yAxis.min}
3197
+ section='yAxis'
3198
+ fieldName='min'
3199
+ type='number'
3200
+ label='axis min value'
3201
+ placeholder='Auto'
3202
+ className='axis-domain-number'
3203
+ updateField={updateFieldDeprecated}
3204
+ />
3205
+ <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
3206
+ </div>
3207
+ )}
3208
+ </div>
3209
+ <TextField
3210
+ value={config.yAxis.smallestLeftAxisMax}
3150
3211
  section='yAxis'
3151
- fieldName='scalePadding'
3152
- label='Padding Percentage'
3212
+ fieldName='smallestLeftAxisMax'
3213
+ type='number'
3214
+ label='Smallest axis maximum'
3215
+ placeholder='Auto'
3153
3216
  className='axis-domain-number'
3217
+ tooltip={
3218
+ <Tooltip style={{ textTransform: 'none' }}>
3219
+ <Tooltip.Target>
3220
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3221
+ </Tooltip.Target>
3222
+ <Tooltip.Content>
3223
+ <p>
3224
+ Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
3225
+ 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
3226
+ </p>
3227
+ </Tooltip.Content>
3228
+ </Tooltip>
3229
+ }
3154
3230
  updateField={updateFieldDeprecated}
3155
- value={config.yAxis.scalePadding}
3156
3231
  />
3157
- )}
3158
- </div>
3159
- </>
3160
- )
3161
- )}
3232
+ {visSupportsAutoMaxStrategy() && (
3233
+ <Select
3234
+ value={config.yAxis.autoMaxStrategy || 'default'}
3235
+ section='yAxis'
3236
+ fieldName='autoMaxStrategy'
3237
+ label='Automatic max strategy'
3238
+ updateField={updateFieldDeprecated}
3239
+ options={[
3240
+ { value: 'default', label: 'Default' },
3241
+ { value: 'clean-top-tick', label: 'Clean top tick' }
3242
+ ]}
3243
+ tooltip={
3244
+ <Tooltip style={{ textTransform: 'none' }}>
3245
+ <Tooltip.Target>
3246
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3247
+ </Tooltip.Target>
3248
+ <Tooltip.Content>
3249
+ {config.visualizationType === 'Combo' ? (
3250
+ <p>
3251
+ Clean top tick rounds automatic left and right axis maximums up to cleaner
3252
+ tick steps before axis padding is applied.
3253
+ </p>
3254
+ ) : (
3255
+ <p>
3256
+ Clean top tick rounds the automatic value axis maximum up to a cleaner
3257
+ tick step before axis padding is applied.
3258
+ </p>
3259
+ )}
3260
+ </Tooltip.Content>
3261
+ </Tooltip>
3262
+ }
3263
+ />
3264
+ )}
3265
+ {visSupportsFilterDomainBehavior() && (
3266
+ <Select
3267
+ value={config.yAxis.filterDomainBehavior || 'dynamic'}
3268
+ section='yAxis'
3269
+ fieldName='filterDomainBehavior'
3270
+ label='Filter Domain Behavior'
3271
+ updateField={updateFieldDeprecated}
3272
+ options={[
3273
+ { value: 'dynamic', label: 'Dynamic' },
3274
+ { value: 'stable', label: 'Stable' }
3275
+ ]}
3276
+ tooltip={
3277
+ <Tooltip style={{ textTransform: 'none' }}>
3278
+ <Tooltip.Target>
3279
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3280
+ </Tooltip.Target>
3281
+ <Tooltip.Content>
3282
+ {config.visualizationType === 'Combo' ? (
3283
+ <p>
3284
+ Dynamic rescales the value axes to the currently filtered data. Stable
3285
+ keeps the left and right axes based on the full eligible dataset while
3286
+ still rendering filtered rows.
3287
+ </p>
3288
+ ) : (
3289
+ <p>
3290
+ Dynamic rescales the value axis to the currently filtered data. Stable
3291
+ keeps the value axis based on the full eligible dataset while still
3292
+ rendering filtered rows.
3293
+ </p>
3294
+ )}
3295
+ </Tooltip.Content>
3296
+ </Tooltip>
3297
+ }
3298
+ />
3299
+ )}
3300
+ {visSupportsYPadding() && (
3301
+ <CheckBox
3302
+ value={config.yAxis.enablePadding}
3303
+ section='yAxis'
3304
+ fieldName='enablePadding'
3305
+ label='Add Padding to Value Axis Scale'
3306
+ updateField={updateFieldDeprecated}
3307
+ />
3308
+ )}
3309
+ {config.yAxis.enablePadding && visSupportsYPadding() && (
3310
+ <TextField
3311
+ type='number'
3312
+ section='yAxis'
3313
+ fieldName='scalePadding'
3314
+ label='Padding Percentage'
3315
+ className='axis-domain-number'
3316
+ updateField={updateFieldDeprecated}
3317
+ value={config.yAxis.scalePadding}
3318
+ />
3319
+ )}
3320
+ </div>
3321
+ </>
3322
+ )
3323
+ ))}
3162
3324
  {/* start: anchors */}
3163
3325
  {visHasAnchors() && config.orientation !== 'horizontal' && (
3164
3326
  <AxisAnchorEditor
@@ -3193,18 +3355,29 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3193
3355
  fieldName='rightLabel'
3194
3356
  label='Label'
3195
3357
  updateField={updateFieldDeprecated}
3196
- maxLength={35}
3358
+ maxLength={config.yAxis.rightTitlePlacement === 'side' ? 35 : undefined}
3197
3359
  tooltip={
3198
3360
  <Tooltip style={{ textTransform: 'none' }}>
3199
3361
  <Tooltip.Target>
3200
3362
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3201
3363
  </Tooltip.Target>
3202
3364
  <Tooltip.Content>
3203
- <p>35 character limit</p>
3365
+ <p>35 character limit when Label Placement is Side</p>
3204
3366
  </Tooltip.Content>
3205
3367
  </Tooltip>
3206
3368
  }
3207
3369
  />
3370
+ <Select
3371
+ value={config.yAxis.rightTitlePlacement || 'top'}
3372
+ section='yAxis'
3373
+ fieldName='rightTitlePlacement'
3374
+ label='Label Placement'
3375
+ updateField={updateField}
3376
+ options={[
3377
+ { value: 'side', label: 'Side' },
3378
+ { value: 'top', label: 'Top' }
3379
+ ]}
3380
+ />
3208
3381
  <TextField
3209
3382
  value={config.yAxis.rightNumTicks}
3210
3383
  placeholder='Auto'
@@ -3215,24 +3388,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3215
3388
  className='number-narrow'
3216
3389
  updateField={updateFieldDeprecated}
3217
3390
  />
3218
- <TextField
3219
- value={config.yAxis.rightAxisSize}
3220
- type='number'
3221
- section='yAxis'
3222
- fieldName='rightAxisSize'
3223
- label='Size (Width)'
3224
- className='number-narrow'
3225
- updateField={updateFieldDeprecated}
3226
- />
3227
- <TextField
3228
- value={config.yAxis.rightLabelOffsetSize}
3229
- type='number'
3230
- section='yAxis'
3231
- fieldName='rightLabelOffsetSize'
3232
- label='Label Offset'
3233
- className='number-narrow'
3234
- updateField={updateFieldDeprecated}
3235
- />
3236
3391
 
3237
3392
  <span className='divider-heading'>Number Formatting</span>
3238
3393
  <CheckBox
@@ -3377,13 +3532,24 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3377
3532
  updateField={updateFieldDeprecated}
3378
3533
  />
3379
3534
  </div>
3535
+ <AxisAnchorEditor
3536
+ axisKey='yAxis'
3537
+ anchorField='rightAnchors'
3538
+ config={config}
3539
+ lineOptions={lineOptions}
3540
+ updateConfig={updateConfig}
3541
+ />
3380
3542
  </AccordionItemPanel>
3381
3543
  </AccordionItem>
3382
3544
  )}
3383
3545
  {visSupportsDateCategoryAxis() && (
3384
3546
  <AccordionItem>
3385
3547
  <AccordionItemHeading>
3386
- <AccordionItemButton>
3548
+ <AccordionItemButton
3549
+ data-required-field-section={
3550
+ config.visualizationType === 'Pie' ? 'pie-segments' : 'date-category-axis'
3551
+ }
3552
+ >
3387
3553
  {config.visualizationType === 'Pie' ? 'Segments' : 'Date/Category Axis'}
3388
3554
  {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
3389
3555
  </AccordionItemButton>
@@ -3394,6 +3560,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3394
3560
  {config.visualizationType !== 'Forest Plot' && (
3395
3561
  <>
3396
3562
  <Select
3563
+ display={!isBarRace}
3397
3564
  label='Data Scaling Type'
3398
3565
  tooltip={
3399
3566
  <Tooltip style={{ textTransform: 'none', display: 'inline-block' }}>
@@ -3442,13 +3609,15 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3442
3609
  })
3443
3610
  }}
3444
3611
  />
3445
- <CheckBox
3446
- value={config.xAxis.manual}
3447
- section='xAxis'
3448
- fieldName='manual'
3449
- label='Manual Ticks'
3450
- updateField={updateFieldDeprecated}
3451
- />
3612
+ {config.visualizationType !== 'HeatMap' && !isBarRace && (
3613
+ <CheckBox
3614
+ value={config.xAxis.manual}
3615
+ section='xAxis'
3616
+ fieldName='manual'
3617
+ label='Manual Ticks'
3618
+ updateField={updateFieldDeprecated}
3619
+ />
3620
+ )}
3452
3621
  <CheckBox
3453
3622
  display={config.xAxis.type !== 'categorical'}
3454
3623
  value={config.xAxis.sortByRecentDate}
@@ -3490,6 +3659,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3490
3659
  section='xAxis'
3491
3660
  fieldName='dataKey'
3492
3661
  label='Data Key'
3662
+ data-required-field-control='date-category-axis'
3493
3663
  initial='Select'
3494
3664
  required={true}
3495
3665
  updateField={updateFieldDeprecated}
@@ -3516,6 +3686,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3516
3686
  section='xAxis'
3517
3687
  fieldName='dataKey'
3518
3688
  label='Segment Labels'
3689
+ data-required-field-control='pie-segments'
3519
3690
  initial='Select'
3520
3691
  required={true}
3521
3692
  updateField={updateFieldDeprecated}
@@ -3546,18 +3717,38 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3546
3717
  fieldName='label'
3547
3718
  label='Label'
3548
3719
  updateField={updateFieldDeprecated}
3549
- maxLength={35}
3720
+ maxLength={
3721
+ config.orientation === 'horizontal' && config.yAxis.titlePlacement === 'top'
3722
+ ? undefined
3723
+ : 35
3724
+ }
3550
3725
  tooltip={
3551
3726
  <Tooltip style={{ textTransform: 'none' }}>
3552
3727
  <Tooltip.Target>
3553
3728
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3554
3729
  </Tooltip.Target>
3555
3730
  <Tooltip.Content>
3556
- <p>35 character limit</p>
3731
+ <p>
3732
+ {config.orientation === 'horizontal'
3733
+ ? '35 character limit when Label Placement is Side'
3734
+ : '35 character limit'}
3735
+ </p>
3557
3736
  </Tooltip.Content>
3558
3737
  </Tooltip>
3559
3738
  }
3560
3739
  />
3740
+ <Select
3741
+ display={config.orientation === 'horizontal' && !isBarRace}
3742
+ value={config.yAxis.titlePlacement}
3743
+ section='yAxis'
3744
+ fieldName='titlePlacement'
3745
+ label='Label Placement'
3746
+ updateField={updateField}
3747
+ options={[
3748
+ { value: 'side', label: 'Side' },
3749
+ { value: 'top', label: 'Top' }
3750
+ ]}
3751
+ />
3561
3752
  {config.visualizationType === 'HeatMap' && (
3562
3753
  <Select
3563
3754
  value={config.heatmap?.xAxisPosition ?? HEATMAP_CONFIG_DEFAULTS.xAxisPosition}
@@ -3778,6 +3969,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3778
3969
  updateField={updateFieldDeprecated}
3779
3970
  />
3780
3971
  <CheckBox
3972
+ display={!isBarRace}
3781
3973
  value={config.xAxis.showYearsOnce}
3782
3974
  section='xAxis'
3783
3975
  fieldName='showYearsOnce'
@@ -3800,7 +3992,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3800
3992
  }
3801
3993
  updateField={updateFieldDeprecated}
3802
3994
  />
3803
- {visHasBrushChart() && (
3995
+ {visHasBrushChart() && config.visualizationSubType !== 'racing' && (
3804
3996
  <>
3805
3997
  <CheckBox
3806
3998
  value={config.xAxis.brushActive}
@@ -3828,6 +4020,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3828
4020
  />
3829
4021
  {config.xAxis.brushActive && (
3830
4022
  <>
4023
+ <CheckBox
4024
+ value={config.xAxis.brushHideHatching === true}
4025
+ section='xAxis'
4026
+ fieldName='brushHideHatching'
4027
+ label='Hide diagonal hatching'
4028
+ className='ms-4'
4029
+ updateField={updateFieldDeprecated}
4030
+ />
3831
4031
  <CheckBox
3832
4032
  value={!!config.xAxis.brushDynamicYAxis}
3833
4033
  section='xAxis'
@@ -3900,7 +4100,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3900
4100
  <>
3901
4101
  {config.xAxis.type === 'categorical' && (
3902
4102
  <>
3903
- {config.exclusions.keys.length > 0 && (
4103
+ {(config.exclusions?.keys?.length ?? 0) > 0 && (
3904
4104
  <>
3905
4105
  <fieldset>
3906
4106
  <legend className='edit-label'>Excluded Keys</legend>
@@ -3948,6 +4148,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3948
4148
  )}
3949
4149
 
3950
4150
  {visSupportsDateCategoryNumTicks() &&
4151
+ config.visualizationType !== 'HeatMap' &&
3951
4152
  config.xAxis.type !== 'date-time' &&
3952
4153
  config.xAxis.manual && (
3953
4154
  <>
@@ -4022,7 +4223,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4022
4223
  </>
4023
4224
  )}
4024
4225
  {visSupportsDateCategoryNumTicks() &&
4025
- (config.xAxis.type === 'date-time' || !config.xAxis.manual) && (
4226
+ (config.visualizationType === 'HeatMap' ||
4227
+ config.xAxis.type === 'date-time' ||
4228
+ !config.xAxis.manual) && (
4026
4229
  <>
4027
4230
  <TextField
4028
4231
  value={config.xAxis.numTicks}
@@ -4048,9 +4251,10 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4048
4251
  </Tooltip.Target>
4049
4252
  <Tooltip.Content>
4050
4253
  <p>
4051
- Apporoximate number of ticks. Other factors such as space available and data
4052
- may change the exact number of ticks used. To enforce an exact number of
4053
- ticks, check "Manual Ticks" above.
4254
+ Approximate number of ticks. Other factors such as space available and data
4255
+ may change the exact number of ticks used.
4256
+ {config.visualizationType !== 'HeatMap' &&
4257
+ ' To enforce an exact number of ticks, check "Manual Ticks" above.'}
4054
4258
  </p>
4055
4259
  </Tooltip.Content>
4056
4260
  </Tooltip>
@@ -4336,7 +4540,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4336
4540
  />
4337
4541
  {config.exclusions.active && (
4338
4542
  <>
4339
- {config.exclusions.keys.length > 0 && (
4543
+ {(config.exclusions?.keys?.length ?? 0) > 0 && (
4340
4544
  <>
4341
4545
  <fieldset>
4342
4546
  <legend className='edit-label'>Excluded Keys</legend>
@@ -4411,7 +4615,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4411
4615
  <Panels.Regions name='Regions' />
4412
4616
 
4413
4617
  {/* Columns */}
4414
- {config.visualizationType !== 'Box Plot' && config.visualizationType !== 'Sankey' && (
4618
+ {!['Box Plot', 'Sankey'].includes(config.visualizationType) && (
4415
4619
  <AccordionItem>
4416
4620
  <AccordionItemHeading>
4417
4621
  <AccordionItemButton>Columns</AccordionItemButton>
@@ -4435,421 +4639,456 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4435
4639
  <AccordionItemButton>Legend</AccordionItemButton>
4436
4640
  </AccordionItemHeading>
4437
4641
  <AccordionItemPanel>
4438
- <Select
4439
- value={config.legend?.position}
4440
- section='legend'
4441
- fieldName='position'
4442
- label='Position'
4443
- updateField={updateFieldDeprecated}
4444
- options={
4445
- config.visualizationType === 'HeatMap'
4446
- ? config.legend.style === 'gradient'
4447
- ? ['bottom', 'top']
4448
- : ['right', 'left', 'bottom', 'top']
4449
- : config.visualizationType === 'Warming Stripes'
4450
- ? ['bottom']
4451
- : ['right', 'left', 'bottom', 'top']
4452
- }
4453
- />
4454
- {(config.legend.position === 'left' ||
4455
- config.legend.position === 'right' ||
4456
- !config.legend.position) &&
4457
- config.legend.style === 'gradient' && (
4458
- <span style={{ color: 'red', fontSize: '14px' }}>
4459
- Position must be set to top or bottom to use gradient style.
4460
- </span>
4461
- )}
4462
-
4463
- <Select
4464
- tooltip={
4465
- <Tooltip style={{ textTransform: 'none' }}>
4466
- <Tooltip.Target>
4467
- <Icon
4468
- display='question'
4469
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4470
- />
4471
- </Tooltip.Target>
4472
- <Tooltip.Content>
4473
- <p>
4474
- If using gradient style, limit the legend to five items for better mobile visibility,
4475
- and position the legend at the top or bottom.
4476
- </p>
4477
- </Tooltip.Content>
4478
- </Tooltip>
4479
- }
4480
- display={!config.legend.hide}
4481
- value={config.legend.style}
4482
- section='legend'
4483
- fieldName='style'
4484
- label='Legend Style'
4485
- updateField={updateFieldDeprecated}
4486
- options={getLegendStyleOptions('style')}
4487
- />
4488
-
4489
- {config.visualizationType !== 'Warming Stripes' && config.visualizationType !== 'HeatMap' && (
4490
- <Select
4491
- value={config.legend.groupBy}
4642
+ {config.visualizationType === 'Network' ? (
4643
+ <CheckBox
4644
+ value={config.legend.hide ? true : false}
4492
4645
  section='legend'
4493
- fieldName='groupBy'
4494
- initial='Select'
4495
- label='Legend Group By:'
4646
+ fieldName='hide'
4647
+ label='Hide Legend'
4496
4648
  updateField={updateFieldDeprecated}
4497
- options={getLegendStyleOptions('groupBy')}
4649
+ tooltip={
4650
+ <Tooltip style={{ textTransform: 'none' }}>
4651
+ <Tooltip.Target>
4652
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
4653
+ </Tooltip.Target>
4654
+ <Tooltip.Content>
4655
+ <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
4656
+ </Tooltip.Content>
4657
+ </Tooltip>
4658
+ }
4498
4659
  />
4499
- )}
4660
+ ) : (
4661
+ <>
4662
+ <Select
4663
+ value={config.legend?.position}
4664
+ section='legend'
4665
+ fieldName='position'
4666
+ label='Position'
4667
+ updateField={updateFieldDeprecated}
4668
+ options={
4669
+ config.visualizationType === 'HeatMap'
4670
+ ? config.legend.style === 'gradient'
4671
+ ? ['bottom', 'top']
4672
+ : ['right', 'left', 'bottom', 'top']
4673
+ : config.visualizationType === 'Warming Stripes'
4674
+ ? ['bottom']
4675
+ : ['right', 'left', 'bottom', 'top']
4676
+ }
4677
+ />
4678
+ {(config.legend.position === 'left' ||
4679
+ config.legend.position === 'right' ||
4680
+ !config.legend.position) &&
4681
+ config.legend.style === 'gradient' && (
4682
+ <span style={{ color: 'red', fontSize: '14px' }}>
4683
+ Position must be set to top or bottom to use gradient style.
4684
+ </span>
4685
+ )}
4500
4686
 
4501
- <CheckBox
4502
- tooltip={
4503
- <Tooltip style={{ textTransform: 'none' }}>
4504
- <Tooltip.Target>
4505
- <Icon
4506
- display='question'
4507
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4508
- />
4509
- </Tooltip.Target>
4510
- <Tooltip.Content>
4511
- <p>Choose option Shapes in Line Datapoint Symbols to display.</p>
4512
- </Tooltip.Content>
4513
- </Tooltip>
4514
- }
4515
- display={!config.legend.hide && config.legend.style === 'lines'}
4516
- value={config.legend.hasShape}
4517
- section='legend'
4518
- fieldName='hasShape'
4519
- label='Shapes'
4520
- updateField={updateFieldDeprecated}
4521
- />
4687
+ <Select
4688
+ tooltip={
4689
+ <Tooltip style={{ textTransform: 'none' }}>
4690
+ <Tooltip.Target>
4691
+ <Icon
4692
+ display='question'
4693
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4694
+ />
4695
+ </Tooltip.Target>
4696
+ <Tooltip.Content>
4697
+ <p>
4698
+ If using gradient style, limit the legend to five items for better mobile
4699
+ visibility, and position the legend at the top or bottom.
4700
+ </p>
4701
+ </Tooltip.Content>
4702
+ </Tooltip>
4703
+ }
4704
+ display={!config.legend.hide}
4705
+ value={config.legend.style}
4706
+ section='legend'
4707
+ fieldName='style'
4708
+ label='Legend Style'
4709
+ updateField={updateFieldDeprecated}
4710
+ options={getLegendStyleOptions('style')}
4711
+ />
4522
4712
 
4523
- <Select
4524
- display={!config.legend.hide && config.legend.style === 'gradient'}
4525
- value={config.legend.subStyle}
4526
- section='legend'
4527
- fieldName='subStyle'
4528
- label='Gradient Style'
4529
- updateField={updateFieldDeprecated}
4530
- options={getLegendStyleOptions('subStyle')}
4531
- />
4532
- <TextField
4533
- display={
4534
- config.visualizationType !== 'HeatMap' &&
4535
- config.legend.style === 'gradient' &&
4536
- !config.legend.hide
4537
- }
4538
- className='number-narrow'
4539
- type='number'
4540
- value={config.legend.tickRotation}
4541
- section='legend'
4542
- fieldName='tickRotation'
4543
- label='Tick Rotation (Degrees)'
4544
- updateField={updateFieldDeprecated}
4545
- />
4713
+ {config.visualizationType !== 'Warming Stripes' && config.visualizationType !== 'HeatMap' && (
4714
+ <Select
4715
+ value={config.legend.groupBy}
4716
+ section='legend'
4717
+ fieldName='groupBy'
4718
+ initial='Select'
4719
+ label='Legend Group By:'
4720
+ updateField={updateFieldDeprecated}
4721
+ options={getLegendStyleOptions('groupBy')}
4722
+ />
4723
+ )}
4546
4724
 
4547
- <CheckBox
4548
- display={
4549
- config.visualizationType !== 'Radar' &&
4550
- config.preliminaryData?.some(pd => pd.label && pd.type === 'suppression' && pd.value)
4551
- }
4552
- value={config.legend.hideSuppressedLabels}
4553
- section='legend'
4554
- fieldName='hideSuppressedLabels'
4555
- label='Hide Suppressed Labels'
4556
- updateField={updateFieldDeprecated}
4557
- tooltip={
4558
- <Tooltip style={{ textTransform: 'none' }}>
4559
- <Tooltip.Target>
4560
- <Icon
4561
- display='question'
4562
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4563
- />
4564
- </Tooltip.Target>
4565
- <Tooltip.Content>
4566
- <p>
4567
- Hiding suppressed labels will not override the 'Special Class' assigned to line chart
4568
- indicating "suppressed" data in the Data Series Panel.
4569
- </p>
4570
- </Tooltip.Content>
4571
- </Tooltip>
4572
- }
4573
- />
4574
- <CheckBox
4575
- display={
4576
- config.visualizationType !== 'Radar' &&
4577
- config.preliminaryData?.some(pd => pd.label && pd.type === 'suppression' && pd.value)
4578
- }
4579
- value={config.legend.hideSuppressionLink}
4580
- section='legend'
4581
- fieldName='hideSuppressionLink'
4582
- label='Hide Suppression Definition Link'
4583
- updateField={updateFieldDeprecated}
4584
- tooltip={
4585
- <Tooltip style={{ textTransform: 'none' }}>
4586
- <Tooltip.Target>
4587
- <Icon
4588
- display='question'
4589
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4590
- />
4591
- </Tooltip.Target>
4592
- <Tooltip.Content>
4593
- <p>Selecting this option will hide the suppression definition link from display.</p>
4594
- </Tooltip.Content>
4595
- </Tooltip>
4596
- }
4597
- />
4725
+ <CheckBox
4726
+ tooltip={
4727
+ <Tooltip style={{ textTransform: 'none' }}>
4728
+ <Tooltip.Target>
4729
+ <Icon
4730
+ display='question'
4731
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4732
+ />
4733
+ </Tooltip.Target>
4734
+ <Tooltip.Content>
4735
+ <p>Choose option Shapes in Line Datapoint Symbols to display.</p>
4736
+ </Tooltip.Content>
4737
+ </Tooltip>
4738
+ }
4739
+ display={!config.legend.hide && config.legend.style === 'lines'}
4740
+ value={config.legend.hasShape}
4741
+ section='legend'
4742
+ fieldName='hasShape'
4743
+ label='Shapes'
4744
+ updateField={updateFieldDeprecated}
4745
+ />
4598
4746
 
4599
- <Select
4600
- display={visSupportsClickingLegend() && (hasDynamicCategory || hasMultipleSeries)}
4601
- value={config.legend.behavior}
4602
- section='legend'
4603
- fieldName='behavior'
4604
- label='Legend Behavior (When clicked)'
4605
- updateField={(...[section, , fieldName, value]) => updateBehavior(section, fieldName, value)}
4606
- options={['highlight', 'isolate']}
4607
- />
4747
+ <Select
4748
+ display={!config.legend.hide && config.legend.style === 'gradient'}
4749
+ value={config.legend.subStyle}
4750
+ section='legend'
4751
+ fieldName='subStyle'
4752
+ label='Gradient Style'
4753
+ updateField={updateFieldDeprecated}
4754
+ options={getLegendStyleOptions('subStyle')}
4755
+ />
4756
+ <TextField
4757
+ display={
4758
+ config.visualizationType !== 'HeatMap' &&
4759
+ config.legend.style === 'gradient' &&
4760
+ !config.legend.hide
4761
+ }
4762
+ className='number-narrow'
4763
+ type='number'
4764
+ value={config.legend.tickRotation}
4765
+ section='legend'
4766
+ fieldName='tickRotation'
4767
+ label='Tick Rotation (Degrees)'
4768
+ updateField={updateFieldDeprecated}
4769
+ />
4608
4770
 
4609
- <Select
4610
- display={visHasLegendColorCategory()}
4611
- value={config.legend.colorCode}
4612
- section='legend'
4613
- fieldName='colorCode'
4614
- label='Color code by category'
4615
- initial='Select'
4616
- updateField={updateFieldDeprecated}
4617
- options={getDataValueOptions(data)}
4618
- />
4619
- {visHasLegendAxisAlign() && (
4620
- <CheckBox
4621
- value={config.legend.axisAlign}
4622
- fieldName='axisAlign'
4623
- section='legend'
4624
- label='Align to Axis on Isolate'
4625
- updateField={updateFieldDeprecated}
4626
- />
4627
- )}
4628
- {config.legend.behavior === 'highlight' && config.tooltips.singleSeries && (
4629
- <CheckBox
4630
- value={config.legend.highlightOnHover}
4631
- section='legend'
4632
- fieldName='highlightOnHover'
4633
- label='HIGHLIGHT DATA SERIES ON HOVER'
4634
- updateField={updateFieldDeprecated}
4635
- />
4636
- )}
4637
- {/* start: isolated values */}
4638
- {visHasSelectableLegendValues && config.legend.behavior === 'isolate' && !colorCodeByCategory && (
4639
- <fieldset className='primary-fieldset edit-block' key={'additional-highlight-values'}>
4640
- <label>
4641
- <span className='edit-label'>
4642
- Isolate Data Series
4771
+ <CheckBox
4772
+ display={
4773
+ config.visualizationType !== 'Radar' &&
4774
+ config.preliminaryData?.some(pd => pd.label && pd.type === 'suppression' && pd.value)
4775
+ }
4776
+ value={config.legend.hideSuppressedLabels}
4777
+ section='legend'
4778
+ fieldName='hideSuppressedLabels'
4779
+ label='Hide Suppressed Labels'
4780
+ updateField={updateFieldDeprecated}
4781
+ tooltip={
4643
4782
  <Tooltip style={{ textTransform: 'none' }}>
4644
4783
  <Tooltip.Target>
4645
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
4784
+ <Icon
4785
+ display='question'
4786
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4787
+ />
4646
4788
  </Tooltip.Target>
4647
4789
  <Tooltip.Content>
4648
4790
  <p>
4649
- You can choose data series that are shown on load. Others will be added when the
4650
- user clicks on them in the legend.
4791
+ Hiding suppressed labels will not override the 'Special Class' assigned to line
4792
+ chart indicating "suppressed" data in the Data Series Panel.
4651
4793
  </p>
4652
4794
  </Tooltip.Content>
4653
4795
  </Tooltip>
4654
- </span>
4655
- </label>
4656
- {config.legend.seriesHighlight &&
4657
- config.legend.seriesHighlight.map((val, i) => (
4658
- <fieldset className='edit-block' key={`${val}-${i}`}>
4796
+ }
4797
+ />
4798
+ <CheckBox
4799
+ display={
4800
+ config.visualizationType !== 'Radar' &&
4801
+ config.preliminaryData?.some(pd => pd.label && pd.type === 'suppression' && pd.value)
4802
+ }
4803
+ value={config.legend.hideSuppressionLink}
4804
+ section='legend'
4805
+ fieldName='hideSuppressionLink'
4806
+ label='Hide Suppression Definition Link'
4807
+ updateField={updateFieldDeprecated}
4808
+ tooltip={
4809
+ <Tooltip style={{ textTransform: 'none' }}>
4810
+ <Tooltip.Target>
4811
+ <Icon
4812
+ display='question'
4813
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4814
+ />
4815
+ </Tooltip.Target>
4816
+ <Tooltip.Content>
4817
+ <p>Selecting this option will hide the suppression definition link from display.</p>
4818
+ </Tooltip.Content>
4819
+ </Tooltip>
4820
+ }
4821
+ />
4822
+
4823
+ <Select
4824
+ display={visSupportsClickingLegend() && (hasDynamicCategory || hasMultipleSeries)}
4825
+ value={config.legend.behavior}
4826
+ section='legend'
4827
+ fieldName='behavior'
4828
+ label='Legend Behavior (When clicked)'
4829
+ updateField={(...[section, , fieldName, value]) =>
4830
+ updateBehavior(section, fieldName, value)
4831
+ }
4832
+ options={['highlight', 'isolate']}
4833
+ />
4834
+
4835
+ <Select
4836
+ display={visHasLegendColorCategory()}
4837
+ value={config.legend.colorCode}
4838
+ section='legend'
4839
+ fieldName='colorCode'
4840
+ label='Color code by category'
4841
+ initial='Select'
4842
+ updateField={updateFieldDeprecated}
4843
+ options={getDataValueOptions(data)}
4844
+ />
4845
+ {visHasLegendAxisAlign() && (
4846
+ <CheckBox
4847
+ value={config.legend.axisAlign}
4848
+ fieldName='axisAlign'
4849
+ section='legend'
4850
+ label='Align to Axis on Isolate'
4851
+ updateField={updateFieldDeprecated}
4852
+ />
4853
+ )}
4854
+ {config.legend.behavior === 'highlight' && config.tooltips.singleSeries && (
4855
+ <CheckBox
4856
+ value={config.legend.highlightOnHover}
4857
+ section='legend'
4858
+ fieldName='highlightOnHover'
4859
+ label='HIGHLIGHT DATA SERIES ON HOVER'
4860
+ updateField={updateFieldDeprecated}
4861
+ />
4862
+ )}
4863
+ {/* start: isolated values */}
4864
+ {visHasSelectableLegendValues &&
4865
+ config.legend.behavior === 'isolate' &&
4866
+ !colorCodeByCategory && (
4867
+ <fieldset className='primary-fieldset edit-block' key={'additional-highlight-values'}>
4868
+ <label>
4869
+ <span className='edit-label'>
4870
+ Isolate Data Series
4871
+ <Tooltip style={{ textTransform: 'none' }}>
4872
+ <Tooltip.Target>
4873
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
4874
+ </Tooltip.Target>
4875
+ <Tooltip.Content>
4876
+ <p>
4877
+ You can choose data series that are shown on load. Others will be added when
4878
+ the user clicks on them in the legend.
4879
+ </p>
4880
+ </Tooltip.Content>
4881
+ </Tooltip>
4882
+ </span>
4883
+ </label>
4884
+ {config.legend.seriesHighlight &&
4885
+ config.legend.seriesHighlight.map((val, i) => (
4886
+ <fieldset className='edit-block' key={`${val}-${i}`}>
4887
+ <Button
4888
+ className='btn btn-danger'
4889
+ onClick={event => {
4890
+ event.preventDefault()
4891
+ const updatedSeriesHighlight = [...config.legend.seriesHighlight]
4892
+ updatedSeriesHighlight.splice(i, 1)
4893
+ updateFieldDeprecated(
4894
+ 'legend',
4895
+ null,
4896
+ 'seriesHighlight',
4897
+ updatedSeriesHighlight
4898
+ )
4899
+ if (!updatedSeriesHighlight.length) {
4900
+ handleShowAll()
4901
+ }
4902
+ }}
4903
+ >
4904
+ Remove
4905
+ </Button>
4906
+ <Select
4907
+ value={config.legend.seriesHighlight[i]}
4908
+ fieldName='seriesHighlight'
4909
+ label='Isolate Value'
4910
+ onChange={e => {
4911
+ const updatedSeriesHighlight = [...config.legend.seriesHighlight]
4912
+ if (!updatedSeriesHighlight.includes(e.target.value)) {
4913
+ updatedSeriesHighlight[i] = e.target.value
4914
+ updateSeriesIsolateValues([...updatedSeriesHighlight])
4915
+ }
4916
+ }}
4917
+ options={getLegendColumns()}
4918
+ />
4919
+ </fieldset>
4920
+ ))}
4659
4921
  <Button
4660
- className='btn btn-danger'
4922
+ variant='editor-primary'
4661
4923
  onClick={event => {
4662
4924
  event.preventDefault()
4925
+ const legendColumns = getLegendColumns()
4663
4926
  const updatedSeriesHighlight = [...config.legend.seriesHighlight]
4664
- updatedSeriesHighlight.splice(i, 1)
4665
- updateFieldDeprecated('legend', null, 'seriesHighlight', updatedSeriesHighlight)
4666
- if (!updatedSeriesHighlight.length) {
4667
- handleShowAll()
4927
+ const seriesLength = updatedSeriesHighlight.length
4928
+ if (seriesLength < legendColumns.length) {
4929
+ const [newSeriesHighlight] = legendColumns.filter(
4930
+ d => !updatedSeriesHighlight.includes(d)
4931
+ )
4932
+ updatedSeriesHighlight.push(newSeriesHighlight)
4933
+ updateSeriesIsolateValues([...updatedSeriesHighlight])
4668
4934
  }
4669
4935
  }}
4670
4936
  >
4671
- Remove
4937
+ Add Isolate Value
4672
4938
  </Button>
4673
- <Select
4674
- value={config.legend.seriesHighlight[i]}
4675
- fieldName='seriesHighlight'
4676
- label='Isolate Value'
4677
- onChange={e => {
4678
- const updatedSeriesHighlight = [...config.legend.seriesHighlight]
4679
- if (!updatedSeriesHighlight.includes(e.target.value)) {
4680
- updatedSeriesHighlight[i] = e.target.value
4681
- updateSeriesIsolateValues([...updatedSeriesHighlight])
4682
- }
4683
- }}
4684
- options={getLegendColumns()}
4685
- />
4686
4939
  </fieldset>
4687
- ))}
4688
- <Button
4689
- variant='editor-primary'
4690
- onClick={event => {
4691
- event.preventDefault()
4692
- const legendColumns = getLegendColumns()
4693
- const updatedSeriesHighlight = [...config.legend.seriesHighlight]
4694
- const seriesLength = updatedSeriesHighlight.length
4695
- if (seriesLength < legendColumns.length) {
4696
- const [newSeriesHighlight] = legendColumns.filter(
4697
- d => !updatedSeriesHighlight.includes(d)
4698
- )
4699
- updatedSeriesHighlight.push(newSeriesHighlight)
4700
- updateSeriesIsolateValues([...updatedSeriesHighlight])
4940
+ )}
4941
+ {/* end: isolated values */}
4942
+ <CheckBox
4943
+ display={!config.legend.hide && config.legend.style !== 'gradient'}
4944
+ value={config.legend.reverseLabelOrder}
4945
+ section='legend'
4946
+ fieldName='reverseLabelOrder'
4947
+ label='Reverse Labels'
4948
+ updateField={updateFieldDeprecated}
4949
+ />
4950
+ {config.visualizationType !== 'Warming Stripes' && (
4951
+ <CheckBox
4952
+ display={!config.legend.hide}
4953
+ value={
4954
+ ['left', 'right'].includes(config.legend.position)
4955
+ ? config.legend.hideBorder.side
4956
+ : config.legend.hideBorder.topBottom
4701
4957
  }
4702
- }}
4703
- >
4704
- Add Isolate Value
4705
- </Button>
4706
- </fieldset>
4707
- )}
4708
- {/* end: isolated values */}
4709
- <CheckBox
4710
- display={!config.legend.hide && config.legend.style !== 'gradient'}
4711
- value={config.legend.reverseLabelOrder}
4712
- section='legend'
4713
- fieldName='reverseLabelOrder'
4714
- label='Reverse Labels'
4715
- updateField={updateFieldDeprecated}
4716
- />
4717
- {config.visualizationType !== 'Warming Stripes' && (
4718
- <CheckBox
4719
- display={!config.legend.hide}
4720
- value={
4721
- ['left', 'right'].includes(config.legend.position)
4722
- ? config.legend.hideBorder.side
4723
- : config.legend.hideBorder.topBottom
4724
- }
4725
- section='legend'
4726
- subsection='hideBorder'
4727
- fieldName={['left', 'right'].includes(config.legend.position) ? 'side' : 'topBottom'}
4728
- label='Hide Legend Box'
4729
- updateField={updateFieldDeprecated}
4730
- tooltip={
4731
- <Tooltip style={{ textTransform: 'none' }}>
4732
- <Tooltip.Target>
4733
- <Icon
4734
- display='question'
4735
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4736
- />
4737
- </Tooltip.Target>
4738
- <Tooltip.Content>
4739
- <p>Default option for top and bottom legends is ‘No Box.’.</p>
4740
- </Tooltip.Content>
4741
- </Tooltip>
4742
- }
4743
- />
4744
- )}
4745
- <CheckBox
4746
- display={
4747
- !config.legend.hide &&
4748
- !['left', 'right'].includes(config.legend.position) &&
4749
- config.legend.style !== 'gradient'
4750
- }
4751
- value={config.legend.singleRow}
4752
- section='legend'
4753
- fieldName='singleRow'
4754
- label='Single Row Legend'
4755
- updateField={updateFieldDeprecated}
4756
- />
4757
- <CheckBox
4758
- display={
4759
- ['bottom', 'top'].includes(config.legend.position) &&
4760
- !config.legend.hide &&
4761
- config.legend.style !== 'gradient' &&
4762
- !config.legend.singleRow &&
4763
- !config.legend.singleRow
4764
- }
4765
- value={config.legend.verticalSorted}
4766
- section='legend'
4767
- fieldName='verticalSorted'
4768
- label='Vertical sorted Legend'
4769
- updateField={updateFieldDeprecated}
4770
- />
4958
+ section='legend'
4959
+ subsection='hideBorder'
4960
+ fieldName={['left', 'right'].includes(config.legend.position) ? 'side' : 'topBottom'}
4961
+ label='Hide Legend Box'
4962
+ updateField={updateFieldDeprecated}
4963
+ tooltip={
4964
+ <Tooltip style={{ textTransform: 'none' }}>
4965
+ <Tooltip.Target>
4966
+ <Icon
4967
+ display='question'
4968
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4969
+ />
4970
+ </Tooltip.Target>
4971
+ <Tooltip.Content>
4972
+ <p>Default option for top and bottom legends is ‘No Box.’.</p>
4973
+ </Tooltip.Content>
4974
+ </Tooltip>
4975
+ }
4976
+ />
4977
+ )}
4978
+ <CheckBox
4979
+ display={
4980
+ !config.legend.hide &&
4981
+ !['left', 'right'].includes(config.legend.position) &&
4982
+ config.legend.style !== 'gradient'
4983
+ }
4984
+ value={config.legend.singleRow}
4985
+ section='legend'
4986
+ fieldName='singleRow'
4987
+ label='Single Row Legend'
4988
+ updateField={updateFieldDeprecated}
4989
+ />
4990
+ <CheckBox
4991
+ display={
4992
+ ['bottom', 'top'].includes(config.legend.position) &&
4993
+ !config.legend.hide &&
4994
+ config.legend.style !== 'gradient' &&
4995
+ !config.legend.singleRow &&
4996
+ !config.legend.singleRow
4997
+ }
4998
+ value={config.legend.verticalSorted}
4999
+ section='legend'
5000
+ fieldName='verticalSorted'
5001
+ label='Vertical sorted Legend'
5002
+ updateField={updateFieldDeprecated}
5003
+ />
4771
5004
 
4772
- {config.visualizationType !== 'Warming Stripes' && (
4773
- <CheckBox
4774
- value={config.legend.hide ? true : false}
4775
- section='legend'
4776
- fieldName='hide'
4777
- label='Hide Legend'
4778
- updateField={updateFieldDeprecated}
4779
- tooltip={
4780
- <Tooltip style={{ textTransform: 'none' }}>
4781
- <Tooltip.Target>
4782
- <Icon
4783
- display='question'
4784
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4785
- />
4786
- </Tooltip.Target>
4787
- <Tooltip.Content>
4788
- <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
4789
- </Tooltip.Content>
4790
- </Tooltip>
4791
- }
4792
- />
4793
- )}
4794
- <TextField
4795
- value={config.legend.label}
4796
- section='legend'
4797
- fieldName='label'
4798
- label='Title'
4799
- updateField={updateFieldDeprecated}
4800
- />
4801
- <TextField
4802
- type='textarea'
4803
- value={config.legend.description}
4804
- updateField={updateFieldDeprecated}
4805
- section='legend'
4806
- fieldName='description'
4807
- label='Legend Description'
4808
- />
5005
+ {config.visualizationType !== 'Warming Stripes' && (
5006
+ <CheckBox
5007
+ value={config.legend.hide ? true : false}
5008
+ section='legend'
5009
+ fieldName='hide'
5010
+ label='Hide Legend'
5011
+ updateField={updateFieldDeprecated}
5012
+ tooltip={
5013
+ <Tooltip style={{ textTransform: 'none' }}>
5014
+ <Tooltip.Target>
5015
+ <Icon
5016
+ display='question'
5017
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
5018
+ />
5019
+ </Tooltip.Target>
5020
+ <Tooltip.Content>
5021
+ <p>
5022
+ With a single-series chart, consider hiding the legend to reduce visual clutter.
5023
+ </p>
5024
+ </Tooltip.Content>
5025
+ </Tooltip>
5026
+ }
5027
+ />
5028
+ )}
5029
+ <TextField
5030
+ value={config.legend.label}
5031
+ section='legend'
5032
+ fieldName='label'
5033
+ label='Title'
5034
+ updateField={updateFieldDeprecated}
5035
+ />
5036
+ <TextField
5037
+ type='textarea'
5038
+ value={config.legend.description}
5039
+ updateField={updateFieldDeprecated}
5040
+ section='legend'
5041
+ fieldName='description'
5042
+ label='Legend Description'
5043
+ />
4809
5044
 
4810
- {config.visualizationType !== 'Warming Stripes' && (
4811
- <CheckBox
4812
- value={config.legend.unified}
4813
- section='legend'
4814
- fieldName='unified'
4815
- label='Unified Legend'
4816
- updateField={updateFieldDeprecated}
4817
- tooltip={
4818
- <Tooltip style={{ textTransform: 'none' }}>
4819
- <Tooltip.Target>
4820
- <Icon
4821
- display='question'
4822
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4823
- />
4824
- </Tooltip.Target>
4825
- <Tooltip.Content>
4826
- <p>
4827
- For a chart with filters, check this option if you want the legend to contain an item
4828
- for every series in the data set, including those that are filtered.
4829
- </p>
4830
- </Tooltip.Content>
4831
- </Tooltip>
4832
- }
4833
- />
5045
+ {config.visualizationType !== 'Warming Stripes' && (
5046
+ <CheckBox
5047
+ value={config.legend.unified}
5048
+ section='legend'
5049
+ fieldName='unified'
5050
+ label='Unified Legend'
5051
+ updateField={updateFieldDeprecated}
5052
+ tooltip={
5053
+ <Tooltip style={{ textTransform: 'none' }}>
5054
+ <Tooltip.Target>
5055
+ <Icon
5056
+ display='question'
5057
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
5058
+ />
5059
+ </Tooltip.Target>
5060
+ <Tooltip.Content>
5061
+ <p>
5062
+ For a chart with filters, check this option if you want the legend to contain an
5063
+ item for every series in the data set, including those that are filtered.
5064
+ </p>
5065
+ </Tooltip.Content>
5066
+ </Tooltip>
5067
+ }
5068
+ />
5069
+ )}
5070
+ </>
4834
5071
  )}
4835
5072
  </AccordionItemPanel>
4836
5073
  </AccordionItem>
4837
5074
  )}
4838
5075
  {visSupportsFilters() && (
4839
5076
  <>
4840
- <AccordionItem>
4841
- <AccordionItemHeading>
4842
- <AccordionItemButton>Filters</AccordionItemButton>
4843
- </AccordionItemHeading>
4844
- <AccordionItemPanel>
4845
- <VizFilterEditor
4846
- config={config}
4847
- updateField={updateField}
4848
- rawData={rawData}
4849
- hasFootnotes={isDashboard}
4850
- />
4851
- </AccordionItemPanel>
4852
- </AccordionItem>
5077
+ {!isBarRace && (
5078
+ <AccordionItem>
5079
+ <AccordionItemHeading>
5080
+ <AccordionItemButton>Filters</AccordionItemButton>
5081
+ </AccordionItemHeading>
5082
+ <AccordionItemPanel>
5083
+ <VizFilterEditor
5084
+ config={config}
5085
+ updateField={updateField}
5086
+ rawData={rawData}
5087
+ hasFootnotes={isDashboard}
5088
+ />
5089
+ </AccordionItemPanel>
5090
+ </AccordionItem>
5091
+ )}
4853
5092
  <AccordionItem>
4854
5093
  <AccordionItemHeading>
4855
5094
  <AccordionItemButton>Footnotes</AccordionItemButton>
@@ -4861,7 +5100,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4861
5100
  </>
4862
5101
  )}
4863
5102
  <Panels.Visual name='Visual' />
4864
- <Panels.PatternSettings name='PatternSettings' />
5103
+ {!isBarRace && !['Network', 'Dendrogram'].includes(config.visualizationType) && (
5104
+ <Panels.PatternSettings name='PatternSettings' />
5105
+ )}
4865
5106
  {/* Spark Line has no data table */}
4866
5107
  {config.visualizationType !== 'Spark Line' && (
4867
5108
  <AccordionItem>
@@ -4879,7 +5120,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4879
5120
  </AccordionItemPanel>
4880
5121
  </AccordionItem>
4881
5122
  )}
4882
- <Panels.Annotate name='Text Annotations' />
5123
+ {!isBarRace && !['Network', 'Dendrogram'].includes(config.visualizationType) && (
5124
+ <Panels.Annotate name='Text Annotations' />
5125
+ )}
4883
5126
  {/* {(config.visualizationType === 'Bar' || config.visualizationType === 'Line') && <Panels.DateHighlighting name='Date Highlighting' />} */}
4884
5127
  {config.visualizationType !== 'Radar' && (
4885
5128
  <PanelMarkup
@@ -4894,6 +5137,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4894
5137
  )}
4895
5138
  <Panels.SmallMultiples name='Small Multiples' />
4896
5139
  </Accordion>
5140
+ {!isDashboard && <ModernStylesAction />}
4897
5141
  {config.type !== 'Spark Line' && (
4898
5142
  <AdvancedEditor
4899
5143
  loadConfig={updateConfig}
@@ -4913,6 +5157,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4913
5157
  onCancel={handleConversionCancel}
4914
5158
  onReturnToV1={handleReturnToV1}
4915
5159
  paletteName={pendingPaletteSelection?.palette}
5160
+ message={config.general?.palette?.version === '2.0' ? V21_PALETTE_CONVERSION_MESSAGE : undefined}
4916
5161
  />
4917
5162
  )}
4918
5163
  </EditorPanelContext.Provider>