@cdc/chart 4.26.5 → 4.26.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/CONFIG.md +20 -14
  2. package/dist/{cdcchart-DQ00cQCm.es.js → cdcchart-BWVIUcAF.es.js} +5 -55
  3. package/dist/cdcchart.js +36554 -34320
  4. package/examples/feature/heatmap/average-age-categorical.json +1 -1
  5. package/examples/feature/heatmap/calendar-heatmap.json +1 -1
  6. package/examples/feature/heatmap/sparse-aggregation.json +1 -1
  7. package/examples/private/bad-y-axis.json +543 -0
  8. package/examples/private/bar-chart-negative-value.json +455 -0
  9. package/examples/private/flueview.json +22051 -0
  10. package/package.json +3 -11
  11. package/src/CdcChart.tsx +7 -6
  12. package/src/CdcChartComponent.tsx +71 -18
  13. package/src/_stories/Chart.PieLabels.stories.tsx +47 -0
  14. package/src/_stories/Chart.SeriesColorAssignments.stories.tsx +183 -0
  15. package/src/_stories/Chart.YAxisAutoMaxStrategy.stories.tsx +52 -0
  16. package/src/_stories/Chart.YAxisFilterDomain.stories.tsx +90 -0
  17. package/src/_stories/Chart.smoke.stories.tsx +14 -1
  18. package/src/_stories/ChartAnnotation.smoke.stories.tsx +10 -0
  19. package/src/_stories/ChartPrefixSuffix.smoke.stories.tsx +28 -1
  20. package/src/_stories/_mock/annotation_event-line_mock.json +1064 -0
  21. package/src/_stories/_mock/heatmap-average-age-categorical.json +1 -1
  22. package/src/_stories/_mock/heatmap.json +1 -1
  23. package/src/components/Annotations/components/AnnotationDraggable.styles.css +22 -1
  24. package/src/components/Annotations/components/AnnotationDraggable.tsx +219 -119
  25. package/src/components/Annotations/tests/AnnotationDraggable.test.tsx +198 -0
  26. package/src/components/Axis/LeftAxis.tsx +3 -0
  27. package/src/components/Axis/LeftAxisGridlines.tsx +8 -1
  28. package/src/components/Axis/RightAxis.tsx +3 -0
  29. package/src/components/Axis/tests/AxisTickValues.test.tsx +86 -0
  30. package/src/components/BarChart/components/BarChart.Horizontal.tsx +1 -2
  31. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +1 -1
  32. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +1 -1
  33. package/src/components/BarChart/components/BarChart.Vertical.tsx +1 -2
  34. package/src/components/BarChart/helpers/getBarData.ts +28 -28
  35. package/src/components/BarChart/helpers/getBarHeights.ts +2 -2
  36. package/src/components/BarChart/helpers/tests/useBarChart.test.tsx +98 -0
  37. package/src/components/BarChart/helpers/useBarChart.ts +4 -5
  38. package/src/components/BoxPlot/BoxPlot.Horizontal.tsx +7 -6
  39. package/src/components/BoxPlot/BoxPlot.Vertical.tsx +9 -7
  40. package/src/components/BoxPlot/helpers/index.ts +4 -3
  41. package/src/components/Brush/BrushSelector.tsx +1 -1
  42. package/src/components/EditorPanel/EditorPanel.tsx +457 -165
  43. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +101 -52
  44. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +16 -7
  45. package/src/components/EditorPanel/components/Panels/Panel.PatternSettings.tsx +3 -3
  46. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +19 -4
  47. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.test.tsx +98 -0
  48. package/src/components/EditorPanel/components/Panels/Panel.SmallMultiples.tsx +10 -0
  49. package/src/components/EditorPanel/components/Panels/Panel.Visual.test.tsx +484 -0
  50. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +3 -0
  51. package/src/components/EditorPanel/components/Panels/SeriesColorAssignments.tsx +262 -0
  52. package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +32 -0
  53. package/src/components/EditorPanel/components/panels.scss +10 -0
  54. package/src/components/EditorPanel/editor-panel.scss +47 -0
  55. package/src/components/EditorPanel/helpers/getVisualizationTypeConfigUpdate.ts +6 -2
  56. package/src/components/EditorPanel/helpers/tests/getVisualizationTypeConfigUpdate.test.ts +20 -2
  57. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +3 -3
  58. package/src/components/EditorPanel/useEditorPermissions.test.tsx +288 -11
  59. package/src/components/EditorPanel/useEditorPermissions.ts +46 -6
  60. package/src/components/Forecasting/Forecasting.tsx +1 -1
  61. package/src/components/HeatMap/components/HeatMap.tsx +22 -17
  62. package/src/components/HeatMap/components/HeatMapGradientLegend.tsx +29 -15
  63. package/src/components/HeatMap/heatmap.css +15 -1
  64. package/src/components/HeatMap/tests/HeatMap.test.tsx +39 -7
  65. package/src/components/Legend/Legend.Component.tsx +56 -61
  66. package/src/components/Legend/Legend.Suppression.tsx +3 -3
  67. package/src/components/Legend/LegendGroup/LegendGroup.tsx +0 -1
  68. package/src/components/Legend/helpers/createFormatLabels.test.ts +88 -0
  69. package/src/components/Legend/helpers/createFormatLabels.tsx +6 -1
  70. package/src/components/LineChart/helpers.test.ts +230 -1
  71. package/src/components/LineChart/helpers.ts +25 -14
  72. package/src/components/LineChart/index.tsx +23 -7
  73. package/src/components/LinearChart/tests/LinearChart.test.tsx +30 -0
  74. package/src/components/LinearChart.tsx +51 -15
  75. package/src/components/PieChart/PieChart.tsx +117 -10
  76. package/src/components/PieChart/helpers/labelPlacement.test.ts +88 -0
  77. package/src/components/PieChart/helpers/labelPlacement.ts +95 -0
  78. package/src/components/ScatterPlot/ScatterPlot.jsx +5 -13
  79. package/src/components/SmallMultiples/SmallMultipleTile.tsx +3 -0
  80. package/src/components/SmallMultiples/SmallMultiples.tsx +38 -9
  81. package/src/components/SmallMultiples/tests/SmallMultiples.test.tsx +170 -0
  82. package/src/data/initial-state.js +3 -0
  83. package/src/helpers/calculateLeftYAxisWidth.ts +9 -3
  84. package/src/helpers/categoryOrder.ts +60 -0
  85. package/src/helpers/colorAssignmentHelpers.ts +102 -0
  86. package/src/helpers/dataHelpers.ts +11 -1
  87. package/src/helpers/getAxisMaxOverride.ts +16 -0
  88. package/src/helpers/getBoxPlotConfig.ts +19 -12
  89. package/src/helpers/getCleanTopTickMax.ts +64 -0
  90. package/src/helpers/getColorScale.ts +18 -9
  91. package/src/helpers/getComboChartConfig.ts +0 -1
  92. package/src/helpers/getExcludedData.ts +0 -1
  93. package/src/helpers/getHasBoundarySuppression.ts +27 -0
  94. package/src/helpers/getMinMax.ts +25 -22
  95. package/src/helpers/getNewRuntime.ts +0 -2
  96. package/src/helpers/getPiePercent.ts +3 -3
  97. package/src/helpers/getYAxisDomainData.ts +38 -0
  98. package/src/helpers/getYAxisFinalizationEligibility.ts +40 -0
  99. package/src/helpers/hasSpacedInlineLabel.ts +10 -0
  100. package/src/helpers/isConvertLineToBarGraph.ts +2 -2
  101. package/src/helpers/seriesColumnSettings.ts +26 -7
  102. package/src/helpers/sizeHelpers.ts +0 -2
  103. package/src/helpers/smallMultiplesHelpers.ts +5 -0
  104. package/src/helpers/tests/calculateLeftYAxisWidth.test.ts +38 -0
  105. package/src/helpers/tests/categoryOrder.test.ts +57 -0
  106. package/src/helpers/tests/dataHelpers.test.ts +135 -0
  107. package/src/helpers/tests/getAxisMaxOverride.test.ts +36 -0
  108. package/src/helpers/tests/getCleanTopTickMax.test.ts +165 -0
  109. package/src/helpers/tests/getColorScale.test.ts +197 -0
  110. package/src/helpers/tests/getMinMax.test.ts +211 -0
  111. package/src/helpers/tests/getYAxisDomainData.test.ts +119 -0
  112. package/src/helpers/tests/getYAxisFinalizationEligibility.test.ts +185 -0
  113. package/src/helpers/tests/{getYAxisAutoPaddingMode.test.ts → hasSpacedInlineLabel.test.ts} +17 -32
  114. package/src/helpers/tests/seriesColumnSettings.test.ts +76 -2
  115. package/src/helpers/tests/smallMultiplesHelpers.test.ts +99 -0
  116. package/src/hooks/tests/useRightAxis.test.tsx +268 -0
  117. package/src/hooks/tests/useScales.test.tsx +302 -27
  118. package/src/hooks/tests/useTooltip.test.tsx +132 -0
  119. package/src/hooks/useRightAxis.ts +35 -25
  120. package/src/hooks/useScales.ts +45 -28
  121. package/src/hooks/useTooltip.tsx +17 -11
  122. package/src/store/chart.reducer.ts +0 -1
  123. package/src/test/CdcChart.dataTable.test.tsx +216 -0
  124. package/src/types/ChartConfig.ts +6 -1
  125. package/src/types/ChartContext.ts +3 -0
  126. package/src/helpers/getYAxisAutoPadding.ts +0 -55
  127. package/src/helpers/getYAxisAutoPaddingMode.ts +0 -17
  128. package/src/helpers/tests/getYAxisAutoPadding.test.ts +0 -37
@@ -15,6 +15,7 @@ import { EditorPanel as BaseEditorPanel } from '@cdc/core/components/EditorPanel
15
15
  import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
16
16
  import Icon from '@cdc/core/components/ui/Icon'
17
17
  import ColumnsEditor from '@cdc/core/components/EditorPanel/ColumnsEditor'
18
+ import CustomSortOrder from '@cdc/core/components/EditorPanel/CustomSortOrder'
18
19
  import DataTableEditor from '@cdc/core/components/EditorPanel/DataTableEditor'
19
20
  import GroupedList from '@cdc/core/components/EditorPanel/GroupedList'
20
21
  import VizFilterEditor from '@cdc/core/components/EditorPanel/VizFilterEditor'
@@ -36,7 +37,6 @@ import { useEditorPermissions } from './useEditorPermissions'
36
37
  import { useHighlightedBars } from '../../hooks/useHighlightedBars'
37
38
  import ConfigContext from '../../ConfigContext'
38
39
  import useReduceData from '../../hooks/useReduceData'
39
- import useRightAxis from '../../hooks/useRightAxis'
40
40
  import WarningImage from '../../images/warning.svg'
41
41
  import getMinMax from '../../helpers/getMinMax'
42
42
 
@@ -61,6 +61,7 @@ import { paletteMigrationMap, twoColorPaletteMigrationMap } from '@cdc/core/help
61
61
  import { isV1Palette, migratePaletteWithMap } from '@cdc/core/helpers/palettes/utils'
62
62
  import { USE_V2_MIGRATION } from '@cdc/core/helpers/constants'
63
63
  import { getSeriesOwnedColumnNames } from '../../helpers/seriesColumnSettings'
64
+ import { getOrderedCategoryValues } from '../../helpers/categoryOrder'
64
65
  import {
65
66
  HEATMAP_CONFIG_DEFAULTS,
66
67
  MAX_HEATMAP_COLOR_BUCKETS,
@@ -142,7 +143,8 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
142
143
  hideBarSymbol: false,
143
144
  hideLineStyle: false,
144
145
  circleSize: 6,
145
- displayGray: true
146
+ displayGray: true,
147
+ weight: undefined
146
148
  }
147
149
  preliminaryData.push(defaultValues)
148
150
  updateConfig({ ...config, preliminaryData })
@@ -197,7 +199,8 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
197
199
  type,
198
200
  value,
199
201
  hideBarSymbol,
200
- hideLineStyle
202
+ hideLineStyle,
203
+ weight
201
204
  },
202
205
  i
203
206
  ) => (
@@ -296,6 +299,16 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
296
299
  updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
297
300
  options={getStyleOptions(type)}
298
301
  />
302
+ <TextField
303
+ type='number'
304
+ min={1}
305
+ max={9}
306
+ value={weight}
307
+ fieldName='weight'
308
+ label='Line Weight'
309
+ placeholder='Default'
310
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
311
+ />
299
312
  <CheckBox
300
313
  value={hideLineStyle}
301
314
  fieldName='hideLineStyle'
@@ -496,6 +509,18 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
496
509
  updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
497
510
  />
498
511
  )}
512
+ {style && !style.includes('Circles') && (
513
+ <TextField
514
+ type='number'
515
+ min={1}
516
+ max={9}
517
+ value={weight}
518
+ fieldName='weight'
519
+ label='Line Weight'
520
+ placeholder='Default'
521
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
522
+ />
523
+ )}
499
524
  {style !== 'Filled Circles' && (
500
525
  <TextField
501
526
  value={label}
@@ -867,11 +892,14 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
867
892
  visSupportsDateCategoryNumTicks,
868
893
  visSupportsDateCategoryTickRotation,
869
894
  visSupportsDynamicSeries,
895
+ visSupportsAutoMaxStrategy,
896
+ visSupportsFilterDomainBehavior,
870
897
  visSupportsFilters,
871
898
  visSupportsLeftValueAxis,
872
899
  visSupportsPreliminaryData,
873
900
  visSupportsRankByValue,
874
901
  visSupportsResponsiveTicks,
902
+ visSupportsRightValueAxis,
875
903
  visSupportsValueAxisGridLines,
876
904
  visSupportsValueAxisLabels,
877
905
  visSupportsValueAxisLine,
@@ -923,8 +951,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
923
951
  }
924
952
  }, [config.visualizationType])
925
953
 
926
- const { hasRightAxis } = useRightAxis({ config: config, yMax: 0, data: config.data, updateConfig })
927
-
928
954
  const getItemStyle = (isDragging, draggableStyle) => ({
929
955
  ...draggableStyle
930
956
  })
@@ -1033,6 +1059,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1033
1059
  xAxis: {
1034
1060
  ...config.xAxis,
1035
1061
  dataKey: newValue,
1062
+ categoryOrder: [],
1063
+ categoryOrderType: 'data',
1036
1064
  ...(autoDetectedDateParseFormat ? { dateParseFormat: autoDetectedDateParseFormat } : {})
1037
1065
  }
1038
1066
  }
@@ -1225,7 +1253,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1225
1253
  }
1226
1254
  break
1227
1255
  case 'subStyle':
1228
- if (config.visualizationType === 'Bar') {
1256
+ if (config.visualizationType === 'Bar' || config.visualizationType === 'HeatMap') {
1229
1257
  options.push('linear blocks')
1230
1258
  } else {
1231
1259
  options.push('linear blocks', 'smooth')
@@ -1258,6 +1286,63 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
1258
1286
  return unique ? [...new Set(values)] : values
1259
1287
  }
1260
1288
 
1289
+ const getAvailableExclusionValues = dataKey => {
1290
+ const excludedKeys = (config.exclusions.keys || []).map(String)
1291
+ return getDataValues(dataKey, true).filter(value => !excludedKeys.includes(String(value)))
1292
+ }
1293
+
1294
+ const categoryOrderValues = useMemo(
1295
+ () =>
1296
+ getOrderedCategoryValues(
1297
+ excludedData as Record<string, any>[],
1298
+ config.xAxis?.dataKey,
1299
+ config.xAxis?.categoryOrder
1300
+ ),
1301
+ [excludedData, config.xAxis?.dataKey, config.xAxis?.categoryOrder]
1302
+ )
1303
+
1304
+ const updateCategoryOrderType = (categoryOrderType: 'data' | 'custom') => {
1305
+ updateConfig({
1306
+ ...config,
1307
+ xAxis: {
1308
+ ...config.xAxis,
1309
+ categoryOrderType,
1310
+ categoryOrder: categoryOrderType === 'custom' ? categoryOrderValues : []
1311
+ }
1312
+ })
1313
+ }
1314
+
1315
+ const renderCategoryOrderControls = (label = 'Category Order') => {
1316
+ if (config.xAxis?.type !== 'categorical' || !config.xAxis?.dataKey || !categoryOrderValues.length) return null
1317
+
1318
+ return (
1319
+ <>
1320
+ <Select
1321
+ value={config.xAxis.categoryOrderType || 'data'}
1322
+ section='xAxis'
1323
+ fieldName='categoryOrderType'
1324
+ label={label}
1325
+ options={[
1326
+ { label: 'Data order', value: 'data' },
1327
+ { label: 'Custom', value: 'custom' }
1328
+ ]}
1329
+ updateField={(_section, _subsection, _fieldName, value) => updateCategoryOrderType(value)}
1330
+ />
1331
+ {config.xAxis.categoryOrderType === 'custom' && (
1332
+ <CustomSortOrder
1333
+ column={config.xAxis.dataKey}
1334
+ data={excludedData as Record<string, any>[]}
1335
+ customOrder={config.xAxis.categoryOrder}
1336
+ updateField={updateFieldDeprecated}
1337
+ updateTarget={{ section: 'xAxis', subsection: null, fieldName: 'categoryOrder' }}
1338
+ droppableId='category_order'
1339
+ draggableIdPrefix='categoryOrder'
1340
+ />
1341
+ )}
1342
+ </>
1343
+ )
1344
+ }
1345
+
1261
1346
  // prettier-ignore
1262
1347
  const {
1263
1348
  highlightedBarValues,
@@ -2558,26 +2643,6 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2558
2643
  title={!config.yAxis.gridLines ? 'Show gridlines to enable' : ''}
2559
2644
  />
2560
2645
  )}
2561
- {visSupportsYPadding() && (
2562
- <CheckBox
2563
- value={config.yAxis.enablePadding}
2564
- section='yAxis'
2565
- fieldName='enablePadding'
2566
- label='Add Padding to Value Axis Scale'
2567
- updateField={updateFieldDeprecated}
2568
- />
2569
- )}
2570
- {config.yAxis.enablePadding && visSupportsYPadding() && (
2571
- <TextField
2572
- type='number'
2573
- section='yAxis'
2574
- fieldName='scalePadding'
2575
- label='Padding Percentage'
2576
- className='number-narrow'
2577
- updateField={updateFieldDeprecated}
2578
- value={config.yAxis.scalePadding}
2579
- />
2580
- )}
2581
2646
  </>
2582
2647
  )}
2583
2648
  <span className='divider-heading'>Number Formatting</span>
@@ -2759,32 +2824,41 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2759
2824
  updateField={updateFieldDeprecated}
2760
2825
  />
2761
2826
  )}
2762
- {visSupportsValueAxisMax() && (
2763
- <TextField
2764
- value={config.xAxis.max}
2765
- section='xAxis'
2766
- fieldName='max'
2767
- label='max value'
2768
- type='number'
2769
- placeholder='Auto'
2770
- updateField={updateFieldDeprecated}
2771
- />
2772
- )}
2773
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
2774
- {visSupportsValueAxisMin() && (
2775
- <TextField
2776
- value={config.xAxis.min}
2777
- section='xAxis'
2778
- fieldName='min'
2779
- type='number'
2780
- label='min value'
2781
- placeholder='Auto'
2782
- updateField={updateFieldDeprecated}
2783
- />
2784
- )}
2785
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
2786
- {config.visualizationType === 'Deviation Bar' && (
2787
- <>
2827
+ <div className='axis-domain-group'>
2828
+ <span className='axis-domain-group__title'>Value Axis Domain</span>
2829
+ <div className='axis-domain-group__row'>
2830
+ {visSupportsValueAxisMax() && (
2831
+ <div className='axis-domain-group__field'>
2832
+ <TextField
2833
+ value={config.xAxis.max}
2834
+ section='xAxis'
2835
+ fieldName='max'
2836
+ label='axis max value'
2837
+ type='number'
2838
+ placeholder='Auto'
2839
+ className='axis-domain-number'
2840
+ updateField={updateFieldDeprecated}
2841
+ />
2842
+ <span className='axis-domain-warning'>{warningMsg.maxMsg}</span>
2843
+ </div>
2844
+ )}
2845
+ {visSupportsValueAxisMin() && (
2846
+ <div className='axis-domain-group__field'>
2847
+ <TextField
2848
+ value={config.xAxis.min}
2849
+ section='xAxis'
2850
+ fieldName='min'
2851
+ type='number'
2852
+ label='axis min value'
2853
+ placeholder='Auto'
2854
+ className='axis-domain-number'
2855
+ updateField={updateFieldDeprecated}
2856
+ />
2857
+ <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
2858
+ </div>
2859
+ )}
2860
+ </div>
2861
+ {config.visualizationType === 'Deviation Bar' && (
2788
2862
  <TextField
2789
2863
  value={config.xAxis.target}
2790
2864
  section='xAxis'
@@ -2792,8 +2866,104 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2792
2866
  type='number'
2793
2867
  label='Deviation point'
2794
2868
  placeholder='Auto'
2869
+ className='axis-domain-number'
2795
2870
  updateField={updateFieldDeprecated}
2796
2871
  />
2872
+ )}
2873
+ <TextField
2874
+ value={config.yAxis.smallestLeftAxisMax}
2875
+ section='yAxis'
2876
+ fieldName='smallestLeftAxisMax'
2877
+ type='number'
2878
+ label='Smallest axis maximum'
2879
+ placeholder='Auto'
2880
+ className='axis-domain-number'
2881
+ tooltip={
2882
+ <Tooltip style={{ textTransform: 'none' }}>
2883
+ <Tooltip.Target>
2884
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2885
+ </Tooltip.Target>
2886
+ <Tooltip.Content>
2887
+ <p>
2888
+ Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
2889
+ 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
2890
+ </p>
2891
+ </Tooltip.Content>
2892
+ </Tooltip>
2893
+ }
2894
+ updateField={updateFieldDeprecated}
2895
+ />
2896
+ {visSupportsAutoMaxStrategy() && (
2897
+ <Select
2898
+ value={config.yAxis.autoMaxStrategy || 'default'}
2899
+ section='yAxis'
2900
+ fieldName='autoMaxStrategy'
2901
+ label='Automatic max strategy'
2902
+ updateField={updateFieldDeprecated}
2903
+ options={[
2904
+ { value: 'default', label: 'Default' },
2905
+ { value: 'clean-top-tick', label: 'Clean top tick' }
2906
+ ]}
2907
+ tooltip={
2908
+ <Tooltip style={{ textTransform: 'none' }}>
2909
+ <Tooltip.Target>
2910
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2911
+ </Tooltip.Target>
2912
+ <Tooltip.Content>
2913
+ {config.visualizationType === 'Combo' ? (
2914
+ <p>
2915
+ Clean top tick rounds automatic left and right axis maximums up to cleaner
2916
+ tick steps before axis padding is applied.
2917
+ </p>
2918
+ ) : (
2919
+ <p>
2920
+ Clean top tick rounds the automatic value axis maximum up to a cleaner tick
2921
+ step before axis padding is applied.
2922
+ </p>
2923
+ )}
2924
+ </Tooltip.Content>
2925
+ </Tooltip>
2926
+ }
2927
+ />
2928
+ )}
2929
+ {visSupportsFilterDomainBehavior() && (
2930
+ <Select
2931
+ value={config.yAxis.filterDomainBehavior || 'dynamic'}
2932
+ section='yAxis'
2933
+ fieldName='filterDomainBehavior'
2934
+ label='Filter Domain Behavior'
2935
+ updateField={updateFieldDeprecated}
2936
+ options={[
2937
+ { value: 'dynamic', label: 'Dynamic' },
2938
+ { value: 'stable', label: 'Stable' }
2939
+ ]}
2940
+ tooltip={
2941
+ <Tooltip style={{ textTransform: 'none' }}>
2942
+ <Tooltip.Target>
2943
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2944
+ </Tooltip.Target>
2945
+ <Tooltip.Content>
2946
+ {config.visualizationType === 'Combo' ? (
2947
+ <p>
2948
+ Dynamic rescales the value axes to the currently filtered data. Stable keeps
2949
+ the left and right axes based on the full eligible dataset while still
2950
+ rendering filtered rows.
2951
+ </p>
2952
+ ) : (
2953
+ <p>
2954
+ Dynamic rescales the value axis to the currently filtered data. Stable keeps
2955
+ the value axis based on the full eligible dataset while still rendering
2956
+ filtered rows.
2957
+ </p>
2958
+ )}
2959
+ </Tooltip.Content>
2960
+ </Tooltip>
2961
+ }
2962
+ />
2963
+ )}
2964
+ </div>
2965
+ {config.visualizationType === 'Deviation Bar' && (
2966
+ <>
2797
2967
  <TextField
2798
2968
  value={config.xAxis.targetLabel || 'Target'}
2799
2969
  section='xAxis'
@@ -2841,52 +3011,151 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2841
3011
  updateField={updateFieldDeprecated}
2842
3012
  />
2843
3013
 
2844
- <TextField
2845
- value={config.yAxis.max}
2846
- section='yAxis'
2847
- fieldName='max'
2848
- type='number'
2849
- label='left axis max value'
2850
- placeholder='Auto'
2851
- updateField={updateFieldDeprecated}
2852
- />
2853
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
2854
- {config.visualizationType !== 'Area Chart' && config.visualizationSubType !== 'stacked' && (
2855
- <>
2856
- <TextField
2857
- value={config.yAxis.min}
3014
+ <div className='axis-domain-group'>
3015
+ <span className='axis-domain-group__title'>Value Axis Domain</span>
3016
+ <div className='axis-domain-group__row'>
3017
+ <div className='axis-domain-group__field'>
3018
+ <TextField
3019
+ value={config.yAxis.max}
3020
+ section='yAxis'
3021
+ fieldName='max'
3022
+ type='number'
3023
+ label='axis max value'
3024
+ placeholder='Auto'
3025
+ className='axis-domain-number'
3026
+ updateField={updateFieldDeprecated}
3027
+ />
3028
+ <span className='axis-domain-warning'>{warningMsg.maxMsg}</span>
3029
+ </div>
3030
+ {config.visualizationType !== 'Area Chart' &&
3031
+ config.visualizationSubType !== 'stacked' && (
3032
+ <div className='axis-domain-group__field'>
3033
+ <TextField
3034
+ value={config.yAxis.min}
3035
+ section='yAxis'
3036
+ fieldName='min'
3037
+ type='number'
3038
+ label='axis min value'
3039
+ placeholder='Auto'
3040
+ className='axis-domain-number'
3041
+ updateField={updateFieldDeprecated}
3042
+ />
3043
+ <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
3044
+ </div>
3045
+ )}
3046
+ </div>
3047
+ <TextField
3048
+ value={config.yAxis.smallestLeftAxisMax}
3049
+ section='yAxis'
3050
+ fieldName='smallestLeftAxisMax'
3051
+ type='number'
3052
+ label='Smallest axis maximum'
3053
+ placeholder='Auto'
3054
+ className='axis-domain-number'
3055
+ tooltip={
3056
+ <Tooltip style={{ textTransform: 'none' }}>
3057
+ <Tooltip.Target>
3058
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3059
+ </Tooltip.Target>
3060
+ <Tooltip.Content>
3061
+ <p>
3062
+ Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
3063
+ 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
3064
+ </p>
3065
+ </Tooltip.Content>
3066
+ </Tooltip>
3067
+ }
3068
+ updateField={updateFieldDeprecated}
3069
+ />
3070
+ {visSupportsAutoMaxStrategy() && (
3071
+ <Select
3072
+ value={config.yAxis.autoMaxStrategy || 'default'}
2858
3073
  section='yAxis'
2859
- fieldName='min'
3074
+ fieldName='autoMaxStrategy'
3075
+ label='Automatic max strategy'
3076
+ updateField={updateFieldDeprecated}
3077
+ options={[
3078
+ { value: 'default', label: 'Default' },
3079
+ { value: 'clean-top-tick', label: 'Clean top tick' }
3080
+ ]}
3081
+ tooltip={
3082
+ <Tooltip style={{ textTransform: 'none' }}>
3083
+ <Tooltip.Target>
3084
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3085
+ </Tooltip.Target>
3086
+ <Tooltip.Content>
3087
+ {config.visualizationType === 'Combo' ? (
3088
+ <p>
3089
+ Clean top tick rounds automatic left and right axis maximums up to cleaner
3090
+ tick steps before axis padding is applied.
3091
+ </p>
3092
+ ) : (
3093
+ <p>
3094
+ Clean top tick rounds the automatic value axis maximum up to a cleaner tick
3095
+ step before axis padding is applied.
3096
+ </p>
3097
+ )}
3098
+ </Tooltip.Content>
3099
+ </Tooltip>
3100
+ }
3101
+ />
3102
+ )}
3103
+ {visSupportsFilterDomainBehavior() && (
3104
+ <Select
3105
+ value={config.yAxis.filterDomainBehavior || 'dynamic'}
3106
+ section='yAxis'
3107
+ fieldName='filterDomainBehavior'
3108
+ label='Filter Domain Behavior'
3109
+ updateField={updateFieldDeprecated}
3110
+ options={[
3111
+ { value: 'dynamic', label: 'Dynamic' },
3112
+ { value: 'stable', label: 'Stable' }
3113
+ ]}
3114
+ tooltip={
3115
+ <Tooltip style={{ textTransform: 'none' }}>
3116
+ <Tooltip.Target>
3117
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3118
+ </Tooltip.Target>
3119
+ <Tooltip.Content>
3120
+ {config.visualizationType === 'Combo' ? (
3121
+ <p>
3122
+ Dynamic rescales the value axes to the currently filtered data. Stable keeps
3123
+ the left and right axes based on the full eligible dataset while still
3124
+ rendering filtered rows.
3125
+ </p>
3126
+ ) : (
3127
+ <p>
3128
+ Dynamic rescales the value axis to the currently filtered data. Stable keeps
3129
+ the value axis based on the full eligible dataset while still rendering
3130
+ filtered rows.
3131
+ </p>
3132
+ )}
3133
+ </Tooltip.Content>
3134
+ </Tooltip>
3135
+ }
3136
+ />
3137
+ )}
3138
+ {visSupportsYPadding() && (
3139
+ <CheckBox
3140
+ value={config.yAxis.enablePadding}
3141
+ section='yAxis'
3142
+ fieldName='enablePadding'
3143
+ label='Add Padding to Value Axis Scale'
3144
+ updateField={updateFieldDeprecated}
3145
+ />
3146
+ )}
3147
+ {config.yAxis.enablePadding && visSupportsYPadding() && (
3148
+ <TextField
2860
3149
  type='number'
2861
- label='left axis min value'
2862
- placeholder='Auto'
3150
+ section='yAxis'
3151
+ fieldName='scalePadding'
3152
+ label='Padding Percentage'
3153
+ className='axis-domain-number'
2863
3154
  updateField={updateFieldDeprecated}
3155
+ value={config.yAxis.scalePadding}
2864
3156
  />
2865
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
2866
- </>
2867
- )}
2868
- <TextField
2869
- value={config.yAxis.smallestLeftAxisMax}
2870
- section='yAxis'
2871
- fieldName='smallestLeftAxisMax'
2872
- type='number'
2873
- label='Smallest Left Axis Maximum'
2874
- placeholder='Auto'
2875
- tooltip={
2876
- <Tooltip style={{ textTransform: 'none' }}>
2877
- <Tooltip.Target>
2878
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2879
- </Tooltip.Target>
2880
- <Tooltip.Content>
2881
- <p>
2882
- Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6,
2883
- 0.8, 1. Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
2884
- </p>
2885
- </Tooltip.Content>
2886
- </Tooltip>
2887
- }
2888
- updateField={updateFieldDeprecated}
2889
- />
3157
+ )}
3158
+ </div>
2890
3159
  </>
2891
3160
  )
2892
3161
  )}
@@ -2912,7 +3181,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
2912
3181
  </AccordionItem>
2913
3182
  )}
2914
3183
  {/* Right Value Axis Settings */}
2915
- {hasRightAxis && (
3184
+ {visSupportsRightValueAxis() && (
2916
3185
  <AccordionItem>
2917
3186
  <AccordionItemHeading>
2918
3187
  <AccordionItemButton>Right Value Axis</AccordionItemButton>
@@ -3054,48 +3323,60 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3054
3323
  updateField={updateFieldDeprecated}
3055
3324
  />
3056
3325
 
3057
- <TextField
3058
- value={config.yAxis.rightMax}
3059
- section='yAxis'
3060
- fieldName='rightMax'
3061
- type='number'
3062
- label='right axis max value'
3063
- placeholder='Auto'
3064
- updateField={updateFieldDeprecated}
3065
- />
3066
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.rightMaxMessage}</span>
3067
- <TextField
3068
- value={config.yAxis.rightMin}
3069
- section='yAxis'
3070
- fieldName='rightMin'
3071
- type='number'
3072
- label='right axis min value'
3073
- placeholder='Auto'
3074
- updateField={updateFieldDeprecated}
3075
- />
3076
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
3077
- <TextField
3078
- value={config.yAxis.smallestRightAxisMax}
3079
- section='yAxis'
3080
- fieldName='smallestRightAxisMax'
3081
- type='number'
3082
- label='Smallest Right Axis Maximum'
3083
- placeholder='Auto'
3084
- tooltip={
3085
- <Tooltip style={{ textTransform: 'none' }}>
3086
- <Tooltip.Target>
3087
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3088
- </Tooltip.Target>
3089
- <Tooltip.Content>
3090
- <p>
3091
- Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6, 0.8, 1.
3092
- Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
3093
- </p>
3094
- </Tooltip.Content>
3095
- </Tooltip>
3096
- }
3097
- updateField={updateFieldDeprecated}
3098
- />
3326
+ <div className='axis-domain-group'>
3327
+ <span className='axis-domain-group__title'>Right Axis Domain</span>
3328
+ <div className='axis-domain-group__row'>
3329
+ <div className='axis-domain-group__field'>
3330
+ <TextField
3331
+ value={config.yAxis.rightMax}
3332
+ section='yAxis'
3333
+ fieldName='rightMax'
3334
+ type='number'
3335
+ label='axis max value'
3336
+ placeholder='Auto'
3337
+ className='axis-domain-number'
3338
+ updateField={updateFieldDeprecated}
3339
+ />
3340
+ <span className='axis-domain-warning'>{warningMsg.rightMaxMessage}</span>
3341
+ </div>
3342
+ <div className='axis-domain-group__field'>
3343
+ <TextField
3344
+ value={config.yAxis.rightMin}
3345
+ section='yAxis'
3346
+ fieldName='rightMin'
3347
+ type='number'
3348
+ label='axis min value'
3349
+ placeholder='Auto'
3350
+ className='axis-domain-number'
3351
+ updateField={updateFieldDeprecated}
3352
+ />
3353
+ <span className='axis-domain-warning'>{warningMsg.minMsg}</span>
3354
+ </div>
3355
+ </div>
3356
+ <TextField
3357
+ value={config.yAxis.smallestRightAxisMax}
3358
+ section='yAxis'
3359
+ fieldName='smallestRightAxisMax'
3360
+ type='number'
3361
+ label='Smallest axis maximum'
3362
+ placeholder='Auto'
3363
+ className='axis-domain-number'
3364
+ tooltip={
3365
+ <Tooltip style={{ textTransform: 'none' }}>
3366
+ <Tooltip.Target>
3367
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3368
+ </Tooltip.Target>
3369
+ <Tooltip.Content>
3370
+ <p>
3371
+ Example: If your data only goes up to 1, the axis might show 0, 0.2, 0.4, 0.6, 0.8, 1.
3372
+ Setting this to 5 would make the axis show 0, 1, 2, 3, 4, 5 instead.
3373
+ </p>
3374
+ </Tooltip.Content>
3375
+ </Tooltip>
3376
+ }
3377
+ updateField={updateFieldDeprecated}
3378
+ />
3379
+ </div>
3099
3380
  </AccordionItemPanel>
3100
3381
  </AccordionItem>
3101
3382
  )}
@@ -3151,6 +3432,9 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3151
3432
  xAxis: {
3152
3433
  ...config.xAxis,
3153
3434
  type: value,
3435
+ ...(value !== 'categorical'
3436
+ ? { categoryOrder: [], categoryOrderType: 'data' }
3437
+ : {}),
3154
3438
  ...(autoDetectedDateParseFormat
3155
3439
  ? { dateParseFormat: autoDetectedDateParseFormat }
3156
3440
  : {})
@@ -3221,33 +3505,37 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3221
3505
  </Tooltip>
3222
3506
  }
3223
3507
  />
3508
+ {renderCategoryOrderControls()}
3224
3509
  </>
3225
3510
  )}
3226
3511
 
3227
3512
  {config.visualizationType === 'Pie' && (
3228
- <Select
3229
- value={config.xAxis.dataKey || ''}
3230
- section='xAxis'
3231
- fieldName='dataKey'
3232
- label='Segment Labels'
3233
- initial='Select'
3234
- required={true}
3235
- updateField={updateFieldDeprecated}
3236
- options={getColumns(false)}
3237
- tooltip={
3238
- <Tooltip style={{ textTransform: 'none' }}>
3239
- <Tooltip.Target>
3240
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3241
- </Tooltip.Target>
3242
- <Tooltip.Content>
3243
- <p>
3244
- Select the source row or column that contains the segment labels. Depending on the
3245
- data structure, it may be listed as "Key."
3246
- </p>
3247
- </Tooltip.Content>
3248
- </Tooltip>
3249
- }
3250
- />
3513
+ <>
3514
+ <Select
3515
+ value={config.xAxis.dataKey || ''}
3516
+ section='xAxis'
3517
+ fieldName='dataKey'
3518
+ label='Segment Labels'
3519
+ initial='Select'
3520
+ required={true}
3521
+ updateField={updateFieldDeprecated}
3522
+ options={getColumns(false)}
3523
+ tooltip={
3524
+ <Tooltip style={{ textTransform: 'none' }}>
3525
+ <Tooltip.Target>
3526
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3527
+ </Tooltip.Target>
3528
+ <Tooltip.Content>
3529
+ <p>
3530
+ Select the source row or column that contains the segment labels. Depending on the
3531
+ data structure, it may be listed as "Key."
3532
+ </p>
3533
+ </Tooltip.Content>
3534
+ </Tooltip>
3535
+ }
3536
+ />
3537
+ {renderCategoryOrderControls('Segment Order')}
3538
+ </>
3251
3539
  )}
3252
3540
 
3253
3541
  {config.visualizationType !== 'Pie' && (
@@ -3631,7 +3919,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3631
3919
  }
3632
3920
  e.target.value = ''
3633
3921
  }}
3634
- options={getDataValues(config.xAxis.dataKey, true)}
3922
+ options={getAvailableExclusionValues(config.xAxis.dataKey)}
3635
3923
  />
3636
3924
  </>
3637
3925
  )}
@@ -3954,8 +4242,8 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
3954
4242
  <label htmlFor='barHighlight'>Bar Highlighting</label>
3955
4243
  {config.series.length === 1 &&
3956
4244
  highlightedBarValues.map((highlightedBarValue, i) => (
3957
- <fieldset>
3958
- <div className='edit-block' key={`highlighted-bar-${i}`}>
4245
+ <fieldset key={`highlighted-bar-${i}`}>
4246
+ <div className='edit-block'>
3959
4247
  <Button
3960
4248
  className='btn btn-danger'
3961
4249
  onClick={e => handleRemoveHighlightedBar(e, i)}
@@ -4067,7 +4355,7 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4067
4355
  }
4068
4356
  e.target.value = ''
4069
4357
  }}
4070
- options={getDataValues(config.xAxis.dataKey, true)}
4358
+ options={getAvailableExclusionValues(config.xAxis.dataKey)}
4071
4359
  />
4072
4360
  </>
4073
4361
  )}
@@ -4242,7 +4530,11 @@ const EditorPanel: React.FC<ChartEditorPanelProps> = ({ datasets }) => {
4242
4530
  options={getLegendStyleOptions('subStyle')}
4243
4531
  />
4244
4532
  <TextField
4245
- display={config.legend.style === 'gradient' && !config.legend.hide}
4533
+ display={
4534
+ config.visualizationType !== 'HeatMap' &&
4535
+ config.legend.style === 'gradient' &&
4536
+ !config.legend.hide
4537
+ }
4246
4538
  className='number-narrow'
4247
4539
  type='number'
4248
4540
  value={config.legend.tickRotation}