@cdc/chart 4.26.6 → 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 (276) hide show
  1. package/CONFIG.md +504 -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 -96498
  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/flueview.json +22051 -0
  22. package/examples/private/overlay-legend.json +485 -0
  23. package/examples/private/pie-test.json +469 -0
  24. package/examples/vega-remote.json +22 -0
  25. package/package.json +11 -13
  26. package/src/CdcChart.tsx +2 -2
  27. package/src/CdcChartComponent.tsx +444 -217
  28. package/src/_stories/Chart.BarRace.stories.tsx +443 -0
  29. package/src/_stories/Chart.BoxPlotNumericSort.stories.tsx +189 -0
  30. package/src/_stories/Chart.BoxPlotStatsParity.stories.tsx +207 -0
  31. package/src/_stories/Chart.ColorDistribution.stories.tsx +299 -0
  32. package/src/_stories/Chart.DataCutoff.stories.tsx +147 -0
  33. package/src/_stories/Chart.DataTableDownloadFilename.stories.tsx +60 -0
  34. package/src/_stories/Chart.Dendrogram.stories.tsx +373 -0
  35. package/src/_stories/Chart.Forecast.CILegend.stories.tsx +236 -0
  36. package/src/_stories/Chart.HeatMap.stories.tsx +170 -4
  37. package/src/_stories/Chart.Legend.AxisAlign.stories.tsx +119 -0
  38. package/src/_stories/Chart.LineRace.stories.tsx +149 -0
  39. package/src/_stories/Chart.Network.stories.tsx +432 -0
  40. package/src/_stories/Chart.PaletteConversion.Editor.stories.tsx +208 -0
  41. package/src/_stories/Chart.Patterns.smoke.stories.tsx +31 -0
  42. package/src/_stories/Chart.PercentageValue.stories.tsx +311 -0
  43. package/src/_stories/Chart.PieLabels.stories.tsx +49 -0
  44. package/src/_stories/Chart.RankByValueMutation.stories.tsx +206 -0
  45. package/src/_stories/Chart.RequiredFields.stories.tsx +681 -0
  46. package/src/_stories/Chart.Sankey.stories.tsx +417 -0
  47. package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +47 -0
  48. package/src/_stories/Chart.SmallMultiplesNumericTileOrder.stories.tsx +137 -0
  49. package/src/_stories/Chart.TooltipSeriesLabels.stories.tsx +43 -0
  50. package/src/_stories/Chart.VegaRemoteData.stories.tsx +31 -0
  51. package/src/_stories/Chart.smoke.stories.tsx +14 -1
  52. package/src/_stories/ChartAnnotation.Editor.stories.tsx +78 -0
  53. package/src/_stories/ChartAxisTitles.smoke.stories.tsx +48 -0
  54. package/src/_stories/ChartBar.Editor.stories.tsx +499 -57
  55. package/src/_stories/ChartBrush.Editor.stories.tsx +46 -67
  56. package/src/_stories/ChartBrush.Regression.stories.tsx +135 -0
  57. package/src/_stories/ChartEditor.Editor.stories.tsx +33 -3
  58. package/src/_stories/ChartLine.EffectCompatibility.stories.tsx +120 -0
  59. package/src/_stories/ChartPrefixSuffix.smoke.stories.tsx +28 -1
  60. package/src/_stories/_mock/annotation_event-line_mock.json +2 -2
  61. package/src/_stories/_mock/editor-test-configs.json +20 -10
  62. package/src/_stories/_mock/editor-test-datasets.json +38 -42
  63. package/src/_stories/_mock/heatmap-average-age-categorical.json +2 -2
  64. package/src/_stories/_mock/heatmap.json +2 -2
  65. package/src/_stories/_mock/legend-axis-align-stacked-bar.json +125 -0
  66. package/src/_stories/_mock/sankey_mock.json +23 -27
  67. package/src/components/Annotations/components/AnnotationDraggable.styles.css +52 -0
  68. package/src/components/Annotations/components/AnnotationDraggable.tsx +639 -139
  69. package/src/components/Annotations/components/AnnotationDropdown.styles.css +44 -4
  70. package/src/components/Annotations/components/AnnotationDropdown.tsx +10 -32
  71. package/src/components/Annotations/helpers/resolveAnnotationLayout.ts +212 -0
  72. package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +612 -19
  73. package/src/components/Annotations/tests/AnnotationDropdown.test.tsx +50 -0
  74. package/src/components/Annotations/tests/resolveAnnotationLayout.test.ts +203 -0
  75. package/src/components/Axis/BottomAxis.tsx +1 -1
  76. package/src/components/Axis/Categorical.Axis.tsx +3 -3
  77. package/src/components/Axis/RightAxis.tsx +21 -13
  78. package/src/components/BarChart/components/BarChart.Horizontal.tsx +39 -8
  79. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +13 -4
  80. package/src/components/BarChart/components/BarChart.StackedVertical.test.ts +28 -0
  81. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +30 -26
  82. package/src/components/BarChart/components/BarChart.Vertical.tsx +38 -28
  83. package/src/components/BarChart/components/PortionPatternOverlay.tsx +61 -0
  84. package/src/components/BarChart/components/context.tsx +6 -0
  85. package/src/components/BarChart/helpers/getBarData.ts +28 -28
  86. package/src/components/BarChart/helpers/getBarHeights.ts +2 -2
  87. package/src/components/BarChart/helpers/getPatternUrl.ts +2 -5
  88. package/src/components/BarChart/helpers/index.ts +8 -0
  89. package/src/components/BarChart/helpers/portionPattern.ts +243 -0
  90. package/src/components/BarChart/helpers/tests/addMinimumBarHeights.test.ts +42 -0
  91. package/src/components/BarChart/helpers/tests/getPatternUrl.test.ts +13 -0
  92. package/src/components/BarChart/helpers/tests/portionPattern.test.ts +280 -0
  93. package/src/components/BarChart/helpers/tests/useBarChart.test.tsx +202 -0
  94. package/src/components/BarChart/helpers/useBarChart.ts +60 -60
  95. package/src/components/BarChartRace/BarChartRace.test.tsx +199 -0
  96. package/src/components/BarChartRace/BarChartRace.tsx +230 -0
  97. package/src/components/BarChartRace/BarChartRaceFallback.test.tsx +61 -0
  98. package/src/components/BarChartRace/BarChartRaceFallback.tsx +48 -0
  99. package/src/components/BarChartRace/bar-chart-race.css +160 -0
  100. package/src/components/BarChartRace/helpers.test.ts +114 -0
  101. package/src/components/BarChartRace/helpers.ts +185 -0
  102. package/src/components/BarChartRace/index.ts +3 -0
  103. package/src/components/BoxPlot/BoxPlot.Horizontal.tsx +7 -6
  104. package/src/components/BoxPlot/BoxPlot.Vertical.tsx +9 -7
  105. package/src/components/BoxPlot/helpers/index.ts +13 -83
  106. package/src/components/Brush/BrushSelector.tsx +10 -24
  107. package/src/components/Brush/MiniChartPreview.tsx +33 -1
  108. package/src/components/Dendrogram/components/Dendrogram.tsx +374 -0
  109. package/src/components/Dendrogram/dendrogram.css +113 -0
  110. package/src/components/Dendrogram/helpers/layoutDendrogram.test.ts +95 -0
  111. package/src/components/Dendrogram/helpers/layoutDendrogram.ts +56 -0
  112. package/src/components/Dendrogram/helpers/prepareDendrogramData.test.ts +135 -0
  113. package/src/components/Dendrogram/helpers/prepareDendrogramData.ts +166 -0
  114. package/src/components/Dendrogram/helpers/resolveDendrogramLabels.test.ts +196 -0
  115. package/src/components/Dendrogram/helpers/resolveDendrogramLabels.ts +418 -0
  116. package/src/components/Dendrogram/index.tsx +1 -0
  117. package/src/components/Dendrogram/types/index.ts +66 -0
  118. package/src/components/EditorPanel/EditorPanel.tsx +1111 -805
  119. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +50 -5
  120. package/src/components/EditorPanel/components/Panels/Panel.Dendrogram.css +10 -0
  121. package/src/components/EditorPanel/components/Panels/Panel.Dendrogram.tsx +211 -0
  122. package/src/components/EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx +19 -8
  123. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +104 -61
  124. package/src/components/EditorPanel/components/Panels/Panel.Network.css +9 -0
  125. package/src/components/EditorPanel/components/Panels/Panel.Network.tsx +202 -0
  126. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +236 -36
  127. package/src/components/EditorPanel/components/Panels/Panel.Radar.tsx +6 -1
  128. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +89 -105
  129. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +21 -6
  130. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +1 -1
  131. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +8 -66
  132. package/src/components/EditorPanel/components/Panels/RacingControls.test.tsx +131 -0
  133. package/src/components/EditorPanel/components/Panels/RacingControls.tsx +185 -0
  134. package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +2 -2
  135. package/src/components/EditorPanel/components/Panels/index.tsx +4 -0
  136. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +20 -7
  137. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +25 -2
  138. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +5 -4
  139. package/src/components/EditorPanel/useEditorPermissions.test.tsx +94 -0
  140. package/src/components/EditorPanel/useEditorPermissions.ts +75 -25
  141. package/src/components/Forecasting/Forecasting.tsx +16 -7
  142. package/src/components/HeatMap/components/HeatMap.tsx +511 -178
  143. package/src/components/HeatMap/heatmap.constants.ts +7 -3
  144. package/src/components/HeatMap/heatmap.css +101 -2
  145. package/src/components/HeatMap/helpers/layout.ts +80 -0
  146. package/src/components/HeatMap/tests/HeatMap.test.tsx +339 -16
  147. package/src/components/HeatMap/tests/helpers.test.ts +79 -0
  148. package/src/components/Legend/Legend.Component.tsx +163 -148
  149. package/src/components/Legend/Legend.Suppression.tsx +3 -3
  150. package/src/components/Legend/LegendGroup/LegendGroup.styles.css +7 -0
  151. package/src/components/Legend/LegendGroup/LegendGroup.tsx +47 -35
  152. package/src/components/Legend/helpers/createFormatLabels.test.ts +226 -0
  153. package/src/components/Legend/helpers/createFormatLabels.tsx +45 -51
  154. package/src/components/LineChart/components/LineChart.Circle.tsx +3 -3
  155. package/src/components/LineChart/helpers.test.ts +126 -38
  156. package/src/components/LineChart/helpers.ts +9 -6
  157. package/src/components/LineChart/index.tsx +71 -27
  158. package/src/components/LineChart/tests/LineChart.test.tsx +630 -0
  159. package/src/components/LineChartRace/LineChartRace.test.tsx +275 -0
  160. package/src/components/LineChartRace/LineChartRace.tsx +134 -0
  161. package/src/components/LineChartRace/LineChartRaceFallback.tsx +28 -0
  162. package/src/components/LineChartRace/helpers.test.ts +88 -0
  163. package/src/components/LineChartRace/helpers.ts +157 -0
  164. package/src/components/LineChartRace/index.ts +3 -0
  165. package/src/components/LineChartRace/line-chart-race.css +16 -0
  166. package/src/components/LinearChart/ValueAxisAnchors.tsx +58 -0
  167. package/src/components/LinearChart/VisualizationRenderer.tsx +18 -23
  168. package/src/components/LinearChart/tests/LinearChart.test.tsx +412 -13
  169. package/src/components/LinearChart/tests/VisualizationRenderer.test.tsx +141 -0
  170. package/src/components/LinearChart/tests/mockConfigContext.ts +2 -1
  171. package/src/components/LinearChart.tsx +85 -54
  172. package/src/components/Network/components/Network.tsx +372 -0
  173. package/src/components/Network/helpers/layoutNetwork.test.ts +68 -0
  174. package/src/components/Network/helpers/layoutNetwork.ts +87 -0
  175. package/src/components/Network/helpers/prepareNetworkData.test.ts +116 -0
  176. package/src/components/Network/helpers/prepareNetworkData.ts +101 -0
  177. package/src/components/Network/helpers/resolveNetworkLabels.test.ts +112 -0
  178. package/src/components/Network/helpers/resolveNetworkLabels.ts +206 -0
  179. package/src/components/Network/index.tsx +3 -0
  180. package/src/components/Network/network.css +107 -0
  181. package/src/components/Network/types/index.ts +56 -0
  182. package/src/components/PairedBarChart.jsx +5 -10
  183. package/src/components/PairedBarChart.test.tsx +71 -0
  184. package/src/components/PieChart/PieChart.tsx +121 -13
  185. package/src/components/PieChart/helpers/labelPlacement.test.ts +88 -0
  186. package/src/components/PieChart/helpers/labelPlacement.ts +95 -0
  187. package/src/components/RacingChartRenderer.tsx +44 -0
  188. package/src/components/Regions/components/Regions.test.tsx +179 -0
  189. package/src/components/Regions/components/Regions.tsx +104 -69
  190. package/src/components/Regions/index.tsx +2 -3
  191. package/src/components/Sankey/components/Sankey.tsx +264 -437
  192. package/src/components/Sankey/helpers/getSankeyTooltip.ts +12 -0
  193. package/src/components/Sankey/helpers/prepareSankeyData.test.ts +71 -0
  194. package/src/components/Sankey/helpers/prepareSankeyData.ts +90 -0
  195. package/src/components/Sankey/sankey.scss +57 -116
  196. package/src/components/Sankey/types/index.ts +41 -4
  197. package/src/components/ScatterPlot/ScatterPlot.jsx +28 -12
  198. package/src/components/ScatterPlot/ScatterPlot.test.tsx +60 -0
  199. package/src/components/SmallMultiples/SmallMultiples.tsx +12 -12
  200. package/src/components/SmallMultiples/tests/SmallMultipleTile.test.tsx +7 -5
  201. package/src/components/raceTiming.ts +18 -0
  202. package/src/data/initial-state.js +79 -31
  203. package/src/helpers/applyChartTypeContract.ts +71 -0
  204. package/src/helpers/axisLabelFontSize.ts +2 -2
  205. package/src/helpers/boxPlotStats.ts +60 -0
  206. package/src/helpers/bumpChartTooltip.ts +2 -1
  207. package/src/helpers/calculateHorizontalBarCategoryLabelWidth.test.ts +37 -0
  208. package/src/helpers/calculateHorizontalBarCategoryLabelWidth.ts +3 -2
  209. package/src/helpers/calculateRightYAxisWidth.ts +60 -0
  210. package/src/helpers/categoryOrder.ts +60 -0
  211. package/src/helpers/colorAssignmentHelpers.ts +2 -2
  212. package/src/helpers/createNewChartConfig.ts +56 -0
  213. package/src/helpers/dataDrivenYAxisCategories.ts +18 -0
  214. package/src/helpers/forecastLegend.ts +88 -0
  215. package/src/helpers/getBoxPlotConfig.ts +26 -38
  216. package/src/helpers/getChartTypeDefaultPalette.ts +29 -0
  217. package/src/helpers/getColorCodeCategoryColorMap.ts +26 -0
  218. package/src/helpers/getColorScale.ts +31 -22
  219. package/src/helpers/getComboChartConfig.ts +0 -1
  220. package/src/helpers/getDynamicYAxisCategories.ts +69 -0
  221. package/src/helpers/getExcludedData.ts +0 -1
  222. package/src/helpers/getHasBoundarySuppression.ts +4 -3
  223. package/src/helpers/getMinMax.ts +11 -8
  224. package/src/helpers/getNewRuntime.ts +4 -3
  225. package/src/helpers/getPiePercent.ts +3 -3
  226. package/src/helpers/getStackedSeriesMax.ts +51 -0
  227. package/src/helpers/getV21ChartDistributionColors.ts +57 -0
  228. package/src/helpers/handleRankByValue.ts +15 -15
  229. package/src/helpers/isConvertLineToBarGraph.ts +2 -2
  230. package/src/helpers/seriesColumnSettings.ts +31 -3
  231. package/src/helpers/sizeHelpers.ts +4 -5
  232. package/src/helpers/smallMultiplesHelpers.ts +10 -13
  233. package/src/helpers/tests/applyChartTypeContract.test.ts +37 -0
  234. package/src/helpers/tests/boxPlotStats.test.ts +31 -0
  235. package/src/helpers/tests/bumpChartTooltip.test.ts +29 -0
  236. package/src/helpers/tests/calculateRightYAxisWidth.test.ts +105 -0
  237. package/src/helpers/tests/categoryOrder.test.ts +57 -0
  238. package/src/helpers/tests/countNumOfTicks.test.ts +11 -0
  239. package/src/helpers/tests/createNewChartConfig.test.ts +182 -0
  240. package/src/helpers/tests/getBoxPlotConfig.test.ts +70 -0
  241. package/src/helpers/tests/getColorCodeCategoryColorMap.test.ts +113 -0
  242. package/src/helpers/tests/getColorScale.test.ts +226 -1
  243. package/src/helpers/tests/getDynamicYAxisCategories.test.ts +61 -0
  244. package/src/helpers/tests/getMinMax.test.ts +41 -0
  245. package/src/helpers/tests/getStackedSeriesMax.test.ts +26 -0
  246. package/src/helpers/tests/handleRankByValue.test.ts +55 -37
  247. package/src/helpers/tests/seriesColumnSettings.test.ts +83 -0
  248. package/src/helpers/tests/smallMultiplesHelpers.test.ts +37 -1
  249. package/src/helpers/tests/tooltipHelpers.test.ts +80 -0
  250. package/src/helpers/tooltipHelpers.ts +16 -0
  251. package/src/hooks/tests/useRightAxis.test.tsx +143 -2
  252. package/src/hooks/tests/useScales.test.tsx +3 -6
  253. package/src/hooks/tests/useTooltip.test.tsx +484 -0
  254. package/src/hooks/usePrefersReducedMotion.ts +22 -0
  255. package/src/hooks/useReduceData.ts +4 -36
  256. package/src/hooks/useRightAxis.ts +19 -26
  257. package/src/hooks/useScales.ts +15 -0
  258. package/src/hooks/useTooltip.tsx +106 -71
  259. package/src/scss/main.scss +74 -2
  260. package/src/store/chart.reducer.ts +4 -4
  261. package/src/test/CdcChart.dataTable.test.tsx +582 -14
  262. package/src/test/CdcChart.dendrogram.test.tsx +277 -0
  263. package/src/test/CdcChart.finalization.test.tsx +143 -0
  264. package/src/test/CdcChart.network.test.tsx +271 -0
  265. package/src/types/ChartConfig.ts +91 -54
  266. package/src/types/ChartContext.ts +5 -0
  267. package/src/types/Horizon.ts +1 -1
  268. package/LICENSE +0 -201
  269. package/dist/cdcchart-BWVIUcAF.es.js +0 -4802
  270. package/src/_stories/Chart.Sankey.smoke.stories.tsx +0 -62
  271. package/src/components/Sankey/components/ColumnList.tsx +0 -19
  272. package/src/components/Sankey/helpers/getSankeyTooltip.tsx +0 -34
  273. package/src/components/Sankey/useSankeyAlert.tsx +0 -60
  274. package/src/data/legacy-defaults.ts +0 -18
  275. package/src/helpers/ensureSpecialChartAxisTypes.ts +0 -11
  276. package/src/helpers/tests/ensureSpecialChartAxisTypes.test.ts +0 -30
@@ -13,8 +13,10 @@ 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'
19
+ import CustomSortOrder from '@cdc/core/components/EditorPanel/CustomSortOrder'
18
20
  import DataTableEditor from '@cdc/core/components/EditorPanel/DataTableEditor'
19
21
  import GroupedList from '@cdc/core/components/EditorPanel/GroupedList'
20
22
  import VizFilterEditor from '@cdc/core/components/EditorPanel/VizFilterEditor'
@@ -29,14 +31,13 @@ import { useDataColumns } from '@cdc/core/hooks/useDataColumns'
29
31
 
30
32
  // chart components
31
33
  import Panels from './components/Panels'
32
- import PaletteConversionModal from '@cdc/core/components/PaletteConversionModal'
34
+ import PaletteConversionModal, { V21_PALETTE_CONVERSION_MESSAGE } from '@cdc/core/components/PaletteConversionModal'
33
35
 
34
36
  // cdc additional
35
37
  import { useEditorPermissions } from './useEditorPermissions'
36
38
  import { useHighlightedBars } from '../../hooks/useHighlightedBars'
37
39
  import ConfigContext from '../../ConfigContext'
38
40
  import useReduceData from '../../hooks/useReduceData'
39
- import useRightAxis from '../../hooks/useRightAxis'
40
41
  import WarningImage from '../../images/warning.svg'
41
42
  import getMinMax from '../../helpers/getMinMax'
42
43
 
@@ -61,9 +62,12 @@ import { paletteMigrationMap, twoColorPaletteMigrationMap } from '@cdc/core/help
61
62
  import { isV1Palette, migratePaletteWithMap } from '@cdc/core/helpers/palettes/utils'
62
63
  import { USE_V2_MIGRATION } from '@cdc/core/helpers/constants'
63
64
  import { getSeriesOwnedColumnNames } from '../../helpers/seriesColumnSettings'
65
+ import { getOrderedCategoryValues } from '../../helpers/categoryOrder'
64
66
  import {
65
67
  HEATMAP_CONFIG_DEFAULTS,
68
+ MAX_HEATMAP_COLUMN_WIDTH,
66
69
  MAX_HEATMAP_COLOR_BUCKETS,
70
+ MIN_HEATMAP_COLUMN_WIDTH,
67
71
  MIN_HEATMAP_COLOR_BUCKETS
68
72
  } from '../HeatMap/heatmap.constants'
69
73
 
@@ -128,6 +132,7 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
128
132
  let preliminaryData = config.preliminaryData ? [...config.preliminaryData] : []
129
133
  const defaultValues = {
130
134
  type: defaultType,
135
+ lineEffectScope: 'outgoing',
131
136
  seriesKeys: [],
132
137
  label: 'Suppressed',
133
138
  column: '',
@@ -156,7 +161,10 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
156
161
  preliminaryData = [...config.preliminaryData]
157
162
  }
158
163
 
159
- preliminaryData[i][fieldName] = value
164
+ preliminaryData[i] = { ...preliminaryData[i], [fieldName]: value }
165
+ if (fieldName === 'lineEffectScope' && value === '') {
166
+ delete preliminaryData[i].lineEffectScope
167
+ }
160
168
  if (fieldName === 'symbol') {
161
169
  preliminaryData[i]['iconCode'] = symbolCodes[value]
162
170
  }
@@ -199,6 +207,7 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
199
207
  value,
200
208
  hideBarSymbol,
201
209
  hideLineStyle,
210
+ lineEffectScope,
202
211
  weight
203
212
  },
204
213
  i
@@ -508,6 +517,34 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
508
517
  updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
509
518
  />
510
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
+ )}
511
548
  {style && !style.includes('Circles') && (
512
549
  <TextField
513
550
  type='number'
@@ -558,20 +595,27 @@ interface CategoricalAxisProps {
558
595
 
559
596
  type AxisAnchorEditorProps = {
560
597
  axisKey: 'xAxis' | 'yAxis'
598
+ anchorField?: 'anchors' | 'rightAnchors'
561
599
  config: ChartConfig
562
600
  lineOptions: { value: string; label?: string }[]
563
601
  updateConfig: Function
564
602
  }
565
603
 
566
- const AxisAnchorEditor: React.FC<AxisAnchorEditorProps> = ({ axisKey, config, lineOptions, updateConfig }) => {
567
- 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] || []
568
612
 
569
613
  const updateAnchors = (nextAnchors: Anchor[]) => {
570
614
  updateConfig({
571
615
  ...config,
572
616
  [axisKey]: {
573
617
  ...config[axisKey],
574
- anchors: nextAnchors
618
+ [anchorField]: nextAnchors
575
619
  }
576
620
  })
577
621
  }
@@ -607,13 +651,17 @@ const AxisAnchorEditor: React.FC<AxisAnchorEditorProps> = ({ axisKey, config, li
607
651
  <GroupedList
608
652
  items={anchors}
609
653
  label='Anchors'
610
- droppableId={`${axisKey}-anchors-order`}
654
+ droppableId={`${axisKey}-${anchorField}-order`}
611
655
  onDragEnd={({ source, destination }) => {
612
656
  if (!destination || source.index === destination.index) return
613
657
  reorderAnchors(source.index, destination.index)
614
658
  }}
615
659
  renderItem={(anchor, index) => (
616
- <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
+ >
617
665
  {(provided, snapshot) => (
618
666
  <div
619
667
  ref={provided.innerRef}
@@ -709,6 +757,38 @@ const AxisAnchorEditor: React.FC<AxisAnchorEditorProps> = ({ axisKey, config, li
709
757
  }
710
758
 
711
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
+
712
792
  const maxHeight = config?.yAxis?.maxValue
713
793
 
714
794
  const totalEnteredHeight =
@@ -762,6 +842,44 @@ const CategoricalAxis: React.FC<CategoricalAxisProps> = ({ config, updateConfig,
762
842
  return <></>
763
843
  }
764
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
+
765
883
  return (
766
884
  <>
767
885
  {config.yAxis.type === 'categorical' &&
@@ -858,7 +976,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
858
976
  handleShowAll,
859
977
  dimensions
860
978
  } = useContext<ChartContext>(ConfigContext)
861
-
979
+ const isBarRace = config.visualizationType === 'Bar' && config.visualizationSubType === 'racing'
862
980
  const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
863
981
  const properties = {
864
982
  data,
@@ -898,6 +1016,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
898
1016
  visSupportsPreliminaryData,
899
1017
  visSupportsRankByValue,
900
1018
  visSupportsResponsiveTicks,
1019
+ visSupportsRightValueAxis,
901
1020
  visSupportsValueAxisGridLines,
902
1021
  visSupportsValueAxisLabels,
903
1022
  visSupportsValueAxisLine,
@@ -919,7 +1038,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
919
1038
  ...series,
920
1039
  type:
921
1040
  config.visualizationType === 'Combo' ? 'Bar' : config.visualizationType ? config.visualizationType : 'Bar',
922
- axis: 'Left'
1041
+ axis: 'Left',
1042
+ tooltip: series.tooltip ?? true
923
1043
  }
924
1044
  })
925
1045
  }
@@ -949,8 +1069,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
949
1069
  }
950
1070
  }, [config.visualizationType])
951
1071
 
952
- const { hasRightAxis } = useRightAxis({ config: config, yMax: 0, data: config.data, updateConfig })
953
-
954
1072
  const getItemStyle = (isDragging, draggableStyle) => ({
955
1073
  ...draggableStyle
956
1074
  })
@@ -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
  }
@@ -1059,6 +1183,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1059
1183
  xAxis: {
1060
1184
  ...config.xAxis,
1061
1185
  dataKey: newValue,
1186
+ categoryOrder: [],
1187
+ categoryOrderType: 'data',
1062
1188
  ...(autoDetectedDateParseFormat ? { dateParseFormat: autoDetectedDateParseFormat } : {})
1063
1189
  }
1064
1190
  }
@@ -1141,7 +1267,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1141
1267
  }
1142
1268
 
1143
1269
  const addNewExclusion = exclusionKey => {
1144
- let newExclusion = [...config.exclusions.keys]
1270
+ let newExclusion = [...(config.exclusions?.keys ?? [])]
1145
1271
  newExclusion.push(exclusionKey)
1146
1272
 
1147
1273
  let payload = { ...config.exclusions, keys: newExclusion }
@@ -1150,7 +1276,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1150
1276
 
1151
1277
  const removeExclusion = excludeValue => {
1152
1278
  let exclusionsIndex = -1
1153
- let exclusions = [...config.exclusions.keys]
1279
+ let exclusions = [...(config.exclusions?.keys ?? [])]
1154
1280
 
1155
1281
  for (let i = 0; i < exclusions.length; i++) {
1156
1282
  if (exclusions[i] === excludeValue) {
@@ -1165,10 +1291,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1165
1291
  let newExclusions = { ...config.exclusions, keys: exclusions }
1166
1292
  let newExclusionsPayload = { ...config, exclusions: newExclusions }
1167
1293
 
1168
- if (exclusions.length === 0) {
1169
- delete newExclusionsPayload.exclusions.keys
1170
- }
1171
-
1172
1294
  updateConfig(newExclusionsPayload)
1173
1295
  }
1174
1296
  }
@@ -1289,6 +1411,58 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1289
1411
  return getDataValues(dataKey, true).filter(value => !excludedKeys.includes(String(value)))
1290
1412
  }
1291
1413
 
1414
+ const categoryOrderValues = useMemo(
1415
+ () =>
1416
+ getOrderedCategoryValues(
1417
+ excludedData as Record<string, any>[],
1418
+ config.xAxis?.dataKey,
1419
+ config.xAxis?.categoryOrder
1420
+ ),
1421
+ [excludedData, config.xAxis?.dataKey, config.xAxis?.categoryOrder]
1422
+ )
1423
+
1424
+ const updateCategoryOrderType = (categoryOrderType: 'data' | 'custom') => {
1425
+ updateConfig({
1426
+ ...config,
1427
+ xAxis: {
1428
+ ...config.xAxis,
1429
+ categoryOrderType,
1430
+ categoryOrder: categoryOrderType === 'custom' ? categoryOrderValues : []
1431
+ }
1432
+ })
1433
+ }
1434
+
1435
+ const renderCategoryOrderControls = (label = 'Category Order') => {
1436
+ if (config.xAxis?.type !== 'categorical' || !config.xAxis?.dataKey || !categoryOrderValues.length) return null
1437
+
1438
+ return (
1439
+ <>
1440
+ <Select
1441
+ value={config.xAxis.categoryOrderType || 'data'}
1442
+ section='xAxis'
1443
+ fieldName='categoryOrderType'
1444
+ label={label}
1445
+ options={[
1446
+ { label: 'Data order', value: 'data' },
1447
+ { label: 'Custom', value: 'custom' }
1448
+ ]}
1449
+ updateField={(_section, _subsection, _fieldName, value) => updateCategoryOrderType(value)}
1450
+ />
1451
+ {config.xAxis.categoryOrderType === 'custom' && (
1452
+ <CustomSortOrder
1453
+ column={config.xAxis.dataKey}
1454
+ data={excludedData as Record<string, any>[]}
1455
+ customOrder={config.xAxis.categoryOrder}
1456
+ updateField={updateFieldDeprecated}
1457
+ updateTarget={{ section: 'xAxis', subsection: null, fieldName: 'categoryOrder' }}
1458
+ droppableId='category_order'
1459
+ draggableIdPrefix='categoryOrder'
1460
+ />
1461
+ )}
1462
+ </>
1463
+ )
1464
+ }
1465
+
1292
1466
  // prettier-ignore
1293
1467
  const {
1294
1468
  highlightedBarValues,
@@ -1301,34 +1475,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1301
1475
  handleUpdateHighlightedBorderWidth
1302
1476
  } = useHighlightedBars(config, updateConfig)
1303
1477
 
1304
- // when the orientation changes, swap x and y axis anchors
1305
- useEffect(() => {
1306
- const prevXAnchors = config.xAxis.anchors.length > 0 ? config.xAxis.anchors : []
1307
- const prevYAnchors = config.yAxis.anchors.length > 0 ? config.yAxis.anchors : []
1308
-
1309
- updateConfig({
1310
- ...config,
1311
- xAxis: {
1312
- ...config.xAxis,
1313
- anchors: prevYAnchors
1314
- },
1315
- yAxis: {
1316
- ...config.yAxis,
1317
- anchors: prevXAnchors
1318
- }
1319
- })
1320
- }, [config.orientation])
1321
-
1322
- // Set paired bars to be horizontal, even though that option doesn't display
1323
- useEffect(() => {
1324
- if (config.visualizationType === 'Paired Bar') {
1325
- updateConfig({
1326
- ...config,
1327
- orientation: 'horizontal'
1328
- })
1329
- }
1330
- }, []) // eslint-disable-line
1331
-
1332
1478
  useEffect(() => {
1333
1479
  if (config.orientation === 'horizontal') {
1334
1480
  updateConfig({
@@ -1338,15 +1484,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1338
1484
  }
1339
1485
  }, [config.isLollipopChart, config.lollipopShape]) // eslint-disable-line
1340
1486
 
1341
- /// temporary force orientation untill we support Vartical deviaton bar
1342
- useEffect(() => {
1343
- if (config.visualizationType === 'Deviation Bar') {
1344
- updateConfig({ ...config, orientation: 'horizontal' })
1345
- }
1346
- }, [config.visualizationType])
1347
-
1348
1487
  const ExclusionsList = useCallback(() => {
1349
- const exclusions = [...config.exclusions.keys]
1488
+ const exclusions = [...(config.exclusions?.keys ?? [])]
1350
1489
  return (
1351
1490
  <ul className='series-list'>
1352
1491
  {exclusions.map((exclusion, index) => {
@@ -1409,6 +1548,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1409
1548
 
1410
1549
  // Check if it's a v1 palette configuration
1411
1550
  const isV1PaletteConfig = isV1Palette(config)
1551
+ const shouldUpgradePalette = USE_V2_MIGRATION && (isV1PaletteConfig || config.general?.palette?.version === '2.0')
1412
1552
 
1413
1553
  const executeSelection = () => {
1414
1554
  const _newConfig = cloneConfig(config)
@@ -1424,14 +1564,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1424
1564
  // V2 migration logic
1425
1565
  const migratedName = palette ? migratePaletteWithMap(palette, paletteMigrationMap, false) : undefined
1426
1566
  _newConfig.general.palette.name = migratedName
1427
- if (isV1PaletteConfig) {
1428
- _newConfig.general.palette.version = '2.0'
1567
+ if (shouldUpgradePalette) {
1568
+ _newConfig.general.palette.version = '2.1'
1429
1569
  }
1430
1570
  }
1431
1571
  updateConfig(_newConfig)
1432
1572
  }
1433
1573
 
1434
- if (isV1PaletteConfig) {
1574
+ if (shouldUpgradePalette) {
1435
1575
  setPendingPaletteSelection({ palette, action: executeSelection, type: 'general' })
1436
1576
  setShowConversionModal(true)
1437
1577
  } else {
@@ -1485,7 +1625,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1485
1625
  if (!_newConfig.general.palette) {
1486
1626
  _newConfig.general.palette = {}
1487
1627
  }
1488
- _newConfig.general.palette.version = '2.0'
1628
+ _newConfig.general.palette.version = '2.1'
1489
1629
 
1490
1630
  // Create backup for rollback functionality (consistent with standard format)
1491
1631
  if (!_newConfig.general.palette.backups) {
@@ -1541,7 +1681,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1541
1681
  if (!_newConfig.general.palette) {
1542
1682
  _newConfig.general.palette = {}
1543
1683
  }
1544
- _newConfig.general.palette.version = '2.0'
1684
+ _newConfig.general.palette.version = '2.1'
1545
1685
 
1546
1686
  // Forecast-specific migration map for v1 → v2 palette names (all lowercase-hyphen format)
1547
1687
  const forecastPaletteMigrationMap: Record<string, string> = {
@@ -1666,15 +1806,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1666
1806
  _newConfig.general.palette.name = palette
1667
1807
  }
1668
1808
 
1669
- // Set version to V1
1809
+ // Keep the current palette version
1670
1810
  if (!_newConfig.general) {
1671
1811
  _newConfig.general = {}
1672
1812
  }
1673
1813
  if (!_newConfig.general.palette) {
1674
1814
  _newConfig.general.palette = {}
1675
1815
  }
1676
- _newConfig.general.palette.version = '1.0'
1677
-
1816
+ _newConfig.general.palette.version = config.general?.palette?.version || '1.0'
1678
1817
  updateConfig(_newConfig)
1679
1818
  }
1680
1819
  setShowConversionModal(false)
@@ -1994,6 +2133,25 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1994
2133
  label='Show Cell Values'
1995
2134
  updateField={updateFieldDeprecated}
1996
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
+ )}
1997
2155
  <TextField
1998
2156
  value={config.heatmap?.cellPadding ?? HEATMAP_CONFIG_DEFAULTS.cellPadding}
1999
2157
  type='number'
@@ -2002,6 +2160,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2002
2160
  fieldName='cellPadding'
2003
2161
  label='Cell Padding'
2004
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
+ }
2005
2171
  />
2006
2172
  <TextField
2007
2173
  value={config.heatmap?.rowLabelGap ?? HEATMAP_CONFIG_DEFAULTS.rowLabelGap}
@@ -2067,16 +2233,21 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2067
2233
  <Panels.General name='General' />
2068
2234
  <Panels.ForestPlot name='Forest Plot Settings' />
2069
2235
  <Panels.Sankey name='Sankey' />
2236
+ <Panels.Network name='Network' />
2237
+ <Panels.Dendrogram name='Dendrogram' />
2070
2238
  {config.visualizationType !== 'Pie' &&
2071
2239
  config.visualizationType !== 'Forest Plot' &&
2072
- config.visualizationType !== 'Sankey' && (
2240
+ !['Sankey', 'Network', 'Dendrogram'].includes(config.visualizationType) && (
2073
2241
  <AccordionItem>
2074
2242
  <AccordionItemHeading>
2075
- <AccordionItemButton>
2243
+ <AccordionItemButton data-required-field-section='data-series'>
2076
2244
  Data Series{' '}
2077
2245
  {(!config.series ||
2078
2246
  config.series.length === 0 ||
2079
- (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)) &&
2080
2251
  !config.dynamicSeries &&
2081
2252
  config.visualizationType !== 'HeatMap' && (
2082
2253
  <WarningImage width='25' className='warning-icon' />
@@ -2126,25 +2297,31 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2126
2297
  {(!config.series || config.series.length === 0) &&
2127
2298
  !config.dynamicSeries &&
2128
2299
  config.visualizationType !== 'Paired Bar' &&
2129
- config.visualizationType !== 'HeatMap' && (
2130
- <p className='warning'>At least one series is required</p>
2131
- )}
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
+ )}
2132
2309
  {(!config.series || config.series.length === 0) &&
2133
2310
  !config.dynamicSeries &&
2134
2311
  config.visualizationType === 'HeatMap' && (
2135
2312
  <p className='warning'>At least one series is required</p>
2136
2313
  )}
2137
- {(!config.series || config.series.length === 0 || config.series.length < 2) &&
2138
- config.visualizationType === 'Paired Bar' && (
2139
- <p className='warning'>
2140
- Select two data series for paired bar chart (e.g., Male and Female).
2141
- </p>
2142
- )}
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
+ )}
2143
2319
  <>
2144
2320
  <Select
2145
2321
  fieldName='visualizationType'
2146
2322
  label='Add Data Series'
2147
2323
  aria-label='Add Data Series'
2324
+ data-required-field-control='data-series'
2148
2325
  initial='Select'
2149
2326
  onChange={e => {
2150
2327
  if (e.target.value !== '' && e.target.value !== 'Select') {
@@ -2251,7 +2428,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2251
2428
  {visSupportsLeftValueAxis() && (
2252
2429
  <AccordionItem>
2253
2430
  <AccordionItemHeading>
2254
- <AccordionItemButton>
2431
+ <AccordionItemButton
2432
+ data-required-field-section={config.visualizationType === 'Pie' ? 'pie-data-column' : undefined}
2433
+ >
2255
2434
  {config.visualizationType === 'Pie'
2256
2435
  ? 'Data Format'
2257
2436
  : config.orientation === 'vertical'
@@ -2270,6 +2449,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2270
2449
  section='yAxis'
2271
2450
  fieldName='dataKey'
2272
2451
  label='Data Column'
2452
+ data-required-field-control='pie-data-column'
2273
2453
  initial='Select'
2274
2454
  required={true}
2275
2455
  updateField={updateFieldDeprecated}
@@ -2386,29 +2566,57 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2386
2566
  />
2387
2567
  </>
2388
2568
  )}
2389
- {config.visualizationType !== 'Pie' && config.visualizationType !== 'HeatMap' && (
2569
+ {!isBarRace && config.visualizationType !== 'Pie' && config.visualizationType !== 'HeatMap' && (
2390
2570
  <>
2391
2571
  <Select
2392
2572
  label='Axis Type'
2393
- 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
+ }
2394
2580
  options={[
2395
2581
  { value: 'linear', label: 'Numeric (Linear Scale)' },
2396
2582
  ...(config.visualizationSubType !== 'stacked'
2397
2583
  ? [{ value: 'logarithmic', label: 'Numeric (Logarithmic Scale)' }]
2398
2584
  : []),
2399
2585
  ...(config.orientation !== 'horizontal'
2400
- ? [{ value: 'categorical', label: 'Categorical' }]
2586
+ ? [
2587
+ { value: 'categorical', label: 'Categorical' },
2588
+ { value: 'categorical-data-driven', label: 'Categorical (Data-Driven)' }
2589
+ ]
2401
2590
  : [])
2402
2591
  ]}
2403
2592
  section='yAxis'
2404
2593
  fieldName='type'
2405
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
+
2406
2617
  updateConfig({
2407
2618
  ...config,
2408
- yAxis: {
2409
- ...config.yAxis,
2410
- type: value
2411
- }
2619
+ yAxis: nextYAxis
2412
2620
  })
2413
2621
  }}
2414
2622
  tooltip={
@@ -2417,8 +2625,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2417
2625
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2418
2626
  </Tooltip.Target>
2419
2627
  <Tooltip.Content>
2420
- Select 'Numeric (Linear Scale)' for uniform scaling, 'Numeric (Logarithmic Scale)' for
2421
- 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.
2422
2630
  </Tooltip.Content>
2423
2631
  </Tooltip>
2424
2632
  }
@@ -2437,20 +2645,28 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2437
2645
  fieldName='label'
2438
2646
  label='Label'
2439
2647
  updateField={updateFieldDeprecated}
2440
- maxLength={config.yAxis.titlePlacement === 'side' ? 35 : undefined}
2648
+ maxLength={
2649
+ config.orientation === 'horizontal' || config.yAxis.titlePlacement === 'side'
2650
+ ? 35
2651
+ : undefined
2652
+ }
2441
2653
  tooltip={
2442
2654
  <Tooltip style={{ textTransform: 'none' }}>
2443
2655
  <Tooltip.Target>
2444
2656
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2445
2657
  </Tooltip.Target>
2446
2658
  <Tooltip.Content>
2447
- <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>
2448
2664
  </Tooltip.Content>
2449
2665
  </Tooltip>
2450
2666
  }
2451
2667
  />
2452
2668
  <Select
2453
- display={!visHasCategoricalAxis()}
2669
+ display={config.orientation !== 'horizontal' && !visHasCategoricalAxis()}
2454
2670
  value={config.yAxis.titlePlacement}
2455
2671
  section='yAxis'
2456
2672
  fieldName='titlePlacement'
@@ -2613,7 +2829,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2613
2829
  }
2614
2830
  />
2615
2831
  <CheckBox
2616
- display={!visHasCategoricalAxis()}
2832
+ display={!isBarRace && !visHasCategoricalAxis()}
2617
2833
  value={config.dataFormat.abbreviated}
2618
2834
  section='dataFormat'
2619
2835
  fieldName='abbreviated'
@@ -2741,273 +2957,100 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2741
2957
  }
2742
2958
  />
2743
2959
  </div>
2744
- {config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
2745
- <>
2746
- {visSupportsValueAxisLine() && (
2747
- <CheckBox
2748
- value={config.xAxis.hideAxis}
2749
- section='xAxis'
2750
- fieldName='hideAxis'
2751
- label='Hide Axis'
2752
- updateField={updateFieldDeprecated}
2753
- />
2754
- )}
2755
- {visSupportsValueAxisLabels() && (
2756
- <CheckBox
2757
- value={config.xAxis.hideLabel}
2758
- section='xAxis'
2759
- fieldName='hideLabel'
2760
- label='Hide Tick Labels'
2761
- updateField={updateFieldDeprecated}
2762
- />
2763
- )}
2764
- {visSupportsValueAxisTicks() && (
2765
- <CheckBox
2766
- value={config.xAxis.hideTicks}
2767
- section='xAxis'
2768
- fieldName='hideTicks'
2769
- label='Hide Ticks'
2770
- updateField={updateFieldDeprecated}
2771
- />
2772
- )}
2773
- <div className='axis-domain-group'>
2774
- <span className='axis-domain-group__title'>Value Axis Domain</span>
2775
- <div className='axis-domain-group__row'>
2776
- {visSupportsValueAxisMax() && (
2777
- <div className='axis-domain-group__field'>
2778
- <TextField
2779
- value={config.xAxis.max}
2780
- section='xAxis'
2781
- fieldName='max'
2782
- label='axis max value'
2783
- type='number'
2784
- placeholder='Auto'
2785
- className='axis-domain-number'
2786
- updateField={updateFieldDeprecated}
2787
- />
2788
- <span className='axis-domain-warning'>{warningMsg.maxMsg}</span>
2789
- </div>
2790
- )}
2791
- {visSupportsValueAxisMin() && (
2792
- <div className='axis-domain-group__field'>
2793
- <TextField
2794
- value={config.xAxis.min}
2795
- section='xAxis'
2796
- fieldName='min'
2797
- type='number'
2798
- label='axis min value'
2799
- placeholder='Auto'
2800
- className='axis-domain-number'
2801
- updateField={updateFieldDeprecated}
2802
- />
2803
- <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
2804
- </div>
2805
- )}
2806
- </div>
2807
- {config.visualizationType === 'Deviation Bar' && (
2808
- <TextField
2809
- 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}
2810
2966
  section='xAxis'
2811
- fieldName='target'
2812
- type='number'
2813
- label='Deviation point'
2814
- placeholder='Auto'
2815
- className='axis-domain-number'
2967
+ fieldName='hideAxis'
2968
+ label='Hide Axis'
2816
2969
  updateField={updateFieldDeprecated}
2817
2970
  />
2818
2971
  )}
2819
- <TextField
2820
- value={config.yAxis.smallestLeftAxisMax}
2821
- section='yAxis'
2822
- fieldName='smallestLeftAxisMax'
2823
- type='number'
2824
- label='Smallest axis maximum'
2825
- placeholder='Auto'
2826
- className='axis-domain-number'
2827
- tooltip={
2828
- <Tooltip style={{ textTransform: 'none' }}>
2829
- <Tooltip.Target>
2830
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2831
- </Tooltip.Target>
2832
- <Tooltip.Content>
2833
- <p>
2834
- Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
2835
- 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
2836
- </p>
2837
- </Tooltip.Content>
2838
- </Tooltip>
2839
- }
2840
- updateField={updateFieldDeprecated}
2841
- />
2842
- {visSupportsAutoMaxStrategy() && (
2843
- <Select
2844
- value={config.yAxis.autoMaxStrategy || 'default'}
2845
- section='yAxis'
2846
- fieldName='autoMaxStrategy'
2847
- label='Automatic max strategy'
2972
+ {visSupportsValueAxisLabels() && (
2973
+ <CheckBox
2974
+ value={config.xAxis.hideLabel}
2975
+ section='xAxis'
2976
+ fieldName='hideLabel'
2977
+ label='Hide Tick Labels'
2848
2978
  updateField={updateFieldDeprecated}
2849
- options={[
2850
- { value: 'default', label: 'Default' },
2851
- { value: 'clean-top-tick', label: 'Clean top tick' }
2852
- ]}
2853
- tooltip={
2854
- <Tooltip style={{ textTransform: 'none' }}>
2855
- <Tooltip.Target>
2856
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2857
- </Tooltip.Target>
2858
- <Tooltip.Content>
2859
- {config.visualizationType === 'Combo' ? (
2860
- <p>
2861
- Clean top tick rounds automatic left and right axis maximums up to cleaner
2862
- tick steps before axis padding is applied.
2863
- </p>
2864
- ) : (
2865
- <p>
2866
- Clean top tick rounds the automatic value axis maximum up to a cleaner tick
2867
- step before axis padding is applied.
2868
- </p>
2869
- )}
2870
- </Tooltip.Content>
2871
- </Tooltip>
2872
- }
2873
2979
  />
2874
2980
  )}
2875
- {visSupportsFilterDomainBehavior() && (
2876
- <Select
2877
- value={config.yAxis.filterDomainBehavior || 'dynamic'}
2878
- section='yAxis'
2879
- fieldName='filterDomainBehavior'
2880
- label='Filter Domain Behavior'
2981
+ {visSupportsValueAxisTicks() && (
2982
+ <CheckBox
2983
+ value={config.xAxis.hideTicks}
2984
+ section='xAxis'
2985
+ fieldName='hideTicks'
2986
+ label='Hide Ticks'
2881
2987
  updateField={updateFieldDeprecated}
2882
- options={[
2883
- { value: 'dynamic', label: 'Dynamic' },
2884
- { value: 'stable', label: 'Stable' }
2885
- ]}
2988
+ />
2989
+ )}
2990
+ <div className='axis-domain-group'>
2991
+ <span className='axis-domain-group__title'>Value Axis Domain</span>
2992
+ <div className='axis-domain-group__row'>
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
+ )}
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
+ )}
3036
+ <TextField
3037
+ value={config.yAxis.smallestLeftAxisMax}
3038
+ section='yAxis'
3039
+ fieldName='smallestLeftAxisMax'
3040
+ type='number'
3041
+ label='Smallest axis maximum'
3042
+ placeholder='Auto'
3043
+ className='axis-domain-number'
2886
3044
  tooltip={
2887
3045
  <Tooltip style={{ textTransform: 'none' }}>
2888
3046
  <Tooltip.Target>
2889
3047
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2890
3048
  </Tooltip.Target>
2891
3049
  <Tooltip.Content>
2892
- {config.visualizationType === 'Combo' ? (
2893
- <p>
2894
- Dynamic rescales the value axes to the currently filtered data. Stable keeps
2895
- the left and right axes based on the full eligible dataset while still
2896
- rendering filtered rows.
2897
- </p>
2898
- ) : (
2899
- <p>
2900
- Dynamic rescales the value axis to the currently filtered data. Stable keeps
2901
- the value axis based on the full eligible dataset while still rendering
2902
- filtered rows.
2903
- </p>
2904
- )}
2905
- </Tooltip.Content>
2906
- </Tooltip>
2907
- }
2908
- />
2909
- )}
2910
- </div>
2911
- {config.visualizationType === 'Deviation Bar' && (
2912
- <>
2913
- <TextField
2914
- value={config.xAxis.targetLabel || 'Target'}
2915
- section='xAxis'
2916
- fieldName='targetLabel'
2917
- type='text'
2918
- label='Deviation point Label'
2919
- updateField={updateFieldDeprecated}
2920
- />
2921
- <CheckBox
2922
- value={config.xAxis.showTargetLabel}
2923
- section='xAxis'
2924
- fieldName='showTargetLabel'
2925
- label='Show Deviation point label'
2926
- updateField={updateFieldDeprecated}
2927
- />
2928
- </>
2929
- )}
2930
- </>
2931
- ) : (
2932
- config.visualizationType !== 'Pie' &&
2933
- config.visualizationType !== 'HeatMap' && (
2934
- <>
2935
- <CheckBox
2936
- display={!visHasCategoricalAxis()}
2937
- value={config.yAxis.hideAxis}
2938
- section='yAxis'
2939
- fieldName='hideAxis'
2940
- label='Hide Axis'
2941
- updateField={updateFieldDeprecated}
2942
- />
2943
- <CheckBox
2944
- display={!visHasCategoricalAxis()}
2945
- value={config.yAxis.hideLabel}
2946
- section='yAxis'
2947
- fieldName='hideLabel'
2948
- label='Hide Tick Labels'
2949
- updateField={updateFieldDeprecated}
2950
- />
2951
- <CheckBox
2952
- display={!visHasCategoricalAxis()}
2953
- value={config.yAxis.hideTicks}
2954
- section='yAxis'
2955
- fieldName='hideTicks'
2956
- label='Hide Ticks'
2957
- updateField={updateFieldDeprecated}
2958
- />
2959
-
2960
- <div className='axis-domain-group'>
2961
- <span className='axis-domain-group__title'>Value Axis Domain</span>
2962
- <div className='axis-domain-group__row'>
2963
- <div className='axis-domain-group__field'>
2964
- <TextField
2965
- value={config.yAxis.max}
2966
- section='yAxis'
2967
- fieldName='max'
2968
- type='number'
2969
- label='axis max value'
2970
- placeholder='Auto'
2971
- className='axis-domain-number'
2972
- updateField={updateFieldDeprecated}
2973
- />
2974
- <span className='axis-domain-warning'>{warningMsg.maxMsg}</span>
2975
- </div>
2976
- {config.visualizationType !== 'Area Chart' &&
2977
- config.visualizationSubType !== 'stacked' && (
2978
- <div className='axis-domain-group__field'>
2979
- <TextField
2980
- value={config.yAxis.min}
2981
- section='yAxis'
2982
- fieldName='min'
2983
- type='number'
2984
- label='axis min value'
2985
- placeholder='Auto'
2986
- className='axis-domain-number'
2987
- updateField={updateFieldDeprecated}
2988
- />
2989
- <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
2990
- </div>
2991
- )}
2992
- </div>
2993
- <TextField
2994
- value={config.yAxis.smallestLeftAxisMax}
2995
- section='yAxis'
2996
- fieldName='smallestLeftAxisMax'
2997
- type='number'
2998
- label='Smallest axis maximum'
2999
- placeholder='Auto'
3000
- className='axis-domain-number'
3001
- tooltip={
3002
- <Tooltip style={{ textTransform: 'none' }}>
3003
- <Tooltip.Target>
3004
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3005
- </Tooltip.Target>
3006
- <Tooltip.Content>
3007
- <p>
3008
- Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
3009
- 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
3010
- </p>
3050
+ <p>
3051
+ Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
3052
+ 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
3053
+ </p>
3011
3054
  </Tooltip.Content>
3012
3055
  </Tooltip>
3013
3056
  }
@@ -3081,30 +3124,203 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3081
3124
  }
3082
3125
  />
3083
3126
  )}
3084
- {visSupportsYPadding() && (
3127
+ </div>
3128
+ {config.visualizationType === 'Deviation Bar' && (
3129
+ <>
3130
+ <TextField
3131
+ value={config.xAxis.targetLabel || 'Target'}
3132
+ section='xAxis'
3133
+ fieldName='targetLabel'
3134
+ type='text'
3135
+ label='Deviation point Label'
3136
+ updateField={updateFieldDeprecated}
3137
+ />
3085
3138
  <CheckBox
3086
- value={config.yAxis.enablePadding}
3087
- section='yAxis'
3088
- fieldName='enablePadding'
3089
- label='Add Padding to Value Axis Scale'
3139
+ value={config.xAxis.showTargetLabel}
3140
+ section='xAxis'
3141
+ fieldName='showTargetLabel'
3142
+ label='Show Deviation point label'
3090
3143
  updateField={updateFieldDeprecated}
3091
3144
  />
3092
- )}
3093
- {config.yAxis.enablePadding && visSupportsYPadding() && (
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>
3094
3209
  <TextField
3095
- type='number'
3210
+ value={config.yAxis.smallestLeftAxisMax}
3096
3211
  section='yAxis'
3097
- fieldName='scalePadding'
3098
- label='Padding Percentage'
3212
+ fieldName='smallestLeftAxisMax'
3213
+ type='number'
3214
+ label='Smallest axis maximum'
3215
+ placeholder='Auto'
3099
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
+ }
3100
3230
  updateField={updateFieldDeprecated}
3101
- value={config.yAxis.scalePadding}
3102
3231
  />
3103
- )}
3104
- </div>
3105
- </>
3106
- )
3107
- )}
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
+ ))}
3108
3324
  {/* start: anchors */}
3109
3325
  {visHasAnchors() && config.orientation !== 'horizontal' && (
3110
3326
  <AxisAnchorEditor
@@ -3127,7 +3343,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3127
3343
  </AccordionItem>
3128
3344
  )}
3129
3345
  {/* Right Value Axis Settings */}
3130
- {hasRightAxis && (
3346
+ {visSupportsRightValueAxis() && (
3131
3347
  <AccordionItem>
3132
3348
  <AccordionItemHeading>
3133
3349
  <AccordionItemButton>Right Value Axis</AccordionItemButton>
@@ -3139,18 +3355,29 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3139
3355
  fieldName='rightLabel'
3140
3356
  label='Label'
3141
3357
  updateField={updateFieldDeprecated}
3142
- maxLength={35}
3358
+ maxLength={config.yAxis.rightTitlePlacement === 'side' ? 35 : undefined}
3143
3359
  tooltip={
3144
3360
  <Tooltip style={{ textTransform: 'none' }}>
3145
3361
  <Tooltip.Target>
3146
3362
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3147
3363
  </Tooltip.Target>
3148
3364
  <Tooltip.Content>
3149
- <p>35 character limit</p>
3365
+ <p>35 character limit when Label Placement is Side</p>
3150
3366
  </Tooltip.Content>
3151
3367
  </Tooltip>
3152
3368
  }
3153
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
+ />
3154
3381
  <TextField
3155
3382
  value={config.yAxis.rightNumTicks}
3156
3383
  placeholder='Auto'
@@ -3161,24 +3388,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3161
3388
  className='number-narrow'
3162
3389
  updateField={updateFieldDeprecated}
3163
3390
  />
3164
- <TextField
3165
- value={config.yAxis.rightAxisSize}
3166
- type='number'
3167
- section='yAxis'
3168
- fieldName='rightAxisSize'
3169
- label='Size (Width)'
3170
- className='number-narrow'
3171
- updateField={updateFieldDeprecated}
3172
- />
3173
- <TextField
3174
- value={config.yAxis.rightLabelOffsetSize}
3175
- type='number'
3176
- section='yAxis'
3177
- fieldName='rightLabelOffsetSize'
3178
- label='Label Offset'
3179
- className='number-narrow'
3180
- updateField={updateFieldDeprecated}
3181
- />
3182
3391
 
3183
3392
  <span className='divider-heading'>Number Formatting</span>
3184
3393
  <CheckBox
@@ -3323,13 +3532,24 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3323
3532
  updateField={updateFieldDeprecated}
3324
3533
  />
3325
3534
  </div>
3535
+ <AxisAnchorEditor
3536
+ axisKey='yAxis'
3537
+ anchorField='rightAnchors'
3538
+ config={config}
3539
+ lineOptions={lineOptions}
3540
+ updateConfig={updateConfig}
3541
+ />
3326
3542
  </AccordionItemPanel>
3327
3543
  </AccordionItem>
3328
3544
  )}
3329
3545
  {visSupportsDateCategoryAxis() && (
3330
3546
  <AccordionItem>
3331
3547
  <AccordionItemHeading>
3332
- <AccordionItemButton>
3548
+ <AccordionItemButton
3549
+ data-required-field-section={
3550
+ config.visualizationType === 'Pie' ? 'pie-segments' : 'date-category-axis'
3551
+ }
3552
+ >
3333
3553
  {config.visualizationType === 'Pie' ? 'Segments' : 'Date/Category Axis'}
3334
3554
  {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
3335
3555
  </AccordionItemButton>
@@ -3340,6 +3560,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3340
3560
  {config.visualizationType !== 'Forest Plot' && (
3341
3561
  <>
3342
3562
  <Select
3563
+ display={!isBarRace}
3343
3564
  label='Data Scaling Type'
3344
3565
  tooltip={
3345
3566
  <Tooltip style={{ textTransform: 'none', display: 'inline-block' }}>
@@ -3378,6 +3599,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3378
3599
  xAxis: {
3379
3600
  ...config.xAxis,
3380
3601
  type: value,
3602
+ ...(value !== 'categorical'
3603
+ ? { categoryOrder: [], categoryOrderType: 'data' }
3604
+ : {}),
3381
3605
  ...(autoDetectedDateParseFormat
3382
3606
  ? { dateParseFormat: autoDetectedDateParseFormat }
3383
3607
  : {})
@@ -3385,13 +3609,15 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3385
3609
  })
3386
3610
  }}
3387
3611
  />
3388
- <CheckBox
3389
- value={config.xAxis.manual}
3390
- section='xAxis'
3391
- fieldName='manual'
3392
- label='Manual Ticks'
3393
- updateField={updateFieldDeprecated}
3394
- />
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
+ )}
3395
3621
  <CheckBox
3396
3622
  display={config.xAxis.type !== 'categorical'}
3397
3623
  value={config.xAxis.sortByRecentDate}
@@ -3433,6 +3659,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3433
3659
  section='xAxis'
3434
3660
  fieldName='dataKey'
3435
3661
  label='Data Key'
3662
+ data-required-field-control='date-category-axis'
3436
3663
  initial='Select'
3437
3664
  required={true}
3438
3665
  updateField={updateFieldDeprecated}
@@ -3448,33 +3675,38 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3448
3675
  </Tooltip>
3449
3676
  }
3450
3677
  />
3678
+ {renderCategoryOrderControls()}
3451
3679
  </>
3452
3680
  )}
3453
3681
 
3454
3682
  {config.visualizationType === 'Pie' && (
3455
- <Select
3456
- value={config.xAxis.dataKey || ''}
3457
- section='xAxis'
3458
- fieldName='dataKey'
3459
- label='Segment Labels'
3460
- initial='Select'
3461
- required={true}
3462
- updateField={updateFieldDeprecated}
3463
- options={getColumns(false)}
3464
- tooltip={
3465
- <Tooltip style={{ textTransform: 'none' }}>
3466
- <Tooltip.Target>
3467
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3468
- </Tooltip.Target>
3469
- <Tooltip.Content>
3470
- <p>
3471
- Select the source row or column that contains the segment labels. Depending on the
3472
- data structure, it may be listed as "Key."
3473
- </p>
3474
- </Tooltip.Content>
3475
- </Tooltip>
3476
- }
3477
- />
3683
+ <>
3684
+ <Select
3685
+ value={config.xAxis.dataKey || ''}
3686
+ section='xAxis'
3687
+ fieldName='dataKey'
3688
+ label='Segment Labels'
3689
+ data-required-field-control='pie-segments'
3690
+ initial='Select'
3691
+ required={true}
3692
+ updateField={updateFieldDeprecated}
3693
+ options={getColumns(false)}
3694
+ tooltip={
3695
+ <Tooltip style={{ textTransform: 'none' }}>
3696
+ <Tooltip.Target>
3697
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3698
+ </Tooltip.Target>
3699
+ <Tooltip.Content>
3700
+ <p>
3701
+ Select the source row or column that contains the segment labels. Depending on the
3702
+ data structure, it may be listed as "Key."
3703
+ </p>
3704
+ </Tooltip.Content>
3705
+ </Tooltip>
3706
+ }
3707
+ />
3708
+ {renderCategoryOrderControls('Segment Order')}
3709
+ </>
3478
3710
  )}
3479
3711
 
3480
3712
  {config.visualizationType !== 'Pie' && (
@@ -3485,18 +3717,38 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3485
3717
  fieldName='label'
3486
3718
  label='Label'
3487
3719
  updateField={updateFieldDeprecated}
3488
- maxLength={35}
3720
+ maxLength={
3721
+ config.orientation === 'horizontal' && config.yAxis.titlePlacement === 'top'
3722
+ ? undefined
3723
+ : 35
3724
+ }
3489
3725
  tooltip={
3490
3726
  <Tooltip style={{ textTransform: 'none' }}>
3491
3727
  <Tooltip.Target>
3492
3728
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3493
3729
  </Tooltip.Target>
3494
3730
  <Tooltip.Content>
3495
- <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>
3496
3736
  </Tooltip.Content>
3497
3737
  </Tooltip>
3498
3738
  }
3499
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
+ />
3500
3752
  {config.visualizationType === 'HeatMap' && (
3501
3753
  <Select
3502
3754
  value={config.heatmap?.xAxisPosition ?? HEATMAP_CONFIG_DEFAULTS.xAxisPosition}
@@ -3717,6 +3969,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3717
3969
  updateField={updateFieldDeprecated}
3718
3970
  />
3719
3971
  <CheckBox
3972
+ display={!isBarRace}
3720
3973
  value={config.xAxis.showYearsOnce}
3721
3974
  section='xAxis'
3722
3975
  fieldName='showYearsOnce'
@@ -3739,7 +3992,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3739
3992
  }
3740
3993
  updateField={updateFieldDeprecated}
3741
3994
  />
3742
- {visHasBrushChart() && (
3995
+ {visHasBrushChart() && config.visualizationSubType !== 'racing' && (
3743
3996
  <>
3744
3997
  <CheckBox
3745
3998
  value={config.xAxis.brushActive}
@@ -3767,6 +4020,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3767
4020
  />
3768
4021
  {config.xAxis.brushActive && (
3769
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
+ />
3770
4031
  <CheckBox
3771
4032
  value={!!config.xAxis.brushDynamicYAxis}
3772
4033
  section='xAxis'
@@ -3839,7 +4100,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3839
4100
  <>
3840
4101
  {config.xAxis.type === 'categorical' && (
3841
4102
  <>
3842
- {config.exclusions.keys.length > 0 && (
4103
+ {(config.exclusions?.keys?.length ?? 0) > 0 && (
3843
4104
  <>
3844
4105
  <fieldset>
3845
4106
  <legend className='edit-label'>Excluded Keys</legend>
@@ -3887,6 +4148,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3887
4148
  )}
3888
4149
 
3889
4150
  {visSupportsDateCategoryNumTicks() &&
4151
+ config.visualizationType !== 'HeatMap' &&
3890
4152
  config.xAxis.type !== 'date-time' &&
3891
4153
  config.xAxis.manual && (
3892
4154
  <>
@@ -3961,7 +4223,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3961
4223
  </>
3962
4224
  )}
3963
4225
  {visSupportsDateCategoryNumTicks() &&
3964
- (config.xAxis.type === 'date-time' || !config.xAxis.manual) && (
4226
+ (config.visualizationType === 'HeatMap' ||
4227
+ config.xAxis.type === 'date-time' ||
4228
+ !config.xAxis.manual) && (
3965
4229
  <>
3966
4230
  <TextField
3967
4231
  value={config.xAxis.numTicks}
@@ -3987,9 +4251,10 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3987
4251
  </Tooltip.Target>
3988
4252
  <Tooltip.Content>
3989
4253
  <p>
3990
- Apporoximate number of ticks. Other factors such as space available and data
3991
- may change the exact number of ticks used. To enforce an exact number of
3992
- 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.'}
3993
4258
  </p>
3994
4259
  </Tooltip.Content>
3995
4260
  </Tooltip>
@@ -4181,8 +4446,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4181
4446
  <label htmlFor='barHighlight'>Bar Highlighting</label>
4182
4447
  {config.series.length === 1 &&
4183
4448
  highlightedBarValues.map((highlightedBarValue, i) => (
4184
- <fieldset>
4185
- <div className='edit-block' key={`highlighted-bar-${i}`}>
4449
+ <fieldset key={`highlighted-bar-${i}`}>
4450
+ <div className='edit-block'>
4186
4451
  <Button
4187
4452
  className='btn btn-danger'
4188
4453
  onClick={e => handleRemoveHighlightedBar(e, i)}
@@ -4275,7 +4540,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4275
4540
  />
4276
4541
  {config.exclusions.active && (
4277
4542
  <>
4278
- {config.exclusions.keys.length > 0 && (
4543
+ {(config.exclusions?.keys?.length ?? 0) > 0 && (
4279
4544
  <>
4280
4545
  <fieldset>
4281
4546
  <legend className='edit-label'>Excluded Keys</legend>
@@ -4350,7 +4615,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4350
4615
  <Panels.Regions name='Regions' />
4351
4616
 
4352
4617
  {/* Columns */}
4353
- {config.visualizationType !== 'Box Plot' && config.visualizationType !== 'Sankey' && (
4618
+ {!['Box Plot', 'Sankey'].includes(config.visualizationType) && (
4354
4619
  <AccordionItem>
4355
4620
  <AccordionItemHeading>
4356
4621
  <AccordionItemButton>Columns</AccordionItemButton>
@@ -4374,421 +4639,456 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4374
4639
  <AccordionItemButton>Legend</AccordionItemButton>
4375
4640
  </AccordionItemHeading>
4376
4641
  <AccordionItemPanel>
4377
- <Select
4378
- value={config.legend?.position}
4379
- section='legend'
4380
- fieldName='position'
4381
- label='Position'
4382
- updateField={updateFieldDeprecated}
4383
- options={
4384
- config.visualizationType === 'HeatMap'
4385
- ? config.legend.style === 'gradient'
4386
- ? ['bottom', 'top']
4387
- : ['right', 'left', 'bottom', 'top']
4388
- : config.visualizationType === 'Warming Stripes'
4389
- ? ['bottom']
4390
- : ['right', 'left', 'bottom', 'top']
4391
- }
4392
- />
4393
- {(config.legend.position === 'left' ||
4394
- config.legend.position === 'right' ||
4395
- !config.legend.position) &&
4396
- config.legend.style === 'gradient' && (
4397
- <span style={{ color: 'red', fontSize: '14px' }}>
4398
- Position must be set to top or bottom to use gradient style.
4399
- </span>
4400
- )}
4401
-
4402
- <Select
4403
- tooltip={
4404
- <Tooltip style={{ textTransform: 'none' }}>
4405
- <Tooltip.Target>
4406
- <Icon
4407
- display='question'
4408
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4409
- />
4410
- </Tooltip.Target>
4411
- <Tooltip.Content>
4412
- <p>
4413
- If using gradient style, limit the legend to five items for better mobile visibility,
4414
- and position the legend at the top or bottom.
4415
- </p>
4416
- </Tooltip.Content>
4417
- </Tooltip>
4418
- }
4419
- display={!config.legend.hide}
4420
- value={config.legend.style}
4421
- section='legend'
4422
- fieldName='style'
4423
- label='Legend Style'
4424
- updateField={updateFieldDeprecated}
4425
- options={getLegendStyleOptions('style')}
4426
- />
4427
-
4428
- {config.visualizationType !== 'Warming Stripes' && config.visualizationType !== 'HeatMap' && (
4429
- <Select
4430
- value={config.legend.groupBy}
4642
+ {config.visualizationType === 'Network' ? (
4643
+ <CheckBox
4644
+ value={config.legend.hide ? true : false}
4431
4645
  section='legend'
4432
- fieldName='groupBy'
4433
- initial='Select'
4434
- label='Legend Group By:'
4646
+ fieldName='hide'
4647
+ label='Hide Legend'
4435
4648
  updateField={updateFieldDeprecated}
4436
- 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
+ }
4437
4659
  />
4438
- )}
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
+ )}
4439
4686
 
4440
- <CheckBox
4441
- tooltip={
4442
- <Tooltip style={{ textTransform: 'none' }}>
4443
- <Tooltip.Target>
4444
- <Icon
4445
- display='question'
4446
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4447
- />
4448
- </Tooltip.Target>
4449
- <Tooltip.Content>
4450
- <p>Choose option Shapes in Line Datapoint Symbols to display.</p>
4451
- </Tooltip.Content>
4452
- </Tooltip>
4453
- }
4454
- display={!config.legend.hide && config.legend.style === 'lines'}
4455
- value={config.legend.hasShape}
4456
- section='legend'
4457
- fieldName='hasShape'
4458
- label='Shapes'
4459
- updateField={updateFieldDeprecated}
4460
- />
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
+ />
4461
4712
 
4462
- <Select
4463
- display={!config.legend.hide && config.legend.style === 'gradient'}
4464
- value={config.legend.subStyle}
4465
- section='legend'
4466
- fieldName='subStyle'
4467
- label='Gradient Style'
4468
- updateField={updateFieldDeprecated}
4469
- options={getLegendStyleOptions('subStyle')}
4470
- />
4471
- <TextField
4472
- display={
4473
- config.visualizationType !== 'HeatMap' &&
4474
- config.legend.style === 'gradient' &&
4475
- !config.legend.hide
4476
- }
4477
- className='number-narrow'
4478
- type='number'
4479
- value={config.legend.tickRotation}
4480
- section='legend'
4481
- fieldName='tickRotation'
4482
- label='Tick Rotation (Degrees)'
4483
- updateField={updateFieldDeprecated}
4484
- />
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
+ )}
4485
4724
 
4486
- <CheckBox
4487
- display={
4488
- config.visualizationType !== 'Radar' &&
4489
- config.preliminaryData?.some(pd => pd.label && pd.type === 'suppression' && pd.value)
4490
- }
4491
- value={config.legend.hideSuppressedLabels}
4492
- section='legend'
4493
- fieldName='hideSuppressedLabels'
4494
- label='Hide Suppressed Labels'
4495
- updateField={updateFieldDeprecated}
4496
- tooltip={
4497
- <Tooltip style={{ textTransform: 'none' }}>
4498
- <Tooltip.Target>
4499
- <Icon
4500
- display='question'
4501
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4502
- />
4503
- </Tooltip.Target>
4504
- <Tooltip.Content>
4505
- <p>
4506
- Hiding suppressed labels will not override the 'Special Class' assigned to line chart
4507
- indicating "suppressed" data in the Data Series Panel.
4508
- </p>
4509
- </Tooltip.Content>
4510
- </Tooltip>
4511
- }
4512
- />
4513
- <CheckBox
4514
- display={
4515
- config.visualizationType !== 'Radar' &&
4516
- config.preliminaryData?.some(pd => pd.label && pd.type === 'suppression' && pd.value)
4517
- }
4518
- value={config.legend.hideSuppressionLink}
4519
- section='legend'
4520
- fieldName='hideSuppressionLink'
4521
- label='Hide Suppression Definition Link'
4522
- updateField={updateFieldDeprecated}
4523
- tooltip={
4524
- <Tooltip style={{ textTransform: 'none' }}>
4525
- <Tooltip.Target>
4526
- <Icon
4527
- display='question'
4528
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4529
- />
4530
- </Tooltip.Target>
4531
- <Tooltip.Content>
4532
- <p>Selecting this option will hide the suppression definition link from display.</p>
4533
- </Tooltip.Content>
4534
- </Tooltip>
4535
- }
4536
- />
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
+ />
4537
4746
 
4538
- <Select
4539
- display={visSupportsClickingLegend() && (hasDynamicCategory || hasMultipleSeries)}
4540
- value={config.legend.behavior}
4541
- section='legend'
4542
- fieldName='behavior'
4543
- label='Legend Behavior (When clicked)'
4544
- updateField={(...[section, , fieldName, value]) => updateBehavior(section, fieldName, value)}
4545
- options={['highlight', 'isolate']}
4546
- />
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
+ />
4547
4770
 
4548
- <Select
4549
- display={visHasLegendColorCategory()}
4550
- value={config.legend.colorCode}
4551
- section='legend'
4552
- fieldName='colorCode'
4553
- label='Color code by category'
4554
- initial='Select'
4555
- updateField={updateFieldDeprecated}
4556
- options={getDataValueOptions(data)}
4557
- />
4558
- {visHasLegendAxisAlign() && (
4559
- <CheckBox
4560
- value={config.legend.axisAlign}
4561
- fieldName='axisAlign'
4562
- section='legend'
4563
- label='Align to Axis on Isolate'
4564
- updateField={updateFieldDeprecated}
4565
- />
4566
- )}
4567
- {config.legend.behavior === 'highlight' && config.tooltips.singleSeries && (
4568
- <CheckBox
4569
- value={config.legend.highlightOnHover}
4570
- section='legend'
4571
- fieldName='highlightOnHover'
4572
- label='HIGHLIGHT DATA SERIES ON HOVER'
4573
- updateField={updateFieldDeprecated}
4574
- />
4575
- )}
4576
- {/* start: isolated values */}
4577
- {visHasSelectableLegendValues && config.legend.behavior === 'isolate' && !colorCodeByCategory && (
4578
- <fieldset className='primary-fieldset edit-block' key={'additional-highlight-values'}>
4579
- <label>
4580
- <span className='edit-label'>
4581
- 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={
4582
4782
  <Tooltip style={{ textTransform: 'none' }}>
4583
4783
  <Tooltip.Target>
4584
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
4784
+ <Icon
4785
+ display='question'
4786
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4787
+ />
4585
4788
  </Tooltip.Target>
4586
4789
  <Tooltip.Content>
4587
4790
  <p>
4588
- You can choose data series that are shown on load. Others will be added when the
4589
- 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.
4590
4793
  </p>
4591
4794
  </Tooltip.Content>
4592
4795
  </Tooltip>
4593
- </span>
4594
- </label>
4595
- {config.legend.seriesHighlight &&
4596
- config.legend.seriesHighlight.map((val, i) => (
4597
- <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
+ ))}
4598
4921
  <Button
4599
- className='btn btn-danger'
4922
+ variant='editor-primary'
4600
4923
  onClick={event => {
4601
4924
  event.preventDefault()
4925
+ const legendColumns = getLegendColumns()
4602
4926
  const updatedSeriesHighlight = [...config.legend.seriesHighlight]
4603
- updatedSeriesHighlight.splice(i, 1)
4604
- updateFieldDeprecated('legend', null, 'seriesHighlight', updatedSeriesHighlight)
4605
- if (!updatedSeriesHighlight.length) {
4606
- 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])
4607
4934
  }
4608
4935
  }}
4609
4936
  >
4610
- Remove
4937
+ Add Isolate Value
4611
4938
  </Button>
4612
- <Select
4613
- value={config.legend.seriesHighlight[i]}
4614
- fieldName='seriesHighlight'
4615
- label='Isolate Value'
4616
- onChange={e => {
4617
- const updatedSeriesHighlight = [...config.legend.seriesHighlight]
4618
- if (!updatedSeriesHighlight.includes(e.target.value)) {
4619
- updatedSeriesHighlight[i] = e.target.value
4620
- updateSeriesIsolateValues([...updatedSeriesHighlight])
4621
- }
4622
- }}
4623
- options={getLegendColumns()}
4624
- />
4625
4939
  </fieldset>
4626
- ))}
4627
- <Button
4628
- variant='editor-primary'
4629
- onClick={event => {
4630
- event.preventDefault()
4631
- const legendColumns = getLegendColumns()
4632
- const updatedSeriesHighlight = [...config.legend.seriesHighlight]
4633
- const seriesLength = updatedSeriesHighlight.length
4634
- if (seriesLength < legendColumns.length) {
4635
- const [newSeriesHighlight] = legendColumns.filter(
4636
- d => !updatedSeriesHighlight.includes(d)
4637
- )
4638
- updatedSeriesHighlight.push(newSeriesHighlight)
4639
- 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
4640
4957
  }
4641
- }}
4642
- >
4643
- Add Isolate Value
4644
- </Button>
4645
- </fieldset>
4646
- )}
4647
- {/* end: isolated values */}
4648
- <CheckBox
4649
- display={!config.legend.hide && config.legend.style !== 'gradient'}
4650
- value={config.legend.reverseLabelOrder}
4651
- section='legend'
4652
- fieldName='reverseLabelOrder'
4653
- label='Reverse Labels'
4654
- updateField={updateFieldDeprecated}
4655
- />
4656
- {config.visualizationType !== 'Warming Stripes' && (
4657
- <CheckBox
4658
- display={!config.legend.hide}
4659
- value={
4660
- ['left', 'right'].includes(config.legend.position)
4661
- ? config.legend.hideBorder.side
4662
- : config.legend.hideBorder.topBottom
4663
- }
4664
- section='legend'
4665
- subsection='hideBorder'
4666
- fieldName={['left', 'right'].includes(config.legend.position) ? 'side' : 'topBottom'}
4667
- label='Hide Legend Box'
4668
- updateField={updateFieldDeprecated}
4669
- tooltip={
4670
- <Tooltip style={{ textTransform: 'none' }}>
4671
- <Tooltip.Target>
4672
- <Icon
4673
- display='question'
4674
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4675
- />
4676
- </Tooltip.Target>
4677
- <Tooltip.Content>
4678
- <p>Default option for top and bottom legends is ‘No Box.’.</p>
4679
- </Tooltip.Content>
4680
- </Tooltip>
4681
- }
4682
- />
4683
- )}
4684
- <CheckBox
4685
- display={
4686
- !config.legend.hide &&
4687
- !['left', 'right'].includes(config.legend.position) &&
4688
- config.legend.style !== 'gradient'
4689
- }
4690
- value={config.legend.singleRow}
4691
- section='legend'
4692
- fieldName='singleRow'
4693
- label='Single Row Legend'
4694
- updateField={updateFieldDeprecated}
4695
- />
4696
- <CheckBox
4697
- display={
4698
- ['bottom', 'top'].includes(config.legend.position) &&
4699
- !config.legend.hide &&
4700
- config.legend.style !== 'gradient' &&
4701
- !config.legend.singleRow &&
4702
- !config.legend.singleRow
4703
- }
4704
- value={config.legend.verticalSorted}
4705
- section='legend'
4706
- fieldName='verticalSorted'
4707
- label='Vertical sorted Legend'
4708
- updateField={updateFieldDeprecated}
4709
- />
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
+ />
4710
5004
 
4711
- {config.visualizationType !== 'Warming Stripes' && (
4712
- <CheckBox
4713
- value={config.legend.hide ? true : false}
4714
- section='legend'
4715
- fieldName='hide'
4716
- label='Hide Legend'
4717
- updateField={updateFieldDeprecated}
4718
- tooltip={
4719
- <Tooltip style={{ textTransform: 'none' }}>
4720
- <Tooltip.Target>
4721
- <Icon
4722
- display='question'
4723
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4724
- />
4725
- </Tooltip.Target>
4726
- <Tooltip.Content>
4727
- <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
4728
- </Tooltip.Content>
4729
- </Tooltip>
4730
- }
4731
- />
4732
- )}
4733
- <TextField
4734
- value={config.legend.label}
4735
- section='legend'
4736
- fieldName='label'
4737
- label='Title'
4738
- updateField={updateFieldDeprecated}
4739
- />
4740
- <TextField
4741
- type='textarea'
4742
- value={config.legend.description}
4743
- updateField={updateFieldDeprecated}
4744
- section='legend'
4745
- fieldName='description'
4746
- label='Legend Description'
4747
- />
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
+ />
4748
5044
 
4749
- {config.visualizationType !== 'Warming Stripes' && (
4750
- <CheckBox
4751
- value={config.legend.unified}
4752
- section='legend'
4753
- fieldName='unified'
4754
- label='Unified Legend'
4755
- updateField={updateFieldDeprecated}
4756
- tooltip={
4757
- <Tooltip style={{ textTransform: 'none' }}>
4758
- <Tooltip.Target>
4759
- <Icon
4760
- display='question'
4761
- style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
4762
- />
4763
- </Tooltip.Target>
4764
- <Tooltip.Content>
4765
- <p>
4766
- For a chart with filters, check this option if you want the legend to contain an item
4767
- for every series in the data set, including those that are filtered.
4768
- </p>
4769
- </Tooltip.Content>
4770
- </Tooltip>
4771
- }
4772
- />
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
+ </>
4773
5071
  )}
4774
5072
  </AccordionItemPanel>
4775
5073
  </AccordionItem>
4776
5074
  )}
4777
5075
  {visSupportsFilters() && (
4778
5076
  <>
4779
- <AccordionItem>
4780
- <AccordionItemHeading>
4781
- <AccordionItemButton>Filters</AccordionItemButton>
4782
- </AccordionItemHeading>
4783
- <AccordionItemPanel>
4784
- <VizFilterEditor
4785
- config={config}
4786
- updateField={updateField}
4787
- rawData={rawData}
4788
- hasFootnotes={isDashboard}
4789
- />
4790
- </AccordionItemPanel>
4791
- </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
+ )}
4792
5092
  <AccordionItem>
4793
5093
  <AccordionItemHeading>
4794
5094
  <AccordionItemButton>Footnotes</AccordionItemButton>
@@ -4800,7 +5100,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4800
5100
  </>
4801
5101
  )}
4802
5102
  <Panels.Visual name='Visual' />
4803
- <Panels.PatternSettings name='PatternSettings' />
5103
+ {!isBarRace && !['Network', 'Dendrogram'].includes(config.visualizationType) && (
5104
+ <Panels.PatternSettings name='PatternSettings' />
5105
+ )}
4804
5106
  {/* Spark Line has no data table */}
4805
5107
  {config.visualizationType !== 'Spark Line' && (
4806
5108
  <AccordionItem>
@@ -4818,7 +5120,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4818
5120
  </AccordionItemPanel>
4819
5121
  </AccordionItem>
4820
5122
  )}
4821
- <Panels.Annotate name='Text Annotations' />
5123
+ {!isBarRace && !['Network', 'Dendrogram'].includes(config.visualizationType) && (
5124
+ <Panels.Annotate name='Text Annotations' />
5125
+ )}
4822
5126
  {/* {(config.visualizationType === 'Bar' || config.visualizationType === 'Line') && <Panels.DateHighlighting name='Date Highlighting' />} */}
4823
5127
  {config.visualizationType !== 'Radar' && (
4824
5128
  <PanelMarkup
@@ -4833,6 +5137,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4833
5137
  )}
4834
5138
  <Panels.SmallMultiples name='Small Multiples' />
4835
5139
  </Accordion>
5140
+ {!isDashboard && <ModernStylesAction />}
4836
5141
  {config.type !== 'Spark Line' && (
4837
5142
  <AdvancedEditor
4838
5143
  loadConfig={updateConfig}
@@ -4852,6 +5157,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4852
5157
  onCancel={handleConversionCancel}
4853
5158
  onReturnToV1={handleReturnToV1}
4854
5159
  paletteName={pendingPaletteSelection?.palette}
5160
+ message={config.general?.palette?.version === '2.0' ? V21_PALETTE_CONVERSION_MESSAGE : undefined}
4855
5161
  />
4856
5162
  )}
4857
5163
  </EditorPanelContext.Provider>